Page 1 of 1

Another Long Mode Paging Question

Posted: Thu Apr 15, 2010 12:05 pm
by proxy
So I've been toying with the self mapping trick in long mode and have been having trouble with the 4 levels of indirection and keep it all straight in my head. From my understanding, if I self map the PML4 in its own last entry I'll end up with a mapping that looks like this:

Code: Select all

pml4_address    = 0xfffffffffffff000;
pdp_address     = 0xffffffffffe00000;
pd_address      = 0xffffffffc0000000;
pt_address      = 0xffffff8000000000;
The math is really easy for the PML4 stuff. I simply do:

Code: Select all

pml4_address + ((address >> 39) & 0x1ff)
and I've got the address of the correct PML4 entry for that address. But it gets more confusing after that :-(.

What is the correct bit-twiddling for PDPs, PDs and PTs? If I've done my math right, each PD represents 1GB of address space. So would that mean that the PD for address 0x40001000 (1GB + 1 Page) would be at the 513th entry aka:

Code: Select all

0xffffff8000000000 + (512 * 8)
.

I think this is right, but it gets more confusing with PD and PDP entries.

Extending this, I might end up with this for the page table index:

Code: Select all

0xffffff8000000000 + (8 * (pt_offset + (pd_offset << 9) + (pdp_offset << 18) + (pml4_offset << 27)))


But that yields addresses like PT addresses like 0xfffffffffffffff8 for 0xfffffffffffff000 which can't be right, since it is out side of the possible page ranges. I feel like the gap between kernel/user addresses (positive/negative) is what's messing up my math. Do I need to special case the upper half ones?

Could someone help clarify the proper way to formulate the different parts? Thanks.

Re: Another Long Mode Paging Question

Posted: Thu Apr 15, 2010 12:58 pm
by proxy
I've been toying with the math, and I think that I may have actually had it correct. But I was using a poorly suited test case. So far the only addresses which give me values outside of the PT address at 0xffffff8000000000 are ones which are within the self mapping, which is invalid anyway.

It would be great if someone could reassure me that I'm right, but I think I'm on the right track.

Re: Another Long Mode Paging Question

Posted: Thu Apr 15, 2010 1:30 pm
by Owen
My suggestion is this:
Create an ENTRY_ADDR(_l4, _l3, _l2, _l1) macro (or inline function). This shouldn't be too difficult; just ors and bitshifts.

To find an PTE, you would provide all four values. To find a PDE, you would specify invoke as ENTRY_ADDR(0x1FF, pml4e, pdpte, pde). To find a PDPTE, you would invoke as ENTRY_ADDR(0x1FF, 0x1FF, pml4e, pdpte), and so on. You would probably want to define macros built on top of this to simplify things. It would also be advisable to make macros for getting indexes from addresses, and for getting the table responsible for a given address.

Remember than, when you modify a PDE (or higher level entry) you need to invtlb the recursive mapping addresses as well.

[Edit: I'm going to add that my ENTRY_ADDR macro was specified on top of a macro which took a given set of table indexes and converted them to the corresponding virtual address]