Converted curenv calls into an opaque macro
[akaros.git] / kern / src / syscall.c
index 0018394..74ce283 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <arch/types.h>
 #include <arch/x86.h>
+#include <arch/mmu.h>
 #include <arch/console.h>
 #include <arch/apic.h>
 #include <arch/timer.h>
 #include <pmap.h>
 #include <trap.h>
 #include <syscall.h>
+#include <kfs.h> // eventually replace this with vfs.h
 
-void syscall_wrapper(struct Trapframe *tf)
+/* This is called from sysenter's asm, with the tf on the kernel stack. */
+void sysenter_callwrapper(struct Trapframe *tf)
 {
-       env_t* curenv = curenvs[lapic_get_id()];
-    curenv->env_tf = *tf;
-       //Re enable interrupts. sysenter disables them.
-       enable_irq();
+       current->env_tf = *tf;
        
-       curenv->env_tf.tf_regs.reg_eax =
-           (intreg_t) 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,
-                              0);
-       env_run(curenv);
+       // The trapframe on the stack should be ignored from here on.
+       tf = &current->env_tf;
+       tf->tf_regs.reg_eax = (intreg_t) syscall(current,
+                                                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,
+                                                0);
+       /*
+        * careful here - we need to make sure that this current is the right
+        * process, which could be weird if the syscall blocked.  it would need to
+        * restore the proper value in current before returning to here.
+        */
+       env_run(current);
 }
 
 //Do absolutely nothing.  Used for profiling.
@@ -50,7 +56,7 @@ static ssize_t sys_serial_write(env_t* e, const char *DANGEROUS buf, size_t len)
                        serial_send_byte(buf[i]);       
                return (ssize_t)len;
        #else
-               return -E_INVAL;
+               return -EINVAL;
        #endif
 }
 
@@ -67,7 +73,7 @@ static ssize_t sys_serial_read(env_t* e, char *DANGEROUS buf, size_t len)
                }
                return (ssize_t)bytes_read;
        #else
-               return -E_INVAL;
+               return -EINVAL;
        #endif
 }
 
@@ -194,7 +200,7 @@ static envid_t sys_getcpuid(void)
 // Destroy a given environment (possibly the currently running environment).
 //
 // Returns 0 on success, < 0 on error.  Errors are:
-//     -E_BAD_ENV if environment envid doesn't currently exist,
+//     -EBADENV if environment envid doesn't currently exist,
 //             or the caller doesn't have permission to change envid.
 static error_t sys_env_destroy(env_t* e, envid_t envid)
 {
@@ -211,11 +217,66 @@ static error_t sys_env_destroy(env_t* e, envid_t envid)
        return 0;
 }
 
+/*
+ * Current process yields its remaining "time slice".  Currently works for
+ * single-core processes.
+ */
+static void sys_yield(env_t *e)
+{
+       // TODO: watch for races throughout anything related to process statuses
+       // and schedule/yielding
+       assert(e->env_status == ENV_RUNNING);
+       e->env_status = ENV_RUNNABLE;
+       schedule();
+}
+
+/*
+ * Creates a process found at the user string 'path'.  Currently uses KFS.
+ * Not runnable by default, so it needs it's status to be changed so that the
+ * next call to schedule() will try to run it.
+ * TODO: once we have a decent VFS, consider splitting this up
+ */
+static int sys_proc_create(env_t *e, const char *DANGEROUS path)
+{
+       #define MAX_PATH_LEN 256 // totally arbitrary
+       int pid = 0;
+       char tpath[MAX_PATH_LEN];
+       /*
+        * There's a bunch of issues with reading in the path, which we'll
+        * need to sort properly in the VFS.  Main concerns are TOCTOU (copy-in),
+        * whether or not it's a big deal that the pointer could be into kernel
+        * space, and resolving both of these without knowing the length of the
+        * string. (TODO)
+        */
+       strncpy(tpath, path, MAX_PATH_LEN);
+       int kfs_inode = kfs_lookup_path(tpath);
+       if (kfs_inode < 0)
+               return -EINVAL;
+       env_t *new_e = kfs_proc_create(kfs_inode);
+       return new_e->env_id; // TODO replace this with a real proc_id
+}
+
+/* Makes process PID runnable.  Consider moving the functionality to env.c */
+static error_t sys_proc_run(env_t *e, int pid)
+{
+       // TODO PIDs are currently env_id's and encapsulate these functions better
+       // TODO worry about concurrency on the statuses
+       // get the target process (techincally a neg number is invalid)
+       env_t *target = &envs[ENVX(pid)];
+       // make sure it's in the right state to be activated
+       if (target->env_status != ENV_CREATED)
+               return -EINVAL;
+       // make sure we have access (are the parent of)
+       if (target->env_parent_id != e->env_id)
+               return -EINVAL;
+       target->env_status = ENV_RUNNABLE;      
+       return 0;
+}
 
 // TODO: Build a dispatch table instead of switching on the syscallno
 // Dispatches to the correct kernel function, passing the arguments.
 intreg_t syscall(env_t* e, uint32_t syscallno, uint32_t a1, uint32_t a2,
-                uint32_t a3, uint32_t a4, uint32_t a5)
+                 uint32_t a3, uint32_t a4, uint32_t a5)
 {
        // Call the function corresponding to the 'syscallno' parameter.
        // Return any appropriate return value.
@@ -227,35 +288,41 @@ intreg_t syscall(env_t* e, uint32_t syscallno, uint32_t a1, uint32_t a2,
        assert(e); // should always have an env for every syscall
        //printk("Running syscall: %d\n", syscallno);
        if (INVALID_SYSCALL(syscallno))
-               return -E_INVAL;
+               return -EINVAL;
 
        switch (syscallno) {
                case SYS_null:
                        sys_null();
                        return 0;
-               case SYS_serial_write:
-                       //printk("I am here\n");
-                       return sys_serial_write(e, (char *DANGEROUS)a1, (size_t)a2);
-               case SYS_serial_read:
-                       return sys_serial_read(e, (char *DANGEROUS)a1, (size_t)a2);
-               case SYS_cache_invalidate:
-                       sys_cache_invalidate();
-                       return 0;
                case SYS_cache_buster:
                        sys_cache_buster(e, a1, a2, a3);
                        return 0;
+               case SYS_cache_invalidate:
+                       sys_cache_invalidate();
+                       return 0;
                case SYS_cputs:
                        return sys_cputs(e, (char *DANGEROUS)a1, (size_t)a2);
                case SYS_cgetc:
                        return sys_cgetc(e);
-               case SYS_getenvid:
-                       return sys_getenvid(e);
                case SYS_getcpuid:
                        return sys_getcpuid();
+               case SYS_serial_write:
+                       return sys_serial_write(e, (char *DANGEROUS)a1, (size_t)a2);
+               case SYS_serial_read:
+                       return sys_serial_read(e, (char *DANGEROUS)a1, (size_t)a2);
+               case SYS_getenvid:
+                       return sys_getenvid(e);
                case SYS_env_destroy:
                        return sys_env_destroy(e, (envid_t)a1);
+               case SYS_yield:
+                       sys_yield(e);
+                       return 0;
+               case SYS_proc_create:
+                       return sys_proc_create(e, (char *DANGEROUS)a1);
+               case SYS_proc_run:
+                       return sys_proc_run(e, (size_t)a1);
                default:
-                       // or just return -E_INVAL
+                       // or just return -EINVAL
                        panic("Invalid syscall number %d for env %x!", syscallno, *e);
        }
        return 0xdeadbeef;