Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


added virtio console, finished the stream interface implementation, added v3_stream...
[palacios.git] / palacios / src / devices / lnx_virtio_console.c
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20 #include <palacios/vmm.h>
21 #include <palacios/vmm_dev_mgr.h>
22 #include <devices/lnx_virtio_pci.h>
23 #include <palacios/vm_guest_mem.h>
24
25 #include <devices/pci.h>
26
27
28
29 struct console_config {
30     uint16_t cols;
31     uint16_t rows;
32 } __attribute__((packed));
33
34
35
36
37 #define QUEUE_SIZE 128
38
39 /* Host Feature flags */
40 #define VIRTIO_CONSOLE_F_SIZE 0x1
41
42 struct virtio_console_state {
43     struct console_config cons_cfg;
44     struct virtio_config virtio_cfg;
45
46     struct vm_device * pci_bus;
47     struct pci_device * pci_dev;
48     
49     struct virtio_queue queue[2];
50
51     struct v3_stream * stream;
52
53
54     struct virtio_queue * cur_queue;
55
56     struct v3_vm_info * vm;
57
58     int io_range_size;
59
60     void * backend_data;
61     struct v3_dev_char_ops * ops;
62 };
63
64
65 struct virtio_console_state * cons_state = NULL;
66
67 static int virtio_reset(struct virtio_console_state * virtio) {
68
69     memset(virtio->queue, 0, sizeof(struct virtio_queue) * 2);
70
71     virtio->cur_queue = &(virtio->queue[0]);
72
73     virtio->virtio_cfg.status = 0;
74     virtio->virtio_cfg.pci_isr = 0;
75
76     /* Console configuration */
77     // virtio->virtio_cfg.host_features = VIRTIO_NOTIFY_HOST;
78
79     // Virtio Console uses two queues
80     virtio->queue[0].queue_size = QUEUE_SIZE;
81     virtio->queue[1].queue_size = QUEUE_SIZE;
82
83
84     memset(&(virtio->cons_cfg), 0, sizeof(struct console_config));
85
86     return 0;
87 }
88
89 static int get_desc_count(struct virtio_queue * q, int index) {
90     struct vring_desc * tmp_desc = &(q->desc[index]);
91     int cnt = 1;
92     
93     while (tmp_desc->flags & VIRTIO_NEXT_FLAG) {
94         tmp_desc = &(q->desc[tmp_desc->next]);
95         cnt++;
96     }
97
98     return cnt;
99 }
100
101
102 static int handle_kick(struct guest_info * core, struct virtio_console_state * virtio) {
103     struct virtio_queue * q = virtio->cur_queue;
104
105     PrintDebug("VIRTIO CONSOLE KICK: cur_index=%d (mod=%d), avail_index=%d\n", 
106                q->cur_avail_idx, q->cur_avail_idx % QUEUE_SIZE, q->avail->index);
107
108     while (q->cur_avail_idx < q->avail->index) {
109         struct vring_desc * tmp_desc = NULL;
110         uint16_t desc_idx = q->avail->ring[q->cur_avail_idx % QUEUE_SIZE];
111         int desc_cnt = get_desc_count(q, desc_idx);
112         int i = 0;
113         uint32_t req_len = 0;
114
115
116         PrintDebug("Descriptor Count=%d, index=%d\n", desc_cnt, q->cur_avail_idx % QUEUE_SIZE);
117
118         for (i = 0; i < desc_cnt; i++) {
119             addr_t page_addr;
120             tmp_desc = &(q->desc[desc_idx]);
121             
122         
123             PrintDebug("Console output (ptr=%p) gpa=%p, len=%d, flags=%x, next=%d\n", 
124                        tmp_desc, 
125                        (void *)(addr_t)(tmp_desc->addr_gpa), tmp_desc->length, 
126                        tmp_desc->flags, tmp_desc->next);
127         
128             if (v3_gpa_to_hva(core, tmp_desc->addr_gpa, (addr_t *)&(page_addr)) == -1) {
129                 PrintError("Could not translate block header address\n");
130                 return -1;
131             }
132
133             virtio->ops->output((uint8_t *)page_addr, tmp_desc->length, virtio->backend_data);
134
135             PrintDebug("Guest Console Currently Ignored\n");
136
137             req_len += tmp_desc->length;
138             desc_idx = tmp_desc->next;
139         }
140
141         q->used->ring[q->used->index % QUEUE_SIZE].id = q->avail->ring[q->cur_avail_idx % QUEUE_SIZE];
142         q->used->ring[q->used->index % QUEUE_SIZE].length = req_len; // What do we set this to????
143
144         q->used->index++;
145         q->cur_avail_idx++;
146     }
147
148     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
149         PrintDebug("Raising IRQ %d\n",  virtio->pci_dev->config_header.intr_line);
150         v3_pci_raise_irq(virtio->pci_bus, 0, virtio->pci_dev);
151         virtio->virtio_cfg.pci_isr = VIRTIO_ISR_ACTIVE;
152     }
153
154     return 0;
155 }
156
157
158 static uint64_t virtio_input(struct v3_vm_info * vm, uint8_t * buf, uint64_t len, void * private_data) {
159     struct virtio_console_state * cons_state = private_data;
160     struct virtio_queue * q = &(cons_state->queue[0]);
161     int xfer_len = 0;
162     
163    PrintDebug("VIRTIO CONSOLE Handle Input: cur_index=%d (mod=%d), avail_index=%d\n", 
164                q->cur_avail_idx, q->cur_avail_idx % QUEUE_SIZE, q->avail->index);
165
166
167    if (q->cur_avail_idx != q->avail->index) {
168        uint16_t input_idx = q->avail->ring[q->cur_avail_idx % q->queue_size];
169        struct vring_desc * input_desc = NULL;
170        uint8_t * input_buf = NULL;
171  
172
173        input_desc = &(q->desc[input_idx]);
174
175        if (v3_gpa_to_hva(&(cons_state->vm->cores[0]), input_desc->addr_gpa, (addr_t *)&(input_buf)) == -1) {
176            PrintError("Could not translate receive buffer address\n");
177            return 0;
178        }
179
180        memset(input_buf, 0, input_desc->length);
181
182        xfer_len = (input_desc->length > len) ? len : input_desc->length;
183
184        memcpy(input_buf, buf, xfer_len);
185
186        
187        q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size];
188        q->used->ring[q->used->index % q->queue_size].length = xfer_len;
189
190        q->used->index++;
191        q->cur_avail_idx++;
192    }
193
194
195     // say hello
196     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
197             v3_pci_raise_irq(cons_state->pci_bus, 0, cons_state->pci_dev);
198             cons_state->virtio_cfg.pci_isr = 0x1;
199     }
200
201     return xfer_len;
202 }
203
204
205 static int virtio_io_write(struct guest_info * core, uint16_t port, void * src, uint_t length, void * private_data) {
206     struct virtio_console_state * virtio = (struct virtio_console_state *)private_data;
207     int port_idx = port % virtio->io_range_size;
208
209
210     PrintDebug("VIRTIO CONSOLE Write for port %d (index=%d) len=%d, value=%x\n", 
211                port, port_idx,  length, *(uint32_t *)src);
212
213
214
215     switch (port_idx) {
216         case GUEST_FEATURES_PORT:
217             if (length != 4) {
218                 PrintError("Illegal write length for guest features\n");
219                 return -1;
220             }
221             
222             virtio->virtio_cfg.guest_features = *(uint32_t *)src;
223
224             break;
225         case VRING_PG_NUM_PORT:
226             if (length == 4) {
227                 addr_t pfn = *(uint32_t *)src;
228                 addr_t page_addr = (pfn << VIRTIO_PAGE_SHIFT);
229
230
231                 virtio->cur_queue->pfn = pfn;
232                 
233                 virtio->cur_queue->ring_desc_addr = page_addr ;
234                 virtio->cur_queue->ring_avail_addr = page_addr + (QUEUE_SIZE * sizeof(struct vring_desc));
235                 virtio->cur_queue->ring_used_addr = ( virtio->cur_queue->ring_avail_addr + \
236                                                  sizeof(struct vring_avail)    + \
237                                                  (QUEUE_SIZE * sizeof(uint16_t)));
238                 
239                 // round up to next page boundary.
240                 virtio->cur_queue->ring_used_addr = (virtio->cur_queue->ring_used_addr + 0xfff) & ~0xfff;
241
242                 if (v3_gpa_to_hva(core, virtio->cur_queue->ring_desc_addr, (addr_t *)&(virtio->cur_queue->desc)) == -1) {
243                     PrintError("Could not translate ring descriptor address\n");
244                     return -1;
245                 }
246
247
248                 if (v3_gpa_to_hva(core, virtio->cur_queue->ring_avail_addr, (addr_t *)&(virtio->cur_queue->avail)) == -1) {
249                     PrintError("Could not translate ring available address\n");
250                     return -1;
251                 }
252
253
254                 if (v3_gpa_to_hva(core, virtio->cur_queue->ring_used_addr, (addr_t *)&(virtio->cur_queue->used)) == -1) {
255                     PrintError("Could not translate ring used address\n");
256                     return -1;
257                 }
258
259                 PrintDebug("RingDesc_addr=%p, Avail_addr=%p, Used_addr=%p\n",
260                            (void *)(virtio->cur_queue->ring_desc_addr),
261                            (void *)(virtio->cur_queue->ring_avail_addr),
262                            (void *)(virtio->cur_queue->ring_used_addr));
263
264                 PrintDebug("RingDesc=%p, Avail=%p, Used=%p\n", 
265                            virtio->cur_queue->desc, virtio->cur_queue->avail, virtio->cur_queue->used);
266
267             } else {
268                 PrintError("Illegal write length for page frame number\n");
269                 return -1;
270             }
271             break;
272         case VRING_Q_SEL_PORT:
273             virtio->virtio_cfg.vring_queue_selector = *(uint16_t *)src;
274
275             if (virtio->virtio_cfg.vring_queue_selector > 1) {
276                 PrintError("Virtio Console device only uses 2 queue, selected %d\n", 
277                            virtio->virtio_cfg.vring_queue_selector);
278                 return -1;
279             }
280             
281             virtio->cur_queue = &(virtio->queue[virtio->virtio_cfg.vring_queue_selector]);
282
283             break;
284         case VRING_Q_NOTIFY_PORT:
285             PrintDebug("Handling Kick\n");
286             if (handle_kick(core, virtio) == -1) {
287                 PrintError("Could not handle Console Notification\n");
288                 return -1;
289             }
290             break;
291         case VIRTIO_STATUS_PORT:
292             virtio->virtio_cfg.status = *(uint8_t *)src;
293
294             if (virtio->virtio_cfg.status == 0) {
295                 PrintDebug("Resetting device\n");
296                 virtio_reset(virtio);
297             }
298
299             break;
300
301         case VIRTIO_ISR_PORT:
302             virtio->virtio_cfg.pci_isr = *(uint8_t *)src;
303             break;
304         default:
305             return -1;
306             break;
307     }
308
309     return length;
310 }
311
312
313 static int virtio_io_read(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * private_data) {
314     struct virtio_console_state * virtio = (struct virtio_console_state *)private_data;
315     int port_idx = port % virtio->io_range_size;
316
317
318     PrintDebug("VIRTIO CONSOLE Read  for port %d (index =%d), length=%d\n", 
319                port, port_idx, length);
320
321     switch (port_idx) {
322         case HOST_FEATURES_PORT:
323             if (length != 4) {
324                 PrintError("Illegal read length for host features\n");
325                 return -1;
326             }
327
328             *(uint32_t *)dst = virtio->virtio_cfg.host_features;
329         
330             break;
331         case VRING_PG_NUM_PORT:
332             if (length != 4) {
333                 PrintError("Illegal read length for page frame number\n");
334                 return -1;
335             }
336
337             *(uint32_t *)dst = virtio->cur_queue->pfn;
338
339             break;
340         case VRING_SIZE_PORT:
341             if (length != 2) {
342                 PrintError("Illegal read length for vring size\n");
343                 return -1;
344             }
345                 
346             *(uint16_t *)dst = virtio->cur_queue->queue_size;
347
348             break;
349
350         case VIRTIO_STATUS_PORT:
351             if (length != 1) {
352                 PrintError("Illegal read length for status\n");
353                 return -1;
354             }
355
356             *(uint8_t *)dst = virtio->virtio_cfg.status;
357             break;
358
359         case VIRTIO_ISR_PORT:
360             *(uint8_t *)dst = virtio->virtio_cfg.pci_isr;
361             virtio->virtio_cfg.pci_isr = 0;
362             v3_pci_lower_irq(virtio->pci_bus, 0, virtio->pci_dev);
363             break;
364
365         default:
366             if ( (port_idx >= sizeof(struct virtio_config)) && 
367                  (port_idx < (sizeof(struct virtio_config) + sizeof(struct console_config))) ) {
368                 int cfg_offset = port_idx - sizeof(struct virtio_config);
369                 uint8_t * cfg_ptr = (uint8_t *)&(virtio->cons_cfg);
370
371                 memcpy(dst, cfg_ptr + cfg_offset, length);
372                 
373             } else {
374                 PrintError("Read of Unhandled Virtio Read\n");
375                 return -1;
376             }
377           
378             break;
379     }
380
381     return length;
382 }
383
384
385
386
387 static int connect_fn(struct v3_vm_info * vm, 
388                       void * frontend_data, 
389                       struct v3_dev_char_ops * ops, 
390                       v3_cfg_tree_t * cfg, 
391                       void * private_data, 
392                       void ** push_fn_arg) {
393
394     struct virtio_console_state * state = (struct virtio_console_state *)frontend_data;
395
396     state->ops = ops;
397     state->backend_data = private_data;
398
399     state->ops->input = virtio_input;
400     *push_fn_arg = state;
401
402     return 0;
403 }
404
405 static int virtio_free(struct virtio_console_state * virtio) {
406
407     // unregister from PCI
408
409     V3_Free(virtio);
410     return 0;
411 }
412
413
414 static struct v3_device_ops dev_ops = {
415     .free = (int (*)(void *))virtio_free,
416
417 };
418
419
420
421
422 static int virtio_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
423     struct vm_device * pci_bus = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
424     struct virtio_console_state * virtio_state = NULL;
425     struct pci_device * pci_dev = NULL;
426     char * dev_id = v3_cfg_val(cfg, "ID");
427
428     PrintDebug("Initializing VIRTIO Console device\n");
429
430     if (pci_bus == NULL) {
431         PrintError("VirtIO devices require a PCI Bus");
432         return -1;
433     }
434
435     
436     virtio_state = (struct virtio_console_state *)V3_Malloc(sizeof(struct virtio_console_state));
437     memset(virtio_state, 0, sizeof(struct virtio_console_state));
438     
439
440     cons_state = virtio_state;
441     cons_state->vm = vm;
442
443    
444
445     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, virtio_state);
446
447     if (dev == NULL) {
448         PrintError("Could not attach device %s\n", dev_id);
449         V3_Free(virtio_state);
450         return -1;
451     }
452
453     // PCI initialization
454     {
455         struct v3_pci_bar bars[6];
456         int num_ports = sizeof(struct virtio_config) + sizeof(struct console_config);
457         int tmp_ports = num_ports;
458         int i;
459
460
461         // This gets the number of ports, rounded up to a power of 2
462         virtio_state->io_range_size = 1; // must be a power of 2
463
464         while (tmp_ports > 0) {
465             tmp_ports >>= 1;
466             virtio_state->io_range_size <<= 1;
467         }
468         
469         // this is to account for any low order bits being set in num_ports
470         // if there are none, then num_ports was already a power of 2 so we shift right to reset it
471         if ((num_ports & ((virtio_state->io_range_size >> 1) - 1)) == 0) {
472             virtio_state->io_range_size >>= 1;
473         }
474
475
476         for (i = 0; i < 6; i++) {
477             bars[i].type = PCI_BAR_NONE;
478         }
479
480         bars[0].type = PCI_BAR_IO;
481         bars[0].default_base_port = -1;
482         bars[0].num_ports = virtio_state->io_range_size;
483
484         bars[0].io_read = virtio_io_read;
485         bars[0].io_write = virtio_io_write;
486         bars[0].private_data = virtio_state;
487         
488
489         pci_dev = v3_pci_register_device(pci_bus, PCI_STD_DEVICE, 
490                                          0, PCI_AUTO_DEV_NUM, 0,
491                                          "LNX_VIRTIO_CONSOLE", bars,
492                                          NULL, NULL, NULL, virtio_state);
493
494         if (!pci_dev) {
495             PrintError("Could not register PCI Device\n");
496             v3_remove_device(dev);
497             return -1;
498         }
499         
500         pci_dev->config_header.vendor_id = VIRTIO_VENDOR_ID;
501         pci_dev->config_header.subsystem_vendor_id = VIRTIO_SUBVENDOR_ID;
502         
503
504         pci_dev->config_header.device_id = VIRTIO_CONSOLE_DEV_ID;
505         pci_dev->config_header.class = PCI_CLASS_DISPLAY;
506         pci_dev->config_header.subclass = PCI_DISPLAY_SUBCLASS_OTHER;
507     
508         pci_dev->config_header.subsystem_id = VIRTIO_CONSOLE_SUBDEVICE_ID;
509
510         pci_dev->config_header.intr_pin = 1;
511
512         pci_dev->config_header.max_latency = 1; // ?? (qemu does it...)
513
514
515         virtio_state->pci_dev = pci_dev;
516         virtio_state->pci_bus = pci_bus;
517     }
518
519     virtio_reset(virtio_state);
520
521     if (v3_dev_add_char_frontend(vm, dev_id, connect_fn, (void *)virtio_state) == -1) {
522         PrintError("Could not register %s as frontend\n", dev_id);
523         v3_remove_device(dev);
524         return -1;
525     }
526
527
528     return 0;
529 }
530
531
532 device_register("LNX_VIRTIO_CONSOLE", virtio_init)