From 79cd8b3eedeb1f85d3b19fb6119bd5224c4c532a Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Thu, 2 Sep 2010 18:28:36 -0400 Subject: [PATCH] Simplify allocuvm/deallocuvm to operate in a contiguous memory model. This makes their interface match up better with proc->sz and also simplifies the callers (it even gets the main body of exec on one page). --- defs.h | 4 ++-- exec.c | 26 +++++++++++--------------- proc.c | 7 ++++--- vm.c | 58 +++++++++++++++++++++++++++------------------------------- 4 files changed, 44 insertions(+), 51 deletions(-) diff --git a/defs.h b/defs.h index cc3a721..4de95ad 100644 --- a/defs.h +++ b/defs.h @@ -157,8 +157,8 @@ void kvmalloc(void); void vmenable(void); pde_t* setupkvm(void); char* uva2ka(pde_t*, char*); -int allocuvm(pde_t*, char*, uint); -int deallocuvm(pde_t *pgdir, char *addr, uint sz); +int allocuvm(pde_t*, uint, uint); +int deallocuvm(pde_t*, uint, uint); void freevm(pde_t*); void inituvm(pde_t*, char*, uint); int loaduvm(pde_t*, char*, struct inode *ip, uint, uint); diff --git a/exec.c b/exec.c index c518c04..222f64c 100644 --- a/exec.c +++ b/exec.c @@ -11,7 +11,7 @@ exec(char *path, char **argv) { char *mem, *s, *last; int i, argc, arglen, len, off; - uint sz, sp, spoffset, argp; + uint sz, sp, spbottom, argp; struct elfhdr elf; struct inode *ip; struct proghdr ph; @@ -41,22 +41,18 @@ exec(char *path, char **argv) continue; if(ph.memsz < ph.filesz) goto bad; - if(!allocuvm(pgdir, (char *)ph.va, ph.memsz)) + if(!(sz = allocuvm(pgdir, sz, ph.va + ph.memsz))) goto bad; - if(ph.va + ph.memsz > sz) - sz = ph.va + ph.memsz; if(!loaduvm(pgdir, (char *)ph.va, ip, ph.offset, ph.filesz)) goto bad; } iunlockput(ip); // Allocate and initialize stack at sz - sz = PGROUNDUP(sz); - if(!allocuvm(pgdir, (char *)sz, PGSIZE)) + sz = spbottom = PGROUNDUP(sz); + if(!(sz = allocuvm(pgdir, sz, sz + PGSIZE))) goto bad; - mem = uva2ka(pgdir, (char *)sz); - spoffset = sz; - sz += PGSIZE; + mem = uva2ka(pgdir, (char *)spbottom); arglen = 0; for(argc=0; argv[argc]; argc++) @@ -67,22 +63,22 @@ exec(char *path, char **argv) argp = sz - arglen - 4*(argc+1); // Copy argv strings and pointers to stack. - *(uint*)(mem+argp-spoffset + 4*argc) = 0; // argv[argc] + *(uint*)(mem+argp-spbottom + 4*argc) = 0; // argv[argc] for(i=argc-1; i>=0; i--){ len = strlen(argv[i]) + 1; sp -= len; - memmove(mem+sp-spoffset, argv[i], len); - *(uint*)(mem+argp-spoffset + 4*i) = sp; // argv[i] + memmove(mem+sp-spbottom, argv[i], len); + *(uint*)(mem+argp-spbottom + 4*i) = sp; // argv[i] } // Stack frame for main(argc, argv), below arguments. sp = argp; sp -= 4; - *(uint*)(mem+sp-spoffset) = argp; + *(uint*)(mem+sp-spbottom) = argp; sp -= 4; - *(uint*)(mem+sp-spoffset) = argc; + *(uint*)(mem+sp-spbottom) = argc; sp -= 4; - *(uint*)(mem+sp-spoffset) = 0xffffffff; // fake return pc + *(uint*)(mem+sp-spbottom) = 0xffffffff; // fake return pc // Save program name for debugging. for(last=s=path; *s; s++) diff --git a/proc.c b/proc.c index 853eb0a..6f7bdb6 100644 --- a/proc.c +++ b/proc.c @@ -142,14 +142,15 @@ userinit(void) int growproc(int n) { + uint sz = proc->sz; if(n > 0){ - if(!allocuvm(proc->pgdir, (char *)proc->sz, n)) + if(!(sz = allocuvm(proc->pgdir, sz, sz + n))) return -1; } else if(n < 0){ - if(!deallocuvm(proc->pgdir, (char *)(proc->sz + n), 0 - n)) + if(!(sz = deallocuvm(proc->pgdir, sz, sz + n))) return -1; } - proc->sz += n; + proc->sz = sz; switchuvm(proc); return 0; } diff --git a/vm.c b/vm.c index 0104c3e..5c6f943 100644 --- a/vm.c +++ b/vm.c @@ -228,54 +228,50 @@ loaduvm(pde_t *pgdir, char *addr, struct inode *ip, uint offset, uint sz) return 1; } -// 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. +// Allocate memory to the process to bring its size from oldsz to +// newsz. Allocates physical memory and page table entries. oldsz and +// newsz need not be page-aligned, nor does newsz have to be larger +// than oldsz. Returns the new process size or 0 on error. int -allocuvm(pde_t *pgdir, char *addr, uint sz) +allocuvm(pde_t *pgdir, uint oldsz, uint newsz) { - if(addr + sz > (char*)USERTOP) + if(newsz > USERTOP) return 0; - char *a = PGROUNDDOWN(addr); - char *last = PGROUNDDOWN(addr + sz - 1); - for(; a <= last; a += PGSIZE){ - pte_t *pte = walkpgdir(pgdir, a, 0); - if(pte == 0 || (*pte & PTE_P) == 0){ - char *mem = kalloc(); - if(mem == 0){ - cprintf("allocuvm out of memory\n"); - deallocuvm(pgdir, addr, sz); - return 0; - } - memset(mem, 0, PGSIZE); - mappages(pgdir, a, PGSIZE, PADDR(mem), PTE_W|PTE_U); + char *a = (char *)PGROUNDUP(oldsz); + char *last = PGROUNDDOWN(newsz - 1); + for (; a <= last; a += PGSIZE){ + char *mem = kalloc(); + if(mem == 0){ + cprintf("allocuvm out of memory\n"); + deallocuvm(pgdir, newsz, oldsz); + return 0; } + memset(mem, 0, PGSIZE); + mappages(pgdir, a, PGSIZE, PADDR(mem), PTE_W|PTE_U); } - return 1; + return newsz > oldsz ? newsz : oldsz; } -// Deallocate some of the user pages. If addr is not page-aligned, -// then only deallocates starting at the next page boundary. +// Deallocate user pages to bring the process size from oldsz to +// newsz. oldsz and newsz need not be page-aligned, nor does newsz +// need to be less than oldsz. oldsz can be larger than the actual +// process size. Returns the new process size. int -deallocuvm(pde_t *pgdir, char *addr, uint sz) +deallocuvm(pde_t *pgdir, uint oldsz, uint newsz) { - if(addr + sz > (char*)USERTOP) - return 0; - char *a = (char *)PGROUNDUP((uint)addr); - char *last = PGROUNDDOWN(addr + sz - 1); + char *a = (char *)PGROUNDUP(newsz); + char *last = PGROUNDDOWN(oldsz - 1); for(; 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"); + panic("kfree"); kfree((void *) pa); *pte = 0; } } - return 1; + return newsz < oldsz ? newsz : oldsz; } // Free a page table and all the physical memory pages @@ -287,7 +283,7 @@ freevm(pde_t *pgdir) if(!pgdir) panic("freevm: no pgdir"); - deallocuvm(pgdir, 0, USERTOP); + deallocuvm(pgdir, USERTOP, 0); for(i = 0; i < NPDENTRIES; i++){ if(pgdir[i] & PTE_P) kfree((void *) PTE_ADDR(pgdir[i]));