The following code, moving from 32-bit protected mode (with A20 support) to 64-bit long mode, seems to give me problems. I have 1GiB card identification pages from 0x00000000 to 0x3fffffff; enable PAE; enable long bit in EFER MSR; install gdt; enable paging; and then execute the simulated FAR JMP for 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 crashes in BOCHS when executing a command RETF, but does not seem to return any errors. If I type info tabbefore this jump, I get:
0x00000000-0x3fffffff -> 0x000000000000-0x00003fffffff
It seems to me that paging works. This is the conclusion sreg:
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:
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:
The structure of my page table using 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 this could be a triple mistake?
Github