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.


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