OSDev Wiki paging code

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
Agola
Member
Member
Posts: 155
Joined: Sun Nov 20, 2016 7:26 am
Location: Somewhere

OSDev Wiki paging code

Post by Agola »

Hello.

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:

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));
}
To map a virtual address to a physical address can be done as follows:

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.
}
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

unsigned long * pt = ((unsigned long *)0xFFC00000) + (0x400 * pdindex);
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 :|
Last edited by Agola on Fri May 05, 2017 11:54 pm, edited 1 time in total.
Keyboard not found!

Press F1 to run setup.
Press F2 to continue.
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: OSDev Wiki paging code

Post by iansjack »

User avatar
Agola
Member
Member
Posts: 155
Joined: Sun Nov 20, 2016 7:26 am
Location: Somewhere

Re: OSDev Wiki paging code

Post by Agola »

iansjack wrote:https://www.tutorialspoint.com/cprogramming/c_pointer_arithmetic.htm

Code: Select all

((unsigned long*) 0xFFC00000) + (0x400 * pdindex);
Ah, I forgot taking care about (unsigned long*) before calculating. Such a noobish mistake. Maybe I should sleep more.
Even after thinking this about 2 hours, how couldn't I see it.

That code in my os is like:

Code: Select all

(uint32_t*) (0xFFC00000 + (0x1000 * pdindex))
Probably that's why I couldn't see it :|
Keyboard not found!

Press F1 to run setup.
Press F2 to continue.
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: OSDev Wiki paging code

Post by iansjack »

I think it's a mistake that catches everyone out from time to time. It's certainly bitten me a few times.
Post Reply