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