Adding support for the brk system call
authorKevin Klues <klueska@r53.millennium.berkeley.edu>
Wed, 21 Oct 2009 07:46:06 +0000 (00:46 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Wed, 21 Oct 2009 19:15:27 +0000 (21:15 +0200)
kern/arch/i386/pmap.c
kern/include/env.h
kern/include/ros/memlayout.h
kern/src/env.c
kern/src/mm.c
kern/src/page_alloc.c
kern/src/syscall.c
user/apps/roslib/mhello.c
user/parlib/inc/parlib.h
user/parlib/src/i386/newlib_backend.c
user/parlib/src/syscall.c

index f0aeced..0ead41f 100644 (file)
@@ -650,7 +650,7 @@ void *get_free_va_range(pde_t *pgdir, uintptr_t addr, size_t len)
        addr &= ~0xfff;
        if (!addr)
                // some sensible default.  can cache the previous value somewhere
-               addr = USTACKTOP - PGSIZE; // TODO: not looking down
+               addr = USTACKBOT; // TODO: not looking down
        startaddr = addr;       
        pte_t *pte = pgdir_walk(pgdir, (void*)addr, 0);
        // what about jumbo pages?
index 996bf03..dc3f080 100644 (file)
@@ -64,6 +64,11 @@ struct Env {
        /* Info about this process's resources (granted, desired) for each type. */
        struct resource resources[MAX_NUM_RESOURCES];
 
+       /* Keeps track of this process's current memory allocation 
+         * (i.e. its heap pointer */
+       void* end_text_segment;
+       void* end_data_segment;
+
        // Address space
        pde_t *COUNT(NPDENTRIES) env_pgdir;                     // Kernel virtual address of page dir
        physaddr_t env_cr3;                     // Physical address of page dir
@@ -108,6 +113,8 @@ void        env_push_ancillary_state(env_t* e);
 void   env_pop_ancillary_state(env_t* e);
 void   env_free(env_t *SAFE e);
 void   env_user_mem_free(env_t* e);
+void   env_segment_alloc(env_t *e, void *SNT va, size_t len);
+void   env_segment_free(env_t *e, void *SNT va, size_t len);
 env_t* env_create(uint8_t *COUNT(size) binary, size_t size);
 
 /*
index f19154b..90d84df 100644 (file)
  *                     +------------------------------+ 0xbebfe000
  *                     |       Empty Memory (*)       | --/--  PGSIZE
  *    USTACKTOP  --->  +------------------------------+ 0xbebfd000
- *                     |      Normal User Stack       | RW/RW  PGSIZE
- *                     +------------------------------+ 0xbebfc000
+ *                     |      Normal User Stack       | RW/RW  256*PGSIZE (1MB)
+ *                     +------------------------------+ 0xbeafd000
+ *                     |       Empty Memory (*)       | --/--  PGSIZE
+ *    USTACKBOT  --->  +------------------------------+ 0xbeafc000
  *                     |                              |
  *                     |                              |
  *                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Next page left invalid to guard against exception stack overflow; then:
 // Top of normal user stack
 #define USTACKTOP      (UXSTACKTOP - 2*PGSIZE)
+// Maximum stack depth preallocated to 1MB
+#define USTACK_NUM_PAGES       256
+// Next page left invalid to guard against stack overflow
+// Maximum bottom of normal user stack
+#define USTACKBOT      (USTACKTOP - (USTACK_NUM_PAGES+1)*PGSIZE)
 
 // Where user programs generally begin
 #define UTEXT          (2*PTSIZE)
index ec270a6..2a55103 100644 (file)
@@ -103,6 +103,8 @@ env_init(void)
        for (i = NENV-1; i >= 0; i--) {
                // these should already be set from when i memset'd the array to 0
                envs[i].state = ENV_FREE;
+               envs[i].end_text_segment = (void*)UTEXT;
+               envs[i].end_data_segment = (void*)UTEXT;
                envs[i].env_id = 0;
                TAILQ_INSERT_HEAD(&proc_freelist, &envs[i], proc_link);
        }
@@ -291,7 +293,7 @@ env_alloc(env_t **newenv_store, envid_t parent_id)
        /*
         * Initialize the contents of the e->env_procinfo structure
         */
-        e->env_procinfo->id = (e->env_id & 0x3FF);
+       e->env_procinfo->id = (e->env_id & 0x3FF);
 
        /*
         * Initialize the contents of the e->env_procdata structure
@@ -325,8 +327,8 @@ env_alloc(env_t **newenv_store, envid_t parent_id)
 // Pages should be writable by user and kernel.
 // Panic if any allocation attempt fails.
 //
-static void
-segment_alloc(env_t *e, void *SNT va, size_t len)
+void
+env_segment_alloc(env_t *e, void *SNT va, size_t len)
 {
        void *SNT start, *SNT end;
        size_t num_pages;
@@ -354,11 +356,39 @@ segment_alloc(env_t *e, void *SNT va, size_t len)
                if (pte && *pte & PTE_P)
                        continue;
                if ((r = page_alloc(&page)) < 0)
-                       panic("segment_alloc: %e", r);
+                       panic("env_segment_alloc: %e", r);
                page_insert(e->env_pgdir, page, start, PTE_USER_RW);
        }
 }
 
+void
+env_segment_free(env_t *e, void *SNT va, size_t len)
+{
+       void *SNT start, *SNT end;
+       size_t num_pages;
+       page_t *page;
+       pte_t *pte;
+
+       // Round this up this time so we don't free the page that va is actually on
+       start = ROUNDUP(va, PGSIZE);
+       end = ROUNDUP(va + len, PGSIZE);
+       if (start >= end)
+               panic("Wrap-around in memory free addresses!");
+       if ((uintptr_t)end > UTOP)
+               panic("Attempting to unmap above UTOP!");
+       // page_insert/pgdir_walk alloc a page and read/write to it via its address
+       // starting from pgdir (e's), so we need to be using e's pgdir
+       assert(e->env_cr3 == rcr3());
+       num_pages = PPN(end - start);
+
+       for (int i = 0; i < num_pages; i++, start += PGSIZE) {
+               // skip if a page is already unmapped. 
+               pte = pgdir_walk(e->env_pgdir, start, 0);
+               if (pte && *pte & PTE_P)
+                       page_decref(ppn2page(PPN(*pte)));
+       }
+}
+
 //
 // Set up the initial program binary, stack, and processor flags
 // for a user process.
@@ -371,12 +401,13 @@ segment_alloc(env_t *e, void *SNT va, size_t len)
 // but not actually present in the ELF file - i.e., the program's bss section.
 //
 // Finally, this function maps one page for the program's initial stack.
-static void
+static void*
 load_icode(env_t *SAFE e, uint8_t *COUNT(size) binary, size_t size)
 {
        // asw: copy the headers because they might not be aligned.
        elf_t elfhdr;
        proghdr_t phdr;
+       void* _end = 0;
        memcpy(&elfhdr, binary, sizeof(elfhdr));
 
        int i, r;
@@ -413,21 +444,26 @@ load_icode(env_t *SAFE e, uint8_t *COUNT(size) binary, size_t size)
         // TODO: validate elf header fields!
                // seg alloc creates PTE_U|PTE_W pages.  if you ever want to change
                // this, there will be issues with overlapping sections
-               segment_alloc(e, (void*SNT)phdr.p_va, phdr.p_memsz);
+               _end = MAX(_end, (void*)(phdr.p_va + phdr.p_memsz));
+               env_segment_alloc(e, (void*SNT)phdr.p_va, phdr.p_memsz);
                memcpy((void*)phdr.p_va, binary + phdr.p_offset, phdr.p_filesz);
-               memset((void*)phdr.p_va + phdr.p_filesz, 0, phdr.p_memsz - phdr.p_filesz);
+               memset((void*)phdr.p_va + phdr.p_filesz, 0, 
+                             phdr.p_memsz - phdr.p_filesz);
        }}
 
        proc_set_program_counter(&e->env_tf, elfhdr.e_entry);
        e->env_entry = elfhdr.e_entry;
 
-       // Now map one page for the program's initial stack
-       // at virtual address USTACKTOP - PGSIZE.
-       segment_alloc(e, (void*SNT)(USTACKTOP - PGSIZE), PGSIZE);
+       // Now map USTACK_NUM_PAGES pages for the program's initial stack
+       // starting at virtual address USTACKTOP - USTACK_NUM_PAGES*PGSIZE.
+       env_segment_alloc(e, (void*SNT)(USTACKTOP - USTACK_NUM_PAGES*PGSIZE), 
+                         USTACK_NUM_PAGES*PGSIZE);
 
        // reload the original address space
        lcr3(old_cr3);
        proc_decref(e);
+       
+       return _end;
 }
 
 //
@@ -442,7 +478,12 @@ env_t* env_create(uint8_t *binary, size_t size)
        curid = (current ? current->env_id : 0);
        if ((r = env_alloc(&e, curid)) < 0)
                panic("env_create: %e", r);
-       load_icode(e, binary, size);
+       
+       /* Load the binary and set the current locations of the elf segments.
+        * All end-of-segment pointers are page aligned (invariant) */
+       e->end_text_segment = load_icode(e, binary, size);
+       e->end_data_segment = e->end_text_segment;
+
        return e;
 }
 
index 734afdd..f26cc83 100644 (file)
@@ -49,7 +49,7 @@ void *mmap(struct proc *p, uintptr_t addr, size_t len, int prot, int flags,
                a_pte = pgdir_walk(p->env_pgdir, (void*SNT)addr, 0);
                if (a_pte && *a_pte & PTE_P)
                        goto mmap_abort;
-               if (addr + i*PGSIZE >= USTACKTOP - PGSIZE)
+               if (addr + i*PGSIZE >= USTACKBOT)
                        goto mmap_abort;
        }
        page_t *a_page;
index 6dcba14..fcbe64a 100644 (file)
@@ -288,6 +288,10 @@ void page_decref(page_t *page)
  */
 static void __page_decref(page_t *page)
 {
+       if (page->page_ref == 0) {
+               warn("Trying to Free already freed page...\n");
+               return;
+       }
        if (--page->page_ref == 0)
                __page_free(page);
 }
index 56a7058..67f9c53 100644 (file)
@@ -409,6 +409,26 @@ static error_t sys_proc_run(struct proc *p, unsigned pid)
        return retval;
 }
 
+static error_t sys_brk(struct proc *p, void* addr) {
+       size_t range;
+
+       if((addr < p->end_text_segment) || (addr >= (void*)USTACKBOT))
+               return -EINVAL;
+       if(addr == p->end_data_segment)
+               return ESUCCESS;
+
+       if (addr > p->end_data_segment) {
+               range = addr - p->end_data_segment;
+               env_segment_alloc(p, p->end_data_segment, range);
+       }
+       else if (addr < p->end_data_segment) {
+               range = p->end_data_segment - addr;
+               env_segment_free(p, addr, range);
+       }
+       p->end_data_segment = addr;
+       return ESUCCESS;
+}
+
 /* Executes the given syscall.
  *
  * Note tf is passed in, which points to the tf of the context on the kernel
@@ -480,8 +500,7 @@ intreg_t syscall(struct proc *p, trapframe_t *tf, uintreg_t syscallno,
                        _a6 = args[2];
                        return (intreg_t) mmap(p, a1, a2, a3, _a4, _a5, _a6);
                case SYS_brk:
-                       printk("brk not implemented yet\n");
-                       return -EINVAL;
+                       return sys_brk(p, (void*)a1);
                case SYS_resource_req:
                        /* preemptively set the return code to 0.  if it's not, it will get
                         * overwriten on a proper return path.  if it ends up being a core
index 33e5d73..8fe0539 100644 (file)
@@ -48,7 +48,7 @@ int main(int argc, char** argv)
                        case TEST_MMAP:
                                cprintf("Testing MMAP\n");
                                void* addr;
-                               addr = sys_mmap((void*SNT)USTACKTOP - 20*PGSIZE, 8*PGSIZE, 3,
+                               addr = sys_mmap((void*SNT)USTACKBOT-8*PGSIZE, 8*PGSIZE, 3,
                                                MAP_FIXED, 0, 0);
                                cprintf("got addr = 0x%08x\n", addr);
                                *(int*)addr = 0xdeadbeef;
index 660bef7..b3a5f11 100644 (file)
@@ -35,6 +35,7 @@ ssize_t     sys_eth_read(void *COUNT(len) buf, size_t len);
 ssize_t     sys_run_binary(void* binary_buf, void* arg, size_t len);
 int         sys_getpid(void);
 size_t      sys_getcpuid(void);
+error_t     sys_brk(void* addr);
 error_t     sys_proc_destroy(int pid);
 ssize_t     sys_shared_page_alloc(void *COUNT(PGSIZE) *addr, pid_t p2, 
                                   int p1_flags, int p2_flags);
index ca1c6d5..1e327ec 100644 (file)
@@ -432,15 +432,14 @@ void* sbrk(ptrdiff_t incr)
        debug_in_out("SBRK\n");
        debug_in_out("\tincr: %u\n", incr);     
 
-       #define HEAP_SIZE (1<<18)
-       static uint8_t array[HEAP_SIZE];
-       static uint8_t *BND(array, array + HEAP_SIZE) heap_end = array;
-       static uint8_t *stack_ptr = &(array[HEAP_SIZE-1]);
+       extern char (SNT RO _end)[];
+       static void* heap_end = NULL;
+       if (heap_end == NULL)
+               heap_end = (void*)_end;
 
        uint8_t* prev_heap_end; 
-
        prev_heap_end = heap_end;
-       if (heap_end + incr > stack_ptr) {
+       if (sys_brk(heap_end + incr) < 0) {
                errno = ENOMEM;
                return (void*CT(1))TC(-1);
        }
index 10aeae9..2fbe086 100644 (file)
@@ -7,6 +7,11 @@ error_t sys_proc_destroy(int pid)
        return syscall(SYS_proc_destroy, pid, 0, 0, 0, 0);
 }
 
+error_t sys_brk(void* addr)
+{
+       return syscall(SYS_brk, (intreg_t)addr, 0, 0, 0, 0);
+}
+
 int sys_getpid(void)
 {
         return syscall(SYS_getpid, 0, 0, 0, 0, 0);