Handles multiple simultaneous synchronous syscalls
authorBarret Rhoden <brho@cs.berkeley.edu>
Sat, 9 May 2009 22:17:16 +0000 (15:17 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Sat, 9 May 2009 22:17:16 +0000 (15:17 -0700)
Running multiple processes has worked before, but we needed a per-core
curenv to track which process was in the kernel on that specific core
while processing a syscall.

Also changed some debugging statements to include the core number.

kern/env.c
kern/env.h
kern/init.c
kern/pmap.c
kern/syscall.c
kern/syscall.h
kern/trap.c
user/null.c

index 01e2d3d..6b308c7 100644 (file)
 #include <kern/smp.h>
 
 env_t *envs = NULL;            // All environments
-env_t *curenv = NULL;          // The current env
+// TODO: make this a struct of info including the pointer and cacheline-align it
+// This lets the kernel know what process is running on the core it traps into.
+// A lot of the Env business, including this and its usage, will change when we
+// redesign the env as a multi-process.
+env_t* curenvs[MAX_NUM_CPUS] = {[0 ... (MAX_NUM_CPUS-1)] NULL};
 static env_list_t env_free_list;       // Free list
 
 #define ENVGENSHIFT    12              // >= LOGNENV
@@ -36,6 +40,7 @@ int
 envid2env(envid_t envid, env_t **env_store, bool checkperm)
 {
        env_t *e;
+       env_t* curenv = curenvs[lapic_get_id()];
 
        // If envid is zero, return the current environment.
        if (envid == 0) {
@@ -242,6 +247,8 @@ env_alloc(env_t **newenv_store, envid_t parent_id)
        // show them all of env, only specific things like PID, PPID, etc
        memcpy(e->env_procinfo, e, sizeof(env_t));
 
+       env_t* curenv = curenvs[lapic_get_id()];
+
        cprintf("[%08x] new env %08x\n", curenv ? curenv->env_id : 0, e->env_id);
        return 0;
 }
@@ -405,6 +412,7 @@ env_free(env_t *e)
        physaddr_t pa;
 
        // Note the environment's demise.
+       env_t* curenv = curenvs[lapic_get_id()];
        cprintf("[%08x] free env %08x\n", curenv ? curenv->env_id : 0, e->env_id);
 
        // Flush all mapped pages in the user portion of the address space
@@ -517,8 +525,8 @@ env_run(env_t *e)
        //      e->env_tf to sensible values.
 
                // would set the curenv->env_status if we had more states
-       if (e != curenv) {
-               curenv = e;
+       if (e != curenvs[lapic_get_id()]) {
+               curenvs[lapic_get_id()] = e;
                e->env_runs++;
                lcr3(e->env_cr3);
        }
index 040fd9b..d08613f 100644 (file)
@@ -12,7 +12,7 @@
 #endif
 
 extern env_t *envs;            // All environments
-extern env_t *NORACE curenv;           // Current environment
+extern env_t* NORACE curenvs[MAX_NUM_CPUS];
 
 LIST_HEAD(env_list_t, env_t);          // Declares 'struct Env_list'
 
index 0cc26dd..669d922 100644 (file)
@@ -80,36 +80,32 @@ void kernel_init(multiboot_info_t *mboot_info)
        //ENV_CREATE(user_badsegment);
        //ENV_CREATE(user_divzero);
        //ENV_CREATE(user_buggyhello);
+       //ENV_CREATE(user_evilhello);
+       //ENV_CREATE(user_hello);
        //ENV_CREATE(user_hello);
        //ENV_CREATE(user_hello);
        ENV_CREATE(user_null);
-       //ENV_CREATE(user_evilhello);
+       ENV_CREATE(user_null);
+       ENV_CREATE(user_null);
 
-       // We only have one user environment for now, so just run it.
        //env_run(&envs[0]);
-       // run_env_handler just runs the first env, like the prev command
-       // need a way to have call_func to pass a pointer to a struct for arguments
        smp_call_function_single(2, run_env_handler, &envs[0], 0);
-       //smp_call_function_single(4, run_env_handler, &envs[1], 0);
+       smp_call_function_single(4, run_env_handler, &envs[1], 0);
+       smp_call_function_single(6, run_env_handler, &envs[2], 0);
 
        // wait 5 sec, then print what's in shared mem
        udelay(5000000);
-       printk("Attempting to run two syscalls at the beginning of procdata for env 0 and 1:\n\n");
+       printk("Servicing syscalls from Core 0:\n\n");
        while (1) {
                process_generic_syscalls(&envs[0], 1);
-               //process_generic_syscalls(&envs[1], 1);
+               process_generic_syscalls(&envs[1], 1);
+               process_generic_syscalls(&envs[2], 1);
                cpu_relax();
        }
        panic("Don't Panic");
 }
 
 /*
- * Variable panicstr contains argument to first call to panic; used as flag
- * to indicate that the kernel has already called panic.
- */
-static const char *NTS panicstr;
-
-/*
  * Panic is called on unresolvable fatal errors.
  * It prints "panic: mesg", and then enters the kernel monitor.
  */
@@ -117,18 +113,18 @@ void _panic(const char *file, int line, const char *fmt,...)
 {
        va_list ap;
 
-       if (panicstr)
-               goto dead;
-       panicstr = fmt;
-
        va_start(ap, fmt);
-       cprintf("kernel panic at %s:%d: ", file, line);
+       cprintf("kernel panic at %s:%d, from core %d: ", file, line, lapic_get_id());
        vcprintf(fmt, ap);
        cprintf("\n");
        va_end(ap);
 
 dead:
-       /* break into the kernel monitor */
+       /* break into the kernel monitor, if we're core 0 */
+       if (lapic_get_id()) {
+               smp_idle();
+               panic("should never see me");
+       }
        while (1)
                monitor(NULL);
 }
@@ -139,7 +135,7 @@ void _warn(const char *file, int line, const char *fmt,...)
        va_list ap;
 
        va_start(ap, fmt);
-       cprintf("kernel warning at %s:%d: ", file, line);
+       cprintf("kernel warning at %s:%d, from core %d: ", file, line, lapic_get_id());
        vcprintf(fmt, ap);
        cprintf("\n");
        va_end(ap);
index 0504c35..e9d3ac8 100644 (file)
@@ -1034,7 +1034,7 @@ user_mem_assert(env_t *env, const void *DANGEROUS va, size_t len, int perm)
     void *COUNT(len) res = user_mem_check(env,va,len,perm | PTE_U);
        if (!res) {
                cprintf("[%08x] user_mem_check assertion failure for "
-                       "va %08x\n", curenv->env_id, user_mem_check_addr);
+                       "va %08x\n", env->env_id, user_mem_check_addr);
                env_destroy(env);       // may not return
         return NULL;
        }
index fb733d7..655d5f0 100644 (file)
@@ -15,7 +15,7 @@
 #include <kern/console.h>
 
 //Do absolutely nothing.  Used for profiling.
-static void sys_null()
+static void sys_null(env_t* e)
 {
        return;
 }
@@ -24,11 +24,11 @@ static void sys_null()
 // The string is exactly 'len' characters long.
 // Destroys the environment on memory errors.
 static void
-sys_cputs(const char *DANGEROUS s, size_t len)
+sys_cputs(env_t* e, const char *DANGEROUS s, size_t len)
 {
        // Check that the user has permission to read memory [s, s+len).
        // Destroy the environment if not.
-    char *COUNT(len) _s = user_mem_assert(curenv, s, len, PTE_U);
+    char *COUNT(len) _s = user_mem_assert(e, s, len, PTE_U);
 
        // Print the string supplied by the user.
        cprintf("%.*s", len, _s);
@@ -37,7 +37,7 @@ sys_cputs(const char *DANGEROUS s, size_t len)
 // Read a character from the system console.
 // Returns the character.
 static int
-sys_cgetc(void)
+sys_cgetc(env_t* e)
 {
        int c;
 
@@ -51,9 +51,9 @@ sys_cgetc(void)
 
 // Returns the current environment's envid.
 static envid_t
-sys_getenvid(void)
+sys_getenvid(env_t* e)
 {
-       return curenv->env_id;
+       return e->env_id;
 }
 
 // Destroy a given environment (possibly the currently running environment).
@@ -62,58 +62,59 @@ sys_getenvid(void)
 //     -E_BAD_ENV if environment envid doesn't currently exist,
 //             or the caller doesn't have permission to change envid.
 static int
-sys_env_destroy(envid_t envid)
+sys_env_destroy(env_t* e, envid_t envid)
 {
        int r;
-       env_t *e;
+       env_t *env_to_die;
 
-       if ((r = envid2env(envid, &e, 1)) < 0)
+       if ((r = envid2env(envid, &env_to_die, 1)) < 0)
                return r;
-       if (e == curenv)
-               cprintf("[%08x] exiting gracefully\n", curenv->env_id);
+       if (env_to_die == e)
+               cprintf("[%08x] exiting gracefully\n", e->env_id);
        else
-               cprintf("[%08x] destroying %08x\n", curenv->env_id, e->env_id);
-       env_destroy(e);
+               cprintf("[%08x] destroying %08x\n", e->env_id, env_to_die->env_id);
+       env_destroy(env_to_die);
        return 0;
 }
 
 
 
 // Dispatches to the correct kernel function, passing the arguments.
-int32_t syscall(uint32_t syscallno, uint32_t a1, uint32_t a2, uint32_t a3,
-                uint32_t a4, uint32_t a5)
+int32_t syscall(env_t* e, uint32_t syscallno, uint32_t a1, uint32_t a2,
+                uint32_t a3, uint32_t a4, uint32_t a5)
 {
        // Call the function corresponding to the 'syscallno' parameter.
        // Return any appropriate return value.
 
        //cprintf("Incoming syscall number: %d\n    a1: %x\n    a2: %x\n    a3: %x\n    a4: %x\n    a5: %x\n", syscallno, a1, a2, a3, a4, a5);
 
+       assert(e); // should always have an env for every syscall
        if (INVALID_SYSCALL(syscallno))
                return -E_INVAL;
 
        switch (syscallno) {
                case SYS_null:
-                       sys_null();
+                       sys_null(e);
                        return 0;
                case SYS_cputs:
-                       sys_cputs((char *DANGEROUS)a1, (size_t)a2);
+                       sys_cputs(e, (char *DANGEROUS)a1, (size_t)a2);
                        return 0;  // would rather have this return the number of chars put.
                case SYS_cgetc:
-                       return sys_cgetc();
+                       return sys_cgetc(e);
                case SYS_getenvid:
-                       return sys_getenvid();
+                       return sys_getenvid(e);
                case SYS_env_destroy:
-                       return sys_env_destroy((envid_t)a1);
+                       return sys_env_destroy(e, (envid_t)a1);
                default:
                        // or just return -E_INVAL
-                       panic("invalid syscall number (%d)!", syscallno);
+                       panic("Invalid syscall number %d for env %x!", syscallno, *e);
        }
        return 0xdeadbeef;
 }
 
-int32_t syscall_async(syscall_req_t *call)
+int32_t syscall_async(env_t* e, syscall_req_t *call)
 {
-       return syscall(call->num, call->args[0], call->args[1],
+       return syscall(e, call->num, call->args[0], call->args[1],
                       call->args[2], call->args[3], call->args[4]);
 }
 
@@ -140,7 +141,7 @@ uint32_t process_generic_syscalls(env_t* e, uint32_t max)
                syscall_rsp_t rsp;
                // this assumes we get our answer immediately for the syscall.
                syscall_req_t* req = RING_GET_REQUEST(sysbr, ++(sysbr->req_cons));
-               rsp.retval = syscall_async(req);
+               rsp.retval = syscall_async(e, req);
                // write response into the slot it came from
                memcpy(req, &rsp, sizeof(syscall_rsp_t));
                // update our counter for what we've produced (assumes we went in order!)
index 9fcadd3..d2fab8d 100644 (file)
@@ -7,9 +7,9 @@
 #include <inc/syscall.h>
 #include <inc/env.h>
 
-int32_t (SYNCHRONOUS syscall)(uint32_t num, uint32_t a1, uint32_t a2,
-                               uint32_t a3, uint32_t a4, uint32_t a5);
-int32_t syscall_async(syscall_req_t *syscall);
+int32_t (SYNCHRONOUS syscall)(env_t* e, uint32_t num, uint32_t a1, uint32_t a2,
+                              uint32_t a3, uint32_t a4, uint32_t a5);
+int32_t syscall_async(env_t* e, syscall_req_t *syscall);
 uint32_t process_generic_syscalls(env_t* e, uint32_t max);
 
 #endif /* !ROS_KERN_SYSCALL_H */
index 16da5e4..291e135 100644 (file)
@@ -127,7 +127,7 @@ idt_init(void)
 void
 (IN_HANDLER print_trapframe)(trapframe_t *tf)
 {
-       cprintf("TRAP frame at %p\n", tf);
+       cprintf("TRAP frame at %p on core %d\n", tf, lapic_get_id());
        print_regs(&tf->tf_regs);
        cprintf("  es   0x----%04x\n", tf->tf_es);
        cprintf("  ds   0x----%04x\n", tf->tf_ds);
@@ -156,8 +156,9 @@ void
 static void
 (IN_HANDLER trap_dispatch)(trapframe_t *tf)
 {
-       // Handle processor exceptions.
+       env_t* curenv = curenvs[lapic_get_id()];
 
+       // Handle processor exceptions.
        switch(tf->tf_trapno) {
                case T_BRKPT:
                        while (1)
@@ -171,7 +172,7 @@ static void
                        // check for userspace, for now
                        assert(tf->tf_cs != GD_KT);
                        tf->tf_regs.reg_eax =
-                               syscall(tf->tf_regs.reg_eax, tf->tf_regs.reg_edx,
+                               syscall(curenv, tf->tf_regs.reg_eax, tf->tf_regs.reg_edx,
                                        tf->tf_regs.reg_ecx, tf->tf_regs.reg_ebx,
                                        tf->tf_regs.reg_edi, tf->tf_regs.reg_esi);
                        env_run(curenv);
@@ -182,6 +183,7 @@ static void
                        if (tf->tf_cs == GD_KT)
                                panic("Damn Damn!  Unhandled trap in the kernel!");
                        else {
+                               warn("Unexpected trap from userspace");
                                env_destroy(curenv);
                                return;
                        }
@@ -194,6 +196,7 @@ void
 {
        //cprintf("Incoming TRAP frame at %p\n", tf);
 
+       env_t* curenv = curenvs[lapic_get_id()];
        if ((tf->tf_cs & ~3) != GD_UT && (tf->tf_cs & ~3) != GD_KT) {
                print_trapframe(tf);
                panic("Trapframe with invalid CS!");
@@ -201,6 +204,7 @@ void
 
        if ((tf->tf_cs & 3) == 3) {
                // Trapped from user mode.
+               // TODO: this will change when an env has more than one context
                // Copy trap frame (which is currently on the stack)
                // into 'curenv->env_tf', so that running the environment
                // will restart at the trap point.
@@ -306,8 +310,9 @@ page_fault_handler(trapframe_t *tf)
        // LAB 4: Your code here.
 
        // Destroy the environment that caused the fault.
-       cprintf("[%08x] user fault va %08x ip %08x\n",
-               curenv->env_id, fault_va, tf->tf_eip);
+       env_t* curenv = curenvs[lapic_get_id()];
+       cprintf("[%08x] user fault va %08x ip %08x from core %d\n",
+               curenv->env_id, fault_va, tf->tf_eip, lapic_get_id());
        print_trapframe(tf);
        env_destroy(curenv);
 }
index 7da24d9..435f0ce 100644 (file)
@@ -26,7 +26,7 @@ uint64_t total(uint64_t (COUNT(length) array)[], int length)
 void umain(void)
 {
        measure_function(sys_null(), NUM_ITERATIONS, "sys_null");
-       measure_function(asm volatile("nop;"), NUM_ITERATIONS, "nop");
+       //measure_function(asm volatile("nop;"), NUM_ITERATIONS, "nop");
        //measure_function(cprintf("Reg Sync call  \n"), 10, "printf");
        //measure_function_async(cprintf_async(&desc, "Cross-Core call\n"), desc, 10,\
        //                       1, "Async Printf");