Removed env_segment_alloc/free
authorAndrew Waterman <waterman@ros-dev.(none)>
Tue, 30 Mar 2010 06:13:48 +0000 (23:13 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:38 +0000 (17:35 -0700)
The remaining uses (sys_brk and load_icode) have been replaced
with calls to mmap.  This makes load_icode ugly, but that will
be removed soon anyway.

kern/include/env.h
kern/include/mm.h
kern/src/env.c
kern/src/mm.c
kern/src/syscall.c

index b669153..95e17a8 100644 (file)
@@ -79,8 +79,6 @@ void  env_push_ancillary_state(env_t* e);
 void   env_pop_ancillary_state(env_t* e);
 void   env_user_mem_free(env_t* e, void* start, size_t len);
 void   env_pagetable_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);
 void   env_load_icode(env_t* e, env_t* binary_env, uint8_t *COUNT(size) binary, size_t size);
 
 typedef int (*mem_walk_callback_t)(env_t* e, pte_t* pte, void* va, void* arg);
index 4ec7410..1ec8c61 100644 (file)
@@ -93,7 +93,13 @@ void *do_mmap(struct proc *p, uintptr_t addr, size_t len, int prot, int flags,
              struct file* f, size_t offset);
 int mprotect(struct proc* p, void* addr, size_t len, int prot);
 int munmap(struct proc* p, void* addr, size_t len);
-
 int handle_page_fault(struct proc* p, uintptr_t va, int prot);
 
+// assumes proc_lock is held already
+void *__do_mmap(struct proc *p, uintptr_t addr, size_t len, int prot, int flags,
+               struct file* f, size_t offset);
+int __mprotect(struct proc* p, void* addr, size_t len, int prot);
+int __munmap(struct proc* p, void* addr, size_t len);
+int __handle_page_fault(struct proc* p, uintptr_t va, int prot);
+
 #endif // !ROS_KERN_MM_H
index 60180eb..8105f1f 100644 (file)
@@ -128,66 +128,6 @@ env_setup_vm_error_i:
        return -ENOMEM;
 }
 
-// Allocate len bytes of physical memory for environment env,
-// and map it at virtual address va in the environment's address space.
-// Pages are zeroed by upage_alloc.
-// Pages should be writable by user and kernel.
-// Panic if any allocation attempt fails.
-//
-void
-env_segment_alloc(env_t *e, void *SNT va, size_t len)
-{
-       void *SNT start, *SNT end;
-       size_t num_pages;
-       int i, r;
-       page_t *page;
-       pte_t *pte;
-
-       start = ROUNDDOWN(va, PGSIZE);
-       end = ROUNDUP(va + len, PGSIZE);
-       if (start >= end)
-               panic("Wrap-around in memory allocation addresses!");
-       if ((uintptr_t)end > UTOP)
-               panic("Attempting to map above UTOP!");
-       num_pages = LA2PPN(end - start);
-
-       for (i = 0; i < num_pages; i++, start += PGSIZE) {
-               // skip if a page is already mapped.  yes, page_insert will page_remove
-               // whatever page was already there, but if we are seg allocing adjacent
-               // regions, we don't want to destroy that old mapping/page
-               // though later on we are told we can ignore this...
-               pte = pgdir_walk(e->env_pgdir, start, 0);
-               if (pte && *pte & PTE_P)
-                       continue;
-               if ((r = upage_alloc(e, &page, 1)) < 0)
-                       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 = LA2PPN(end - start);
-
-       env_user_mem_free(e,start,(char*)end-(char*)start);
-}
-
 // this helper function handles all cases of copying to/from user/kernel
 // or between two users.
 static error_t load_icode_memcpy(struct proc *dest_p, struct proc *src_p,
@@ -276,7 +216,18 @@ static void* load_icode(env_t *SAFE e, env_t* binary_env,
                // seg alloc creates PTE_U|PTE_W pages.  if you ever want to change
                // this, there will be issues with overlapping sections
                _end = MAX(_end, (void*)(phdr.p_va + phdr.p_memsz));
-               env_segment_alloc(e, (void*SNT)phdr.p_va, phdr.p_memsz);
+
+               // use mmap to allocate memory.  don't clobber other sections.
+               // this is ugly but will go away once we stop using load_icode
+               uintptr_t pgstart = ROUNDDOWN((uintptr_t)phdr.p_va,PGSIZE);
+               uintptr_t pgend = ROUNDUP((uintptr_t)phdr.p_va+phdr.p_memsz,PGSIZE);
+               for(uintptr_t addr = pgstart; addr < pgend; addr += PGSIZE)
+               {
+                       pte_t* pte = pgdir_walk(e->env_pgdir, (void*)addr, 0);
+                       if(!pte || PAGE_UNMAPPED(*pte))
+                               assert(do_mmap(e,addr,PGSIZE,PROT_READ|PROT_WRITE|PROT_EXEC,
+                                          MAP_ANONYMOUS|MAP_FIXED,NULL,0) != MAP_FAILED);
+               }
 
                // copy section to user mem
                assert(load_icode_memcpy(e,binary_env,(void*)phdr.p_va, binary + phdr.p_offset, phdr.p_filesz) == ESUCCESS);
@@ -290,8 +241,10 @@ static void* load_icode(env_t *SAFE e, env_t* binary_env,
 
        // 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);
+       uintptr_t stacksz = USTACK_NUM_PAGES*PGSIZE;
+       assert(do_mmap(e, USTACKTOP-stacksz, stacksz, PROT_READ | PROT_WRITE,
+                      MAP_FIXED | MAP_ANONYMOUS | MAP_POPULATE, NULL, 0)
+              != MAP_FAILED);
        
        return _end;
 }
index d301180..82ac989 100644 (file)
@@ -29,6 +29,10 @@ void *mmap(struct proc *p, uintptr_t addr, size_t len, int prot, int flags,
                printk("[kernel] mmap() with MAP_ANONYMOUS requires fd == -1.\n");
                return (void*)-1;
        }
+       if((flags & MAP_FIXED) && PGOFF(addr)) {
+               printk("[kernel] mmap() page align your addr.\n");
+               return (void*SAFE)TC(-1);
+       }
 
        struct file* file = NULL;
        if(fd != -1)
@@ -49,22 +53,16 @@ void *mmap(struct proc *p, uintptr_t addr, size_t len, int prot, int flags,
 void *do_mmap(struct proc *p, uintptr_t addr, size_t len, int prot, int flags,
               struct file* file, size_t offset)
 {
-       /* TODO: make this work, instead of a ghetto hack
-        * Find a valid range, make sure it doesn't run into the kernel
-        * make sure there's enough memory (not exceeding quotas)
-        * allocate and map the pages, update appropriate structures (vm_region)
-        * return appropriate pointer
-        * Right now, all we can do is give them the range they ask for.
-        * (or try to find one on sparc) */
-
-       if((flags & MAP_FIXED) && PGOFF(addr)) {
-               printk("[kernel] mmap() page align your addr.\n");
-               return (void*SAFE)TC(-1);
-       }
-
        // TODO: grab the appropriate mm_lock
        spin_lock_irqsave(&p->proc_lock);
+       void* ret = __do_mmap(p,addr,len,prot,flags,file,offset);
+       spin_unlock_irqsave(&p->proc_lock);
+       return ret;
+}
 
+void *__do_mmap(struct proc *p, uintptr_t addr, size_t len, int prot, int flags,
+                struct file* file, size_t offset)
+{
        int num_pages = ROUNDUP(len, PGSIZE) / PGSIZE;
 
        if(!(flags & MAP_FIXED))
@@ -131,13 +129,10 @@ void *do_mmap(struct proc *p, uintptr_t addr, size_t len, int prot, int flags,
        kfree(ptes);
        kfree(pfis);
 
-       // TODO: release the appropriate mm_lock
-       spin_unlock_irqsave(&p->proc_lock);
-
        // fault in pages now if MAP_POPULATE.  die on failure.
        if(flags & MAP_POPULATE)
                for(int i = 0; i < num_pages; i++)
-                       if(handle_page_fault(p,addr+i*PGSIZE,PROT_READ))
+                       if(__handle_page_fault(p,addr+i*PGSIZE,PROT_READ))
                                proc_destroy(p);
 
        return (void*SAFE)TC(addr);
@@ -146,8 +141,6 @@ void *do_mmap(struct proc *p, uintptr_t addr, size_t len, int prot, int flags,
        // and dealloc everything.  or at least define what we want to do if we run
        // out of memory.
        mmap_abort:
-               // TODO: release the appropriate mm_lock
-               spin_unlock_irqsave(&p->proc_lock);
                // not a kernel problem, like if they ask to mmap a mapped location.
                printk("[kernel] mmap() aborted!\n");
                // mmap's semantics.  we need a better error propagation system
@@ -172,10 +165,18 @@ int mprotect(struct proc* p, void* addr, size_t len, int prot)
        }
 
        spin_lock_irqsave(&p->proc_lock);
+       int ret = __mprotect(p,addr,len,prot);
+       spin_unlock_irqsave(&p->proc_lock);
 
+       return ret;
+}
+
+int __mprotect(struct proc* p, void* addr, size_t len, int prot)
+{
        int newperm = (prot & PROT_WRITE) ? PTE_USER_RW :
                      (prot & (PROT_READ|PROT_EXEC)) ? PTE_USER_RO : 0;
 
+       char* end = ROUNDUP((char*)addr+len,PGSIZE);
        for(char* a = (char*)addr; a < end; a += PGSIZE)
        {
                pte_t* pte = pgdir_walk(p->env_pgdir,a,0);
@@ -214,8 +215,6 @@ int mprotect(struct proc* p, void* addr, size_t len, int prot)
                }
        }
 
-       spin_unlock_irqsave(&p->proc_lock);
-
        //TODO: TLB shootdown - needs to be process wide
        tlbflush();
        return 0;
@@ -226,17 +225,28 @@ int munmap(struct proc* p, void* addr, size_t len)
        return mprotect(p, addr, len, PROT_UNMAP);
 }
 
+int __munmap(struct proc* p, void* addr, size_t len)
+{
+       return __mprotect(p, addr, len, PROT_UNMAP);
+}
+
 int handle_page_fault(struct proc* p, uintptr_t va, int prot)
 {
-       int ret = -1;
        va = ROUNDDOWN(va,PGSIZE);
 
        if(prot != PROT_READ && prot != PROT_WRITE && prot != PROT_EXEC)
                panic("bad prot!");
 
        spin_lock_irqsave(&p->proc_lock);
-
-       /// find offending PTE
+       int ret = __handle_page_fault(p,va,prot);
+       spin_unlock_irqsave(&p->proc_lock);
+       return ret;
+}
+       
+int __handle_page_fault(struct proc* p, uintptr_t va, int prot)
+{
+       int ret = -1;
+       // find offending PTE
        pte_t* ppte = pgdir_walk(p->env_pgdir,(void*)va,0);
        // if PTE is NULL, this is a fault that should kill the process
        if(!ppte)
@@ -310,7 +320,6 @@ int handle_page_fault(struct proc* p, uintptr_t va, int prot)
        ret = 0;
 
 out:
-       spin_unlock_irqsave(&p->proc_lock);
        tlbflush();
        return ret;
 }
index 28d6556..ba193e3 100644 (file)
@@ -399,7 +399,7 @@ intreg_t sys_exec(struct proc* p, int fd, procinfo_t* pi)
        }
        proc_init_procinfo(p);
 
-       env_segment_free(p,0,USTACKTOP);
+       env_user_mem_free(p,0,USTACKTOP);
 
        if(load_elf(p,f))
        {
@@ -482,20 +482,25 @@ static intreg_t sys_munmap(struct proc* p, void* addr, size_t len)
 }
 
 static void* sys_brk(struct proc *p, void* addr) {
-       size_t range;
+       ssize_t range;
 
        spin_lock_irqsave(&p->proc_lock);
 
        if((addr < p->heap_bottom) || (addr >= (void*)USTACKBOT))
                goto out;
 
-       if (addr > p->heap_top) {
-               range = addr - p->heap_top;
-               env_segment_alloc(p, p->heap_top, range);
+       uintptr_t real_heap_top = ROUNDUP((uintptr_t)p->heap_top,PGSIZE);
+       uintptr_t real_new_heap_top = ROUNDUP((uintptr_t)addr,PGSIZE);
+       range = real_new_heap_top - real_heap_top;
+
+       if (range > 0) {
+               if(__do_mmap(p, real_heap_top, range, PROT_READ | PROT_WRITE,
+                            MAP_FIXED | MAP_ANONYMOUS, NULL, 0))
+                       goto out;
        }
-       else if (addr < p->heap_top) {
-               range = p->heap_top - addr;
-               env_segment_free(p, addr, range);
+       else if (range < 0) {
+               if(__munmap(p, (void*)real_new_heap_top, -range))
+                       goto out;
        }
        p->heap_top = addr;