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.


build fixes
[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
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_blk_state * virtio = (struct virtio_blk_state *)dev->private_data;
66     int port_idx = port % virtio->io_range_size;
67
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_idx) {
75         case VRING_Q_NOTIFY_PORT:
76             // handle output
77             PrintError("Notification\n");
78             return -1;
79             break;
80         case VIRTIO_STATUS_PORT:
81             if (virtio->virtio_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 virtio_blk_state * virtio = (struct virtio_blk_state *)dev->private_data;
101     int port_idx = port % virtio->io_range_size;
102
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
119 static int virtio_free(struct vm_device * dev) {
120     return -1;
121 }
122
123
124
125
126 static struct v3_device_ops dev_ops = {
127     .free = virtio_free,
128     .reset = NULL,
129     .start = NULL,
130     .stop = NULL,
131 };
132
133
134
135
136
137
138 static int virtio_init(struct guest_info * vm, void * cfg_data) {
139     struct vm_device * pci_bus = v3_find_dev(vm, (char *)cfg_data);
140     struct virtio_blk_state * virtio_state = NULL;
141     struct pci_device * pci_dev = NULL;
142
143     PrintDebug("Initializing VIRTIO Block device\n");
144
145     if (pci_bus == NULL) {
146         PrintError("VirtIO devices require a PCI Bus");
147         return -1;
148     }
149
150     
151     virtio_state  = (struct virtio_blk_state *)V3_Malloc(sizeof(struct virtio_blk_state));
152     memset(virtio_state, 0, sizeof(struct virtio_blk_state));
153
154
155     struct vm_device * dev = v3_allocate_device("LNX_VIRTIO_BLK", &dev_ops, virtio_state);
156     if (v3_attach_device(vm, dev) == -1) {
157         PrintError("Could not attach device %s\n", "LNX_VIRTIO_BLK");
158         return -1;
159     }
160
161
162     // PCI initialization
163     {
164         struct v3_pci_bar bars[6];
165         int num_ports = sizeof(struct virtio_config) + sizeof(struct blk_config);
166         int tmp_ports = num_ports;
167         int i;
168
169
170
171         // This gets the number of ports, rounded up to a power of 2
172         virtio_state->io_range_size = 1; // must be a power of 2
173
174         while (tmp_ports > 0) {
175             tmp_ports >>= 1;
176             virtio_state->io_range_size <<= 1;
177         }
178         
179         // this is to account for any low order bits being set in num_ports
180         // if there are none, then num_ports was already a power of 2 so we shift right to reset it
181         if ((num_ports & ((virtio_state->io_range_size >> 1) - 1)) == 0) {
182             virtio_state->io_range_size >>= 1;
183         }
184
185
186         for (i = 0; i < 6; i++) {
187             bars[i].type = PCI_BAR_NONE;
188         }
189
190         bars[0].type = PCI_BAR_IO;
191         bars[0].default_base_port = -1;
192         bars[0].num_ports = virtio_state->io_range_size;
193
194         bars[0].io_read = virtio_io_read;
195         bars[0].io_write = virtio_io_write;
196
197         pci_dev = v3_pci_register_device(pci_bus, PCI_STD_DEVICE, 
198                                          0, PCI_AUTO_DEV_NUM, 0,
199                                          "LNX_VIRTIO_BLK", bars,
200                                          NULL, NULL, NULL, dev);
201
202         if (!pci_dev) {
203             PrintError("Could not register PCI Device\n");
204             return -1;
205         }
206         
207         pci_dev->config_header.vendor_id = VIRTIO_VENDOR_ID;
208         pci_dev->config_header.subsystem_vendor_id = VIRTIO_SUBVENDOR_ID;
209         
210
211         pci_dev->config_header.device_id = VIRTIO_BLOCK_DEV_ID;
212         pci_dev->config_header.class = PCI_CLASS_STORAGE;
213         pci_dev->config_header.subclass = PCI_STORAGE_SUBCLASS_OTHER;
214     
215         pci_dev->config_header.subsystem_id = VIRTIO_BLOCK_SUBDEVICE_ID;
216
217
218         pci_dev->config_header.intr_pin = 1;
219
220         pci_dev->config_header.max_latency = 1; // ?? (qemu does it...)
221
222
223         virtio_state->pci_dev = pci_dev;
224         virtio_state->pci_bus = pci_bus;
225
226         /* Block configuration */
227     }
228     
229     return 0;
230 }
231
232
233 device_register("LNX_VIRTIO_BLK", virtio_init)