Jump from Real Mode (RM) to Protected Mode (PM)



  • Hey Leute, habe mal eine kleine Verständnisfrage. Den Sprung zum ProtectedMode verstehe ich leider nicht wirklich. Mir ist klar was das 0x8:ProtectedMode bedeuten soll, aber wie es funktioniert versteh ich leider gar nicht. Mit 0x8 wird das erste Segment nach dem NULL_DESC der GDT ausgewählt. So un ProtectedMode ist ja ein Label und wir hier als Offset verwendet. Aber wie funktioniert der Sprung genau? Ich meine ProtectedMode ist doch einfach ein Offset, wo wurde dies denn in das entsprechende Segment geschrieben? Vielleicht stehe ich gerade auch einfach nur auf dem Schlauch, ich kann im Moment nicht mal die Frage richtig formulieren. Ich hoffe ihr versteht was ich meine. Schonmal vielen Dank für Eure Hilfe

    Lg freeG


  • Mod

    Also gehen wir hier ganz langsam vor.

    Der Code aus PrettyOS (aktuell im Bootloader Second Stage):

    gdt_data:
    
    NULL_Desc:              ; null descriptor (necessary)
        dd    0
        dd    0
    
    CODE_Desc:
        dw    0xFFFF        ; segment length  bits 0-15 ("limit")
        dw    0             ; segment base    byte 0,1
        db    0             ; segment base    byte 2
        db    10011010b     ; access rights
        db    11001111b     ; bit 7-4: 4 flag bits:  granularity, default operation size bit,
                            ; 2 bits available for OS
                            ; bit 3-0: segment length bits 16-19
        db    0             ; segment base    byte 3
    
    DATA_Desc:
        dw    0xFFFF        ; segment length  bits 0-15
        dw    0             ; segment base    byte 0,1
        db    0             ; segment base    byte 2
        db    10010010b     ; access rights
        db    11001111b     ; bit 7-4: 4 flag bits:  granularity,
                            ; big bit (0=USE16-Segm., 1=USE32-Segm.), 2 bits avail.
                            ; bit 3-0: segment length bits 16-19
        db    0             ; segment base    byte 3
    
    CODE16_Desc:
        dw    0xFFFF
        dw    0
        db    0
        db    10011010b
        db    00001111b
        db    0
    
    end_of_gdt:
    
    ;....
    
    ;....
    
        cli
        mov eax, cr0                       ; bit 0 in CR0 has to be set for entering PM
        or al, 1
        mov cr0, eax
        jmp DWORD CODE_DESC:ProtectedMode  ; far jump to code selector (cs = 0x08)
    
    [Bits 32]
    ProtectedMode:
        mov ax, DATA_DESC                  ; set data segments to data selector (0x10)
        mov ds, ax
        mov ss, ax
        mov es, ax
        mov esp, 0x9000
    

    Diese Schritte sind notwendig:

    1. GDT anlegen (separate Datei GDT.inc)
    2. Laden des GDT-Register (GDTR) mit GDT-Adresse
    3. A20-Gate-Bit einschalten, damit kein 8086-kompatibler "wrap" der Speicher-Adressieruing erfolgt
    4. Protected Mode aktivieren: Setzen von Bit 0 ("PE-Bit") des Registers CR0
    5. Durchführen eines "FAR JMP" zur Leerung der "prefetch input queue" (PIQ)

    http://en.wikipedia.org/wiki/Protected_mode

    To enter protected mode, the Global Descriptor Table (GDT) must first be created with a minimum of three entries: a null descriptor, a code segment descriptor and data segment descriptor. The 21st address line (A20 line) also must be enabled to allow the use of all the address lines so that the CPU can access beyond 1 megabyte of memory (only the first 20 are allowed to be used after power-up to guarantee compatibility with older software). After performing those two steps, the PE bit must be set in the CR0 register and a far jump must be made to clear the prefetch input queue.

    ; set PE bit
    mov eax, cr0
    or eax, 1
    mov cr0, eax
    
    ; far jump (cs = selector of code segment)
    jmp cs:@pm
    
    @pm:
      ; Now we are in PM.
    

    Du kannst dir das genau in boot2.asm anschauen.



  • Achso jetzt verstehe ich das Ganze. Das Code- und Datensegment, steht ja an der physischen Adresse 0. Und daher kann ich ja einfach das Label als Offset nehmen, so stimmt die physikalische Adresse dran. Dachte die ganze Zeit das Segment fängt iwo im Speicher an, aber nicht bei 0:D

    Dann ist mir das ganze klar=)

    Vielen Dank

    Lg freeG

    EDIT: Allerdings habe ich noch eine kurze Frage zu dieser wrap around technik für den stack pointer. Wieso schreiben wir nicht einfach 0xFFC0 in sp sondern -0x40? Zudem entspricht FFC0 doch 63KB und nicht 63 byte?



  • Ich weiß zwar nicht genau, worauf du dich beziehst, aber ich nehme an, es ist ein 16-Bit-Offset. Die binäre Darstellung für ein 16-bittiges -0x40 ist genau 0xffc0 (Stichwort Zweierkomplement), das gibt also genau den gleichen Code und funktioniert nur wegen dem Wraparound.



  • taljeth schrieb:

    Ich weiß zwar nicht genau, worauf du dich beziehst, aber ich nehme an, es ist ein 16-Bit-Offset. Die binäre Darstellung für ein 16-bittiges -0x40 ist genau 0xffc0 (Stichwort Zweierkomplement), das gibt also genau den gleichen Code und funktioniert nur wegen dem Wraparound.

    Ja wieso dann so umständlich und nicht einfach mov sp, 0xFFC0? Wäre doch viel verständlicher oder nicht? Wie gehe ich eigentlich sicher, den Stack hoch genug angesetzt zu haben, dass nicht der Code oder andere Daten in ihn hineinwachsen?

    Lg freeG


  • Mod

    Die Belegung des memory muss man individuell planen. Irgendwo gibt es immer Grenzen. Der Stack wächst nach unten.



  • So schnell wie möglich in den PM wechseln, Paging einschalten und eine Guard Page benutzen. (Oder falls du zu den Abenteuerlustigen gehörst, auf Hochsprachen verzichtest und Segmentierung benutzt, halt das Stacksegment mit entsprechendem Limit setzen).


Anmelden zum Antworten