Begin work on true virtio mmio Kill tests/vmrunkernel.c Our makefiles, plus emacs...
authorRonald G. Minnich <rminnich@gmail.com>
Mon, 3 Aug 2015 16:59:24 +0000 (09:59 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 2 Nov 2015 23:24:25 +0000 (18:24 -0500)
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
kern/include/ros/vmm.h
scripts/VMPXE
tests/vmm/vmrunkernel.c
tests/vmrunkernel.c [deleted file]
user/vmm/include/virtio.h
user/vmm/include/virtio_config.h
user/vmm/include/virtio_mmio.h
user/vmm/virtio-mmio.c
user/vmm/virtio_ring.c
user/vmm/vmx.c

index cd46ff7..e4198fc 100644 (file)
@@ -1591,13 +1591,17 @@ static int vmx_handle_ept_violation(struct vmx_vcpu *vcpu, struct vmctl *v) {
        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) {
@@ -1658,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:
@@ -1673,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;
 
@@ -1743,7 +1751,7 @@ int vmx_launch(struct vmctl *v) {
                } 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;
                }
 
@@ -1760,11 +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 = vcpu->ret_code;
+       v->ret_code = ret;
 //  hexdump((void *)vcpu->regs.tf_rsp, 128 * 8);
        /*
         * Return both the reason for the shutdown and a status value.
index 3db8cf3..76b2910 100644 (file)
@@ -28,9 +28,9 @@ struct vmctl {
        uint64_t gva;
        uint64_t gpa;
        uint64_t exit_qual;
-       int shutdown;
-       int ret_code;
-       int core;
+       uint64_t shutdown;
+       uint64_t ret_code;
+       uint64_t core;
        struct hw_trapframe regs;
 };
 
index 4b351b1..4d89c0b 100644 (file)
@@ -1,9 +1,7 @@
 #!/bin/bash
-make tests && make fill-kfs &&make  && sudo cp obj/kern/akaros-kernel /var/lib/tftpboot/akaros && \
-       sudo dhcpd -d eth0 && echo "OK" && exit
-
-
-#      sudo service isc-dhcp-server restart && echo "OK" && exit
+export ARCH=x86
+rm -f obj/tests/vmm/vmrunkernel kern/kfs/bin/vmrunkernel && make tests && make fill-kfs &&make  && sudo cp obj/kern/akaros-kernel /var/lib/tftpboot/akaros && \
+       sudo service isc-dhcp-server restart && echo "OK" && exit
 
 
 echo " IT WENT WRONG"
index 4b27657..243b1b0 100644 (file)
 #include <sys/mman.h>
 #include <vmm/coreboot_tables.h>
 #include <ros/vmm.h>
+#include <parlib/uthread.h>
 #include <vmm/virtio.h>
 #include <vmm/virtio_mmio.h>
 #include <vmm/virtio_ids.h>
+#include <vmm/virtio_config.h>
 
 /* this test will run the "kernel" in the negative address space. We hope. */
 int *mmap_blob;
@@ -33,67 +35,69 @@ uint8_t _kernel[KERNSIZE];
 
 unsigned long long *p512, *p1, *p2m;
 
-pthread_t *my_threads;
 void **my_retvals;
-int nr_threads = 2;
+int nr_threads = 3;
 char *line, *consline, *outline;
 struct scatterlist iov[32];
 unsigned int inlen, outlen, conslen;
+int debug = 1;
 /* unlike Linux, this shared struct is for both host and guest. */
 //     struct virtqueue *constoguest = 
 //             vring_new_virtqueue(0, 512, 8192, 0, inpages, NULL, NULL, "test");
 volatile int gaveit = 0, gotitback = 0;
-struct virtqueue *guesttocons;
 struct scatterlist out[] = { {NULL, sizeof(outline)}, };
 struct scatterlist in[] = { {NULL, sizeof(line)}, };
+uint64_t virtio_mmio_base = 0x100000000;
 
-static inline uint32_t read32(const volatile void *addr)
-{
-       return *(const volatile uint32_t *)addr;
-}
-
-static inline void write32(volatile void *addr, uint32_t value)
+void *consout(void *arg)
 {
-       *(volatile uint32_t *)addr = value;
+       struct virtio_threadarg *a = arg;
+       struct virtqueue *v = a->arg->virtio;
+       fprintf(stderr, "talk thread ..\n");
+       uint16_t head;
+       uint32_t vv;
+       int i;
+       int num;
+       printf("Sleep 15 seconds\n");
+       uthread_sleep(15);
+       printf("----------------------- TT a %p\n", a);
+       printf("talk thread ttargs %x v %x\n", a, v);
+       
+       for(num = 0;;num++) {
+               /* host: use any buffers we should have been sent. */
+               head = wait_for_vq_desc(v, iov, &outlen, &inlen);
+               if (debug)
+                       printf("vq desc head %d, gaveit %d gotitback %d\n", head, gaveit, gotitback);
+               for(i = 0; debug && i < outlen + inlen; i++)
+                       printf("v[%d/%d] v %p len %d\n", i, outlen + inlen, iov[i].v, iov[i].length);
+               /* host: if we got an output buffer, just output it. */
+               for(i = 0; i < outlen; i++) {
+                       num++;
+                       printf("Host:%s:\n", (char *)iov[i].v);
+               }
+               
+               if (debug)
+                       printf("outlen is %d; inlen is %d\n", outlen, inlen);
+               /* host: fill in the writeable buffers. */
+               /* why we're getting these I don't know. */
+               for (i = outlen; i < outlen + inlen; i++) {
+                       if (debug) fprintf(stderr, "send back empty writeable");
+                       iov[i].length = 0;
+               }
+               if (debug) printf("call add_used\n");
+               /* host: now ack that we used them all. */
+               add_used(v, head, outlen+inlen);
+               if (debug) printf("DONE call add_used\n");
+       }
+       fprintf(stderr, "All done\n");
+       return NULL;
 }
 
-void dumpvirtio_mmio(FILE *f, void *v)
+void *consin(void *arg)
 {
-       fprintf(f, "VIRTIO_MMIO_MAGIC_VALUE: 0x%x\n", read32(v+VIRTIO_MMIO_MAGIC_VALUE));
-       fprintf(f, "VIRTIO_MMIO_VERSION: 0x%x\n", read32(v+VIRTIO_MMIO_VERSION));
-       fprintf(f, "VIRTIO_MMIO_DEVICE_ID: 0x%x\n", read32(v+VIRTIO_MMIO_DEVICE_ID));
-       fprintf(f, "VIRTIO_MMIO_VENDOR_ID: 0x%x\n", read32(v+VIRTIO_MMIO_VENDOR_ID));
-       fprintf(f, "VIRTIO_MMIO_DEVICE_FEATURES: 0x%x\n", read32(v+VIRTIO_MMIO_DEVICE_FEATURES));
-       fprintf(f, "VIRTIO_MMIO_DEVICE_FEATURES_SEL: 0x%x\n", read32(v+VIRTIO_MMIO_DEVICE_FEATURES_SEL));
-       fprintf(f, "VIRTIO_MMIO_DRIVER_FEATURES: 0x%x\n", read32(v+VIRTIO_MMIO_DRIVER_FEATURES));
-       fprintf(f, "VIRTIO_MMIO_DRIVER_FEATURES_SEL: 0x%x\n", read32(v+VIRTIO_MMIO_DRIVER_FEATURES_SEL));
-       fprintf(f, "VIRTIO_MMIO_GUEST_PAGE_SIZE: 0x%x\n", read32(v+VIRTIO_MMIO_GUEST_PAGE_SIZE));
-       fprintf(f, "VIRTIO_MMIO_QUEUE_SEL: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_SEL));
-       fprintf(f, "VIRTIO_MMIO_QUEUE_NUM_MAX: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_NUM_MAX));
-       fprintf(f, "VIRTIO_MMIO_QUEUE_NUM: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_NUM));
-       fprintf(f, "VIRTIO_MMIO_QUEUE_ALIGN: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_ALIGN));
-       fprintf(f, "VIRTIO_MMIO_QUEUE_PFN: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_PFN));
-       fprintf(f, "VIRTIO_MMIO_QUEUE_READY: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_READY));
-       fprintf(f, "VIRTIO_MMIO_QUEUE_NOTIFY: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_NOTIFY));
-       fprintf(f, "VIRTIO_MMIO_INTERRUPT_STATUS: 0x%x\n", read32(v+VIRTIO_MMIO_INTERRUPT_STATUS));
-       fprintf(f, "VIRTIO_MMIO_INTERRUPT_ACK: 0x%x\n", read32(v+VIRTIO_MMIO_INTERRUPT_ACK));
-       fprintf(f, "VIRTIO_MMIO_STATUS: 0x%x\n", read32(v+VIRTIO_MMIO_STATUS));
-       fprintf(f, "VIRTIO_MMIO_QUEUE_DESC_LOW: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_DESC_LOW));
-       fprintf(f, "VIRTIO_MMIO_QUEUE_DESC_HIGH: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_DESC_HIGH));
-       fprintf(f, "VIRTIO_MMIO_QUEUE_AVAIL_LOW: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_AVAIL_LOW));
-       fprintf(f, "VIRTIO_MMIO_QUEUE_AVAIL_HIGH: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_AVAIL_HIGH));
-       fprintf(f, "VIRTIO_MMIO_QUEUE_USED_LOW: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_USED_LOW));
-       fprintf(f, "VIRTIO_MMIO_QUEUE_USED_HIGH: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_USED_HIGH));
-       fprintf(f, "VIRTIO_MMIO_CONFIG_GENERATION: 0x%x\n", read32(v+VIRTIO_MMIO_CONFIG_GENERATION));
-}
-int debug = 1;
-
-struct ttargs {
-       void *virtio;
-};
 
-void *talk_thread(void *arg)
-{
+       fprintf(stderr, "consinput; nothing to do\n");
+#if 0
        struct ttargs *a = arg;
        void *v = a->virtio;
        fprintf(stderr, "talk thread ..\n");
@@ -101,7 +105,6 @@ void *talk_thread(void *arg)
        uint32_t vv;
        int i;
        int num;
-       return NULL;
        printf("Sleep 15 seconds\n");
        uthread_sleep(15);
        printf("----------------------- TT a %p\n", a);
@@ -155,12 +158,21 @@ void *talk_thread(void *arg)
                add_used(guesttocons, head, outlen+inlen);
                if (debug) printf("DONE call add_used\n");
        }
+#endif
        fprintf(stderr, "All done\n");
        return NULL;
 }
 
-struct ttargs t;
-       
+static struct vqdev vqdev= {
+name: "console",
+dev: VIRTIO_ID_CONSOLE,
+features: VIRTIO_F_VERSION_1,
+numvqs: 2,
+vqs: {
+               {name: "consin", maxqnum: 2, f: &consin, arg: (void *)0},
+               {name: "consout", maxqnum: 2, f: consout, arg: (void *)0},
+       }
+};
 
 int main(int argc, char **argv)
 {
@@ -250,9 +262,8 @@ int main(int argc, char **argv)
 
        mcp = 1;
        if (mcp) {
-               my_threads = malloc(sizeof(pthread_t) * nr_threads);
                my_retvals = malloc(sizeof(void*) * nr_threads);
-               if (!(my_retvals && my_threads))
+               if (!my_retvals)
                        perror("Init threads/malloc");
 
                pthread_can_vcore_request(FALSE);       /* 2LS won't manage vcores */
@@ -267,8 +278,6 @@ int main(int argc, char **argv)
                }
        }
 
-       //t.virtio = (void *)VIRTIOBASE;
-
        ret = syscall(33, 1);
        if (ret < 0) {
                perror("vm setup");
@@ -306,48 +315,53 @@ int main(int argc, char **argv)
        vmctl.regs.tf_rip = entry;
        vmctl.regs.tf_rsp = (uint64_t) &stack[1024];
        if (mcp) {
-               if (pthread_create(&my_threads[0], NULL, &talk_thread, &t))
-                       perror("pth_create failed");
+               /* set up virtio bits, which depend on threads being enabled. */
+               register_virtio_mmio(&vqdev, virtio_mmio_base);
        }
        printf("threads started\n");
        printf("Writing command :%s:\n", cmd);
-       // sys_getpcoreid
+
        ret = write(fd, &vmctl, sizeof(vmctl));
        if (ret != sizeof(vmctl)) {
                perror(cmd);
        }
-       vmctl.command = RESUME;
        while (1) {
                void showstatus(FILE *f, struct vmctl *v);
                int c;
+               vmctl.command = REG_RIP;
                printf("RESUME?\n");
                c = getchar();
                if (c == 'q')
                        break;
+               printf("RIP %p, shutdown 0x%x\n", vmctl.regs.tf_rip, vmctl.shutdown);
+               //showstatus(stdout, &vmctl);
+               // this will be in a function, someday.
+               // A rough check: is the GPA 
+               if ((vmctl.shutdown == 5/*EXIT_REASON_EPT_VIOLATION*/) && ((vmctl.gpa & ~0xfffULL) == virtiobase)) {
+                       printf("DO SOME VIRTIO\n");
+                       virtio_mmio(&vmctl);
+                       vmctl.shutdown = 0;
+                       vmctl.gpa = 0;
+                       vmctl.command = REG_ALL;
+               }
+               printf("NOW DO A RESUME\n");
                ret = write(fd, &vmctl, sizeof(vmctl));
                if (ret != sizeof(vmctl)) {
                        perror(cmd);
                }
-               printf("RIP %p\n", vmctl.regs.tf_rip);
-               showstatus(stdout, &vmctl);
-               // this will be in a function, someday.
-               // A rough check: is the GPA 
-               if (vmctl.gpa == virtiobase) {
-                       int virtio(struct vmctl *v, uint64_t);
-                       if (virtio(&vmctl, virtiobase))
-                               break;
-               }
        }
 
        printf("shared is %d, blob is %d\n", shared, *mmap_blob);
 
        quit = 1;
+       /* later. 
        for (int i = 0; i < nr_threads-1; i++) {
                int ret;
                if (pthread_join(my_threads[i], &my_retvals[i]))
                        perror("pth_join failed");
                printf("%d %d\n", i, ret);
        }
+ */
 
        return 0;
 }
diff --git a/tests/vmrunkernel.c b/tests/vmrunkernel.c
deleted file mode 100644 (file)
index cccb493..0000000
+++ /dev/null
@@ -1,353 +0,0 @@
-#include <stdio.h> 
-#include <pthread.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <parlib/arch/arch.h>
-#include <parlib/ros_debug.h>
-#include <unistd.h>
-#include <errno.h>
-#include <dirent.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ros/syscall.h>
-#include <sys/mman.h>
-#include <vmm/coreboot_tables.h>
-#include <ros/vmm.h>
-#include <vmm/virtio.h>
-#include <vmm/virtio_mmio.h>
-#include <vmm/virtio_ids.h>
-
-/* this test will run the "kernel" in the negative address space. We hope. */
-int *mmap_blob;
-unsigned long long stack[1024];
-volatile int shared = 0;
-volatile int quit = 0;
-int mcp = 1;
-
-#define MiB 0x100000u
-#define GiB (1u<<30)
-#define VIRTIOBASE (15*MiB)
-#define GKERNBASE (16*MiB)
-#define KERNSIZE (128*MiB+GKERNBASE)
-uint8_t _kernel[KERNSIZE];
-
-unsigned long long *p512, *p1, *p2m;
-
-pthread_t *my_threads;
-void **my_retvals;
-int nr_threads = 2;
-char *line, *consline, *outline;
-struct scatterlist iov[32];
-unsigned int inlen, outlen, conslen;
-/* unlike Linux, this shared struct is for both host and guest. */
-//     struct virtqueue *constoguest = 
-//             vring_new_virtqueue(0, 512, 8192, 0, inpages, NULL, NULL, "test");
-volatile int gaveit = 0, gotitback = 0;
-struct virtqueue *guesttocons;
-struct scatterlist out[] = { {NULL, sizeof(outline)}, };
-struct scatterlist in[] = { {NULL, sizeof(line)}, };
-
-static inline uint32_t read32(const volatile void *addr)
-{
-       return *(const volatile uint32_t *)addr;
-}
-
-static inline void write32(volatile void *addr, uint32_t value)
-{
-       *(volatile uint32_t *)addr = value;
-}
-
-void dumpvirtio_mmio(FILE *f, void *v)
-{
-       fprintf(f, "VIRTIO_MMIO_MAGIC_VALUE: 0x%x\n", read32(v+VIRTIO_MMIO_MAGIC_VALUE));
-       fprintf(f, "VIRTIO_MMIO_VERSION: 0x%x\n", read32(v+VIRTIO_MMIO_VERSION));
-       fprintf(f, "VIRTIO_MMIO_DEVICE_ID: 0x%x\n", read32(v+VIRTIO_MMIO_DEVICE_ID));
-       fprintf(f, "VIRTIO_MMIO_VENDOR_ID: 0x%x\n", read32(v+VIRTIO_MMIO_VENDOR_ID));
-       fprintf(f, "VIRTIO_MMIO_DEVICE_FEATURES: 0x%x\n", read32(v+VIRTIO_MMIO_DEVICE_FEATURES));
-       fprintf(f, "VIRTIO_MMIO_DEVICE_FEATURES_SEL: 0x%x\n", read32(v+VIRTIO_MMIO_DEVICE_FEATURES_SEL));
-       fprintf(f, "VIRTIO_MMIO_DRIVER_FEATURES: 0x%x\n", read32(v+VIRTIO_MMIO_DRIVER_FEATURES));
-       fprintf(f, "VIRTIO_MMIO_DRIVER_FEATURES_SEL: 0x%x\n", read32(v+VIRTIO_MMIO_DRIVER_FEATURES_SEL));
-       fprintf(f, "VIRTIO_MMIO_GUEST_PAGE_SIZE: 0x%x\n", read32(v+VIRTIO_MMIO_GUEST_PAGE_SIZE));
-       fprintf(f, "VIRTIO_MMIO_QUEUE_SEL: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_SEL));
-       fprintf(f, "VIRTIO_MMIO_QUEUE_NUM_MAX: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_NUM_MAX));
-       fprintf(f, "VIRTIO_MMIO_QUEUE_NUM: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_NUM));
-       fprintf(f, "VIRTIO_MMIO_QUEUE_ALIGN: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_ALIGN));
-       fprintf(f, "VIRTIO_MMIO_QUEUE_PFN: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_PFN));
-       fprintf(f, "VIRTIO_MMIO_QUEUE_READY: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_READY));
-       fprintf(f, "VIRTIO_MMIO_QUEUE_NOTIFY: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_NOTIFY));
-       fprintf(f, "VIRTIO_MMIO_INTERRUPT_STATUS: 0x%x\n", read32(v+VIRTIO_MMIO_INTERRUPT_STATUS));
-       fprintf(f, "VIRTIO_MMIO_INTERRUPT_ACK: 0x%x\n", read32(v+VIRTIO_MMIO_INTERRUPT_ACK));
-       fprintf(f, "VIRTIO_MMIO_STATUS: 0x%x\n", read32(v+VIRTIO_MMIO_STATUS));
-       fprintf(f, "VIRTIO_MMIO_QUEUE_DESC_LOW: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_DESC_LOW));
-       fprintf(f, "VIRTIO_MMIO_QUEUE_DESC_HIGH: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_DESC_HIGH));
-       fprintf(f, "VIRTIO_MMIO_QUEUE_AVAIL_LOW: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_AVAIL_LOW));
-       fprintf(f, "VIRTIO_MMIO_QUEUE_AVAIL_HIGH: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_AVAIL_HIGH));
-       fprintf(f, "VIRTIO_MMIO_QUEUE_USED_LOW: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_USED_LOW));
-       fprintf(f, "VIRTIO_MMIO_QUEUE_USED_HIGH: 0x%x\n", read32(v+VIRTIO_MMIO_QUEUE_USED_HIGH));
-       fprintf(f, "VIRTIO_MMIO_CONFIG_GENERATION: 0x%x\n", read32(v+VIRTIO_MMIO_CONFIG_GENERATION));
-}
-static void setupconsole(void *v)
-{
-       // try to make linux happy.
-       // this is not really endian safe but ... well ... WE'RE ON THE SAME MACHINE
-       write32(v+VIRTIO_MMIO_MAGIC_VALUE, ('v' | 'i' << 8 | 'r' << 16 | 't' << 24));
-       // no constant for this is defined anywhere. It's just 1.
-       write32(v+VIRTIO_MMIO_VERSION, 1);
-       write32(v+VIRTIO_MMIO_DEVICE_ID, VIRTIO_ID_CONSOLE);
-       write32(v+VIRTIO_MMIO_QUEUE_NUM_MAX, 1);
-       write32(v+VIRTIO_MMIO_QUEUE_PFN, 0);
-}
-
-int debug = 1;
-
-struct ttargs {
-       void *virtio;
-};
-
-void *talk_thread(void *arg)
-{
-       struct ttargs *a = arg;
-       void *v = a->virtio;
-       fprintf(stderr, "talk thread ..\n");
-       uint16_t head;
-       uint32_t vv;
-       int i;
-       int num;
-       printf("Sleep 15 seconds\n");
-       uthread_sleep(15);
-       printf("----------------------- TT a %p\n", a);
-       printf("talk thread ttargs %x v %x\n", a, v);
-       
-       if (debug) printf("Spin on console being read, print num queues, halt\n");
-       while ((vv = read32(v+VIRTIO_MMIO_DRIVER_FEATURES)) == 0) {
-               printf("no ready ... \n");
-               if (debug) {
-                       dumpvirtio_mmio(stdout, v);
-               }
-               printf("sleep 1 second\n");
-               uthread_sleep(1);
-       }
-       if (debug)printf("vv %x, set selector %x\n", vv, read32(v + VIRTIO_MMIO_DRIVER_FEATURES_SEL));
-       if (debug) printf("loop forever");
-       while (! quit)
-               ;
-       for(num = 0;;num++) {
-               /* host: use any buffers we should have been sent. */
-               head = wait_for_vq_desc(guesttocons, iov, &outlen, &inlen);
-               if (debug)
-                       printf("vq desc head %d, gaveit %d gotitback %d\n", head, gaveit, gotitback);
-               for(i = 0; debug && i < outlen + inlen; i++)
-                       printf("v[%d/%d] v %p len %d\n", i, outlen + inlen, iov[i].v, iov[i].length);
-               /* host: if we got an output buffer, just output it. */
-               for(i = 0; i < outlen; i++) {
-                       num++;
-                       printf("Host:%s:\n", (char *)iov[i].v);
-               }
-               
-               if (debug)
-                       printf("outlen is %d; inlen is %d\n", outlen, inlen);
-               /* host: fill in the writeable buffers. */
-               for (i = outlen; i < outlen + inlen; i++) {
-                       /* host: read a line. */
-                       memset(consline, 0, 128);
-                       if (1) {
-                               if (fgets(consline, 4096-256, stdin) == NULL) {
-                                       exit(0);
-                               } 
-                               if (debug) printf("GOT A LINE:%s:\n", consline);
-                       } else {
-                               sprintf(consline, "hi there. %d\n", i);
-                       }
-                       memmove(iov[i].v, consline, strlen(consline)+ 1);
-                       iov[i].length = strlen(consline) + 1;
-               }
-               if (debug) printf("call add_used\n");
-               /* host: now ack that we used them all. */
-               add_used(guesttocons, head, outlen+inlen);
-               if (debug) printf("DONE call add_used\n");
-       }
-       fprintf(stderr, "All done\n");
-       return NULL;
-}
-
-struct ttargs t;
-       
-
-int main(int argc, char **argv)
-{
-       struct vmctl vmctl;
-       int amt;
-       int vmmflags = VMM_VMCALL_PRINTF;
-       uint64_t entry = 0x1000000, kerneladdress = 0x1000000;
-       int nr_gpcs = 1;
-       int fd = open("#c/vmctl", O_RDWR), ret;
-       void * x;
-       int kfd = -1;
-       static char cmd[512];
-       void *coreboot_tables = (void *) 0x1165000;
-       /* kernel has to be in the range VIRTIOBASE to KERNSIZE+GKERNBASE for now. */
-       // mmap is not working for us at present.
-       if ((uint64_t)_kernel > VIRTIOBASE) {
-               printf("kernel array @%p is above , VIRTIOBASE@%p sucks\n", _kernel, VIRTIOBASE);
-               exit(1);
-       }
-       memset(_kernel, 0, sizeof(_kernel));
-
-       if (fd < 0) {
-               perror("#c/sysctl");
-               exit(1);
-       }
-       argc--,argv++;
-       // switches ...
-       // Sorry, I don't much like the gnu opt parsing code.
-       while (1) {
-               if (*argv[0] != '-')
-                       break;
-               switch(argv[0][1]) {
-               case 'n':
-                       vmmflags &= ~VMM_VMCALL_PRINTF;
-                       break;
-               default:
-                       printf("BMAFR\n");
-                       break;
-               }
-               argc--,argv++;
-       }
-       if (argc < 1) {
-               fprintf(stderr, "Usage: %s vmimage [-n (no vmcall printf)] [coreboot_tables [loadaddress [entrypoint]]]\n", argv[0]);
-               exit(1);
-       }
-       if (argc > 1)
-               coreboot_tables = (void *) strtoull(argv[1], 0, 0);
-       if (argc > 2)
-               kerneladdress = strtoull(argv[2], 0, 0);
-       if (argc > 3)
-               entry = strtoull(argv[3], 0, 0);
-       kfd = open(argv[0], O_RDONLY);
-       if (kfd < 0) {
-               perror(argv[0]);
-               exit(1);
-       }
-       // read in the kernel.
-       x = (void *)kerneladdress;
-       for(;;) {
-               amt = read(kfd, x, 1048576);
-               if (amt < 0) {
-                       perror("read");
-                       exit(1);
-               }
-               if (amt == 0) {
-                       break;
-               }
-               x += amt;
-       }
-       fprintf(stderr, "Read in %d bytes\n", x-kerneladdress);
-
-       fprintf(stderr, "Run with %d cores and vmmflags 0x%x\n", nr_gpcs, vmmflags);
-       if (ros_syscall(SYS_setup_vmm, nr_gpcs, vmmflags, 0, 0, 0, 0) != nr_gpcs) {
-               perror("Guest pcore setup failed");
-               exit(1);
-       }
-       /* blob that is faulted in from the EPT first.  we need this to be in low
-        * memory (not above the normal mmap_break), so the EPT can look it up.
-        * Note that we won't get 4096.  The min is 1MB now, and ld is there. */
-       mmap_blob = mmap((int*)4096, PGSIZE, PROT_READ | PROT_WRITE,
-                        MAP_ANONYMOUS, -1, 0);
-       if (mmap_blob == MAP_FAILED) {
-               perror("Unable to mmap");
-               exit(1);
-       }
-
-       mcp = 1;
-       if (mcp) {
-               my_threads = malloc(sizeof(pthread_t) * nr_threads);
-               my_retvals = malloc(sizeof(void*) * nr_threads);
-               if (!(my_retvals && my_threads))
-                       perror("Init threads/malloc");
-
-               pthread_can_vcore_request(FALSE);       /* 2LS won't manage vcores */
-               pthread_need_tls(FALSE);
-               pthread_mcp_init();                                     /* gives us one vcore */
-               vcore_request(nr_threads - 1);          /* ghetto incremental interface */
-               for (int i = 0; i < nr_threads; i++) {
-                       x = __procinfo.vcoremap;
-                       printf("%p\n", __procinfo.vcoremap);
-                       printf("Vcore %d mapped to pcore %d\n", i,
-                               __procinfo.vcoremap[i].pcoreid);
-               }
-       }
-
-       t.virtio = (void *)VIRTIOBASE;
-
-       ret = syscall(33, 1);
-       if (ret < 0) {
-               perror("vm setup");
-               exit(1);
-       }
-       ret = posix_memalign((void **)&p512, 4096, 3*4096);
-       printf("memalign is %p\n", p512);
-       if (ret) {
-               perror("ptp alloc");
-               exit(1);
-       }
-       p1 = &p512[512];
-       p2m = &p512[1024];
-       uint64_t kernbase = 0; //0xffffffff80000000;
-       uint64_t highkernbase = 0xffffffff80000000;
-       p512[PML4(kernbase)] = (unsigned long long)p1 | 7;
-       p1[PML3(kernbase)] = /*0x87; */(unsigned long long)p2m | 7;
-       p512[PML4(highkernbase)] = (unsigned long long)p1 | 7;
-       p1[PML3(highkernbase)] = /*0x87; */(unsigned long long)p2m | 7;
-#define _2MiB (0x200000)
-       int i;
-       for (i = 0; i < 512; i++) {
-               p2m[PML2(kernbase + i * _2MiB)] = 0x87 | i * _2MiB;
-       }
-
-       kernbase >>= (0+12);
-       kernbase <<= (0 + 12);
-       uint8_t *kernel = (void *)GKERNBASE;
-       write_coreboot_table(coreboot_tables, ((void *)VIRTIOBASE) /*kernel*/, KERNSIZE + 1048576);
-       hexdump(stdout, coreboot_tables, 512);
-       setupconsole((void *)VIRTIOBASE);
-       hexdump(stdout, (void *)VIRTIOBASE, 128);
-       printf("kernbase for pml4 is 0x%llx and entry is %llx\n", kernbase, entry);
-       printf("p512 %p p512[0] is 0x%lx p1 %p p1[0] is 0x%x\n", p512, p512[0], p1, p1[0]);
-       vmctl.command = REG_RSP_RIP_CR3;
-       vmctl.cr3 = (uint64_t) p512;
-       vmctl.regs.tf_rip = entry;
-       vmctl.regs.tf_rsp = (uint64_t) &stack[1024];
-       if (mcp) {
-               if (pthread_create(&my_threads[0], NULL, &talk_thread, &t))
-                       perror("pth_create failed");
-       }
-       printf("threads started\n");
-       printf("Writing command :%s:\n", cmd);
-       // sys_getpcoreid
-       while (1) {
-               int c;
-               ret = write(fd, &vmctl, sizeof(vmctl));
-               if (ret != sizeof(vmctl)) {
-                       perror(cmd);
-               }
-               printf("RESUME?\n");
-               c = getchar();
-               if (c == 'q')
-                       break;
-               printf("RIP %p\n", vmctl.regs.tf_rip);
-               vmctl.command = RESUME;
-       }
-       dumpvirtio_mmio(stdout, (void *)VIRTIOBASE);
-       printf("shared is %d, blob is %d\n", shared, *mmap_blob);
-
-       quit = 1;
-       for (int i = 0; i < nr_threads-1; i++) {
-               int ret;
-               if (pthread_join(my_threads[i], &my_retvals[i]))
-                       perror("pth_join failed");
-               printf("%d %d\n", i, ret);
-       }
-
-       return 0;
-}
index 21a6c02..96f2507 100644 (file)
@@ -125,4 +125,14 @@ unsigned int virtqueue_get_vring_size(struct virtqueue *vq);
 bool virtqueue_is_broken(struct virtqueue *vq);
 void virtqueue_close(struct virtqueue *vq);
 
+static inline uint32_t read32(const volatile void *addr)
+{
+       return *(const volatile uint32_t *)addr;
+}
+
+static inline void write32(volatile void *addr, uint32_t value)
+{
+       *(volatile uint32_t *)addr = value;
+}
+
 #endif /* VIRTIO_VIRTIO_H */
index c18264d..d78c8cd 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef _UAPI_LINUX_VIRTIO_CONFIG_H
-#define _UAPI_LINUX_VIRTIO_CONFIG_H
+#ifndef _VMM_INCLUDE_VIRTIO_CONFIG_H
+#define _VMM_INCLUDE_VIRTIO_CONFIG_H
 /* This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so
  * anyone can use the definitions to implement compatible drivers/servers.
  *
@@ -29,7 +29,6 @@
 /* Virtio devices use a standardized configuration space to define their
  * features and pass configuration information, but each implementation can
  * store and access that space differently. */
-#include <linux/types.h>
 
 /* Status byte for guest to report progress, and synchronize features. */
 /* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */
@@ -61,4 +60,4 @@
 /* v1.0 compliant. */
 #define VIRTIO_F_VERSION_1             32
 
-#endif /* _UAPI_LINUX_VIRTIO_CONFIG_H */
+#endif /* _VMM_INCLUDE_VIRTIO_CONFIG_H */
index c4b0968..b0e8cad 100644 (file)
  * the per-driver configuration space - Read Write */
 #define VIRTIO_MMIO_CONFIG             0x100
 
-
-
 /*
  * Interrupt flags (re: interrupt status & acknowledge registers)
  */
 #define VIRTIO_MMIO_INT_VRING          (1 << 0)
 #define VIRTIO_MMIO_INT_CONFIG         (1 << 1)
 
+// A vq defines on queue attached to a device. It has a function, started as a thread;
+// an arg, for arbitrary use; qnum, which is an indicator of how much memory is given
+// to the queue; a pointer to the thread that gets started when the queue is notified;
+// a physical frame number, which is process virtual to the vmm; an isr (not used yet);
+// status; and a pointer to the virtio struct.
+struct vq {
+       char *name;
+       void *(*f)(void *arg); // Start this as a thread when a matching virtio is discovered.
+       void *arg;
+       int maxqnum; // how many things the q gets? or something. 
+       int qnum; 
+       int qalign;
+       pthread_t thread;
+       /* filled in by virtio probing. */
+       uint64_t pfn;
+       uint32_t isr; // not used yet but ...
+       uint32_t status;
+       uint64_t qdesc;
+       uint64_t qavail;
+       uint64_t qused;
+       void *virtio;
+};
+
+// a vqdev has a name; magic number; features ( we MUST have features);
+// and an array of vqs.
+struct vqdev {
+       /* Set up usually as a static initializer */
+       char *name;
+       uint32_t dev; // e.g. VIRTIO_ID_CONSOLE);
+       uint32_t features;
+       int numvqs;
+       struct vq vqs[];
+};
+
+
+/* This struct is passed to a virtio thread when it is started. It includes
+ * needed info and the vqdev arg. This seems overkill but we may need to add to it.
+ */
+struct virtio_threadarg {
+       struct vq *arg;
+};
+
+void dumpvirtio_mmio(FILE *f, uint64_t gpa);
+void register_virtio_mmio(struct vqdev *v, uint64_t virtio_base);
+void virtio_mmio(struct vmctl *v);
+
 #endif
index c8f7294..f274ccc 100644 (file)
  * with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "hw/sysbus.h"
-#include "hw/virtio/virtio.h"
-#include "qemu/host-utils.h"
-#include "sysemu/kvm.h"
-#include "hw/virtio/virtio-bus.h"
-#include "qemu/error-report.h"
-
-/* #define DEBUG_VIRTIO_MMIO */
-
-#ifdef DEBUG_VIRTIO_MMIO
-
+#include <stdio.h>
+#include <sys/types.h>
+#include <pthread.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <parlib/arch/arch.h>
+#include <parlib/ros_debug.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/uio.h>
+#include <stdint.h>
+#include <err.h>
+#include <sys/mman.h>
+#include <ros/vmm.h>
+#include <vmm/virtio.h>
+#include <vmm/virtio_mmio.h>
+#include <vmm/virtio_ids.h>
+#include <vmm/virtio_config.h>
+
+int debug_virtio_mmio = 1;
 #define DPRINTF(fmt, ...) \
-do { printf("virtio_mmio: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
+       if (debug_virtio_mmio) { printf("virtio_mmio: " fmt , ## __VA_ARGS__); }
 
-/* QOM macros */
-/* virtio-mmio-bus */
-#define TYPE_VIRTIO_MMIO_BUS "virtio-mmio-bus"
-#define VIRTIO_MMIO_BUS(obj) \
-        OBJECT_CHECK(VirtioBusState, (obj), TYPE_VIRTIO_MMIO_BUS)
-#define VIRTIO_MMIO_BUS_GET_CLASS(obj) \
-        OBJECT_GET_CLASS(VirtioBusClass, (obj), TYPE_VIRTIO_MMIO_BUS)
-#define VIRTIO_MMIO_BUS_CLASS(klass) \
-        OBJECT_CLASS_CHECK(VirtioBusClass, (klass), TYPE_VIRTIO_MMIO_BUS)
-
-/* virtio-mmio */
-#define TYPE_VIRTIO_MMIO "virtio-mmio"
-#define VIRTIO_MMIO(obj) \
-        OBJECT_CHECK(VirtIOMMIOProxy, (obj), TYPE_VIRTIO_MMIO)
-
-/* Memory mapped register offsets */
-#define VIRTIO_MMIO_MAGIC 0x0
-#define VIRTIO_MMIO_VERSION 0x4
-#define VIRTIO_MMIO_DEVICEID 0x8
-#define VIRTIO_MMIO_VENDORID 0xc
-#define VIRTIO_MMIO_HOSTFEATURES 0x10
-#define VIRTIO_MMIO_HOSTFEATURESSEL 0x14
-#define VIRTIO_MMIO_GUESTFEATURES 0x20
-#define VIRTIO_MMIO_GUESTFEATURESSEL 0x24
-#define VIRTIO_MMIO_GUESTPAGESIZE 0x28
-#define VIRTIO_MMIO_QUEUESEL 0x30
-#define VIRTIO_MMIO_QUEUENUMMAX 0x34
-#define VIRTIO_MMIO_QUEUENUM 0x38
-#define VIRTIO_MMIO_QUEUEALIGN 0x3c
-#define VIRTIO_MMIO_QUEUEPFN 0x40
-#define VIRTIO_MMIO_QUEUENOTIFY 0x50
-#define VIRTIO_MMIO_INTERRUPTSTATUS 0x60
-#define VIRTIO_MMIO_INTERRUPTACK 0x64
-#define VIRTIO_MMIO_STATUS 0x70
-/* Device specific config space starts here */
-#define VIRTIO_MMIO_CONFIG 0x100
 
 #define VIRT_MAGIC 0x74726976 /* 'virt' */
-#define VIRT_VERSION 1
+#define VIRT_VERSION 2
 #define VIRT_VENDOR 0x554D4551 /* 'QEMU' */
 
-typedef struct {
-    /* Generic */
-    SysBusDevice parent_obj;
-    MemoryRegion iomem;
-    qemu_irq irq;
-    /* Guest accessible state needing migration and reset */
-    uint32_t host_features_sel;
-    uint32_t guest_features_sel;
-    uint32_t guest_page_shift;
-    /* virtio-bus */
-    VirtioBusState bus;
-    bool ioeventfd_disabled;
-    bool ioeventfd_started;
-} VirtIOMMIOProxy;
-
-static int virtio_mmio_set_host_notifier_internal(VirtIOMMIOProxy *proxy,
-                                                  int n, bool assign,
-                                                  bool set_handler)
-{
-    VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
-    VirtQueue *vq = virtio_get_queue(vdev, n);
-    EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
-    int r = 0;
-
-    if (assign) {
-        r = event_notifier_init(notifier, 1);
-        if (r < 0) {
-            error_report("%s: unable to init event notifier: %d",
-                         __func__, r);
-            return r;
-        }
-        virtio_queue_set_host_notifier_fd_handler(vq, true, set_handler);
-        memory_region_add_eventfd(&proxy->iomem, VIRTIO_MMIO_QUEUENOTIFY, 4,
-                                  true, n, notifier);
-    } else {
-        memory_region_del_eventfd(&proxy->iomem, VIRTIO_MMIO_QUEUENOTIFY, 4,
-                                  true, n, notifier);
-        virtio_queue_set_host_notifier_fd_handler(vq, false, false);
-        event_notifier_cleanup(notifier);
-    }
-    return r;
-}
 
-static void virtio_mmio_start_ioeventfd(VirtIOMMIOProxy *proxy)
+typedef struct {
+       int state; // not used yet. */
+       uint64_t bar;
+       uint32_t status;
+       int qsel; // queue we are on.
+       int pagesize;
+       int page_shift;
+       int host_features_sel;
+       int guest_features_sel;
+       struct vqdev *vqdev;
+} mmiostate;
+
+static mmiostate mmio;
+
+void register_virtio_mmio(struct vqdev *vqdev, uint64_t virtio_base)
 {
-    VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
-    int n, r;
-
-    if (!kvm_eventfds_enabled() ||
-        proxy->ioeventfd_disabled ||
-        proxy->ioeventfd_started) {
-        return;
-    }
-
-    for (n = 0; n < VIRTIO_QUEUE_MAX; n++) {
-        if (!virtio_queue_get_num(vdev, n)) {
-            continue;
-        }
-
-        r = virtio_mmio_set_host_notifier_internal(proxy, n, true, true);
-        if (r < 0) {
-            goto assign_error;
-        }
-    }
-    proxy->ioeventfd_started = true;
-    return;
-
-assign_error:
-    while (--n >= 0) {
-        if (!virtio_queue_get_num(vdev, n)) {
-            continue;
-        }
-
-        r = virtio_mmio_set_host_notifier_internal(proxy, n, false, false);
-        assert(r >= 0);
-    }
-    proxy->ioeventfd_started = false;
-    error_report("%s: failed. Fallback to a userspace (slower).", __func__);
+       mmio.bar = virtio_base;
+       mmio.vqdev = vqdev;
 }
 
-static void virtio_mmio_stop_ioeventfd(VirtIOMMIOProxy *proxy)
-{
-    int r;
-    int n;
-    VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
-
-    if (!proxy->ioeventfd_started) {
-        return;
-    }
-
-    for (n = 0; n < VIRTIO_QUEUE_MAX; n++) {
-        if (!virtio_queue_get_num(vdev, n)) {
-            continue;
-        }
-
-        r = virtio_mmio_set_host_notifier_internal(proxy, n, false, false);
-        assert(r >= 0);
-    }
-    proxy->ioeventfd_started = false;
-}
+static uint32_t virtio_mmio_read(uint64_t gpa);
+char *virtio_names[] = {
+       [VIRTIO_MMIO_MAGIC_VALUE] "VIRTIO_MMIO_MAGIC_VALUE",
+       [VIRTIO_MMIO_VERSION] "VIRTIO_MMIO_VERSION",
+       [VIRTIO_MMIO_DEVICE_ID] "VIRTIO_MMIO_DEVICE_ID",
+       [VIRTIO_MMIO_VENDOR_ID] "VIRTIO_MMIO_VENDOR_ID",
+       [VIRTIO_MMIO_DEVICE_FEATURES] "VIRTIO_MMIO_DEVICE_FEATURES",
+       [VIRTIO_MMIO_DEVICE_FEATURES_SEL] "VIRTIO_MMIO_DEVICE_FEATURES_SEL",
+       [VIRTIO_MMIO_DRIVER_FEATURES] "VIRTIO_MMIO_DRIVER_FEATURES",
+       [VIRTIO_MMIO_DRIVER_FEATURES_SEL] "VIRTIO_MMIO_DRIVER_FEATURES_SEL",
+       [VIRTIO_MMIO_GUEST_PAGE_SIZE] "VIRTIO_MMIO_GUEST_PAGE_SIZE",
+       [VIRTIO_MMIO_QUEUE_SEL] "VIRTIO_MMIO_QUEUE_SEL",
+       [VIRTIO_MMIO_QUEUE_NUM_MAX] "VIRTIO_MMIO_QUEUE_NUM_MAX",
+       [VIRTIO_MMIO_QUEUE_NUM] "VIRTIO_MMIO_QUEUE_NUM",
+       [VIRTIO_MMIO_QUEUE_ALIGN] "VIRTIO_MMIO_QUEUE_ALIGN",
+       [VIRTIO_MMIO_QUEUE_PFN] "VIRTIO_MMIO_QUEUE_PFN",
+       [VIRTIO_MMIO_QUEUE_READY] "VIRTIO_MMIO_QUEUE_READY",
+       [VIRTIO_MMIO_QUEUE_NOTIFY] "VIRTIO_MMIO_QUEUE_NOTIFY",
+       [VIRTIO_MMIO_INTERRUPT_STATUS] "VIRTIO_MMIO_INTERRUPT_STATUS",
+       [VIRTIO_MMIO_INTERRUPT_ACK] "VIRTIO_MMIO_INTERRUPT_ACK",
+       [VIRTIO_MMIO_STATUS] "VIRTIO_MMIO_STATUS",
+       [VIRTIO_MMIO_QUEUE_DESC_LOW] "VIRTIO_MMIO_QUEUE_DESC_LOW",
+       [VIRTIO_MMIO_QUEUE_DESC_HIGH] "VIRTIO_MMIO_QUEUE_DESC_HIGH",
+       [VIRTIO_MMIO_QUEUE_AVAIL_LOW] "VIRTIO_MMIO_QUEUE_AVAIL_LOW",
+       [VIRTIO_MMIO_QUEUE_AVAIL_HIGH] "VIRTIO_MMIO_QUEUE_AVAIL_HIGH",
+       [VIRTIO_MMIO_QUEUE_USED_LOW] "VIRTIO_MMIO_QUEUE_USED_LOW",
+       [VIRTIO_MMIO_QUEUE_USED_HIGH] "VIRTIO_MMIO_QUEUE_USED_HIGH",
+       [VIRTIO_MMIO_CONFIG_GENERATION] "VIRTIO_MMIO_CONFIG_GENERATION",
+};
 
-static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
+/* We're going to attempt to make mmio stateless, since the real machine is in
+ * the guest kernel. From what we know so far, all IO to the mmio space is 32 bits.
+ */
+static uint32_t virtio_mmio_read(uint64_t gpa)
 {
-    VirtIOMMIOProxy *proxy = (VirtIOMMIOProxy *)opaque;
-    VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
-
-    DPRINTF("virtio_mmio_read offset 0x%x\n", (int)offset);
-
-    if (!vdev) {
-        /* If no backend is present, we treat most registers as
-         * read-as-zero, except for the magic number, version and
-         * vendor ID. This is not strictly sanctioned by the virtio
-         * spec, but it allows us to provide transports with no backend
-         * plugged in which don't confuse Linux's virtio code: the
-         * probe won't complain about the bad magic number, but the
-         * device ID of zero means no backend will claim it.
-         */
-        switch (offset) {
-        case VIRTIO_MMIO_MAGIC:
-            return VIRT_MAGIC;
-        case VIRTIO_MMIO_VERSION:
-            return VIRT_VERSION;
-        case VIRTIO_MMIO_VENDORID:
-            return VIRT_VENDOR;
-        default:
-            return 0;
-        }
-    }
 
+       unsigned int offset = gpa - mmio.bar;
+       
+       DPRINTF("virtio_mmio_read offset %s 0x%x\n", virtio_names[offset],(int)offset);
+
+       /* If no backend is present, we treat most registers as
+        * read-as-zero, except for the magic number, version and
+        * vendor ID. This is not strictly sanctioned by the virtio
+        * spec, but it allows us to provide transports with no backend
+        * plugged in which don't confuse Linux's virtio code: the
+        * probe won't complain about the bad magic number, but the
+        * device ID of zero means no backend will claim it.
+        */
+       if (mmio.vqdev->numvqs == 0) {
+               switch (offset) {
+               case VIRTIO_MMIO_MAGIC_VALUE:
+                       return VIRT_MAGIC;
+               case VIRTIO_MMIO_VERSION:
+                       return VIRT_VERSION;
+               case VIRTIO_MMIO_VENDOR_ID:
+                       return VIRT_VENDOR;
+               default:
+                       return 0;
+               }
+       }
+
+
+    // WTF? Does this happen? 
     if (offset >= VIRTIO_MMIO_CONFIG) {
-        offset -= VIRTIO_MMIO_CONFIG;
-        switch (size) {
-        case 1:
-            return virtio_config_readb(vdev, offset);
-        case 2:
-            return virtio_config_readw(vdev, offset);
-        case 4:
-            return virtio_config_readl(vdev, offset);
-        default:
-            abort();
-        }
+           fprintf(stderr, "Whoa. Reading past mmio config space? What gives?\n");
+           return -1;
+#if 0
+           offset -= VIRTIO_MMIO_CONFIG;
+           switch (size) {
+           case 1:
+                   return virtio_config_readb(vdev, offset);
+           case 2:
+                   return virtio_config_readw(vdev, offset);
+           case 4:
+                   return virtio_config_readl(vdev, offset);
+           default:
+                   abort();
+           }
+#endif
     }
+
+#if 0
     if (size != 4) {
         DPRINTF("wrong size access to register!\n");
         return 0;
     }
+#endif
+DPRINTF("FUCK 0x%x\n", offset);
+fprintf(stderr, "FUCK2 0x%x\n", offset);
     switch (offset) {
-    case VIRTIO_MMIO_MAGIC:
-        return VIRT_MAGIC;
+    case VIRTIO_MMIO_MAGIC_VALUE:
+           return VIRT_MAGIC;
     case VIRTIO_MMIO_VERSION:
-        return VIRT_VERSION;
-    case VIRTIO_MMIO_DEVICEID:
-        return vdev->device_id;
-    case VIRTIO_MMIO_VENDORID:
-        return VIRT_VENDOR;
-    case VIRTIO_MMIO_HOSTFEATURES:
-        if (proxy->host_features_sel) {
-            return 0;
-        }
-        return vdev->host_features;
-    case VIRTIO_MMIO_QUEUENUMMAX:
-        if (!virtio_queue_get_num(vdev, vdev->queue_sel)) {
-            return 0;
-        }
-        return VIRTQUEUE_MAX_SIZE;
-    case VIRTIO_MMIO_QUEUEPFN:
-        return virtio_queue_get_addr(vdev, vdev->queue_sel)
-            >> proxy->guest_page_shift;
-    case VIRTIO_MMIO_INTERRUPTSTATUS:
-        return vdev->isr;
+           return VIRT_VERSION;
+    case VIRTIO_MMIO_DEVICE_ID:
+           return mmio.vqdev->dev;
+    case VIRTIO_MMIO_VENDOR_ID:
+           return VIRT_VENDOR;
+    case VIRTIO_MMIO_DEVICE_FEATURES:
+// ???     if (proxy->host_features_sel) {
+//         return 0;
+//         }
+       printf("FUCK %x\n", mmio.vqdev->features);
+       DPRINTF("RETURN 0x%x \n", mmio.vqdev->features);
+           return mmio.vqdev->features;
+    case VIRTIO_MMIO_QUEUE_NUM_MAX:
+           DPRINTF("For q %d, qnum is %d\n", mmio.qsel, mmio.vqdev->vqs[mmio.qsel].qnum);
+           return mmio.vqdev->vqs[mmio.qsel].maxqnum;
+    case VIRTIO_MMIO_QUEUE_PFN:
+           return mmio.vqdev->vqs[mmio.qsel].pfn;
+    case VIRTIO_MMIO_INTERRUPT_STATUS:
+           return mmio.vqdev->vqs[mmio.qsel].isr;
     case VIRTIO_MMIO_STATUS:
-        return vdev->status;
-    case VIRTIO_MMIO_HOSTFEATURESSEL:
-    case VIRTIO_MMIO_GUESTFEATURES:
-    case VIRTIO_MMIO_GUESTFEATURESSEL:
-    case VIRTIO_MMIO_GUESTPAGESIZE:
-    case VIRTIO_MMIO_QUEUESEL:
-    case VIRTIO_MMIO_QUEUENUM:
-    case VIRTIO_MMIO_QUEUEALIGN:
-    case VIRTIO_MMIO_QUEUENOTIFY:
-    case VIRTIO_MMIO_INTERRUPTACK:
-        DPRINTF("read of write-only register\n");
+           return mmio.vqdev->vqs[mmio.qsel].status;
+    case VIRTIO_MMIO_DEVICE_FEATURES_SEL:
+    case VIRTIO_MMIO_DRIVER_FEATURES:
+    case VIRTIO_MMIO_DRIVER_FEATURES_SEL:
+    case VIRTIO_MMIO_GUEST_PAGE_SIZE:
+    case VIRTIO_MMIO_QUEUE_SEL:
+    case VIRTIO_MMIO_QUEUE_NUM:
+    case VIRTIO_MMIO_QUEUE_ALIGN:
+    case VIRTIO_MMIO_QUEUE_READY:
+    case VIRTIO_MMIO_INTERRUPT_ACK:
+           fprintf(stderr, "read of write-only register@%p\n", (void *)gpa);
         return 0;
     default:
-        DPRINTF("bad register offset\n");
+           fprintf(stderr, "bad register offset@%p\n", (void *)gpa);
         return 0;
     }
     return 0;
 }
 
-static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
-                              unsigned size)
+static void virtio_mmio_write(uint64_t gpa, uint32_t value)
 {
-    VirtIOMMIOProxy *proxy = (VirtIOMMIOProxy *)opaque;
-    VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
-
-    DPRINTF("virtio_mmio_write offset 0x%x value 0x%" PRIx64 "\n",
-            (int)offset, value);
-
-    if (!vdev) {
-        /* If no backend is present, we just make all registers
-         * write-ignored. This allows us to provide transports with
-         * no backend plugged in.
-         */
-        return;
-    }
+       uint64_t val64;
+       unsigned int offset = gpa - mmio.bar;
+       
+       DPRINTF("virtio_mmio_write offset %s 0x%x value 0x%x\n", virtio_names[offset], (int)offset, value);
 
     if (offset >= VIRTIO_MMIO_CONFIG) {
+           fprintf(stderr, "Whoa. Writing past mmio config space? What gives?\n");
+#if 0
         offset -= VIRTIO_MMIO_CONFIG;
         switch (size) {
         case 1:
@@ -299,278 +226,252 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
         default:
             abort();
         }
+#endif
         return;
     }
+#if 0
     if (size != 4) {
         DPRINTF("wrong size access to register!\n");
         return;
     }
+#endif
     switch (offset) {
-    case VIRTIO_MMIO_HOSTFEATURESSEL:
-        proxy->host_features_sel = value;
+    case VIRTIO_MMIO_DEVICE_FEATURES_SEL:
+        mmio.host_features_sel = value;
         break;
-    case VIRTIO_MMIO_GUESTFEATURES:
-        if (!proxy->guest_features_sel) {
-            virtio_set_features(vdev, value);
+       /* what's the difference here? Maybe FEATURES is the one you offer. */
+    case VIRTIO_MMIO_DRIVER_FEATURES:
+        if (!mmio.guest_features_sel) {
+            mmio.guest_features_sel = value;
         }
         break;
-    case VIRTIO_MMIO_GUESTFEATURESSEL:
-        proxy->guest_features_sel = value;
+    case VIRTIO_MMIO_DRIVER_FEATURES_SEL:
+           mmio.guest_features_sel = value;
         break;
-    case VIRTIO_MMIO_GUESTPAGESIZE:
-        proxy->guest_page_shift = ctz32(value);
-        if (proxy->guest_page_shift > 31) {
-            proxy->guest_page_shift = 0;
-        }
-        DPRINTF("guest page size %" PRIx64 " shift %d\n", value,
-                proxy->guest_page_shift);
+
+    case VIRTIO_MMIO_GUEST_PAGE_SIZE:
+           mmio.pagesize = value;
+           DPRINTF("guest page size %d bytes\n", mmio.pagesize);
         break;
-    case VIRTIO_MMIO_QUEUESEL:
-        if (value < VIRTIO_QUEUE_MAX) {
-            vdev->queue_sel = value;
-        }
+    case VIRTIO_MMIO_QUEUE_SEL:
+           /* don't check it here. Check it on use. Or maybe check it here. Who knows. */
+           if (value < mmio.vqdev->numvqs)
+                   mmio.qsel = value;
+           else
+                   mmio.qsel = -1;
+           break;
+    case VIRTIO_MMIO_QUEUE_NUM:
+       mmio.vqdev->vqs[mmio.qsel].qnum = value;
         break;
-    case VIRTIO_MMIO_QUEUENUM:
-        DPRINTF("mmio_queue write %d max %d\n", (int)value, VIRTQUEUE_MAX_SIZE);
-        virtio_queue_set_num(vdev, vdev->queue_sel, value);
+    case VIRTIO_MMIO_QUEUE_ALIGN:
+       mmio.vqdev->vqs[mmio.qsel].qalign = value;
         break;
-    case VIRTIO_MMIO_QUEUEALIGN:
-        virtio_queue_set_align(vdev, vdev->queue_sel, value);
+    case VIRTIO_MMIO_QUEUE_PFN:
+       // failure of vision: they used 32 bit numbers. Geez.
+       // v2 is better, we'll do v1 for now.
+       mmio.vqdev->vqs[mmio.qsel].pfn = value;
+                   // let's kick off the thread and see how it goes?
+                   struct virtio_threadarg *va = malloc(sizeof(*va));
+                   va->arg = &mmio.vqdev->vqs[mmio.qsel];
+                   va->arg->virtio = (void *)(va->arg->pfn * mmio.pagesize);
+                   fprintf(stderr, "START THE THREAD. pfn is 0x%x, virtio is %p\n", mmio.pagesize, va->arg->virtio);
+                   if (pthread_create(&va->arg->thread, NULL, va->arg->f, va)) {
+                           fprintf(stderr, "pth_create failed for vq %s", va->arg->name);
+                           perror("pth_create");
+                   }
         break;
-    case VIRTIO_MMIO_QUEUEPFN:
-        if (value == 0) {
-            virtio_reset(vdev);
-        } else {
-            virtio_queue_set_addr(vdev, vdev->queue_sel,
-                                  value << proxy->guest_page_shift);
-        }
+    case VIRTIO_MMIO_QUEUE_NOTIFY:
+           if (value < mmio.vqdev->numvqs) {
+                   mmio.qsel = value;
+           }
         break;
-    case VIRTIO_MMIO_QUEUENOTIFY:
-        if (value < VIRTIO_QUEUE_MAX) {
-            virtio_queue_notify(vdev, value);
-        }
-        break;
-    case VIRTIO_MMIO_INTERRUPTACK:
-        vdev->isr &= ~value;
-        virtio_update_irq(vdev);
+    case VIRTIO_MMIO_INTERRUPT_ACK:
+        //vdev->isr &= ~value;
+        //virtio_update_irq(vdev);
         break;
     case VIRTIO_MMIO_STATUS:
         if (!(value & VIRTIO_CONFIG_S_DRIVER_OK)) {
-            virtio_mmio_stop_ioeventfd(proxy);
+            printf("VIRTIO_MMIO_STATUS write: NOT OK! 0x%x\n", value);
         }
 
-        virtio_set_status(vdev, value & 0xff);
+       mmio.status |= value & 0xff;
 
         if (value & VIRTIO_CONFIG_S_DRIVER_OK) {
-            virtio_mmio_start_ioeventfd(proxy);
+            printf("VIRTIO_MMIO_STATUS write: OK! 0x%x\n", value);
         }
 
-        if (vdev->status == 0) {
-            virtio_reset(vdev);
-        }
         break;
-    case VIRTIO_MMIO_MAGIC:
+    case VIRTIO_MMIO_QUEUE_DESC_LOW:
+           val64 = mmio.vqdev->vqs[mmio.qsel].qdesc;
+           val64 = val64 >> 32;
+           val64 = (val64 <<32) | value;
+           mmio.vqdev->vqs[mmio.qsel].qdesc = val64;
+           DPRINTF("qdesc set low result 0xx%x\n", val64);
+           break;
+           
+    case VIRTIO_MMIO_QUEUE_DESC_HIGH:
+           val64 = (uint32_t) mmio.vqdev->vqs[mmio.qsel].qdesc;
+           mmio.vqdev->vqs[mmio.qsel].qdesc = (((uint64_t) value) <<32) | val64;
+           DPRINTF("qdesc set high result 0xx%x\n", mmio.vqdev->vqs[mmio.qsel].qdesc);
+           break;
+           
+/* Selected queue's Available Ring address, 64 bits in two halves */
+    case VIRTIO_MMIO_QUEUE_AVAIL_LOW:
+           val64 = mmio.vqdev->vqs[mmio.qsel].qavail;
+           val64 = val64 >> 32;
+           val64 = (val64 <<32) | value;
+           mmio.vqdev->vqs[mmio.qsel].qavail = val64;
+           DPRINTF("qavail set low result 0xx%x\n", val64);
+           break;
+    case VIRTIO_MMIO_QUEUE_AVAIL_HIGH:
+           val64 = (uint32_t) mmio.vqdev->vqs[mmio.qsel].qavail;
+           mmio.vqdev->vqs[mmio.qsel].qavail = (((uint64_t) value) <<32) | val64;
+           DPRINTF("qavail set high result 0xx%x\n", mmio.vqdev->vqs[mmio.qsel].qavail);
+           break;
+           
+/* Selected queue's Used Ring address, 64 bits in two halves */
+    case VIRTIO_MMIO_QUEUE_USED_LOW:
+           val64 = mmio.vqdev->vqs[mmio.qsel].qused;
+           val64 = val64 >> 32;
+           val64 = (val64 <<32) | value;
+           mmio.vqdev->vqs[mmio.qsel].qused = val64;
+           DPRINTF("qused set low result 0xx%x\n", val64);
+           break;
+    case VIRTIO_MMIO_QUEUE_USED_HIGH:
+           val64 = (uint32_t) mmio.vqdev->vqs[mmio.qsel].qused;
+           mmio.vqdev->vqs[mmio.qsel].qused = (((uint64_t) value) <<32) | val64;
+           DPRINTF("qused set used result 0xx%x\n", mmio.vqdev->vqs[mmio.qsel].qused);
+           break;
+           
+       // for v2. 
+    case VIRTIO_MMIO_QUEUE_READY:
+           if (value) {
+                   // let's kick off the thread and see how it goes?
+                   struct virtio_threadarg *va = malloc(sizeof(*va));
+                   va->arg = &mmio.vqdev->vqs[mmio.qsel];
+                   va->arg->virtio = (void *)(va->arg->pfn * mmio.pagesize);
+                   fprintf(stderr, "START THE THREAD. pfn is 0x%x, virtio is %p\n", mmio.pagesize, va->arg->virtio);
+                   if (pthread_create(&va->arg->thread, NULL, va->arg->f, va)) {
+                           fprintf(stderr, "pth_create failed for vq %s", va->arg->name);
+                           perror("pth_create");
+                   }
+           }
+           break;
+
+    case VIRTIO_MMIO_MAGIC_VALUE:
     case VIRTIO_MMIO_VERSION:
-    case VIRTIO_MMIO_DEVICEID:
-    case VIRTIO_MMIO_VENDORID:
-    case VIRTIO_MMIO_HOSTFEATURES:
-    case VIRTIO_MMIO_QUEUENUMMAX:
-    case VIRTIO_MMIO_INTERRUPTSTATUS:
+    case VIRTIO_MMIO_DEVICE_ID:
+    case VIRTIO_MMIO_VENDOR_ID:
+//    case VIRTIO_MMIO_HOSTFEATURES:
+    case VIRTIO_MMIO_QUEUE_NUM_MAX:
+    case VIRTIO_MMIO_INTERRUPT_STATUS:
         DPRINTF("write to readonly register\n");
         break;
 
     default:
-        DPRINTF("bad register offset\n");
+        DPRINTF("bad register offset 0x%x\n", offset);
     }
-}
 
-static const MemoryRegionOps virtio_mem_ops = {
-    .read = virtio_mmio_read,
-    .write = virtio_mmio_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void virtio_mmio_update_irq(DeviceState *opaque, uint16_t vector)
-{
-    VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
-    VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
-    int level;
-
-    if (!vdev) {
-        return;
-    }
-    level = (vdev->isr != 0);
-    DPRINTF("virtio_mmio setting IRQ %d\n", level);
-    qemu_set_irq(proxy->irq, level);
-}
-
-static int virtio_mmio_load_config(DeviceState *opaque, QEMUFile *f)
-{
-    VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
-
-    proxy->host_features_sel = qemu_get_be32(f);
-    proxy->guest_features_sel = qemu_get_be32(f);
-    proxy->guest_page_shift = qemu_get_be32(f);
-    return 0;
-}
-
-static void virtio_mmio_save_config(DeviceState *opaque, QEMUFile *f)
-{
-    VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
-
-    qemu_put_be32(f, proxy->host_features_sel);
-    qemu_put_be32(f, proxy->guest_features_sel);
-    qemu_put_be32(f, proxy->guest_page_shift);
-}
-
-static void virtio_mmio_reset(DeviceState *d)
-{
-    VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
-
-    virtio_mmio_stop_ioeventfd(proxy);
-    virtio_bus_reset(&proxy->bus);
-    proxy->host_features_sel = 0;
-    proxy->guest_features_sel = 0;
-    proxy->guest_page_shift = 0;
-}
-
-static int virtio_mmio_set_guest_notifier(DeviceState *d, int n, bool assign,
-                                          bool with_irqfd)
-{
-    VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
-    VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
-    VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
-    VirtQueue *vq = virtio_get_queue(vdev, n);
-    EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
-
-    if (assign) {
-        int r = event_notifier_init(notifier, 0);
-        if (r < 0) {
-            return r;
-        }
-        virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd);
-    } else {
-        virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd);
-        event_notifier_cleanup(notifier);
-    }
-
-    if (vdc->guest_notifier_mask) {
-        vdc->guest_notifier_mask(vdev, n, !assign);
-    }
-
-    return 0;
-}
-
-static int virtio_mmio_set_guest_notifiers(DeviceState *d, int nvqs,
-                                           bool assign)
-{
-    VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
-    VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
-    /* TODO: need to check if kvm-arm supports irqfd */
-    bool with_irqfd = false;
-    int r, n;
-
-    nvqs = MIN(nvqs, VIRTIO_QUEUE_MAX);
-
-    for (n = 0; n < nvqs; n++) {
-        if (!virtio_queue_get_num(vdev, n)) {
-            break;
-        }
-
-        r = virtio_mmio_set_guest_notifier(d, n, assign, with_irqfd);
-        if (r < 0) {
-            goto assign_error;
-        }
-    }
-
-    return 0;
-
-assign_error:
-    /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */
-    assert(assign);
-    while (--n >= 0) {
-        virtio_mmio_set_guest_notifier(d, n, !assign, false);
-    }
-    return r;
-}
-
-static int virtio_mmio_set_host_notifier(DeviceState *opaque, int n,
-                                         bool assign)
-{
-    VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
-
-    /* Stop using ioeventfd for virtqueue kick if the device starts using host
-     * notifiers.  This makes it easy to avoid stepping on each others' toes.
-     */
-    proxy->ioeventfd_disabled = assign;
-    if (assign) {
-        virtio_mmio_stop_ioeventfd(proxy);
-    }
-    /* We don't need to start here: it's not needed because backend
-     * currently only stops on status change away from ok,
-     * reset, vmstop and such. If we do add code to start here,
-     * need to check vmstate, device state etc. */
-    return virtio_mmio_set_host_notifier_internal(proxy, n, assign, false);
 }
 
-/* virtio-mmio device */
+static char *modrmreg[] = {"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi"};
 
-static void virtio_mmio_realizefn(DeviceState *d, Error **errp)
+void virtio_mmio(struct vmctl *v)
 {
-    VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
-    SysBusDevice *sbd = SYS_BUS_DEVICE(d);
-
-    qbus_create_inplace(&proxy->bus, sizeof(proxy->bus), TYPE_VIRTIO_MMIO_BUS,
-                        d, NULL);
-    sysbus_init_irq(sbd, &proxy->irq);
-    memory_region_init_io(&proxy->iomem, OBJECT(d), &virtio_mem_ops, proxy,
-                          TYPE_VIRTIO_MMIO, 0x200);
-    sysbus_init_mmio(sbd, &proxy->iomem);
+       int advance = 3; /* how much to move the IP forward at the end. 3 is a good default. */
+       // All virtio accesses seem to be 32 bits.
+       // valp points to a place to get or put the value. 
+       uint32_t *valp;
+       //DPRINTF("v is %p\n", v);
+       // regp points to the register in hw_trapframe from which
+       // to load or store a result.
+       uint64_t *regp;
+
+       // Duh, which way did he go George? Which way did he go? 
+       // First hit on Google gets you there!
+       // This is the guest physical address of the access.
+       // This is nice, because if we ever go with more complete
+       // instruction decode, knowing this gpa reduces our work:
+       // we don't have to find the source address in registers,
+       // only the register holding or receiving the value.
+       uint64_t gpa = v->gpa;
+       //DPRINTF("gpa is %p\n", gpa);
+
+       // To find out what to do, we have to look at
+       // RIP. Technically, we should read RIP, walk the page tables
+       // to find the PA, and read that. But we're in the kernel, so
+       // we take a shortcut for now: read the low 30 bits and use
+       // that as the kernel PA, or our VA, and see what's
+       // there. Hokey. Works.
+       uint8_t *kva = (void *)(v->regs.tf_rip & 0x3fffffff);
+       //DPRINTF("kva is %p\n", kva);
+
+       if ((kva[0] != 0x8b) && (kva[0] != 0x89)) {
+               fprintf(stderr, "%s: can't handle instruction 0x%x\n", kva[0]);
+               return;
+       }
+
+       uint16_t ins = *(uint16_t *)kva;
+       //DPRINTF("ins is %04x\n", ins);
+       
+       int write = (kva[0] == 0x8b) ? 0 : 1;
+       if (write)
+               valp = (uint32_t *)gpa;
+
+       int mod = kva[1]>>6;
+       switch (mod) {
+               case 0: 
+               case 3:
+                       advance = 2;
+                       break;
+               case 1:
+                       advance = 3;
+                       break;
+               case 2: 
+                       advance = 6;
+                       break;
+       }
+       /* the dreaded mod/rm byte. */
+       int destreg = (ins>>11) & 7;
+       // Our primitive approach wins big here.
+       // We don't have to decode the register or the offset used
+       // in the computation; that was done by the CPU and is the gpa.
+       // All we need to know is which destination or source register it is.
+       switch (destreg) {
+       case 0:
+               regp = &v->regs.tf_rax;
+               break;
+       case 1:
+               regp = &v->regs.tf_rcx;
+               break;
+       case 2:
+               regp = &v->regs.tf_rdx;
+               break;
+       case 3:
+               regp = &v->regs.tf_rbx;
+               break;
+       case 4:
+               regp = &v->regs.tf_rsp; // uh, right.
+               break;
+       case 5:
+               regp = &v->regs.tf_rbp;
+               break;
+       case 6:
+               regp = &v->regs.tf_rsi;
+               break;
+       case 7:
+               regp = &v->regs.tf_rdi;
+               break;
+       }
+
+       if (write) {
+               virtio_mmio_write(gpa, *regp);
+               DPRINTF("Write: mov %s to %s @%p val %p\n", modrmreg[destreg], virtio_names[(uint8_t)gpa], gpa, *regp);
+       } else {
+               *regp = virtio_mmio_read(gpa);
+               DPRINTF("Read: Set %s from %s @%p to %p\n", modrmreg[destreg], virtio_names[(uint8_t)gpa], gpa, *regp);
+       }
+
+       DPRINTF("Advance rip by %d bytes to %p\n", advance, v->regs.tf_rip);
+       v->regs.tf_rip += advance;
 }
-
-static void virtio_mmio_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    dc->realize = virtio_mmio_realizefn;
-    dc->reset = virtio_mmio_reset;
-    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
-}
-
-static const TypeInfo virtio_mmio_info = {
-    .name          = TYPE_VIRTIO_MMIO,
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(VirtIOMMIOProxy),
-    .class_init    = virtio_mmio_class_init,
-};
-
-/* virtio-mmio-bus. */
-
-static void virtio_mmio_bus_class_init(ObjectClass *klass, void *data)
-{
-    BusClass *bus_class = BUS_CLASS(klass);
-    VirtioBusClass *k = VIRTIO_BUS_CLASS(klass);
-
-    k->notify = virtio_mmio_update_irq;
-    k->save_config = virtio_mmio_save_config;
-    k->load_config = virtio_mmio_load_config;
-    k->set_host_notifier = virtio_mmio_set_host_notifier;
-    k->set_guest_notifiers = virtio_mmio_set_guest_notifiers;
-    k->has_variable_vring_alignment = true;
-    bus_class->max_dev = 1;
-}
-
-static const TypeInfo virtio_mmio_bus_info = {
-    .name          = TYPE_VIRTIO_MMIO_BUS,
-    .parent        = TYPE_VIRTIO_BUS,
-    .instance_size = sizeof(VirtioBusState),
-    .class_init    = virtio_mmio_bus_class_init,
-};
-
-static void virtio_mmio_register_types(void)
-{
-    type_register_static(&virtio_mmio_bus_info);
-    type_register_static(&virtio_mmio_info);
-}
-
-type_init(virtio_mmio_register_types)
index 62cd554..ee8a9d3 100644 (file)
@@ -28,6 +28,8 @@
 #include <stdint.h>
 #include <err.h>
 #include <sys/mman.h>
+#include <parlib/uthread.h>
+#include <parlib/ros_debug.h>
 #include <vmm/virtio.h>
 
 #define BAD_RING(_vq, fmt, args...)                            \
@@ -230,7 +232,7 @@ static inline int virtqueue_add_avail(struct virtqueue *_vq,
        canary = vq->vq.num_free;
 
        if (vq->vq.num_free < total_sg) {
-               if (0) fprintf(stderr, "Can't add buf len %i - avail = %i\n",
+               if (1) fprintf(stderr, "Can't add buf len %i - avail = %i\n",
                                 total_sg, vq->vq.num_free);
                /* FIXME: for historical reasons, we force a notify here if
                 * there are outgoing parts to the buffer.  Presumably the
@@ -286,7 +288,7 @@ add_head:
        if (unlikely(vq->num_added == (1 << 16) - 1))
                virtqueue_kick(_vq);
 
-       if (0) fprintf(stderr, "Added buffer head %i to %p\n", head, vq);
+       if (1) fprintf(stderr, "Added buffer head %i to %p\n", head, vq);
        END_USE(vq);
        BUG_ON(vq->vq.num_free > canary);
        return 0;
@@ -476,7 +478,7 @@ void *virtqueue_get_buf_used(struct virtqueue *_vq, unsigned int *len)
        }
 
        if (!more_used(vq)) {
-               if (0) fprintf(stderr, "No more buffers in queue\n");
+               if (1) fprintf(stderr, "No more buffers in queue\n");
                END_USE(vq);
                return NULL;
        }
@@ -682,7 +684,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
 
        /* We assume num is a power of 2. */
        if (num & (num - 1)) {
-               if (0) fprintf(stderr, "Bad virtqueue length %u\n", num);
+               if (1) fprintf(stderr, "Bad virtqueue length %u\n", num);
                exit(1);
        }
 
@@ -854,7 +856,7 @@ int virtio_get_buf_avail_start(struct virtqueue *_vq, uint16_t *last_avail_idx,
        head = vq->vring.avail->ring[i];
 
        if (head >= vq->vring.num) {
-               if (0) fprintf(stderr, "Guest says index %u > %u is available",
+               if (1) fprintf(stderr, "Guest says index %u > %u is available",
                           head, vq->vring.num);
                return -EINVAL;
        }
@@ -868,7 +870,7 @@ int virtio_get_buf_avail_start(struct virtqueue *_vq, uint16_t *last_avail_idx,
        }
 
        if (sgp) {
-               if (0) fprintf(stderr, "entry @%d is %d long\n", head, sglen);
+               if (1) fprintf(stderr, "entry @%d is %d long\n", head, sglen);
 
                sg = calloc(sglen, sizeof(*sg));
                *sgp = sg;
@@ -965,10 +967,24 @@ unsigned int wait_for_vq_desc(struct virtqueue *_vq,
        unsigned int i, head, max;
        struct vring_desc *desc;
        uint16_t last_avail = lg_last_avail(vq);
+       int j = 0;
 
+       if (1){
+                fprintf(stderr, "out_num %p in_num %p\n", out_num, in_num);
+               fprintf(stderr, "va %p vq->vring %p\n", vq, vq->vring);
+       }
        *out_num = *in_num = 0;
        /* There's nothing available? */
+fprintf(stderr, "last_avail %d\n"); 
+       while (! vq->vring.avail) {
+               uthread_sleep(1);
+               fprintf(stderr, "last_avail %p\n", vq->vring.avail); 
+               hexdump(stderr, &(vq->vring), 96);
+       }
+               ;
+fprintf(stderr, "vq %p vq->vring.avail %p idx %d\n", vq, vq->vring.avail, vq->vring.avail);
        while (last_avail == vq->vring.avail->idx) {
+fprintf(stderr, "%d.", j++);
                //uint64_t event;
                if (virtqueue_is_broken(_vq)) {
                        return 0;
@@ -979,29 +995,35 @@ unsigned int wait_for_vq_desc(struct virtqueue *_vq,
                 * Guest about what we've used up to now.
 
                trigger_irq(vq);
+fprintf(stderr, "%d.", j++);
                 */
                /* OK, now we need to know about added descriptors. */
                vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY;
 
+fprintf(stderr, "%d.", j++);
                /*
                 * They could have slipped one in as we were doing that: make
                 * sure it's written, then check again.
                 */
                mb();
+fprintf(stderr, "%d.", j++);
                if (last_avail != vq->vring.avail->idx) {
                        vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY;
                        break;
                }
 
+fprintf(stderr, "%d.", j++);
                /* Nothing new?  Wait for eventfd to tell us they refilled. *
                if (read(vq->eventfd, &event, sizeof(event)) != sizeof(event))
                        errx(1, "Event read failed?");
                */
                /* We don't need to be notified again. */
                vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY;
+fprintf(stderr, "%d.", j++);
        }
 
        /* Check it isn't doing very strange things with descriptor numbers. */
+fprintf(stderr, "out of loop %d.", j++);
        if ((uint16_t)(vq->vring.avail->idx - last_avail) > vq->vring.num)
                errx(1, "Guest moved used index from %u to %u",
                     last_avail, vq->vring.avail->idx);
@@ -1012,6 +1034,7 @@ unsigned int wait_for_vq_desc(struct virtqueue *_vq,
         */
        rmb();
 
+fprintf(stderr, "out of loop %d.", j++);
        /*
         * Grab the next descriptor number they're advertising, and increment
         * the index we've seen.
@@ -1019,13 +1042,16 @@ unsigned int wait_for_vq_desc(struct virtqueue *_vq,
        head = vq->vring.avail->ring[last_avail % vq->vring.num];
        lg_last_avail(vq)++;
 
+fprintf(stderr, "out of loop %d.", j++);
        /* If their number is silly, that's a fatal mistake. */
        if (head >= vq->vring.num)
                errx(1, "Guest says index %u is available", head);
 
+fprintf(stderr, "out of loop %d.", j++);
        /* When we start there are none of either input nor output. */
        *out_num = *in_num = 0;
 
+fprintf(stderr, "out of loop %d.", j++);
        max = vq->vring.num;
        desc = vq->vring.desc;
        i = head;
@@ -1050,7 +1076,10 @@ unsigned int wait_for_vq_desc(struct virtqueue *_vq,
                i = 0;
        }
 
+
+fprintf(stderr, "out of loop %d.", j++);
        do {
+fprintf(stderr, "do loop %d.", j++);
                /* Grab the first descriptor, and check it's OK. */
                iov[*out_num + *in_num].length = desc[i].len;
                iov[*out_num + *in_num].v
@@ -1073,6 +1102,7 @@ unsigned int wait_for_vq_desc(struct virtqueue *_vq,
                        errx(1, "Looped descriptor");
        } while ((i = next_desc(desc, i, max)) != max);
 
+fprintf(stderr, "RETURN head %d\n", head);
        return head;
 }
 
index 05ea966..fd6d9d2 100644 (file)
@@ -114,7 +114,8 @@ void showstatus(FILE *f, struct vmctl *v)
        char *reason = "UNKNOWN";
        if (v->shutdown < ARRAY_SIZE(vmxexit) && vmxexit[v->shutdown])
                reason = vmxexit[v->shutdown];
-       fprintf(f, "Shutdown: core %d, %s due to %s(0x%x); ret code 0x%x", v->core, when, reason, v->shutdown, v->ret_code);
+       fprintf(f, "Shutdown: core %d, %s due to %s(0x%x); ret code 0x%x\n", v->core, when, reason, v->shutdown, v->ret_code);
+       fprintf(f, "  gva %p gpa %p cr3 %p\n", (void *)v->gva, (void *)v->gpa, (void *)v->cr3);
 
        fprintf(f, "  rax  0x%016lx\n",           v->regs.tf_rax);
        fprintf(f, "  rbx  0x%016lx\n",           v->regs.tf_rbx);