The following code that transitions from 32-bit protected mode (with A20 enabled) to 64-bit longmode seems to be giving me issues. I identity map the 1GiB page from 0x00000000 to 0x3fffffff; enable PAE; enable the longmode bit in the EFER MSR; install a GDT; enable paging; and then do a simulated FAR JMP to my 64-bit entry point:
lea eax, [PML4]
mov cr3, eax
mov eax, cr4
or eax, 100000b
mov cr4, eax
mov ecx, 0xc0000080
rdmsr
or eax, 100000000b
wrmsr
mov eax, cr0
mov ebx, 0x1
shl ebx, 31
or eax, ebx
mov cr0, eax
call gdt64_install
push 8
push longmode
retf ;<===================== faults here
The program triple faults in BOCHS when the RETF
instruction is executed but doesn't seem to return any error. If i type info tab
before this jump I get:
0x00000000-0x3fffffff -> 0x000000000000-0x00003fffffff
It appears to me paging is working. This is sreg
output:
es:0x0010, dh=0x00cf9300, dl=0x0000ffff, valid=1
Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
cs:0x0008, dh=0x00cf9b00, dl=0x0000ffff, valid=1
Code segment, base=0x00000000, limit=0xffffffff, Execute/Read, Non-Conforming, Accessed, 32-bit
ss:0x0010, dh=0x00cf9300, dl=0x0000ffff, valid=31
Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
ds:0x0010, dh=0x00cf9300, dl=0x0000ffff, valid=31
Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
fs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1
Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
gs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1
Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
ldtr:0x0000, dh=0x00008200, dl=0x0000ffff, valid=1
tr:0x0000, dh=0x00008b00, dl=0x0000ffff, valid=1
gdtr:base=0x0000000000008252, limit=0x1f
idtr:base=0x0000000000000000, limit=0x3ff
My GDT entry is:
gdt64_install:
lgdt[GDT_addr]
ret
GDT_addr:
dw (GDT64_end - GDT64) - 1
dd GDT64
GDT64:
dd 0, 0
dd 0xffff ; segment limit
dd 0xef9a00
dd 0xffff ; segment limit
dd 0xef9200
dd 0, 0
GDT64_end:
My page table structure using a PML4 and PDP is defined as:
align 4096 ;;align to 4 KB
PML4:
dq 0 or 1b or 10b or PDP;;preset bit, r/w bit
dq 511 dup(PDP or 10b)
PDP:
dq 0 or 1b or 10000000b ;;dq zero, because we map memory from start so 0x0000, present bit
;;PDPE.PS to indicate 1gb pages
dq 511 dup(10000000b)
Any ideas why it might be triple faulting?
A copy of my project can be found on Github