Revision 6e02c38d
b/Makefile.target | ||
---|---|---|
665 | 665 |
OBJS+= cirrus_vga.o apic.o parallel.o acpi.o piix_pci.o |
666 | 666 |
OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o |
667 | 667 |
# virtio support |
668 |
OBJS+= virtio.o |
|
668 |
OBJS+= virtio.o virtio-blk.o
|
|
669 | 669 |
CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE |
670 | 670 |
endif |
671 | 671 |
ifeq ($(TARGET_BASE_ARCH), ppc) |
... | ... | |
684 | 684 |
# PowerPC 4xx boards |
685 | 685 |
OBJS+= pflash_cfi02.o ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o |
686 | 686 |
# virtio support |
687 |
OBJS+= virtio.o |
|
687 |
OBJS+= virtio.o virtio-blk.o
|
|
688 | 688 |
endif |
689 | 689 |
ifeq ($(TARGET_BASE_ARCH), mips) |
690 | 690 |
OBJS+= mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o |
b/hw/pc.c | ||
---|---|---|
33 | 33 |
#include "boards.h" |
34 | 34 |
#include "console.h" |
35 | 35 |
#include "fw_cfg.h" |
36 |
#include "virtio-blk.h" |
|
36 | 37 |
|
37 | 38 |
/* output Bochs bios info messages */ |
38 | 39 |
//#define DEBUG_BIOS |
... | ... | |
1092 | 1093 |
} |
1093 | 1094 |
} |
1094 | 1095 |
} |
1096 |
|
|
1097 |
/* Add virtio block devices */ |
|
1098 |
if (pci_enabled) { |
|
1099 |
int index; |
|
1100 |
int unit_id = 0; |
|
1101 |
|
|
1102 |
while ((index = drive_get_index(IF_VIRTIO, 0, unit_id)) != -1) { |
|
1103 |
virtio_blk_init(pci_bus, 0x1AF4, 0x1001, |
|
1104 |
drives_table[index].bdrv); |
|
1105 |
unit_id++; |
|
1106 |
} |
|
1107 |
} |
|
1095 | 1108 |
} |
1096 | 1109 |
|
1097 | 1110 |
static void pc_init_pci(ram_addr_t ram_size, int vga_ram_size, |
b/hw/virtio-blk.c | ||
---|---|---|
1 |
/* |
|
2 |
* Virtio Block Device |
|
3 |
* |
|
4 |
* Copyright IBM, Corp. 2007 |
|
5 |
* |
|
6 |
* Authors: |
|
7 |
* Anthony Liguori <aliguori@us.ibm.com> |
|
8 |
* |
|
9 |
* This work is licensed under the terms of the GNU GPL, version 2. See |
|
10 |
* the COPYING file in the top-level directory. |
|
11 |
* |
|
12 |
*/ |
|
13 |
|
|
14 |
#include "virtio-blk.h" |
|
15 |
#include "block_int.h" |
|
16 |
|
|
17 |
typedef struct VirtIOBlock |
|
18 |
{ |
|
19 |
VirtIODevice vdev; |
|
20 |
BlockDriverState *bs; |
|
21 |
VirtQueue *vq; |
|
22 |
} VirtIOBlock; |
|
23 |
|
|
24 |
static VirtIOBlock *to_virtio_blk(VirtIODevice *vdev) |
|
25 |
{ |
|
26 |
return (VirtIOBlock *)vdev; |
|
27 |
} |
|
28 |
|
|
29 |
typedef struct VirtIOBlockReq |
|
30 |
{ |
|
31 |
VirtIOBlock *dev; |
|
32 |
VirtQueueElement elem; |
|
33 |
struct virtio_blk_inhdr *in; |
|
34 |
struct virtio_blk_outhdr *out; |
|
35 |
size_t size; |
|
36 |
uint8_t *buffer; |
|
37 |
} VirtIOBlockReq; |
|
38 |
|
|
39 |
static void virtio_blk_rw_complete(void *opaque, int ret) |
|
40 |
{ |
|
41 |
VirtIOBlockReq *req = opaque; |
|
42 |
VirtIOBlock *s = req->dev; |
|
43 |
|
|
44 |
/* Copy read data to the guest */ |
|
45 |
if (!ret && !(req->out->type & VIRTIO_BLK_T_OUT)) { |
|
46 |
size_t offset = 0; |
|
47 |
int i; |
|
48 |
|
|
49 |
for (i = 0; i < req->elem.in_num - 1; i++) { |
|
50 |
size_t len; |
|
51 |
|
|
52 |
/* Be pretty defensive wrt malicious guests */ |
|
53 |
len = MIN(req->elem.in_sg[i].iov_len, |
|
54 |
req->size - offset); |
|
55 |
|
|
56 |
memcpy(req->elem.in_sg[i].iov_base, |
|
57 |
req->buffer + offset, |
|
58 |
len); |
|
59 |
offset += len; |
|
60 |
} |
|
61 |
} |
|
62 |
|
|
63 |
req->in->status = ret ? VIRTIO_BLK_S_IOERR : VIRTIO_BLK_S_OK; |
|
64 |
virtqueue_push(s->vq, &req->elem, req->size + sizeof(*req->in)); |
|
65 |
virtio_notify(&s->vdev, s->vq); |
|
66 |
|
|
67 |
qemu_free(req->buffer); |
|
68 |
qemu_free(req); |
|
69 |
} |
|
70 |
|
|
71 |
static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s) |
|
72 |
{ |
|
73 |
VirtIOBlockReq *req; |
|
74 |
|
|
75 |
req = qemu_mallocz(sizeof(*req)); |
|
76 |
if (req == NULL) |
|
77 |
return NULL; |
|
78 |
|
|
79 |
req->dev = s; |
|
80 |
if (!virtqueue_pop(s->vq, &req->elem)) { |
|
81 |
qemu_free(req); |
|
82 |
return NULL; |
|
83 |
} |
|
84 |
|
|
85 |
return req; |
|
86 |
} |
|
87 |
|
|
88 |
static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) |
|
89 |
{ |
|
90 |
VirtIOBlock *s = to_virtio_blk(vdev); |
|
91 |
VirtIOBlockReq *req; |
|
92 |
|
|
93 |
while ((req = virtio_blk_get_request(s))) { |
|
94 |
int i; |
|
95 |
|
|
96 |
if (req->elem.out_num < 1 || req->elem.in_num < 1) { |
|
97 |
fprintf(stderr, "virtio-blk missing headers\n"); |
|
98 |
exit(1); |
|
99 |
} |
|
100 |
|
|
101 |
if (req->elem.out_sg[0].iov_len < sizeof(*req->out) || |
|
102 |
req->elem.in_sg[req->elem.in_num - 1].iov_len < sizeof(*req->in)) { |
|
103 |
fprintf(stderr, "virtio-blk header not in correct element\n"); |
|
104 |
exit(1); |
|
105 |
} |
|
106 |
|
|
107 |
req->out = (void *)req->elem.out_sg[0].iov_base; |
|
108 |
req->in = (void *)req->elem.in_sg[req->elem.in_num - 1].iov_base; |
|
109 |
|
|
110 |
if (req->out->type & VIRTIO_BLK_T_SCSI_CMD) { |
|
111 |
unsigned int len = sizeof(*req->in); |
|
112 |
|
|
113 |
req->in->status = VIRTIO_BLK_S_UNSUPP; |
|
114 |
virtqueue_push(vq, &req->elem, len); |
|
115 |
virtio_notify(vdev, vq); |
|
116 |
qemu_free(req); |
|
117 |
} else if (req->out->type & VIRTIO_BLK_T_OUT) { |
|
118 |
size_t offset; |
|
119 |
|
|
120 |
for (i = 1; i < req->elem.out_num; i++) |
|
121 |
req->size += req->elem.out_sg[i].iov_len; |
|
122 |
|
|
123 |
req->buffer = qemu_memalign(512, req->size); |
|
124 |
if (req->buffer == NULL) { |
|
125 |
qemu_free(req); |
|
126 |
break; |
|
127 |
} |
|
128 |
|
|
129 |
/* We copy the data from the SG list to avoid splitting up the request. This helps |
|
130 |
performance a lot until we can pass full sg lists as AIO operations */ |
|
131 |
offset = 0; |
|
132 |
for (i = 1; i < req->elem.out_num; i++) { |
|
133 |
size_t len; |
|
134 |
|
|
135 |
len = MIN(req->elem.out_sg[i].iov_len, |
|
136 |
req->size - offset); |
|
137 |
memcpy(req->buffer + offset, |
|
138 |
req->elem.out_sg[i].iov_base, |
|
139 |
len); |
|
140 |
offset += len; |
|
141 |
} |
|
142 |
|
|
143 |
bdrv_aio_write(s->bs, req->out->sector, |
|
144 |
req->buffer, |
|
145 |
req->size / 512, |
|
146 |
virtio_blk_rw_complete, |
|
147 |
req); |
|
148 |
} else { |
|
149 |
for (i = 0; i < req->elem.in_num - 1; i++) |
|
150 |
req->size += req->elem.in_sg[i].iov_len; |
|
151 |
|
|
152 |
req->buffer = qemu_memalign(512, req->size); |
|
153 |
if (req->buffer == NULL) { |
|
154 |
qemu_free(req); |
|
155 |
break; |
|
156 |
} |
|
157 |
|
|
158 |
bdrv_aio_read(s->bs, req->out->sector, |
|
159 |
req->buffer, |
|
160 |
req->size / 512, |
|
161 |
virtio_blk_rw_complete, |
|
162 |
req); |
|
163 |
} |
|
164 |
} |
|
165 |
/* |
|
166 |
* FIXME: Want to check for completions before returning to guest mode, |
|
167 |
* so cached reads and writes are reported as quickly as possible. But |
|
168 |
* that should be done in the generic block layer. |
|
169 |
*/ |
|
170 |
} |
|
171 |
|
|
172 |
static void virtio_blk_reset(VirtIODevice *vdev) |
|
173 |
{ |
|
174 |
/* |
|
175 |
* This should cancel pending requests, but can't do nicely until there |
|
176 |
* are per-device request lists. |
|
177 |
*/ |
|
178 |
qemu_aio_flush(); |
|
179 |
} |
|
180 |
|
|
181 |
static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config) |
|
182 |
{ |
|
183 |
VirtIOBlock *s = to_virtio_blk(vdev); |
|
184 |
struct virtio_blk_config blkcfg; |
|
185 |
uint64_t capacity; |
|
186 |
int cylinders, heads, secs; |
|
187 |
|
|
188 |
bdrv_get_geometry(s->bs, &capacity); |
|
189 |
bdrv_get_geometry_hint(s->bs, &cylinders, &heads, &secs); |
|
190 |
stq_raw(&blkcfg.capacity, capacity); |
|
191 |
stl_raw(&blkcfg.seg_max, 128 - 2); |
|
192 |
stw_raw(&blkcfg.cylinders, cylinders); |
|
193 |
blkcfg.heads = heads; |
|
194 |
blkcfg.sectors = secs; |
|
195 |
memcpy(config, &blkcfg, sizeof(blkcfg)); |
|
196 |
} |
|
197 |
|
|
198 |
static uint32_t virtio_blk_get_features(VirtIODevice *vdev) |
|
199 |
{ |
|
200 |
return (1 << VIRTIO_BLK_F_SEG_MAX | 1 << VIRTIO_BLK_F_GEOMETRY); |
|
201 |
} |
|
202 |
|
|
203 |
static void virtio_blk_save(QEMUFile *f, void *opaque) |
|
204 |
{ |
|
205 |
VirtIOBlock *s = opaque; |
|
206 |
virtio_save(&s->vdev, f); |
|
207 |
} |
|
208 |
|
|
209 |
static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id) |
|
210 |
{ |
|
211 |
VirtIOBlock *s = opaque; |
|
212 |
|
|
213 |
if (version_id != 1) |
|
214 |
return -EINVAL; |
|
215 |
|
|
216 |
virtio_load(&s->vdev, f); |
|
217 |
|
|
218 |
return 0; |
|
219 |
} |
|
220 |
|
|
221 |
void *virtio_blk_init(PCIBus *bus, uint16_t vendor, uint16_t device, |
|
222 |
BlockDriverState *bs) |
|
223 |
{ |
|
224 |
VirtIOBlock *s; |
|
225 |
int cylinders, heads, secs; |
|
226 |
static int virtio_blk_id; |
|
227 |
|
|
228 |
s = (VirtIOBlock *)virtio_init_pci(bus, "virtio-blk", vendor, device, |
|
229 |
0, VIRTIO_ID_BLOCK, |
|
230 |
0x01, 0x80, 0x00, |
|
231 |
sizeof(struct virtio_blk_config), sizeof(VirtIOBlock)); |
|
232 |
if (!s) |
|
233 |
return NULL; |
|
234 |
|
|
235 |
s->vdev.get_config = virtio_blk_update_config; |
|
236 |
s->vdev.get_features = virtio_blk_get_features; |
|
237 |
s->vdev.reset = virtio_blk_reset; |
|
238 |
s->bs = bs; |
|
239 |
bdrv_guess_geometry(s->bs, &cylinders, &heads, &secs); |
|
240 |
bdrv_set_geometry_hint(s->bs, cylinders, heads, secs); |
|
241 |
|
|
242 |
s->vq = virtio_add_queue(&s->vdev, 128, virtio_blk_handle_output); |
|
243 |
|
|
244 |
register_savevm("virtio-blk", virtio_blk_id++, 1, |
|
245 |
virtio_blk_save, virtio_blk_load, s); |
|
246 |
|
|
247 |
return s; |
|
248 |
} |
b/hw/virtio-blk.h | ||
---|---|---|
1 |
/* |
|
2 |
* Virtio Block Device |
|
3 |
* |
|
4 |
* Copyright IBM, Corp. 2007 |
|
5 |
* |
|
6 |
* Authors: |
|
7 |
* Anthony Liguori <aliguori@us.ibm.com> |
|
8 |
* |
|
9 |
* This work is licensed under the terms of the GNU GPL, version 2. See |
|
10 |
* the COPYING file in the top-level directory. |
|
11 |
* |
|
12 |
*/ |
|
13 |
|
|
14 |
#ifndef _QEMU_VIRTIO_BLK_H |
|
15 |
#define _QEMU_VIRTIO_BLK_H |
|
16 |
|
|
17 |
#include "virtio.h" |
|
18 |
#include "block.h" |
|
19 |
#include "pci.h" |
|
20 |
|
|
21 |
/* from Linux's linux/virtio_blk.h */ |
|
22 |
|
|
23 |
/* The ID for virtio_block */ |
|
24 |
#define VIRTIO_ID_BLOCK 2 |
|
25 |
|
|
26 |
/* Feature bits */ |
|
27 |
#define VIRTIO_BLK_F_BARRIER 0 /* Does host support barriers? */ |
|
28 |
#define VIRTIO_BLK_F_SIZE_MAX 1 /* Indicates maximum segment size */ |
|
29 |
#define VIRTIO_BLK_F_SEG_MAX 2 /* Indicates maximum # of segments */ |
|
30 |
#define VIRTIO_BLK_F_GEOMETRY 4 /* Indicates support of legacy geometry */ |
|
31 |
|
|
32 |
struct virtio_blk_config |
|
33 |
{ |
|
34 |
uint64_t capacity; |
|
35 |
uint32_t size_max; |
|
36 |
uint32_t seg_max; |
|
37 |
uint16_t cylinders; |
|
38 |
uint8_t heads; |
|
39 |
uint8_t sectors; |
|
40 |
} __attribute__((packed)); |
|
41 |
|
|
42 |
/* These two define direction. */ |
|
43 |
#define VIRTIO_BLK_T_IN 0 |
|
44 |
#define VIRTIO_BLK_T_OUT 1 |
|
45 |
|
|
46 |
/* This bit says it's a scsi command, not an actual read or write. */ |
|
47 |
#define VIRTIO_BLK_T_SCSI_CMD 2 |
|
48 |
|
|
49 |
/* Barrier before this op. */ |
|
50 |
#define VIRTIO_BLK_T_BARRIER 0x80000000 |
|
51 |
|
|
52 |
/* This is the first element of the read scatter-gather list. */ |
|
53 |
struct virtio_blk_outhdr |
|
54 |
{ |
|
55 |
/* VIRTIO_BLK_T* */ |
|
56 |
uint32_t type; |
|
57 |
/* io priority. */ |
|
58 |
uint32_t ioprio; |
|
59 |
/* Sector (ie. 512 byte offset) */ |
|
60 |
uint64_t sector; |
|
61 |
}; |
|
62 |
|
|
63 |
#define VIRTIO_BLK_S_OK 0 |
|
64 |
#define VIRTIO_BLK_S_IOERR 1 |
|
65 |
#define VIRTIO_BLK_S_UNSUPP 2 |
|
66 |
|
|
67 |
/* This is the first element of the write scatter-gather list */ |
|
68 |
struct virtio_blk_inhdr |
|
69 |
{ |
|
70 |
unsigned char status; |
|
71 |
}; |
|
72 |
|
|
73 |
void *virtio_blk_init(PCIBus *bus, uint16_t vendor, uint16_t device, |
|
74 |
BlockDriverState *bs); |
|
75 |
|
|
76 |
#endif |
b/qemu-doc.texi | ||
---|---|---|
253 | 253 |
(for instance, "file=my,,file" to use file "my,file"). |
254 | 254 |
@item if=@var{interface} |
255 | 255 |
This option defines on which type on interface the drive is connected. |
256 |
Available types are: ide, scsi, sd, mtd, floppy, pflash. |
|
256 |
Available types are: ide, scsi, sd, mtd, floppy, pflash, virtio.
|
|
257 | 257 |
@item bus=@var{bus},unit=@var{unit} |
258 | 258 |
These options define where is connected the drive by defining the bus number and |
259 | 259 |
the unit id. |
b/sysemu.h | ||
---|---|---|
123 | 123 |
#endif |
124 | 124 |
|
125 | 125 |
typedef enum { |
126 |
IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD |
|
126 |
IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO
|
|
127 | 127 |
} BlockInterfaceType; |
128 | 128 |
|
129 | 129 |
typedef struct DriveInfo { |
b/vl.c | ||
---|---|---|
2267 | 2267 |
} else if (!strcmp(buf, "sd")) { |
2268 | 2268 |
type = IF_SD; |
2269 | 2269 |
max_devs = 0; |
2270 |
} else { |
|
2270 |
} else if (!strcmp(buf, "virtio")) { |
|
2271 |
type = IF_VIRTIO; |
|
2272 |
max_devs = 0; |
|
2273 |
} else { |
|
2271 | 2274 |
fprintf(stderr, "qemu: '%s' unsupported bus type '%s'\n", str, buf); |
2272 | 2275 |
return -1; |
2273 | 2276 |
} |
... | ... | |
2474 | 2477 |
break; |
2475 | 2478 |
case IF_PFLASH: |
2476 | 2479 |
case IF_MTD: |
2480 |
case IF_VIRTIO: |
|
2477 | 2481 |
break; |
2478 | 2482 |
} |
2479 | 2483 |
if (!file[0]) |
Also available in: Unified diff