Stuck with paging

Programming, for all ages and all languages.
Post Reply
heemogoblin
Posts: 13
Joined: Sat Jun 27, 2020 8:00 am
Libera.chat IRC: heemogoblin

Stuck with paging

Post 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
nexos
Member
Member
Posts: 1081
Joined: Tue Feb 18, 2020 3:29 pm
Libera.chat IRC: nexos

Re: Stuck with paging

Post 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.
"How did you do this?"
"It's very simple — you read the protocol and write the code." - Bill Joy
Projects: NexNix | libnex | nnpkg
Octocontrabass
Member
Member
Posts: 5568
Joined: Mon Mar 25, 2013 7:01 pm

Re: Stuck with paging

Post 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.)
heemogoblin
Posts: 13
Joined: Sat Jun 27, 2020 8:00 am
Libera.chat IRC: heemogoblin

Re: Stuck with paging

Post 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
linguofreak
Member
Member
Posts: 510
Joined: Wed Mar 09, 2011 3:55 am

Re: Stuck with paging

Post 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.
heemogoblin
Posts: 13
Joined: Sat Jun 27, 2020 8:00 am
Libera.chat IRC: heemogoblin

Re: Stuck with paging

Post 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
Octocontrabass
Member
Member
Posts: 5568
Joined: Mon Mar 25, 2013 7:01 pm

Re: Stuck with paging

Post 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?
heemogoblin
Posts: 13
Joined: Sat Jun 27, 2020 8:00 am
Libera.chat IRC: heemogoblin

Re: Stuck with paging

Post 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
Octocontrabass
Member
Member
Posts: 5568
Joined: Mon Mar 25, 2013 7:01 pm

Re: Stuck with paging

Post 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.
heemogoblin
Posts: 13
Joined: Sat Jun 27, 2020 8:00 am
Libera.chat IRC: heemogoblin

Re: Stuck with paging

Post 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
Octocontrabass
Member
Member
Posts: 5568
Joined: Mon Mar 25, 2013 7:01 pm

Re: Stuck with paging

Post 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.
Post Reply