vm exit handler for xsetbv
authorMichael Taufen <mtaufen@gmail.com>
Mon, 22 Feb 2016 22:47:54 +0000 (14:47 -0800)
committerBarret Rhoden <brho@cs.berkeley.edu>
Fri, 26 Feb 2016 16:28:20 +0000 (11:28 -0500)
Signed-off-by: Michael Taufen <mtaufen@gmail.com>
Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/arch/x86/trap.c

index 3bd995a..7bde8b0 100644 (file)
@@ -777,6 +777,37 @@ bool handle_vmexit_extirq(struct vm_trapframe *tf)
        return TRUE;
 }
 
+static bool handle_vmexit_xsetbv(struct vm_trapframe *tf)
+{
+       // The VM's requested-feature bitmap is represented by edx:eax
+       uint64_t vm_rfbm = (tf->tf_rdx << 32) | tf->tf_rax;
+
+       // If the VM tries to set xcr0 to a superset
+       // of Akaros's default value, kill the VM.
+
+       // Bit in vm_rfbm and x86_default_xcr0:        Ok. Requested and allowed.
+       // Bit in vm_rfbm but not x86_default_xcr0:    Bad! Requested, not allowed.
+       // Bit not in vm_rfbm but in x86_default_xcr0: Ok. Not requested.
+
+       // vm_rfbm & (~x86_default_xcr0) is nonzero if any bits
+       // are set in vm_rfbm but not x86_default_xcr0
+
+       if (vm_rfbm & (~x86_default_xcr0))
+               return FALSE;
+
+
+       // If attempting to use vm_rfbm for xsetbv
+       // causes a fault, we reflect to the VMM.
+       if (safe_lxcr0(vm_rfbm))
+               return FALSE;
+
+
+       // If no fault, advance the instruction pointer
+       // and return TRUE to make the VM resume.
+       tf->tf_rip += 3; // XSETBV is a 3-byte instruction
+       return TRUE;
+}
+
 static void vmexit_dispatch(struct vm_trapframe *tf)
 {
        bool handled = FALSE;
@@ -814,6 +845,9 @@ static void vmexit_dispatch(struct vm_trapframe *tf)
        case EXIT_REASON_EXTERNAL_INTERRUPT:
                handled = handle_vmexit_extirq(tf);
                break;
+       case EXIT_REASON_XSETBV:
+               handled = handle_vmexit_xsetbv(tf);
+               break;
        default:
                printd("Unhandled vmexit: reason 0x%x, exit qualification 0x%x\n",
                       tf->tf_exit_reason, tf->tf_exit_qual);