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.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
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.
14 * Author: Jack Lange <jarusl@cs.northwestern.edu>
16 * This is free software. You are permitted to use,
17 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
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>
25 #include <devices/pci.h>
29 struct console_config {
32 } __attribute__((packed));
37 #define QUEUE_SIZE 128
39 /* Host Feature flags */
40 #define VIRTIO_CONSOLE_F_SIZE 0x1
42 struct virtio_console_state {
43 struct console_config cons_cfg;
44 struct virtio_config virtio_cfg;
46 struct vm_device * pci_bus;
47 struct pci_device * pci_dev;
49 struct virtio_queue queue[2];
51 struct v3_stream * stream;
54 struct virtio_queue * cur_queue;
56 struct v3_vm_info * vm;
61 struct v3_dev_char_ops * ops;
65 struct virtio_console_state * cons_state = NULL;
67 static int virtio_reset(struct virtio_console_state * virtio) {
69 memset(virtio->queue, 0, sizeof(struct virtio_queue) * 2);
71 virtio->cur_queue = &(virtio->queue[0]);
73 virtio->virtio_cfg.status = 0;
74 virtio->virtio_cfg.pci_isr = 0;
76 /* Console configuration */
77 // virtio->virtio_cfg.host_features = VIRTIO_NOTIFY_HOST;
79 // Virtio Console uses two queues
80 virtio->queue[0].queue_size = QUEUE_SIZE;
81 virtio->queue[1].queue_size = QUEUE_SIZE;
84 memset(&(virtio->cons_cfg), 0, sizeof(struct console_config));
89 static int get_desc_count(struct virtio_queue * q, int index) {
90 struct vring_desc * tmp_desc = &(q->desc[index]);
93 while (tmp_desc->flags & VIRTIO_NEXT_FLAG) {
94 tmp_desc = &(q->desc[tmp_desc->next]);
102 static int handle_kick(struct guest_info * core, struct virtio_console_state * virtio) {
103 struct virtio_queue * q = virtio->cur_queue;
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);
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);
113 uint32_t req_len = 0;
116 PrintDebug("Descriptor Count=%d, index=%d\n", desc_cnt, q->cur_avail_idx % QUEUE_SIZE);
118 for (i = 0; i < desc_cnt; i++) {
120 tmp_desc = &(q->desc[desc_idx]);
123 PrintDebug("Console output (ptr=%p) gpa=%p, len=%d, flags=%x, next=%d\n",
125 (void *)(addr_t)(tmp_desc->addr_gpa), tmp_desc->length,
126 tmp_desc->flags, tmp_desc->next);
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");
133 virtio->ops->output((uint8_t *)page_addr, tmp_desc->length, virtio->backend_data);
135 PrintDebug("Guest Console Currently Ignored\n");
137 req_len += tmp_desc->length;
138 desc_idx = tmp_desc->next;
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????
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;
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]);
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);
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;
173 input_desc = &(q->desc[input_idx]);
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");
180 memset(input_buf, 0, input_desc->length);
182 xfer_len = (input_desc->length > len) ? len : input_desc->length;
184 memcpy(input_buf, buf, xfer_len);
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;
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;
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;
210 PrintDebug("VIRTIO CONSOLE Write for port %d (index=%d) len=%d, value=%x\n",
211 port, port_idx, length, *(uint32_t *)src);
216 case GUEST_FEATURES_PORT:
218 PrintError("Illegal write length for guest features\n");
222 virtio->virtio_cfg.guest_features = *(uint32_t *)src;
225 case VRING_PG_NUM_PORT:
227 addr_t pfn = *(uint32_t *)src;
228 addr_t page_addr = (pfn << VIRTIO_PAGE_SHIFT);
231 virtio->cur_queue->pfn = pfn;
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)));
239 // round up to next page boundary.
240 virtio->cur_queue->ring_used_addr = (virtio->cur_queue->ring_used_addr + 0xfff) & ~0xfff;
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");
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");
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");
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));
264 PrintDebug("RingDesc=%p, Avail=%p, Used=%p\n",
265 virtio->cur_queue->desc, virtio->cur_queue->avail, virtio->cur_queue->used);
268 PrintError("Illegal write length for page frame number\n");
272 case VRING_Q_SEL_PORT:
273 virtio->virtio_cfg.vring_queue_selector = *(uint16_t *)src;
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);
281 virtio->cur_queue = &(virtio->queue[virtio->virtio_cfg.vring_queue_selector]);
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");
291 case VIRTIO_STATUS_PORT:
292 virtio->virtio_cfg.status = *(uint8_t *)src;
294 if (virtio->virtio_cfg.status == 0) {
295 PrintDebug("Resetting device\n");
296 virtio_reset(virtio);
301 case VIRTIO_ISR_PORT:
302 virtio->virtio_cfg.pci_isr = *(uint8_t *)src;
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;
318 PrintDebug("VIRTIO CONSOLE Read for port %d (index =%d), length=%d\n",
319 port, port_idx, length);
322 case HOST_FEATURES_PORT:
324 PrintError("Illegal read length for host features\n");
328 *(uint32_t *)dst = virtio->virtio_cfg.host_features;
331 case VRING_PG_NUM_PORT:
333 PrintError("Illegal read length for page frame number\n");
337 *(uint32_t *)dst = virtio->cur_queue->pfn;
340 case VRING_SIZE_PORT:
342 PrintError("Illegal read length for vring size\n");
346 *(uint16_t *)dst = virtio->cur_queue->queue_size;
350 case VIRTIO_STATUS_PORT:
352 PrintError("Illegal read length for status\n");
356 *(uint8_t *)dst = virtio->virtio_cfg.status;
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);
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);
371 memcpy(dst, cfg_ptr + cfg_offset, length);
374 PrintError("Read of Unhandled Virtio Read\n");
387 static int connect_fn(struct v3_vm_info * vm,
388 void * frontend_data,
389 struct v3_dev_char_ops * ops,
392 void ** push_fn_arg) {
394 struct virtio_console_state * state = (struct virtio_console_state *)frontend_data;
397 state->backend_data = private_data;
399 state->ops->input = virtio_input;
400 *push_fn_arg = state;
405 static int virtio_free(struct virtio_console_state * virtio) {
407 // unregister from PCI
414 static struct v3_device_ops dev_ops = {
415 .free = (int (*)(void *))virtio_free,
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");
428 PrintDebug("Initializing VIRTIO Console device\n");
430 if (pci_bus == NULL) {
431 PrintError("VirtIO devices require a PCI Bus");
436 virtio_state = (struct virtio_console_state *)V3_Malloc(sizeof(struct virtio_console_state));
437 memset(virtio_state, 0, sizeof(struct virtio_console_state));
440 cons_state = virtio_state;
445 struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, virtio_state);
448 PrintError("Could not attach device %s\n", dev_id);
449 V3_Free(virtio_state);
453 // PCI initialization
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;
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
464 while (tmp_ports > 0) {
466 virtio_state->io_range_size <<= 1;
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;
476 for (i = 0; i < 6; i++) {
477 bars[i].type = PCI_BAR_NONE;
480 bars[0].type = PCI_BAR_IO;
481 bars[0].default_base_port = -1;
482 bars[0].num_ports = virtio_state->io_range_size;
484 bars[0].io_read = virtio_io_read;
485 bars[0].io_write = virtio_io_write;
486 bars[0].private_data = virtio_state;
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);
495 PrintError("Could not register PCI Device\n");
496 v3_remove_device(dev);
500 pci_dev->config_header.vendor_id = VIRTIO_VENDOR_ID;
501 pci_dev->config_header.subsystem_vendor_id = VIRTIO_SUBVENDOR_ID;
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;
508 pci_dev->config_header.subsystem_id = VIRTIO_CONSOLE_SUBDEVICE_ID;
510 pci_dev->config_header.intr_pin = 1;
512 pci_dev->config_header.max_latency = 1; // ?? (qemu does it...)
515 virtio_state->pci_dev = pci_dev;
516 virtio_state->pci_bus = pci_bus;
519 virtio_reset(virtio_state);
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);
532 device_register("LNX_VIRTIO_CONSOLE", virtio_init)