fix allocuvm() to handle sbrk() with non-page-granularity argument

(maybe this never worked, but it works now)
This commit is contained in:
Robert Morris 2010-08-05 12:10:54 -04:00
parent b738a4f1a2
commit eb18645f17
5 changed files with 65 additions and 13 deletions

View file

@ -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''

2
defs.h
View file

@ -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);

4
mmu.h
View file

@ -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

View file

@ -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();

36
vm.c
View file

@ -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;
}