I'm writing a simple home-made 64-bit OS, booting it via UEFI. This means that when my code starts executing, it is already in long mode, with paging enabled.
Now, after exiting the UEFI boot services, I want to replace all control structures built by UEFI with my own.
After successfully changing the contents of CR3 (paging structures), I successfully loaded a new GDT using lgdt
.
The problem is that now, to correctly use this new GDT, I need to move a new value into CS. Online I found lots of tutorials on how to do that while switching from 32-bit to 64-bit, but almost nothing about long mode to long mode.
I think I should use a far jump, but I didn't manage to do that with this code (AT&T syntax):
mov %rax, %cr3 # load paging structures (it works)
lgdt 6(%rcx) # load gdt (it works)
mov $100, %rsp # update stack pointer (it works)
# now what I tried unsuccessfully:
pushw $8 # new code segment selector
pushq fun # function to execute next
retfq # far return (pops address and code segment)
Not having any IDT in place, this code triple faults at retfq
.
EDIT: I checked my paging structures, and I'm quite sure they are not the cause of the problems. In fact, the code runs fine without the last three instructions. The problem is that I need a way to update the CS, that in my code still refers to the old segment built by UEFI. Is retfq
the correct way of doing this? Or which other instruction should I use?
Thanks in advance.