Handle multiple virtio mmio devices.
authorGan Shun <ganshun@gmail.com>
Tue, 17 May 2016 22:58:33 +0000 (15:58 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Fri, 20 May 2016 19:33:10 +0000 (15:33 -0400)
This change removes current assumptions of a single mmio device, and
allows us to handle multiple devices naturally. Removed legacy
virtio_mmio_base and virtio_irq fields.

Issue: 3
Bug: 28824279
Change-Id: I62640634d98290e6328948ec9fe071cf4632fd1b
Signed-off-by: Gan Shun <ganshun@gmail.com>
Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
tests/vmm/vmrunkernel.c
user/vmm/include/vmm/vmm.h
user/vmm/vmexit.c

index 1f8d96c..6a86284 100644 (file)
@@ -381,8 +381,6 @@ int main(int argc, char **argv)
        ((uint32_t *)a_page)[0x30/4] = 0x01060015;
        //((uint32_t *)a_page)[0x30/4] = 0xDEADBEEF;
 
-       vm->virtio_irq = 17; /* TODO: is this an option?  or a #define? */
-
        argc--, argv++;
        // switches ...
        // Sorry, I don't much like the gnu opt parsing code.
@@ -400,10 +398,6 @@ int main(int argc, char **argv)
                        argc--, argv++;
                        maxresume = strtoull(argv[0], 0, 0);
                        break;
-               case 'i':
-                       argc--, argv++;
-                       vm->virtio_irq = strtoull(argv[0], 0, 0);
-                       break;
                case 'c':
                        argc--, argv++;
                        cmdline_extra = argv[0];
@@ -622,11 +616,14 @@ int main(int argc, char **argv)
        fprintf(stderr, "kernbase for pml4 is 0x%llx and entry is %llx\n", kernbase, entry);
        fprintf(stderr, "p512 %p p512[0] is 0x%lx p1 %p p1[0] is 0x%x\n", p512, p512[0], p1, p1[0]);
 
-       vm->virtio_mmio_base = 0x100000000;
-
-       cons_mmio_dev.addr = vm->virtio_mmio_base;
+       /* The MMIO address of the console device is really the address of an
+        * unbacked EPT page: accesses to this page will cause a page fault that
+        * traps to the host, which will examine the fault, see it was for the
+        * known MMIO address, and fulfill the MMIO read or write on the guest's
+        * behalf accordingly. */
+       cons_mmio_dev.addr = 0x100000000;
        cons_mmio_dev.vqdev = &cons_vqdev;
-       vm->cons_mmio_dev = &cons_mmio_dev;
+       vm->virtio_mmio_devices[VIRTIO_MMIO_CONSOLE_DEV] = &cons_mmio_dev;
 
        vmm_run_task(vm, timer_thread, 0);
 
index 5b5e7a1..971f2d0 100644 (file)
@@ -9,6 +9,15 @@
 #include <ros/vmm.h>
 #include <vmm/sched.h>
 
+/* The listing of VIRTIO MMIO devices. We currently only expect to have 2,
+ * console and network. Only the console is implemented right now.*/
+enum {
+       VIRTIO_MMIO_CONSOLE_DEV,
+
+       /* This should always be the last entry. */
+       VIRTIO_MMIO_MAX_NUM_DEV = 2,
+};
+
 /* Structure to encapsulate all of the bookkeeping for a VM. */
 struct virtual_machine {
        struct guest_thread                     **gths;
@@ -18,10 +27,8 @@ struct virtual_machine {
        /* TODO: put these in appropriate structures.  e.g., virtio things in
         * something related to virtio.  low4k in something related to the guest's
         * memory. */
-       uintptr_t                                       virtio_mmio_base;
-       int                                                     virtio_irq;
        uint8_t                                         *low4k;
-       struct virtio_mmio_dev          *cons_mmio_dev;
+       struct virtio_mmio_dev          *virtio_mmio_devices[VIRTIO_MMIO_MAX_NUM_DEV];
 };
 
 char *regname(uint8_t reg);
index 615a86f..f1fb83f 100644 (file)
@@ -24,25 +24,24 @@ static bool handle_ept_fault(struct guest_thread *gth)
 
        if (decode(gth, &gpa, &regx, &regp, &store, &size, &advance))
                return FALSE;
+       assert(size >= 0);
        /* TODO use helpers for some of these addr checks.  the fee/fec ones might
         * be wrong too. */
-       if (PG_ADDR(gpa) == vm->virtio_mmio_base) {
+       for (int i = 0; i < VIRTIO_MMIO_MAX_NUM_DEV; i++) {
+               if (vm->virtio_mmio_devices[i] == NULL)
+                       continue;
+               if (PG_ADDR(gpa) != vm->virtio_mmio_devices[i]->addr)
+                       continue;
                /* TODO: can the guest cause us to spawn off infinite threads? */
-               if (size < 0) {
-                       // TODO: It would be preferable for the decoder to return an
-                       //       unsigned value, so that we don't have to worry
-                       //       about this. I don't know if it's even possible for
-                       //       the width to be negative;
-                       VIRTIO_DRI_ERRX(vm->cons_mmio_dev->vqdev,
-                           "Driver tried to access the device with a negative access width in the instruction?");
-               }
-               //fprintf(stderr, "RIP is 0x%x\n", vm_tf->tf_rip);
                if (store)
-                       virtio_mmio_wr(vm, vm->cons_mmio_dev, gpa, size, (uint32_t *)regp);
+                       virtio_mmio_wr(vm, vm->virtio_mmio_devices[i], gpa, size,
+                                      (uint32_t *)regp);
                else
-                       *regp = virtio_mmio_rd(vm, vm->cons_mmio_dev, gpa, size);
-
-       } else if (PG_ADDR(gpa) == 0xfec00000) {
+                       *regp = virtio_mmio_rd(vm, vm->virtio_mmio_devices[i], gpa, size);
+               vm_tf->tf_rip += advance;
+               return TRUE;
+       }
+       if (PG_ADDR(gpa) == 0xfec00000) {
                do_ioapic(gth, gpa, regx, regp, store);
        } else if (PG_ADDR(gpa) == 0) {
                memmove(regp, &vm->low4k[gpa], size);
@@ -52,7 +51,7 @@ static bool handle_ept_fault(struct guest_thread *gth)
                                vm_tf->tf_exit_reason);
                fprintf(stderr, "Returning 0xffffffff\n");
                showstatus(stderr, gth);
-               // Just fill the whole register for now.
+               /* Just fill the whole register for now. */
                *regp = (uint64_t) -1;
                return FALSE;
        }