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.


virtio updates
[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
22 #include <devices/lnx_virtio_pci.h>
23
24
25 #include <devices/pci.h>
26
27
28 struct blk_config {
29     uint64_t capacity;
30     uint32_t max_size;
31     uint32_t max_seg;
32     uint16_t cylinders;
33     uint8_t heads;
34     uint8_t sectors;
35 } __attribute__((packed));
36
37
38
39
40 /* Host Feature flags */
41 #define VIRTIO_BARRIER       0x01       /* Does host support barriers? */
42 #define VIRTIO_SIZE_MAX      0x02       /* Indicates maximum segment size */
43 #define VIRTIO_SEG_MAX       0x04       /* Indicates maximum # of segments */
44 #define VIRTIO_LEGACY_GEOM   0x10       /* Indicates support of legacy geometry */
45
46
47
48 struct virtio_blk_state {
49     struct blk_config block_cfg;
50     struct virtio_config virtio_cfg;
51
52     struct vm_device * pci_bus;
53     struct pci_device * pci_dev;
54
55     struct virtio_device * virtio_dev; // the virtio device struction for _this_ device
56     
57
58     int io_range_size;
59 };
60
61
62
63
64 static int virtio_io_write(uint16_t port, void * src, uint_t length, struct vm_device * dev) {
65     struct virtio_device * virtio_dev = find_virtio_dev(dev);
66     int port_idx = port % virtio->io_range_size;
67     uint8_t * cfg_ptr = (uint8_t *)cfg;
68
69     PrintDebug("VIRTIO BLOCK Write for port %d (index=%d) len=%d, value=%x\n", 
70                port, port_idx,  length, *(uint32_t *)src);
71
72
73
74     switch (port_index) {
75         case VRING_Q_NOTIFY_PORT:
76             // handle output
77             PrintError("Notification\n");
78             return -1;
79             break;
80         case VRING_STATUS_PORT:
81             if (cfg->status == 0) {
82                 PrintDebug("Resetting device\n");
83                 return -1;
84                 //reset
85             }
86             break;
87         default:
88             return -1;
89             break;
90     }
91
92
93
94
95     return length;
96 }
97
98
99 static int virtio_io_read(uint16_t port, void * dst, uint_t length, struct vm_device * dev) {
100     struct blk_state * virtio = (struct blk_state *)dev->private_data;
101     int port_idx = port % virtio->io_range_size;
102     uint8_t * cfg_ptr = (uint8_t *)cfg;
103
104     PrintDebug("VIRTIO BLOCK Read  for port %d (index =%d), length=%d\n", 
105                port, port_idx, length);
106
107     switch (port_idx) {
108         // search for device....
109         // call and return dev config read
110         default:
111         return -1;
112     }
113
114
115     return length;
116 }
117
118 struct v3_dev_ops  = {
119     .free = virtio_free,
120     .reset = NULL,
121     .stop = NULL,
122     .start = NULL
123 };
124
125
126 static int virtio_free(struct vm_device * dev) {
127     return -1;
128 }
129
130
131
132
133 static struct v3_device_ops dev_ops = {
134     .free = virtio_free,
135     .reset = NULL,
136     .start = NULL,
137     .stop = NULL,
138 };
139
140
141
142
143
144
145 static int virtio_init(struct guest_info * vm, void * cfg_data) {
146     struct vm_device * pci_bus = v3_find_dev(vm, (char *)cfg_data);
147     struct virtio_blk_state * virtio_state = NULL;
148     struct pci_device * pci_dev = NULL;
149
150     PrintDebug("Initializing VIRTIO Block device\n");
151
152     if (pci_bus == NULL) {
153         PrintError("VirtIO devices require a PCI Bus");
154         return -1;
155     }
156
157     
158     virtio_state  = (struct virtio_blk_state *)V3_Malloc(sizeof(struct virtio_blk_state));
159     memset(virtio_state, 0, sizeof(struct virtio_blk_state));
160
161
162     struct vm_device * dev = v3_allocate_device("LNX_VIRTIO_BLK", &dev_ops, virtio_state);
163     if (v3_attach_device(vm, dev) == -1) {
164         PrintError("Could not attach device %s\n", "LNX_VIRTIO_BLK");
165         return -1;
166     }
167
168
169     // PCI initialization
170     {
171         struct v3_pci_bar bars[6];
172         int num_ports = sizeof(struct virtio_config) + sizeof(struct blk_config);
173         int tmp_ports = num_ports;
174         int i;
175
176
177
178         // This gets the number of ports, rounded up to a power of 2
179         virtio_state->io_range_size = 1; // must be a power of 2
180
181         while (tmp_ports > 0) {
182             tmp_ports >>= 1;
183             virtio_state->io_range_size <<= 1;
184         }
185         
186         // this is to account for any low order bits being set in num_ports
187         // if there are none, then num_ports was already a power of 2 so we shift right to reset it
188         if ((num_ports & ((virtio_state->io_range_size >> 1) - 1)) == 0) {
189             virtio_state->io_range_size >>= 1;
190         }
191
192
193         for (i = 0; i < 6; i++) {
194             bars[i].type = PCI_BAR_NONE;
195         }
196
197         bars[0].type = PCI_BAR_IO;
198         bars[0].default_base_port = -1;
199         bars[0].num_ports = virtio_state->io_range_size;
200
201         bars[0].io_read = virtio_io_read;
202         bars[0].io_write = virtio_io_write;
203
204         pci_dev = v3_pci_register_device(pci_bus, PCI_STD_DEVICE, 
205                                          0, PCI_AUTO_DEV_NUM, 0,
206                                          "LNX_VIRTIO_BLK", bars,
207                                          NULL, NULL, NULL, dev);
208
209         if (!pci_dev) {
210             PrintError("Could not register PCI Device\n");
211             return -1;
212         }
213         
214         pci_dev->config_header.vendor_id = VIRTIO_VENDOR_ID;
215         pci_dev->config_header.subsystem_vendor_id = VIRTIO_SUBVENDOR_ID;
216         
217
218         pci_dev->config_header.device_id = VIRTIO_BLOCK_DEV_ID;
219         pci_dev->config_header.class = PCI_CLASS_STORAGE;
220         pci_dev->config_header.subclass = PCI_STORAGE_SUBCLASS_OTHER;
221     
222         pci_dev->config_header.subsystem_id = VIRTIO_BLOCK_SUBDEVICE_ID;
223
224
225         pci_dev->config_header.intr_pin = 1;
226
227         pci_dev->config_header.max_latency = 1; // ?? (qemu does it...)
228
229
230         virtio_state->pci_dev = pci_dev;
231         virtio_state->pci_bus = pci_bus;
232
233         /* Block configuration */
234     }
235     
236     return 0;
237 }
238
239
240 device_register("LNX_VIRTIO_BLK", virtio_init)