Begin work on true virtio mmio Kill tests/vmrunkernel.c Our makefiles, plus emacs...
[akaros.git] / kern / arch / x86 / vmm / intel / vmx.c
index ae634bd..e4198fc 100644 (file)
@@ -1284,178 +1284,6 @@ msrio(struct vmx_vcpu *vcpu, uint32_t opcode, uint32_t qual) {
        return SHUTDOWN_UNHANDLED_EXIT_REASON;
 }
 
-/* crude PCI bus. Just enough to get virtio working. I would rather not add to this. */
-struct pciconfig {
-       uint32_t registers[256];
-};
-
-/* just index by devfn, i.e. 8 bits */
-struct pciconfig pcibus[] = {
-       /* linux requires that devfn 0 be a bridge. 
-        * 00:00.0 Host bridge: Intel Corporation 440BX/ZX/DX - 82443BX/ZX/DX Host bridge (rev 01)
-        */
-       {
-               {0x71908086, 0x02000006, 0x06000001},
-       },
-};
-/* cf8 is a single-threaded resource. */
-static uint32_t cf8;
-static uint32_t allones = (uint32_t)-1;
-
-/* Return a pointer to the 32-bit "register" in the "pcibus" give an address. Use cf8.
- * only for readonly access.
- * this will fail if we ever want to do writes, but we don't.
- */
-void regp(uint32_t **reg)
-{
-       *reg = &allones;
-       int devfn = (cf8>>8) & 0xff;
-       //printk("devfn %d\n", devfn);
-       if (devfn < ARRAY_SIZE(pcibus))
-               *reg = &pcibus[devfn].registers[(cf8>>2)&0x3f];
-       //printk("-->regp *reg 0x%lx\n", **reg);
-}
-
-static uint32_t configaddr(uint32_t val)
-{
-       printk("%s 0x%lx\n", __func__, val);
-       cf8 = val;
-       return 0;
-}
-
-static uint32_t configread32(uint32_t edx, uint64_t *reg)
-{
-       uint32_t *r = &cf8;
-       regp(&r);
-       *reg = set_low32(*reg, *r);
-       printk("%s: 0x%lx 0x%lx, 0x%lx 0x%lx\n", __func__, cf8, edx, r, *reg);
-       return 0;
-}
-
-static uint32_t configread16(uint32_t edx, uint64_t *reg)
-{
-       uint64_t val;
-       int which = ((edx&2)>>1) * 16;
-       configread32(edx, &val);
-       val >>= which;
-       *reg = set_low16(*reg, val);
-       printk("%s: 0x%lx, 0x%lx 0x%lx\n", __func__, edx, val, *reg);
-       return 0;
-}
-
-static uint32_t configread8(uint32_t edx, uint64_t *reg)
-{
-       uint64_t val;
-       int which = (edx&3) * 8;
-       configread32(edx, &val);
-       val >>= which;
-       *reg = set_low16(*reg, val);
-       printk("%s: 0x%lx, 0x%lx 0x%lx\n", __func__, edx, val, *reg);
-       return 0;
-}
-
-static int configwrite32(uint32_t addr, uint32_t val)
-{
-       uint32_t *r = &cf8;
-       regp(&r);
-       *r = val;
-       printk("%s 0x%lx 0x%lx\n", __func__, addr, val);
-       return 0;
-}
-
-static int configwrite16(uint32_t addr, uint16_t val)
-{
-       printk("%s 0x%lx 0x%lx\n", __func__, addr, val);
-       return 0;
-}
-
-static int configwrite8(uint32_t addr, uint8_t val)
-{
-       printk("%s 0x%lx 0x%lx\n", __func__, addr, val);
-       return 0;
-}
-
-/* this is very minimal. It needs to move to vmm/io.c but we don't
- * know if this minimal approach will even be workable. It only (for
- * now) handles pci config space. We'd like to hope that's all we will
- * need.
- * It would have been nice had intel encoded the IO exit info as nicely as they
- * encoded, some of the other exits.
- */
-static int io(struct vmx_vcpu *vcpu, int *advance)
-{
-
-       /* Get a pointer to the memory at %rip. This is quite messy and part of the
-        * reason we don't want to do this at all. It sucks. Would have been nice
-        * had linux had an option to ONLY do mmio config space access, but no such
-        * luck.
-        */
-       uint8_t *ip8 = NULL;
-       uint16_t *ip16;
-       uintptr_t ip;
-       uint32_t edx;
-       /* for now, we're going to be a bit crude. In kernel, p is about v, so we just blow away
-        * the upper 34 bits and take the rest as our address
-        */
-       ip = vcpu->regs.tf_rip & 0x3fffffff;
-       edx = vcpu->regs.tf_rdx;
-       ip8 = (void *)ip;
-       ip16 = (void *)ip;
-       //printk("io: ip16 %p\n", *ip16, edx);
-
-       if (*ip8 == 0xef) {
-               *advance = 1;
-               /* out at %edx */
-               if (edx == 0xcf8) {
-                       //printk("Set cf8 ");
-                       return configaddr(vcpu->regs.tf_rax);
-               }
-               if (edx == 0xcfc) {
-                       //printk("Set cfc ");
-                       return configwrite32(edx, vcpu->regs.tf_rax);
-               }
-               printk("unhandled IO address dx @%p is 0x%x\n", ip8, edx);
-               return SHUTDOWN_UNHANDLED_EXIT_REASON;
-       }
-       // out %al, %dx
-       if (*ip8 == 0xee) {
-               *advance = 1;
-               /* out al %edx */
-               if (edx == 0xcfb) { // special!
-                       printk("Just ignore the damned cfb write\n");
-                       return 0;
-               }
-               if ((edx&~3) == 0xcfc) {
-                       //printk("ignoring write to cfc ");
-                       return 0;
-               }
-               printk("unhandled IO address dx @%p is 0x%x\n", ip8, edx);
-               return SHUTDOWN_UNHANDLED_EXIT_REASON;
-       }
-       if (*ip8 == 0xec) {
-               *advance = 1;
-               //printk("configread8 ");
-               return configread8(edx, &vcpu->regs.tf_rax);
-       }
-       if (*ip8 == 0xed) {
-               *advance = 1;
-               if (edx == 0xcf8) {
-                       //printk("read cf8 0x%lx\n", vcpu->regs.tf_rax);
-                       vcpu->regs.tf_rax = cf8;
-                       return 0;
-               }
-               //printk("configread32 ");
-               return configread32(edx, &vcpu->regs.tf_rax);
-       }
-       if (*ip16 == 0xed66) {
-               *advance = 2;
-               //printk("configread16 ");
-               return configread16(edx, &vcpu->regs.tf_rax);
-       }
-       printk("unknown IO %p %x %x\n", ip8, *ip8, *ip16);
-       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,
@@ -1743,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;
@@ -1752,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;
@@ -1761,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) {
@@ -1828,13 +1662,16 @@ int vmx_launch(struct vmctl *v) {
                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\n");
+               printk("REG_RIP %p\n", v->regs.tf_rip);
                vmcs_writel(GUEST_RIP, v->regs.tf_rip);
                break;
        case RESUME:
@@ -1843,6 +1680,7 @@ int vmx_launch(struct vmctl *v) {
        default: 
                error(EINVAL, "Bad command in vmx_launch");
        }
+       vcpu->shutdown = 0;
        vmx_put_cpu(vcpu);
        vcpu->ret_code = -1;
 
@@ -1887,10 +1725,10 @@ int vmx_launch(struct vmctl *v) {
                        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");
@@ -1908,13 +1746,12 @@ int vmx_launch(struct vmctl *v) {
                                msrio(vcpu, ret, vmcs_read32(EXIT_QUALIFICATION));
                        advance = 2;
                } else if (ret == EXIT_REASON_IO_INSTRUCTION) {
-                       /* we never wanted to do this. But virtio
-                        * requires pci config space emulation. */
-                       vcpu->shutdown = io(vcpu, &advance);
+                       /* 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;
                }
 
@@ -1931,9 +1768,11 @@ int vmx_launch(struct vmctl *v) {
                }
        }
 
-       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.