We're finding more undocumented bits. So the bit set test is failing.
[akaros.git] / tests / vmm / vmrunkernel.c
1 #include <stdio.h> 
2 #include <pthread.h>
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <fcntl.h>
6 #include <parlib/arch/arch.h>
7 #include <parlib/ros_debug.h>
8 #include <unistd.h>
9 #include <errno.h>
10 #include <dirent.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <ros/syscall.h>
14 #include <sys/mman.h>
15 #include <vmm/coreboot_tables.h>
16 #include <ros/vmm.h>
17 #include <parlib/uthread.h>
18 #include <vmm/virtio.h>
19 #include <vmm/virtio_mmio.h>
20 #include <vmm/virtio_ids.h>
21 #include <vmm/virtio_config.h>
22
23 /* this test will run the "kernel" in the negative address space. We hope. */
24 int *mmap_blob;
25 unsigned long long stack[1024];
26 volatile int shared = 0;
27 volatile int quit = 0;
28 int mcp = 1;
29
30 #define MiB 0x100000u
31 #define GiB (1u<<30)
32 #define GKERNBASE (16*MiB)
33 #define KERNSIZE (128*MiB+GKERNBASE)
34 uint8_t _kernel[KERNSIZE];
35
36 unsigned long long *p512, *p1, *p2m;
37
38 void **my_retvals;
39 int nr_threads = 3;
40 char *line, *consline, *outline;
41 struct scatterlist iov[32];
42 unsigned int inlen, outlen, conslen;
43 int debug = 0;
44 /* unlike Linux, this shared struct is for both host and guest. */
45 //      struct virtqueue *constoguest = 
46 //              vring_new_virtqueue(0, 512, 8192, 0, inpages, NULL, NULL, "test");
47 volatile int gaveit = 0, gotitback = 0;
48 struct scatterlist out[] = { {NULL, sizeof(outline)}, };
49 struct scatterlist in[] = { {NULL, sizeof(line)}, };
50 uint64_t virtio_mmio_base = 0x100000000;
51
52 void *consout(void *arg)
53 {
54         struct virtio_threadarg *a = arg;
55         struct virtqueue *v = a->arg->virtio;
56         fprintf(stderr, "talk thread ..\n");
57         uint16_t head;
58         uint32_t vv;
59         int i;
60         int num;
61         if (debug) {
62                 printf("----------------------- TT a %p\n", a);
63                 printf("talk thread ttargs %x v %x\n", a, v);
64         }
65         
66         for(num = 0;;num++) {
67                 /* host: use any buffers we should have been sent. */
68                 head = wait_for_vq_desc(v, iov, &outlen, &inlen);
69                 if (debug)
70                         printf("CCC: vq desc head %d, gaveit %d gotitback %d\n", head, gaveit, gotitback);
71                 for(i = 0; debug && i < outlen + inlen; i++)
72                         printf("CCC: v[%d/%d] v %p len %d\n", i, outlen + inlen, iov[i].v, iov[i].length);
73                 /* host: if we got an output buffer, just output it. */
74                 for(i = 0; i < outlen; i++) {
75                         num++;
76                         int j;
77                         for (j = 0; j < iov[i].length; j++)
78                                 printf("%c", ((char *)iov[i].v)[j]);
79                 }
80                 
81                 if (debug)
82                         printf("CCC: outlen is %d; inlen is %d\n", outlen, inlen);
83                 /* host: fill in the writeable buffers. */
84                 /* why we're getting these I don't know. */
85                 for (i = outlen; i < outlen + inlen; i++) {
86                         if (debug) fprintf(stderr, "CCC: send back empty writeable");
87                         iov[i].length = 0;
88                 }
89                 if (debug) printf("CCC: call add_used\n");
90                 /* host: now ack that we used them all. */
91                 add_used(v, head, outlen+inlen);
92                 if (debug) printf("CCC: DONE call add_used\n");
93         }
94         fprintf(stderr, "All done\n");
95         return NULL;
96 }
97
98 void *consin(void *arg)
99 {
100
101         fprintf(stderr, "consinput; nothing to do\n");
102 #if 0
103         struct ttargs *a = arg;
104         void *v = a->virtio;
105         fprintf(stderr, "talk thread ..\n");
106         uint16_t head;
107         uint32_t vv;
108         int i;
109         int num;
110         printf("Sleep 15 seconds\n");
111         uthread_sleep(15);
112         printf("----------------------- TT a %p\n", a);
113         printf("talk thread ttargs %x v %x\n", a, v);
114         
115         if (debug) printf("Spin on console being read, print num queues, halt\n");
116         while ((vv = read32(v+VIRTIO_MMIO_DRIVER_FEATURES)) == 0) {
117                 printf("no ready ... \n");
118                 if (debug) {
119                         dumpvirtio_mmio(stdout, v);
120                 }
121                 printf("sleep 1 second\n");
122                 uthread_sleep(1);
123         }
124         if (debug)printf("vv %x, set selector %x\n", vv, read32(v + VIRTIO_MMIO_DRIVER_FEATURES_SEL));
125         if (debug) printf("loop forever");
126         while (! quit)
127                 ;
128         for(num = 0;;num++) {
129                 /* host: use any buffers we should have been sent. */
130                 head = wait_for_vq_desc(guesttocons, iov, &outlen, &inlen);
131                 if (debug)
132                         printf("vq desc head %d, gaveit %d gotitback %d\n", head, gaveit, gotitback);
133                 for(i = 0; debug && i < outlen + inlen; i++)
134                         printf("v[%d/%d] v %p len %d\n", i, outlen + inlen, iov[i].v, iov[i].length);
135                 /* host: if we got an output buffer, just output it. */
136                 for(i = 0; i < outlen; i++) {
137                         num++;
138                         printf("Host:%s:\n", (char *)iov[i].v);
139                 }
140                 
141                 if (debug)
142                         printf("outlen is %d; inlen is %d\n", outlen, inlen);
143                 /* host: fill in the writeable buffers. */
144                 for (i = outlen; i < outlen + inlen; i++) {
145                         /* host: read a line. */
146                         memset(consline, 0, 128);
147                         if (1) {
148                                 if (fgets(consline, 4096-256, stdin) == NULL) {
149                                         exit(0);
150                                 } 
151                                 if (debug) printf("GOT A LINE:%s:\n", consline);
152                         } else {
153                                 sprintf(consline, "hi there. %d\n", i);
154                         }
155                         memmove(iov[i].v, consline, strlen(consline)+ 1);
156                         iov[i].length = strlen(consline) + 1;
157                 }
158                 if (debug) printf("call add_used\n");
159                 /* host: now ack that we used them all. */
160                 add_used(guesttocons, head, outlen+inlen);
161                 if (debug) printf("DONE call add_used\n");
162         }
163 #endif
164         fprintf(stderr, "All done\n");
165         return NULL;
166 }
167
168 static struct vqdev vqdev= {
169 name: "console",
170 dev: VIRTIO_ID_CONSOLE,
171 device_features: 0, /* Can't do it: linux console device does not support it. VIRTIO_F_VERSION_1*/
172 numvqs: 2,
173 vqs: {
174                 {name: "consin", maxqnum: 64, f: &consin, arg: (void *)0},
175                 {name: "consout", maxqnum: 64, f: consout, arg: (void *)0},
176         }
177 };
178
179 int main(int argc, char **argv)
180 {
181         uint64_t virtiobase = 0x100000000ULL;
182         struct vmctl vmctl;
183         int amt;
184         int vmmflags = VMM_VMCALL_PRINTF;
185         uint64_t entry = 0x1000000, kerneladdress = 0x1000000;
186         int nr_gpcs = 1;
187         int fd = open("#c/vmctl", O_RDWR), ret;
188         void * x;
189         int kfd = -1;
190         static char cmd[512];
191         void *coreboot_tables = (void *) 0x1165000;
192
193         // mmap is not working for us at present.
194         if ((uint64_t)_kernel > GKERNBASE) {
195                 printf("kernel array @%p is above , GKERNBASE@%p sucks\n", _kernel, GKERNBASE);
196                 exit(1);
197         }
198         memset(_kernel, 0, sizeof(_kernel));
199
200         if (fd < 0) {
201                 perror("#cons/sysctl");
202                 exit(1);
203         }
204         argc--,argv++;
205         // switches ...
206         // Sorry, I don't much like the gnu opt parsing code.
207         while (1) {
208                 if (*argv[0] != '-')
209                         break;
210                 switch(argv[0][1]) {
211                 case 'n':
212                         vmmflags &= ~VMM_VMCALL_PRINTF;
213                         break;
214                 default:
215                         printf("BMAFR\n");
216                         break;
217                 }
218                 argc--,argv++;
219         }
220         if (argc < 1) {
221                 fprintf(stderr, "Usage: %s vmimage [-n (no vmcall printf)] [coreboot_tables [loadaddress [entrypoint]]]\n", argv[0]);
222                 exit(1);
223         }
224         if (argc > 1)
225                 coreboot_tables = (void *) strtoull(argv[1], 0, 0);
226         if (argc > 2)
227                 kerneladdress = strtoull(argv[2], 0, 0);
228         if (argc > 3)
229                 entry = strtoull(argv[3], 0, 0);
230         kfd = open(argv[0], O_RDONLY);
231         if (kfd < 0) {
232                 perror(argv[0]);
233                 exit(1);
234         }
235         // read in the kernel.
236         x = (void *)kerneladdress;
237         for(;;) {
238                 amt = read(kfd, x, 1048576);
239                 if (amt < 0) {
240                         perror("read");
241                         exit(1);
242                 }
243                 if (amt == 0) {
244                         break;
245                 }
246                 x += amt;
247         }
248         fprintf(stderr, "Read in %d bytes\n", x-kerneladdress);
249
250         fprintf(stderr, "Run with %d cores and vmmflags 0x%x\n", nr_gpcs, vmmflags);
251         if (ros_syscall(SYS_setup_vmm, nr_gpcs, vmmflags, 0, 0, 0, 0) != nr_gpcs) {
252                 perror("Guest pcore setup failed");
253                 exit(1);
254         }
255         /* blob that is faulted in from the EPT first.  we need this to be in low
256          * memory (not above the normal mmap_break), so the EPT can look it up.
257          * Note that we won't get 4096.  The min is 1MB now, and ld is there. */
258         mmap_blob = mmap((int*)4096, PGSIZE, PROT_READ | PROT_WRITE,
259                          MAP_ANONYMOUS, -1, 0);
260         if (mmap_blob == MAP_FAILED) {
261                 perror("Unable to mmap");
262                 exit(1);
263         }
264
265         mcp = 1;
266         if (mcp) {
267                 my_retvals = malloc(sizeof(void*) * nr_threads);
268                 if (!my_retvals)
269                         perror("Init threads/malloc");
270
271                 pthread_can_vcore_request(FALSE);       /* 2LS won't manage vcores */
272                 pthread_need_tls(FALSE);
273                 pthread_mcp_init();                                     /* gives us one vcore */
274                 vcore_request(nr_threads - 1);          /* ghetto incremental interface */
275                 for (int i = 0; i < nr_threads; i++) {
276                         x = __procinfo.vcoremap;
277                         printf("%p\n", __procinfo.vcoremap);
278                         printf("Vcore %d mapped to pcore %d\n", i,
279                                 __procinfo.vcoremap[i].pcoreid);
280                 }
281         }
282
283         ret = syscall(33, 1);
284         if (ret < 0) {
285                 perror("vm setup");
286                 exit(1);
287         }
288         ret = posix_memalign((void **)&p512, 4096, 3*4096);
289         printf("memalign is %p\n", p512);
290         if (ret) {
291                 perror("ptp alloc");
292                 exit(1);
293         }
294         p1 = &p512[512];
295         p2m = &p512[1024];
296         uint64_t kernbase = 0; //0xffffffff80000000;
297         uint64_t highkernbase = 0xffffffff80000000;
298         p512[PML4(kernbase)] = (unsigned long long)p1 | 7;
299         p1[PML3(kernbase)] = /*0x87; */(unsigned long long)p2m | 7;
300         p512[PML4(highkernbase)] = (unsigned long long)p1 | 7;
301         p1[PML3(highkernbase)] = /*0x87; */(unsigned long long)p2m | 7;
302 #define _2MiB (0x200000)
303         int i;
304         for (i = 0; i < 512; i++) {
305                 p2m[PML2(kernbase + i * _2MiB)] = 0x87 | i * _2MiB;
306         }
307
308         kernbase >>= (0+12);
309         kernbase <<= (0 + 12);
310         uint8_t *kernel = (void *)GKERNBASE;
311         //write_coreboot_table(coreboot_tables, ((void *)VIRTIOBASE) /*kernel*/, KERNSIZE + 1048576);
312         hexdump(stdout, coreboot_tables, 512);
313         printf("kernbase for pml4 is 0x%llx and entry is %llx\n", kernbase, entry);
314         printf("p512 %p p512[0] is 0x%lx p1 %p p1[0] is 0x%x\n", p512, p512[0], p1, p1[0]);
315         vmctl.command = REG_RSP_RIP_CR3;
316         vmctl.cr3 = (uint64_t) p512;
317         vmctl.regs.tf_rip = entry;
318         vmctl.regs.tf_rsp = (uint64_t) &stack[1024];
319         if (mcp) {
320                 /* set up virtio bits, which depend on threads being enabled. */
321                 register_virtio_mmio(&vqdev, virtio_mmio_base);
322         }
323         printf("threads started\n");
324         printf("Writing command :%s:\n", cmd);
325
326         ret = write(fd, &vmctl, sizeof(vmctl));
327         if (ret != sizeof(vmctl)) {
328                 perror(cmd);
329         }
330         while (1) {
331                 void showstatus(FILE *f, struct vmctl *v);
332                 int c;
333                 vmctl.command = REG_RIP;
334                 if (debug) printf("RESUME?\n");
335                 //c = getchar();
336                 //if (c == 'q')
337                         //break;
338                 if (debug) printf("RIP %p, shutdown 0x%x\n", vmctl.regs.tf_rip, vmctl.shutdown);
339                 //showstatus(stdout, &vmctl);
340                 // this will be in a function, someday.
341                 // A rough check: is the GPA 
342                 if ((vmctl.shutdown == 5/*EXIT_REASON_EPT_VIOLATION*/) && ((vmctl.gpa & ~0xfffULL) == virtiobase)) {
343                         if (debug) printf("DO SOME VIRTIO\n");
344                         virtio_mmio(&vmctl);
345                         vmctl.shutdown = 0;
346                         vmctl.gpa = 0;
347                         vmctl.command = REG_ALL;
348                 }
349                 if (debug) printf("NOW DO A RESUME\n");
350                 ret = write(fd, &vmctl, sizeof(vmctl));
351                 if (ret != sizeof(vmctl)) {
352                         perror(cmd);
353                 }
354         }
355
356         printf("shared is %d, blob is %d\n", shared, *mmap_blob);
357
358         quit = 1;
359         /* later. 
360         for (int i = 0; i < nr_threads-1; i++) {
361                 int ret;
362                 if (pthread_join(my_threads[i], &my_retvals[i]))
363                         perror("pth_join failed");
364                 printf("%d %d\n", i, ret);
365         }
366  */
367
368         return 0;
369 }