Page 1 of 1

QEMU page faults upon mov edx, imm32

Posted: Sat Dec 07, 2024 7:55 am
by restingwitchface
I'm working on adding paging to my kernel which has so far been working well with physical addresses. I'm basing it off off the x86 Higher Half tutorial, but I'm writing the assembly code myself, as I want the simpler scheme of just mapping the first 8 MiB to the higher quarter, 0x00xxxxxx to 0xC0xxxxxx. The linker script puts the main .text section, which contains ISRs and C code, at virtual offset +0xC0000000, and we put the paging bootstrap code in a separate .multiboot.text section, as in the tutorial.

My code reads as follows:

Code: Select all

.section .bss
.global stack_top
.align 16

stack_bottom:
	.skip 16384
stack_top:

.align 4096

boot_pd:
	.skip 4096
boot_pt:
	.skip 4096

.section .multiboot.text, "a"
.global _start
.type _start, @function
_start:
	/* Place the page table in the page directory; it should be the 768'th page table out of 1024 */
	movl $(boot_pt - 0xC0000000), %esi
	movl $(boot_pd - 0xC0000000), %edi
	orl $0x3, %esi
	movl %esi, 0xC00(%edi)
	
	/* Map 0x00XXXyyy to 0xC0XXXyyy for all X from 0 to 0x3FF (first 4 MiB of physmem) */
	movl $0, %ecx
	movl %esi, %edi
	andl $0xFFFFFFFC, %edi
1:
	cmpl $0x3FF, %ecx
	jg 2f
	/* The entry in the page table is boot_pt - 0xC0000000 + 4 * %ecx, our page is 4096 * %ecx */
	movl %ecx, %esi
	shll $12, %esi
	orl $0x3, %esi
	movl %esi, (%edi, %ecx, 4)
	incl %ecx
	jmp 1b

2:
	/* Tell them where our page directory is and enable CR0's PG bit */
	movl $(boot_pd - 0xC0000000), %edi
	movl %edi, %cr3
	movl %cr0, %edx
	orl $0x80000000, %edx
	movl %edx, %cr0
	movl $kernel_begin, %edx
	jmp *%edx

.size _start, . - _start

.section .text
kernel_begin:
	[... set up stack and enter C kernel ...]
I've figured out how to combine the QEMU monitor - internal debugger - with gdb, which is quite useful. QEMU doesn't complain when I boot this as it did when I hadn't gotten the linker script quite right ("PVH ELF note" etc). A page fault occurs at address 0x201047, which is the

Code: Select all

movl $kernel_begin, %edx
instruction.

The monitor's logs aren't much more than those obtained by -d int. Both using gdb to inspect the memory at CR3 and using the monitor's info mem and info tlb commands shows that the desired mapping is present, read-write. So why on earth does moving an immediate into EDX page fault? Screenshots attached.

Re: QEMU page faults upon mov edx, imm32

Posted: Sat Dec 07, 2024 8:26 am
by MichaelPetch
just mapping the first 8 MiB
Your code is currently only mapping the first 4MiB.

You will also need to identity map the range 0x00000000-0x00400000 to physical address 0x00000000-0x00400000. Once you are in the higher half and finished using lower half addresses you can remove the identity mapping to the lower half. When you flip on paging by changing CR0 the next instruction is still executing in the lower half until you jump to the higher half which is why you need to identity map the lower half to make the paging switch work.

Side note: since this is Multiboot be aware that if you intend to pass the Multiboot info structure to your kernel it will be using lower half addresses so you will need to keep the lower half mapped until after you have processed the Multiboot structure so that the Multiboot pointers don't cause a page fault.

Re: QEMU page faults upon mov edx, imm32

Posted: Sat Dec 07, 2024 8:36 am
by restingwitchface
> Your code is currently only mapping the first 4MiB.
Oops, typo. Pretty sure that's fine though, no?

> the next instruction is still executing in the lower half until you jump to the higher half which is why you need to identity map the lower half to make the paging switch work.
Thanks.

> be aware that if you intend to pass the Multiboot info structure to your kernel it will be using lower half addresses so you will need to keep the lower half mapped
Yeah, I thought so. I'm hoping to just get to the kernel entry point, then patch up any bad pointers on my own.

Re: QEMU page faults upon mov edx, imm32

Posted: Sat Dec 07, 2024 8:40 am
by restingwitchface
Alright, it works! Thanks, I probably should have realized that the page fault was because of instruction fetch, not the execution of those instructions. For now I've duplicated the page table in the page directory, time to unmap it.

Re: QEMU page faults upon mov edx, imm32

Posted: Sat Dec 07, 2024 8:57 am
by MichaelPetch
restingwitchface wrote: Sat Dec 07, 2024 8:36 am Oops, typo. Pretty sure that's fine though, no?
It is (as long as your kernel is <= 2MiB in size), I was just pointing it out.
Yeah, I thought so. I'm hoping to just get to the kernel entry point, then patch up any bad pointers on my own.
That works too.