All local system calls are asynchronous (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 11 Nov 2010 02:32:44 +0000 (18:32 -0800)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:56 +0000 (17:35 -0700)
Rebuild your cross compiler.

For now, userspace just submits a call and then spins on the response
(synchronous in userspace, but async in the kernel).  When the kernel
blocks, it first attempts to start/run more syscalls, then restarts the
current_tf (which gets the process back to where it trapped into the
kernel).  The kernel will return how many syscalls it started, (similar
to Xen's interface), so if you batch calls, you need to make sure they
all started.

Regardless of whether the call blocked or not, the kernel will return
via smp_idle().  A blocked call will simply post its results and
smp_idle(), just like when it didn't block.  Current_tf only has meaning
the "first time", when the process first trapped in.  After a kthread
unblocks, current_tf has already restarted, so it no longer has meaning
(and should be 0'd).  Things get a bit tricky with some syscalls that
don't return (like yield, resource_req, exec, etc).  Fork is also a bit
tricky.

I can see why people like synchronous calls backed by a single kernel
task - but this is quite awesome when it works right.

14 files changed:
kern/arch/i686/ros/bits/syscall.h
kern/arch/i686/ros/syscall.h
kern/arch/i686/trap.c
kern/arch/sparc/ros/syscall.h
kern/arch/sparc/trap.c
kern/include/ros/ring_syscall.h
kern/include/ros/syscall.h
kern/include/smp.h
kern/include/syscall.h
kern/src/arsc.c
kern/src/resource.c
kern/src/smp.c
kern/src/syscall.c
tools/compilers/gcc-glibc/glibc-2.11.1-ros/sysdeps/ros/i386/tls.h

index 6aed514..edc4694 100644 (file)
@@ -46,6 +46,7 @@ static inline intreg_t __syscall_sysenter(uint16_t num, intreg_t a1,
                        "r" (a3),
                        "D" (a4)
                      : "cc", "memory");
+       // TODO: gut errno 
        if(err != 0 && err_loc != NULL)
                *err_loc = err;
        return ret;
@@ -83,6 +84,7 @@ static inline intreg_t __syscall_trap(uint16_t num, intreg_t a1,
                       "D" (a4),
                       "S" (a5)
                     : "cc", "memory");
+       // TODO: gut errno 
        if(err != 0 && err_loc != NULL)
                *err_loc = err;
        return ret;
index 891df14..99243a4 100644 (file)
@@ -6,32 +6,19 @@
 #ifndef ROS_KERNEL
 
 #include <ros/arch/bits/syscall.h>
-#include <errno.h>
 
-static inline intreg_t syscall_sysenter(uint16_t num, intreg_t a1,
-                                  intreg_t a2, intreg_t a3,
-                                  intreg_t a4, intreg_t a5)
-{
-       return __syscall_sysenter(num, a1, a2, a3, a4, a5, &errno);
-}
-static inline intreg_t syscall_trap(uint16_t num, intreg_t a1,
-                                  intreg_t a2, intreg_t a3,
-                                  intreg_t a4, intreg_t a5)
-{
-       return __syscall_trap(num, a1, a2, a3, a4, a5, &errno);
-}
-
-static inline long __attribute__((always_inline))
-__ros_syscall(long _num, long _a0, long _a1, long _a2, long _a3, long _a4)
+/* Traditional interface, though this should only be used for *syscalls */
+static inline long __ros_arch_syscall(long _num, long _a0, long _a1, long _a2,
+                                      long _a3, long _a4)
 {
        #ifdef __CONFIG_SYSCALL_TRAP__
-               return syscall_trap(_num, _a0, _a1, _a2, _a3, _a4);
+               return __syscall_trap(_num, _a0, _a1, _a2, _a3, _a4, 0);
        #else
-               return syscall_sysenter(_num, _a0, _a1, _a2, _a3, _a4);
+               return __syscall_sysenter(_num, _a0, _a1, _a2, _a3, _a4, 0);
        #endif
 }
 
-#endif
+#endif /* ifndef ROS_KERNEL */
 
 #endif
 
index fe53da6..1fd56a8 100644 (file)
@@ -234,15 +234,12 @@ trap_dispatch(trapframe_t *tf)
                        // check for userspace, for now
                        assert(tf->tf_cs != GD_KT);
                        struct per_cpu_info* coreinfo = &per_cpu_info[core_id()];
-                       coreinfo->cur_ret.returnloc = &(tf->tf_regs.reg_eax);
-                       coreinfo->cur_ret.errno_loc = &(tf->tf_regs.reg_esi);
-                       // syscall code wants an edible reference for current
-                       kref_get(&coreinfo->cur_proc->kref, 1);
-                       tf->tf_regs.reg_eax =
-                               syscall(coreinfo->cur_proc, 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);
-                       kref_put(&coreinfo->cur_proc->kref);
+                       coreinfo->tf_retval_loc = &(tf->tf_regs.reg_eax);
+                       /* Set up and run the async calls */
+                       prep_syscalls(current, (struct syscall*)tf->tf_regs.reg_eax,
+                                     tf->tf_regs.reg_edx);
+                       run_local_syscall();
+                       warn("No syscalls on a trap!");
                        break;
                default:
                        // Unexpected trap: The user process or the kernel has a bug.
@@ -381,27 +378,19 @@ void sysenter_init(void)
 void sysenter_callwrapper(struct trapframe *tf)
 {
        struct per_cpu_info* coreinfo = &per_cpu_info[core_id()];
-       if (!in_kernel(tf))
-               coreinfo->cur_tf = tf;
-       coreinfo->cur_ret.returnloc = &(tf->tf_regs.reg_eax);
-       coreinfo->cur_ret.errno_loc = &(tf->tf_regs.reg_esi);
-
-       // syscall code wants an edible reference for current
-       kref_get(&current->kref, 1);
-       tf->tf_regs.reg_eax = (intreg_t) syscall(current,
-                                                tf->tf_regs.reg_eax,
-                                                tf->tf_regs.reg_esi,
-                                                tf->tf_regs.reg_ecx,
-                                                tf->tf_regs.reg_ebx,
-                                                tf->tf_regs.reg_edi,
-                                                0);
-       kref_put(&current->kref);
-       /*
-        * careful here - we need to make sure that this current is the right
+       if (in_kernel(tf))
+               panic("sysenter from a kernel TF!!");
+       coreinfo->cur_tf = tf;
+       coreinfo->tf_retval_loc = &(tf->tf_regs.reg_eax);
+       /* Set up and run the async calls */
+       prep_syscalls(current, (struct syscall*)tf->tf_regs.reg_eax,
+                     tf->tf_regs.reg_esi);
+       run_local_syscall();            /* alternatively, we can call smp_idle() */
+       warn("No syscalls on a sysenter!");
+       /* 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.
-        * likewise, tf could be pointing to random gibberish.
-        */
+        * likewise, tf could be pointing to random gibberish. */
        proc_restartcore(current, tf);
 }
 
index 30b2817..b902b66 100644 (file)
@@ -6,7 +6,7 @@
 #include <errno.h>
 
 static inline long __attribute__((always_inline))
-__ros_syscall(long _num, long _a0, long _a1, long _a2, long _a3, long _a4)
+__ros_arch_syscall(long _num, long _a0, long _a1, long _a2, long _a3, long _a4)
 {
        register long num asm("g1") = _num;
        register long a0 asm("o0") = _a0, a1 asm("o1") = _a1;
@@ -16,6 +16,7 @@ __ros_syscall(long _num, long _a0, long _a1, long _a2, long _a3, long _a4)
        asm volatile("ta 8" : "=r"(a0),"=r"(a1)
                     : "r"(num),"0"(a0),"1"(a1),"r"(a2),"r"(a3),"r"(a4));
 
+       // TODO: gut errno
        // move a1, a2 into regular variables so they're volatile across
        // procedure calls (of which errno is one)
        long ret = a0, err = a1;
index e04fb4d..e60bc63 100644 (file)
@@ -459,13 +459,11 @@ handle_syscall(trapframe_t* state)
 
        set_current_tf(state);
 
-       coreinfo->cur_ret.returnloc = &(state->gpr[8]);
-       coreinfo->cur_ret.errno_loc = &(state->gpr[9]);
+       coreinfo->tf_retval_loc = &(state->gpr[8]);
 
-       // syscall code wants an edible reference for current
-       kref_get(&coreinfo->cur_proc->kref, 1);
-       state->gpr[8] = syscall(current,num,a1,a2,a3,a4,a5);
-       kref_put(&coreinfo->cur_proc->kref);
+       prep_syscalls(current, (struct syscall*)a1, a2);
+       run_local_syscall();
+       warn("No syscalls on a trap!");
 
        proc_restartcore(current,state);
 }
index 968c1af..4eb6856 100644 (file)
@@ -5,6 +5,8 @@
 #include <ros/ring_buffer.h>
 
 #define NUM_SYSCALL_ARGS 6
+/* This will need to change to represent sending pointers to syscalls, not the
+ * syscalls themselves */
 typedef struct syscall_req {
         uint32_t num;
         uint32_t flags;
index 0a9dc75..b4de63a 100644 (file)
@@ -1,11 +1,65 @@
 #ifndef ROS_INCLUDE_SYSCALL_H
 #define ROS_INCLUDE_SYSCALL_H
 
+#include <arch/arch.h>
 #include <ros/bits/syscall.h>
+#include <ros/arch/syscall.h>
+
+/* Flags for an individual syscall */
+#define SC_DONE                                        0x0001
+
+struct syscall {
+       unsigned int                            num;
+       long                                            retval;
+       int                                                     err;                    /* errno */
+       int                                                     flags;
+       long                                            arg0;
+       long                                            arg1;
+       long                                            arg2;
+       long                                            arg3;
+       long                                            arg4;
+       long                                            arg5;
+};
+
+#ifndef ROS_KERNEL
+
+/* These are simple synchronous system calls, built on top of the kernel's async
+ * interface.  This version makes no assumptions about errno.  You usually don't
+ * want this. */
+static inline long __ros_syscall(long _num, long _a0, long _a1, long _a2,
+                                 long _a3, long _a4, int *errno_loc)
+{
+       int num_started;
+       struct syscall sysc = {0};
+       sysc.num = _num;
+       sysc.arg0 = _a0;
+       sysc.arg1 = _a1;
+       sysc.arg2 = _a2;
+       sysc.arg3 = _a3;
+       sysc.arg4 = _a4;
+       // TODO: arg5
+       num_started = __ros_arch_syscall(&sysc, 1, 0, 0, 0, 0);
+       while (!(sysc.flags & SC_DONE))
+               cpu_relax();
+       if (errno_loc)
+               *errno_loc = sysc.err;
+       return sysc.retval;
+}
 
-// convenience wrapper for __ros_syscall
+#include <errno.h>
+
+/* This version knows about errno and will handle it. */
+static inline long __ros_syscall_errno(long _num, long _a0, long _a1, long _a2,
+                                       long _a3, long _a4)
+{
+       return __ros_syscall(_num, _a0, _a1, _a2, _a3, _a4, &errno);
+}
+
+/* Convenience wrapper for __ros_syscall */
 #define ros_syscall(which,a0,a1,a2,a3,a4) \
-   __ros_syscall(which,(long)(a0),(long)(a1),(long)(a2),(long)(a3),(long)(a4))
-#include <ros/arch/syscall.h>
+   __ros_syscall_errno(which, (long)(a0), (long)(a1), (long)(a2), (long)(a3), \
+                       (long)(a4))
+
+#endif /* ifndef ROS_KERNEL */
 
 #endif /* !ROS_INCLUDE_SYSCALL_H */
index c8b620a..277d42c 100644 (file)
@@ -23,11 +23,16 @@ typedef sharC_env_t;
 
 struct per_cpu_info {
        spinlock_t lock;
+       /* Process management */
        // cur_proc should be valid on all cores that are not management cores.
        struct proc *cur_proc;
        trapframe_t *cur_tf;
-       struct sys_return cur_ret;
        struct kthread *spare;          /* useful when restarting */
+       /* Syscall management */
+       struct syscall *syscalls;       /* ptr is into cur_proc's address space */
+       unsigned int nr_calls;
+       int *errno_loc;
+       uintreg_t *tf_retval_loc;
 
 #ifdef __SHARC__
        // held spin-locks. this will have to go elsewhere if multiple kernel
@@ -39,7 +44,7 @@ struct per_cpu_info {
        taskstate_t *tss;
        segdesc_t *gdt;
 #endif
-
+       /* KMSGs */
        spinlock_t immed_amsg_lock;
        struct kernel_msg_list NTPTV(a0t) NTPTV(a1t) NTPTV(a2t) immed_amsgs;
        spinlock_t routine_amsg_lock;
index 01cf800..4f989ed 100644 (file)
@@ -30,11 +30,6 @@ struct systrace_record {
        uint32_t                vcoreid;
 };
 
-struct sys_return {
-       uint32_t *returnloc;
-       uint32_t *errno_loc;
-};
-
 /* Syscall table */
 typedef intreg_t (*syscall_t)(struct proc *, uintreg_t, uintreg_t, uintreg_t,
                               uintreg_t, uintreg_t);
@@ -44,8 +39,11 @@ struct sys_table_entry {
 };
 const static struct sys_table_entry syscall_table[];
 /* Syscall invocation */
+void prep_syscalls(struct proc *p, struct syscall *sysc, unsigned int nr_calls);
 intreg_t syscall(struct proc *p, uintreg_t num, uintreg_t a1, uintreg_t a2,
                  uintreg_t a3, uintreg_t a4, uintreg_t a5);
+void run_local_syscall(void);
+void set_errno(int errno);
 
 /* Tracing functions */
 void systrace_start(bool silent);
@@ -55,7 +53,4 @@ int systrace_dereg(bool all, struct proc *p);
 void systrace_print(bool all, struct proc *p);
 void systrace_clear_buffer(void);
 
-/* direct returnval and errno handling */
-void set_errno(uint32_t errno);
-void set_retval(uint32_t retval);
 #endif /* !ROS_KERN_SYSCALL_H */
index 4adb3b1..6550b24 100644 (file)
@@ -94,8 +94,7 @@ static intreg_t process_generic_syscalls(struct proc *p, size_t max)
                // print req
                printd("req no %d, req arg %c\n", req->num, *((char*)req->args[0]));
                
-               coreinfo->cur_ret.returnloc = &(rsp.retval);
-               coreinfo->cur_ret.errno_loc = &(rsp.syserr);
+               coreinfo->errno_loc = (int*)&(rsp.syserr);
                
                rsp.retval = syscall_async(p, req);
                // write response into the slot it came from
index d368c05..818d74e 100644 (file)
@@ -52,7 +52,6 @@ ssize_t core_request(struct proc *p)
                p->env_tf = *current_tf;
                current_tf = 0;                 /* Make sure it isn't used in the future */
                env_push_ancillary_state(p); // TODO: (HSS)
-               set_retval(ESUCCESS);
                /* sending death, since it's not our job to save contexts or anything in
                 * this case.  also, if this returns true, we will not return down
                 * below, and need to eat the reference to p */
index b86739d..3311904 100644 (file)
@@ -41,11 +41,19 @@ atomic_t outstanding_calls = 0;
 void smp_idle(void)
 {
        int8_t state = 0;
-       per_cpu_info_t *myinfo = &per_cpu_info[core_id()];
+       per_cpu_info_t *pcpui = &per_cpu_info[core_id()];
 
-       /* TODO: this is only for a couple commits, to make sure we aren't keeping
-        * this around */
-       assert(!current_tf);
+       /* There was a process running here, and we should return to it */
+       if (pcpui->cur_tf) {                    /* aka, current_tf */
+               assert(pcpui->cur_proc);        /* aka, current */
+               /* We also check in run_local_syscall().  This is for sys_exec() */
+               if (pcpui->nr_calls)
+                       run_local_syscall();
+               /* Now we're done, so return */
+               proc_restartcore(pcpui->cur_proc, pcpui->cur_tf);
+               assert(0);
+       }
+       /* if we made it here, we truly want to idle */
        /* in the future, we may need to proactively leave process context here.
         * for now, it is possible to have a current loaded, even if we are idle
         * (and presumably about to execute a kmsg or fire up a vcore). */
index b526b2e..f4bd2aa 100644 (file)
@@ -59,6 +59,39 @@ static bool proc_is_traced(struct proc *p)
        return false;
 }
 
+/* Helper that "finishes" the current async syscall.  This should be used when
+ * we are calling a function in a syscall that might not return and won't be
+ * able to use the normal syscall return path, such as proc_yield() and
+ * resource_req().  Call this from within syscall.c (I don't want it global).
+ *
+ * It is possible for another user thread to see the syscall being done early -
+ * they just need to be careful with the weird proc management calls (as in,
+ * don't trust an async fork).
+ *
+ * *sysc is in user memory, and should be pinned (TODO: UMEM).  There may be
+ * issues with unpinning this if we never return.
+ *
+ * Note, this is currently tied to how cores execute syscall batches: pcpui
+ * telling them what to do *next*, which should be advanced one past the call we
+ * are currently working on.  If this sucks too much in the future, we can have
+ * two separate struct syscall *s. */
+static void signal_current_sc(int retval)
+{
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       struct syscall *sysc = pcpui->syscalls - 1;     /* it was already advanced */
+       sysc->retval = retval;
+       sysc->flags |= SC_DONE;
+}
+
+/* Callable by any function while executing a syscall (or otherwise, actually).
+ * Prep this by setting the errno_loc in advance. */
+void set_errno(int errno)
+{
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       if (pcpui->errno_loc)
+               *(pcpui->errno_loc) = errno;
+}
+
 /************** Utility Syscalls **************/
 
 static int sys_null(void)
@@ -306,8 +339,10 @@ static error_t sys_proc_destroy(struct proc *p, pid_t pid, int exitcode)
 
 static int sys_proc_yield(struct proc *p, bool being_nice)
 {
+       /* proc_yield() doesn't return - we need to set the syscall retval early */
+       signal_current_sc(0);
        proc_yield(p, being_nice);
-       return 0;
+       assert(0);
 }
 
 static ssize_t sys_fork(env_t* e)
@@ -330,6 +365,12 @@ static ssize_t sys_fork(env_t* e)
        env->ppid = e->pid;
        env->env_tf = *current_tf;
 
+       /* We need to speculatively say the syscall worked before copying the memory
+        * out, since the 'forked' process's call never actually goes through the
+        * syscall return path, and will never think it is done.  This violates a
+        * few things.  Just be careful with fork. */
+       signal_current_sc(0);
+
        env->cache_colors_map = cache_colors_map_alloc();
        for(int i=0; i < llc_cache->num_colors; i++)
                if(GET_BITMASK_BIT(e->cache_colors_map,i))
@@ -404,14 +445,16 @@ static int sys_exec(struct proc *p, char *path, size_t path_l,
        int ret = -1;
        char *t_path;
        struct file *program;
+       struct trapframe *old_cur_tf = current_tf;
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
 
        /* We probably want it to never be allowed to exec if it ever was _M */
        if (p->state != PROC_RUNNING_S) {
                set_errno(EINVAL);
                return -1;
        }
-       /* Can't really exec if we don't have a current_tf to reset */
-       if (!current_tf) {
+       /* Can't exec if we don't have a current_tf to restart (if we fail). */
+       if (!old_cur_tf) {
                set_errno(EINVAL);
                return -1;
        }
@@ -419,10 +462,16 @@ static int sys_exec(struct proc *p, char *path, size_t path_l,
        t_path = user_strdup_errno(p, path, path_l);
        if (!t_path)
                return -1;
+       /* Clear the current_tf.  We won't be returning the 'normal' way.  Even if
+        * we want to return with an error, we need to go back differently in case
+        * we succeed.  This needs to be done before we could possibly block, but
+        * unfortunately happens before the point of no return. */
+       current_tf = 0;
+       /* This could block: */
        program = do_file_open(t_path, 0, 0);
        user_memdup_free(p, t_path);
        if (!program)
-               return -1;                      /* presumably, errno is already set */
+               goto early_error;
        /* Set the argument stuff needed by glibc */
        if (memcpy_from_user_errno(p, p->procinfo->argp, pi->argp,
                                   sizeof(pi->argp)))
@@ -442,15 +491,41 @@ static int sys_exec(struct proc *p, char *path, size_t path_l,
        if (load_elf(p, program)) {
                kref_put(&program->f_kref);
                proc_destroy(p);
-               smp_idle();             /* syscall can't return on failure now */
+               /* We don't want to do anything else - we just need to not accidentally
+                * return to the user (hence the all_out) */
+               goto all_out;
        }
        printd("[PID %d] exec %s\n", p->pid, file_name(program));
        kref_put(&program->f_kref);
-       *current_tf = p->env_tf;
-       return 0;
+       goto success;
+       /* These error and out paths are so we can handle the async interface, both
+        * for when we want to error/return to the proc, as well as when we succeed
+        * and want to start the newly exec'd _S */
 mid_error:
+       /* These two error paths are for when we want to restart the process with an
+        * error value (errno is already set). */
        kref_put(&program->f_kref);
-       return -1;
+early_error:
+       p->env_tf = *old_cur_tf;
+       signal_current_sc(-1);
+success:
+       /* Here's how we'll restart the new (or old) process: */
+       spin_lock(&p->proc_lock);
+       __proc_set_state(p, PROC_RUNNABLE_S);
+       schedule_proc(p);
+       spin_unlock(&p->proc_lock);
+all_out:
+       /* When we idle, we don't want to try executing other syscalls.  If exec
+        * succeeded (or the proc was destroyed) it'd just be wrong. */
+       pcpui->syscalls = 0;
+       pcpui->nr_calls = 0;
+       /* we can't return, since we'd write retvals to the old location of the
+        * sycall struct (which has been freed and is in the old userspace) (or has
+        * already been written to).*/
+       /* TODO: remove this when we remove the one in local_syscall() */
+       kref_put(&current->kref);
+       smp_idle();
+       assert(0);
 }
 
 static ssize_t sys_trywait(env_t* e, pid_t pid, int* status)
@@ -535,7 +610,13 @@ static int sys_shared_page_free(env_t* p1, void*DANGEROUS addr, pid_t p2)
 }
 
 
-/* sys_resource_req(): called directly from dispatch table. */
+static int sys_resource_req(struct proc *p, int type, unsigned int amt_wanted,
+                            unsigned int amt_wanted_min, int flags)
+{
+       signal_current_sc(0);
+       /* this might not return (if it's a _S -> _M transition) */
+       return resource_req(p, type, amt_wanted, amt_wanted_min, flags);
+}
 
 /* Will notify the target on the given vcore, if the caller controls the target.
  * Will honor the target's wanted/vcoreid.  u_ne can be NULL. */
@@ -1201,7 +1282,7 @@ const static struct sys_table_entry syscall_table[] = {
        [SYS_mprotect] = {(syscall_t)sys_mprotect, "mprotect"},
        [SYS_shared_page_alloc] = {(syscall_t)sys_shared_page_alloc, "pa"},
        [SYS_shared_page_free] = {(syscall_t)sys_shared_page_free, "pf"},
-       [SYS_resource_req] = {(syscall_t)resource_req, "resource_req"},
+       [SYS_resource_req] = {(syscall_t)sys_resource_req, "resource_req"},
        [SYS_notify] = {(syscall_t)sys_notify, "notify"},
        [SYS_self_notify] = {(syscall_t)sys_self_notify, "self_notify"},
        [SYS_halt_core] = {(syscall_t)sys_halt_core, "halt_core"},
@@ -1256,10 +1337,6 @@ const static struct sys_table_entry syscall_table[] = {
 intreg_t syscall(struct proc *p, uintreg_t syscallno, uintreg_t a1,
                  uintreg_t a2, uintreg_t a3, uintreg_t a4, uintreg_t a5)
 {
-       /* Initialize the return value and error code returned to 0 */
-       set_retval(ESUCCESS);
-       set_errno(ESUCCESS);
-
        const int max_syscall = sizeof(syscall_table)/sizeof(syscall_table[0]);
 
        uint32_t coreid, vcoreid;
@@ -1303,6 +1380,57 @@ intreg_t syscall(struct proc *p, uintreg_t syscallno, uintreg_t a1,
        return syscall_table[syscallno].call(p, a1, a2, a3, a4, a5);
 }
 
+/* A process can trap and call this function, which will set up the core to
+ * handle all the syscalls.  a.k.a. "sys_debutante(needs, wants)" */
+void prep_syscalls(struct proc *p, struct syscall *sysc, unsigned int nr_calls)
+{
+       int retval;
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       /* TODO: (UMEM) assert / pin the memory range sysc for nr_calls.  Not sure
+        * how we'll know it is done to unpin it. (might need to handle it in
+        * abandon_core() or smp_idle(). */
+       user_mem_assert(p, sysc, nr_calls * sizeof(struct syscall), PTE_USER_RW);
+       /* TEMP! */
+       if (nr_calls != 1)
+               warn("Debutante calls: %d\n", nr_calls);
+       /* Set up this core to process the local call */
+       *pcpui->tf_retval_loc = 0;      /* current_tf's retval says how many are done */
+       pcpui->syscalls = sysc;
+       pcpui->nr_calls = nr_calls;
+}
+
+/* This returns if there are no syscalls to do, o/w it always calls smp_idle()
+ * afterwards. */
+void run_local_syscall(void)
+{
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       struct syscall *sysc;
+
+       if (!pcpui->nr_calls) {
+               /* TODO: UMEM - stop pinning their memory.  Note, we may need to do this
+                * in other places.  This also will be tricky with exec, which doesn't
+                * have the same memory map anymore */
+               return;
+       }
+       sysc = pcpui->syscalls++;               /* get the next */
+       pcpui->nr_calls--;                              /* one less to do */
+       (*pcpui->tf_retval_loc)++;              /* one more started */
+       pcpui->errno_loc = &sysc->err;
+       // TODO: push this deeper into the syscalls */
+       kref_get(&current->kref, 1);
+       /* TODO: arg5 */
+       sysc->retval = syscall(pcpui->cur_proc, sysc->num, sysc->arg0, sysc->arg1,
+                              sysc->arg2, sysc->arg3, sysc->arg4);
+       /* TODO: when we remove this, remove it from sys_exec() too */
+       kref_put(&current->kref);
+       sysc->flags |= SC_DONE;
+       /* regardless of whether the call blocked or not, we smp_idle().  If it was
+        * the last call, it'll return to the process.  If there are more, it will
+        * do them. */
+       smp_idle();
+       assert(0);
+}
+
 /* Syscall tracing */
 static void __init_systrace(void)
 {
@@ -1409,15 +1537,3 @@ void systrace_clear_buffer(void)
        memset(systrace_buffer, 0, sizeof(struct systrace_record) * MAX_SYSTRACES);
        spin_unlock_irqsave(&systrace_lock);
 }
-
-void set_retval(uint32_t retval)
-{
-       struct per_cpu_info* coreinfo = &per_cpu_info[core_id()];
-       *(coreinfo->cur_ret.returnloc) = retval;
-}
-void set_errno(uint32_t errno)
-{
-       struct per_cpu_info* coreinfo = &per_cpu_info[core_id()];
-       if (coreinfo && coreinfo->cur_ret.errno_loc)
-               *(coreinfo->cur_ret.errno_loc) = errno;
-}
index 6d01e68..3f01a16 100644 (file)
@@ -30,8 +30,7 @@
 # include <sysdep.h>
 # include <kernel-features.h>
 #include <sys/mman.h>
-#include <ros/bits/syscall.h>
-#include <ros/arch/bits/syscall.h>
+#include <ros/syscall.h>
 #include <ros/procinfo.h>
 #include <ros/procdata.h>
 #include <ros/arch/mmu.h>
@@ -441,7 +440,7 @@ static const char* tls_init_tp(void* thrdescr)
 
   //TODO: think about how to avoid this. Probably add a field to the 
   // rthreads struct that we manually fill in in _start(). 
-  int core_id = __syscall_sysenter(SYS_getvcoreid,0,0,0,0,0,NULL);
+  int core_id = __ros_syscall(SYS_getvcoreid, 0, 0, 0, 0, 0, NULL);
 
   /* Bug with this whole idea (TODO: (TLSV))*/
   if(__procdata.ldt == NULL)
@@ -452,15 +451,14 @@ static const char* tls_init_tp(void* thrdescr)
     // exist yet (it relies on tls, and we are currently in the process of setting 
     // it up...)
     intreg_t params[3] = { MAP_ANONYMOUS | MAP_POPULATE, -1, 0 };
-    void* ldt = (void*) __syscall_sysenter(SYS_mmap, 0,
-                                           sz, PROT_READ | PROT_WRITE, 
-                                           (intreg_t)params, 0, NULL);
-    if(ldt == MAP_FAILED)
+       void *ldt = (void*)__ros_syscall(SYS_mmap, 0, sz, PROT_READ | PROT_WRITE,
+                                        (long)params, 0, NULL);
+    if (ldt == MAP_FAILED)
       return "tls couldn't allocate memory\n";
 
     __procdata.ldt = ldt;
     // force kernel crossing
-    __syscall_sysenter(SYS_getpid,0,0,0,0,0,NULL);
+       __ros_syscall(SYS_getpid, 0, 0, 0, 0, 0, NULL);
   }
 
   // Build the segment