Added API to enumerate the VM regions of a process
[akaros.git] / kern / src / mm.c
index 2b10536..022f5ad 100644 (file)
@@ -58,7 +58,7 @@ struct vm_region *create_vmr(struct proc *p, uintptr_t va, size_t len)
        vm_i = TAILQ_FIRST(&p->vm_regions);
        /* This works for now, but if all we have is BRK_END ones, we'll start
         * growing backwards (TODO) */
-       if (!vm_i || (va + len < vm_i->vm_base)) {
+       if (!vm_i || (va + len <= vm_i->vm_base)) {
                vmr = kmem_cache_alloc(vmr_kcache, 0);
                if (!vmr)
                        panic("EOM!");
@@ -292,7 +292,7 @@ static int copy_pages(struct proc *p, struct proc *new_p, uintptr_t va_start,
                        /* TODO: check for jumbos */
                        if (upage_alloc(new_p, &pp, 0))
                                return -ENOMEM;
-                       if (page_insert(new_p->env_pgdir, pp, va, pte_get_perm(pte))) {
+                       if (page_insert(new_p->env_pgdir, pp, va, pte_get_settings(pte))) {
                                page_decref(pp);
                                return -ENOMEM;
                        }
@@ -359,6 +359,18 @@ void print_vmrs(struct proc *p)
                       vmr->vm_file, vmr->vm_foff);
 }
 
+void enumerate_vmrs(struct proc *p,
+                                       void (*func)(struct vm_region *vmr, void *opaque),
+                                       void *opaque)
+{
+       struct vm_region *vmr;
+
+       spin_lock(&p->vmr_lock);
+       TAILQ_FOREACH(vmr, &p->vm_regions, vm_link)
+               func(vmr, opaque);
+       spin_unlock(&p->vmr_lock);
+}
+
 /* Error values aren't quite comprehensive - check man mmap() once we do better
  * with the FS.
  *
@@ -734,7 +746,7 @@ int __do_mprotect(struct proc *p, uintptr_t addr, size_t len, int prot)
                 * prot.  The others will fault on access, and we'll change the PTE
                 * then.  In the off chance we have a mapped but not present PTE, we
                 * might as well change it too, since we're already here. */
-               for (uintptr_t va = vmr->vm_base; va < vmr->vm_end; va += PGSIZE) { 
+               for (uintptr_t va = vmr->vm_base; va < vmr->vm_end; va += PGSIZE) {
                        pte = pgdir_walk(p->env_pgdir, (void*)va, 0);
                        if (pte_walk_okay(pte) && pte_is_mapped(pte)) {
                                pte_replace_perm(pte, pte_prot);
@@ -910,7 +922,7 @@ static int __hpf_load_page(struct proc *p, struct page_map *pm,
        return 0;
 }
 
-/* Returns 0 on success, or an appropriate -error code. 
+/* Returns 0 on success, or an appropriate -error code.
  *
  * Notes: if your TLB caches negative results, you'll need to flush the
  * appropriate tlb entry.  Also, you could have a weird race where a present PTE
@@ -927,14 +939,13 @@ int handle_page_fault(struct proc *p, uintptr_t va, int prot)
        bool first = TRUE;
        va = ROUNDDOWN(va,PGSIZE);
 
-       if (prot != PROT_READ && prot != PROT_WRITE && prot != PROT_EXEC)
-               panic("bad prot!");
 refault:
        /* read access to the VMRs TODO: RCU */
        spin_lock(&p->vmr_lock);
        /* Check the vmr's protection */
        vmr = find_vmr(p, va);
        if (!vmr) {                                                     /* not mapped at all */
+               printd("fault: %p not mapped\n", va);
                ret = -EFAULT;
                goto out;
        }
@@ -1005,6 +1016,9 @@ refault:
        int pte_prot = (vmr->vm_prot & PROT_WRITE) ? PTE_USER_RW :
                       (vmr->vm_prot & (PROT_READ|PROT_EXEC)) ? PTE_USER_RO : 0;
        ret = map_page_at_addr(p, a_page, va, pte_prot);
+       if (ret) {
+               printd("map_page_at for %p fails with %d\n", va, ret);
+       }
        /* fall through, even for errors */
 out_put_pg:
        /* the VMR's existence in the PM (via the mmap) allows us to have PTE point