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.


Minor fix
[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 8192
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;
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 (guest_pa_to_host_va(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 (guest_pa_to_host_va(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 (guest_pa_to_host_va(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             //if(q->cur_avail_idx % 100 == 0)
255                // PrintError("cur_avai_idx %d, idx: %d\n", q->cur_avail_idx, q->avail->index);
256
257             pkt_desc = &(q->desc[pkt_idx]);
258             PrintDebug("VNET Bridge RX: buffer desc len: %d\n", pkt_desc->length);
259
260             if (guest_pa_to_host_va(&(vm->cores[0]), pkt_desc->addr_gpa, (addr_t *)&(virtio_pkt)) == -1) {
261                 PrintError("Could not translate buffer address\n");
262                 goto exit;
263             }
264
265             PrintDebug("VNET Bridge: RX: pkt sent to guest pkt size: %d, dst link: %d\n", pkt->size, pkt->dst_id);
266
267             // Fill in dst packet buffer
268             virtio_pkt->link_id = pkt->dst_id;
269             virtio_pkt->pkt_size = pkt->size;
270             memcpy(virtio_pkt->pkt, pkt->data, pkt->size);
271         
272             q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size];
273             q->used->ring[q->used->index % q->queue_size].length = sizeof(struct vnet_bridge_pkt); // This should be the total length of data sent to guest (header+pkt_data)
274
275             q->used->index++;
276             q->cur_avail_idx++;
277         } else {
278             //PrintError("VNET Bridge: guest RX buffer full: cur_avai_idx %d, idx: %d\nDisable Bridge\n", q->cur_avail_idx, q->avail->index);
279             vnet_state->pkt_drop ++;
280             v3_vnet_disable_bridge();
281         }
282     }
283
284     if(sent == 0){
285         goto exit;
286     }
287
288     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
289         v3_pci_raise_irq(vnet_state->pci_bus, 0, vnet_state->pci_dev);
290         vnet_state->virtio_cfg.pci_isr = 0x1;
291         PrintDebug("Raising IRQ %d\n",  vnet_state->pci_dev->config_header.intr_line);
292     }
293
294     ret_val = 0;
295
296 exit:
297         
298 #ifdef CONFIG_VNET_PROFILE
299     if (vnet_state->pkt_recv % 10000 == 0)
300         PrintError("Vnet Bridge: sent: %ld, rxed: %ld, dropped: %ld\n",
301                         vnet_state->pkt_sent,
302                         vnet_state->pkt_recv,
303                         vnet_state->pkt_drop);
304 #endif
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
321     while (q->cur_avail_idx != q->avail->index) {
322         uint16_t desc_idx = q->avail->ring[q->cur_avail_idx % q->queue_size];
323         struct vring_desc * pkt_desc = NULL;
324         struct vnet_bridge_pkt * virtio_pkt = NULL;
325
326         pkt_desc = &(q->desc[desc_idx]);
327
328         PrintDebug("VNET Bridge: Handle TX desc buf_len: %d\n", pkt_desc->length);
329         
330         if (guest_pa_to_host_va(core, pkt_desc->addr_gpa, (addr_t *)&(virtio_pkt)) == -1) {
331             PrintError("Could not translate buffer address\n");
332             return -1;
333         }
334
335         PrintDebug("VNET Bridge: TX: on cpu %d pkt size: %d, dst link: %d\n", cpu, virtio_pkt->pkt_size, virtio_pkt->link_id);
336         
337         v3_vnet_bridge_rx(virtio_pkt->pkt, virtio_pkt->pkt_size, virtio_pkt->link_id);
338
339         q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size];
340         q->used->ring[q->used->index % q->queue_size].length = pkt_desc->length; // What do we set this to????
341         q->used->index++;
342
343         vnet_state->pkt_sent ++;
344
345         q->cur_avail_idx++;
346     }
347
348     //interrupt the vnet to poll pkts
349     int cpu = V3_Get_CPU();
350     cpu = (cpu == 0)?1:0;
351     v3_interrupt_cpu(vnet_state->vm, cpu, V3_VNET_POLLING_VECTOR);
352
353     if((vnet_state->pkt_sent % (QUEUE_SIZE/20)) == 0) { //optimized for guest's, batch the interrupts
354             if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
355                 v3_pci_raise_irq(vnet_state->pci_bus, 0, vnet_state->pci_dev);
356                 vnet_state->virtio_cfg.pci_isr = 0x1;
357             }
358     }
359
360 #ifdef CONFIG_VNET_PROFILE
361     if (vnet_state->pkt_sent % 10000 == 0)
362         PrintError("Vnet Bridge: sent: %ld, rxed: %ld, dropped: %ld\n",
363                         vnet_state->pkt_sent,
364                         vnet_state->pkt_recv,
365                         vnet_state->pkt_drop);
366 #endif
367
368     return 0;
369 }
370
371
372 static int handle_rx_kick(struct guest_info *core, struct virtio_vnet_state * vnet_state) 
373 {
374     v3_vnet_enable_bridge();
375         
376     return 0;
377 }
378
379 static int vnet_virtio_io_write(struct guest_info * core, uint16_t port, void * src, uint_t length, void * private_data) {
380     struct virtio_vnet_state * vnet_state = (struct virtio_vnet_state *)private_data;
381     int port_idx = port % vnet_state->io_range_size;
382
383     PrintDebug("VNET Bridge: VIRTIO VNET Write for port %d len=%d, value=%x\n", 
384                port, length, *(uint32_t *)src);
385     PrintDebug("VNET Bridge: port idx=%d\n", port_idx);
386
387
388     switch (port_idx) {
389         case GUEST_FEATURES_PORT:
390             if (length != 4) {
391                 PrintError("Illegal write length for guest features\n");
392                 return -1;
393             }    
394             vnet_state->virtio_cfg.guest_features = *(uint32_t *)src;
395
396             break;
397         case VRING_PG_NUM_PORT:
398             if (length == 4) {
399                 addr_t pfn = *(uint32_t *)src;
400                 addr_t page_addr = (pfn << VIRTIO_PAGE_SHIFT);
401
402                 vnet_state->cur_queue->pfn = pfn;
403                 
404                 vnet_state->cur_queue->ring_desc_addr = page_addr ;
405                 vnet_state->cur_queue->ring_avail_addr = page_addr + (QUEUE_SIZE * sizeof(struct vring_desc));
406                 vnet_state->cur_queue->ring_used_addr = ( vnet_state->cur_queue->ring_avail_addr + \
407                                                  sizeof(struct vring_avail)    + \
408                                                  (QUEUE_SIZE * sizeof(uint16_t)));
409                 
410                 // round up to next page boundary.
411                 vnet_state->cur_queue->ring_used_addr = (vnet_state->cur_queue->ring_used_addr + 0xfff) & ~0xfff;
412
413                 if (guest_pa_to_host_va(core, vnet_state->cur_queue->ring_desc_addr, (addr_t *)&(vnet_state->cur_queue->desc)) == -1) {
414                     PrintError("Could not translate ring descriptor address\n");
415                     return -1;
416                 }
417
418                 if (guest_pa_to_host_va(core, vnet_state->cur_queue->ring_avail_addr, (addr_t *)&(vnet_state->cur_queue->avail)) == -1) {
419                     PrintError("Could not translate ring available address\n");
420                     return -1;
421                 }
422
423                 if (guest_pa_to_host_va(core, vnet_state->cur_queue->ring_used_addr, (addr_t *)&(vnet_state->cur_queue->used)) == -1) {
424                     PrintError("Could not translate ring used address\n");
425                     return -1;
426                 }
427
428                 PrintDebug("VNET Bridge: RingDesc_addr=%p, Avail_addr=%p, Used_addr=%p\n",
429                            (void *)(vnet_state->cur_queue->ring_desc_addr),
430                            (void *)(vnet_state->cur_queue->ring_avail_addr),
431                            (void *)(vnet_state->cur_queue->ring_used_addr));
432
433                 PrintDebug("VNET Bridge: RingDesc=%p, Avail=%p, Used=%p\n", 
434                            vnet_state->cur_queue->desc, vnet_state->cur_queue->avail, vnet_state->cur_queue->used);
435
436                 if(vnet_state->queue[RECV_QUEUE].avail != NULL){
437                     vnet_state->ready = 1;
438                 }
439             } else {
440                 PrintError("Illegal write length for page frame number\n");
441                 return -1;
442             }
443             break;
444         case VRING_Q_SEL_PORT:
445             vnet_state->virtio_cfg.vring_queue_selector = *(uint16_t *)src;
446
447             if (vnet_state->virtio_cfg.vring_queue_selector > NUM_QUEUES) {
448                 PrintError("VNET Bridge device has no qeueues. Selected %d\n", 
449                            vnet_state->virtio_cfg.vring_queue_selector);
450                 return -1;
451             }
452             
453             vnet_state->cur_queue = &(vnet_state->queue[vnet_state->virtio_cfg.vring_queue_selector]);
454
455             break;
456         case VRING_Q_NOTIFY_PORT: {
457             uint16_t queue_idx = *(uint16_t *)src;
458
459             PrintDebug("VNET Bridge: Handling Kick\n");
460
461             if (queue_idx == 0) {
462                 if (handle_cmd_kick(core, vnet_state) == -1) {
463                     PrintError("Could not handle Virtio VNET Control command\n");
464                     return -1;
465                 }
466             } else if (queue_idx == 1) {
467                 if (handle_pkt_kick(core, vnet_state) == -1){
468                     PrintError("Could not handle Virtio VNET TX\n");
469                     return -1;
470                 }               
471             } else if (queue_idx == 2) {
472                 if (handle_rx_kick(core, vnet_state) == -1){
473                     PrintError("Could not handle Virtio RX buffer refills Kick\n");
474                     return -1;
475                 }
476             } else {
477                 PrintError("VNET Bridge: Kick on invalid queue (%d)\n", queue_idx);
478                 return -1;
479             }
480
481             break;
482         }
483         case VIRTIO_STATUS_PORT:
484             vnet_state->virtio_cfg.status = *(uint8_t *)src;
485
486             if (vnet_state->virtio_cfg.status == 0) {
487                 PrintDebug("VNET Bridge: Resetting device\n");
488                 virtio_reset(vnet_state);
489             }
490
491             break;
492
493         case VIRTIO_ISR_PORT:
494             vnet_state->virtio_cfg.pci_isr = *(uint8_t *)src;
495             break;
496         default:
497             return -1;
498             break;
499     }
500
501     return length;
502 }
503
504
505 static int vnet_virtio_io_read(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * private_data) {
506
507     struct virtio_vnet_state * vnet_state = (struct virtio_vnet_state *)private_data;
508     int port_idx = port % vnet_state->io_range_size;
509
510 /*
511     PrintDebug("VirtioVNET: VIRTIO SYMBIOTIC Read  for port %d (index =%d), length=%d\n", 
512                port, port_idx, length);
513 */
514     switch (port_idx) {
515         case HOST_FEATURES_PORT:
516             if (length != 4) {
517                 PrintError("Illegal read length for host features\n");
518                 return -1;
519             }
520
521             *(uint32_t *)dst = vnet_state->virtio_cfg.host_features;
522         
523             break;
524         case VRING_PG_NUM_PORT:
525             if (length != 4) {
526                 PrintError("Illegal read length for page frame number\n");
527                 return -1;
528             }
529
530             *(uint32_t *)dst = vnet_state->cur_queue->pfn;
531
532             break;
533         case VRING_SIZE_PORT:
534             if (length != 2) {
535                 PrintError("Illegal read length for vring size\n");
536                 return -1;
537             }
538                 
539             *(uint16_t *)dst = vnet_state->cur_queue->queue_size;
540
541             break;
542
543         case VIRTIO_STATUS_PORT:
544             if (length != 1) {
545                 PrintError("Illegal read length for status\n");
546                 return -1;
547             }
548
549             *(uint8_t *)dst = vnet_state->virtio_cfg.status;
550             break;
551
552         case VIRTIO_ISR_PORT:
553             *(uint8_t *)dst = vnet_state->virtio_cfg.pci_isr;
554             vnet_state->virtio_cfg.pci_isr = 0;
555             v3_pci_lower_irq(vnet_state->pci_bus, 0, vnet_state->pci_dev);
556             break;
557
558         default:
559             if ( (port_idx >= sizeof(struct virtio_config)) && 
560                  (port_idx < (sizeof(struct virtio_config) + sizeof(struct vnet_config))) ) {
561                 int cfg_offset = port_idx - sizeof(struct virtio_config);
562                 uint8_t * cfg_ptr = (uint8_t *)&(vnet_state->vnet_cfg);
563
564                 memcpy(dst, cfg_ptr + cfg_offset, length);
565                 
566             } else {
567                 PrintError("Read of Unhandled Virtio Read\n");
568                 return -1;
569             }
570           
571             break;
572     }
573
574     return length;
575 }
576
577
578
579 static struct v3_device_ops dev_ops = {
580     .free = NULL,
581     .reset = NULL,
582     .start = NULL,
583     .stop = NULL,
584 };
585
586 static int dev_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
587     struct vm_device * pci_bus = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
588     struct virtio_vnet_state * vnet_state = NULL;
589     struct pci_device * pci_dev = NULL;
590     char * name = v3_cfg_val(cfg, "name");
591
592     PrintDebug("VNET Bridge: Initializing VNET Bridge Control device: %s\n", name);
593
594     if (pci_bus == NULL) {
595         PrintError("VNET Bridge device require a PCI Bus");
596         return -1;
597     }
598     
599     vnet_state  = (struct virtio_vnet_state *)V3_Malloc(sizeof(struct virtio_vnet_state));
600     memset(vnet_state, 0, sizeof(struct virtio_vnet_state));
601         
602     vnet_state->vm = vm;
603
604     struct vm_device * dev = v3_allocate_device(name, &dev_ops, vnet_state);
605
606     if (v3_attach_device(vm, dev) == -1) {
607         PrintError("Could not attach device %s\n", name);
608         return -1;
609     }
610
611
612     // PCI initialization
613     {
614         struct v3_pci_bar bars[6];
615         int num_ports = sizeof(struct virtio_config) + sizeof(struct vnet_config);
616         int tmp_ports = num_ports;
617         int i;
618
619         // This gets the number of ports, rounded up to a power of 2
620         vnet_state->io_range_size = 1; // must be a power of 2
621
622         while (tmp_ports > 0) {
623             tmp_ports >>= 1;
624             vnet_state->io_range_size <<= 1;
625         }
626         
627         // this is to account for any low order bits being set in num_ports
628         // if there are none, then num_ports was already a power of 2 so we shift right to reset it
629         if ((num_ports & ((vnet_state->io_range_size >> 1) - 1)) == 0) {
630             vnet_state->io_range_size >>= 1;
631         }
632
633         for (i = 0; i < 6; i++) {
634             bars[i].type = PCI_BAR_NONE;
635         }
636
637         bars[0].type = PCI_BAR_IO;
638         bars[0].default_base_port = -1;
639         bars[0].num_ports = vnet_state->io_range_size;
640         bars[0].io_read = vnet_virtio_io_read;
641         bars[0].io_write = vnet_virtio_io_write;
642         bars[0].private_data = vnet_state;
643
644         pci_dev = v3_pci_register_device(pci_bus, PCI_STD_DEVICE, 
645                                          0, PCI_AUTO_DEV_NUM, 0,
646                                          "LNX_VIRTIO_VNET", bars,
647                                          NULL, NULL, NULL, vnet_state);
648
649         if (!pci_dev) {
650             PrintError("Could not register PCI Device\n");
651             return -1;
652         }
653         
654         pci_dev->config_header.vendor_id = VIRTIO_VENDOR_ID;
655         pci_dev->config_header.subsystem_vendor_id = VIRTIO_SUBVENDOR_ID;
656         pci_dev->config_header.device_id = VIRTIO_VNET_DEV_ID;
657         pci_dev->config_header.class = PCI_CLASS_MEMORY;
658         pci_dev->config_header.subclass = PCI_MEM_SUBCLASS_RAM;
659         pci_dev->config_header.subsystem_id = VIRTIO_VNET_SUBDEVICE_ID;
660         pci_dev->config_header.intr_pin = 1;
661         pci_dev->config_header.max_latency = 1; // ?? (qemu does it...)
662
663
664         vnet_state->pci_dev = pci_dev;
665         vnet_state->pci_bus = pci_bus;
666     }
667
668     virtio_reset(vnet_state);
669
670     V3_Print("Registering Virtio device as vnet bridge\n");
671     v3_vnet_add_bridge(vm, vnet_pkt_input_cb, vnet_pkt_input_xcall, 0, 500000, (void *)vnet_state);
672
673
674     return 0;
675 }
676
677
678 device_register("LNX_VIRTIO_VNET", dev_init)