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.


Fix to vnet/virtio networking
[palacios.git] / palacios / src / devices / lnx_virtio_nic.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, Lei Xia <lxia@northwestern.edu>
11  * Copyright (c) 2008, Cui Zheng <cuizheng@cs.unm.edu>
12  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
13  * All rights reserved.
14  *
15  * Author: Lei Xia <lxia@northwestern.edu>
16  *             Cui Zheng <cuizheng@cs.unm.edu>
17  *               
18  *
19  * This is free software.  You are permitted to use,
20  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
21  */
22  
23 #include <palacios/vmm.h>
24 #include <palacios/vmm_dev_mgr.h>
25 #include <devices/lnx_virtio_pci.h>
26 #include <palacios/vm_guest_mem.h>
27 #include <palacios/vmm_sprintf.h>
28 #include <palacios/vmm_vnet.h>
29 #include <palacios/vmm_lock.h>
30 #include <palacios/vmm_util.h>
31
32 #include <devices/pci.h>
33
34
35 #ifndef CONFIG_DEBUG_VIRTIO_NET
36 #undef PrintDebug
37 #define PrintDebug(fmt, args...)
38 #endif
39
40 #define VIRTIO_NIC_PROFILE
41
42 #define VIRTIO_NET_S_LINK_UP    1       /* Link is up */
43 #define VIRTIO_NET_MAX_BUFSIZE (sizeof(struct virtio_net_hdr) + (64 << 10))
44
45 struct virtio_net_hdr {
46         uint8_t flags;
47
48 #define VIRTIO_NET_HDR_GSO_NONE         0       /* Not a GSO frame */
49         uint8_t gso_type;
50         uint16_t hdr_len;               /* Ethernet + IP + tcp/udp hdrs */
51         uint16_t gso_size;              /* Bytes to append to hdr_len per frame */
52         uint16_t csum_start;    /* Position to start checksumming from */
53         uint16_t csum_offset;   /* Offset after that to place checksum */
54 }__attribute__((packed));
55
56         
57 #define QUEUE_SIZE 1024
58 #define CTRL_QUEUE_SIZE 64
59 #define ETH_ALEN 6
60
61 struct virtio_net_config
62 {
63     uint8_t mac[ETH_ALEN]; //VIRTIO_NET_F_MAC
64     uint16_t status;
65 } __attribute__((packed));
66
67 struct virtio_dev_state {
68     struct vm_device * pci_bus;
69     struct list_head dev_list;
70     struct v3_vm_info *vm;
71 };
72
73 struct virtio_net_state {
74     struct virtio_net_config net_cfg;
75     struct virtio_config virtio_cfg;
76
77     struct vm_device * dev;
78     struct pci_device * pci_dev; 
79     int io_range_size;
80     
81     struct virtio_queue rx_vq;   //index 0, rvq in Linux virtio driver, handle packet to guest
82     struct virtio_queue tx_vq;   //index 1, svq in Linux virtio driver, handle packet from guest
83     struct virtio_queue ctrl_vq; //index 2, ctrol info from guest
84
85     ulong_t pkt_sent, pkt_recv, pkt_drop;
86
87     struct v3_dev_net_ops * net_ops;
88
89     v3_lock_t lock;
90
91     void * backend_data;
92     struct virtio_dev_state * virtio_dev;
93     struct list_head dev_link;
94 };
95
96 static int virtio_free(struct vm_device * dev) 
97 {
98         
99     return -1;
100 }
101
102 static int virtio_init_state(struct virtio_net_state * virtio) 
103 {
104     virtio->rx_vq.ring_desc_addr = 0;
105     virtio->rx_vq.ring_avail_addr = 0;
106     virtio->rx_vq.ring_used_addr = 0;
107     virtio->rx_vq.pfn = 0;
108     virtio->rx_vq.cur_avail_idx = 0;
109
110     virtio->tx_vq.ring_desc_addr = 0;
111     virtio->tx_vq.ring_avail_addr = 0;
112     virtio->tx_vq.ring_used_addr = 0;
113     virtio->tx_vq.pfn = 0;
114     virtio->tx_vq.cur_avail_idx = 0;
115
116     virtio->ctrl_vq.ring_desc_addr = 0;
117     virtio->ctrl_vq.ring_avail_addr = 0;
118     virtio->ctrl_vq.ring_used_addr = 0;
119     virtio->ctrl_vq.pfn = 0;
120     virtio->ctrl_vq.cur_avail_idx = 0;
121
122     virtio->virtio_cfg.host_features = 0;
123     //virtio->virtio_cfg.status = VIRTIO_NET_S_LINK_UP;
124     virtio->virtio_cfg.pci_isr = 0;
125
126     if (v3_lock_init(&(virtio->lock)) == -1){
127         PrintError("Virtio NIC: Failure to init lock for net_state\n");
128     }
129
130     virtio->pkt_sent = virtio->pkt_recv = virtio->pkt_drop = 0;
131
132     return 0;
133 }
134
135 static int pkt_tx(struct guest_info *core, struct virtio_net_state * virtio, struct vring_desc * buf_desc) 
136 {
137     uint8_t * buf = NULL;
138     uint32_t len = buf_desc->length;
139
140     PrintDebug("Virtio NIC: Virtio Pkt Sending, net_state: %p, pkt size: %d\n", virtio, len);
141
142     if (guest_pa_to_host_va(core, buf_desc->addr_gpa, (addr_t *)&(buf)) == -1) {
143         PrintError("Could not translate buffer address\n");
144         return -1;
145     }
146
147     if (virtio->net_ops->send(buf, len, (void *)core, NULL) == -1) {
148         return -1;
149     }
150
151     return 0;
152 }
153
154 static int build_receive_header(struct virtio_net_hdr * hdr, const void * buf, int raw) {
155     hdr->flags = 0;
156
157     if (!raw) {
158         memcpy(hdr, buf, sizeof(struct virtio_net_hdr));
159     } else {
160         memset(hdr, 0, sizeof(struct virtio_net_hdr));
161     }
162
163     return 0;
164 }
165
166 static int copy_data_to_desc(struct guest_info *core, 
167                                         struct virtio_net_state * virtio_state, 
168                                         struct vring_desc * desc, 
169                                         uchar_t * buf, 
170                                         uint_t buf_len) 
171 {
172     uint32_t len;
173     uint8_t * desc_buf = NULL;
174
175     if (guest_pa_to_host_va(core, desc->addr_gpa, (addr_t *)&(desc_buf)) == -1) {
176         PrintError("Could not translate buffer address\n");
177         return -1;
178     }
179     len = (desc->length < buf_len)?desc->length:buf_len;
180     memcpy(desc_buf, buf, len);
181
182     return len;
183 }
184
185
186
187
188 static int get_desc_count(struct virtio_queue * q, int index) {
189     struct vring_desc * tmp_desc = &(q->desc[index]);
190     int cnt = 1;
191     
192     while (tmp_desc->flags & VIRTIO_NEXT_FLAG) {
193         tmp_desc = &(q->desc[tmp_desc->next]);
194         cnt++;
195     }
196
197     return cnt;
198 }
199
200 static int handle_ctrl(struct guest_info *core, struct virtio_net_state * dev) {
201     return 0;
202 }
203
204 static int handle_pkt_tx(struct guest_info *core, struct virtio_net_state * virtio_state) 
205 {
206     struct virtio_queue * q = &(virtio_state->tx_vq);
207     struct virtio_net_hdr * hdr = NULL;
208
209     if (q->avail->index < q->last_avail_idx) {
210         q->idx_overflow = true;
211     }
212
213     q->last_avail_idx = q->avail->index;
214
215     while (q->cur_avail_idx < q->avail->index || 
216            (q->idx_overflow && q->cur_avail_idx < (q->avail->index + 65536))) {
217         struct vring_desc * hdr_desc = NULL;
218         addr_t hdr_addr = 0;
219         uint16_t desc_idx = q->avail->ring[q->cur_avail_idx % q->queue_size];
220         int desc_cnt = get_desc_count(q, desc_idx);
221         uint32_t req_len = 0;
222         int i = 0;
223
224         hdr_desc = &(q->desc[desc_idx]);
225         if (guest_pa_to_host_va(core, hdr_desc->addr_gpa, &(hdr_addr)) == -1) {
226             PrintError("Could not translate block header address\n");
227             return -1;
228         }
229
230         hdr = (struct virtio_net_hdr*)hdr_addr;
231         desc_idx = hdr_desc->next;
232         
233         for (i = 0; i < desc_cnt - 1; i++) {    
234             struct vring_desc * buf_desc = &(q->desc[desc_idx]);
235             if (pkt_tx(core, virtio_state, buf_desc) == -1) {
236                 PrintError("Error handling nic operation\n");
237                 return -1;
238             }
239
240             req_len += buf_desc->length;
241             desc_idx = buf_desc->next;
242         }
243         virtio_state->pkt_sent ++;
244
245         q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size];
246         q->used->ring[q->used->index % q->queue_size].length = req_len; // What do we set this to????
247         q->used->index++;
248
249         int last_idx = q->cur_avail_idx;
250
251         q->cur_avail_idx ++;
252
253         if (q->cur_avail_idx < last_idx) {
254             q->idx_overflow = false;
255         }
256     }
257
258     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
259         v3_pci_raise_irq(virtio_state->virtio_dev->pci_bus, 0, virtio_state->pci_dev);
260         virtio_state->virtio_cfg.pci_isr = 0x1;
261     }
262
263 #ifdef VIRTIO_NIC_PROFILE
264     if(virtio_state->pkt_sent % 10000 == 0)
265         PrintError("Virtio NIC: %p, pkt_sent: %ld\n", virtio_state, virtio_state->pkt_sent);
266 #endif  
267
268 #ifdef CONFIG_VNET_PROFILE
269     uint64_t time;
270     rdtscll(time);
271     core->vnet_times.total_handle_time = time - core->vnet_times.virtio_handle_start;
272
273     PrintError("Vnet_profiling: total_handle_time: %ld vnet_time: %ld  copy_from_guest: %ld copy_to_guest: %ld malloc_free: %ld, route_lookup: %ld\n", 
274                          (long)core->vnet_times.total_handle_time,
275                          (long)core->vnet_times.vnet_handle_time,
276                          (long)core->vnet_times.time_copy_from_guest,
277                          (long)core->vnet_times.time_copy_to_guest,
278                          (long)core->vnet_times.time_mallocfree,
279                          (long)core->vnet_times.time_route_lookup);
280 #endif
281
282     return 0;
283 }
284
285
286 static int virtio_setup_queue(struct guest_info *core, 
287                                                         struct virtio_net_state * virtio_state, 
288                                                         struct virtio_queue * queue, 
289                                                         addr_t pfn, 
290                                                         addr_t page_addr) {
291     queue->pfn = pfn;
292                 
293     queue->ring_desc_addr = page_addr;
294     queue->ring_avail_addr = page_addr + (queue->queue_size * sizeof(struct vring_desc));
295     queue->ring_used_addr = ((queue->ring_avail_addr) + 
296                              (sizeof(struct vring_avail)) + 
297                              (queue->queue_size * sizeof(uint16_t)));
298
299     // round up to next page boundary.
300     queue->ring_used_addr = (queue->ring_used_addr + 0xfff) & ~0xfff;
301     if (guest_pa_to_host_va(core, queue->ring_desc_addr, (addr_t *)&(queue->desc)) == -1) {
302         PrintError("Could not translate ring descriptor address\n");
303          return -1;
304     }
305  
306     if (guest_pa_to_host_va(core, queue->ring_avail_addr, (addr_t *)&(queue->avail)) == -1) {
307         PrintError("Could not translate ring available address\n");
308         return -1;
309     }
310
311     if (guest_pa_to_host_va(core, queue->ring_used_addr, (addr_t *)&(queue->used)) == -1) {
312         PrintError("Could not translate ring used address\n");
313         return -1;
314     }
315
316     PrintDebug("RingDesc_addr=%p, Avail_addr=%p, Used_addr=%p\n",
317                (void *)(queue->ring_desc_addr),
318                (void *)(queue->ring_avail_addr),
319                (void *)(queue->ring_used_addr));
320     
321     PrintDebug("RingDesc=%p, Avail=%p, Used=%p\n", 
322                queue->desc, queue->avail, queue->used);
323     
324     return 0;
325 }
326
327 static int virtio_io_write(struct guest_info *core, uint16_t port, void * src, uint_t length, void * private_data) 
328 {
329     struct virtio_net_state * virtio = (struct virtio_net_state *)private_data;
330     int port_idx = port % virtio->io_range_size;
331
332 #ifdef CONFIG_VNET_PROFILE
333     uint64_t time;
334     rdtscll(time);
335     core->vnet_times.virtio_handle_start = time;
336 #endif
337
338     PrintDebug("VIRTIO NIC %p Write for port %d (index=%d) len=%d, value=%x\n", private_data,
339                port, port_idx,  length, *(uint32_t *)src);
340
341     switch (port_idx) {
342         case GUEST_FEATURES_PORT:
343             if (length != 4) {
344                 PrintError("Illegal write length for guest features\n");
345                 return -1;
346             }       
347             virtio->virtio_cfg.guest_features = *(uint32_t *)src;
348             PrintDebug("Setting Guest Features to %x\n", virtio->virtio_cfg.guest_features);
349             break;
350                 
351         case VRING_PG_NUM_PORT:
352             if (length != 4) {
353                 PrintError("Illegal write length for page frame number\n");
354                 return -1;
355             }
356             addr_t pfn = *(uint32_t *)src;
357             addr_t page_addr = (pfn << VIRTIO_PAGE_SHIFT);
358             uint16_t queue_idx = virtio->virtio_cfg.vring_queue_selector;
359
360             PrintDebug("Virtio Write: pfn: %p, page_addr %p, queue_idx %d\n", (void *)pfn, (void *)page_addr, queue_idx);
361
362             switch (queue_idx) {
363                 case 0:
364                     virtio_setup_queue(core, virtio, &virtio->rx_vq, pfn, page_addr);
365                     break;
366                 case 1:
367                     virtio_setup_queue(core, virtio, &virtio->tx_vq, pfn, page_addr);
368                     break;
369                 case 2:
370                     virtio_setup_queue(core, virtio, &virtio->ctrl_vq, pfn, page_addr);
371                     break;          
372                 default:
373                     break;
374             }
375             break;
376                 
377         case VRING_Q_SEL_PORT:
378             virtio->virtio_cfg.vring_queue_selector = *(uint16_t *)src;
379             if (virtio->virtio_cfg.vring_queue_selector > 2) {
380                 PrintError("Virtio NIC device only uses 3 queue, selected %d\n", 
381                            virtio->virtio_cfg.vring_queue_selector);
382                 return -1;
383             }
384             break;
385                 
386         case VRING_Q_NOTIFY_PORT: 
387             {
388                 uint16_t queue_idx = *(uint16_t *)src;                  
389                 if (queue_idx == 0){
390                     PrintDebug("receive queue notification 0, packet get by Guest\n");
391                 } else if (queue_idx == 1){
392                     if (handle_pkt_tx(core, virtio) == -1) {
393                         PrintError("Could not handle NIC Notification\n");
394                         return -1;
395                     }
396                 } else if (queue_idx == 2){
397                     if (handle_ctrl(core, virtio) == -1) {
398                         PrintError("Could not handle NIC Notification\n");
399                         return -1;
400                     }
401                 } else {
402                     PrintError("Virtio NIC device only uses 3 queue, selected %d\n", 
403                                queue_idx);
404                 }       
405                 break;          
406             }
407         
408         case VIRTIO_STATUS_PORT:
409             virtio->virtio_cfg.status = *(uint8_t *)src;
410             if (virtio->virtio_cfg.status == 0) {
411                 PrintDebug("Resetting device\n");
412                 virtio_init_state(virtio);
413             }
414             break;
415
416         case VIRTIO_ISR_PORT:
417             virtio->virtio_cfg.pci_isr = *(uint8_t *)src;
418             break;
419         default:
420             return -1;
421             break;
422     }
423
424     return length;
425 }
426
427 static int virtio_io_read(struct guest_info *core, uint16_t port, void * dst, uint_t length, void * private_data) 
428 {
429     struct virtio_net_state * virtio = (struct virtio_net_state *)private_data;
430     int port_idx = port % virtio->io_range_size;
431     uint16_t queue_idx = virtio->virtio_cfg.vring_queue_selector;
432
433     PrintDebug("Virtio NIC %p: Read  for port %d (index =%d), length=%d\n", private_data,
434                port, port_idx, length);
435         
436     switch (port_idx) {
437         case HOST_FEATURES_PORT:
438             if (length != 4) {
439                 PrintError("Illegal read length for host features\n");
440                 return -1;
441             }
442             *(uint32_t *)dst = virtio->virtio_cfg.host_features;
443             break;
444
445         case VRING_PG_NUM_PORT:
446             if (length != 4) {
447                 PrintError("Illegal read length for page frame number\n");
448                 return -1;
449             }
450             switch (queue_idx) {
451                 case 0:
452                     *(uint32_t *)dst = virtio->rx_vq.pfn;
453                     break;
454                 case 1:
455                     *(uint32_t *)dst = virtio->tx_vq.pfn;
456                     break;      
457                 case 2:
458                     *(uint32_t *)dst = virtio->ctrl_vq.pfn;
459                     break;
460                 default:
461                     break;
462             }
463             break;
464
465         case VRING_SIZE_PORT:
466             if (length != 2) {
467                 PrintError("Illegal read length for vring size\n");
468                 return -1;
469             }
470             switch (queue_idx) {
471                 case 0:
472                     *(uint16_t *)dst = virtio->rx_vq.queue_size;
473                     break;
474                 case 1:
475                     *(uint16_t *)dst = virtio->tx_vq.queue_size;
476                     break;      
477                 case 2:
478                     *(uint16_t *)dst = virtio->ctrl_vq.queue_size;
479                     break;
480                 default:
481                     break;
482             }
483             PrintDebug("queue index: %d, value=0x%x\n", (int)queue_idx, *(uint16_t *)dst);
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             *(uint8_t *)dst = virtio->virtio_cfg.status;
492             break;
493                 
494         case VIRTIO_ISR_PORT:
495             *(uint8_t *)dst = virtio->virtio_cfg.pci_isr;
496             virtio->virtio_cfg.pci_isr = 0;
497             v3_pci_lower_irq(virtio->virtio_dev->pci_bus, 0, virtio->pci_dev);
498             break;
499
500         default:
501             PrintError("Virtio NIC: Read of Unhandled Virtio Read\n");
502             return -1;
503     }
504
505     return length;
506 }
507
508
509
510
511 static int virtio_rx(uint8_t * buf, uint32_t size, void * private_data) {
512     struct virtio_net_state * virtio = (struct virtio_net_state *)private_data;
513     struct virtio_queue * q = &(virtio->rx_vq);
514     struct virtio_net_hdr hdr;
515     uint32_t hdr_len = sizeof(struct virtio_net_hdr);
516     uint32_t data_len = size;
517     uint32_t offset = 0;
518     unsigned long flags;
519     int ret_val;
520     int raw = 1;
521
522     flags = v3_lock_irqsave(virtio->lock);
523         
524     PrintDebug("VIRTIO NIC: receiving packet to virtio nic %p, size:%d\n", virtio, size);
525
526     virtio->pkt_recv ++;
527
528     if (!raw){
529         data_len -= hdr_len;
530     }
531
532     build_receive_header(&hdr, buf, raw);
533
534     if (q->ring_avail_addr == 0) {
535         PrintError("Queue is not set\n");
536         ret_val = -1;
537         goto exit;
538     }
539
540     if (q->last_avail_idx > q->avail->index)
541         q->idx_overflow = true;
542     q->last_avail_idx = q->avail->index;
543
544     if (q->cur_avail_idx < q->avail->index || (q->idx_overflow && q->cur_avail_idx < q->avail->index+65536)){
545         addr_t hdr_addr = 0;
546         uint16_t hdr_idx = q->avail->ring[q->cur_avail_idx % q->queue_size];
547         uint16_t buf_idx = 0;
548         struct vring_desc * hdr_desc = NULL;
549
550         hdr_desc = &(q->desc[hdr_idx]);
551         if (guest_pa_to_host_va(&(virtio->virtio_dev->vm->cores[0]), hdr_desc->addr_gpa, &(hdr_addr)) == -1) {
552             PrintError("Could not translate receive buffer address\n");
553             ret_val = -1;
554             goto exit;
555         }
556
557         memcpy((void *)hdr_addr, &hdr, sizeof(struct virtio_net_hdr));
558         if (offset >= data_len) {
559             hdr_desc->flags &= ~VIRTIO_NEXT_FLAG;
560         }
561
562         for (buf_idx = hdr_desc->next; offset < data_len; buf_idx = q->desc[hdr_idx].next) {
563             struct vring_desc * buf_desc = &(q->desc[buf_idx]);
564             uint32_t len = 0;
565
566             len = copy_data_to_desc(&(virtio->virtio_dev->vm->cores[0]), virtio, buf_desc, buf + offset, data_len - offset);        
567             offset += len;
568             if (offset < data_len) {
569                 buf_desc->flags = VIRTIO_NEXT_FLAG;             
570             }
571             buf_desc->length = len;
572         }
573         
574         q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size];
575         q->used->ring[q->used->index % q->queue_size].length = data_len + hdr_len; // This should be the total length of data sent to guest (header+pkt_data)
576         q->used->index++;
577
578         int last_idx = q->cur_avail_idx;
579         q->cur_avail_idx++;
580         if (q->cur_avail_idx < last_idx)
581             q->idx_overflow = false;
582     } else {
583         virtio->pkt_drop++;
584
585 #ifdef VIRTIO_NIC_PROFILE
586         PrintError("Virtio NIC: %p, one pkt dropped receieved: %ld, dropped: %ld, sent: %ld curidx: %d, avaiIdx: %d\n", 
587                 virtio, virtio->pkt_recv, virtio->pkt_drop, virtio->pkt_sent, q->cur_avail_idx, q->avail->index);
588 #endif
589     }
590
591     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
592         PrintDebug("Raising IRQ %d\n",  virtio->pci_dev->config_header.intr_line);
593         v3_pci_raise_irq(virtio->virtio_dev->pci_bus, 0, virtio->pci_dev);
594         virtio->virtio_cfg.pci_isr = 0x1;
595     }
596
597 #ifdef VIRTIO_NIC_PROFILE
598     if ((virtio->pkt_recv % 10000) == 0){
599         PrintError("Virtio NIC: %p, receieved: %ld, dropped: %ld, sent: %ld\n", 
600                 virtio, virtio->pkt_recv, virtio->pkt_drop, virtio->pkt_sent);
601     }
602 #endif
603
604     ret_val = offset;
605
606 exit:
607
608     v3_unlock_irqrestore(virtio->lock, flags);
609  
610     return ret_val;
611 }
612
613
614 static struct v3_device_ops dev_ops = {
615     .free = virtio_free,
616     .reset = NULL,
617     .start = NULL,
618     .stop = NULL,
619 };
620
621 static int register_dev(struct virtio_dev_state * virtio, struct virtio_net_state * net_state) 
622 {
623     struct pci_device * pci_dev = NULL;
624     struct v3_pci_bar bars[6];
625     int num_ports = sizeof(struct virtio_config);
626     int tmp_ports = num_ports;
627     int i;
628
629     // This gets the number of ports, rounded up to a power of 2
630     net_state->io_range_size = 1; // must be a power of 2
631     while (tmp_ports > 0) {
632         tmp_ports >>= 1;
633         net_state->io_range_size <<= 1;
634     }
635         
636     // this is to account for any low order bits being set in num_ports
637     // if there are none, then num_ports was already a power of 2 so we shift right to reset it
638     if ((num_ports & ((net_state->io_range_size >> 1) - 1)) == 0) {
639         net_state->io_range_size >>= 1;
640     }
641     
642     for (i = 0; i < 6; i++) {
643         bars[i].type = PCI_BAR_NONE;
644     }
645     
646     PrintDebug("Virtio-NIC io_range_size = %d\n", net_state->io_range_size);
647     
648     bars[0].type = PCI_BAR_IO;
649     bars[0].default_base_port = -1;
650     bars[0].num_ports = net_state->io_range_size;
651     bars[0].io_read = virtio_io_read;
652     bars[0].io_write = virtio_io_write;
653     bars[0].private_data = net_state;
654     
655     pci_dev = v3_pci_register_device(virtio->pci_bus, PCI_STD_DEVICE, 
656                                      0, PCI_AUTO_DEV_NUM, 0,
657                                      "LNX_VIRTIO_NIC", bars,
658                                      NULL, NULL, NULL, net_state);
659     
660     if (!pci_dev) {
661         PrintError("Virtio NIC: Could not register PCI Device\n");
662         return -1;
663     }
664
665     PrintDebug("Virtio NIC:  registered to PCI bus\n");
666     
667     pci_dev->config_header.vendor_id = VIRTIO_VENDOR_ID;
668     pci_dev->config_header.subsystem_vendor_id = VIRTIO_SUBVENDOR_ID;
669         
670
671     pci_dev->config_header.device_id = VIRTIO_NET_DEV_ID;
672     pci_dev->config_header.class = PCI_CLASS_NETWORK;
673     pci_dev->config_header.subclass = PCI_NET_SUBCLASS_OTHER;  
674     pci_dev->config_header.subsystem_id = VIRTIO_NET_SUBDEVICE_ID;
675     pci_dev->config_header.intr_pin = 1;
676     pci_dev->config_header.max_latency = 1; // ?? (qemu does it...)
677
678     net_state->pci_dev = pci_dev;   
679     net_state->virtio_cfg.host_features = 0; //no features support now
680     net_state->rx_vq.queue_size = QUEUE_SIZE;
681     net_state->tx_vq.queue_size = QUEUE_SIZE;
682     net_state->ctrl_vq.queue_size = CTRL_QUEUE_SIZE;
683     net_state->virtio_dev = virtio;
684    
685     virtio_init_state(net_state);
686
687     return 0;
688 }
689
690 static int connect_fn(struct v3_vm_info * info, 
691                       void * frontend_data, 
692                       struct v3_dev_net_ops * ops, 
693                       v3_cfg_tree_t * cfg, 
694                       void * private_data) {
695     struct virtio_dev_state * virtio = (struct virtio_dev_state *)frontend_data;
696     struct virtio_net_state * net_state  = (struct virtio_net_state *)V3_Malloc(sizeof(struct virtio_net_state));
697
698     memset(net_state, 0, sizeof(struct virtio_net_state));
699     register_dev(virtio, net_state);
700
701     net_state->net_ops = ops;
702     net_state->backend_data = private_data;
703
704     ops->recv = virtio_rx;
705     ops->frontend_data = net_state;
706
707     return 0;
708 }
709
710 static int virtio_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
711     struct vm_device * pci_bus = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
712     struct virtio_dev_state * virtio_state = NULL;
713     char * name = v3_cfg_val(cfg, "name");
714
715     PrintDebug("Virtio NIC: Initializing VIRTIO Network device: %s\n", name);
716
717     if (pci_bus == NULL) {
718         PrintError("Virtio NIC: VirtIO devices require a PCI Bus");
719         return -1;
720     }
721
722     virtio_state  = (struct virtio_dev_state *)V3_Malloc(sizeof(struct virtio_dev_state));
723     memset(virtio_state, 0, sizeof(struct virtio_dev_state));
724
725     INIT_LIST_HEAD(&(virtio_state->dev_list));
726     virtio_state->pci_bus = pci_bus;
727     virtio_state->vm = vm;
728
729     struct vm_device * dev = v3_allocate_device(name, &dev_ops, virtio_state);
730     if (v3_attach_device(vm, dev) == -1) {
731         PrintError("Virtio NIC: Could not attach device %s\n", name);
732         return -1;
733     }
734
735     if (v3_dev_add_net_frontend(vm, name, connect_fn, (void *)virtio_state) == -1) {
736         PrintError("Virtio NIC: Could not register %s as net frontend\n", name);
737         return -1;
738     }
739         
740     return 0;
741 }
742
743 device_register("LNX_VIRTIO_NIC", virtio_init)
744