My problem is that I can only get the physical address of PTE and I don't know how to get the virtual one. However I need it to change it's flags or page address.
It was not a problem when tables where all identity mapped, but now they can be anywhere.
I tried to find a solution by myself but with no success, and same result by looking on the internet. It seems impossible to me since the only place this information is in the PTE, which is what I'm try to access ... And the only solutions I found online assumed a fixed offset (something like
Code: Select all
#define P_TO_V(p) (p+0xC0000000)
Code: Select all
va_t vmap(va_t vstart, pa_t pstart, size_t size)
{
if(!size) return -1;
uintptr_t v = (uintptr_t)vstart;
uintptr_t p = (uintptr_t)pstart;
const size_t page_num = size/PAGE_SIZE + (size%PAGE_SIZE ? 1 : 0);
for(size_t i=0; i<page_num; i++)
{
pde_t* const pde = &page_dir[v>>22];
pde->writeable = 1;
pde->present = 1;
if(!pde->table_address)
{ // Allocate and map a table
va_t table = find_unmapped_vpages(PAGE_SIZE);
if(!table)
{
pde->present = 0;
return NULL;
}
/* With identity mapping
pde->table_address = (uintptr_t)table>>12;
vmap(table, table, PAGE_SIZE);
*/
// Now, with "random" physical and virtual allocation
pa_t paddr = palloc();
pde->table_address = (uintptr_t)paddr>>12;
vmap(table, paddr, PAGE_SIZE);
//
mprotect(table, PAGE_SIZE, PROT_WRITE);
memset(table, 0, PAGE_SIZE);
}
// Physical address of PTE. Not usable to access it.
pte_t* pte = &((pte_t*)(pde->table_address<<12))[(v>>12)&0x3FF];
pte->page_address = p>>12;
pte->present = 1;
p += PAGE_SIZE;
v += PAGE_SIZE;
}
return vstart;
}
void vunmap(va_t vstart, size_t size)
{
if(!size) return;
uintptr_t v = (uintptr_t)vstart;
size_t page_num = size/PAGE_SIZE +(size%PAGE_SIZE ? 1 : 0);
for(size_t i=0; i<page_num; i++)
{
pde_t* pde = &page_dir[v>>22];
if(pde->table_address)
((pte_t*)(pde->table_address<<12))[(v>>12)&0x3FF].present = 0;
v += PAGE_SIZE;
}
// TODO: Clear PDE present bit and free unused PTE if the whole directory has been unmapped
}