From eb18645f17877de4ced951eed5abac61bdfcd5c5 Mon Sep 17 00:00:00 2001 From: Robert Morris Date: Thu, 5 Aug 2010 12:10:54 -0400 Subject: [PATCH] fix allocuvm() to handle sbrk() with non-page-granularity argument (maybe this never worked, but it works now) --- Makefile | 2 +- defs.h | 2 -- mmu.h | 4 ++++ usertests.c | 34 ++++++++++++++++++++++++++++++++++ vm.c | 36 ++++++++++++++++++++++++++---------- 5 files changed, 65 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index a0c901d..ef9b66d 100644 --- a/Makefile +++ b/Makefile @@ -38,7 +38,7 @@ AS = $(TOOLPREFIX)gas LD = $(TOOLPREFIX)ld OBJCOPY = $(TOOLPREFIX)objcopy OBJDUMP = $(TOOLPREFIX)objdump -CFLAGS = -fno-pic -static -fno-builtin -fno-strict-aliasing -O2 -Wall -MD -ggdb -m32 +CFLAGS = -fno-pic -static -fno-builtin -fno-strict-aliasing -O2 -Wall -MD -ggdb -m32 -Werror CFLAGS += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector) ASFLAGS = -m32 -gdwarf-2 # FreeBSD ld wants ``elf_i386_fbsd'' diff --git a/defs.h b/defs.h index 86268b2..b414a5f 100644 --- a/defs.h +++ b/defs.h @@ -153,8 +153,6 @@ void uartintr(void); void uartputc(int); // vm.c -#define PGROUNDUP(sz) ((sz+PGSIZE-1) & ~(PGSIZE-1)) -extern pde_t *kpgdir; void pminit(void); void ksegment(void); void kvmalloc(void); diff --git a/mmu.h b/mmu.h index 378ae22..e3ea46f 100644 --- a/mmu.h +++ b/mmu.h @@ -126,6 +126,9 @@ struct segdesc { #define PTXSHIFT 12 // offset of PTX in a linear address #define PDXSHIFT 22 // offset of PDX in a linear address +#define PGROUNDUP(sz) (((sz)+PGSIZE-1) & ~(PGSIZE-1)) +#define PGROUNDDOWN(a) ((char*)((((unsigned int)a) & ~(PGSIZE-1)))) + // Page table/directory entry flags. #define PTE_P 0x001 // Present #define PTE_W 0x002 // Writeable @@ -148,6 +151,7 @@ struct segdesc { #define PTE_ADDR(pte) ((uint) (pte) & ~0xFFF) typedef uint pte_t; +extern pde_t *kpgdir; // Control Register flags #define CR0_PE 0x00000001 // Protection Enable diff --git a/usertests.c b/usertests.c index cc2601c..2bd21ba 100644 --- a/usertests.c +++ b/usertests.c @@ -1229,6 +1229,38 @@ forktest(void) printf(1, "fork test OK\n"); } +void +sbrktest(void) +{ + printf(stdout, "sbrk test\n"); + char *a = sbrk(0); + int i; + for(i = 0; i < 5000; i++){ + char *b = sbrk(1); + if(b != a){ + printf(stdout, "sbrk test failed %d %x %x\n", i, a, b); + exit(); + } + *b = 1; + a = b + 1; + } + int pid = fork(); + if(pid < 0){ + printf(stdout, "sbrk test fork failed\n"); + exit(); + } + char *c = sbrk(1); + c = sbrk(1); + if(c != a + 1){ + printf(stdout, "sbrk test failed post-fork\n"); + exit(); + } + if(pid == 0) + exit(); + wait(); + printf(stdout, "sbrk test OK\n"); +} + int main(int argc, char *argv[]) { @@ -1240,6 +1272,8 @@ main(int argc, char *argv[]) } close(open("usertests.ran", O_CREATE)); + sbrktest(); + opentest(); writetest(); writetest1(); 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; }