implemented map_region() (more testing needed; will propably replaced by a iterative solution)
This commit is contained in:
parent
892154c9f1
commit
ec171dfcce
1 changed files with 49 additions and 54 deletions
|
@ -283,21 +283,14 @@ size_t virt_to_phys(size_t viraddr)
|
||||||
size_t map_region(size_t viraddr, size_t phyaddr, uint32_t npages, uint32_t flags)
|
size_t map_region(size_t viraddr, size_t phyaddr, uint32_t npages, uint32_t flags)
|
||||||
{
|
{
|
||||||
task_t* task = per_core(current_task);
|
task_t* task = per_core(current_task);
|
||||||
page_map_t* pdpt, * pgd, * pgt;
|
|
||||||
uint16_t index_pml4, index_pdpt;
|
|
||||||
uint16_t index_pgd, index_pgt;
|
|
||||||
size_t i, ret;
|
size_t i, ret;
|
||||||
|
|
||||||
if (BUILTIN_EXPECT(!task || !task->page_map, 0))
|
if (BUILTIN_EXPECT(!task || !task->page_map, 0))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (flags & MAP_KERNEL_SPACE)
|
|
||||||
spinlock_lock(&kslock);
|
|
||||||
else
|
|
||||||
spinlock_irqsave_lock(&task->page_lock);
|
|
||||||
|
|
||||||
if (!viraddr) {
|
if (!viraddr) {
|
||||||
viraddr = vm_alloc(npages, flags);
|
kputs("map_region: deprecated vma_alloc() call from within map_region\n");
|
||||||
|
viraddr = vma_alloc(npages*PAGE_SIZE, VMA_HEAP);
|
||||||
if (BUILTIN_EXPECT(!viraddr, 0)) {
|
if (BUILTIN_EXPECT(!viraddr, 0)) {
|
||||||
kputs("map_region: found no valid virtual address\n");
|
kputs("map_region: found no valid virtual address\n");
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
@ -305,59 +298,40 @@ size_t map_region(size_t viraddr, size_t phyaddr, uint32_t npages, uint32_t flag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// correct alignment
|
||||||
|
phyaddr &= PAGE_MASK;
|
||||||
|
viraddr &= PAGE_MASK;
|
||||||
ret = viraddr;
|
ret = viraddr;
|
||||||
|
|
||||||
|
if (flags & MAP_KERNEL_SPACE)
|
||||||
|
spinlock_lock(&kslock);
|
||||||
|
else
|
||||||
|
spinlock_irqsave_lock(&task->page_lock);
|
||||||
|
|
||||||
|
kprintf("map_region: map %u pages from 0x%lx to 0x%lx with flags: 0x%x\n", npages, viraddr, phyaddr, flags);
|
||||||
for(i=0; i<npages; i++, viraddr+=PAGE_SIZE, phyaddr+=PAGE_SIZE) {
|
for(i=0; i<npages; i++, viraddr+=PAGE_SIZE, phyaddr+=PAGE_SIZE) {
|
||||||
index_pml4 = (viraddr >> 39) & 0x1FF;
|
// page table entry
|
||||||
index_pdpt = (viraddr >> 30) & 0x1FF;
|
size_t* pte = (size_t *) (PAGE_PGT|(viraddr >> 9));
|
||||||
index_pgd = (viraddr >> 21) & 0x1FF;
|
|
||||||
index_pgt = (viraddr >> 12) & 0x1FF;
|
|
||||||
|
|
||||||
pdpt = (page_map_t*) (task->page_map->entries[index_pml4] & PAGE_MASK);
|
if (*pte && !(flags & MAP_REMAP)) {
|
||||||
if (!pgt) {
|
kprintf("map_region: 0x%lx is already mapped\n", viraddr);
|
||||||
kputs("map_region: out of memory\n");
|
|
||||||
ret = 0;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
pgd = (page_map_t*) (pdpt->entries[index_pdpt] & PAGE_MASK);
|
|
||||||
if (!pgd) {
|
|
||||||
kputs("map_region: out of memory\n");
|
|
||||||
ret = 0;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
pgt = (page_map_t*) (pgd->entries[index_pgd] & PAGE_MASK);
|
|
||||||
if (!pgt) {
|
|
||||||
kputs("map_region: out of memory\n");
|
|
||||||
ret = 0;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* convert physical address to virtual */
|
|
||||||
// Currently, we allocate pages only in kernel space.
|
|
||||||
// => physical address of the page table is identical of the virtual address
|
|
||||||
//if (paging_enabled)
|
|
||||||
// pgt = (page_map_t*) ((KERNEL_SPACE - 1024*PAGE_SIZE + index*PAGE_SIZE) & PAGE_MASK);
|
|
||||||
|
|
||||||
if (pgt->entries[index_pgt] && !(flags & MAP_REMAP)) {
|
|
||||||
kprintf("0x%x is already mapped\n", viraddr);
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & MAP_USER_SPACE)
|
if (flags & MAP_USER_SPACE)
|
||||||
pgt->entries[index_pgt] = USER_PAGE|(phyaddr & PAGE_MASK);
|
*pte = phyaddr|USER_PAGE;
|
||||||
else
|
else
|
||||||
pgt->entries[index_pgt] = KERN_PAGE|(phyaddr & PAGE_MASK);
|
*pte = phyaddr|KERN_PAGE;
|
||||||
|
|
||||||
if (flags & MAP_NO_CACHE)
|
if (flags & MAP_NO_CACHE)
|
||||||
pgt->entries[index_pgt] |= PG_PCD;
|
*pte |= PG_PCD;
|
||||||
|
|
||||||
if (flags & MAP_NO_ACCESS)
|
if (flags & MAP_NO_ACCESS)
|
||||||
pgt->entries[index_pgt] &= ~PG_PRESENT;
|
*pte &= ~PG_PRESENT;
|
||||||
|
|
||||||
if (flags & MAP_WT)
|
if (flags & MAP_WT)
|
||||||
pgt->entries[index_pgt] |= PG_PWT;
|
*pte |= PG_PWT;
|
||||||
|
|
||||||
if (flags & MAP_USER_SPACE)
|
if (flags & MAP_USER_SPACE)
|
||||||
atomic_int32_inc(&task->user_usage);
|
atomic_int32_inc(&task->user_usage);
|
||||||
|
@ -651,10 +625,8 @@ int vm_free(size_t viraddr, uint32_t npages)
|
||||||
static void pagefault_handler(struct state *s)
|
static void pagefault_handler(struct state *s)
|
||||||
{
|
{
|
||||||
task_t* task = per_core(current_task);
|
task_t* task = per_core(current_task);
|
||||||
//page_map_t* pgd = task->page_map;
|
|
||||||
//page_map_t* pgt = NULL;
|
|
||||||
size_t viraddr = read_cr2();
|
size_t viraddr = read_cr2();
|
||||||
//size_t phyaddr;
|
size_t phyaddr;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
if ((viraddr >= task->start_heap) && (viraddr <= task->end_heap) && (viraddr > KERNEL_SPACE)) {
|
if ((viraddr >= task->start_heap) && (viraddr <= task->end_heap) && (viraddr > KERNEL_SPACE)) {
|
||||||
|
@ -662,7 +634,7 @@ static void pagefault_handler(struct state *s)
|
||||||
|
|
||||||
phyaddr = get_page();
|
phyaddr = get_page();
|
||||||
if (BUILTIN_EXPECT(!phyaddr, 0))
|
if (BUILTIN_EXPECT(!phyaddr, 0))
|
||||||
goto default_handler;
|
goto oom;
|
||||||
|
|
||||||
if (map_region(viraddr, phyaddr, 1, MAP_USER_SPACE) == viraddr) {
|
if (map_region(viraddr, phyaddr, 1, MAP_USER_SPACE) == viraddr) {
|
||||||
memset((void*) viraddr, 0x00, PAGE_SIZE);
|
memset((void*) viraddr, 0x00, PAGE_SIZE);
|
||||||
|
@ -672,14 +644,37 @@ static void pagefault_handler(struct state *s)
|
||||||
kprintf("Could not map 0x%x at 0x%x\n", phyaddr, viraddr);
|
kprintf("Could not map 0x%x at 0x%x\n", phyaddr, viraddr);
|
||||||
put_page(phyaddr);
|
put_page(phyaddr);
|
||||||
}
|
}
|
||||||
|
// handle missing paging structures for userspace
|
||||||
|
// all kernel space paging structures have been initialized in entry64.asm
|
||||||
|
else if (viraddr >= PAGE_PGT) {
|
||||||
|
kprintf("map_region: missing paging structure at: 0x%lx (%s)\n", viraddr, map_to_lvlname(viraddr));
|
||||||
|
|
||||||
|
phyaddr = get_page();
|
||||||
|
if (BUILTIN_EXPECT(!phyaddr, 0))
|
||||||
|
goto oom;
|
||||||
|
|
||||||
|
// TODO: initialize with zeros
|
||||||
|
// TODO: check that we are in userspace
|
||||||
|
|
||||||
|
// get pointer to parent page level entry
|
||||||
|
size_t *entry = (size_t *) ((int64_t) viraddr >> 9 & ~0x07);
|
||||||
|
|
||||||
|
// update entry
|
||||||
|
*entry = phyaddr|USER_TABLE;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//default_handler:
|
|
||||||
kprintf("PAGE FAULT: Task %u got page fault at %p (irq %llu, cs:rip 0x%llx:0x%llx)\n", task->id, viraddr, s->int_no, s->cs, s->rip);
|
kprintf("PAGE FAULT: Task %u got page fault at %p (irq %llu, cs:rip 0x%llx:0x%llx)\n", task->id, viraddr, s->int_no, s->cs, s->rip);
|
||||||
kprintf("Register state: rax = 0x%llx, rbx = 0x%llx, rcx = 0x%llx, rdx = 0x%llx, rdi = 0x%llx, rsi = 0x%llx, rbp = 0x%llx, rsp = 0x%llx\n",
|
kprintf("Register state: rax = 0x%llx, rbx = 0x%llx, rcx = 0x%llx, rdx = 0x%llx, rdi = 0x%llx, rsi = 0x%llx, rbp = 0x%llx, rsp = 0x%llx\n",
|
||||||
s->rax, s->rbx, s->rcx, s->rdx, s->rdi, s->rsi, s->rbp, s->rsp);
|
s->rax, s->rbx, s->rcx, s->rdx, s->rdi, s->rsi, s->rbp, s->rsp);
|
||||||
|
|
||||||
while(1);
|
irq_enable();
|
||||||
|
abort();
|
||||||
|
|
||||||
|
oom:
|
||||||
|
kputs("map_region: out of memory\n");
|
||||||
irq_enable();
|
irq_enable();
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue