Check that bus freq is not zero
[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 /* TODO: probably embed this in the struct virtual_machine */
71 static mmiostate mmio;
72
73 void register_virtio_mmio(struct vqdev *vqdev, uint64_t virtio_base)
74 {
75         mmio.bar = virtio_base;
76         mmio.vqdev = vqdev;
77 }
78
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(struct virtual_machine *vm, 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(struct virtual_machine *vm, uint64_t gpa,
213                               uint32_t value)
214 {
215         uint64_t val64;
216         uint32_t low, high;
217         unsigned int offset = gpa - mmio.bar;
218         
219         DPRINTF("virtio_mmio_write offset %s 0x%x value 0x%x\n", virtio_names[offset], (int)offset, value);
220
221     if (offset >= VIRTIO_MMIO_CONFIG) {
222             fprintf(stderr, "Whoa. %p Writing past mmio config space? What gives?\n", gpa);
223 #if 0
224         offset -= VIRTIO_MMIO_CONFIG;
225         switch (size) {
226         case 1:
227             virtio_config_writeb(vdev, offset, value);
228             break;
229         case 2:
230             virtio_config_writew(vdev, offset, value);
231             break;
232         case 4:
233             virtio_config_writel(vdev, offset, value);
234             break;
235         default:
236             abort();
237         }
238 #endif
239         return;
240     }
241 #if 0
242     if (size != 4) {
243         DPRINTF("wrong size access to register!\n");
244         return;
245     }
246 #endif
247     switch (offset) {
248     case VIRTIO_MMIO_DEVICE_FEATURES_SEL:
249         mmio.device_features_word = value;
250         break;
251     case VIRTIO_MMIO_DEVICE_FEATURES:
252         if (mmio.device_features_word) {
253             /* changing the high word. */
254             low = mmio.vqdev->device_features;
255             high = value;
256         } else {
257             /* changing the low word. */
258             high = (mmio.vqdev->device_features >> 32);
259             low = value;
260         }
261         mmio.vqdev->device_features = ((uint64_t)high << 32) | low;
262         DPRINTF("Set VIRTIO_MMIO_DEVICE_FEATURES to %p\n", mmio.vqdev->device_features);
263         break;
264     case VIRTIO_MMIO_DRIVER_FEATURES:
265         if (mmio.driver_features_word) {
266             /* changing the high word. */
267             low = mmio.vqdev->driver_features;
268             high = value;
269         } else {
270             /* changing the low word. */
271             high = (mmio.vqdev->driver_features >> 32);
272             low = value;
273         }
274         mmio.vqdev->driver_features = ((uint64_t)high << 32) | low;
275         DPRINTF("Set VIRTIO_MMIO_DRIVER_FEATURES to %p\n", mmio.vqdev->driver_features);
276         break;
277     case VIRTIO_MMIO_DRIVER_FEATURES_SEL:
278             mmio.driver_features_word = value;
279         break;
280
281     case VIRTIO_MMIO_GUEST_PAGE_SIZE:
282             mmio.pagesize = value;
283             DPRINTF("guest page size %d bytes\n", mmio.pagesize);
284         break;
285     case VIRTIO_MMIO_QUEUE_SEL:
286             /* don't check it here. Check it on use. Or maybe check it here. Who knows. */
287             if (value < mmio.vqdev->numvqs)
288                     mmio.qsel = value;
289             else
290                     mmio.qsel = -1;
291             break;
292     case VIRTIO_MMIO_QUEUE_NUM:
293         mmio.vqdev->vqs[mmio.qsel].qnum = value;
294         break;
295     case VIRTIO_MMIO_QUEUE_ALIGN:
296         mmio.vqdev->vqs[mmio.qsel].qalign = value;
297         break;
298     case VIRTIO_MMIO_QUEUE_PFN:
299         // failure of vision: they used 32 bit numbers. Geez.
300         // v2 is better, we'll do v1 for now.
301         mmio.vqdev->vqs[mmio.qsel].pfn = value;
302                     // let's kick off the thread and see how it goes?
303                     struct virtio_threadarg *va = malloc(sizeof(*va));
304                     va->arg = &mmio.vqdev->vqs[mmio.qsel];
305
306                     va->arg->virtio = vring_new_virtqueue(mmio.qsel, 
307                                                           mmio.vqdev->vqs[mmio.qsel].qnum,
308                                                           mmio.vqdev->vqs[mmio.qsel].qalign,
309                                                           false, // weak_barriers
310                                                           (void *)(mmio.vqdev->vqs[mmio.qsel].pfn * mmio.vqdev->vqs[mmio.qsel].qalign),
311                                                           NULL, NULL, /* callbacks */
312                                                           mmio.vqdev->vqs[mmio.qsel].name);
313                     fprintf(stderr, "START THE THREAD. pfn is 0x%x, virtio is %p\n", mmio.pagesize, va->arg->virtio);
314                         vmm_run_task(vm, va->arg->func, va);
315         break;
316     case VIRTIO_MMIO_QUEUE_NOTIFY:
317             if (value < mmio.vqdev->numvqs) {
318                     mmio.qsel = value;
319             }
320         break;
321     case VIRTIO_MMIO_INTERRUPT_ACK:
322         mmio.isr &= ~value;
323         // I think we're suppose to do stuff here but the hell with it for now.
324         //virtio_update_irq(vdev);
325         break;
326     case VIRTIO_MMIO_STATUS:
327         if (!(value & VIRTIO_CONFIG_S_DRIVER_OK)) {
328             printf("VIRTIO_MMIO_STATUS write: NOT OK! 0x%x\n", value);
329         }
330
331         mmio.status |= value & 0xff;
332
333         if (value & VIRTIO_CONFIG_S_DRIVER_OK) {
334             printf("VIRTIO_MMIO_STATUS write: OK! 0x%x\n", value);
335         }
336
337         break;
338     case VIRTIO_MMIO_QUEUE_DESC_LOW:
339             val64 = mmio.vqdev->vqs[mmio.qsel].qdesc;
340             val64 = val64 >> 32;
341             val64 = (val64 <<32) | value;
342             mmio.vqdev->vqs[mmio.qsel].qdesc = val64;
343             DPRINTF("qdesc set low result 0xx%x\n", val64);
344             break;
345             
346     case VIRTIO_MMIO_QUEUE_DESC_HIGH:
347             val64 = (uint32_t) mmio.vqdev->vqs[mmio.qsel].qdesc;
348             mmio.vqdev->vqs[mmio.qsel].qdesc = (((uint64_t) value) <<32) | val64;
349             DPRINTF("qdesc set high result 0xx%x\n", mmio.vqdev->vqs[mmio.qsel].qdesc);
350             break;
351             
352 /* Selected queue's Available Ring address, 64 bits in two halves */
353     case VIRTIO_MMIO_QUEUE_AVAIL_LOW:
354             val64 = mmio.vqdev->vqs[mmio.qsel].qavail;
355             val64 = val64 >> 32;
356             val64 = (val64 <<32) | value;
357             mmio.vqdev->vqs[mmio.qsel].qavail = val64;
358             DPRINTF("qavail set low result 0xx%x\n", val64);
359             break;
360     case VIRTIO_MMIO_QUEUE_AVAIL_HIGH:
361             val64 = (uint32_t) mmio.vqdev->vqs[mmio.qsel].qavail;
362             mmio.vqdev->vqs[mmio.qsel].qavail = (((uint64_t) value) <<32) | val64;
363             DPRINTF("qavail set high result 0xx%x\n", mmio.vqdev->vqs[mmio.qsel].qavail);
364             break;
365             
366 /* Selected queue's Used Ring address, 64 bits in two halves */
367     case VIRTIO_MMIO_QUEUE_USED_LOW:
368             val64 = mmio.vqdev->vqs[mmio.qsel].qused;
369             val64 = val64 >> 32;
370             val64 = (val64 <<32) | value;
371             mmio.vqdev->vqs[mmio.qsel].qused = val64;
372             DPRINTF("qused set low result 0xx%x\n", val64);
373             break;
374     case VIRTIO_MMIO_QUEUE_USED_HIGH:
375             val64 = (uint32_t) mmio.vqdev->vqs[mmio.qsel].qused;
376             mmio.vqdev->vqs[mmio.qsel].qused = (((uint64_t) value) <<32) | val64;
377             DPRINTF("qused set used result 0xx%x\n", mmio.vqdev->vqs[mmio.qsel].qused);
378             break;
379             
380         // for v2. 
381     case VIRTIO_MMIO_QUEUE_READY:
382             if (value) {
383                     // let's kick off the thread and see how it goes?
384                     struct virtio_threadarg *va = malloc(sizeof(*va));
385                     va->arg = &mmio.vqdev->vqs[mmio.qsel];
386                     va->arg->virtio = (void *)(va->arg->pfn * mmio.pagesize);
387                     fprintf(stderr, "START THE THREAD. pfn is 0x%x, virtio is %p\n", mmio.pagesize, va->arg->virtio);
388                         vmm_run_task(vm, va->arg->func, va);
389             }
390             break;
391
392     case VIRTIO_MMIO_MAGIC_VALUE:
393     case VIRTIO_MMIO_VERSION:
394     case VIRTIO_MMIO_DEVICE_ID:
395     case VIRTIO_MMIO_VENDOR_ID:
396 //    case VIRTIO_MMIO_HOSTFEATURES:
397     case VIRTIO_MMIO_QUEUE_NUM_MAX:
398     case VIRTIO_MMIO_INTERRUPT_STATUS:
399         DPRINTF("write to readonly register\n");
400         break;
401
402     default:
403         DPRINTF("bad register offset 0x%x\n", offset);
404     }
405
406 }
407
408 void virtio_mmio_set_vring_irq(void)
409 {
410         mmio.isr |= VIRTIO_MMIO_INT_VRING;
411 }
412
413 int virtio_mmio(struct guest_thread *gth, uint64_t gpa, int destreg,
414                 uint64_t *regp, int store)
415 {
416         if (store) {
417                 virtio_mmio_write(gth_to_vm(gth), gpa, *regp);
418                 DPRINTF("Write: mov %s to %s @%p val %p\n", regname(destreg),
419                         virtio_names[(uint8_t)gpa], gpa, *regp);
420         } else {
421                 *regp = virtio_mmio_read(gth_to_vm(gth), gpa);
422                 DPRINTF("Read: Set %s from %s @%p to %p\n", regname(destreg),
423                         virtio_names[(uint8_t)gpa], gpa, *regp);
424         }
425
426 }