I have a subroutine 'switch32' on my bootloader which is supposed to make the transition to 32 bit protected mode, however the lgdt
instruction seems to be causing trouble. Here is the code for
"switch32.asm":
gdt_start:
gdt_null:
dq 0x0
gdt_code:
dw 0xFFFF ;Lower 16 bits of limit
dw 0x0000 ;Lower 16 bits of base address
db 0x00 ;Middle 8 bits of base address
db 10011010b;Access byte: present=1,privilege=00,type=1,exec=1,comform=0,read=1,acc=0
db 0100111b ;High 4 bits = flags, Low 4 bits = last nibble of limit (20 bits)
db 0x00 ;Higher 8 bits of base address (32 bits)
gdt_data:
dw 0xFFFF ;Lower 16 bits of limit
dw 0x0000 ;Lower 16 bits of base address
db 0x00 ;Middle 8 bits of base address
db 10010010b;Access byte: present=1,privilege=00,type=1,exec=0,dir=0,write=1,acc=0
db 0100111b ;High 4 bits = flags, Low 4 bits = last nibble of limit (20 bits)
db 0x00 ;Higher 8 bits of base address (32 bits)
gdt_end:
gdtr_data: ;The data to pass to the GDTR register (lower word=size of GDT, higher dword=address of GDT)
dw gdt_end - gdt_start - 1 ;16 bit size of GDT
dd gdt_start ;Address to start of GDT
CODE_SEGMENT equ gdt_code - gdt_start ;Index of code segment descriptor
DATA_SEGMENT equ gdt_data - gdt_start ;Index of data segment descriptor
switch32:
pusha
cli ;Disable interrupts
lgdt [gdtr_data]
;Set first bit (protected mode enable) in control register 0
mov eax,cr0
or eax,0x1
mov cr0,eax
jmp CODE_SEGMENT:post_flush ; 'fake' far jump to trick CPU into flushing pipeline to prevent nasty exceptions
; according to intel manual, CS register is implicitly set to far JMP's selector
post_flush:
[bits 32]
mov eax,DATA_SEGMENT
mov ds,eax
mov ss,eax
mov es,eax
mov fs,eax
mov gs,eax
popa
ret
I'm using qemu and whenever the subroutine is called, the screen starts blinking and nothing past the lgdt
instruction is executed, I'm pretty sure that means there is a CPU error. The error is coming from the lgdt
instruction but i'm clueless as to why. Am I passing the right data to the GDTR register? or is my entire GDT set up wrong?
I'm using the intel i386 programmer manual and the osdev wiki article on the Global Descriptor Table as resources and I set up my GDT according to what I've read.