We're finding more undocumented bits. So the bit set test is failing.
[akaros.git] / tests / vmm / vmrunkernel.c
index 461ce89..65f669e 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;
 unsigned long long stack[1024];
 volatile int shared = 0;
+volatile int quit = 0;
 int mcp = 1;
-#define V(x, t) (*((volatile t*)(x)))
 
-uint8_t _kernel[64*1048576];
+#define MiB 0x100000u
+#define GiB (1u<<30)
+#define GKERNBASE (16*MiB)
+#define KERNSIZE (128*MiB+GKERNBASE)
+uint8_t _kernel[KERNSIZE];
 
 unsigned long long *p512, *p1, *p2m;
 
-void *talk_thread(void *arg)
+void **my_retvals;
+int nr_threads = 3;
+char *line, *consline, *outline;
+struct scatterlist iov[32];
+unsigned int inlen, outlen, conslen;
+int debug = 0;
+/* 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 scatterlist out[] = { {NULL, sizeof(outline)}, };
+struct scatterlist in[] = { {NULL, sizeof(line)}, };
+uint64_t virtio_mmio_base = 0x100000000;
+
+void *consout(void *arg)
 {
-       printf("talk thread ..\n");
-       for(; V(&shared, int) < 32; ){
-               if (V(&shared, int) & 1) {
-                       printf("shared %d\n", V(&shared, int) );
-                       V(&shared, int) = V(&shared, int) + 1;
+       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;
+       if (debug) {
+               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("CCC: vq desc head %d, gaveit %d gotitback %d\n", head, gaveit, gotitback);
+               for(i = 0; debug && i < outlen + inlen; i++)
+                       printf("CCC: 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++;
+                       int j;
+                       for (j = 0; j < iov[i].length; j++)
+                               printf("%c", ((char *)iov[i].v)[j]);
+               }
+               
+               if (debug)
+                       printf("CCC: 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, "CCC: send back empty writeable");
+                       iov[i].length = 0;
                }
-               cpu_relax();
+               if (debug) printf("CCC: call add_used\n");
+               /* host: now ack that we used them all. */
+               add_used(v, head, outlen+inlen);
+               if (debug) printf("CCC: DONE call add_used\n");
        }
-       printf("All done, read %d\n", *mmap_blob);
+       fprintf(stderr, "All done\n");
        return NULL;
 }
 
-pthread_t *my_threads;
-void **my_retvals;
-int nr_threads = 2;
+void *consin(void *arg)
+{
+
+       fprintf(stderr, "consinput; nothing to do\n");
+#if 0
+       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");
+       }
+#endif
+       fprintf(stderr, "All done\n");
+       return NULL;
+}
+
+static struct vqdev vqdev= {
+name: "console",
+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: "consout", maxqnum: 64, f: consout, arg: (void *)0},
+       }
+};
 
 int main(int argc, char **argv)
 {
+       uint64_t virtiobase = 0x100000000ULL;
+       struct vmctl vmctl;
        int amt;
        int vmmflags = VMM_VMCALL_PRINTF;
-       uint64_t entry = 0x101000c, kerneladdress = 0x1010000;
+       uint64_t entry = 0x1000000, kerneladdress = 0x1000000;
        int nr_gpcs = 1;
-       int fd = open("#c/sysctl", O_RDWR), ret;
+       int fd = open("#c/vmctl", O_RDWR), ret;
        void * x;
        int kfd = -1;
        static char cmd[512];
-       void *coreboot_tables;
-       /* kernel has to be in the range 16M to 64M for now. */
+       void *coreboot_tables = (void *) 0x1165000;
+
        // mmap is not working for us at present.
-       if ((uint64_t)_kernel > 16*1048576) {
-               printf("kernel array is above 16M, sucks\n");
+       if ((uint64_t)_kernel > GKERNBASE) {
+               printf("kernel array @%p is above , GKERNBASE@%p sucks\n", _kernel, GKERNBASE);
                exit(1);
        }
        memset(_kernel, 0, sizeof(_kernel));
 
        if (fd < 0) {
-               perror("#c/sysctl");
+               perror("#cons/sysctl");
                exit(1);
        }
        argc--,argv++;
        // switches ...
+       // Sorry, I don't much like the gnu opt parsing code.
        while (1) {
                if (*argv[0] != '-')
                        break;
@@ -83,10 +218,11 @@ int main(int argc, char **argv)
                argc--,argv++;
        }
        if (argc < 1) {
-               fprintf(stderr, "Usage: %s vmimage coreboot_tables [loadaddress [entrypoint]]\n", argv[0]);
+               fprintf(stderr, "Usage: %s vmimage [-n (no vmcall printf)] [coreboot_tables [loadaddress [entrypoint]]]\n", argv[0]);
                exit(1);
        }
-       coreboot_tables = (void *) strtoull(argv[1], 0, 0);
+       if (argc > 1)
+               coreboot_tables = (void *) strtoull(argv[1], 0, 0);
        if (argc > 2)
                kerneladdress = strtoull(argv[2], 0, 0);
        if (argc > 3)
@@ -126,11 +262,10 @@ int main(int argc, char **argv)
                exit(1);
        }
 
-       mcp = 1; //argc - 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))
+               if (!my_retvals)
                        perror("Init threads/malloc");
 
                pthread_can_vcore_request(FALSE);       /* 2LS won't manage vcores */
@@ -145,22 +280,6 @@ int main(int argc, char **argv)
                }
        }
 
-       if (mcp) {
-               if (pthread_create(&my_threads[0], NULL, &talk_thread, NULL))
-                       perror("pth_create failed");
-//             if (pthread_create(&my_threads[1], NULL, &fail, NULL))
-//                     perror("pth_create failed");
-       }
-       printf("threads started\n");
-
-       if (0) 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);
-       }
-       
-
        ret = syscall(33, 1);
        if (ret < 0) {
                perror("vm setup");
@@ -175,8 +294,11 @@ int main(int argc, char **argv)
        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++) {
@@ -185,30 +307,63 @@ int main(int argc, char **argv)
 
        kernbase >>= (0+12);
        kernbase <<= (0 + 12);
-       uint8_t *kernel = (void *)(16*1048576);
-       write_coreboot_table(coreboot_tables, kernel, 16*1048576);
-       hexdump(stdout, coreboot_tables, 128);
+       uint8_t *kernel = (void *)GKERNBASE;
+       //write_coreboot_table(coreboot_tables, ((void *)VIRTIOBASE) /*kernel*/, KERNSIZE + 1048576);
+       hexdump(stdout, coreboot_tables, 512);
        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]);
-       sprintf(cmd, "V 0x%llx 0x%llx 0x%llx", entry, (unsigned long long) &stack[1024], (unsigned long long) p512);
+       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) {
+               /* 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);
-       ret = write(fd, cmd, strlen(cmd));
-       if (ret != strlen(cmd)) {
+
+       ret = write(fd, &vmctl, sizeof(vmctl));
+       if (ret != sizeof(vmctl)) {
                perror(cmd);
        }
-       sprintf(cmd, "V 0 0 0");
        while (1) {
+               void showstatus(FILE *f, struct vmctl *v);
                int c;
-               printf("RESUME?\n");
-               c = getchar();
-               if (c == 'q')
-                       break;
-               ret = write(fd, cmd, strlen(cmd));
-               if (ret != strlen(cmd)) {
+               vmctl.command = REG_RIP;
+               if (debug) printf("RESUME?\n");
+               //c = getchar();
+               //if (c == 'q')
+                       //break;
+               if (debug) 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)) {
+                       if (debug) printf("DO SOME VIRTIO\n");
+                       virtio_mmio(&vmctl);
+                       vmctl.shutdown = 0;
+                       vmctl.gpa = 0;
+                       vmctl.command = REG_ALL;
+               }
+               if (debug) printf("NOW DO A RESUME\n");
+               ret = write(fd, &vmctl, sizeof(vmctl));
+               if (ret != sizeof(vmctl)) {
                        perror(cmd);
                }
        }
+
        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;
 }