Revision 26b258e1 hw/virtio.c
b/hw/virtio.c | ||
---|---|---|
16 | 16 |
#include "virtio.h" |
17 | 17 |
#include "sysemu.h" |
18 | 18 |
|
19 |
//#define VIRTIO_ZERO_COPY |
|
20 |
|
|
21 | 19 |
/* from Linux's linux/virtio_pci.h */ |
22 | 20 |
|
23 | 21 |
/* A 32-bit r/o bitmask of the features supported by the host */ |
... | ... | |
113 | 111 |
#define VIRTIO_PCI_QUEUE_MAX 16 |
114 | 112 |
|
115 | 113 |
/* virt queue functions */ |
116 |
#ifdef VIRTIO_ZERO_COPY |
|
117 |
static void *virtio_map_gpa(target_phys_addr_t addr, size_t size) |
|
118 |
{ |
|
119 |
ram_addr_t off; |
|
120 |
target_phys_addr_t addr1; |
|
121 |
|
|
122 |
off = cpu_get_physical_page_desc(addr); |
|
123 |
if ((off & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { |
|
124 |
fprintf(stderr, "virtio DMA to IO ram\n"); |
|
125 |
exit(1); |
|
126 |
} |
|
127 |
|
|
128 |
off = (off & TARGET_PAGE_MASK) | (addr & ~TARGET_PAGE_MASK); |
|
129 |
|
|
130 |
for (addr1 = addr + TARGET_PAGE_SIZE; |
|
131 |
addr1 < TARGET_PAGE_ALIGN(addr + size); |
|
132 |
addr1 += TARGET_PAGE_SIZE) { |
|
133 |
ram_addr_t off1; |
|
134 |
|
|
135 |
off1 = cpu_get_physical_page_desc(addr1); |
|
136 |
if ((off1 & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { |
|
137 |
fprintf(stderr, "virtio DMA to IO ram\n"); |
|
138 |
exit(1); |
|
139 |
} |
|
140 |
|
|
141 |
off1 = (off1 & TARGET_PAGE_MASK) | (addr1 & ~TARGET_PAGE_MASK); |
|
142 |
|
|
143 |
if (off1 != (off + (addr1 - addr))) { |
|
144 |
fprintf(stderr, "discontigous virtio memory\n"); |
|
145 |
exit(1); |
|
146 |
} |
|
147 |
} |
|
148 |
|
|
149 |
return phys_ram_base + off; |
|
150 |
} |
|
151 |
#endif |
|
152 |
|
|
153 | 114 |
static void virtqueue_init(VirtQueue *vq, target_phys_addr_t pa) |
154 | 115 |
{ |
155 | 116 |
vq->vring.desc = pa; |
... | ... | |
274 | 235 |
unsigned int offset; |
275 | 236 |
int i; |
276 | 237 |
|
277 |
#ifndef VIRTIO_ZERO_COPY |
|
278 |
for (i = 0; i < elem->out_num; i++) |
|
279 |
qemu_free(elem->out_sg[i].iov_base); |
|
280 |
#endif |
|
281 |
|
|
282 | 238 |
offset = 0; |
283 | 239 |
for (i = 0; i < elem->in_num; i++) { |
284 | 240 |
size_t size = MIN(len - offset, elem->in_sg[i].iov_len); |
285 | 241 |
|
286 |
#ifdef VIRTIO_ZERO_COPY |
|
287 |
if (size) { |
|
288 |
ram_addr_t addr = (uint8_t *)elem->in_sg[i].iov_base - phys_ram_base; |
|
289 |
ram_addr_t off; |
|
242 |
cpu_physical_memory_unmap(elem->in_sg[i].iov_base, |
|
243 |
elem->in_sg[i].iov_len, |
|
244 |
1, size); |
|
290 | 245 |
|
291 |
for (off = 0; off < size; off += TARGET_PAGE_SIZE) |
|
292 |
cpu_physical_memory_set_dirty(addr + off); |
|
293 |
} |
|
294 |
#else |
|
295 |
if (size) |
|
296 |
cpu_physical_memory_write(elem->in_addr[i], |
|
297 |
elem->in_sg[i].iov_base, |
|
298 |
size); |
|
299 |
|
|
300 |
qemu_free(elem->in_sg[i].iov_base); |
|
301 |
#endif |
|
302 |
|
|
303 |
offset += size; |
|
246 |
offset += elem->in_sg[i].iov_len; |
|
304 | 247 |
} |
305 | 248 |
|
249 |
for (i = 0; i < elem->out_num; i++) |
|
250 |
cpu_physical_memory_unmap(elem->out_sg[i].iov_base, |
|
251 |
elem->out_sg[i].iov_len, |
|
252 |
0, elem->out_sg[i].iov_len); |
|
253 |
|
|
306 | 254 |
idx = (idx + vring_used_idx(vq)) % vq->vring.num; |
307 | 255 |
|
308 | 256 |
/* Get a pointer to the next entry in the used ring. */ |
... | ... | |
414 | 362 |
int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem) |
415 | 363 |
{ |
416 | 364 |
unsigned int i, head; |
365 |
target_phys_addr_t len; |
|
417 | 366 |
|
418 | 367 |
if (!virtqueue_num_heads(vq, vq->last_avail_idx)) |
419 | 368 |
return 0; |
... | ... | |
424 | 373 |
i = head = virtqueue_get_head(vq, vq->last_avail_idx++); |
425 | 374 |
do { |
426 | 375 |
struct iovec *sg; |
376 |
int is_write = 0; |
|
427 | 377 |
|
428 | 378 |
if (vring_desc_flags(vq, i) & VRING_DESC_F_WRITE) { |
429 | 379 |
elem->in_addr[elem->in_num] = vring_desc_addr(vq, i); |
430 | 380 |
sg = &elem->in_sg[elem->in_num++]; |
381 |
is_write = 1; |
|
431 | 382 |
} else |
432 | 383 |
sg = &elem->out_sg[elem->out_num++]; |
433 | 384 |
|
434 | 385 |
/* Grab the first descriptor, and check it's OK. */ |
435 | 386 |
sg->iov_len = vring_desc_len(vq, i); |
387 |
len = sg->iov_len; |
|
436 | 388 |
|
437 |
#ifdef VIRTIO_ZERO_COPY |
|
438 |
sg->iov_base = virtio_map_gpa(vring_desc_addr(vq, i), sg->iov_len); |
|
439 |
#else |
|
440 |
/* cap individual scatter element size to prevent unbounded allocations |
|
441 |
of memory from the guest. Practically speaking, no virtio driver |
|
442 |
will ever pass more than a page in each element. We set the cap to |
|
443 |
be 2MB in case for some reason a large page makes it way into the |
|
444 |
sg list. When we implement a zero copy API, this limitation will |
|
445 |
disappear */ |
|
446 |
if (sg->iov_len > (2 << 20)) |
|
447 |
sg->iov_len = 2 << 20; |
|
448 |
|
|
449 |
sg->iov_base = qemu_malloc(sg->iov_len); |
|
450 |
if (!(vring_desc_flags(vq, i) & VRING_DESC_F_WRITE)) { |
|
451 |
cpu_physical_memory_read(vring_desc_addr(vq, i), |
|
452 |
sg->iov_base, |
|
453 |
sg->iov_len); |
|
454 |
} |
|
455 |
#endif |
|
456 |
if (sg->iov_base == NULL) { |
|
457 |
fprintf(stderr, "Invalid mapping\n"); |
|
389 |
sg->iov_base = cpu_physical_memory_map(vring_desc_addr(vq, i), &len, is_write); |
|
390 |
|
|
391 |
if (sg->iov_base == NULL || len != sg->iov_len) { |
|
392 |
fprintf(stderr, "virtio: trying to map MMIO memory\n"); |
|
458 | 393 |
exit(1); |
459 | 394 |
} |
460 | 395 |
|
Also available in: Unified diff