#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
#define PTE_ADDR(pte) ((uint) (pte) & ~0xFFF)
typedef uint pte_t;
+extern pde_t *kpgdir;
// Control Register flags
#define CR0_PE 0x00000001 // Protection Enable
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[])
{
}
close(open("usertests.ran", O_CREATE));
+ sbrktest();
+
opentest();
writetest();
writetest1();
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)
{
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)
{
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;
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;
}