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.


functional virtio block device
[palacios.git] / palacios / src / devices / lnx_virtio_blk.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, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20 #include <palacios/vmm.h>
21 #include <palacios/vmm_dev_mgr.h>
22 #include <devices/lnx_virtio_pci.h>
23 #include <devices/lnx_virtio_blk.h>
24 #include <devices/block_dev.h>
25 #include <palacios/vm_guest_mem.h>
26
27 #include <devices/pci.h>
28
29
30 #define BLK_CAPACITY_PORT     20
31 #define BLK_MAX_SIZE_PORT     28
32 #define BLK_MAX_SEG_PORT      32
33 #define BLK_CYLINDERS_PORT    36
34 #define BLK_HEADS_PORT        38
35 #define BLK_SECTS_PORT        39
36
37 #define BLK_IN_REQ            0
38 #define BLK_OUT_REQ           1
39 #define BLK_SCSI_CMD          2
40
41 #define BLK_BARRIER_FLAG     0x80000000
42
43 #define BLK_STATUS_OK             0
44 #define BLK_STATUS_ERR            1
45 #define BLK_STATUS_NOT_SUPPORTED  2
46
47
48 struct blk_config {
49     uint64_t capacity;
50     uint32_t max_size;
51     uint32_t max_seg;
52     uint16_t cylinders;
53     uint8_t heads;
54     uint8_t sectors;
55 } __attribute__((packed));
56
57
58
59 struct blk_op_hdr {
60     uint32_t type;
61     uint32_t prior;
62     uint64_t sector;
63 } __attribute__((packed));
64
65 #define QUEUE_SIZE 128
66
67 /* Host Feature flags */
68 #define VIRTIO_BARRIER       0x01       /* Does host support barriers? */
69 #define VIRTIO_SIZE_MAX      0x02       /* Indicates maximum segment size */
70 #define VIRTIO_SEG_MAX       0x04       /* Indicates maximum # of segments */
71 #define VIRTIO_LEGACY_GEOM   0x10       /* Indicates support of legacy geometry */
72
73
74
75
76 struct virtio_blk_state {
77     struct blk_config block_cfg;
78     struct virtio_config virtio_cfg;
79
80     struct vm_device * pci_bus;
81     struct pci_device * pci_dev;
82     
83     struct virtio_queue queue;
84
85     union {
86         struct v3_cd_ops * cd_ops;
87         struct v3_hd_ops * hd_ops;
88     };
89
90     v3_block_type_t block_type;
91     void * backend_data;
92
93     int io_range_size;
94 };
95
96
97 static int virtio_free(struct vm_device * dev) {
98     return -1;
99 }
100
101 static int virtio_reset(struct vm_device * dev) {
102     struct virtio_blk_state * virtio = (struct virtio_blk_state *)dev->private_data;
103
104     virtio->queue.ring_desc_addr = 0;
105     virtio->queue.ring_avail_addr = 0;
106     virtio->queue.ring_used_addr = 0;
107     virtio->queue.pfn = 0;
108     virtio->queue.cur_avail_idx = 0;
109
110     virtio->virtio_cfg.status = 0;
111     virtio->virtio_cfg.pci_isr = 0;
112
113     return 0;
114 }
115
116 static int handle_read_op(struct vm_device * dev, uint8_t * buf, uint64_t sector, uint32_t len) {
117     struct virtio_blk_state * virtio = (struct virtio_blk_state *)dev->private_data; 
118
119     if (virtio->block_type == BLOCK_DISK) {
120         if (len % HD_SECTOR_SIZE) {
121             PrintError("Write of something that is not a sector len %d, mod=%d\n", len, len % HD_SECTOR_SIZE);
122             return -1;
123         }
124
125
126         PrintDebug("Reading Disk\n");
127
128         return virtio->hd_ops->read(buf, len / HD_SECTOR_SIZE, sector * HD_SECTOR_SIZE, virtio->backend_data);
129     } else if (virtio->block_type == BLOCK_CDROM) {
130         if (len % ATAPI_BLOCK_SIZE) {
131             PrintError("Write of something that is not an ATAPI block len %d, mod=%d\n", len, len % ATAPI_BLOCK_SIZE);
132             return -1;
133         }
134
135         return virtio->cd_ops->read(buf, len / ATAPI_BLOCK_SIZE, sector * ATAPI_BLOCK_SIZE, virtio->backend_data);
136
137     }
138
139     return -1;
140 }
141
142
143 static int handle_write_op(struct vm_device * dev, uint8_t * buf, uint64_t sector, uint32_t len) {
144     struct virtio_blk_state * virtio = (struct virtio_blk_state *)dev->private_data; 
145
146
147     if (virtio->block_type == BLOCK_DISK) {
148         if (len % HD_SECTOR_SIZE) {
149             PrintError("Write of something that is not a sector len %d, mod=%d\n", len, len % HD_SECTOR_SIZE);
150             return -1;
151         }
152
153         PrintDebug("Writing Disk\n");
154
155         return virtio->hd_ops->write(buf, len / HD_SECTOR_SIZE, sector * HD_SECTOR_SIZE, virtio->backend_data);
156     }
157
158     return -1;
159 }
160
161
162 static int handle_block_op(struct vm_device * dev, struct vring_desc * hdr_desc, 
163                            struct vring_desc * buf_desc, struct vring_desc * status_desc) {
164     struct virtio_blk_state * virtio = (struct virtio_blk_state *)dev->private_data;    
165     struct blk_op_hdr * hdr = NULL;
166     uint8_t * buf = NULL;
167     uint8_t * status = NULL;
168
169
170     PrintDebug("Handling Block op\n");
171
172     if (guest_pa_to_host_va(dev->vm, hdr_desc->addr_gpa, (addr_t *)&(hdr)) == -1) {
173         PrintError("Could not translate block header address\n");
174         return -1;
175     }
176
177     if (guest_pa_to_host_va(dev->vm, buf_desc->addr_gpa, (addr_t *)&(buf)) == -1) {
178         PrintError("Could not translate buffer address\n");
179         return -1;
180     }
181
182     if (guest_pa_to_host_va(dev->vm, status_desc->addr_gpa, (addr_t *)&(status)) == -1) {
183         PrintError("Could not translate status address\n");
184         return -1;
185     }
186
187     PrintDebug("Sector=%p Length=%d\n", (void *)(addr_t)(hdr->sector), buf_desc->length);
188
189     if (hdr->type == BLK_IN_REQ) {
190         if (virtio->block_type != BLOCK_NONE) {
191             if (handle_read_op(dev, buf, hdr->sector, buf_desc->length) == -1) {
192                 *status = BLK_STATUS_ERR;
193             } else {
194                 *status = BLK_STATUS_OK;
195             }
196         } else {
197             *status = BLK_STATUS_NOT_SUPPORTED;
198         } 
199
200     } else if (hdr->type == BLK_OUT_REQ) {
201         if (virtio->block_type == BLOCK_DISK) {
202             if (handle_write_op(dev, buf, hdr->sector, buf_desc->length) == -1) {
203                 *status = BLK_STATUS_ERR;
204             } else {
205                 *status = BLK_STATUS_OK;
206             }
207         } else {
208             *status = BLK_STATUS_NOT_SUPPORTED;
209         }
210     } else if (hdr->type == BLK_SCSI_CMD) {
211         *status = BLK_STATUS_NOT_SUPPORTED;
212     }
213
214     PrintDebug("Returning Status: %d\n", *status);
215
216     return 0;
217 }
218
219
220
221 static int handle_kick(struct vm_device * dev) {
222     struct virtio_blk_state * virtio = (struct virtio_blk_state *)dev->private_data;    
223     struct virtio_queue * q = &(virtio->queue);
224
225     PrintDebug("VIRTIO KICK: cur_index=%d, avail_index=%d\n", q->cur_avail_idx, q->avail->index);
226
227     while (q->cur_avail_idx < q->avail->index) {
228         struct vring_desc * hdr_desc = NULL;
229         struct vring_desc * buf_desc = NULL;
230         struct vring_desc * status_desc = NULL;
231         uint16_t chain_idx = q->avail->ring[q->cur_avail_idx];
232         uint32_t req_len = 0;
233         int chained = 1;
234
235         PrintDebug("chained=%d, Chain Index=%d\n", chained, chain_idx);
236
237         while (chained) {
238             hdr_desc = &(q->desc[chain_idx]);
239             
240             PrintDebug("Header Descriptor (ptr=%p) gpa=%p, len=%d, flags=%x, next=%d\n", hdr_desc, 
241                        (void *)(hdr_desc->addr_gpa), hdr_desc->length, hdr_desc->flags, hdr_desc->next);
242         
243             if (!(hdr_desc->flags & VIRTIO_NEXT_FLAG)) {
244                 PrintError("Block operations must chain a buffer descriptor\n");
245                 return -1;
246             }
247
248             buf_desc = &(q->desc[hdr_desc->next]);
249             
250             PrintDebug("Buffer Descriptor (ptr=%p) gpa=%p, len=%d, flags=%x, next=%d\n", buf_desc, 
251                        (void *)(buf_desc->addr_gpa), buf_desc->length, buf_desc->flags, buf_desc->next);
252             
253             if (!(buf_desc->flags & VIRTIO_NEXT_FLAG)) {
254                 PrintError("Block operatoins must chain a status descriptor\n");
255                 return -1;
256             }
257             
258             status_desc = &(q->desc[buf_desc->next]);
259
260             // We detect whether we are chained here...
261             if (status_desc->flags & VIRTIO_NEXT_FLAG) {
262                 chained = 1;
263                 chain_idx = status_desc->next; 
264             } else {
265                 chained = 0;
266             }
267
268             PrintDebug("Status Descriptor (ptr=%p) gpa=%p, len=%d, flags=%x, next=%d\n", status_desc, 
269                        (void *)(status_desc->addr_gpa), status_desc->length, status_desc->flags, status_desc->next);
270             
271
272             if (handle_block_op(dev, hdr_desc, buf_desc, status_desc) == -1) {
273                 PrintError("Error handling block operation\n");
274                 return -1;
275             }
276
277             req_len += (buf_desc->length + status_desc->length);
278         }
279
280         q->used->ring[q->used->index].id = q->avail->ring[q->cur_avail_idx];
281         q->used->ring[q->used->index].length = req_len; // What do we set this to????
282
283         q->used->index = (q->used->index + 1) % (QUEUE_SIZE * sizeof(struct vring_desc));;
284
285
286         q->cur_avail_idx = (q->cur_avail_idx + 1) % (QUEUE_SIZE * sizeof(struct vring_desc));
287     }
288
289     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
290         PrintDebug("Raising IRQ %d\n",  virtio->pci_dev->config_header.intr_line);
291         v3_pci_raise_irq(virtio->pci_bus, 0, virtio->pci_dev);
292         virtio->virtio_cfg.pci_isr = 1;
293     }
294
295     return 0;
296 }
297
298 static int virtio_io_write(uint16_t port, void * src, uint_t length, struct vm_device * dev) {
299     struct virtio_blk_state * virtio = (struct virtio_blk_state *)dev->private_data;
300     int port_idx = port % virtio->io_range_size;
301
302
303     PrintDebug("VIRTIO BLOCK Write for port %d (index=%d) len=%d, value=%x\n", 
304                port, port_idx,  length, *(uint32_t *)src);
305
306
307
308     switch (port_idx) {
309         case GUEST_FEATURES_PORT:
310             if (length != 4) {
311                 PrintError("Illegal write length for guest features\n");
312                 return -1;
313             }
314             
315             virtio->virtio_cfg.guest_features = *(uint32_t *)src;
316
317             break;
318         case VRING_PG_NUM_PORT:
319             if (length == 4) {
320                 addr_t pfn = *(uint32_t *)src;
321                 addr_t page_addr = (pfn << VIRTIO_PAGE_SHIFT);
322
323
324                 virtio->queue.pfn = pfn;
325                 
326                 virtio->queue.ring_desc_addr = page_addr ;
327                 virtio->queue.ring_avail_addr = page_addr + (QUEUE_SIZE * sizeof(struct vring_desc));
328                 virtio->queue.ring_used_addr = ( virtio->queue.ring_avail_addr + \
329                                                  sizeof(struct vring_avail)    + \
330                                                  (QUEUE_SIZE * sizeof(uint16_t)));
331                 
332                 // round up to next page boundary.
333                 virtio->queue.ring_used_addr = (virtio->queue.ring_used_addr + 0xfff) & ~0xfff;
334
335                 if (guest_pa_to_host_va(dev->vm, virtio->queue.ring_desc_addr, (addr_t *)&(virtio->queue.desc)) == -1) {
336                     PrintError("Could not translate ring descriptor address\n");
337                     return -1;
338                 }
339
340
341                 if (guest_pa_to_host_va(dev->vm, virtio->queue.ring_avail_addr, (addr_t *)&(virtio->queue.avail)) == -1) {
342                     PrintError("Could not translate ring available address\n");
343                     return -1;
344                 }
345
346
347                 if (guest_pa_to_host_va(dev->vm, virtio->queue.ring_used_addr, (addr_t *)&(virtio->queue.used)) == -1) {
348                     PrintError("Could not translate ring used address\n");
349                     return -1;
350                 }
351
352                 PrintDebug("RingDesc_addr=%p, Avail_addr=%p, Used_addr=%p\n",
353                            (void *)(virtio->queue.ring_desc_addr),
354                            (void *)(virtio->queue.ring_avail_addr),
355                            (void *)(virtio->queue.ring_used_addr));
356
357                 PrintDebug("RingDesc=%p, Avail=%p, Used=%p\n", 
358                            virtio->queue.desc, virtio->queue.avail, virtio->queue.used);
359
360             } else {
361                 PrintError("Illegal write length for page frame number\n");
362                 return -1;
363             }
364             break;
365         case VRING_Q_SEL_PORT:
366             virtio->virtio_cfg.vring_queue_selector = *(uint16_t *)src;
367
368             if (virtio->virtio_cfg.vring_queue_selector != 0) {
369                 PrintError("Virtio Block device only uses 1 queue, selected %d\n", 
370                            virtio->virtio_cfg.vring_queue_selector);
371                 return -1;
372             }
373
374             break;
375         case VRING_Q_NOTIFY_PORT:
376             PrintDebug("Handling Kick\n");
377             if (handle_kick(dev) == -1) {
378                 PrintError("Could not handle Block Notification\n");
379                 return -1;
380             }
381             break;
382         case VIRTIO_STATUS_PORT:
383             virtio->virtio_cfg.status = *(uint8_t *)src;
384
385             if (virtio->virtio_cfg.status == 0) {
386                 PrintDebug("Resetting device\n");
387                 virtio_reset(dev);
388             }
389
390             break;
391
392         case VIRTIO_ISR_PORT:
393             virtio->virtio_cfg.pci_isr = *(uint8_t *)src;
394             break;
395         default:
396             return -1;
397             break;
398     }
399
400     return length;
401 }
402
403
404 static int virtio_io_read(uint16_t port, void * dst, uint_t length, struct vm_device * dev) {
405     struct virtio_blk_state * virtio = (struct virtio_blk_state *)dev->private_data;
406     int port_idx = port % virtio->io_range_size;
407
408
409     PrintDebug("VIRTIO BLOCK Read  for port %d (index =%d), length=%d\n", 
410                port, port_idx, length);
411
412     switch (port_idx) {
413         case HOST_FEATURES_PORT:
414             if (length != 4) {
415                 PrintError("Illegal read length for host features\n");
416                 return -1;
417             }
418
419             *(uint32_t *)dst = virtio->virtio_cfg.host_features;
420         
421             break;
422         case VRING_PG_NUM_PORT:
423             if (length != 4) {
424                 PrintError("Illegal read length for page frame number\n");
425                 return -1;
426             }
427
428             *(uint32_t *)dst = virtio->queue.pfn;
429
430             break;
431         case VRING_SIZE_PORT:
432             if (length != 2) {
433                 PrintError("Illegal read length for vring size\n");
434                 return -1;
435             }
436                 
437             *(uint16_t *)dst = virtio->queue.queue_size;
438
439             break;
440
441         case VIRTIO_STATUS_PORT:
442             if (length != 1) {
443                 PrintError("Illegal read length for status\n");
444                 return -1;
445             }
446
447             *(uint8_t *)dst = virtio->virtio_cfg.status;
448             break;
449
450         case VIRTIO_ISR_PORT:
451             *(uint8_t *)dst = virtio->virtio_cfg.pci_isr;
452             virtio->virtio_cfg.pci_isr = 0;
453             v3_pci_lower_irq(virtio->pci_bus, 0, virtio->pci_dev);
454             break;
455
456         default:
457             if ( (port_idx >= sizeof(struct virtio_config)) && 
458                  (port_idx < (sizeof(struct virtio_config) + sizeof(struct blk_config))) ) {
459
460                 uint8_t * cfg_ptr = (uint8_t *)&(virtio->block_cfg);
461                 memcpy(dst, cfg_ptr, length);
462                 
463             } else {
464                 PrintError("Read of Unhandled Virtio Read\n");
465                 return -1;
466             }
467           
468             break;
469     }
470
471     return length;
472 }
473
474
475
476
477 static struct v3_device_ops dev_ops = {
478     .free = virtio_free,
479     .reset = NULL,
480     .start = NULL,
481     .stop = NULL,
482 };
483
484
485
486
487 int v3_virtio_register_cdrom(struct vm_device * dev, struct v3_cd_ops * ops, void * private_data) {
488     struct virtio_blk_state * virtio = (struct virtio_blk_state *)dev->private_data;
489     
490     virtio->block_type = BLOCK_CDROM;
491     virtio->cd_ops = ops;
492     virtio->backend_data = private_data;
493
494     virtio->block_cfg.capacity = ops->get_capacity(private_data);
495
496     return 0;
497 }
498
499
500 int v3_virtio_register_harddisk(struct vm_device * dev, struct v3_hd_ops * ops, void * private_data) {
501     struct virtio_blk_state * virtio = (struct virtio_blk_state *)dev->private_data;
502
503     virtio->block_type = BLOCK_DISK;
504     virtio->hd_ops = ops;
505     virtio->backend_data = private_data;
506
507     virtio->block_cfg.capacity = ops->get_capacity(private_data);
508
509     return 0;
510 }
511
512
513
514 static int virtio_init(struct guest_info * vm, void * cfg_data) {
515     struct vm_device * pci_bus = v3_find_dev(vm, (char *)cfg_data);
516     struct virtio_blk_state * virtio_state = NULL;
517     struct pci_device * pci_dev = NULL;
518
519     PrintDebug("Initializing VIRTIO Block device\n");
520
521     if (pci_bus == NULL) {
522         PrintError("VirtIO devices require a PCI Bus");
523         return -1;
524     }
525
526     
527     virtio_state  = (struct virtio_blk_state *)V3_Malloc(sizeof(struct virtio_blk_state));
528     memset(virtio_state, 0, sizeof(struct virtio_blk_state));
529
530
531     struct vm_device * dev = v3_allocate_device("LNX_VIRTIO_BLK", &dev_ops, virtio_state);
532     if (v3_attach_device(vm, dev) == -1) {
533         PrintError("Could not attach device %s\n", "LNX_VIRTIO_BLK");
534         return -1;
535     }
536
537
538     // PCI initialization
539     {
540         struct v3_pci_bar bars[6];
541         int num_ports = sizeof(struct virtio_config) + sizeof(struct blk_config);
542         int tmp_ports = num_ports;
543         int i;
544
545
546
547         // This gets the number of ports, rounded up to a power of 2
548         virtio_state->io_range_size = 1; // must be a power of 2
549
550         while (tmp_ports > 0) {
551             tmp_ports >>= 1;
552             virtio_state->io_range_size <<= 1;
553         }
554         
555         // this is to account for any low order bits being set in num_ports
556         // if there are none, then num_ports was already a power of 2 so we shift right to reset it
557         if ((num_ports & ((virtio_state->io_range_size >> 1) - 1)) == 0) {
558             virtio_state->io_range_size >>= 1;
559         }
560
561
562         for (i = 0; i < 6; i++) {
563             bars[i].type = PCI_BAR_NONE;
564         }
565
566         bars[0].type = PCI_BAR_IO;
567         bars[0].default_base_port = -1;
568         bars[0].num_ports = virtio_state->io_range_size;
569
570         bars[0].io_read = virtio_io_read;
571         bars[0].io_write = virtio_io_write;
572
573         pci_dev = v3_pci_register_device(pci_bus, PCI_STD_DEVICE, 
574                                          0, PCI_AUTO_DEV_NUM, 0,
575                                          "LNX_VIRTIO_BLK", bars,
576                                          NULL, NULL, NULL, dev);
577
578         if (!pci_dev) {
579             PrintError("Could not register PCI Device\n");
580             return -1;
581         }
582         
583         pci_dev->config_header.vendor_id = VIRTIO_VENDOR_ID;
584         pci_dev->config_header.subsystem_vendor_id = VIRTIO_SUBVENDOR_ID;
585         
586
587         pci_dev->config_header.device_id = VIRTIO_BLOCK_DEV_ID;
588         pci_dev->config_header.class = PCI_CLASS_STORAGE;
589         pci_dev->config_header.subclass = PCI_STORAGE_SUBCLASS_OTHER;
590     
591         pci_dev->config_header.subsystem_id = VIRTIO_BLOCK_SUBDEVICE_ID;
592
593
594         pci_dev->config_header.intr_pin = 1;
595
596         pci_dev->config_header.max_latency = 1; // ?? (qemu does it...)
597
598
599         virtio_state->pci_dev = pci_dev;
600         virtio_state->pci_bus = pci_bus;
601     }
602
603     /* Block configuration */
604     virtio_state->virtio_cfg.host_features = VIRTIO_SEG_MAX;
605
606     // Virtio Block only uses one queue
607     virtio_state->queue.queue_size = QUEUE_SIZE;
608
609     virtio_reset(dev);
610
611     virtio_state->backend_data = NULL;
612     virtio_state->block_type = BLOCK_NONE;
613     virtio_state->hd_ops = NULL;
614
615     return 0;
616 }
617
618
619 device_register("LNX_VIRTIO_BLK", virtio_init)