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.


0c0f4bc7728bcf3c6d72c85860d15313304d7900
[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, virtio->pci_dev, 0);
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, cons_state->pci_dev, 0);
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, virtio->pci_dev, 0);
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
438     if (!virtio_state) {
439         PrintError("Cannot allocate in init\n");
440         return -1;
441     }
442
443     memset(virtio_state, 0, sizeof(struct virtio_console_state));
444     
445
446     cons_state = virtio_state;
447     cons_state->vm = vm;
448
449    
450
451     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, virtio_state);
452
453     if (dev == NULL) {
454         PrintError("Could not attach device %s\n", dev_id);
455         V3_Free(virtio_state);
456         return -1;
457     }
458
459     // PCI initialization
460     {
461         struct v3_pci_bar bars[6];
462         int num_ports = sizeof(struct virtio_config) + sizeof(struct console_config);
463         int tmp_ports = num_ports;
464         int i;
465
466
467         // This gets the number of ports, rounded up to a power of 2
468         virtio_state->io_range_size = 1; // must be a power of 2
469
470         while (tmp_ports > 0) {
471             tmp_ports >>= 1;
472             virtio_state->io_range_size <<= 1;
473         }
474         
475         // this is to account for any low order bits being set in num_ports
476         // if there are none, then num_ports was already a power of 2 so we shift right to reset it
477         if ((num_ports & ((virtio_state->io_range_size >> 1) - 1)) == 0) {
478             virtio_state->io_range_size >>= 1;
479         }
480
481
482         for (i = 0; i < 6; i++) {
483             bars[i].type = PCI_BAR_NONE;
484         }
485
486         bars[0].type = PCI_BAR_IO;
487         bars[0].default_base_port = -1;
488         bars[0].num_ports = virtio_state->io_range_size;
489
490         bars[0].io_read = virtio_io_read;
491         bars[0].io_write = virtio_io_write;
492         bars[0].private_data = virtio_state;
493         
494
495         pci_dev = v3_pci_register_device(pci_bus, PCI_STD_DEVICE, 
496                                          0, PCI_AUTO_DEV_NUM, 0,
497                                          "LNX_VIRTIO_CONSOLE", bars,
498                                          NULL, NULL, NULL, NULL, virtio_state);
499
500         if (!pci_dev) {
501             PrintError("Could not register PCI Device\n");
502             v3_remove_device(dev);
503             return -1;
504         }
505         
506         pci_dev->config_header.vendor_id = VIRTIO_VENDOR_ID;
507         pci_dev->config_header.subsystem_vendor_id = VIRTIO_SUBVENDOR_ID;
508         
509
510         pci_dev->config_header.device_id = VIRTIO_CONSOLE_DEV_ID;
511         pci_dev->config_header.class = PCI_CLASS_DISPLAY;
512         pci_dev->config_header.subclass = PCI_DISPLAY_SUBCLASS_OTHER;
513     
514         pci_dev->config_header.subsystem_id = VIRTIO_CONSOLE_SUBDEVICE_ID;
515
516         pci_dev->config_header.intr_pin = 1;
517
518         pci_dev->config_header.max_latency = 1; // ?? (qemu does it...)
519
520
521         virtio_state->pci_dev = pci_dev;
522         virtio_state->pci_bus = pci_bus;
523     }
524
525     virtio_reset(virtio_state);
526
527     if (v3_dev_add_char_frontend(vm, dev_id, connect_fn, (void *)virtio_state) == -1) {
528         PrintError("Could not register %s as frontend\n", dev_id);
529         v3_remove_device(dev);
530         return -1;
531     }
532
533
534     return 0;
535 }
536
537
538 device_register("LNX_VIRTIO_CONSOLE", virtio_init)