Make akaros_vfprintf() take a stream (XCC)
[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 <vmm/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 #include <vmm/sched.h>
43
44 int debug_virtio_mmio = 0;
45 #define DPRINTF(fmt, ...) \
46         if (debug_virtio_mmio) { printf("virtio_mmio: " fmt , ## __VA_ARGS__); }
47
48
49 #define VIRT_MAGIC 0x74726976 /* 'virt' */
50 /* version is a real mess. A real mess. I don't understand it at all. Let's stick with 1, which sucks, 
51  * instead of 2, which seems to be not supported right. I think.
52  */
53 #define VIRT_VERSION 1
54 #define VIRT_VENDOR 0x554D4551 /* 'QEMU' */
55
56
57 typedef struct {
58         int state; // not used yet. */
59         uint64_t bar;
60         uint32_t status;
61         uint32_t isr;
62         int qsel; // queue we are on.
63         int pagesize;
64         int page_shift;
65         int device_features_word; // if this is 1, use the high 32 bits. 
66         int driver_features_word;
67         struct vqdev *vqdev;
68 } mmiostate;
69
70 static mmiostate mmio;
71
72 void register_virtio_mmio(struct vqdev *vqdev, uint64_t virtio_base)
73 {
74         mmio.bar = virtio_base;
75         mmio.vqdev = vqdev;
76 }
77
78 static uint32_t virtio_mmio_read(uint64_t gpa);
79 char *virtio_names[] = {
80         [VIRTIO_MMIO_MAGIC_VALUE] "VIRTIO_MMIO_MAGIC_VALUE",
81         [VIRTIO_MMIO_VERSION] "VIRTIO_MMIO_VERSION",
82         [VIRTIO_MMIO_DEVICE_ID] "VIRTIO_MMIO_DEVICE_ID",
83         [VIRTIO_MMIO_VENDOR_ID] "VIRTIO_MMIO_VENDOR_ID",
84         [VIRTIO_MMIO_DEVICE_FEATURES] "VIRTIO_MMIO_DEVICE_FEATURES",
85         [VIRTIO_MMIO_DEVICE_FEATURES_SEL] "VIRTIO_MMIO_DEVICE_FEATURES_SEL",
86         [VIRTIO_MMIO_DRIVER_FEATURES] "VIRTIO_MMIO_DRIVER_FEATURES",
87         [VIRTIO_MMIO_DRIVER_FEATURES_SEL] "VIRTIO_MMIO_DRIVER_FEATURES_SEL",
88         [VIRTIO_MMIO_GUEST_PAGE_SIZE] "VIRTIO_MMIO_GUEST_PAGE_SIZE",
89         [VIRTIO_MMIO_QUEUE_SEL] "VIRTIO_MMIO_QUEUE_SEL",
90         [VIRTIO_MMIO_QUEUE_NUM_MAX] "VIRTIO_MMIO_QUEUE_NUM_MAX",
91         [VIRTIO_MMIO_QUEUE_NUM] "VIRTIO_MMIO_QUEUE_NUM",
92         [VIRTIO_MMIO_QUEUE_ALIGN] "VIRTIO_MMIO_QUEUE_ALIGN",
93         [VIRTIO_MMIO_QUEUE_PFN] "VIRTIO_MMIO_QUEUE_PFN",
94         [VIRTIO_MMIO_QUEUE_READY] "VIRTIO_MMIO_QUEUE_READY",
95         [VIRTIO_MMIO_QUEUE_NOTIFY] "VIRTIO_MMIO_QUEUE_NOTIFY",
96         [VIRTIO_MMIO_INTERRUPT_STATUS] "VIRTIO_MMIO_INTERRUPT_STATUS",
97         [VIRTIO_MMIO_INTERRUPT_ACK] "VIRTIO_MMIO_INTERRUPT_ACK",
98         [VIRTIO_MMIO_STATUS] "VIRTIO_MMIO_STATUS",
99         [VIRTIO_MMIO_QUEUE_DESC_LOW] "VIRTIO_MMIO_QUEUE_DESC_LOW",
100         [VIRTIO_MMIO_QUEUE_DESC_HIGH] "VIRTIO_MMIO_QUEUE_DESC_HIGH",
101         [VIRTIO_MMIO_QUEUE_AVAIL_LOW] "VIRTIO_MMIO_QUEUE_AVAIL_LOW",
102         [VIRTIO_MMIO_QUEUE_AVAIL_HIGH] "VIRTIO_MMIO_QUEUE_AVAIL_HIGH",
103         [VIRTIO_MMIO_QUEUE_USED_LOW] "VIRTIO_MMIO_QUEUE_USED_LOW",
104         [VIRTIO_MMIO_QUEUE_USED_HIGH] "VIRTIO_MMIO_QUEUE_USED_HIGH",
105         [VIRTIO_MMIO_CONFIG_GENERATION] "VIRTIO_MMIO_CONFIG_GENERATION",
106 };
107
108 /* We're going to attempt to make mmio stateless, since the real machine is in
109  * the guest kernel. From what we know so far, all IO to the mmio space is 32 bits.
110  */
111 static uint32_t virtio_mmio_read(uint64_t gpa)
112 {
113
114         unsigned int offset = gpa - mmio.bar;
115         uint32_t low;
116         
117         DPRINTF("virtio_mmio_read offset %s 0x%x\n", virtio_names[offset],(int)offset);
118
119         /* If no backend is present, we treat most registers as
120          * read-as-zero, except for the magic number, version and
121          * vendor ID. This is not strictly sanctioned by the virtio
122          * spec, but it allows us to provide transports with no backend
123          * plugged in which don't confuse Linux's virtio code: the
124          * probe won't complain about the bad magic number, but the
125          * device ID of zero means no backend will claim it.
126          */
127         if (mmio.vqdev->numvqs == 0) {
128                 switch (offset) {
129                 case VIRTIO_MMIO_MAGIC_VALUE:
130                         return VIRT_MAGIC;
131                 case VIRTIO_MMIO_VERSION:
132                         return VIRT_VERSION;
133                 case VIRTIO_MMIO_VENDOR_ID:
134                         return VIRT_VENDOR;
135                 default:
136                         return 0;
137                 }
138         }
139
140
141     // WTF? Does this happen? 
142     if (offset >= VIRTIO_MMIO_CONFIG) {
143             fprintf(stderr, "Whoa. %p Reading past mmio config space? What gives?\n", gpa);
144             return -1;
145 #if 0
146             offset -= VIRTIO_MMIO_CONFIG;
147             switch (size) {
148             case 1:
149                     return virtio_config_readb(vdev, offset);
150             case 2:
151                     return virtio_config_readw(vdev, offset);
152             case 4:
153                     return virtio_config_readl(vdev, offset);
154             default:
155                     abort();
156             }
157 #endif
158     }
159
160 #if 0
161     if (size != 4) {
162         DPRINTF("wrong size access to register!\n");
163         return 0;
164     }
165 #endif
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                 // pretty sure this is per-mmio, not per-q. 
187         //fprintf(stderr, "MMIO ISR 0x%08x\n", mmio.isr);
188         //fprintf(stderr, "GPA IS 0x%016x\n", gpa);
189         //fprintf(stderr, "mmio.bar IS 0x%016x\n", mmio.bar);
190                 return mmio.isr;
191             //return mmio.vqdev->vqs[mmio.qsel].isr;
192     case VIRTIO_MMIO_STATUS:
193             return mmio.vqdev->vqs[mmio.qsel].status;
194     case VIRTIO_MMIO_DEVICE_FEATURES_SEL:
195     case VIRTIO_MMIO_DRIVER_FEATURES:
196     case VIRTIO_MMIO_DRIVER_FEATURES_SEL:
197     case VIRTIO_MMIO_GUEST_PAGE_SIZE:
198     case VIRTIO_MMIO_QUEUE_SEL:
199     case VIRTIO_MMIO_QUEUE_NUM:
200     case VIRTIO_MMIO_QUEUE_ALIGN:
201     case VIRTIO_MMIO_QUEUE_READY:
202     case VIRTIO_MMIO_INTERRUPT_ACK:
203             fprintf(stderr, "read of write-only register@%p\n", (void *)gpa);
204         return 0;
205     default:
206             fprintf(stderr, "bad register offset@%p\n", (void *)gpa);
207         return 0;
208     }
209     return 0;
210 }
211
212 static void virtio_mmio_write(uint64_t gpa, uint32_t value)
213 {
214         uint64_t val64;
215         uint32_t low, high;
216         unsigned int offset = gpa - mmio.bar;
217         
218         DPRINTF("virtio_mmio_write offset %s 0x%x value 0x%x\n", virtio_names[offset], (int)offset, value);
219
220     if (offset >= VIRTIO_MMIO_CONFIG) {
221             fprintf(stderr, "Whoa. %p Writing past mmio config space? What gives?\n", gpa);
222 #if 0
223         offset -= VIRTIO_MMIO_CONFIG;
224         switch (size) {
225         case 1:
226             virtio_config_writeb(vdev, offset, value);
227             break;
228         case 2:
229             virtio_config_writew(vdev, offset, value);
230             break;
231         case 4:
232             virtio_config_writel(vdev, offset, value);
233             break;
234         default:
235             abort();
236         }
237 #endif
238         return;
239     }
240 #if 0
241     if (size != 4) {
242         DPRINTF("wrong size access to register!\n");
243         return;
244     }
245 #endif
246     switch (offset) {
247     case VIRTIO_MMIO_DEVICE_FEATURES_SEL:
248         mmio.device_features_word = value;
249         break;
250     case VIRTIO_MMIO_DEVICE_FEATURES:
251         if (mmio.device_features_word) {
252             /* changing the high word. */
253             low = mmio.vqdev->device_features;
254             high = value;
255         } else {
256             /* changing the low word. */
257             high = (mmio.vqdev->device_features >> 32);
258             low = value;
259         }
260         mmio.vqdev->device_features = ((uint64_t)high << 32) | low;
261         DPRINTF("Set VIRTIO_MMIO_DEVICE_FEATURES to %p\n", mmio.vqdev->device_features);
262         break;
263     case VIRTIO_MMIO_DRIVER_FEATURES:
264         if (mmio.driver_features_word) {
265             /* changing the high word. */
266             low = mmio.vqdev->driver_features;
267             high = value;
268         } else {
269             /* changing the low word. */
270             high = (mmio.vqdev->driver_features >> 32);
271             low = value;
272         }
273         mmio.vqdev->driver_features = ((uint64_t)high << 32) | low;
274         DPRINTF("Set VIRTIO_MMIO_DRIVER_FEATURES to %p\n", mmio.vqdev->driver_features);
275         break;
276     case VIRTIO_MMIO_DRIVER_FEATURES_SEL:
277             mmio.driver_features_word = value;
278         break;
279
280     case VIRTIO_MMIO_GUEST_PAGE_SIZE:
281             mmio.pagesize = value;
282             DPRINTF("guest page size %d bytes\n", mmio.pagesize);
283         break;
284     case VIRTIO_MMIO_QUEUE_SEL:
285             /* don't check it here. Check it on use. Or maybe check it here. Who knows. */
286             if (value < mmio.vqdev->numvqs)
287                     mmio.qsel = value;
288             else
289                     mmio.qsel = -1;
290             break;
291     case VIRTIO_MMIO_QUEUE_NUM:
292         mmio.vqdev->vqs[mmio.qsel].qnum = value;
293         break;
294     case VIRTIO_MMIO_QUEUE_ALIGN:
295         mmio.vqdev->vqs[mmio.qsel].qalign = value;
296         break;
297     case VIRTIO_MMIO_QUEUE_PFN:
298         // failure of vision: they used 32 bit numbers. Geez.
299         // v2 is better, we'll do v1 for now.
300         mmio.vqdev->vqs[mmio.qsel].pfn = value;
301                     // let's kick off the thread and see how it goes?
302                     struct virtio_threadarg *va = malloc(sizeof(*va));
303                     va->arg = &mmio.vqdev->vqs[mmio.qsel];
304
305                     va->arg->virtio = vring_new_virtqueue(mmio.qsel, 
306                                                           mmio.vqdev->vqs[mmio.qsel].qnum,
307                                                           mmio.vqdev->vqs[mmio.qsel].qalign,
308                                                           false, // weak_barriers
309                                                           (void *)(mmio.vqdev->vqs[mmio.qsel].pfn * mmio.vqdev->vqs[mmio.qsel].qalign),
310                                                           NULL, NULL, /* callbacks */
311                                                           mmio.vqdev->vqs[mmio.qsel].name);
312                     fprintf(stderr, "START THE THREAD. pfn is 0x%x, virtio is %p\n", mmio.pagesize, va->arg->virtio);
313                     if (pthread_create(&va->arg->thread, NULL, va->arg->f, va)) {
314                             fprintf(stderr, "pth_create failed for vq %s", va->arg->name);
315                             perror("pth_create");
316                     }
317         break;
318     case VIRTIO_MMIO_QUEUE_NOTIFY:
319             if (value < mmio.vqdev->numvqs) {
320                     mmio.qsel = value;
321             }
322         break;
323     case VIRTIO_MMIO_INTERRUPT_ACK:
324         mmio.isr &= ~value;
325         // I think we're suppose to do stuff here but the hell with it for now.
326         //virtio_update_irq(vdev);
327         break;
328     case VIRTIO_MMIO_STATUS:
329         if (!(value & VIRTIO_CONFIG_S_DRIVER_OK)) {
330             printf("VIRTIO_MMIO_STATUS write: NOT OK! 0x%x\n", value);
331         }
332
333         mmio.status |= value & 0xff;
334
335         if (value & VIRTIO_CONFIG_S_DRIVER_OK) {
336             printf("VIRTIO_MMIO_STATUS write: OK! 0x%x\n", value);
337         }
338
339         break;
340     case VIRTIO_MMIO_QUEUE_DESC_LOW:
341             val64 = mmio.vqdev->vqs[mmio.qsel].qdesc;
342             val64 = val64 >> 32;
343             val64 = (val64 <<32) | value;
344             mmio.vqdev->vqs[mmio.qsel].qdesc = val64;
345             DPRINTF("qdesc set low result 0xx%x\n", val64);
346             break;
347             
348     case VIRTIO_MMIO_QUEUE_DESC_HIGH:
349             val64 = (uint32_t) mmio.vqdev->vqs[mmio.qsel].qdesc;
350             mmio.vqdev->vqs[mmio.qsel].qdesc = (((uint64_t) value) <<32) | val64;
351             DPRINTF("qdesc set high result 0xx%x\n", mmio.vqdev->vqs[mmio.qsel].qdesc);
352             break;
353             
354 /* Selected queue's Available Ring address, 64 bits in two halves */
355     case VIRTIO_MMIO_QUEUE_AVAIL_LOW:
356             val64 = mmio.vqdev->vqs[mmio.qsel].qavail;
357             val64 = val64 >> 32;
358             val64 = (val64 <<32) | value;
359             mmio.vqdev->vqs[mmio.qsel].qavail = val64;
360             DPRINTF("qavail set low result 0xx%x\n", val64);
361             break;
362     case VIRTIO_MMIO_QUEUE_AVAIL_HIGH:
363             val64 = (uint32_t) mmio.vqdev->vqs[mmio.qsel].qavail;
364             mmio.vqdev->vqs[mmio.qsel].qavail = (((uint64_t) value) <<32) | val64;
365             DPRINTF("qavail set high result 0xx%x\n", mmio.vqdev->vqs[mmio.qsel].qavail);
366             break;
367             
368 /* Selected queue's Used Ring address, 64 bits in two halves */
369     case VIRTIO_MMIO_QUEUE_USED_LOW:
370             val64 = mmio.vqdev->vqs[mmio.qsel].qused;
371             val64 = val64 >> 32;
372             val64 = (val64 <<32) | value;
373             mmio.vqdev->vqs[mmio.qsel].qused = val64;
374             DPRINTF("qused set low result 0xx%x\n", val64);
375             break;
376     case VIRTIO_MMIO_QUEUE_USED_HIGH:
377             val64 = (uint32_t) mmio.vqdev->vqs[mmio.qsel].qused;
378             mmio.vqdev->vqs[mmio.qsel].qused = (((uint64_t) value) <<32) | val64;
379             DPRINTF("qused set used result 0xx%x\n", mmio.vqdev->vqs[mmio.qsel].qused);
380             break;
381             
382         // for v2. 
383     case VIRTIO_MMIO_QUEUE_READY:
384             if (value) {
385                     // let's kick off the thread and see how it goes?
386                     struct virtio_threadarg *va = malloc(sizeof(*va));
387                     va->arg = &mmio.vqdev->vqs[mmio.qsel];
388                     va->arg->virtio = (void *)(va->arg->pfn * mmio.pagesize);
389                     fprintf(stderr, "START THE THREAD. pfn is 0x%x, virtio is %p\n", mmio.pagesize, va->arg->virtio);
390                     if (pthread_create(&va->arg->thread, NULL, va->arg->f, va)) {
391                             fprintf(stderr, "pth_create failed for vq %s", va->arg->name);
392                             perror("pth_create");
393                     }
394             }
395             break;
396
397     case VIRTIO_MMIO_MAGIC_VALUE:
398     case VIRTIO_MMIO_VERSION:
399     case VIRTIO_MMIO_DEVICE_ID:
400     case VIRTIO_MMIO_VENDOR_ID:
401 //    case VIRTIO_MMIO_HOSTFEATURES:
402     case VIRTIO_MMIO_QUEUE_NUM_MAX:
403     case VIRTIO_MMIO_INTERRUPT_STATUS:
404         DPRINTF("write to readonly register\n");
405         break;
406
407     default:
408         DPRINTF("bad register offset 0x%x\n", offset);
409     }
410
411 }
412
413 void virtio_mmio_set_vring_irq(void)
414 {
415         mmio.isr |= VIRTIO_MMIO_INT_VRING;
416 }
417
418 int virtio_mmio(struct guest_thread *vm_thread, uint64_t gpa, int destreg,
419                 uint64_t *regp, int store)
420 {
421         if (store) {
422                 virtio_mmio_write(gpa, *regp);
423                 DPRINTF("Write: mov %s to %s @%p val %p\n", regname(destreg),
424                         virtio_names[(uint8_t)gpa], gpa, *regp);
425         } else {
426                 *regp = virtio_mmio_read(gpa);
427                 DPRINTF("Read: Set %s from %s @%p to %p\n", regname(destreg),
428                         virtio_names[(uint8_t)gpa], gpa, *regp);
429         }
430
431 }