OSDev Wiki paging code
Posted: Fri May 05, 2017 11:22 pm
Hello.
There's a strange thing in the Paging wiki page code in the "Manipulation" section. (http://wiki.osdev.org/Paging#Manipulation)
Isn't that calculation wrong? I thought (0x400 * pdindex) should be (0x1000 * pdindex) because each page table is one page long in that mapping.
Also it gives wrong addresses. The last page table's address is in this calculation:
0xFFC00000 + (0x400 * 1023) = 0xFFCFFC00
Using 0x1000 instead of 0x400 gives the correct address:
0xFFC00000 + (0x1000 * 1023) = 0xFFFFF000
If it's correct, could you explain why the calculation is (0x400 * pdindex), please?
Thanks in advance.
Edit: I forgot taking care about (unsigned long*), fixed.
A really noobish mistake, maybe I should sleep more
There's a strange thing in the Paging wiki page code in the "Manipulation" section. (http://wiki.osdev.org/Paging#Manipulation)
The CR3 value, that is, the value containing the address of the page directory, is in physical form. Once, then, the computer is in paging mode, only recognizing those virtual addresses mapped into the paging tables, how can the tables be edited and dynamically changed?
Many prefer to map the last PDE to itself. The page directory will look like a page table to the system. To get the physical address of any virtual address in the range 0x00000000-0xFFFFF000 is then just a matter of:
To map a virtual address to a physical address can be done as follows:Code: Select all
void * get_physaddr(void * virtualaddr) { unsigned long pdindex = (unsigned long)virtualaddr >> 22; unsigned long ptindex = (unsigned long)virtualaddr >> 12 & 0x03FF; unsigned long * pd = (unsigned long *)0xFFFFF000; // Here you need to check whether the PD entry is present. unsigned long * pt = ((unsigned long *)0xFFC00000) + (0x400 * pdindex); // Here you need to check whether the PT entry is present. return (void *)((pt[ptindex] & ~0xFFF) + ((unsigned long)virtualaddr & 0xFFF)); }
Unmapping an entry is essentially the same as above, but instead of assigning the pt[ptindex] a value, you set it to 0x00000000 (i.e. not present). When the entire page table is empty, you may want to remove it and mark the page directory entry 'not present'. Of course you don't need the 'flags' or 'physaddr' for unmapping.Code: Select all
void map_page(void * physaddr, void * virtualaddr, unsigned int flags) { // Make sure that both addresses are page-aligned. unsigned long pdindex = (unsigned long)virtualaddr >> 22; unsigned long ptindex = (unsigned long)virtualaddr >> 12 & 0x03FF; unsigned long * pd = (unsigned long *)0xFFFFF000; // Here you need to check whether the PD entry is present. // When it is not present, you need to create a new empty PT and // adjust the PDE accordingly. unsigned long * pt = ((unsigned long *)0xFFC00000) + (0x400 * pdindex); // Here you need to check whether the PT entry is present. // When it is, then there is already a mapping present. What do you do now? pt[ptindex] = ((unsigned long)physaddr) | (flags & 0xFFF) | 0x01; // Present // Now you need to flush the entry in the TLB // or you might not notice the change. }
Code: Select all
unsigned long * pt = ((unsigned long *)0xFFC00000) + (0x400 * pdindex);
Also it gives wrong addresses. The last page table's address is in this calculation:
0xFFC00000 + (0x400 * 1023) = 0xFFCFFC00
Using 0x1000 instead of 0x400 gives the correct address:
0xFFC00000 + (0x1000 * 1023) = 0xFFFFF000
If it's correct, could you explain why the calculation is (0x400 * pdindex), please?
Thanks in advance.
Edit: I forgot taking care about (unsigned long*), fixed.
A really noobish mistake, maybe I should sleep more