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.


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