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.


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