Actual working output now from virtio ring. Time for lots and lots of cleanup.
[akaros.git] / user / vmm / virtio-mmio.c
1 /*
2  * Virtio MMIO bindings
3  *
4  * Copyright (c) 2011 Linaro Limited
5  *
6  * Author:
7  *  Peter Maydell <peter.maydell@linaro.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include <stdio.h>
23 #include <sys/types.h>
24 #include <pthread.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <parlib/arch/arch.h>
28 #include <parlib/ros_debug.h>
29 #include <unistd.h>
30 #include <errno.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/uio.h>
34 #include <stdint.h>
35 #include <err.h>
36 #include <sys/mman.h>
37 #include <ros/vmm.h>
38 #include <vmm/virtio.h>
39 #include <vmm/virtio_mmio.h>
40 #include <vmm/virtio_ids.h>
41 #include <vmm/virtio_config.h>
42
43 int debug_virtio_mmio = 1;
44 #define DPRINTF(fmt, ...) \
45         if (debug_virtio_mmio) { printf("virtio_mmio: " fmt , ## __VA_ARGS__); }
46
47
48 #define VIRT_MAGIC 0x74726976 /* 'virt' */
49 /* version is a real mess. A real mess. I don't understand it at all. Let's stick with 1, which sucks, 
50  * instead of 2, which seems to be not supported right. I think.
51  */
52 #define VIRT_VERSION 1
53 #define VIRT_VENDOR 0x554D4551 /* 'QEMU' */
54
55
56 typedef struct {
57         int state; // not used yet. */
58         uint64_t bar;
59         uint32_t status;
60         int qsel; // queue we are on.
61         int pagesize;
62         int page_shift;
63         int device_features_word; // if this is 1, use the high 32 bits. 
64         int driver_features_word;
65         struct vqdev *vqdev;
66 } mmiostate;
67
68 static mmiostate mmio;
69
70 void register_virtio_mmio(struct vqdev *vqdev, uint64_t virtio_base)
71 {
72         mmio.bar = virtio_base;
73         mmio.vqdev = vqdev;
74 }
75
76 static uint32_t virtio_mmio_read(uint64_t gpa);
77 char *virtio_names[] = {
78         [VIRTIO_MMIO_MAGIC_VALUE] "VIRTIO_MMIO_MAGIC_VALUE",
79         [VIRTIO_MMIO_VERSION] "VIRTIO_MMIO_VERSION",
80         [VIRTIO_MMIO_DEVICE_ID] "VIRTIO_MMIO_DEVICE_ID",
81         [VIRTIO_MMIO_VENDOR_ID] "VIRTIO_MMIO_VENDOR_ID",
82         [VIRTIO_MMIO_DEVICE_FEATURES] "VIRTIO_MMIO_DEVICE_FEATURES",
83         [VIRTIO_MMIO_DEVICE_FEATURES_SEL] "VIRTIO_MMIO_DEVICE_FEATURES_SEL",
84         [VIRTIO_MMIO_DRIVER_FEATURES] "VIRTIO_MMIO_DRIVER_FEATURES",
85         [VIRTIO_MMIO_DRIVER_FEATURES_SEL] "VIRTIO_MMIO_DRIVER_FEATURES_SEL",
86         [VIRTIO_MMIO_GUEST_PAGE_SIZE] "VIRTIO_MMIO_GUEST_PAGE_SIZE",
87         [VIRTIO_MMIO_QUEUE_SEL] "VIRTIO_MMIO_QUEUE_SEL",
88         [VIRTIO_MMIO_QUEUE_NUM_MAX] "VIRTIO_MMIO_QUEUE_NUM_MAX",
89         [VIRTIO_MMIO_QUEUE_NUM] "VIRTIO_MMIO_QUEUE_NUM",
90         [VIRTIO_MMIO_QUEUE_ALIGN] "VIRTIO_MMIO_QUEUE_ALIGN",
91         [VIRTIO_MMIO_QUEUE_PFN] "VIRTIO_MMIO_QUEUE_PFN",
92         [VIRTIO_MMIO_QUEUE_READY] "VIRTIO_MMIO_QUEUE_READY",
93         [VIRTIO_MMIO_QUEUE_NOTIFY] "VIRTIO_MMIO_QUEUE_NOTIFY",
94         [VIRTIO_MMIO_INTERRUPT_STATUS] "VIRTIO_MMIO_INTERRUPT_STATUS",
95         [VIRTIO_MMIO_INTERRUPT_ACK] "VIRTIO_MMIO_INTERRUPT_ACK",
96         [VIRTIO_MMIO_STATUS] "VIRTIO_MMIO_STATUS",
97         [VIRTIO_MMIO_QUEUE_DESC_LOW] "VIRTIO_MMIO_QUEUE_DESC_LOW",
98         [VIRTIO_MMIO_QUEUE_DESC_HIGH] "VIRTIO_MMIO_QUEUE_DESC_HIGH",
99         [VIRTIO_MMIO_QUEUE_AVAIL_LOW] "VIRTIO_MMIO_QUEUE_AVAIL_LOW",
100         [VIRTIO_MMIO_QUEUE_AVAIL_HIGH] "VIRTIO_MMIO_QUEUE_AVAIL_HIGH",
101         [VIRTIO_MMIO_QUEUE_USED_LOW] "VIRTIO_MMIO_QUEUE_USED_LOW",
102         [VIRTIO_MMIO_QUEUE_USED_HIGH] "VIRTIO_MMIO_QUEUE_USED_HIGH",
103         [VIRTIO_MMIO_CONFIG_GENERATION] "VIRTIO_MMIO_CONFIG_GENERATION",
104 };
105
106 /* We're going to attempt to make mmio stateless, since the real machine is in
107  * the guest kernel. From what we know so far, all IO to the mmio space is 32 bits.
108  */
109 static uint32_t virtio_mmio_read(uint64_t gpa)
110 {
111
112         unsigned int offset = gpa - mmio.bar;
113         uint32_t low;
114         
115         DPRINTF("virtio_mmio_read offset %s 0x%x\n", virtio_names[offset],(int)offset);
116
117         /* If no backend is present, we treat most registers as
118          * read-as-zero, except for the magic number, version and
119          * vendor ID. This is not strictly sanctioned by the virtio
120          * spec, but it allows us to provide transports with no backend
121          * plugged in which don't confuse Linux's virtio code: the
122          * probe won't complain about the bad magic number, but the
123          * device ID of zero means no backend will claim it.
124          */
125         if (mmio.vqdev->numvqs == 0) {
126                 switch (offset) {
127                 case VIRTIO_MMIO_MAGIC_VALUE:
128                         return VIRT_MAGIC;
129                 case VIRTIO_MMIO_VERSION:
130                         return VIRT_VERSION;
131                 case VIRTIO_MMIO_VENDOR_ID:
132                         return VIRT_VENDOR;
133                 default:
134                         return 0;
135                 }
136         }
137
138
139     // WTF? Does this happen? 
140     if (offset >= VIRTIO_MMIO_CONFIG) {
141             fprintf(stderr, "Whoa. Reading past mmio config space? What gives?\n");
142             return -1;
143 #if 0
144             offset -= VIRTIO_MMIO_CONFIG;
145             switch (size) {
146             case 1:
147                     return virtio_config_readb(vdev, offset);
148             case 2:
149                     return virtio_config_readw(vdev, offset);
150             case 4:
151                     return virtio_config_readl(vdev, offset);
152             default:
153                     abort();
154             }
155 #endif
156     }
157
158 #if 0
159     if (size != 4) {
160         DPRINTF("wrong size access to register!\n");
161         return 0;
162     }
163 #endif
164 DPRINTF("FUCK 0x%x\n", offset);
165 fprintf(stderr, "FUCK2 0x%x\n", offset);
166     switch (offset) {
167     case VIRTIO_MMIO_MAGIC_VALUE:
168             return VIRT_MAGIC;
169     case VIRTIO_MMIO_VERSION:
170             return VIRT_VERSION;
171     case VIRTIO_MMIO_DEVICE_ID:
172             return mmio.vqdev->dev;
173     case VIRTIO_MMIO_VENDOR_ID:
174             return VIRT_VENDOR;
175     case VIRTIO_MMIO_DEVICE_FEATURES:
176         low = mmio.vqdev->device_features >> ((mmio.device_features_word) ? 32 : 0);
177         DPRINTF("RETURN from 0x%x 32 bits of word %s : 0x%x \n", mmio.vqdev->device_features, 
178                                 mmio.device_features_word ? "high" : "low", low);
179             return low;
180     case VIRTIO_MMIO_QUEUE_NUM_MAX:
181             DPRINTF("For q %d, qnum is %d\n", mmio.qsel, mmio.vqdev->vqs[mmio.qsel].qnum);
182             return mmio.vqdev->vqs[mmio.qsel].maxqnum;
183     case VIRTIO_MMIO_QUEUE_PFN:
184             return mmio.vqdev->vqs[mmio.qsel].pfn;
185     case VIRTIO_MMIO_INTERRUPT_STATUS:
186             return mmio.vqdev->vqs[mmio.qsel].isr;
187     case VIRTIO_MMIO_STATUS:
188             return mmio.vqdev->vqs[mmio.qsel].status;
189     case VIRTIO_MMIO_DEVICE_FEATURES_SEL:
190     case VIRTIO_MMIO_DRIVER_FEATURES:
191     case VIRTIO_MMIO_DRIVER_FEATURES_SEL:
192     case VIRTIO_MMIO_GUEST_PAGE_SIZE:
193     case VIRTIO_MMIO_QUEUE_SEL:
194     case VIRTIO_MMIO_QUEUE_NUM:
195     case VIRTIO_MMIO_QUEUE_ALIGN:
196     case VIRTIO_MMIO_QUEUE_READY:
197     case VIRTIO_MMIO_INTERRUPT_ACK:
198             fprintf(stderr, "read of write-only register@%p\n", (void *)gpa);
199         return 0;
200     default:
201             fprintf(stderr, "bad register offset@%p\n", (void *)gpa);
202         return 0;
203     }
204     return 0;
205 }
206
207 static void virtio_mmio_write(uint64_t gpa, uint32_t value)
208 {
209         uint64_t val64;
210         uint32_t low, high;
211         unsigned int offset = gpa - mmio.bar;
212         
213         DPRINTF("virtio_mmio_write offset %s 0x%x value 0x%x\n", virtio_names[offset], (int)offset, value);
214
215     if (offset >= VIRTIO_MMIO_CONFIG) {
216             fprintf(stderr, "Whoa. Writing past mmio config space? What gives?\n");
217 #if 0
218         offset -= VIRTIO_MMIO_CONFIG;
219         switch (size) {
220         case 1:
221             virtio_config_writeb(vdev, offset, value);
222             break;
223         case 2:
224             virtio_config_writew(vdev, offset, value);
225             break;
226         case 4:
227             virtio_config_writel(vdev, offset, value);
228             break;
229         default:
230             abort();
231         }
232 #endif
233         return;
234     }
235 #if 0
236     if (size != 4) {
237         DPRINTF("wrong size access to register!\n");
238         return;
239     }
240 #endif
241     switch (offset) {
242     case VIRTIO_MMIO_DEVICE_FEATURES_SEL:
243         mmio.device_features_word = value;
244         break;
245     case VIRTIO_MMIO_DEVICE_FEATURES:
246         if (mmio.device_features_word) {
247             /* changing the high word. */
248             low = mmio.vqdev->device_features;
249             high = value;
250         } else {
251             /* changing the low word. */
252             high = (mmio.vqdev->device_features >> 32);
253             low = value;
254         }
255         mmio.vqdev->device_features = ((uint64_t)high << 32) | low;
256         DPRINTF("Set VIRTIO_MMIO_DEVICE_FEATURES to %p\n", mmio.vqdev->device_features);
257         break;
258     case VIRTIO_MMIO_DRIVER_FEATURES:
259         if (mmio.driver_features_word) {
260             /* changing the high word. */
261             low = mmio.vqdev->driver_features;
262             high = value;
263         } else {
264             /* changing the low word. */
265             high = (mmio.vqdev->driver_features >> 32);
266             low = value;
267         }
268         mmio.vqdev->driver_features = ((uint64_t)high << 32) | low;
269         DPRINTF("Set VIRTIO_MMIO_DRIVER_FEATURES to %p\n", mmio.vqdev->driver_features);
270         break;
271     case VIRTIO_MMIO_DRIVER_FEATURES_SEL:
272             mmio.driver_features_word = value;
273         break;
274
275     case VIRTIO_MMIO_GUEST_PAGE_SIZE:
276             mmio.pagesize = value;
277             DPRINTF("guest page size %d bytes\n", mmio.pagesize);
278         break;
279     case VIRTIO_MMIO_QUEUE_SEL:
280             /* don't check it here. Check it on use. Or maybe check it here. Who knows. */
281             if (value < mmio.vqdev->numvqs)
282                     mmio.qsel = value;
283             else
284                     mmio.qsel = -1;
285             break;
286     case VIRTIO_MMIO_QUEUE_NUM:
287         mmio.vqdev->vqs[mmio.qsel].qnum = value;
288         break;
289     case VIRTIO_MMIO_QUEUE_ALIGN:
290         mmio.vqdev->vqs[mmio.qsel].qalign = value;
291         break;
292     case VIRTIO_MMIO_QUEUE_PFN:
293         // failure of vision: they used 32 bit numbers. Geez.
294         // v2 is better, we'll do v1 for now.
295         mmio.vqdev->vqs[mmio.qsel].pfn = value;
296                     // let's kick off the thread and see how it goes?
297                     struct virtio_threadarg *va = malloc(sizeof(*va));
298                     va->arg = &mmio.vqdev->vqs[mmio.qsel];
299
300                     va->arg->virtio = vring_new_virtqueue(mmio.qsel, 
301                                                           mmio.vqdev->vqs[mmio.qsel].qnum,
302                                                           mmio.vqdev->vqs[mmio.qsel].qalign,
303                                                           false, // weak_barriers
304                                                           mmio.vqdev->vqs[mmio.qsel].pfn * mmio.vqdev->vqs[mmio.qsel].qalign,
305                                                           NULL, NULL, /* callbacks */
306                                                           mmio.vqdev->vqs[mmio.qsel].name);
307                     fprintf(stderr, "START THE THREAD. pfn is 0x%x, virtio is %p\n", mmio.pagesize, va->arg->virtio);
308                     if (pthread_create(&va->arg->thread, NULL, va->arg->f, va)) {
309                             fprintf(stderr, "pth_create failed for vq %s", va->arg->name);
310                             perror("pth_create");
311                     }
312         break;
313     case VIRTIO_MMIO_QUEUE_NOTIFY:
314             if (value < mmio.vqdev->numvqs) {
315                     mmio.qsel = value;
316             }
317         break;
318     case VIRTIO_MMIO_INTERRUPT_ACK:
319         //vdev->isr &= ~value;
320         //virtio_update_irq(vdev);
321         break;
322     case VIRTIO_MMIO_STATUS:
323         if (!(value & VIRTIO_CONFIG_S_DRIVER_OK)) {
324             printf("VIRTIO_MMIO_STATUS write: NOT OK! 0x%x\n", value);
325         }
326
327         mmio.status |= value & 0xff;
328
329         if (value & VIRTIO_CONFIG_S_DRIVER_OK) {
330             printf("VIRTIO_MMIO_STATUS write: OK! 0x%x\n", value);
331         }
332
333         break;
334     case VIRTIO_MMIO_QUEUE_DESC_LOW:
335             val64 = mmio.vqdev->vqs[mmio.qsel].qdesc;
336             val64 = val64 >> 32;
337             val64 = (val64 <<32) | value;
338             mmio.vqdev->vqs[mmio.qsel].qdesc = val64;
339             DPRINTF("qdesc set low result 0xx%x\n", val64);
340             break;
341             
342     case VIRTIO_MMIO_QUEUE_DESC_HIGH:
343             val64 = (uint32_t) mmio.vqdev->vqs[mmio.qsel].qdesc;
344             mmio.vqdev->vqs[mmio.qsel].qdesc = (((uint64_t) value) <<32) | val64;
345             DPRINTF("qdesc set high result 0xx%x\n", mmio.vqdev->vqs[mmio.qsel].qdesc);
346             break;
347             
348 /* Selected queue's Available Ring address, 64 bits in two halves */
349     case VIRTIO_MMIO_QUEUE_AVAIL_LOW:
350             val64 = mmio.vqdev->vqs[mmio.qsel].qavail;
351             val64 = val64 >> 32;
352             val64 = (val64 <<32) | value;
353             mmio.vqdev->vqs[mmio.qsel].qavail = val64;
354             DPRINTF("qavail set low result 0xx%x\n", val64);
355             break;
356     case VIRTIO_MMIO_QUEUE_AVAIL_HIGH:
357             val64 = (uint32_t) mmio.vqdev->vqs[mmio.qsel].qavail;
358             mmio.vqdev->vqs[mmio.qsel].qavail = (((uint64_t) value) <<32) | val64;
359             DPRINTF("qavail set high result 0xx%x\n", mmio.vqdev->vqs[mmio.qsel].qavail);
360             break;
361             
362 /* Selected queue's Used Ring address, 64 bits in two halves */
363     case VIRTIO_MMIO_QUEUE_USED_LOW:
364             val64 = mmio.vqdev->vqs[mmio.qsel].qused;
365             val64 = val64 >> 32;
366             val64 = (val64 <<32) | value;
367             mmio.vqdev->vqs[mmio.qsel].qused = val64;
368             DPRINTF("qused set low result 0xx%x\n", val64);
369             break;
370     case VIRTIO_MMIO_QUEUE_USED_HIGH:
371             val64 = (uint32_t) mmio.vqdev->vqs[mmio.qsel].qused;
372             mmio.vqdev->vqs[mmio.qsel].qused = (((uint64_t) value) <<32) | val64;
373             DPRINTF("qused set used result 0xx%x\n", mmio.vqdev->vqs[mmio.qsel].qused);
374             break;
375             
376         // for v2. 
377     case VIRTIO_MMIO_QUEUE_READY:
378             if (value) {
379                     // let's kick off the thread and see how it goes?
380                     struct virtio_threadarg *va = malloc(sizeof(*va));
381                     va->arg = &mmio.vqdev->vqs[mmio.qsel];
382                     va->arg->virtio = (void *)(va->arg->pfn * mmio.pagesize);
383                     fprintf(stderr, "START THE THREAD. pfn is 0x%x, virtio is %p\n", mmio.pagesize, va->arg->virtio);
384                     if (pthread_create(&va->arg->thread, NULL, va->arg->f, va)) {
385                             fprintf(stderr, "pth_create failed for vq %s", va->arg->name);
386                             perror("pth_create");
387                     }
388             }
389             break;
390
391     case VIRTIO_MMIO_MAGIC_VALUE:
392     case VIRTIO_MMIO_VERSION:
393     case VIRTIO_MMIO_DEVICE_ID:
394     case VIRTIO_MMIO_VENDOR_ID:
395 //    case VIRTIO_MMIO_HOSTFEATURES:
396     case VIRTIO_MMIO_QUEUE_NUM_MAX:
397     case VIRTIO_MMIO_INTERRUPT_STATUS:
398         DPRINTF("write to readonly register\n");
399         break;
400
401     default:
402         DPRINTF("bad register offset 0x%x\n", offset);
403     }
404
405 }
406
407 static char *modrmreg[] = {"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi"};
408
409 void virtio_mmio(struct vmctl *v)
410 {
411         int advance = 3; /* how much to move the IP forward at the end. 3 is a good default. */
412         // All virtio accesses seem to be 32 bits.
413         // valp points to a place to get or put the value. 
414         uint32_t *valp;
415         //DPRINTF("v is %p\n", v);
416         // regp points to the register in hw_trapframe from which
417         // to load or store a result.
418         uint64_t *regp;
419
420         // Duh, which way did he go George? Which way did he go? 
421         // First hit on Google gets you there!
422         // This is the guest physical address of the access.
423         // This is nice, because if we ever go with more complete
424         // instruction decode, knowing this gpa reduces our work:
425         // we don't have to find the source address in registers,
426         // only the register holding or receiving the value.
427         uint64_t gpa = v->gpa;
428         //DPRINTF("gpa is %p\n", gpa);
429
430         // To find out what to do, we have to look at
431         // RIP. Technically, we should read RIP, walk the page tables
432         // to find the PA, and read that. But we're in the kernel, so
433         // we take a shortcut for now: read the low 30 bits and use
434         // that as the kernel PA, or our VA, and see what's
435         // there. Hokey. Works.
436         uint8_t *kva = (void *)(v->regs.tf_rip & 0x3fffffff);
437         //DPRINTF("kva is %p\n", kva);
438
439         if ((kva[0] != 0x8b) && (kva[0] != 0x89)) {
440                 fprintf(stderr, "%s: can't handle instruction 0x%x\n", kva[0]);
441                 return;
442         }
443
444         uint16_t ins = *(uint16_t *)kva;
445         //DPRINTF("ins is %04x\n", ins);
446         
447         int write = (kva[0] == 0x8b) ? 0 : 1;
448         if (write)
449                 valp = (uint32_t *)gpa;
450
451         int mod = kva[1]>>6;
452         switch (mod) {
453                 case 0: 
454                 case 3:
455                         advance = 2;
456                         break;
457                 case 1:
458                         advance = 3;
459                         break;
460                 case 2: 
461                         advance = 6;
462                         break;
463         }
464         /* the dreaded mod/rm byte. */
465         int destreg = (ins>>11) & 7;
466         // Our primitive approach wins big here.
467         // We don't have to decode the register or the offset used
468         // in the computation; that was done by the CPU and is the gpa.
469         // All we need to know is which destination or source register it is.
470         switch (destreg) {
471         case 0:
472                 regp = &v->regs.tf_rax;
473                 break;
474         case 1:
475                 regp = &v->regs.tf_rcx;
476                 break;
477         case 2:
478                 regp = &v->regs.tf_rdx;
479                 break;
480         case 3:
481                 regp = &v->regs.tf_rbx;
482                 break;
483         case 4:
484                 regp = &v->regs.tf_rsp; // uh, right.
485                 break;
486         case 5:
487                 regp = &v->regs.tf_rbp;
488                 break;
489         case 6:
490                 regp = &v->regs.tf_rsi;
491                 break;
492         case 7:
493                 regp = &v->regs.tf_rdi;
494                 break;
495         }
496
497         if (write) {
498                 virtio_mmio_write(gpa, *regp);
499                 DPRINTF("Write: mov %s to %s @%p val %p\n", modrmreg[destreg], virtio_names[(uint8_t)gpa], gpa, *regp);
500         } else {
501                 *regp = virtio_mmio_read(gpa);
502                 DPRINTF("Read: Set %s from %s @%p to %p\n", modrmreg[destreg], virtio_names[(uint8_t)gpa], gpa, *regp);
503         }
504
505         DPRINTF("Advance rip by %d bytes to %p\n", advance, v->regs.tf_rip);
506         v->regs.tf_rip += advance;
507 }