How do you get physical frames

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
nexos
Member
Member
Posts: 1081
Joined: Tue Feb 18, 2020 3:29 pm
Libera.chat IRC: nexos

How do you get physical frames

Post 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.
"How did you do this?"
"It's very simple — you read the protocol and write the code." - Bill Joy
Projects: NexNix | libnex | nnpkg
heat
Member
Member
Posts: 103
Joined: Sat Mar 28, 2015 11:23 am
Libera.chat IRC: heat

Re: How do you get physical frames

Post 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.
If some of you people keep insisting on having backwards compatibitity with the stone age, we'll have stone tools forever.
My Hobby OS: https://github.com/heatd/Onyx
nexos
Member
Member
Posts: 1081
Joined: Tue Feb 18, 2020 3:29 pm
Libera.chat IRC: nexos

Re: How do you get physical frames

Post by nexos »

I know how to allocate physical memory, I was wondering how to get the physical frame from a PTE or PDE
"How did you do this?"
"It's very simple — you read the protocol and write the code." - Bill Joy
Projects: NexNix | libnex | nnpkg
User avatar
iansjack
Member
Member
Posts: 4703
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: How do you get physical frames

Post by iansjack »

It tells you in the PTEs.
thewrongchristian
Member
Member
Posts: 426
Joined: Tue Apr 03, 2018 2:44 am

Re: How do you get physical frames

Post 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.
nexos
Member
Member
Posts: 1081
Joined: Tue Feb 18, 2020 3:29 pm
Libera.chat IRC: nexos

Re: How do you get physical frames

Post 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);
}
"How did you do this?"
"It's very simple — you read the protocol and write the code." - Bill Joy
Projects: NexNix | libnex | nnpkg
thewrongchristian
Member
Member
Posts: 426
Joined: Tue Apr 03, 2018 2:44 am

Re: How do you get physical frames

Post 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);
User avatar
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: How do you get physical frames

Post 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
User avatar
iansjack
Member
Member
Posts: 4703
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: How do you get physical frames

Post 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).
nexos
Member
Member
Posts: 1081
Joined: Tue Feb 18, 2020 3:29 pm
Libera.chat IRC: nexos

Re: How do you get physical frames

Post by nexos »

I'm using recursive paging. All other routines paging routines use the same methods, and they work. This one doesn't, however.
"How did you do this?"
"It's very simple — you read the protocol and write the code." - Bill Joy
Projects: NexNix | libnex | nnpkg
nexos
Member
Member
Posts: 1081
Joined: Tue Feb 18, 2020 3:29 pm
Libera.chat IRC: nexos

Re: How do you get physical frames

Post 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.
"How did you do this?"
"It's very simple — you read the protocol and write the code." - Bill Joy
Projects: NexNix | libnex | nnpkg
kzinti
Member
Member
Posts: 898
Joined: Mon Feb 02, 2015 7:11 pm

Re: How do you get physical frames

Post 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;
}
Post Reply