Page 1 of 1
Stuck with paging
Posted: Sat Oct 10, 2020 2:27 am
by heemogoblin
Dear all,
I am writing a bootloader which boots off UEFI which requires paging to be able to load the kernel. It is built with msvc and yasm. I have set up page tables and everything, and have got functions to map virtual addresses and set attributes, but my OS hangs after I try writing the PML4 table address to cr3(assembly). I think it triple faults, somewhere in the virtualbox log it says 'VM_ERR_TRIPLE_FAULT' or something and enters 'Guru meditation'.
Also, I am not completely sure I am doing paging correct. There isn't much example code that I can use but I have made use of what I have managed to find.
Here is my code:
https://pastebin.com/hQQmPC3j (it's quite big)
Here is some assembly I use:
Code: Select all
global get_paging_root
get_paging_root:
mov rax, cr3
ret
global set_paging_root
set_paging_root:
mov cr3, rcx
ret
global read_cr0
read_cr0:
mov rax, cr0
ret
global write_cr0
write_cr0:
mov cr0, rcx
ret
global enable_pae
enable_pae:
mov rax, 1
shl rax, 4
mov rbx, cr4
or rbx, rax
mov cr4, rbx
ret
global write_cr3
write_cr3:
mov cr3, rcx
ret
global get_cr4
get_cr4:
mov rax, cr4
ret
global tlbflush
tlbflush:
invlpg [rcx]
ret
global memory_barrier
memory_barrier:
mfence
ret
Could anyone please tell me why my OS hangs and meditates? Could anyone also confirm I am doing paging correctly?
Apologies for being so naive, but I shall be very grateful if anyone could help me.
Thank you very much,
Heemogoblin
Re: Stuck with paging
Posted: Sat Oct 10, 2020 6:21 am
by nexos
You put an empty PML4 in CR3. You need to identity map all memory if you have not called ExitBootServices. I still recommend in the bootloader using the page tables EFI set up in the bootloader. Then simply map addresses above the identity map.
Re: Stuck with paging
Posted: Sat Oct 10, 2020 4:36 pm
by Octocontrabass
heemogoblin wrote:I think it triple faults, somewhere in the virtualbox log it says 'VM_ERR_TRIPLE_FAULT' or something and enters 'Guru meditation'.
Perhaps take a closer look at that log. It might tell you where things are going wrong, and give you useful information to help you figure out why. (And it doesn't hurt to try another VM, like QEMU with "-d int", to see if it gives you better information.)
Re: Stuck with paging
Posted: Sun Oct 11, 2020 12:57 am
by heemogoblin
nexos wrote:You put an empty PML4 in CR3. You need to identity map all memory if you have not called ExitBootServices. I still recommend in the bootloader using the page tables EFI set up in the bootloader. Then simply map addresses above the identity map.
Thank you for your reply, but I still have a couple of questions, could you please answer them for me?
Firstly, could you confirm that this means that I just go through the EFI_MEMORY_MAP and just paging_map all of the descriptors?
Secondly, if all my page frames are mapped, then what do I do for a page frame allocator or do I not need one?
Lastly, I read about recursive mapping, and do I need to recursively map or can I get away with not doing it? If I do need to do it, do I override the physical memory page entries?
Thank you for your answer, I shall be very grateful if you could answer these questions for me.
Thank you very much,
Heemogoblin
Re: Stuck with paging
Posted: Sun Oct 11, 2020 4:32 am
by linguofreak
heemogoblin wrote:nexos wrote:You put an empty PML4 in CR3. You need to identity map all memory if you have not called ExitBootServices. I still recommend in the bootloader using the page tables EFI set up in the bootloader. Then simply map addresses above the identity map.
Thank you for your reply, but I still have a couple of questions, could you please answer them for me?
Firstly, could you confirm that this means that I just go through the EFI_MEMORY_MAP and just paging_map all of the descriptors?
It means that you probably shouldn't touch CR3 until you call ExitBootServices. You also shouldn't touch any entry in the PML4, or any entry in any PDPT, page directory, or page table that already has its valid bit set. EFI has already set up an identity mapping for you, so you shouldn't change any mapping that is already in place. If you need to make your own mappings, you can do them in regions that are above the highest address of physical memory (and thus aren't mapped in the identity mapping).
Secondly, if all my page frames are mapped, then what do I do for a page frame allocator or do I not need one?
It very much depends on how you want to structure your bootloader. You could just run within the existing identity mapping set up by EFI, in which case you don't need one at all (for the bootloader).
Lastly, I read about recursive mapping, and do I need to recursively map or can I get away with not doing it? If I do need to do it, do I override the physical memory page entries?
You don't need to do recursive mapping, and probably should not be trying to do it in your bootloader (especially before calling ExitBootServices). It's more a concern for your OS once it's running by itself.
Re: Stuck with paging
Posted: Thu Nov 05, 2020 1:43 pm
by heemogoblin
Dear all,
Thank you for your help. However I am still stuck. I have managed to get EFI's page tables, and now my paging_init() relocates the entries so they point to my page tables instead. Valid entries are used to find the next table. Also I clear the WP bit in cr0. However when I try to put the PML4 base address back in, I still get a triple fault/guru meditation. Looking at vbox's log, I see that my PML4 base address has been correctly placed in cr3.
Can anyone tell me what is going on please and what I could do to ease the problem?
Code:
https://pastebin.com/MxkyLezD
VBox log:
https://pastebin.com/tTtU4LbD
Thanks in advance,
Heemogoblin
Re: Stuck with paging
Posted: Thu Nov 05, 2020 3:38 pm
by Octocontrabass
According to the log, it triple faulted because it wasn't able to load the IDT entry for the double fault handler. The log also says it was executing in unmapped memory, so that's probably what caused the initial fault.
You did call ExitBootServices(), right?
Re: Stuck with paging
Posted: Fri Nov 06, 2020 1:32 am
by heemogoblin
Octocontrabass wrote:According to the log, it triple faulted because it wasn't able to load the IDT entry for the double fault handler. The log also says it was executing in unmapped memory, so that's probably what caused the initial fault.
You did call ExitBootServices(), right?
I do call ExitBootServices(). Why would the area be unmapped? Does that mean I have to identity map all of memory before calling ExitBootServices()?
Thanks in advance,
Heemogoblin
Re: Stuck with paging
Posted: Fri Nov 06, 2020 11:15 am
by Octocontrabass
heemogoblin wrote:Why would the area be unmapped?
Good question. You should examine the contents of your new page tables just before you write CR3 to see what's wrong with them.
heemogoblin wrote:Does that mean I have to identity map all of memory before calling ExitBootServices()?
No. The firmware is in charge of the page tables before you call ExitBootServices(), and the firmware guarantees that all usable memory will be identity mapped afterwards.
Re: Stuck with paging
Posted: Sun Nov 08, 2020 5:03 am
by heemogoblin
Thank you for your reply,
I have noticed that when I relocate my page entries, the bits are being set incorrectly. However it is being very strange. For example, when I do entry & 0b1, even if the last bit is set, this still gives 0. So I changed everything to be u64s not bit fields, but now when I clear the table base address with entry &= 0b1111111111110000000000000000000000000000000000000000111111111111, the entry results to 0 regardless of the bits. Then when I try to | the page table address, it still is 0. However, If i do not & the entry but only | it, then I am able to correctly modify bits.
Is this my bad coding or just undefined behaviour? Any answers will be very grateful, doing | all the time is not so safe as it could leave old bits.
Code:
https://pastebin.com/uM7pXyxu
Thanks in advance,
Heemogoblin
Re: Stuck with paging
Posted: Sun Nov 08, 2020 3:28 pm
by Octocontrabass
heemogoblin wrote:Is this my bad coding or just undefined behaviour?
You're casting a whole lot of pointers to integers and vice-versa, so it could be undefined behavior.
Can you narrow down the issue at all? For example, by trimming down the code to a minimal example of the problem, or by stepping through the code with a debugger to see where it stops making sense.