How do you get physical frames
How do you get physical frames
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.
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
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.
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
My Hobby OS: https://github.com/heatd/Onyx
Re: How do you get physical frames
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
It tells you in the PTEs.
-
- Member
- Posts: 426
- Joined: Tue Apr 03, 2018 2:44 am
Re: How do you get physical frames
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 wrote: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
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);
}
-
- Member
- Posts: 426
- Joined: Tue Apr 03, 2018 2:44 am
Re: How do you get physical frames
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.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); }
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
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).nexos wrote:I have come up with a routine that finds the physical address, but it doesn't work.
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];
...
Cheers,
bzt
Re: How do you get physical frames
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).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
Re: How do you get physical frames
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
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
Since you are using recursive mapping, it is very trivial to get the physical address from a virtual address.
Assuming 32 bits and PAE:
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;
}