Provide a syscall to pop a user context (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 20 Jan 2016 16:47:00 +0000 (11:47 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 2 Feb 2016 22:43:52 +0000 (17:43 -0500)
x86 will need help running VM contexts, which is the only intended use for
this syscall.

The syscall works for any type of context, but be careful actually using
it.  As noted in the comments, Parlib manages TLS separately from
pop_user_ctx(), but this syscall will set the TLS.  When testing, I had
parlib 0 FS base in the the ctx, then had proc_pop_ctx only change the FS
base if it wasn't 0.  Technically, they could want us to set a FS base of
0, so it's not really a fix.  Another solution would be to have parlib read
fsbase, then fill that into the context.  Considering there's no real need
for the kernel to pop HW or SW contexts, none of it is worth doing.

Reinstall your kernel headers.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/include/ros/bits/syscall.h
kern/src/syscall.c

index e51316d..3f47d7f 100644 (file)
@@ -45,6 +45,7 @@
 #define SYS_setup_vmm                          34
 #define SYS_vc_entry                           35
 #define SYS_nanosleep                          36
+#define SYS_pop_ctx                                    37
 
 /* FS Syscalls */
 #define SYS_read                               100
index 9664a41..925fb00 100644 (file)
@@ -1271,6 +1271,54 @@ static int sys_change_to_m(struct proc *p)
        return retval;
 }
 
+/* Assists the user/2LS by atomically running *ctx and leaving vcore context.
+ * Normally, the user can do this themselves, but x86 VM contexts need kernel
+ * support.  The caller ought to be in vcore context, and if a notif is pending,
+ * then the calling vcore will restart in a fresh VC ctx (as if it was notified
+ * or did a sys_vc_entry).
+ *
+ * Note that this will set the TLS too, which is part of the context.  Parlib's
+ * pop_user_ctx currently does *not* do this, since the TLS is managed
+ * separately.  If you want to use this syscall for testing, you'll need to 0
+ * out fsbase and conditionally write_msr in proc_pop_ctx(). */
+static int sys_pop_ctx(struct proc *p, struct user_context *ctx)
+{
+       int pcoreid = core_id();
+       struct per_cpu_info *pcpui = &per_cpu_info[pcoreid];
+       int vcoreid = pcpui->owning_vcoreid;
+       struct preempt_data *vcpd = &p->procdata->vcore_preempt_data[vcoreid];
+
+       /* With change_to, there's a bunch of concerns about changing the vcore map,
+        * since the kernel may have already locked and sent preempts, deaths, etc.
+        *
+        * In this case, we don't care as much.  Other than notif_pending and
+        * notif_disabled, it's more like we're just changing a few registers in
+        * cur_ctx.  We can safely order-after any kernel messages or other changes,
+        * as if the user had done all of the changes we'll make and then did a
+        * no-op syscall.
+        *
+        * Since we are mucking with current_ctx, it is important that we don't
+        * block before or during this syscall. */
+       arch_finalize_ctx(pcpui->cur_ctx);
+       if (copy_from_user(pcpui->cur_ctx, ctx, sizeof(struct user_context))) {
+               /* The 2LS isn't really in a position to handle errors.  At the very
+                * least, we can print something and give them a fresh vc ctx. */
+               printk("[kernel] unable to copy user_ctx, 2LS bug\n");
+               memset(pcpui->cur_ctx, 0, sizeof(struct user_context));
+               proc_init_ctx(pcpui->cur_ctx, vcoreid, vcpd->vcore_entry,
+                             vcpd->vcore_stack, vcpd->vcore_tls_desc);
+               return -1;
+       }
+       proc_secure_ctx(pcpui->cur_ctx);
+       /* The caller leaves vcore context no matter what.  We'll put them back in
+        * if they missed a message. */
+       vcpd->notif_disabled = FALSE;
+       wrmb(); /* order disabled write before pending read */
+       if (vcpd->notif_pending)
+               send_kernel_message(pcoreid, __notify, (long)p, 0, 0, KMSG_ROUTINE);
+       return 0;
+}
+
 /* Initializes a process to run virtual machine contexts, returning the number
  * initialized, optionally setting errno */
 static int sys_setup_vmm(struct proc *p, unsigned int nr_guest_pcores,
@@ -2427,6 +2475,7 @@ const struct sys_table_entry syscall_table[] = {
        [SYS_abort_sysc_fd] = {(syscall_t)sys_abort_sysc_fd, "abort_sysc_fd"},
        [SYS_populate_va] = {(syscall_t)sys_populate_va, "populate_va"},
        [SYS_nanosleep] = {(syscall_t)sys_nanosleep, "nanosleep"},
+       [SYS_pop_ctx] = {(syscall_t)sys_pop_ctx, "pop_ctx"},
 
        [SYS_read] = {(syscall_t)sys_read, "read"},
        [SYS_write] = {(syscall_t)sys_write, "write"},