Page 1 of 1

64 bit paging 4 level pages (4kb)

Posted: Fri Jul 06, 2012 12:28 pm
by gabe
I'm hitting a brick wall setting up paging in 64bit with 4kb pages. Using 2MB pages...I have absolutely no problem. I've oversimplified my code to show what works and what doesn't...hopefully someone can point me in the right direction.

This code sets up 2MB pages and it works fine

Code: Select all

	u64 *pml, *pdp, *pd, *pt;

	pml = (u64 *)physmem_getpage();
	pdp = (u64 *)physmem_getpage();
	pd = (u64 *)physmem_getpage();

	memset((void*)pml, 0x0, PAGE_SIZE);
	memset((void*)pdp, 0x0, PAGE_SIZE);
	memset((void*)pd, 0x0, PAGE_SIZE);

// +3 = present & write
	pml[0] = ((u64)pdp) + 0x3;
	pdp[0] = ((u64)pd) + 0x3;
	pd[0] = ((u64)pt) + 0x3;


	for (int i = 0;i < 512;i++) {
		pd[i] = ((u64)i << 21) + 0x83;
	}

	asm volatile ("movq %0,%%cr3\n\t"
			"jmp 1f\n\t"
			"1:\n\t"
			"movq $2f, %%rax\n\t"
			"jmp *%%rax\n\t"
			"2:\n\t" ::"r"(pml):"memory","rax");
This code sets up 4kb pages (4 levels) and IMO should work...but does not, crashes the second I load CR3

Code: Select all

	u64 *pml, *pdp, *pd, *pt;

	pml = (u64 *)physmem_getpage();
	pdp = (u64 *)physmem_getpage();
	pd = (u64 *)physmem_getpage();
	pt = (u64 *)physmem_getpage();

	memset((void*)pml, 0x0, PAGE_SIZE);
	memset((void*)pdp, 0x0, PAGE_SIZE);
	memset((void*)pd, 0x0, PAGE_SIZE);
	memset((void*)pt, 0x0, PAGE_SIZE);

// +3 = present & write
	pml[0] = ((u64)pdp) + 0x3;
	pdp[0] = ((u64)pd) + 0x3;
	pd[0] = ((u64)pt) + 0x3;


	for (int i = 0;i < 512;i++) {
		pt[i] = ((u64)i << 12) + 0x3;
	}

	asm volatile ("movq %0,%%cr3\n\t"
			"jmp 1f\n\t"
			"1:\n\t"
			"movq $2f, %%rax\n\t"
			"jmp *%%rax\n\t"
			"2:\n\t" ::"r"(pml):"memory","rax");
Thanks.

Re: 64 bit paging 4 level pages (4kb)

Posted: Fri Jul 06, 2012 12:40 pm
by bluemoon

Code: Select all

   memset((void*)pml, 0x0, PAGE_SIZE);
   memset((void*)pdp, 0x0, PAGE_SIZE);
   memset((void*)pd, 0x0, PAGE_SIZE);

// +3 = present & write
   pml[0] = ((u64)pdp) + 0x3;
   pdp[0] = ((u64)pd) + 0x3;
   pd[0] = ((u64)pt) + 0x3;

Note the above code uses pml/pdp/pd for both logical address(when accessing array) and physical address(filling page structures)
It only work if the memory is identity mapped.

And then, how does it crash? When dealing with paging I strongly recommend all sort of debug tool, including bochs-debugger or qemu+gdb(not quite work well with 64bit). bochs will tell you exactly what's wrong most of the time.

Re: 64 bit paging 4 level pages (4kb)

Posted: Fri Jul 06, 2012 12:44 pm
by gabe
yes, this is identity mapping, I understand that. Like I said, I just wrote that to oversimplify my code to find what's wrong.

Re: 64 bit paging 4 level pages (4kb)

Posted: Fri Jul 06, 2012 1:39 pm
by jbemmel
Which register does gcc choose for loading CR3 in both cases? IIRC only eax can be used?

Re: 64 bit paging 4 level pages (4kb)

Posted: Fri Jul 06, 2012 1:48 pm
by jnc100
Your first example identity maps the first 1 GiB, your second example only identity maps the first 2 MiB. Are you sure the mov to cr3 code is located within the first 2 MiB?

Regards,
John.

Re: 64 bit paging 4 level pages (4kb)

Posted: Fri Jul 06, 2012 2:44 pm
by gabe
Thanks for the help.

Turns out my stack was outside the first 2mb that is identity mapped (compared to 1gig) which caused it to crash.

duhhhhhhhh... (always a stupid problem)

Re: 64 bit paging 4 level pages (4kb)

Posted: Fri Jul 06, 2012 3:18 pm
by xenos
jbemmel wrote:Which register does gcc choose for loading CR3 in both cases? IIRC only eax can be used?
Nope, you can use any 64 bit register from RAX to R15 in 64 bit mode (and any 32 bit register in 32 bit mode).