Page 1 of 1

How do you get physical frames

Posted: Sun Jun 07, 2020 6:09 am
by nexos
Hello,
In my quest to improve my paging code, I now need to figure how to obtain physical address of pages. I have seen some examples, but they don't work. What is the best way to get physical frames? Thank you for your help.

Re: How do you get physical frames

Posted: Sun Jun 07, 2020 6:36 am
by heat
Well, first off, you need to parse the memory map that's given to you (or that you need to get yourself, if you're also writing the bootloader) and then you just take the ranges that are free and organise them with data structures so you can keep track of allocated/free pages.

You've got a lot of types of allocators, but I strongly recommend a linked list of pages, for the single reason that the most common allocation by far will be of a single page; you've also got other ones, like buddy allocators (which is used by linux), that handle contiguous physical memory allocation nicely; they're usually much slower on the common 4KB allocation case though.

Note that you'll likely need to allocate memory for the physical memory allocator itself; usually you need some special boot memory allocation routines, which may as well be simple enough that you just manipulate the memory map data structures themselves.

Re: How do you get physical frames

Posted: Sun Jun 07, 2020 7:08 am
by nexos
I know how to allocate physical memory, I was wondering how to get the physical frame from a PTE or PDE

Re: How do you get physical frames

Posted: Sun Jun 07, 2020 8:07 am
by iansjack
It tells you in the PTEs.

Re: How do you get physical frames

Posted: Sun Jun 07, 2020 1:41 pm
by thewrongchristian
nexos wrote:I know how to allocate physical memory, I was wondering how to get the physical frame from a PTE or PDE
For x86 none-PAE, the PTE/PDE simply contains the physical address, with the lower bits of the address replaced by the page meta-data. So, just read the PTE, and mask off the lower 12 bits, and that gives you the physical address.

Re: How do you get physical frames

Posted: Sun Jun 07, 2020 4:23 pm
by nexos
I have come up with a routine that finds the physical address, but it doesn't work. Here it is:

Code: Select all

uint32_t get_physical_address (pdirectory* dir_phys, uint32_t virt)
{
    pdirectory* temp = get_directory();
    pdirectory* dir = (pdirectory*)0xFFFFF000;
    pde* e = &dir->entries[PAGE_DIRECTORY_INDEX(virt)];
    ptable* table = 0;

    if((*e & PDE_PRESENT) != PDE_PRESENT)
    {
        return 0;
    }
    table = (ptable*)(0xFFC00000 + (PAGE_DIRECTORY_INDEX(virt) * 4096));
    pte* entry = &table->entries[PAGE_TABLE_INDEX(virt)];
    if((*entry & PTE_PRESENT) != PTE_PRESENT)
    {
        return 0;
    }
    switch_dir(temp);
    return (*entry & 0x7FFFF000);
}

Re: How do you get physical frames

Posted: Wed Jun 10, 2020 8:27 am
by thewrongchristian
nexos wrote:I have come up with a routine that finds the physical address, but it doesn't work. Here it is:

Code: Select all

uint32_t get_physical_address (pdirectory* dir_phys, uint32_t virt)
{
    pdirectory* temp = get_directory();
    pdirectory* dir = (pdirectory*)0xFFFFF000;
    pde* e = &dir->entries[PAGE_DIRECTORY_INDEX(virt)];
    ptable* table = 0;

    if((*e & PDE_PRESENT) != PDE_PRESENT)
    {
        return 0;
    }
    table = (ptable*)(0xFFC00000 + (PAGE_DIRECTORY_INDEX(virt) * 4096));
    pte* entry = &table->entries[PAGE_TABLE_INDEX(virt)];
    if((*entry & PTE_PRESENT) != PTE_PRESENT)
    {
        return 0;
    }
    switch_dir(temp);
    return (*entry & 0x7FFFF000);
}
I see at least 3 different pointers to a page directory, and you're using only one of them. You're not using what's passed in, and you're not using what's returned from get_directory(). You're best off cleaning up unused stuff which makes it easier for you as well as others trying help you.

You're initialising table incorrectly. You've check the directory is present, so you know the virtual page number has a backing page table, so you can use the VPN as the index into table directly. So you'd want something like:

Code: Select all

    pte* table = (pte*)0xFFC00000;
    pte* entry = table+(virt>>12);

Re: How do you get physical frames

Posted: Wed Jun 10, 2020 8:51 am
by bzt
nexos wrote:I have come up with a routine that finds the physical address, but it doesn't work.
Your code reads linear addresses. Paging tables contain physical addresses. You have to map each table to a known location if you want to read it. Also, I'm not sure what "table->entires" does, paging table is not a structure, just a simple array of 1024 uint32_ts (or 512 uint64_ts in long mode).

Code: Select all

uint32_t *entries = (uint32_t*)0xFFC00000; /* some fixed location in the virtual memory, page aligned */

/* VERY IMPORTANT */
map_and_invalidate(entires, cr3);
/* now you can use entires[] */
uint32_t pte = entries[x];
/* next level, etc. */
map_and_invalidate(entires, pte & ~((1<<12)-1));
pte = entries[y];
...
You can't have the entire paging structure mapped in virtual memory, simply because it's too big (for 32 bits maybe, but for 64 bits you surely can't). So you have to map individual paging table pages as you walk through the address. This solution only wastes 4096 from your virtual address space, and it has the advantage that it can resolve linear addresses for any tasks (not just the current one).

Cheers,
bzt

Re: How do you get physical frames

Posted: Wed Jun 10, 2020 9:21 am
by iansjack
bzt wrote:You can't have the entire paging structure mapped in virtual memory, simply because it's too big (for 32 bits maybe, but for 64 bits you surely can't). So you have to map individual paging table pages as you walk through the address. This solution only wastes 4096 from your virtual address space, and it has the advantage that it can resolve linear addresses for any tasks (not just the current one).

Cheers,
bzt
You don't have to map the entire virtual address space, just the physical address space. Using large pages, 1GB if supported, this uses very little memory. The table entries are sparse, and most of them are unneeded. This does presuppose that you don't have terrabytes of RAM, but in that case memory shortage is not a problem. Mapping the entire physical address space is a common solution to this problem and has many advantages, although it could be argued that there are security implications (but I'm not convinced of this).

Re: How do you get physical frames

Posted: Wed Jun 10, 2020 10:14 am
by nexos
I'm using recursive paging. All other routines paging routines use the same methods, and they work. This one doesn't, however.

Re: How do you get physical frames

Posted: Wed Jun 10, 2020 10:45 am
by nexos
I got it fixed (finally). There was no problem with the function, just I was testing on a PSE page without realizing it, which obviously didn't work.

Re: How do you get physical frames

Posted: Wed Jun 10, 2020 4:43 pm
by kzinti
Since you are using recursive mapping, it is very trivial to get the physical address from a virtual address.

Assuming 32 bits and PAE:

Code: Select all

physaddr_t PageTable::GetPhysicalAddress(void* virtualAddress) const
{
    // TODO: this needs to take into account large pages
    auto va = (physaddr_t)virtualAddress;
    const int i1 = (va >> 12) & 0xFFFFF;
    auto pa = vmm_pml1[i1] & PAGE_ADDRESS_MASK;

    return pa;
}