summaryrefslogtreecommitdiff
path: root/vm.c
diff options
context:
space:
mode:
authorRobert Morris <[email protected]>2010-08-05 12:10:54 -0400
committerRobert Morris <[email protected]>2010-08-05 12:10:54 -0400
commiteb18645f17877de4ced951eed5abac61bdfcd5c5 (patch)
treed5a40a1839ef1264a84f9eeff5723c7c67cad711 /vm.c
parentb738a4f1a2dd2956123a734327aeaf9d09b5faca (diff)
downloadxv6-labs-eb18645f17877de4ced951eed5abac61bdfcd5c5.tar.gz
xv6-labs-eb18645f17877de4ced951eed5abac61bdfcd5c5.tar.bz2
xv6-labs-eb18645f17877de4ced951eed5abac61bdfcd5c5.zip
fix allocuvm() to handle sbrk() with non-page-granularity argument
(maybe this never worked, but it works now)
Diffstat (limited to 'vm.c')
-rw-r--r--vm.c36
1 files changed, 26 insertions, 10 deletions
diff --git a/vm.c b/vm.c
index 231e133..b89efd5 100644
--- a/vm.c
+++ b/vm.c
@@ -54,6 +54,9 @@ printpgdir(pde_t *pgdir)
cprintf("printpgdir done\n", pgdir);
}
+// return the address of the PTE in page table pgdir
+// that corresponds to linear address va. if create!=0,
+// create any required page table pages.
static pte_t *
walkpgdir(pde_t *pgdir, const void *va, int create)
{
@@ -80,6 +83,8 @@ walkpgdir(pde_t *pgdir, const void *va, int create)
return &pgtab[PTX(va)];
}
+// create PTEs for linear addresses starting at la that refer to
+// physical addresses starting at pa.
static int
mappages(pde_t *pgdir, void *la, uint size, uint pa, int perm)
{
@@ -89,6 +94,8 @@ mappages(pde_t *pgdir, void *la, uint size, uint pa, int perm)
for (i = 0; i < size; i += PGSIZE) {
if (!(pte = walkpgdir(pgdir, (void*)(la + i), 1)))
return 0;
+ if(*pte & PTE_P)
+ panic("remap");
*pte = (pa + i) | perm | PTE_P;
}
return 1;
@@ -177,21 +184,30 @@ uva2ka(pde_t *pgdir, char *uva)
return (char *)pa;
}
+// allocate sz bytes more memory for a process starting at the
+// given user address; allocates physical memory and page
+// table entries. addr and sz need not be page-aligned.
+// it is a no-op for any parts of the requested memory
+// that are already allocated.
int
allocuvm(pde_t *pgdir, char *addr, uint sz)
{
- uint i, n;
- char *mem;
-
- n = PGROUNDUP(sz);
- if (addr + n >= USERTOP)
+ if (addr + sz >= (char*)USERTOP)
return 0;
- for (i = 0; i < n; i += PGSIZE) {
- if (!(mem = kalloc(PGSIZE))) { // XXX cleanup what we did?
- return 0;
+ char *start = PGROUNDDOWN(addr);
+ char *last = PGROUNDDOWN(addr + sz - 1);
+ char *a;
+ for(a = start; a <= last; a += PGSIZE){
+ pte_t *pte = walkpgdir(pgdir, a, 0);
+ if(pte == 0 || (*pte & PTE_P) == 0){
+ char *mem = kalloc(PGSIZE);
+ if(mem == 0){
+ // XXX clean up?
+ return 0;
+ }
+ memset(mem, 0, PGSIZE);
+ mappages(pgdir, a, PGSIZE, PADDR(mem), PTE_W|PTE_U);
}
- memset(mem, 0, PGSIZE);
- mappages(pgdir, addr + i, PGSIZE, PADDR(mem), PTE_W|PTE_U);
}
return 1;
}