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.


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