summaryrefslogtreecommitdiff
path: root/src/kernel/arch/amd64/pagedir.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/arch/amd64/pagedir.c')
-rw-r--r--src/kernel/arch/amd64/pagedir.c117
1 files changed, 60 insertions, 57 deletions
diff --git a/src/kernel/arch/amd64/pagedir.c b/src/kernel/arch/amd64/pagedir.c
index 56c541a..0d6078b 100644
--- a/src/kernel/arch/amd64/pagedir.c
+++ b/src/kernel/arch/amd64/pagedir.c
@@ -94,19 +94,28 @@ void pagedir_free(struct pagedir *dir) {
*/
}
-/*
-static struct pagetable_entry*
+static pe_generic_t*
get_entry(struct pagedir *dir, const void __user *virt) {
- uint32_t pd_idx = ((uintptr_t)virt) >> 22;
- uint32_t pt_idx = ((uintptr_t)virt) >> 12 & 0x03FF;
- struct pagetable_entry *pagetable;
+ pe_generic_t *pml4e, *pdpte, *pde, *pte;
+ const union virt_addr v = {.full = (void*)virt};
+
+ // TODO check if sign extension is valid
+
+ pml4e = &dir->e[v.pml4];
+ if (!pml4e->present) return NULL;
+ assert(!pml4e->large);
+
+ pdpte = &((pe_generic_t*)addr_extract(*pml4e))[v.pdpt];
+ if (!pdpte->present) return NULL;
+ assert(!pdpte->large);
- if (!dir->e[pd_idx].present) return NULL;
+ pde = &((pe_generic_t*)addr_extract(*pdpte))[v.pd];
+ if (!pde->present) return NULL;
+ assert(!pde->large);
- pagetable = (void*)(dir->e[pd_idx].address << 11);
- return &pagetable[pt_idx];
+ pte = &((pe_generic_t*)addr_extract(*pde))[v.pt];
+ return pte;
}
-*/
void *pagedir_unmap(struct pagedir *dir, void __user *virt) {
(void)dir; (void)virt;
@@ -129,7 +138,6 @@ void pagedir_map(struct pagedir *dir, void __user *virt, void *phys,
pml4e = &dir->e[v.pml4];
if (!pml4e->present) {
- kprintf("allocating pdpt\n");
pml4e->as_ptr = addr_validate(page_zalloc(1));
pml4e->present = 1;
pml4e->writeable = 1;
@@ -139,7 +147,6 @@ void pagedir_map(struct pagedir *dir, void __user *virt, void *phys,
pdpte = &((pe_generic_t*)addr_extract(*pml4e))[v.pdpt];
if (!pdpte->present) {
- kprintf("allocating pd\n");
pdpte->as_ptr = addr_validate(page_zalloc(1));
pdpte->present = 1;
pdpte->writeable = 1;
@@ -149,7 +156,6 @@ void pagedir_map(struct pagedir *dir, void __user *virt, void *phys,
pde = &((pe_generic_t*)addr_extract(*pdpte))[v.pd];
if (!pde->present) {
- kprintf("allocating pt\n");
pde->as_ptr = addr_validate(page_zalloc(1));
pde->present = 1;
pde->writeable = 1;
@@ -174,68 +180,67 @@ void pagedir_switch(struct pagedir *dir) {
}
// creates a new pagedir with exact copies of the user pages
-struct pagedir *pagedir_copy(const struct pagedir *orig) {
- /*
- struct pagedir *clone = page_alloc(1);
- struct pagetable_entry *orig_pt, *clone_pt;
- void *orig_page, *clone_page;
-
- for (int i = 0; i < 1024; i++) {
- clone->e[i] = orig->e[i];
- if (!orig->e[i].present) continue;
-
- orig_pt = (void*)(orig->e[i].address << 11);
- clone_pt = page_alloc(1);
- clone->e[i].address = (uintptr_t) clone_pt >> 11;
-
- for (int j = 0; j < 1024; j++) {
- clone_pt[j] = orig_pt[j];
- if (!orig_pt[j].present) continue;
- if (!orig_pt[j].user) continue;
- // i could use .global?
-
- orig_page = (void*)(orig_pt[j].address << 11);
- clone_page = page_alloc(1);
- clone_pt[j].address = (uintptr_t) clone_page >> 11;
-
- memcpy(clone_page, orig_page, PAGE_SIZE);
+struct pagedir *pagedir_copy(const struct pagedir *pml4_old) {
+ struct pagedir *pml4_new = page_zalloc(1);
+
+ for (int i = 0; i < 512; i++) {
+ if (!pml4_old->e[i].present) continue;
+ assert(!pml4_old->e[i].large);
+ const pe_generic_t *pdpt_old = addr_extract(pml4_old->e[i]);
+ pe_generic_t *pdpt_new = page_zalloc(1);
+ pml4_new->e[i] = pml4_old->e[i];
+ pml4_new->e[i].address = (uintptr_t) pdpt_new >> 12;
+
+ for (int j = 0; j < 512; j++) {
+ if (!pdpt_old[j].present) continue;
+ assert(!pdpt_old[j].large);
+ const pe_generic_t *pd_old = addr_extract(pdpt_old[j]);
+ pe_generic_t *pd_new = page_zalloc(1);
+ pdpt_new[j] = pdpt_old[j];
+ pdpt_new[j].address = (uintptr_t) pd_new >> 12;
+
+ for (int k = 0; k < 512; k++) {
+ if (!pd_old[k].present) continue;
+ assert(!pd_old[k].large);
+ const pe_generic_t *pt_old = addr_extract(pd_old[k]);
+ pe_generic_t *pt_new = page_zalloc(1);
+ pd_new[k] = pd_old[k];
+ pd_new[k].address = (uintptr_t) pt_new >> 12;
+
+ for (int l = 0; l < 512; l++) {
+ if (!pt_old[l].present || !pt_old[l].user)
+ continue;
+ void *page_new = page_alloc(1);
+ memcpy(page_new, addr_extract(pt_old[l]), PAGE_SIZE);
+ pt_new[l] = pt_old[l];
+ pt_new[l].address = (uintptr_t) page_new >> 12;
+ }
+ }
}
}
- return clone;
- */
- panic_unimplemented();
+ return pml4_new;
}
bool pagedir_iskern(struct pagedir *dir, const void __user *virt) {
- /*
- struct pagetable_entry *page = get_entry(dir, virt);
+ pe_generic_t *page = get_entry(dir, virt);
return page && page->present && !page->user;
- */
- panic_unimplemented();
}
void *pagedir_virt2phys(struct pagedir *dir, const void __user *virt,
bool user, bool writeable)
{
- /*
- struct pagetable_entry *page;
- uintptr_t phys;
- page = get_entry(dir, virt);
+ pe_generic_t *page = get_entry(dir, virt);
if (!page || !page->present) return NULL;
if (user && !page->user) return NULL;
if (writeable && !page->writeable) return NULL;
- phys = page->address << 11;
- phys |= ((uintptr_t)virt) & 0xFFF;
- return (void*)phys;
- */
- panic_unimplemented();
+ return addr_extract(*page) + ((uintptr_t)virt & PAGE_MASK);
}
void __user *pagedir_findfree(struct pagedir *dir, char __user *start, size_t len) {
- /*
- struct pagetable_entry *page;
+ // TODO dogshit slow
+ pe_generic_t *page;
char __user *iter;
start = (userptr_t)(((uintptr_t __force)start + PAGE_MASK) & ~PAGE_MASK); // round up to next page
iter = start;
@@ -251,6 +256,4 @@ void __user *pagedir_findfree(struct pagedir *dir, char __user *start, size_t le
iter += PAGE_SIZE;
}
return NULL;
- */
- panic_unimplemented();
}