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.


vnet device updates
[palacios.git] / palacios / src / devices / lnx_virtio_vnet.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 <palacios/vm_guest_mem.h>
23 #include <devices/lnx_virtio_pci.h>
24 #include <palacios/vmm_vnet.h>
25 #include <palacios/vmm_sprintf.h>
26 #include <devices/pci.h>
27
28
29 #ifndef CONFIG_LINUX_VIRTIO_VNET_DEBUG
30 #undef PrintDebug
31 #define PrintDebug(fmt, args...)
32 #endif
33
34
35 #define QUEUE_SIZE 128
36 #define NUM_QUEUES 3
37
38 struct vnet_config {
39     uint32_t num_devs;
40     uint32_t num_routes;
41 } __attribute__((packed));
42
43
44 #define CTRL_QUEUE 0
45 #define XMIT_QUEUE 1
46 #define RECV_QUEUE 2
47
48 struct virtio_vnet_state {
49     struct v3_vm_info * vm;
50     struct vnet_config vnet_cfg;
51     struct virtio_config virtio_cfg;
52
53     struct vm_device * pci_bus;
54     struct pci_device * pci_dev;
55         
56     struct virtio_queue queue[NUM_QUEUES];
57
58     struct virtio_queue * cur_queue;
59
60     int io_range_size;
61     v3_lock_t lock;
62 };
63
64 #define VNET_GET_ROUTES 10
65 #define VNET_ADD_ROUTE 11
66 #define VNET_DEL_ROUTE 12
67
68 #define VNET_GET_LINKS 20
69 #define VNET_ADD_LINK 21
70 #define VNET_DEL_LINK 22
71
72 // structure of the vnet command header
73 struct vnet_ctrl_hdr {
74     uint8_t cmd_type;
75     uint32_t num_cmds;
76 } __attribute__((packed));
77
78
79 struct vnet_virtio_pkt {
80     uint32_t link_id;
81     uint32_t pkt_size;
82     uint8_t pkt[1500];
83 };
84
85 static int virtio_reset(struct virtio_vnet_state * vnet_state) {
86
87     memset(vnet_state->queue, 0, sizeof(struct virtio_queue) * 2);
88
89     vnet_state->cur_queue = &(vnet_state->queue[0]);
90
91     vnet_state->virtio_cfg.status = 0;
92     vnet_state->virtio_cfg.pci_isr = 0;
93
94     vnet_state->queue[0].queue_size = QUEUE_SIZE;
95     vnet_state->queue[1].queue_size = QUEUE_SIZE;
96     vnet_state->queue[2].queue_size = QUEUE_SIZE;
97
98     memset(&(vnet_state->vnet_cfg), 0, sizeof(struct vnet_config));
99     v3_lock_init(&(vnet_state->lock));
100
101     return 0;
102 }
103
104
105
106 static int get_desc_count(struct virtio_queue * q, int index) {
107     struct vring_desc * tmp_desc = &(q->desc[index]);
108     int cnt = 1;
109     
110     while (tmp_desc->flags & VIRTIO_NEXT_FLAG) {
111         tmp_desc = &(q->desc[tmp_desc->next]);
112         cnt++;
113     }
114
115     return cnt;
116 }
117
118
119
120
121 static int handle_cmd_kick(struct guest_info * core, struct virtio_vnet_state * vnet_state) {
122     struct virtio_queue * q = &(vnet_state->queue[0]);
123     
124     PrintDebug("VNET Bridge: Handling command  queue\n");
125
126     while (q->cur_avail_idx != q->avail->index) {
127         struct vring_desc * hdr_desc = NULL;
128         struct vring_desc * buf_desc = NULL;
129         struct vring_desc * status_desc = NULL;
130         uint16_t desc_idx = q->avail->ring[q->cur_avail_idx % QUEUE_SIZE];
131         uint16_t desc_cnt = get_desc_count(q, desc_idx);
132         struct vnet_ctrl_hdr * hdr = NULL;
133         int i;
134         int xfer_len = 0;
135         uint8_t * status_ptr = NULL;
136         uint8_t status = 0;
137
138
139         PrintDebug("Descriptor Count=%d, index=%d, desc_idx=%d\n", desc_cnt, q->cur_avail_idx % QUEUE_SIZE, desc_idx);
140
141         if (desc_cnt < 3) {
142             PrintError("VNET Bridge cmd must include at least 3 descriptors (cnt=%d)\n", desc_cnt);
143             return -1;
144         }
145         
146         hdr_desc = &(q->desc[desc_idx]);
147
148         if (guest_pa_to_host_va(core, hdr_desc->addr_gpa, (addr_t *)&hdr) == -1) {
149             PrintError("Could not translate VirtioVNET header address\n");
150             return -1;
151         }
152
153         desc_idx = hdr_desc->next;
154         
155         if (hdr->cmd_type == VNET_ADD_ROUTE) {
156             
157             for (i = 0; i < hdr->num_cmds; i++) {
158                 uint8_t tmp_status = 0;
159                 struct v3_vnet_route * route = NULL;
160                 
161                 buf_desc = &(q->desc[desc_idx]);
162
163                 if (guest_pa_to_host_va(core, buf_desc->addr_gpa, (addr_t *)&(route)) == -1) {
164                     PrintError("Could not translate route address\n");
165                     return -1;
166                 }
167
168                 // add route
169                 PrintDebug("Adding VNET Route\n");
170
171                 tmp_status = v3_vnet_add_route(*route);
172
173                 PrintDebug("VNET Route Added\n");
174
175                 if (tmp_status != 0) {
176                     PrintError("Error adding VNET ROUTE\n");
177                     status = tmp_status;
178                 }
179
180                 xfer_len += buf_desc->length;
181                 desc_idx = buf_desc->next;
182             }
183
184         } 
185
186
187
188         status_desc = &(q->desc[desc_idx]);
189
190         if (guest_pa_to_host_va(core, status_desc->addr_gpa, (addr_t *)&status_ptr) == -1) {
191             PrintError("VirtioVNET Error could not translate status address\n");
192             return -1;
193         }
194
195         xfer_len += status_desc->length;
196         *status_ptr = status;
197
198         PrintDebug("Transferred %d bytes (xfer_len)\n", xfer_len);
199         q->used->ring[q->used->index % QUEUE_SIZE].id = q->avail->ring[q->cur_avail_idx % QUEUE_SIZE];
200         q->used->ring[q->used->index % QUEUE_SIZE].length = xfer_len; // set to total inbound xfer length
201
202         q->used->index++;
203         q->cur_avail_idx++;
204     }
205
206
207     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
208         PrintDebug("Raising IRQ %d\n",  vnet_state->pci_dev->config_header.intr_line);
209         v3_pci_raise_irq(vnet_state->pci_bus, 0, vnet_state->pci_dev);
210         vnet_state->virtio_cfg.pci_isr = 1;
211     }
212
213
214     return 0;
215 }
216
217
218 static int vnet_pkt_input_cb(struct v3_vm_info * vm,  struct v3_vnet_pkt * pkt,  void * private_data){
219     struct virtio_vnet_state * vnet_state = (struct virtio_vnet_state *)private_data;
220     struct virtio_queue * q = &(vnet_state->queue[RECV_QUEUE]);
221     int ret_val = -1;
222     unsigned long flags;
223
224     flags = v3_lock_irqsave(vnet_state->lock);
225         
226     PrintDebug("VNET Bridge: RX: pkt sent to guest size: %d\n, pkt_header_len: %d\n", data_len, pkt_head_len);
227
228     if (q->ring_avail_addr == 0) {
229         PrintError("Queue is not set\n");
230         goto exit;
231     }
232
233
234     if (q->cur_avail_idx != q->avail->index) {
235         uint16_t pkt_idx = q->avail->ring[q->cur_avail_idx % q->queue_size];
236         struct vring_desc * pkt_desc = NULL;
237         struct vnet_virtio_pkt * virtio_pkt = NULL;
238
239
240         pkt_desc = &(q->desc[pkt_idx]);
241         PrintDebug("VNET Bridge RX: buffer desc len: %d\n", pkt_desc->length);
242
243         if (guest_pa_to_host_va(&(vm->cores[0]), pkt_desc->addr_gpa, (addr_t *)&(virtio_pkt)) == -1) {
244             PrintError("Could not translate buffer address\n");
245             return -1;
246         }
247
248         // Fill in dst packet buffer
249         virtio_pkt->link_id = pkt->dst_id;
250         virtio_pkt->pkt_size = pkt->size;
251         memcpy(virtio_pkt->pkt, pkt->data, pkt->size);
252
253         
254         q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size];
255         q->used->ring[q->used->index % q->queue_size].length = sizeof(struct vnet_virtio_pkt); // This should be the total length of data sent to guest (header+pkt_data)
256
257         q->used->index++;
258         q->cur_avail_idx++;
259     } else {
260         PrintError("Packet buffer overflow in the guest\n");
261     }
262
263     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
264         v3_pci_raise_irq(vnet_state->pci_bus, 0, vnet_state->pci_dev);
265         vnet_state->virtio_cfg.pci_isr = 0x1;
266         PrintDebug("Raising IRQ %d\n",  vnet_state->pci_dev->config_header.intr_line);
267     }
268
269
270     ret_val = 0;
271
272 exit:
273     v3_unlock_irqrestore(vnet_state->lock, flags);
274  
275     return ret_val;
276 }
277
278
279 static int handle_pkt_kick(struct guest_info *core, struct virtio_vnet_state * vnet_state) 
280 {
281     struct virtio_queue * q = &(vnet_state->queue[XMIT_QUEUE]);
282
283     PrintDebug("VNET Bridge Device: Handle TX\n");
284
285     while (q->cur_avail_idx != q->avail->index) {
286         uint16_t desc_idx = q->avail->ring[q->cur_avail_idx % q->queue_size];
287         struct vring_desc * pkt_desc = NULL;
288         struct vnet_virtio_pkt * virtio_pkt = NULL;
289
290         pkt_desc = &(q->desc[desc_idx]);
291
292         PrintDebug("VNET Bridge: Handle TX buf_len: %d\n", pkt_desc->length);
293
294         if (guest_pa_to_host_va(core, pkt_desc->addr_gpa, (addr_t *)&(virtio_pkt)) == -1) {
295             PrintError("Could not translate buffer address\n");
296             return -1;
297         }
298
299         //TODO:  SETUP VNET PACKET data structure
300
301         /*
302           if (v3_vnet_send_pkt(pkt, (void *)core) == -1) {
303             PrintError("Error sending packet to vnet\n");
304             return -1;
305         }       
306         */
307         q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size];
308         q->used->ring[q->used->index % q->queue_size].length = pkt_desc->length; // What do we set this to????
309         q->used->index++;
310
311         q->cur_avail_idx++;
312     }
313
314     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
315         v3_pci_raise_irq(vnet_state->pci_bus, 0, vnet_state->pci_dev);
316         vnet_state->virtio_cfg.pci_isr = 0x1;
317     }
318
319 #ifdef CONFIG_VNET_PROFILE
320     uint64_t time;
321     rdtscll(time);
322     core->vnet_times.total_handle_time = time - core->vnet_times.virtio_handle_start;
323     core->vnet_times.print = true;
324 #endif
325
326     return 0;
327 }
328
329 static int virtio_io_write(struct guest_info * core, uint16_t port, void * src, uint_t length, void * private_data) {
330     struct virtio_vnet_state * vnet_state = (struct virtio_vnet_state *)private_data;
331     int port_idx = port % vnet_state->io_range_size;
332
333
334     PrintDebug("VNET Bridge: VIRTIO VNET Write for port %d len=%d, value=%x\n", 
335                port, length, *(uint32_t *)src);
336     PrintDebug("VNET Bridge: port idx=%d\n", port_idx);
337
338
339     switch (port_idx) {
340         case GUEST_FEATURES_PORT:
341             if (length != 4) {
342                 PrintError("Illegal write length for guest features\n");
343                 return -1;
344             }    
345             vnet_state->virtio_cfg.guest_features = *(uint32_t *)src;
346
347             break;
348         case VRING_PG_NUM_PORT:
349             if (length == 4) {
350                 addr_t pfn = *(uint32_t *)src;
351                 addr_t page_addr = (pfn << VIRTIO_PAGE_SHIFT);
352
353                 vnet_state->cur_queue->pfn = pfn;
354                 
355                 vnet_state->cur_queue->ring_desc_addr = page_addr ;
356                 vnet_state->cur_queue->ring_avail_addr = page_addr + (QUEUE_SIZE * sizeof(struct vring_desc));
357                 vnet_state->cur_queue->ring_used_addr = ( vnet_state->cur_queue->ring_avail_addr + \
358                                                  sizeof(struct vring_avail)    + \
359                                                  (QUEUE_SIZE * sizeof(uint16_t)));
360                 
361                 // round up to next page boundary.
362                 vnet_state->cur_queue->ring_used_addr = (vnet_state->cur_queue->ring_used_addr + 0xfff) & ~0xfff;
363
364                 if (guest_pa_to_host_va(core, vnet_state->cur_queue->ring_desc_addr, (addr_t *)&(vnet_state->cur_queue->desc)) == -1) {
365                     PrintError("Could not translate ring descriptor address\n");
366                     return -1;
367                 }
368
369                 if (guest_pa_to_host_va(core, vnet_state->cur_queue->ring_avail_addr, (addr_t *)&(vnet_state->cur_queue->avail)) == -1) {
370                     PrintError("Could not translate ring available address\n");
371                     return -1;
372                 }
373
374                 if (guest_pa_to_host_va(core, vnet_state->cur_queue->ring_used_addr, (addr_t *)&(vnet_state->cur_queue->used)) == -1) {
375                     PrintError("Could not translate ring used address\n");
376                     return -1;
377                 }
378
379                 PrintDebug("VNET Bridge: RingDesc_addr=%p, Avail_addr=%p, Used_addr=%p\n",
380                            (void *)(vnet_state->cur_queue->ring_desc_addr),
381                            (void *)(vnet_state->cur_queue->ring_avail_addr),
382                            (void *)(vnet_state->cur_queue->ring_used_addr));
383
384                 PrintDebug("VNET Bridge: RingDesc=%p, Avail=%p, Used=%p\n", 
385                            vnet_state->cur_queue->desc, vnet_state->cur_queue->avail, vnet_state->cur_queue->used);
386
387             } else {
388                 PrintError("Illegal write length for page frame number\n");
389                 return -1;
390             }
391             break;
392         case VRING_Q_SEL_PORT:
393             vnet_state->virtio_cfg.vring_queue_selector = *(uint16_t *)src;
394
395             if (vnet_state->virtio_cfg.vring_queue_selector > NUM_QUEUES) {
396                 PrintError("VNET Bridge device has no qeueues. Selected %d\n", 
397                            vnet_state->virtio_cfg.vring_queue_selector);
398                 return -1;
399             }
400             
401             vnet_state->cur_queue = &(vnet_state->queue[vnet_state->virtio_cfg.vring_queue_selector]);
402
403             break;
404         case VRING_Q_NOTIFY_PORT: {
405             uint16_t queue_idx = *(uint16_t *)src;
406
407             PrintDebug("VNET Bridge: Handling Kick\n");
408
409             if (queue_idx == 0) {
410                 if (handle_cmd_kick(core, vnet_state) == -1) {
411                     PrintError("Could not handle Virtio VNET Control command\n");
412                     return -1;
413                 }
414             } else if (queue_idx == 1) {
415                 if (handle_pkt_kick(core, vnet_state) == -1){
416                     PrintError("Could not handle Virtio VNET TX\n");
417                     return -1;
418                 }
419             } else if (queue_idx == 2) {
420                 PrintDebug("VNET Bridge: receive kick on RX Queue\n");
421             } else {
422                 PrintError("VNET Bridge: Kick on invalid queue (%d)\n", queue_idx);
423                 return -1;
424             }
425
426             break;
427         }
428         case VIRTIO_STATUS_PORT:
429             vnet_state->virtio_cfg.status = *(uint8_t *)src;
430
431             if (vnet_state->virtio_cfg.status == 0) {
432                 PrintDebug("VNET Bridge: Resetting device\n");
433                 virtio_reset(vnet_state);
434             }
435
436             break;
437
438         case VIRTIO_ISR_PORT:
439             vnet_state->virtio_cfg.pci_isr = *(uint8_t *)src;
440             break;
441         default:
442             return -1;
443             break;
444     }
445
446     return length;
447 }
448
449
450 static int virtio_io_read(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * private_data) {
451
452     struct virtio_vnet_state * vnet_state = (struct virtio_vnet_state *)private_data;
453     int port_idx = port % vnet_state->io_range_size;
454
455 /*
456     PrintDebug("VirtioVNET: VIRTIO SYMBIOTIC Read  for port %d (index =%d), length=%d\n", 
457                port, port_idx, length);
458 */
459     switch (port_idx) {
460         case HOST_FEATURES_PORT:
461             if (length != 4) {
462                 PrintError("Illegal read length for host features\n");
463                 return -1;
464             }
465
466             *(uint32_t *)dst = vnet_state->virtio_cfg.host_features;
467         
468             break;
469         case VRING_PG_NUM_PORT:
470             if (length != 4) {
471                 PrintError("Illegal read length for page frame number\n");
472                 return -1;
473             }
474
475             *(uint32_t *)dst = vnet_state->cur_queue->pfn;
476
477             break;
478         case VRING_SIZE_PORT:
479             if (length != 2) {
480                 PrintError("Illegal read length for vring size\n");
481                 return -1;
482             }
483                 
484             *(uint16_t *)dst = vnet_state->cur_queue->queue_size;
485
486             break;
487
488         case VIRTIO_STATUS_PORT:
489             if (length != 1) {
490                 PrintError("Illegal read length for status\n");
491                 return -1;
492             }
493
494             *(uint8_t *)dst = vnet_state->virtio_cfg.status;
495             break;
496
497         case VIRTIO_ISR_PORT:
498             *(uint8_t *)dst = vnet_state->virtio_cfg.pci_isr;
499             vnet_state->virtio_cfg.pci_isr = 0;
500             v3_pci_lower_irq(vnet_state->pci_bus, 0, vnet_state->pci_dev);
501             break;
502
503         default:
504             if ( (port_idx >= sizeof(struct virtio_config)) && 
505                  (port_idx < (sizeof(struct virtio_config) + sizeof(struct vnet_config))) ) {
506                 int cfg_offset = port_idx - sizeof(struct virtio_config);
507                 uint8_t * cfg_ptr = (uint8_t *)&(vnet_state->vnet_cfg);
508
509                 memcpy(dst, cfg_ptr + cfg_offset, length);
510                 
511             } else {
512                 PrintError("Read of Unhandled Virtio Read\n");
513                 return -1;
514             }
515           
516             break;
517     }
518
519     return length;
520 }
521
522
523
524 static struct v3_device_ops dev_ops = {
525     .free = NULL,
526     .reset = NULL,
527     .start = NULL,
528     .stop = NULL,
529 };
530
531
532 static int dev_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
533     struct vm_device * pci_bus = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
534     struct virtio_vnet_state * vnet_state = NULL;
535     struct pci_device * pci_dev = NULL;
536     char * name = v3_cfg_val(cfg, "name");
537
538     PrintDebug("VNET Bridge: Initializing VNET Bridge Control device: %s\n", name);
539
540     if (pci_bus == NULL) {
541         PrintError("VNET Bridge device require a PCI Bus");
542         return -1;
543     }
544     
545     vnet_state  = (struct virtio_vnet_state *)V3_Malloc(sizeof(struct virtio_vnet_state));
546     memset(vnet_state, 0, sizeof(struct virtio_vnet_state));
547         
548     vnet_state->vm = vm;
549
550     struct vm_device * dev = v3_allocate_device(name, &dev_ops, vnet_state);
551
552     if (v3_attach_device(vm, dev) == -1) {
553         PrintError("Could not attach device %s\n", name);
554         return -1;
555     }
556
557
558     // PCI initialization
559     {
560         struct v3_pci_bar bars[6];
561         int num_ports = sizeof(struct virtio_config) + sizeof(struct vnet_config);
562         int tmp_ports = num_ports;
563         int i;
564
565         // This gets the number of ports, rounded up to a power of 2
566         vnet_state->io_range_size = 1; // must be a power of 2
567
568         while (tmp_ports > 0) {
569             tmp_ports >>= 1;
570             vnet_state->io_range_size <<= 1;
571         }
572         
573         // this is to account for any low order bits being set in num_ports
574         // if there are none, then num_ports was already a power of 2 so we shift right to reset it
575         if ((num_ports & ((vnet_state->io_range_size >> 1) - 1)) == 0) {
576             vnet_state->io_range_size >>= 1;
577         }
578
579         for (i = 0; i < 6; i++) {
580             bars[i].type = PCI_BAR_NONE;
581         }
582
583         bars[0].type = PCI_BAR_IO;
584         bars[0].default_base_port = -1;
585         bars[0].num_ports = vnet_state->io_range_size;
586         bars[0].io_read = virtio_io_read;
587         bars[0].io_write = virtio_io_write;
588         bars[0].private_data = vnet_state;
589
590         pci_dev = v3_pci_register_device(pci_bus, PCI_STD_DEVICE, 
591                                          0, PCI_AUTO_DEV_NUM, 0,
592                                          "LNX_VIRTIO_VNET", bars,
593                                          NULL, NULL, NULL, vnet_state);
594
595         if (!pci_dev) {
596             PrintError("Could not register PCI Device\n");
597             return -1;
598         }
599         
600         pci_dev->config_header.vendor_id = VIRTIO_VENDOR_ID;
601         pci_dev->config_header.subsystem_vendor_id = VIRTIO_SUBVENDOR_ID;
602         pci_dev->config_header.device_id = VIRTIO_VNET_DEV_ID;
603         pci_dev->config_header.class = PCI_CLASS_MEMORY;
604         pci_dev->config_header.subclass = PCI_MEM_SUBCLASS_RAM;
605         pci_dev->config_header.subsystem_id = VIRTIO_VNET_SUBDEVICE_ID;
606         pci_dev->config_header.intr_pin = 1;
607         pci_dev->config_header.max_latency = 1; // ?? (qemu does it...)
608
609
610         vnet_state->pci_dev = pci_dev;
611         vnet_state->pci_bus = pci_bus;
612     }
613
614     virtio_reset(vnet_state);
615
616     v3_vnet_add_bridge(vm, vnet_pkt_input_cb, (void *)vnet_state);
617
618     return 0;
619 }
620
621
622 device_register("LNX_VIRTIO_VNET", dev_init)