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.


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