I was just reading the other post when I came across this Wiki article. Let me go through it.
The program needs to go through the following steps:
Disable the interrupts:
Turn off maskable interrupts using CLI.
Disable NMI (optional).
Turn off paging:
Transfer control to a 1:1 page.
Ensure that the GDT and IDT are in a 1:1 page.
Clear the PG-flag in the zeroth control register.
Set the third control register to 0.
Use GDT with 16-bit tables (skip this step if one is already available):
Create a new GDT with a 16-bit data and code segment:
Limit: 0xFFFFF
Base: 0x0
16-bit
Privilege level: 0
Granularity: 0
Read and Write: 1
Load new GDT ensuring that the currently used selectors will remain the same (index in cs/ds/ss will be copy of original segment in new GDT)
Far jump to 16-bit protected mode:
Far jump to 16-bit protected mode with a 16-bit segment index.
Load data segment selectors with 16-bit indexes:
Load ds, es, fs, gs, ss with a 16-bit data segment.
Load real mode IDT:
Limit: 0x3FF
Base 0x0
Use lidt
Disable protected mode:
Set PE bit in CR0 to false.
Far jump to real mode:
Far jump to real mode with real mode segment selector (usually 0).
Reload data segment registers with real mode values:
Load ds, es, fs, gs, ss with appropriate real mode values (usually 0).
Set stack pointer to appropriate value:
Set sp to stack value that will not interfere with real mode program.
Enable interrupts:
Enable maskable interrupts with STI.
Continue on in real mode with all bios interrupts.
First of all, it is missing the most important step. And that is, to restore the hardware to the default configuration. More importantly, this includes remapping the IRQ to their default vectors (real mode).
Next,
Code: Select all
[bits 16]
idt_real:
dw 0x3ff ; 256 entries, 4b each = 1K
dd 0 ; Real Mode IVT @ 0x0000
savcr0:
dd 0 ; Storage location for pmode CR0.
Entry16:
; We are already in 16-bit mode here!
cli ; Disable interrupts.
; Need 16-bit Protected Mode GDT entries!
mov eax, DATASEL16 ; 16-bit Protected Mode data selector.
mov ds, eax
mov es, eax
mov fs, eax
mov gs, eax
; Disable paging (we need everything to be 1:1 mapped).
mov eax, cr0
mov [savcr0], eax ; save pmode CR0
and eax, 0x7FFFFFFe ; Disable paging bit & enable 16-bit pmode.
mov cr0, eax
jump 0:GoRMode ; Perform Far jump to set CS.
GoRMode:
mov sp, 0x8000 ; pick a stack pointer.
mov ax, 0 ; Reset segment registers to 0.
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
lidt [idt_real]
sti ; Restore interrupts -- be careful, unhandled int's will kill it.
Finally,
switching from protected mode to real mode isn't that straight-forward. Most of us like to play with keyboard when we first start our OS. This shouldn't cause much problem when making Protected Mode -> Real Mode transition. But when we gradually go on adding hardware support(which means drivers) to our OS, our hardware devices seem to behave strange when making this transition. I've succesfully resolved some of those issues by reverting the hardware to the original configuration, but still some of the drivers are causing nightmare.
I hope to see that article updated(can't do myself).
Feel free to fire compliments.
Best Regards,
Chandra