User:Johnburger/Demo/Boot/PM
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 JMP
ing, 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