Begin work on true virtio mmio Kill tests/vmrunkernel.c Our makefiles, plus emacs...
[akaros.git] / kern / arch / x86 / vmm / intel / vmx.c
index d2baf07..e4198fc 100644 (file)
@@ -93,8 +93,8 @@
  * We divide this into two things: vmm_proc_init and vm_run.
  * Currently, on Intel, vmm_proc_init does nothing.
  *
- * vm_run is really complicated. It is called with a coreid, rip, rsp,
- * cr3, and flags.  On intel, it calls vmx_launch. vmx_launch is set
+ * vm_run is really complicated. It is called with a coreid, and
+ * vmctl struct. On intel, it calls vmx_launch. vmx_launch is set
  * up for a few test cases. If rip is 1, it sets the guest rip to
  * a function which will deref 0 and should exit with failure 2. If rip is 0,
  * it calls an infinite loop in the guest.
@@ -1143,7 +1143,20 @@ struct emmsr emmsrs[] = {
        {MSR_RAPL_POWER_UNIT, "MSR_RAPL_POWER_UNIT", emsr_readzero},
 };
 
-#define set_low32(hi,lo) (((hi) & 0xffffffff00000000ULL ) | (lo))
+static uint64_t set_low32(uint64_t hi, uint32_t lo)
+{
+       return (hi & 0xffffffff00000000ULL) | lo;
+}
+
+static uint64_t set_low16(uint64_t hi, uint16_t lo)
+{
+       return (hi & 0xffffffffffff0000ULL) | lo;
+}
+
+static uint64_t set_low8(uint64_t hi, uint8_t lo)
+{
+       return (hi & 0xffffffffffffff00ULL) | lo;
+}
 
 /* this may be the only register that needs special handling.
  * If there others then we might want to extend teh emmsr struct.
@@ -1259,7 +1272,7 @@ int emsr_fakewrite(struct vmx_vcpu *vcpu, struct emmsr *msr,
        return 0;
 }
 
-int
+static int
 msrio(struct vmx_vcpu *vcpu, uint32_t opcode, uint32_t qual) {
        int i;
        for (i = 0; i < ARRAY_SIZE(emmsrs); i++) {
@@ -1270,6 +1283,7 @@ msrio(struct vmx_vcpu *vcpu, uint32_t opcode, uint32_t qual) {
        printk("msrio for 0x%lx failed\n", vcpu->regs.tf_rcx);
        return SHUTDOWN_UNHANDLED_EXIT_REASON;
 }
+
 /* Notes on autoloading.  We can't autoload FS_BASE or GS_BASE, according to the
  * manual, but that's because they are automatically saved and restored when all
  * of the other architectural registers are saved and restored, such as cs, ds,
@@ -1557,7 +1571,7 @@ static void vmx_step_instruction(void) {
                    vmcs_read32(VM_EXIT_INSTRUCTION_LEN));
 }
 
-static int vmx_handle_ept_violation(struct vmx_vcpu *vcpu) {
+static int vmx_handle_ept_violation(struct vmx_vcpu *vcpu, struct vmctl *v) {
        unsigned long gva, gpa;
        int exit_qual, ret = -1;
        page_t *page;
@@ -1566,7 +1580,9 @@ static int vmx_handle_ept_violation(struct vmx_vcpu *vcpu) {
        exit_qual = vmcs_read32(EXIT_QUALIFICATION);
        gva = vmcs_readl(GUEST_LINEAR_ADDRESS);
        gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS);
-
+       v->gpa = gpa;
+       v->gva = gva;
+       v->exit_qual = exit_qual;
        vmx_put_cpu(vcpu);
 
        int prot = 0;
@@ -1575,13 +1591,17 @@ static int vmx_handle_ept_violation(struct vmx_vcpu *vcpu) {
        prot |= exit_qual & VMX_EPT_FAULT_INS ? PROT_EXEC : 0;
        ret = handle_page_fault(current, gpa, prot);
 
-       if (ret) {
+       // Some of these get fixed in the vmm; be less chatty now.
+       if (0 && ret) {
                printk("EPT page fault failure %d, GPA: %p, GVA: %p\n", ret, gpa,
                       gva);
                vmx_dump_cpu(vcpu);
        }
 
-       return ret;
+       /* we let the vmm handle the failure cases. So return
+        * the VMX exit violation, not what handle_page_fault returned.
+        */
+       return EXIT_REASON_EPT_VIOLATION;
 }
 
 static void vmx_handle_cpuid(struct vmx_vcpu *vcpu) {
@@ -1617,7 +1637,7 @@ static int vmx_handle_nmi_exception(struct vmx_vcpu *vcpu) {
  * vmx_launch - the main loop for a VMX Dune process
  * @conf: the launch configuration
  */
-int vmx_launch(uint64_t rip, uint64_t rsp, uint64_t cr3) {
+int vmx_launch(struct vmctl *v) {
        int ret;
        struct vmx_vcpu *vcpu;
        int errors = 0;
@@ -1636,14 +1656,32 @@ int vmx_launch(uint64_t rip, uint64_t rsp, uint64_t cr3) {
         * core is the KERN_GS_BASE). */
        rdmsrl(MSR_KERNEL_GS_BASE, vcpu->msr_autoload.host[0].value);
        /* if cr3 is set, means 'set everything', else means 'start where you left off' */
-       if (cr3) {
-               vmx_get_cpu(vcpu);
-               vmcs_writel(GUEST_RIP, rip);
-               vmcs_writel(GUEST_RSP, rsp);
-               vmcs_writel(GUEST_CR3, cr3);
-               vmx_put_cpu(vcpu);
+       vmx_get_cpu(vcpu);
+       switch(v->command) {
+       case REG_ALL:
+               printk("REG_ALL\n");
+               // fallthrough
+               vcpu->regs = v->regs;
+               vmcs_writel(GUEST_RSP, v->regs.tf_rsp);
+               vmcs_writel(GUEST_RIP, v->regs.tf_rip);
+               break;
+       case REG_RSP_RIP_CR3:
+               printk("REG_RSP_RIP_CR3\n");
+               vmcs_writel(GUEST_RSP, v->regs.tf_rsp);
+               vmcs_writel(GUEST_CR3, v->cr3);
+               // fallthrough
+       case REG_RIP:
+               printk("REG_RIP %p\n", v->regs.tf_rip);
+               vmcs_writel(GUEST_RIP, v->regs.tf_rip);
+               break;
+       case RESUME:
+               printk("RESUME\n");
+               break;
+       default: 
+               error(EINVAL, "Bad command in vmx_launch");
        }
-
+       vcpu->shutdown = 0;
+       vmx_put_cpu(vcpu);
        vcpu->ret_code = -1;
 
        while (1) {
@@ -1687,10 +1725,10 @@ int vmx_launch(uint64_t rip, uint64_t rsp, uint64_t cr3) {
                        vmcs_writel(GUEST_RIP, vcpu->regs.tf_rip + 2);
                        vmx_put_cpu(vcpu);
                } else if (ret == EXIT_REASON_EPT_VIOLATION) {
-                       if (vmx_handle_ept_violation(vcpu))
+                       if (vmx_handle_ept_violation(vcpu, v))
                                vcpu->shutdown = SHUTDOWN_EPT_VIOLATION;
                } else if (ret == EXIT_REASON_EXCEPTION_NMI) {
-                       if (vmx_handle_nmi_exception(vcpu))
+                       if (vmx_handle_nmi_exception(vcpu)) 
                                vcpu->shutdown = SHUTDOWN_NMI_EXCEPTION;
                } else if (ret == EXIT_REASON_EXTERNAL_INTERRUPT) {
                        printd("External interrupt\n");
@@ -1707,10 +1745,13 @@ int vmx_launch(uint64_t rip, uint64_t rsp, uint64_t cr3) {
                        vcpu->shutdown =
                                msrio(vcpu, ret, vmcs_read32(EXIT_QUALIFICATION));
                        advance = 2;
+               } else if (ret == EXIT_REASON_IO_INSTRUCTION) {
+                       /* the VMM does this now. */
+                       vcpu->shutdown = ret; 
                } else {
                        printk("unhandled exit: reason 0x%x, exit qualification 0x%x\n",
                               ret, vmcs_read32(EXIT_QUALIFICATION));
-                       vmx_dump_cpu(vcpu);
+                       //vmx_dump_cpu(vcpu);
                        vcpu->shutdown = SHUTDOWN_UNHANDLED_EXIT_REASON;
                }
 
@@ -1727,8 +1768,11 @@ int vmx_launch(uint64_t rip, uint64_t rsp, uint64_t cr3) {
                }
        }
 
-       printd("RETURN. ip %016lx sp %016lx\n",
-              vcpu->regs.tf_rip, vcpu->regs.tf_rsp);
+       printk("RETURN. ip %016lx sp %016lx, shutdown 0x%lx ret 0x%lx\n",
+              vcpu->regs.tf_rip, vcpu->regs.tf_rsp, vcpu->shutdown, vcpu->shutdown);
+       v->regs = vcpu->regs;
+       v->shutdown = vcpu->shutdown;
+       v->ret_code = ret;
 //  hexdump((void *)vcpu->regs.tf_rsp, 128 * 8);
        /*
         * Return both the reason for the shutdown and a status value.