User:Johnburger/Demo/Boot/PM

From OSDev Wiki
Jump to navigation Jump to search

Well, it's been a long road. From the original BIOS Boot Sector load, a lot of work has been done to get things ready for Protected Mode. There's nothing left for it: time to load some registers and leap into the abyss!

The two most important registers that need to be set are the Global Descriptor Table Register (GDTR) and Control Register 0 (CR0). The former defines all the Global Descriptors, while the latter has the bit that sets the CPU into Protected Mode. But in my experience a third register needs to be set before entering Protected Mode: the Interrupt Descriptor Table Register (IDTR). That will ensure that there are immediate handlers for any fault that might occur during the transition.

Once in Protected Mode I made it difficult for myself because I didn't want to "clutter" the GDT with bootstrap code. So I made the Executive (the next port of call) have its own LDT, and put its code there. That means that as soon as the code enters Protected Mode, it needs to load the Local Descriptor Table Register (LDTR) with the correct LDT selector using the LLDT instruction. As soon as that happens though, it can JMP to the new code.

And by JMPing, we say goodbye to this Real Mode code. It has served its purpose and no longer has any use. It also happens to be laying slap bang in the middle of the (now) GDT - it needs to be jettisoned and (ultimately) overwritten.

Memory Map

After this code, the Memory Map will look like this:

Address Usage
0000_0000h Interrupt Vector Table
0000_0400h BIOS Data Area
0000_0500h Protected Mode Data
0000_0518h RAM Map from BIOS
0000_0800h Interrupt Descriptor Table
0000_1000h Loaded Protected Mode code
0000_1D70h Local Descriptor Table
0000_1DE0h Global Descriptor Table
0001_2E70h SS:SP-to-be Stack Top
0001_2E70h Available
0009_F###h Extended BIOS Data Area
000A_0000h Adapter / ROM Area
000B_8000h Text Video Memory
000F_0000h BIOS ROM
0010_0000h High Memory

Demo/Boot/PM.inc

;
; Boot/PM.inc
;

; This code does the final preparations before launching into Protected Mode.
; It loads GDTR, IDTR, switches to Protected Mode, loads LDTR then JMPs to the
; Executive.

Boot.LDT.Code   EQU             Selector(Exec.LDT.Code, LDT, RPL0)

Boot.PM:
                MOV             AX,GDT.Base >> 4 ; Point to GDT
                MOV             DS,AX
                LGDT            [GDT.Alloc.Pseudo]

                PUSH   DWORD    IDT.Base    ; Put on stack as Pseudo-descriptor
                PUSH    WORD    IDT.Limit   ; Only this many entries in IDT
                LIDT            [ESP]
; We're about to abandon the stack, so don't bother fixing it up!

; Can only load the LDTR after we've entered Protected Mode: this is the value
                MOV             BX,Selector(GDT.Exec.LDT, GDT, RPL0)

; Turn on Protected Mode (cross your fingers!)
                CLI                             ; Disable interrupts!
                MOV             EAX,CR0
                OR              AL,x86.CR0.PE
                MOV             CR0,EAX

; First, load the LDT
                LLDT            BX
; Then, launch code
                JMP             Boot.LDT.Code : DWORD Exec.Code

; This code is now unneeded. It can be overwritten by whatever the system wants