summaryrefslogtreecommitdiff
path: root/vm.c
diff options
context:
space:
mode:
authorRobert Morris <[email protected]>2010-08-10 17:08:41 -0400
committerRobert Morris <[email protected]>2010-08-10 17:08:41 -0400
commit83d2db91f75460e1275d67847adec0fca5a9800b (patch)
treecc8df8349ca1981e85d8e343dbf365b59f5eabd7 /vm.c
parentc4cc10da7ef6d65f0f654445e0af35b8309f16c2 (diff)
downloadxv6-labs-83d2db91f75460e1275d67847adec0fca5a9800b.tar.gz
xv6-labs-83d2db91f75460e1275d67847adec0fca5a9800b.tar.bz2
xv6-labs-83d2db91f75460e1275d67847adec0fca5a9800b.zip
allow sbrk(-x) to de-allocate user memory
Diffstat (limited to 'vm.c')
-rw-r--r--vm.c26
1 files changed, 25 insertions, 1 deletions
diff --git a/vm.c b/vm.c
index 6914dd3..8755b82 100644
--- a/vm.c
+++ b/vm.c
@@ -198,7 +198,7 @@ uva2ka(pde_t *pgdir, char *uva)
int
allocuvm(pde_t *pgdir, char *addr, uint sz)
{
- if (addr + sz >= (char*)USERTOP)
+ if (addr + sz > (char*)USERTOP)
return 0;
char *first = PGROUNDDOWN(addr);
char *last = PGROUNDDOWN(addr + sz - 1);
@@ -218,6 +218,30 @@ allocuvm(pde_t *pgdir, char *addr, uint sz)
return 1;
}
+// deallocate some of the user pages, in response to sbrk()
+// with a negative argument. if addr is not page-aligned,
+// then only deallocates starting at the next page boundary.
+int
+deallocuvm(pde_t *pgdir, char *addr, uint sz)
+{
+ if (addr + sz > (char*)USERTOP)
+ return 0;
+ char *first = (char*) PGROUNDUP((uint)addr);
+ char *last = PGROUNDDOWN(addr + sz - 1);
+ char *a;
+ for(a = first; a <= last; a += PGSIZE){
+ pte_t *pte = walkpgdir(pgdir, a, 0);
+ if(pte && (*pte & PTE_P) != 0){
+ uint pa = PTE_ADDR(*pte);
+ if(pa == 0)
+ panic("deallocuvm");
+ kfree((void *) pa, PGSIZE);
+ *pte = 0;
+ }
+ }
+ return 1;
+}
+
// free a page table and all the physical memory pages
// in the user part.
void