int get_user_page(struct proc *p, unsigned long uvastart, int write, int force, struct page **plist) { pte_t pte; int ret = -1; struct page *pp; spin_lock(&p->pte_lock); pte = pgdir_walk(p->env_pgdir, (void*)uvastart, TRUE); if (!pte_walk_okay(pte)) goto err1; if (!pte_is_present(pte)) { unsigned long prot = PTE_P | PTE_U | PTE_A | PTE_W | PTE_D; #if 0 printk("[akaros]: get_user_page() uva=0x%llx pte absent\n", uvastart); #endif /* * TODO: ok to allocate with pte_lock? "prot" needs to be * based on VMR writability, refer to pgprot_noncached(). */ if (upage_alloc(p, &pp, 0)) goto err1; pte_write(pte, page2pa(pp), prot); } else { pp = pa2page(pte_get_paddr(pte)); /* __vmr_free_pgs() refcnt's pagemap pages differently */ if (atomic_read(&pp->pg_flags) & PG_PAGEMAP) { printk("[akaros]: get_user_page(): uva=0x%llx\n", uvastart); goto err1; } } if (write && (!pte_has_perm_urw(pte))) { /* TODO: How is Linux using the "force" parameter */ printk("[akaros]: get_user_page() uva=0x%llx pte ro\n", uvastart); goto err1; } /* TODO (GUP): change the interface such that devices provide the memory and * the user mmaps it, instead of trying to pin arbitrary user memory. */ warn_once("Extremely unsafe, unpinned memory mapped! If your process dies, you might scribble on RAM!"); plist[0] = pp; ret = 1; err1: spin_unlock(&p->pte_lock); return ret; }
/* Frees (decrefs) all memory mapped in the given range */ void env_user_mem_free(env_t* e, void* start, size_t len) { assert((uintptr_t)start + len <= UVPT); //since this keeps f*****g happening int user_page_free(env_t* e, pte_t pte, void* va, void* arg) { if (!pte_is_mapped(pte)) return 0; page_t *page = pa2page(pte_get_paddr(pte)); pte_clear(pte); page_decref(page); /* TODO: consider other states here (like !P, yet still tracking a page, * for VM tricks, page map stuff, etc. Should be okay: once we're * freeing, everything else about this proc is dead. */ return 0; } env_user_mem_walk(e,start,len,&user_page_free,NULL); tlbflush(); }