Merge branch 'master' into proc-work
[akaros.git] / kern / src / syscall.c
index 7278f4b..537e42c 100644 (file)
 
 #include <string.h>
 #include <assert.h>
-#include <env.h>
+#include <process.h>
 #include <pmap.h>
 #include <trap.h>
 #include <syscall.h>
+#include <kfs.h> // eventually replace this with vfs.h
 
 //Do absolutely nothing.  Used for profiling.
 static void sys_null(void)
@@ -85,12 +86,10 @@ static void sys_shared_page_free(env_t* p1, void* addr, envid_t p2)
 {
 }
 
-// Invalidate the cache of this core
+// Invalidate the cache of this core.  Only useful if you want a cold cache for
+// performance testing reasons.
 static void sys_cache_invalidate(void)
 {
-       // why is this necessary with cache coherence?
-       // is it for coherence with respect to i/o?  --asw
-
        #ifdef __i386__
                wbinvd();
        #endif
@@ -210,6 +209,7 @@ static envid_t sys_getcpuid(void)
        return core_id();
 }
 
+// TODO FIX Me!!!! for processes
 // Destroy a given environment (possibly the currently running environment).
 //
 // Returns 0 on success, < 0 on error.  Errors are:
@@ -233,20 +233,76 @@ static error_t sys_env_destroy(env_t* e, envid_t envid)
 /*
  * Current process yields its remaining "time slice".  Currently works for
  * single-core processes.
+ * TODO: think about how this works with async calls and multicored procs.
+ * Want it to only be callable locally.
  */
-static void sys_yield(env_t *e)
+static void sys_yield(struct proc *p)
 {
        // TODO: watch for races throughout anything related to process statuses
        // and schedule/yielding
-       assert(e->env_status == ENV_RUNNING);
-       e->env_status = ENV_RUNNABLE;
+       assert(p->state == PROC_RUNNING_S);
+       p->state = PROC_RUNNABLE_S;
+       // the implied thing here is that all state has been saved.  and you need
+       // todo that before changing the state to RUNNABLE_S, since the process can
+       // get picked up somewhere else. TODO
        schedule();
+
+       /* TODO
+        * if running_s, give up your time slice (schedule, save silly state, block)
+        * if running_m and 2+ cores are left, give yours up, stay runnable_m
+        * if running_m and last core, switch to runnable_s
+        */
+}
+
+/*
+ * 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
+ * and once there's an mmap, can have most of this in process.c
+ */
+static int sys_proc_create(struct proc *p, 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)
+        * Change this so that all syscalls with a pointer take a length.
+        */
+       strncpy(tpath, path, MAX_PATH_LEN);
+       int kfs_inode = kfs_lookup_path(tpath);
+       if (kfs_inode < 0)
+               return -EINVAL;
+       struct proc *new_p = kfs_proc_create(kfs_inode);
+       return new_p->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(struct proc *p, unsigned pid)
+{
+       struct proc *target = get_proc(pid);
+       error_t retval = 0;
+       spin_lock(&p->lock); // note we can get interrupted here.  it's not bad.
+       // make sure we have access and it's in the right state to be activated
+       if (!proc_controls(p, target))
+               retval = -EPERM;
+       else if (target->state != PROC_CREATED)
+               retval = -EINVAL;
+       else
+               proc_set_state(target, PROC_RUNNABLE_S);
+       spin_unlock(&p->lock);
+       return retval;
 }
 
 // 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.
@@ -286,16 +342,17 @@ intreg_t syscall(env_t* e, uint32_t syscallno, uint32_t a1, uint32_t a2,
                        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:
+               case SYS_getpid:
                        return sys_getenvid(e);
-               case SYS_env_destroy:
+               case SYS_proc_destroy:
                        return sys_env_destroy(e, (envid_t)a1);
                case SYS_yield:
                        sys_yield(e);
                        return ESUCCESS;
                case SYS_proc_create:
+                       return sys_proc_create(e, (char *DANGEROUS)a1);
                case SYS_proc_run:
-                       panic("Not implemented");
+                       return sys_proc_run(e, (size_t)a1);
                default:
                        // or just return -EINVAL
                        panic("Invalid syscall number %d for env %x!", syscallno, *e);
@@ -345,6 +402,8 @@ intreg_t process_generic_syscalls(env_t* e, size_t max)
                //printk("DEBUG POST: sring->req_prod: %d, sring->rsp_prod: %d\n",\
                           sysbr->sring->req_prod, sysbr->sring->rsp_prod);
        }
+       // load sane page tables (and don't rely on decref to do it for you).
+       lcr3(boot_cr3);
        env_decref(e);
        return (intreg_t)count;
 }