Made BusyBox work
authorAndrew Waterman <waterman@parcad.millennium.berkeley.edu>
Tue, 9 Feb 2010 09:51:57 +0000 (01:51 -0800)
committerAndrew Waterman <waterman@parcad.millennium.berkeley.edu>
Tue, 9 Feb 2010 09:51:57 +0000 (01:51 -0800)
Minor tweaks to mmap, mostly.

We need a systematic way for the kernel to execute system
calls "anonymously"--for example, to launch the login shell
without having it stored in KFS, we need to be able to
open, read, and close a file.  I made special internal
versions of these, but it's a bit ugly...

kern/arch/i386/pmap.c
kern/arch/sparc/pmap.c
kern/arch/sparc/syscalls.c
kern/include/mm.h
kern/include/syscall.h
kern/src/manager.c
kern/src/mm.c

index 602c884..c221f3a 100644 (file)
@@ -632,32 +632,7 @@ int get_va_perms(pde_t *pgdir, const void *SNT va)
 
 void *get_free_va_range(pde_t *pgdir, uintptr_t addr, size_t len)
 {
-{TRUSTEDBLOCK
-       // want to make sure there aren't mappings already.  will need to do this
-       // later with zones, for when we lazily allocate memory
-
-       uintptr_t startaddr;
-
-       int npages = ROUNDUP(len, PGSIZE) / PGSIZE;
-
-       addr &= ~0xfff;
-       if (!addr)
-               // some sensible default.  can cache the previous value somewhere
-               addr = USTACKBOT; // TODO: not looking down
-       startaddr = addr;       
-       pte_t *pte = pgdir_walk(pgdir, (void*)addr, 0);
-       // what about jumbo pages?
-       // consider looping around, esp if we start from a cached spot
-       // don't map at pg 0, or below brk
-       // consider local memory ranges...
-
-       /*
-       first fit?
-       what if we have a sorted structure of what mem ranges are already in use?
-       */
-
-       return (void*)0xdeadbeef;
-}
+       return NULL;
 }
 
 /* Flushes a TLB, including global pages.  We should always have the CR4_PGE
index 01acaed..de473e4 100644 (file)
@@ -123,9 +123,10 @@ int get_va_perms(pde_t *pgdir, const void *SNT va)
 
 void *get_free_va_range(pde_t *pgdir, uintptr_t addr, size_t len)
 {
-       addr = ROUNDUP(addr,PGSIZE);
+       addr = ROUNDUP(MIN(addr,UMMAP_START),PGSIZE);
        len = ROUNDUP(len,PGSIZE);
-       for(char* a = (char*)addr; a < (char*)UTOP; a++)
+
+       for(char* a = (char*)addr; a < (char*)USTACKBOT; a += PGSIZE)
        {
                for(char* b = a; b < a+len; b += PGSIZE)
                {
@@ -142,152 +143,7 @@ void *get_free_va_range(pde_t *pgdir, uintptr_t addr, size_t len)
        return NULL;
 }
 
-
-
-
 void
 page_check(void)
 {
-/*
-       page_t *pp, *pp0, *pp1, *pp2;
-       page_list_t fl;
-       pte_t *ptep;
-
-       // should be able to allocate three pages
-       pp0 = pp1 = pp2 = 0;
-       assert(page_alloc(&pp0) == 0);
-       assert(page_alloc(&pp1) == 0);
-       assert(page_alloc(&pp2) == 0);
-
-       assert(pp0);
-       assert(pp1 && pp1 != pp0);
-       assert(pp2 && pp2 != pp1 && pp2 != pp0);
-
-       // temporarily steal the rest of the free pages
-       fl = page_free_list;
-       LIST_INIT(&page_free_list);
-
-       // should be no free memory
-       assert(page_alloc(&pp) == -ENOMEM);
-
-       // Fill pp1 with bogus data and check for invalid tlb entries
-       memset(page2kva(pp1), 0xFFFFFFFF, PGSIZE);
-
-       // there is no page allocated at address 0
-       assert(page_lookup(boot_pgdir, (void *) 0x0, &ptep) == NULL);
-
-       // there is no free memory, so we can't allocate a page table 
-       assert(page_insert(boot_pgdir, pp1, 0x0, 0) < 0);
-
-       // free pp0 and try again: pp0 should be used for page table
-       page_free(pp0);
-       assert(page_insert(boot_pgdir, pp1, 0x0, 0) == 0);
-       tlb_invalidate(boot_pgdir, 0x0);
-       // DEP Should have shot down invalid TLB entry - let's check
-       {
-         int *x = 0x0;
-         assert(*x == 0xFFFFFFFF);
-       }
-       assert(PTD_ADDR(boot_pgdir[0]) == page2pa(pp0));
-       assert(check_va2pa(boot_pgdir, 0x0) == page2pa(pp1));
-       assert(pp1->page_ref == 1);
-       assert(pp0->page_ref == 1);
-
-       // should be able to map pp2 at PGSIZE because pp0 is already allocated for page table
-       assert(page_insert(boot_pgdir, pp2, (void*) PGSIZE, 0) == 0);
-       assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp2));
-       assert(pp2->page_ref == 1);
-
-       // Make sure that pgdir_walk returns a pointer to the pte and
-       // not the table or some other garbage
-       {
-         pte_t *p = KADDR(PTD_ADDR(boot_pgdir[PDX(PGSIZE)]));
-         assert(pgdir_walk(boot_pgdir, (void *)PGSIZE, 0) == &p[PTX(PGSIZE)]);
-       }
-
-       // should be no free memory
-       assert(page_alloc(&pp) == -ENOMEM);
-
-       // should be able to map pp2 at PGSIZE because it's already there
-       assert(page_insert(boot_pgdir, pp2, (void*) PGSIZE, PTE_U) == 0);
-       assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp2));
-       assert(pp2->page_ref == 1);
-
-       // Make sure that we actually changed the permission on pp2 when we re-mapped it
-       {
-         pte_t *p = pgdir_walk(boot_pgdir, (void*)PGSIZE, 0);
-         assert(((*p) & PTE_U) == PTE_U);
-       }
-
-       // pp2 should NOT be on the free list
-       // could happen in ref counts are handled sloppily in page_insert
-       assert(page_alloc(&pp) == -ENOMEM);
-
-       // should not be able to map at PTSIZE because need free page for page table
-       assert(page_insert(boot_pgdir, pp0, (void*) PTSIZE, 0) < 0);
-
-       // insert pp1 at PGSIZE (replacing pp2)
-       assert(page_insert(boot_pgdir, pp1, (void*) PGSIZE, 0) == 0);
-
-       // should have pp1 at both 0 and PGSIZE, pp2 nowhere, ...
-       assert(check_va2pa(boot_pgdir, 0) == page2pa(pp1));
-       assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp1));
-       // ... and ref counts should reflect this
-       assert(pp1->page_ref == 2);
-       assert(pp2->page_ref == 0);
-
-       // pp2 should be returned by page_alloc
-       assert(page_alloc(&pp) == 0 && pp == pp2);
-
-       // unmapping pp1 at 0 should keep pp1 at PGSIZE
-       page_remove(boot_pgdir, 0x0);
-       assert(check_va2pa(boot_pgdir, 0x0) == ~0);
-       assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp1));
-       assert(pp1->page_ref == 1);
-       assert(pp2->page_ref == 0);
-
-       // unmapping pp1 at PGSIZE should free it
-       page_remove(boot_pgdir, (void*) PGSIZE);
-       assert(check_va2pa(boot_pgdir, 0x0) == ~0);
-       assert(check_va2pa(boot_pgdir, PGSIZE) == ~0);
-       assert(pp1->page_ref == 0);
-       assert(pp2->page_ref == 0);
-
-       // so it should be returned by page_alloc
-       assert(page_alloc(&pp) == 0 && pp == pp1);
-
-       // should be no free memory
-       assert(page_alloc(&pp) == -ENOMEM);
-
-       // forcibly take pp0 back
-       assert(PTD_ADDR(boot_pgdir[0]) == page2pa(pp0));
-       boot_pgdir[0] = 0;
-       assert(pp0->page_ref == 1);
-       pp0->page_ref = 0;
-
-       // Catch invalid pointer addition in pgdir_walk - i.e. pgdir + PDX(va)
-       {
-         // Give back pp0 for a bit
-         page_free(pp0);
-
-         void * va = (void *)((PGSIZE * NPDENTRIES) + PGSIZE);
-         pte_t *p2 = pgdir_walk(boot_pgdir, va, 1);
-         pte_t *p = KADDR(PTD_ADDR(boot_pgdir[PDX(va)]));
-         assert(p2 == &p[PTX(va)]);
-
-         // Clean up again
-         boot_pgdir[PDX(va)] = 0;
-         pp0->page_ref = 0;
-       }
-
-       // give free list back
-       page_free_list = fl;
-
-       // free the pages we took
-       page_free(pp0);
-       page_free(pp1);
-       page_free(pp2);
-
-       cprintf("page_check() succeeded!\n");
-*/
 }
index 851ded5..16fee46 100644 (file)
@@ -3,14 +3,12 @@
 #include <kmalloc.h>
 #include <ros/error.h>
 #include <pmap.h>
+#include <mm.h>
 #include <arch/frontend.h>
 #include <syscall.h>
 
 void* user_memdup(struct proc* p, const void* va, int len)
 {
-       if(!p)
-               return (void*)va;
-
        void* kva = NULL;
        if(len < 0 || (kva = kmalloc(len,0)) == NULL)
                return ERR_PTR(-ENOMEM);
@@ -36,15 +34,11 @@ static void* user_memdup_errno(struct proc* p, const void* va, int len)
 
 static void user_memdup_free(struct proc* p, void* va)
 {
-       if(p)
-               kfree(va);
+       kfree(va);
 }
 
 char* user_strdup(struct proc* p, const char* va0, int max)
 {
-       if(!p)
-               return (char*)va0;
-
        max++;
        char* kbuf = (char*)kmalloc(PGSIZE,0);
        if(kbuf == NULL)
@@ -88,9 +82,7 @@ static char* user_strdup_errno(struct proc* p, const char* va, int max)
 static int memcpy_to_user_errno(struct proc* p, void* dst, const void* src,
                                 int len)
 {
-       if(!p)
-               memcpy(dst,src,len);
-       else if(memcpy_to_user(p,dst,src,len))
+       if(memcpy_to_user(p,dst,src,len))
        {
                set_errno(current_tf,EINVAL);
                return -1;
@@ -108,7 +100,7 @@ static void* kmalloc_errno(int len)
 
 int user_frontend_syscall_errno(struct proc* p, int n, int a0, int a1, int a2, int a3)
 {
-       int errno, ret = frontend_syscall(p?p->pid:0,n,a0,a1,a2,a3,&errno);
+       int errno, ret = frontend_syscall(p->pid,n,a0,a1,a2,a3,&errno);
        if(errno && p)
                set_errno(current_tf,errno);
        return ret;
@@ -129,11 +121,11 @@ intreg_t sys_write(struct proc* p, int fd, const void* buf, int len)
 
 intreg_t sys_read(struct proc* p, int fd, void* buf, int len)
 {
-       void* kbuf = p ? kmalloc_errno(len) : buf;
+       void* kbuf = kmalloc_errno(len);
        if(kbuf == NULL)
                return -1;
        int ret = fe(read,fd,PADDR(kbuf),len,0);
-       if(ret != -1 && p && memcpy_to_user_errno(p,buf,kbuf,len))
+       if(ret != -1 && memcpy_to_user_errno(p,buf,kbuf,len))
                ret = -1;
        user_memdup_free(p,kbuf);
        return ret;
@@ -149,18 +141,42 @@ intreg_t sys_pwrite(struct proc* p, int fd, const void* buf, int len, int offset
        return ret;
 }
 
+error_t read_page(struct proc* p, int fd, physaddr_t pa, int pgoff)
+{
+       int errno;
+       int ret = frontend_syscall(p->pid,RAMP_SYSCALL_pread,fd,
+                               pa,PGSIZE,pgoff*PGSIZE,&errno);
+
+       if(ret >= 0)
+               memset(KADDR(pa)+ret,0,PGSIZE-ret);
+       return ret;
+}
+
 intreg_t sys_pread(struct proc* p, int fd, void* buf, int len, int offset)
 {
-       void* kbuf = p ? kmalloc_errno(len) : buf;
+       void* kbuf = kmalloc_errno(len);
        if(kbuf == NULL)
                return -1;
        int ret = fe(pread,fd,PADDR(kbuf),len,offset);
-       if(ret != -1 && p && memcpy_to_user_errno(p,buf,kbuf,len))
+       if(ret != -1 && memcpy_to_user_errno(p,buf,kbuf,len))
                ret = -1;
        user_memdup_free(p,kbuf);
        return ret;
 }
 
+error_t open_file(struct proc* p, const char* path, int oflag, int mode)
+{
+       int errno;
+       return frontend_syscall(p->pid,RAMP_SYSCALL_open,PADDR(path),
+                               oflag,mode,0,&errno);
+}
+
+error_t close_file(struct proc* p, int fd)
+{
+       int errno;
+       return frontend_syscall(p->pid,RAMP_SYSCALL_close,fd,0,0,0,&errno);
+}
+
 intreg_t sys_open(struct proc* p, const char* path, int oflag, int mode)
 {
        char* fn = user_strdup_errno(p,path,PGSIZE);
@@ -291,11 +307,11 @@ intreg_t sys_chdir(struct proc* p, const char* path)
 
 intreg_t sys_getcwd(struct proc* p, char* pwd, int size)
 {
-       void* kbuf = p ? kmalloc_errno(size) : pwd;
+       void* kbuf = kmalloc_errno(size);
        if(kbuf == NULL)
                return -1;
        int ret = fe(read,PADDR(kbuf),size,0,0);
-       if(ret != -1 && p && memcpy_to_user_errno(p,pwd,kbuf,strnlen(kbuf,size)))
+       if(ret != -1 && memcpy_to_user_errno(p,pwd,kbuf,strnlen(kbuf,size)))
                ret = -1;
        user_memdup_free(p,kbuf);
        return ret;
index 5634cbf..fe0af2c 100644 (file)
@@ -75,4 +75,9 @@ void *mmap(struct proc *p, uintptr_t addr, size_t len, int prot, int flags,
 int mprotect(struct proc* p, void* addr, size_t len, int prot);
 int munmap(struct proc* p, void* addr, size_t len);
 
+// not sure where to put this (asw)
+error_t open_file(struct proc* p, const char* fn, int flag, int mode);
+error_t close_file(struct proc* p, int fd);
+error_t read_page(struct proc* p, int fd, physaddr_t pa, int pgoff);
+
 #endif // !ROS_KERN_MM_H
index 70c4343..459aa90 100644 (file)
@@ -36,8 +36,6 @@ intreg_t sys_unlink(struct proc* p, const char* path);
 intreg_t sys_chdir(struct proc* p, const char* path);
 intreg_t sys_getcwd(struct proc* p, char* pwd, int size);
 intreg_t sys_gettimeofday(struct proc* p, int* buf);
-intreg_t sys_mprotect(struct proc* p, void* addr, size_t len, int prot);
-intreg_t sys_munmap(struct proc* p, void* addr, size_t len);
 intreg_t sys_tcsetattr(struct proc* p, int fd, int optional_actions, const void* termios_p);
 intreg_t sys_tcgetattr(struct proc* p, int fd, void* termios_p);
 
index 5f25464..3289730 100644 (file)
@@ -11,6 +11,7 @@
 #include <ros/common.h>
 #include <smp.h>
 #include <arch/init.h>
+#include <mm.h>
 
 #include <assert.h>
 #include <manager.h>
@@ -26,6 +27,7 @@
 #include <monitor.h>
 #include <colored_caches.h>
 #include <string.h>
+#include <pmap.h>
 
 /*
  * Currently, if you leave this function by way of proc_run (process_workqueue
@@ -193,7 +195,58 @@ void manager_klueska()
 
 void manager_waterman()
 {
-       manager_klueska();
+#ifndef __i386__
+       static int init = 0;
+       if(!init)
+       {
+               init = 1;
+               struct proc* p = proc_create(NULL,0);
+               int fd = open_file(p,"/lib/ld.so.1",0,0);
+
+               const int MAX_LDSO_PAGES = 256;
+               static int buf[PGSIZE*MAX_LDSO_PAGES/sizeof(int)];
+               for(int i = 0; read_page(p,fd,PADDR((char*)buf+PGSIZE*i),i) == PGSIZE; i++);
+               close_file(p,fd);
+
+               env_load_icode(p,NULL,(void*)buf,MAX_LDSO_PAGES*PGSIZE);
+
+               int pack(struct proc* p, uintptr_t base, int sz, char** args)
+               {
+                       int argc = 0;
+                       while(args[argc])
+                               argc++;
+
+                       uintptr_t* argv = (uintptr_t*)((uintptr_t)p->env_procinfo+base);
+                       int pos = (argc+1)*sizeof(char*);
+                       if(pos > sz)
+                               return -1;
+
+                       argv[0] = UINFO+base+(argc+1)*sizeof(char*);
+                       for(int i = 0; i < argc; i++)
+                       {
+                               int len = strlen(args[i])+1;
+                               if(pos+len > sz)
+                                       return -1;
+
+                               memcpy((char*)argv+pos,args[i],len);
+                               pos += len;
+                               argv[i+1] = argv[i]+len;
+                       }
+                       argv[argc] = 0;
+
+                       return 0;
+               }
+
+               char* argv[] = {"/lib/ld.so.1","/bin/sh","-l",0};
+               char* env[] = {"LD_LIBRARY_PATH=/lib",0};
+
+               pack(p,offsetof(procinfo_t,argv_buf),PROCINFO_MAX_ARGV_SIZE,argv);
+               pack(p,offsetof(procinfo_t,env_buf),PROCINFO_MAX_ENV_SIZE,env);
+               __proc_set_state(p, PROC_RUNNABLE_S);
+               proc_run(p);
+       }
+#endif
+       schedule();
 }
 
 void manager_pearce()
index 52270c7..f1ff912 100644 (file)
@@ -19,15 +19,19 @@ void *mmap(struct proc *p, uintptr_t addr, size_t len, int prot, int flags,
        printd("mmap(addr %x, len %x, prot %x, flags %x, fd %x, off %x)\n", addr,
               len, prot, flags, fd, offset);
        #ifdef __i386__
-       if (fd || offset) {
+       if (fd >= 0 || offset || !(flags & MAP_ANON)) {
                printk("[kernel] mmap() does not support files yet.\n");
                return (void*SAFE)TC(-1);
        }
        #endif
-       if (fd && (flags & MAP_SHARED)) {
+       if (fd >= 0 && (flags & MAP_SHARED)) {
                printk("[kernel] mmap() for files requires !MAP_SHARED.\n");
                return (void*)-1;
        }
+       if (fd >= 0 && (flags & MAP_ANON)) {
+               printk("[kernel] mmap() with MAP_ANONYMOUS requires fd == -1.\n");
+               return (void*)-1;
+       }
 
        /* TODO: make this work, instead of a ghetto hack
         * Find a valid range, make sure it doesn't run into the kernel
@@ -36,39 +40,41 @@ void *mmap(struct proc *p, uintptr_t addr, size_t len, int prot, int flags,
         * return appropriate pointer
         * Right now, all we can do is give them the range they ask for.
         * (or try to find one on sparc) */
-       // TODO: race here
-       if (!(flags & MAP_FIXED))
-       {
-               addr = MIN(addr,UMMAP_START);
-               addr = (uintptr_t)get_free_va_range(p->env_pgdir,UMMAP_START,len);
-               assert(!PGOFF(addr));
-       }
-       else if(PGOFF(addr)) { // MAP_FIXED with unaligned address
+
+       if((flags & MAP_FIXED) && PGOFF(addr)) {
                printk("[kernel] mmap() page align your addr.\n");
                return (void*SAFE)TC(-1);
        }
 
-       int num_pages = ROUNDUP(len, PGSIZE) / PGSIZE;
-       pte_t *a_pte;
        // TODO: grab the appropriate mm_lock
        spin_lock_irqsave(&p->proc_lock);
-       // make sure all pages are available, and in a reasonable range
-       // TODO: can probably do this better with vm_regions, and not do it after
-       // getting the free va range
-       // can also consider not mapping to 0x00000000
-       for (int i = 0; i < num_pages; i++) {
-               a_pte = pgdir_walk(p->env_pgdir, (void*SNT)(addr + i*PGSIZE), 0);
-               if (a_pte && *a_pte & PTE_P)
-                       goto mmap_abort;
-               if (addr + i*PGSIZE >= USTACKBOT)
+
+       int num_pages = ROUNDUP(len, PGSIZE) / PGSIZE;
+
+       if(!(flags & MAP_FIXED))
+       {
+               addr = (uintptr_t)get_free_va_range(p->env_pgdir,addr,len);
+               if(!addr)
                        goto mmap_abort;
+
+               assert(!PGOFF(addr));
+               assert(addr + num_pages*PGSIZE <= USTACKBOT);
        }
+
        page_t *a_page;
        for (int i = 0; i < num_pages; i++) {
                if (upage_alloc(p, &a_page, 1))
                        goto mmap_abort;
-               // TODO: TLB shootdown if replacing an old mapping (depends on semantics
-               // of MAP_FIXED)
+
+               #ifndef __i386__
+               // This is dumb--should not read until faulted in.
+               // This is just to get it correct at first
+               if(!(flags & MAP_ANON))
+                       if(read_page(p,fd,page2pa(a_page),offset+i) < 0)
+                               goto mmap_abort;
+               #endif
+
+               // TODO: TLB shootdown if replacing an old mapping
                // TODO: handle all PROT flags
                if (page_insert(p->env_pgdir, a_page, (void*SNT)(addr + i*PGSIZE),
                                (prot & PROT_WRITE) ? PTE_USER_RW : PTE_USER_RO)) {
@@ -77,19 +83,6 @@ void *mmap(struct proc *p, uintptr_t addr, size_t len, int prot, int flags,
                }
        }
 
-       #ifndef __i386__
-       // This is dumb--should not read until faulted in.
-       // This is just to get it correct at first
-       // TODO: use mmap2 semantics, offset is a PGSIZE
-       if(fd >= 0)
-       {
-               char buf[PGSIZE];
-               int ret = sys_pread(p,fd,(void*)addr,len,offset);
-               if(ret == -1)
-                       goto mmap_abort;
-       }
-       #endif
-
        // TODO: release the appropriate mm_lock
        spin_unlock_irqsave(&p->proc_lock);
        return (void*SAFE)TC(addr);