VMMCP: misc stuff
authorRonald G. Minnich <rminnich@gmail.com>
Tue, 22 Sep 2015 22:20:20 +0000 (15:20 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 2 Nov 2015 23:53:50 +0000 (18:53 -0500)
i.e., use a reserved interrupt vector for virtio_mmio

virtio_mmio, it turns out, doesn't really work on x86. I will refrain
from further comment. Grrrrrrr...

So for now the guest linux will set a trap gate for 17, and we'll be smart and use it.

Awful.

Signed-off-by: Ronald G. Minnich <rminnich@gmail.com>
Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/arch/x86/vmm/intel/vmx.c
tests/vmm/vmrunkernel.c
user/vmm/include/virtio_mmio.h
user/vmm/virtio-mmio.c
user/vmm/virtio_ring.c

index fd7f753..41d3ea6 100644 (file)
@@ -1687,6 +1687,7 @@ int vmx_launch(struct vmctl *v) {
        struct vmx_vcpu *vcpu;
        int errors = 0;
        int advance;
+       int interrupting = 0;
 
        /* TODO: dirty hack til we have VMM contexts */
        vcpu = current->vmm.guest_pcores[0];
@@ -1721,16 +1722,16 @@ int vmx_launch(struct vmctl *v) {
        case RESUME:
                /* If v->interrupt is non-zero, set it in the vmcs and
                 * zero it in the vmctl. Else set RIP.
+                * We used to check IF and such here but we'll let the VMM do it. If the VMM screws up
+                * we can always fix it. Note to people who know about security: could this be an issue?
+                * I don't see how: it will mainly just break your guest vm AFAICT.
                 */
                if (v->interrupt) {
-                       if ((v->regs.tf_rflags & 0x200) && (v->intrinfo1 == 0)) {
-                               printk("Set VM_ENTRY_INFTR_INFO_FIELD to 0x%x\n", v->interrupt);
-                               vmcs_writel(VM_ENTRY_INTR_INFO_FIELD, v->interrupt);
-                               v->interrupt = 0;
-                       } else {
-                               printk("Can't set interrupt yet\n");
-                       }
+                       printk("Set VM_ENTRY_INFTR_INFO_FIELD to 0x%x\n", v->interrupt);
+                       vmcs_writel(VM_ENTRY_INTR_INFO_FIELD, v->interrupt);
                        //vmx_set_rvi(v->interrupt);
+                       v->interrupt = 0;
+                       interrupting = 1;
                }
                printd("RESUME\n");
                break;
@@ -1739,6 +1740,10 @@ int vmx_launch(struct vmctl *v) {
        }
        vcpu->shutdown = 0;
        vmx_put_cpu(vcpu);
+       if (interrupting) {
+               printk("BEFORE INTERRUPT: ");
+               vmx_dump_cpu(vcpu);
+       }
        vcpu->ret_code = -1;
 
        while (1) {
@@ -1753,7 +1758,13 @@ int vmx_launch(struct vmctl *v) {
                ret = vmx_run_vcpu(vcpu);
                //dumpmsrs();
                enable_irq();
+               v->intrinfo1 = vmcs_readl(GUEST_INTERRUPTIBILITY_INFO);
+               v->intrinfo2 = vmcs_readl(VM_ENTRY_INTR_INFO_FIELD);
                vmx_put_cpu(vcpu);
+               if (interrupting) {
+                       printk("POST INTERRUPT: ");
+                       vmx_dump_cpu(vcpu);
+               }
 
                if (ret == EXIT_REASON_VMCALL) {
                        if (current->vmm.flags & VMM_VMCALL_PRINTF) {
@@ -1790,15 +1801,9 @@ int vmx_launch(struct vmctl *v) {
                } else if (ret == EXIT_REASON_EXTERNAL_INTERRUPT) {
                        printk("External interrupt\n");
                        //vmx_dump_cpu(vcpu);
-                       vmx_get_cpu(vcpu);
-                       v->intrinfo1 = vmcs_readl(GUEST_INTERRUPTIBILITY_INFO);
-                       v->intrinfo2 = vmcs_readl(VM_ENTRY_INTR_INFO_FIELD);
-                       //vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, 0);
-                       //vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0);
                        printk("GUEST_INTERRUPTIBILITY_INFO: 0x%08x,",  v->intrinfo1);
                        printk("VM_ENTRY_INTR_INFO_FIELD 0x%08x,", v->intrinfo2);
-                       printk("rflags 0x%x\n", vmcs_readl(GUEST_RFLAGS));
-                       vmx_put_cpu(vcpu);
+                       printk("rflags 0x%x\n", vcpu->regs.tf_rflags);
                        vcpu->shutdown = SHUTDOWN_UNHANDLED_EXIT_REASON;
                } else if (ret == EXIT_REASON_MSR_READ) {
                        printd("msr read\n");
@@ -1824,6 +1829,7 @@ int vmx_launch(struct vmctl *v) {
                        vcpu->shutdown = SHUTDOWN_UNHANDLED_EXIT_REASON;
                }
 
+               interrupting = 0;
                /* TODO: we can't just return and relaunch the VMCS, in case we blocked.
                 * similar to how proc_restartcore/smp_idle only restart the pcpui
                 * cur_ctx, we need to do the same, via the VMCS resume business. */
index 03597da..9bea60e 100644 (file)
@@ -117,6 +117,9 @@ struct acpi_madt_interrupt_override isor[] = {
         .bus = 0, .source_irq = 14, .global_irq = 14, .inti_flags = 0},
        {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
         .bus = 0, .source_irq = 15, .global_irq = 15, .inti_flags = 0},
+       // VMMCP routes irq 32 to gsi 17
+       {.header = {.type = ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, .length = sizeof(struct acpi_madt_interrupt_override)},
+        .bus = 0, .source_irq = 32, .global_irq = 17, .inti_flags = 5},
 };
 
 
@@ -127,7 +130,7 @@ unsigned long long stack[1024];
 volatile int shared = 0;
 volatile int quit = 0;
 int mcp = 1;
-int virtioirq = 0x18;
+int virtioirq = 17;
 
 /* total hack. If the vm runs away we want to get control again. */
 unsigned int maxresume = (unsigned int) -1;
@@ -201,7 +204,7 @@ void *consout(void *arg)
 }
 
 // FIXME. 
-int consdata = 0;
+volatile int consdata = 0;
 
 void *consin(void *arg)
 {
@@ -264,7 +267,7 @@ dev: VIRTIO_ID_CONSOLE,
 device_features: 0, /* Can't do it: linux console device does not support it. VIRTIO_F_VERSION_1*/
 numvqs: 2,
 vqs: {
-               {name: "consin", maxqnum: 64, f: &consin, arg: (void *)0},
+               {name: "consin", maxqnum: 64, f: consin, arg: (void *)0},
                {name: "consout", maxqnum: 64, f: consout, arg: (void *)0},
        }
 };
@@ -631,8 +634,8 @@ fprintf(stderr, "%p %p %p %p\n", PGSIZE, PGSHIFT, PML1_SHIFT, PML1_PTE_REACH);
                                break;
                        case EXIT_REASON_INTERRUPT_WINDOW:
                                if (consdata) {
-                                       debug = 1;
                                        if (debug) fprintf(stderr, "inject an interrupt\n");
+                                       virtio_mmio_set_vring_irq();
                                        vmctl.interrupt = 0x80000000 | virtioirq;
                                        vmctl.command = RESUME;
                                        consdata = 0;
@@ -649,8 +652,19 @@ fprintf(stderr, "%p %p %p %p\n", PGSIZE, PGSHIFT, PML1_SHIFT, PML1_PTE_REACH);
                                break;
                        case EXIT_REASON_HLT:
                                fflush(stdout);
-                               fprintf(stderr, "\n================== Guest halted. RIP. =======================\n");
-                               quit = 1;
+                               if (debug)fprintf(stderr, "\n================== Guest halted. =======================\n");
+                               if (debug)fprintf(stderr, "Wait for cons data\n");
+                               while (!consdata)
+                                       ;
+                               //debug = 1;
+                               if (debug)fprintf(stderr, "Resume with consdata ...\n");
+                               vmctl.regs.tf_rip += 1;
+                               ret = write(fd, &vmctl, sizeof(vmctl));
+                               if (ret != sizeof(vmctl)) {
+                                       perror(cmd);
+                               }
+                               //fprintf(stderr, "RIP %p, shutdown 0x%x\n", vmctl.regs.tf_rip, vmctl.shutdown);
+                               //showstatus(stderr, &vmctl);
                                break;
                        default:
                                fprintf(stderr, "Don't know how to handle exit %d\n", vmctl.ret_code);
@@ -666,12 +680,15 @@ fprintf(stderr, "%p %p %p %p\n", PGSIZE, PGSHIFT, PML1_SHIFT, PML1_PTE_REACH);
                if (consdata) {
                        if (debug) fprintf(stderr, "inject an interrupt\n");
                        fprintf(stderr, "XINT 0x%x 0x%x\n", vmctl.intrinfo1, vmctl.intrinfo2);
-                       if ((vmctl.intrinfo1 == 0) && (vmctl.regs.tf_rflags & 0x200))
+                       if ((vmctl.intrinfo1 == 0) && (vmctl.regs.tf_rflags & 0x200)) {
                                vmctl.interrupt = 0x80000000 | virtioirq;
-                       else 
+                               virtio_mmio_set_vring_irq();
+                               consdata = 0;
+                               //debug = 1;
+                       } else { 
                                fprintf(stderr, "Can't inject interrupt: IF is clear\n");
+                       }
                        vmctl.command = RESUME;
-                       consdata = 0;
                }
                if (debug) fprintf(stderr, "NOW DO A RESUME\n");
                ret = write(fd, &vmctl, sizeof(vmctl));
index 4c28a40..2ad6d39 100644 (file)
@@ -181,5 +181,6 @@ struct virtio_threadarg {
 void dumpvirtio_mmio(FILE *f, uint64_t gpa);
 void register_virtio_mmio(struct vqdev *v, uint64_t virtio_base);
 int virtio_mmio(struct vmctl *v, uint64_t gpa, int destreg, uint64_t *regp, int store);
+void virtio_mmio_set_vring_irq(void);
 
 #endif
index d33d9b6..96abfe4 100644 (file)
@@ -57,6 +57,7 @@ typedef struct {
        int state; // not used yet. */
        uint64_t bar;
        uint32_t status;
+       uint32_t isr;
        int qsel; // queue we are on.
        int pagesize;
        int page_shift;
@@ -181,7 +182,9 @@ static uint32_t virtio_mmio_read(uint64_t gpa)
     case VIRTIO_MMIO_QUEUE_PFN:
            return mmio.vqdev->vqs[mmio.qsel].pfn;
     case VIRTIO_MMIO_INTERRUPT_STATUS:
-           return mmio.vqdev->vqs[mmio.qsel].isr;
+               // pretty sure this is per-mmio, not per-q. 
+               return mmio.isr;
+           //return mmio.vqdev->vqs[mmio.qsel].isr;
     case VIRTIO_MMIO_STATUS:
            return mmio.vqdev->vqs[mmio.qsel].status;
     case VIRTIO_MMIO_DEVICE_FEATURES_SEL:
@@ -314,7 +317,8 @@ static void virtio_mmio_write(uint64_t gpa, uint32_t value)
            }
         break;
     case VIRTIO_MMIO_INTERRUPT_ACK:
-        //vdev->isr &= ~value;
+       mmio.isr &= ~value;
+       // I think we're suppose to do stuff here but the hell with it for now.
         //virtio_update_irq(vdev);
         break;
     case VIRTIO_MMIO_STATUS:
@@ -402,6 +406,11 @@ static void virtio_mmio_write(uint64_t gpa, uint32_t value)
 
 }
 
+void virtio_mmio_set_vring_irq(void)
+{
+       mmio.isr |= VIRTIO_MMIO_INT_VRING;
+}
+
 int virtio_mmio(struct vmctl *v, uint64_t gpa, int destreg, uint64_t *regp, int store)
 {
        if (store) {
index 49bd7a2..762a8e0 100644 (file)
@@ -1110,6 +1110,7 @@ void add_used(struct virtqueue *_vq, unsigned int head, int len)
        /* Make sure buffer is written before we update index. */
        wmb();
        vq->vring.used->idx++;
+       if (vringdebug) fprintf(stderr, "USED IDX is now %d\n", vq->vring.used->idx);
        //vq->pending_used++;
 }