mirror of https://gitee.com/openkylin/qemu.git
Use the DMA api to map virtio elements.
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6904 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
d28a1b6ec6
commit
26b258e138
97
hw/virtio.c
97
hw/virtio.c
|
@ -16,8 +16,6 @@
|
|||
#include "virtio.h"
|
||||
#include "sysemu.h"
|
||||
|
||||
//#define VIRTIO_ZERO_COPY
|
||||
|
||||
/* from Linux's linux/virtio_pci.h */
|
||||
|
||||
/* A 32-bit r/o bitmask of the features supported by the host */
|
||||
|
@ -113,43 +111,6 @@ struct VirtQueue
|
|||
#define VIRTIO_PCI_QUEUE_MAX 16
|
||||
|
||||
/* virt queue functions */
|
||||
#ifdef VIRTIO_ZERO_COPY
|
||||
static void *virtio_map_gpa(target_phys_addr_t addr, size_t size)
|
||||
{
|
||||
ram_addr_t off;
|
||||
target_phys_addr_t addr1;
|
||||
|
||||
off = cpu_get_physical_page_desc(addr);
|
||||
if ((off & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
|
||||
fprintf(stderr, "virtio DMA to IO ram\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
off = (off & TARGET_PAGE_MASK) | (addr & ~TARGET_PAGE_MASK);
|
||||
|
||||
for (addr1 = addr + TARGET_PAGE_SIZE;
|
||||
addr1 < TARGET_PAGE_ALIGN(addr + size);
|
||||
addr1 += TARGET_PAGE_SIZE) {
|
||||
ram_addr_t off1;
|
||||
|
||||
off1 = cpu_get_physical_page_desc(addr1);
|
||||
if ((off1 & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
|
||||
fprintf(stderr, "virtio DMA to IO ram\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
off1 = (off1 & TARGET_PAGE_MASK) | (addr1 & ~TARGET_PAGE_MASK);
|
||||
|
||||
if (off1 != (off + (addr1 - addr))) {
|
||||
fprintf(stderr, "discontigous virtio memory\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
return phys_ram_base + off;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void virtqueue_init(VirtQueue *vq, target_phys_addr_t pa)
|
||||
{
|
||||
vq->vring.desc = pa;
|
||||
|
@ -274,35 +235,22 @@ void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
|
|||
unsigned int offset;
|
||||
int i;
|
||||
|
||||
#ifndef VIRTIO_ZERO_COPY
|
||||
for (i = 0; i < elem->out_num; i++)
|
||||
qemu_free(elem->out_sg[i].iov_base);
|
||||
#endif
|
||||
|
||||
offset = 0;
|
||||
for (i = 0; i < elem->in_num; i++) {
|
||||
size_t size = MIN(len - offset, elem->in_sg[i].iov_len);
|
||||
|
||||
#ifdef VIRTIO_ZERO_COPY
|
||||
if (size) {
|
||||
ram_addr_t addr = (uint8_t *)elem->in_sg[i].iov_base - phys_ram_base;
|
||||
ram_addr_t off;
|
||||
cpu_physical_memory_unmap(elem->in_sg[i].iov_base,
|
||||
elem->in_sg[i].iov_len,
|
||||
1, size);
|
||||
|
||||
for (off = 0; off < size; off += TARGET_PAGE_SIZE)
|
||||
cpu_physical_memory_set_dirty(addr + off);
|
||||
}
|
||||
#else
|
||||
if (size)
|
||||
cpu_physical_memory_write(elem->in_addr[i],
|
||||
elem->in_sg[i].iov_base,
|
||||
size);
|
||||
|
||||
qemu_free(elem->in_sg[i].iov_base);
|
||||
#endif
|
||||
|
||||
offset += size;
|
||||
offset += elem->in_sg[i].iov_len;
|
||||
}
|
||||
|
||||
for (i = 0; i < elem->out_num; i++)
|
||||
cpu_physical_memory_unmap(elem->out_sg[i].iov_base,
|
||||
elem->out_sg[i].iov_len,
|
||||
0, elem->out_sg[i].iov_len);
|
||||
|
||||
idx = (idx + vring_used_idx(vq)) % vq->vring.num;
|
||||
|
||||
/* Get a pointer to the next entry in the used ring. */
|
||||
|
@ -414,6 +362,7 @@ int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes)
|
|||
int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
|
||||
{
|
||||
unsigned int i, head;
|
||||
target_phys_addr_t len;
|
||||
|
||||
if (!virtqueue_num_heads(vq, vq->last_avail_idx))
|
||||
return 0;
|
||||
|
@ -424,37 +373,23 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
|
|||
i = head = virtqueue_get_head(vq, vq->last_avail_idx++);
|
||||
do {
|
||||
struct iovec *sg;
|
||||
int is_write = 0;
|
||||
|
||||
if (vring_desc_flags(vq, i) & VRING_DESC_F_WRITE) {
|
||||
elem->in_addr[elem->in_num] = vring_desc_addr(vq, i);
|
||||
sg = &elem->in_sg[elem->in_num++];
|
||||
is_write = 1;
|
||||
} else
|
||||
sg = &elem->out_sg[elem->out_num++];
|
||||
|
||||
/* Grab the first descriptor, and check it's OK. */
|
||||
sg->iov_len = vring_desc_len(vq, i);
|
||||
len = sg->iov_len;
|
||||
|
||||
#ifdef VIRTIO_ZERO_COPY
|
||||
sg->iov_base = virtio_map_gpa(vring_desc_addr(vq, i), sg->iov_len);
|
||||
#else
|
||||
/* cap individual scatter element size to prevent unbounded allocations
|
||||
of memory from the guest. Practically speaking, no virtio driver
|
||||
will ever pass more than a page in each element. We set the cap to
|
||||
be 2MB in case for some reason a large page makes it way into the
|
||||
sg list. When we implement a zero copy API, this limitation will
|
||||
disappear */
|
||||
if (sg->iov_len > (2 << 20))
|
||||
sg->iov_len = 2 << 20;
|
||||
sg->iov_base = cpu_physical_memory_map(vring_desc_addr(vq, i), &len, is_write);
|
||||
|
||||
sg->iov_base = qemu_malloc(sg->iov_len);
|
||||
if (!(vring_desc_flags(vq, i) & VRING_DESC_F_WRITE)) {
|
||||
cpu_physical_memory_read(vring_desc_addr(vq, i),
|
||||
sg->iov_base,
|
||||
sg->iov_len);
|
||||
}
|
||||
#endif
|
||||
if (sg->iov_base == NULL) {
|
||||
fprintf(stderr, "Invalid mapping\n");
|
||||
if (sg->iov_base == NULL || len != sg->iov_len) {
|
||||
fprintf(stderr, "virtio: trying to map MMIO memory\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue