Add user support for VM contexts
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 20 Jan 2016 22:34:44 +0000 (17:34 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 2 Feb 2016 22:43:52 +0000 (17:43 -0500)
VM contexts are a lot like HW contexts.  The FP state may be dirty, and it
is in the processor's FP registers (or VCPD, if the kernel saved it).  The
FP state is independent of the general purpose registers as far as VMX
goes, which works out well: the VM ctx is just another general purpose
context, albeit one that needs kernel support to enter or exit.

And of course, a VMM needs to build a VM context and try to run it.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
user/parlib/include/x86/vcore64.h
user/parlib/signal.c
user/parlib/uthread.c
user/parlib/x86/vcore.c

index bf3815b..8442d27 100644 (file)
@@ -195,15 +195,29 @@ static inline void pop_sw_tf(struct sw_trapframe *sw_tf, uint32_t vcoreid)
  * a notification message while notifs were disabled. */
 static inline void pop_user_ctx(struct user_context *ctx, uint32_t vcoreid)
 {
  * a notification message while notifs were disabled. */
 static inline void pop_user_ctx(struct user_context *ctx, uint32_t vcoreid)
 {
-       if (ctx->type == ROS_HW_CTX)
+       switch (ctx->type) {
+       case ROS_HW_CTX:
                pop_hw_tf(&ctx->tf.hw_tf, vcoreid);
                pop_hw_tf(&ctx->tf.hw_tf, vcoreid);
-       else
+               break;
+       case ROS_SW_CTX:
                pop_sw_tf(&ctx->tf.sw_tf, vcoreid);
                pop_sw_tf(&ctx->tf.sw_tf, vcoreid);
+               break;
+       case ROS_VM_CTX:
+               ros_syscall(SYS_pop_ctx, ctx, 0, 0, 0, 0, 0);
+               break;
+       }
+       assert(0);
 }
 
 /* Like the regular pop_user_ctx, but this one doesn't check or clear
  * notif_pending.  The only case where we use this is when an IRQ/notif
 }
 
 /* Like the regular pop_user_ctx, but this one doesn't check or clear
  * notif_pending.  The only case where we use this is when an IRQ/notif
- * interrupts a uthread that is in the process of disabling notifs. */
+ * interrupts a uthread that is in the process of disabling notifs.
+ *
+ * If we need to support VM_CTXs here, we'll need to tell the kernel whether or
+ * not we want to enable_notifs (flag to SYS_pop_ctx).  The only use case for
+ * this is when disabling notifs.  Currently, a VM can't do this or do things
+ * like uthread_yield.  It doesn't have access to the vcore's or uthread's TLS
+ * to bootstrap any of that stuff. */
 static inline void pop_user_ctx_raw(struct user_context *ctx, uint32_t vcoreid)
 {
        struct hw_trapframe *tf = &ctx->tf.hw_tf;
 static inline void pop_user_ctx_raw(struct user_context *ctx, uint32_t vcoreid)
 {
        struct hw_trapframe *tf = &ctx->tf.hw_tf;
@@ -355,10 +369,16 @@ static inline void init_user_ctx(struct user_context *ctx, uintptr_t entry_pt,
 
 static inline uintptr_t get_user_ctx_stack(struct user_context *ctx)
 {
 
 static inline uintptr_t get_user_ctx_stack(struct user_context *ctx)
 {
-       if (ctx->type == ROS_HW_CTX)
+       switch (ctx->type) {
+       case ROS_HW_CTX:
                return ctx->tf.hw_tf.tf_rsp;
                return ctx->tf.hw_tf.tf_rsp;
-       else
+       case ROS_SW_CTX:
                return ctx->tf.sw_tf.tf_rsp;
                return ctx->tf.sw_tf.tf_rsp;
+       case ROS_VM_CTX:
+               return ctx->tf.vm_tf.tf_rsp;
+       default:
+               assert(0);
+       }
 }
 
 // this is how we get our thread id on entry.
 }
 
 // this is how we get our thread id on entry.
@@ -370,12 +390,30 @@ static inline uintptr_t get_user_ctx_stack(struct user_context *ctx)
 
 static bool has_refl_fault(struct user_context *ctx)
 {
 
 static bool has_refl_fault(struct user_context *ctx)
 {
-       return ctx->tf.hw_tf.tf_padding3 == ROS_ARCH_REFL_ID;
+       switch (ctx->type) {
+       case ROS_HW_CTX:
+               return ctx->tf.hw_tf.tf_padding3 == ROS_ARCH_REFL_ID;
+       case ROS_SW_CTX:
+               return FALSE;
+       case ROS_VM_CTX:
+               return ctx->tf.vm_tf.tf_flags & VMCTX_FL_HAS_FAULT ? TRUE : FALSE;
+       }
 }
 
 static void clear_refl_fault(struct user_context *ctx)
 {
 }
 
 static void clear_refl_fault(struct user_context *ctx)
 {
-       ctx->tf.hw_tf.tf_padding3 = 0;
+       switch (ctx->type) {
+       case ROS_HW_CTX:
+               ctx->tf.hw_tf.tf_padding3 = 0;
+               break;
+       case ROS_SW_CTX:
+               /* Should never attempt this on an SW ctx */
+               assert(0);
+               break;
+       case ROS_VM_CTX:
+               ctx->tf.vm_tf.tf_flags &= ~VMCTX_FL_HAS_FAULT;
+               break;
+       }
 }
 
 static unsigned int __arch_refl_get_nr(struct user_context *ctx)
 }
 
 static unsigned int __arch_refl_get_nr(struct user_context *ctx)
index 3994d25..bc7be77 100644 (file)
@@ -151,9 +151,12 @@ static void __restore_after_sighandler(struct uthread *uthread)
 {
        uthread->u_ctx = uthread->sigstate.data->u_ctx;
        uthread->flags |= UTHREAD_SAVED;
 {
        uthread->u_ctx = uthread->sigstate.data->u_ctx;
        uthread->flags |= UTHREAD_SAVED;
-       if (uthread->u_ctx.type == ROS_HW_CTX) {
+       switch (uthread->u_ctx.type) {
+       case ROS_HW_CTX:
+       case ROS_VM_CTX:
                uthread->as = uthread->sigstate.data->as;
                uthread->flags |= UTHREAD_FPSAVED;
                uthread->as = uthread->sigstate.data->as;
                uthread->flags |= UTHREAD_FPSAVED;
+               break;
        }
        uthread->sigstate.data = NULL;
 }
        }
        uthread->sigstate.data = NULL;
 }
index 63f7f2d..fbc27b6 100644 (file)
@@ -640,12 +640,17 @@ void run_uthread(struct uthread *uthread)
        assert(!current_uthread);
        assert(uthread->state == UT_NOT_RUNNING);
        assert(uthread->flags & UTHREAD_SAVED);
        assert(!current_uthread);
        assert(uthread->state == UT_NOT_RUNNING);
        assert(uthread->flags & UTHREAD_SAVED);
-       /* For HW CTX, FPSAVED must match UTH SAVE (and both be on here).  For SW,
-        * FP should never be saved. */
-       if (uthread->u_ctx.type == ROS_HW_CTX)
+       /* For HW/VM CTX, FPSAVED must match UTH SAVE (and both be on here).  For
+        * SW, FP should never be saved. */
+       switch (uthread->u_ctx.type) {
+       case ROS_HW_CTX:
+       case ROS_VM_CTX:
                assert(uthread->flags & UTHREAD_FPSAVED);
                assert(uthread->flags & UTHREAD_FPSAVED);
-       else
+               break;
+       case ROS_SW_CTX:
                assert(!(uthread->flags & UTHREAD_FPSAVED));
                assert(!(uthread->flags & UTHREAD_FPSAVED));
+               break;
+       }
        if (has_refl_fault(&uthread->u_ctx)) {
                clear_refl_fault(&uthread->u_ctx);
                handle_refl_fault(uthread, &uthread->u_ctx);
        if (has_refl_fault(&uthread->u_ctx)) {
                clear_refl_fault(&uthread->u_ctx);
                handle_refl_fault(uthread, &uthread->u_ctx);
@@ -712,9 +717,12 @@ static void copyout_uthread(struct preempt_data *vcpd, struct uthread *uthread,
 {
        assert(uthread);
        if (uthread->flags & UTHREAD_SAVED) {
 {
        assert(uthread);
        if (uthread->flags & UTHREAD_SAVED) {
-               /* I don't know of scenarios where HW ctxs FP state differs from GP */
-               if (uthread->u_ctx.type == ROS_HW_CTX)
+               /* I don't know of scenarios where HW/VM ctxs FP state differs from GP*/
+               switch (uthread->u_ctx.type) {
+               case ROS_HW_CTX:
+               case ROS_VM_CTX:
                        assert(uthread->flags & UTHREAD_FPSAVED);
                        assert(uthread->flags & UTHREAD_FPSAVED);
+               }
                assert(vcore_local);
                return;
        }
                assert(vcore_local);
                return;
        }
index b3c6182..05dec14 100644 (file)
@@ -63,12 +63,53 @@ void print_sw_tf(struct sw_trapframe *sw_tf)
        printf(" fpucw 0x%04x\n",             sw_tf->tf_fpucw);
 }
 
        printf(" fpucw 0x%04x\n",             sw_tf->tf_fpucw);
 }
 
+void print_vm_tf(struct vm_trapframe *vm_tf)
+{
+       printf("[user] VM Trapframe 0x%016x\n", vm_tf);
+       printf("  rax  0x%016lx\n",           vm_tf->tf_rax);
+       printf("  rbx  0x%016lx\n",           vm_tf->tf_rbx);
+       printf("  rcx  0x%016lx\n",           vm_tf->tf_rcx);
+       printf("  rdx  0x%016lx\n",           vm_tf->tf_rdx);
+       printf("  rbp  0x%016lx\n",           vm_tf->tf_rbp);
+       printf("  rsi  0x%016lx\n",           vm_tf->tf_rsi);
+       printf("  rdi  0x%016lx\n",           vm_tf->tf_rdi);
+       printf("  r8   0x%016lx\n",           vm_tf->tf_r8);
+       printf("  r9   0x%016lx\n",           vm_tf->tf_r9);
+       printf("  r10  0x%016lx\n",           vm_tf->tf_r10);
+       printf("  r11  0x%016lx\n",           vm_tf->tf_r11);
+       printf("  r12  0x%016lx\n",           vm_tf->tf_r12);
+       printf("  r13  0x%016lx\n",           vm_tf->tf_r13);
+       printf("  r14  0x%016lx\n",           vm_tf->tf_r14);
+       printf("  r15  0x%016lx\n",           vm_tf->tf_r15);
+       printf("  rip  0x%016lx\n",           vm_tf->tf_rip);
+       printf("  rflg 0x%016lx\n",           vm_tf->tf_rflags);
+       printf("  rsp  0x%016lx\n",           vm_tf->tf_rsp);
+       printf("  cr2  0x%016lx\n",           vm_tf->tf_cr2);
+       printf("  cr3  0x%016lx\n",           vm_tf->tf_cr3);
+       printf("Gpcore 0x%08x\n",             vm_tf->tf_guest_pcoreid);
+       printf("Flags  0x%08x\n",             vm_tf->tf_flags);
+       printf("Inject 0x%08x\n",             vm_tf->tf_trap_inject);
+       printf("ExitRs 0x%08x\n",             vm_tf->tf_exit_reason);
+       printf("ExitQl 0x%08x\n",             vm_tf->tf_exit_qual);
+       printf("Intr1  0x%016lx\n",           vm_tf->tf_intrinfo1);
+       printf("Intr2  0x%016lx\n",           vm_tf->tf_intrinfo2);
+       printf("GVA    0x%016lx\n",           vm_tf->tf_guest_va);
+       printf("GPA    0x%016lx\n",           vm_tf->tf_guest_pa);
+}
+
 void print_user_context(struct user_context *ctx)
 {
 void print_user_context(struct user_context *ctx)
 {
-       if (ctx->type == ROS_HW_CTX)
+       switch (ctx->type) {
+       case ROS_HW_CTX:
                print_hw_tf(&ctx->tf.hw_tf);
                print_hw_tf(&ctx->tf.hw_tf);
-       else if (ctx->type == ROS_SW_CTX)
+               break;
+       case ROS_SW_CTX:
                print_sw_tf(&ctx->tf.sw_tf);
                print_sw_tf(&ctx->tf.sw_tf);
-       else
+               break;
+       case ROS_VM_CTX:
+               print_vm_tf(&ctx->tf.vm_tf);
+               break;
+       default:
                printf("Unknown context type %d\n", ctx->type);
                printf("Unknown context type %d\n", ctx->type);
+       }
 }
 }