// Given a parent process's page table, create a copy // of it for a child. pde_t* copyuvm(pde_t *pgdir, uint sz) { pde_t *d; pte_t *pte; uint pa, i, flags; char *mem; if((d = setupkvm()) == 0) return 0; for(i = 0; i < sz; i += PGSIZE){ if((pte = walkpgdir(pgdir, (void *) i, 0)) == 0) panic("copyuvm: pte should exist"); if(!(*pte & PTE_P)) continue; // panic("copyuvm: page not present"); pa = PTE_ADDR(*pte); flags = PTE_FLAGS(*pte); if((mem = kalloc()) == 0) goto bad; memmove(mem, (char*)p2v(pa), PGSIZE); if(mappages(d, (void*)i, PGSIZE, v2p(mem), flags) < 0) goto bad; } return d; bad: freevm(d); return 0; }
static pgentry_t pg_clone_tbl(pgentry_t tblent) { uint32_t flags = (uint32_t)PTE_FLAGS(tblent); paddr_t tblframe = (paddr_t)PTE_ADDR(tblent); if ((flags & PAGE_LINK) != 0) { return tblent; } if ((flags & PAGE_PRESENT) == 0) { // Table not present, but some flags are set return tblent; } paddr_t newtblframe = pg_dir_new(); pgentry_t *tbl = pg_tmp_map((pgaddr_t)tblframe); pgentry_t *newtbl = pg_tmp_map((pgaddr_t)newtblframe); for (int i = 0; i < 1024; i++) { if (tbl[i] != NilPgEnt) { newtbl[i] = pg_clone_page(tbl[i]); } } pg_tmp_unmap(tbl); pg_tmp_unmap(newtbl); return PAGE_ENTRY(newtblframe, flags); }
// Given a parent process's page table, create a copy // of it for a child. // CHANGE: copy on write pde_t* copyuvm(pde_t *pgdir, uint sz) { pde_t *d; pte_t *pte; uint pa, i, flags; if((d = setupkvm()) == 0) return 0; // CHANGE TREINHART TO 4096 for(i = 4096; i < sz; i += PGSIZE){ if((pte = walkpgdir(pgdir, (void *) i, 0)) == 0) panic("copyuvm: pte should exist"); if(!(*pte & PTE_P)) panic("copyuvm: page not present"); *pte = *pte & (~PTE_W); *pte = *pte | PTE_COW; pa = PTE_ADDR(*pte); flags = PTE_FLAGS(*pte); //CHANGE: update reference counts if(mappages(d, (void*)i, PGSIZE, pa, flags) < 0) goto bad; r_c.ref_count[pa/ 4096] ++; } flushtlb(); return d; bad: freevm(d); return 0; }
static int __dune_vm_mprotect_helper(const void *arg, ptent_t *pte, void *va) { ptent_t perm = (ptent_t) arg; // if (!(PTE_FLAGS(*pte) & PTE_P)) // return -ENOMEM; *pte = PTE_ADDR(*pte) | (PTE_FLAGS(*pte) & PTE_PS) | perm; return 0; }
//Wille return 0 if error, 1 if success int check_page_fault(pde_t *pgdir, uint va) { pte_t *pte; uint pa; char *mem; //check if exists, and allowed by user if(va >= KERNBASE || va < 4096) { cprintf("Kernel or Null memory access\n"); return 0; } if((pte = walkpgdir(pgdir, (void *)va, 0)) == 0) { cprintf("memory access not in page dir\n"); return 0; } if( (!(*pte & PTE_P)) || (!(*pte & PTE_U)) ) { cprintf("memory access not for users\n"); return 0; } if( !(*pte & PTE_COW)) { cprintf("No cow bit, writing to read only mem\n"); return 0; } if( *pte & PTE_W) { cprintf("Writing other processes mem, error\n"); return 0; } pa = PTE_ADDR(*pte); //CHANGE: update reference counts acquire(&r_c.lock); if(r_c.ref_count[pa / 4096] == 1) { *pte = *pte | PTE_W; *pte = *pte & (~PTE_COW); release(&r_c.lock); //flush translation lookaside buffer flushtlb(); return 1; } else { r_c.ref_count[pa / 4096]--; release(&r_c.lock); if((mem = kalloc()) == 0) { return 0; } memmove(mem, (char*)p2v(pa), PGSIZE); *pte = v2p(mem) | PTE_FLAGS(*pte) | PTE_W; *pte = *pte & (~PTE_COW); acquire(&r_c.lock); r_c.ref_count[v2p(mem) / 4096] = 1; release(&r_c.lock); //flush translation lookaside buffer flushtlb(); return 1; } }
int showmp(uint a, uint b) { // cprintf("showmp %x %x %x %x\n", rcr3(), cpu->proc->pgdir, a, b); if (a > b) { panic("show mapping"); } char *va = (char*)PGROUNDDOWN(a); char *vb = (char*)PGROUNDDOWN(b); cprintf("Mappings of virtual address %x to %x:\n", va, vb); cprintf("Virt Addr\tPhys Addr\tPermission\n"); pte_t *pte; for (;;) { pte = walkpgdir(cpu->proc->pgdir, va); if (pte == 0 || *pte == 0) { cprintf("%x\t\t-\n", va); } else { uint flags = PTE_FLAGS(*pte); cprintf("%x\t\t%x\t\t", va, PTE_ADDR(*pte)); if (flags & PTE_U) { cprintf("User\t"); } else cprintf("-\t"); cprintf("/ "); if (flags & PTE_W) { cprintf("Writeable"); } else cprintf("-"); cprintf(" %d\n", flags&PTE_D); } if (va == vb) break; va += PGSIZE; } return 0; }
static pgentry_t pg_clone_page(pgentry_t page) { uint32_t flags = (uint32_t)PTE_FLAGS(page); paddr_t pgframe = (paddr_t)PTE_ADDR(page); if ((flags & PAGE_PRESENT) == 0) { // Page not present, but some flags are set return page; } if ((flags & PAGE_LINK) != 0) { return page; } paddr_t newpgframe = frame_alloc(); frame_set(newpgframe); frame_copy(pgframe, newpgframe); return PAGE_ENTRY(newpgframe, flags); }
void dune_vm_default_pgflt_handler(uintptr_t addr, uint64_t fec) { ptent_t *pte = NULL; int rc; /* * Assert on present and reserved bits. */ assert(!(fec & (FEC_P | FEC_RSV))); rc = dune_vm_lookup(pgroot, (void *) addr, 0, &pte); assert(rc == 0); if ((fec & FEC_W) && (*pte & PTE_COW)) { void *newPage; struct page *pg = dune_pa2page(PTE_ADDR(*pte)); ptent_t perm = PTE_FLAGS(*pte); // Compute new permissions perm &= ~PTE_COW; perm |= PTE_W; if (dune_page_isfrompool(PTE_ADDR(*pte)) && pg->ref == 1) { *pte = PTE_ADDR(*pte) | perm; return; } // Duplicate page newPage = alloc_page(); memcpy(newPage, (void *)PGADDR(addr), PGSIZE); // Map page if (dune_page_isfrompool(PTE_ADDR(*pte))) { dune_page_put(pg); } *pte = PTE_ADDR(newPage) | perm; // Invalidate dune_flush_tlb_one(addr); } }
static inline int pte_big(ptent_t pte) { return (PTE_FLAGS(pte) & PTE_PS); }
static inline int pte_present(ptent_t pte) { return (PTE_FLAGS(pte) & PTE_P); }