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.


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