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.


b8d3166d0ffc1fe3f4080320ff0f919117e5f2e3
[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, Jack Lange <jarusl@cs.northwestern.edu>
11  * Copyright (c) 2008, Lei Xia <lxia@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@northwestern.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
29 #include <devices/pci.h>
30
31
32 #ifndef CONFIG_DEBUG_VIRTIO_BLK
33 #undef PrintDebug
34 #define PrintDebug(fmt, args...)
35 #endif
36
37 /* The feature bitmap for virtio net */
38 #define VIRTIO_NET_F_CSUM       0       /* Host handles pkts w/ partial csum */
39 #define VIRTIO_NET_F_GUEST_CSUM 1       /* Guest handles pkts w/ partial csum */
40 #define VIRTIO_NET_F_MAC        5       /* Host has given MAC address. */
41 #define VIRTIO_NET_F_GSO        6       /* Host handles pkts w/ any GSO type */
42 #define VIRTIO_NET_F_GUEST_TSO4 7       /* Guest can handle TSOv4 in. */
43 #define VIRTIO_NET_F_GUEST_TSO6 8       /* Guest can handle TSOv6 in. */
44 #define VIRTIO_NET_F_GUEST_ECN  9       /* Guest can handle TSO[6] w/ ECN in. */
45 #define VIRTIO_NET_F_GUEST_UFO  10      /* Guest can handle UFO in. */
46 #define VIRTIO_NET_F_HOST_TSO4  11      /* Host can handle TSOv4 in. */
47 #define VIRTIO_NET_F_HOST_TSO6  12      /* Host can handle TSOv6 in. */
48 #define VIRTIO_NET_F_HOST_ECN   13      /* Host can handle TSO[6] w/ ECN in. */
49 #define VIRTIO_NET_F_HOST_UFO   14      /* Host can handle UFO in. */
50 #define VIRTIO_NET_F_MRG_RXBUF  15      /* Host can merge receive buffers. */
51 #define VIRTIO_NET_F_STATUS     16      /* virtio_net_config.status available */
52 #define VIRTIO_NET_F_CTRL_VQ    17      /* Control channel available */
53 #define VIRTIO_NET_F_CTRL_RX    18      /* Control channel RX mode support */
54 #define VIRTIO_NET_F_CTRL_VLAN  19      /* Control channel VLAN filtering */
55 #define VIRTIO_NET_F_CTRL_RX_EXTRA 20   /* Extra RX mode control support */
56 #define VIRTIO_NET_S_LINK_UP    1       /* Link is up */
57
58 /* Maximum packet size we can receive from tap device: header + 64k */
59 #define VIRTIO_NET_MAX_BUFSIZE (sizeof(struct virtio_net_hdr) + (64 << 10))
60
61
62 struct virtio_net_hdr {
63         uint8_t flags;
64
65 #define VIRTIO_NET_HDR_GSO_NONE         0       /* Not a GSO frame */
66         uint8_t gso_type;
67
68         uint16_t hdr_len;               /* Ethernet + IP + tcp/udp hdrs */
69         uint16_t gso_size;              /* Bytes to append to hdr_len per frame */
70         uint16_t csum_start;    /* Position to start checksumming from */
71         uint16_t csum_offset;   /* Offset after that to place checksum */
72 }__attribute__((packed));
73
74         
75
76
77 #define QUEUE_SIZE 256
78 #define CTRL_QUEUE_SIZE 64
79
80 #define ETH_ALEN 6
81
82 struct virtio_net_config
83 {
84     uint8_t mac[ETH_ALEN];
85     // See VIRTIO_NET_F_STATUS and VIRTIO_NET_S_* above
86     uint16_t status;
87 } __attribute__((packed));
88
89 struct virtio_dev_state {
90     struct vm_device * pci_bus;
91     struct list_head dev_list;
92     struct guest_info * vm;
93 };
94
95 struct virtio_net_state {
96     struct virtio_net_config net_cfg;
97     struct virtio_config virtio_cfg;
98
99     //struct vm_device * pci_bus;
100     struct pci_device * pci_dev;
101     
102     struct virtio_queue rx_vq;   //index 0, rvq in Linux virtio driver, handle packet to guest
103     struct virtio_queue tx_vq;   //index 1, svq in Linux virtio driver, handle packet from guest
104     struct virtio_queue ctrl_vq; //index 2, ctrol info from guest
105
106     struct v3_dev_net_ops * net_ops;
107
108     void * backend_data;
109
110     struct virtio_dev_state * virtio_dev;
111
112     struct list_head dev_link;
113
114     int io_range_size;
115
116     void *private_data;
117 };
118
119 #if 0
120 //Temporarly for debug
121 static void print_packet(uchar_t *pkt, int size) {
122     PrintDebug("Vnet: print_data_packet: size: %d\n", size);
123     v3_hexdump(pkt, size, NULL, 0);
124 }
125
126 static int send (uchar_t *buf, uint_t len)
127 {
128     print_packet(buf, len);
129     return len;
130 }
131
132 #endif
133
134 static int virtio_free(struct vm_device * dev) 
135 {
136         
137     return -1;
138 }
139
140 static int virtio_reset(struct virtio_net_state * virtio) 
141 {
142     virtio->rx_vq.ring_desc_addr = 0;
143     virtio->rx_vq.ring_avail_addr = 0;
144     virtio->rx_vq.ring_used_addr = 0;
145     virtio->rx_vq.pfn = 0;
146     virtio->rx_vq.cur_avail_idx = 0;
147
148     virtio->tx_vq.ring_desc_addr = 0;
149     virtio->tx_vq.ring_avail_addr = 0;
150     virtio->tx_vq.ring_used_addr = 0;
151     virtio->tx_vq.pfn = 0;
152     virtio->tx_vq.cur_avail_idx = 0;
153
154     virtio->ctrl_vq.ring_desc_addr = 0;
155     virtio->ctrl_vq.ring_avail_addr = 0;
156     virtio->ctrl_vq.ring_used_addr = 0;
157     virtio->ctrl_vq.pfn = 0;
158     virtio->ctrl_vq.cur_avail_idx = 0;
159
160     virtio->virtio_cfg.status = VIRTIO_NET_S_LINK_UP;
161     virtio->virtio_cfg.pci_isr = 0;
162     virtio->private_data = NULL;
163
164     return 0;
165 }
166
167
168 //sending guest's packet to network sink
169 static int pkt_write(struct vm_device *dev,  struct vring_desc *buf_desc) 
170 {
171     struct virtio_net_state * virtio = (struct virtio_net_state *)dev->private_data; 
172     uint8_t *buf = NULL;
173     uint32_t len = buf_desc->length;
174
175     PrintDebug("Handling Virtio Net write\n");
176
177     if (guest_pa_to_host_va(dev->vm, buf_desc->addr_gpa, (addr_t *)&(buf)) == -1) {
178         PrintError("Could not translate buffer address\n");
179         return -1;
180     }
181
182     PrintDebug("Length=%d\n", buf_desc->length);
183
184     if (virtio->net_ops->send(buf, len, virtio->private_data, NULL) == -1) {
185         return -1;
186     }
187
188     return 0;
189 }
190
191
192 static int build_receive_header(struct virtio_net_hdr *hdr, const void *buf, int raw)
193 {
194     hdr->flags = 0;
195
196     if (!raw) {
197         memcpy(hdr, buf, sizeof(struct virtio_net_hdr));
198     } else {
199         memset(hdr, 0, sizeof(struct virtio_net_hdr));
200     }
201
202     return 0;
203 }
204
205
206 //sending guest's packet to network sink
207 static int copy_data_to_desc(struct vm_device * dev, struct vring_desc *desc, uchar_t *buf, uint_t buf_len) 
208 {
209     uint32_t len;
210     uint8_t *desc_buf = NULL;
211
212     if (guest_pa_to_host_va(dev->vm, desc->addr_gpa, (addr_t *)&(desc_buf)) == -1) {
213         PrintError("Could not translate buffer address\n");
214         return -1;
215     }
216
217     len = (desc->length < buf_len)?desc->length:buf_len;
218
219     memcpy(desc_buf, buf, len);
220
221     PrintDebug("Length=%d\n", len);
222
223     return len;
224 }
225
226
227 //send data to guest
228 static int send_pkt_to_guest(struct vm_device * dev, uchar_t *buf, uint_t size, int raw, void *private_data) 
229 {
230     struct virtio_net_state *virtio = (struct virtio_net_state *)dev->private_data;    
231     struct virtio_queue *q = &(virtio->rx_vq);
232
233     PrintDebug("VIRTIO Handle RX: cur_index=%d (mod=%d), avail_index=%d\n", 
234                q->cur_avail_idx, q->cur_avail_idx % q->queue_size, q->avail->index);
235
236     struct virtio_net_hdr hdr;
237     uint32_t hdr_len = sizeof(struct virtio_net_hdr);
238
239     uint32_t data_len = size;
240     if (!raw)
241        data_len -=  hdr_len;
242
243     build_receive_header(&hdr, buf, 1);
244
245     //queue is not set yet
246     if (q->ring_avail_addr == 0)
247                 return -1;
248
249 \r uint32_t offset = 0;
250     if (q->cur_avail_idx < q->avail->index) {
251         struct vring_desc * hdr_desc = NULL;
252         addr_t hdr_addr = 0;
253         uint16_t hdr_idx = q->avail->ring[q->cur_avail_idx % q->queue_size];
254
255         PrintDebug("Descriptor Count=%d, index=%d\n", desc_cnt, q->cur_avail_idx % q->queue_size);
256
257         hdr_desc = &(q->desc[hdr_idx]);
258
259         PrintDebug("Header Descriptor (ptr=%p) gpa=%p, len=%d, flags=%x, next=%d\n", hdr_desc, 
260                    (void *)(hdr_desc->addr_gpa), hdr_desc->length, hdr_desc->flags, hdr_desc->next);    
261
262         if (guest_pa_to_host_va(dev->vm, hdr_desc->addr_gpa, &(hdr_addr)) == -1) {
263             PrintError("Could not translate receive buffer address\n");
264             return -1;
265         }
266
267         //copy header to the header descriptor
268         memcpy((void *)hdr_addr, &hdr, sizeof(struct virtio_net_hdr));
269
270         uint16_t buf_idx = 0;
271         struct vring_desc * buf_desc = NULL;
272         //copy data to the next descriptors
273         for (buf_idx = 0; offset < data_len; buf_idx = q->desc[hdr_idx].next) {
274                 q->desc[buf_idx].flags = VIRTIO_NEXT_FLAG;
275                 buf_desc = &(q->desc[buf_idx]);
276                 uint32_t len = copy_data_to_desc(dev, buf_desc, buf+offset, data_len - offset);
277                 offset += len;
278                 buf_desc->length = len;  // TODO: do we need this?
279         }
280         
281         q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size];
282         q->used->ring[q->used->index % q->queue_size].length = data_len; // What do we set this to????
283
284         q->used->index++;
285         q->cur_avail_idx++;
286     }
287
288     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
289         PrintDebug("Raising IRQ %d\n",  virtio->pci_dev->config_header.intr_line);
290         v3_pci_raise_irq(virtio->virtio_dev->pci_bus, 0, virtio->pci_dev);
291         virtio->virtio_cfg.pci_isr = 0x1;
292     }
293
294     return offset;
295 }
296
297
298 int virtio_send(struct vm_device * dev, uchar_t *buf, uint_t size)
299 {
300     return send_pkt_to_guest(dev, buf, size, 1, NULL);
301 }
302
303
304 static int get_desc_count(struct virtio_queue * q, int index) 
305 {
306     struct vring_desc * tmp_desc = &(q->desc[index]);
307     int cnt = 1;
308     
309     while (tmp_desc->flags & VIRTIO_NEXT_FLAG) {
310         tmp_desc = &(q->desc[tmp_desc->next]);
311         cnt++;
312     }
313
314     return cnt;
315 }
316
317
318 static int handle_ctrl(struct vm_device * dev) 
319 {
320
321
322     return 0;
323 }
324
325 //get packet from guest
326 static int handle_pkt_tx(struct vm_device * dev) 
327 {
328     struct virtio_net_state *virtio = (struct virtio_net_state *)dev->private_data;    
329     struct virtio_queue *q = &(virtio->tx_vq);
330
331     PrintDebug("VIRTIO NIC pkt_tx: cur_index=%d (mod=%d), avail_index=%d\n", 
332                q->cur_avail_idx, q->cur_avail_idx % q->queue_size, q->avail->index);
333
334     while (q->cur_avail_idx < q->avail->index) {
335         struct vring_desc * hdr_desc = NULL;
336         struct vring_desc * buf_desc = NULL;
337
338         addr_t hdr_addr = 0;
339         uint16_t desc_idx = q->avail->ring[q->cur_avail_idx % q->queue_size];
340         int desc_cnt = get_desc_count(q, desc_idx);
341         uint32_t req_len = 0;
342
343         PrintDebug("Descriptor Count=%d, index=%d\n", desc_cnt, q->cur_avail_idx % q->queue_size);
344
345         hdr_desc = &(q->desc[desc_idx]);
346
347         PrintDebug("Header Descriptor (ptr=%p) gpa=%p, len=%d, flags=%x, next=%d\n", hdr_desc, 
348                    (void *)(hdr_desc->addr_gpa), hdr_desc->length, hdr_desc->flags, hdr_desc->next);    
349
350         if (guest_pa_to_host_va(dev->vm, hdr_desc->addr_gpa, &(hdr_addr)) == -1) {
351             PrintError("Could not translate block header address\n");
352             return -1;
353         }
354
355         //memcpy(&hdr, (void *)hdr_addr, sizeof(struct virtio_net_hdr));
356         hdr_desc = (struct vring_desc *)hdr_addr;
357         
358         PrintDebug("NIC Op Hdr (ptr=%p) type=%d, sector=%p\n", (void *)hdr_addr, hdr.hdr_len, (void *)hdr.csum_start)
359
360        desc_idx= hdr_desc->next;
361         int i = 0;
362         for (i = 0; i < desc_cnt - 1; i++) {    
363             buf_desc = &(q->desc[desc_idx]);
364
365             PrintDebug("Buffer Descriptor (ptr=%p) gpa=%p, len=%d, flags=%x, next=%d\n", buf_desc, 
366                        (void *)(buf_desc->addr_gpa), buf_desc->length, buf_desc->flags, buf_desc->next);
367
368             if (pkt_write(dev, buf_desc) == -1) {
369                 PrintError("Error handling nic operation\n");
370                 return -1;
371             }
372
373             req_len += buf_desc->length;
374             desc_idx = buf_desc->next;
375         }
376
377         q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size];
378         q->used->ring[q->used->index % q->queue_size].length = req_len; // What do we set this to????
379
380         q->used->index++;
381         q->cur_avail_idx++;
382     }
383
384     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
385         PrintDebug("Raising IRQ %d\n",  virtio->pci_dev->config_header.intr_line);
386         v3_pci_raise_irq(virtio->virtio_dev->pci_bus, 0, virtio->pci_dev);
387         virtio->virtio_cfg.pci_isr = 0x1;
388     }
389
390     return 0;
391 }
392
393
394 static int virtio_setup_queue(struct vm_device * dev, struct virtio_queue *queue, addr_t pfn, addr_t page_addr)
395 {
396     queue->pfn = pfn;
397                 
398     queue->ring_desc_addr = page_addr ;
399     queue->ring_avail_addr = page_addr + (queue->queue_size* sizeof(struct vring_desc));
400     queue->ring_used_addr = (queue->ring_avail_addr + \
401                                                  sizeof(struct vring_avail)    + \
402                                                  (queue->queue_size * sizeof(uint16_t)));
403                 
404     // round up to next page boundary.
405     queue->ring_used_addr = (queue->ring_used_addr + 0xfff) & ~0xfff;
406
407     if (guest_pa_to_host_va(dev->vm, queue->ring_desc_addr, (addr_t *)&(queue->desc)) == -1) {
408         PrintError("Could not translate ring descriptor address\n");
409          return -1;
410     }
411
412  
413     if (guest_pa_to_host_va(dev->vm, queue->ring_avail_addr, (addr_t *)&(queue->avail)) == -1) {
414         PrintError("Could not translate ring available address\n");
415         return -1;
416     }
417
418
419     if (guest_pa_to_host_va(dev->vm, queue->ring_used_addr, (addr_t *)&(queue->used)) == -1) {
420         PrintError("Could not translate ring used address\n");
421         return -1;
422     }
423
424     PrintDebug("RingDesc_addr=%p, Avail_addr=%p, Used_addr=%p\n",
425                         (void *)(queue->ring_desc_addr),
426                            (void *)(queue->ring_avail_addr),
427                            (void *)(queue->ring_used_addr));
428
429     PrintDebug("RingDesc=%p, Avail=%p, Used=%p\n", 
430                     queue->desc, queue->avail, queue->used);
431
432     return 0;
433 }
434
435
436
437 static int virtio_io_write(uint16_t port, void * src, uint_t length, void * private_data) 
438 {
439     struct vm_device * dev = (struct vm_device *)private_data;
440     struct virtio_net_state * virtio = (struct virtio_net_state *)dev->private_data;
441     int port_idx = port % virtio->io_range_size;
442
443
444     PrintDebug("VIRTIO NIC Write for port %d (index=%d) len=%d, value=%x\n", 
445                port, port_idx,  length, *(uint32_t *)src);
446
447
448     switch (port_idx) {
449         case GUEST_FEATURES_PORT:
450             if (length != 4) {
451                 PrintError("Illegal write length for guest features\n");
452                 return -1;
453             }
454             
455             virtio->virtio_cfg.guest_features = *(uint32_t *)src;
456             PrintDebug("Setting Guest Features to %x\n", virtio->virtio_cfg.guest_features);
457
458             break;
459         case VRING_PG_NUM_PORT:
460             if (length == 4) {
461                 addr_t pfn = *(uint32_t *)src;
462                 addr_t page_addr = (pfn << VIRTIO_PAGE_SHIFT);
463
464                 uint16_t queue_idx = virtio->virtio_cfg.vring_queue_selector;
465                 switch (queue_idx) {
466                     case 0:
467                         virtio_setup_queue(dev, &virtio->rx_vq, pfn, page_addr);
468                         break;
469                   case 1:
470                         virtio_setup_queue(dev, &virtio->tx_vq, pfn, page_addr);
471                          break;
472                     case 2:
473                          virtio_setup_queue(dev, &virtio->ctrl_vq, pfn, page_addr);
474                          break;
475
476                     default:
477                          break;
478                 }
479             } else {
480                 PrintError("Illegal write length for page frame number\n");
481                 return -1;
482             }
483             break;
484         case VRING_Q_SEL_PORT:
485             virtio->virtio_cfg.vring_queue_selector = *(uint16_t *)src;
486
487             if (virtio->virtio_cfg.vring_queue_selector > 2) {
488                 PrintError("Virtio NIC device only uses 3 queue, selected %d\n", 
489                            virtio->virtio_cfg.vring_queue_selector);
490                 return -1;
491             }
492
493             break;
494         case VRING_Q_NOTIFY_PORT:
495             PrintDebug("Handling Kick\n");
496             uint16_t queue_idx = *(uint16_t *)src;
497             if (queue_idx == 0){
498                     PrintError("receive queue notification\n");
499             }else if (queue_idx == 1){
500                     if (handle_pkt_tx(dev) == -1) {
501                         PrintError("Could not handle NIC Notification\n");
502                         return -1;
503                     }
504             }else if (queue_idx == 2){
505                     if (handle_ctrl(dev) == -1) {
506                         PrintError("Could not handle NIC Notification\n");
507                         return -1;
508                     }
509             }else {
510                 PrintError("Virtio NIC device only uses 3 queue, selected %d\n", 
511                            queue_idx);
512             }
513             
514             break;
515         case VIRTIO_STATUS_PORT:
516             virtio->virtio_cfg.status = *(uint8_t *)src;
517
518             if (virtio->virtio_cfg.status == 0) {
519                 PrintDebug("Resetting device\n");
520                 virtio_reset(virtio);
521             }
522
523             break;
524
525         case VIRTIO_ISR_PORT:
526             virtio->virtio_cfg.pci_isr = *(uint8_t *)src;
527             break;
528         default:
529             return -1;
530             break;
531     }
532
533     return length;
534 }
535
536
537 static int virtio_io_read(uint16_t port, void * dst, uint_t length, void * private_data) 
538 {
539     struct vm_device * dev = (struct vm_device *)private_data;
540     struct virtio_net_state * virtio = (struct virtio_net_state *)dev->private_data;
541     int port_idx = port % virtio->io_range_size;
542     uint16_t queue_idx = virtio->virtio_cfg.vring_queue_selector;
543
544
545     PrintDebug("VIRTIO NIC Read  for port %d (index =%d), length=%d\n", 
546                port, port_idx, length);
547
548     switch (port_idx) {
549         case HOST_FEATURES_PORT:
550             if (length != 4) {
551                 PrintError("Illegal read length for host features\n");
552                 return -1;
553             }
554
555             *(uint32_t *)dst = virtio->virtio_cfg.host_features;
556         
557             break;
558         case VRING_PG_NUM_PORT:
559
560             if (length != 4) {
561                 PrintError("Illegal read length for page frame number\n");
562                 return -1;
563             }
564
565             switch (queue_idx) {
566                 case 0:
567                       *(uint32_t *)dst = virtio->rx_vq.pfn;
568                         break;
569                  case 1:
570                       *(uint32_t *)dst = virtio->tx_vq.pfn;
571                         break;  
572                  case 2:
573                       *(uint32_t *)dst = virtio->ctrl_vq.pfn;
574                         break;
575                  default:
576                         break;
577            }
578
579             break;
580         case VRING_SIZE_PORT:
581             if (length != 2) {
582                 PrintError("Illegal read length for vring size\n");
583                 return -1;
584             }
585
586             switch (queue_idx) {
587                 case 0:
588                       *(uint16_t *)dst = virtio->rx_vq.queue_size;
589                         break;
590                  case 1:
591                       *(uint32_t *)dst = virtio->tx_vq.queue_size;
592                         break;  
593                  case 2:
594                       *(uint32_t *)dst = virtio->ctrl_vq.queue_size;
595                         break;
596                  default:
597                         break;
598            }
599
600             break;
601         case VIRTIO_STATUS_PORT:
602             if (length != 1) {
603                 PrintError("Illegal read length for status\n");
604                 return -1;
605             }
606
607             *(uint8_t *)dst = virtio->virtio_cfg.status;
608             break;
609
610         case VIRTIO_ISR_PORT:
611             *(uint8_t *)dst = virtio->virtio_cfg.pci_isr;
612             virtio->virtio_cfg.pci_isr = 0;
613             v3_pci_lower_irq(virtio->virtio_dev->pci_bus, 0, virtio->pci_dev);
614             break;
615
616         default:
617             PrintError("Read of Unhandled Virtio Read\n");
618            return -1;
619     }
620
621     return length;
622 }
623
624
625 static struct v3_device_ops dev_ops = {
626     .free = virtio_free,
627     .reset = NULL,
628     .start = NULL,
629     .stop = NULL,
630 };
631
632
633 static int register_dev(struct virtio_dev_state * virtio, struct virtio_net_state * net_state) {
634     // initialize PCI
635     struct pci_device * pci_dev = NULL;
636     struct v3_pci_bar bars[6];
637     int num_ports = sizeof(struct virtio_config);
638     int tmp_ports = num_ports;
639     int i;
640
641     // This gets the number of ports, rounded up to a power of 2
642     net_state->io_range_size = 1; // must be a power of 2
643     
644     while (tmp_ports > 0) {
645         tmp_ports >>= 1;
646         net_state->io_range_size <<= 1;
647     }
648         
649     // this is to account for any low order bits being set in num_ports
650     // if there are none, then num_ports was already a power of 2 so we shift right to reset it
651     if ((num_ports & ((net_state->io_range_size >> 1) - 1)) == 0) {
652         net_state->io_range_size >>= 1;
653     }
654     
655     
656     for (i = 0; i < 6; i++) {
657         bars[i].type = PCI_BAR_NONE;
658     }
659     
660     PrintDebug("Virtio-BLK io_range_size = %d\n", blk_state->io_range_size);
661     
662     bars[0].type = PCI_BAR_IO;
663     bars[0].default_base_port = -1;
664     bars[0].num_ports = net_state->io_range_size;
665     
666     bars[0].io_read = virtio_io_read;
667     bars[0].io_write = virtio_io_write;
668     bars[0].private_data = net_state;
669     
670     pci_dev = v3_pci_register_device(virtio->pci_bus, PCI_STD_DEVICE, 
671                                      0, PCI_AUTO_DEV_NUM, 0,
672                                      "LNX_VIRTIO_BLK", bars,
673                                      NULL, NULL, NULL, net_state);
674     
675     if (!pci_dev) {
676         PrintError("Could not register PCI Device\n");
677         return -1;
678     }
679     
680     pci_dev->config_header.vendor_id = VIRTIO_VENDOR_ID;
681     pci_dev->config_header.subsystem_vendor_id = VIRTIO_SUBVENDOR_ID;
682         
683
684     pci_dev->config_header.device_id = VIRTIO_NET_DEV_ID;
685     pci_dev->config_header.class = PCI_CLASS_NETWORK;
686     pci_dev->config_header.subclass = PCI_NET_SUBCLASS_OTHER;
687     
688     //TODO:how to define new one for virtio net device
689     pci_dev->config_header.subsystem_id = VIRTIO_BLOCK_SUBDEVICE_ID;
690
691     pci_dev->config_header.intr_pin = 1;
692
693     pci_dev->config_header.max_latency = 1; // ?? (qemu does it...)
694
695
696     net_state->pci_dev = pci_dev;
697     //net_state->pci_bus = pci_bus;
698     
699     net_state->virtio_cfg.host_features = 0; //no features support now
700
701     net_state->rx_vq.queue_size = QUEUE_SIZE;
702     net_state->tx_vq.queue_size = QUEUE_SIZE;
703     net_state->ctrl_vq.queue_size = CTRL_QUEUE_SIZE;
704
705     net_state->virtio_dev = virtio;
706
707     virtio_reset(net_state);
708
709     return 0;
710 }
711
712
713
714 static int connect_fn(struct guest_info * info, 
715                       void * frontend_data, 
716                       struct v3_dev_net_ops * ops, 
717                       v3_cfg_tree_t * cfg, 
718                       void * private_data) {
719
720     struct virtio_dev_state * virtio = (struct virtio_dev_state *)frontend_data;
721
722     struct virtio_net_state * net_state  = (struct virtio_net_state *)V3_Malloc(sizeof(struct virtio_net_state));
723     memset(net_state, 0, sizeof(struct virtio_net_state));
724
725     register_dev(virtio, net_state);
726
727     net_state->net_ops = ops;
728     net_state->backend_data = private_data;
729
730     return 0;
731 }
732
733
734 struct net_frontend {
735     int (*connect)(struct guest_info * info, 
736                     void * frontend_data, 
737                     struct v3_dev_net_ops * ops, 
738                     v3_cfg_tree_t * cfg, 
739                     void * priv_data);
740         
741
742     struct list_head net_node;
743
744     void * priv_data;
745 };
746
747
748 int v3_dev_add_net_frontend(struct guest_info * info, 
749                             char * name, 
750                             int (*connect)(struct guest_info * info, 
751                                             void * frontend_data, 
752                                             struct v3_dev_net_ops * ops, 
753                                             v3_cfg_tree_t * cfg, 
754                                             void * private_data), 
755                             void * priv_data)
756 {
757     struct net_frontend * frontend = NULL;
758
759     frontend = (struct net_frontend *)V3_Malloc(sizeof(struct net_frontend));
760     memset(frontend, 0, sizeof(struct net_frontend));
761     
762     frontend->connect = connect;
763     frontend->priv_data = priv_data;
764         
765     list_add(&(frontend->net_node), &(info->dev_mgr.net_list));
766     v3_htable_insert(info->dev_mgr.net_table, (addr_t)(name), (addr_t)frontend);
767
768     return 0;
769 }
770
771
772 int v3_dev_connect_net(struct guest_info * info, 
773                        char * frontend_name, 
774                        struct v3_dev_net_ops * ops, 
775                        v3_cfg_tree_t * cfg, 
776                        void * private_data){
777     struct net_frontend * frontend = NULL;
778
779     frontend = (struct net_frontend *)v3_htable_search(info->dev_mgr.net_table,
780                                                        (addr_t)frontend_name);
781     
782     if (frontend == NULL) {
783         PrintError("Could not find frontend net device %s\n", frontend_name);
784         return 0;
785     }
786
787     if (frontend->connect(info, frontend->priv_data, ops, cfg, private_data) == -1) {
788         PrintError("Error connecting to block frontend %s\n", frontend_name);
789         return -1;
790     }
791
792     return 0;
793 }
794
795 static int virtio_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
796     struct vm_device * pci_bus = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
797     struct virtio_dev_state * virtio_state = NULL;
798     char * name = v3_cfg_val(cfg, "name");
799
800     PrintDebug("Initializing VIRTIO Network device\n");
801
802     if (pci_bus == NULL) {
803         PrintError("VirtIO devices require a PCI Bus");
804         return -1;
805     }
806
807     virtio_state  = (struct virtio_dev_state *)V3_Malloc(sizeof(struct virtio_dev_state));
808     memset(virtio_state, 0, sizeof(struct virtio_dev_state));
809
810     INIT_LIST_HEAD(&(virtio_state->dev_list));
811     virtio_state->pci_bus = pci_bus;
812     virtio_state->vm = vm;
813
814     struct vm_device * dev = v3_allocate_device(name, &dev_ops, virtio_state);
815     if (v3_attach_device(vm, dev) == -1) {
816         PrintError("Could not attach device %s\n", name);
817         return -1;
818     }
819
820     if (v3_dev_add_net_frontend(vm, name, connect_fn, (void *)virtio_state) == -1) {
821         PrintError("Could not register %s as block frontend\n", name);
822         return -1;
823     }
824
825     return 0;
826 }
827
828 device_register("LNX_VIRTIO_NIC", virtio_init)
829