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.


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