Beispiel #1
0
static int vhost_virtqueue_init(struct vhost_dev *dev,
                                struct VirtIODevice *vdev,
                                struct vhost_virtqueue *vq,
                                unsigned idx)
{
    target_phys_addr_t s, l, a;
    int r;
    struct vhost_vring_file file = {
        .index = idx,
    };
    struct vhost_vring_state state = {
        .index = idx,
    };
    struct VirtQueue *vvq = virtio_get_queue(vdev, idx);

    if (!vdev->binding->set_host_notifier) {
        fprintf(stderr, "binding does not support host notifiers\n");
        return -ENOSYS;
    }

    vq->num = state.num = virtio_queue_get_num(vdev, idx);
    r = ioctl(dev->control, VHOST_SET_VRING_NUM, &state);
    if (r) {
        return -errno;
    }

    state.num = virtio_queue_get_last_avail_idx(vdev, idx);
    r = ioctl(dev->control, VHOST_SET_VRING_BASE, &state);
    if (r) {
        return -errno;
    }

    s = l = virtio_queue_get_desc_size(vdev, idx);
    a = virtio_queue_get_desc_addr(vdev, idx);
    vq->desc = cpu_physical_memory_map(a, &l, 0);
    if (!vq->desc || l != s) {
        r = -ENOMEM;
        goto fail_alloc_desc;
    }
    s = l = virtio_queue_get_avail_size(vdev, idx);
    a = virtio_queue_get_avail_addr(vdev, idx);
    vq->avail = cpu_physical_memory_map(a, &l, 0);
    if (!vq->avail || l != s) {
        r = -ENOMEM;
        goto fail_alloc_avail;
    }
    vq->used_size = s = l = virtio_queue_get_used_size(vdev, idx);
    vq->used_phys = a = virtio_queue_get_used_addr(vdev, idx);
    vq->used = cpu_physical_memory_map(a, &l, 1);
    if (!vq->used || l != s) {
        r = -ENOMEM;
        goto fail_alloc_used;
    }

    vq->ring_size = s = l = virtio_queue_get_ring_size(vdev, idx);
    vq->ring_phys = a = virtio_queue_get_ring_addr(vdev, idx);
    vq->ring = cpu_physical_memory_map(a, &l, 1);
    if (!vq->ring || l != s) {
        r = -ENOMEM;
        goto fail_alloc_ring;
    }

    r = vhost_virtqueue_set_addr(dev, vq, idx, dev->log_enabled);
    if (r < 0) {
        r = -errno;
        goto fail_alloc;
    }
    r = vdev->binding->set_host_notifier(vdev->binding_opaque, idx, true);
    if (r < 0) {
        fprintf(stderr, "Error binding host notifier: %d\n", -r);
        goto fail_host_notifier;
    }

    file.fd = event_notifier_get_fd(virtio_queue_get_host_notifier(vvq));
    r = ioctl(dev->control, VHOST_SET_VRING_KICK, &file);
    if (r) {
        r = -errno;
        goto fail_kick;
    }

    file.fd = event_notifier_get_fd(virtio_queue_get_guest_notifier(vvq));
    r = ioctl(dev->control, VHOST_SET_VRING_CALL, &file);
    if (r) {
        r = -errno;
        goto fail_call;
    }

    return 0;

fail_call:
fail_kick:
    vdev->binding->set_host_notifier(vdev->binding_opaque, idx, false);
fail_host_notifier:
fail_alloc:
    cpu_physical_memory_unmap(vq->ring, virtio_queue_get_ring_size(vdev, idx),
                              0, 0);
fail_alloc_ring:
    cpu_physical_memory_unmap(vq->used, virtio_queue_get_used_size(vdev, idx),
                              0, 0);
fail_alloc_used:
    cpu_physical_memory_unmap(vq->avail, virtio_queue_get_avail_size(vdev, idx),
                              0, 0);
fail_alloc_avail:
    cpu_physical_memory_unmap(vq->desc, virtio_queue_get_desc_size(vdev, idx),
                              0, 0);
fail_alloc_desc:
    return r;
}
Beispiel #2
0
/* Map the guest's vring to host memory */
bool vring_setup(Vring *vring, VirtIODevice *vdev, int n)
{
    struct vring *vr = &vring->vr;
    hwaddr addr;
    hwaddr size;
    void *ptr;

    vring->broken = false;
    vr->num = virtio_queue_get_num(vdev, n);

    addr = virtio_queue_get_desc_addr(vdev, n);
    size = virtio_queue_get_desc_size(vdev, n);
    /* Map the descriptor area as read only */
    ptr = vring_map(&vring->mr_desc, addr, size, NULL, false);
    if (!ptr) {
        error_report("Failed to map 0x%" HWADDR_PRIx " byte for vring desc "
                     "at 0x%" HWADDR_PRIx,
                      size, addr);
        goto out_err_desc;
    }
    vr->desc = ptr;

    addr = virtio_queue_get_avail_addr(vdev, n);
    size = virtio_queue_get_avail_size(vdev, n);
    /* Add the size of the used_event_idx */
    size += sizeof(uint16_t);
    /* Map the driver area as read only */
    ptr = vring_map(&vring->mr_avail, addr, size, NULL, false);
    if (!ptr) {
        error_report("Failed to map 0x%" HWADDR_PRIx " byte for vring avail "
                     "at 0x%" HWADDR_PRIx,
                      size, addr);
        goto out_err_avail;
    }
    vr->avail = ptr;

    addr = virtio_queue_get_used_addr(vdev, n);
    size = virtio_queue_get_used_size(vdev, n);
    /* Add the size of the avail_event_idx */
    size += sizeof(uint16_t);
    /* Map the device area as read-write */
    ptr = vring_map(&vring->mr_used, addr, size, NULL, true);
    if (!ptr) {
        error_report("Failed to map 0x%" HWADDR_PRIx " byte for vring used "
                     "at 0x%" HWADDR_PRIx,
                      size, addr);
        goto out_err_used;
    }
    vr->used = ptr;

    vring->last_avail_idx = virtio_queue_get_last_avail_idx(vdev, n);
    vring->last_used_idx = vring_get_used_idx(vdev, vring);
    vring->signalled_used = 0;
    vring->signalled_used_valid = false;

    trace_vring_setup(virtio_queue_get_ring_addr(vdev, n),
                      vring->vr.desc, vring->vr.avail, vring->vr.used);
    return true;

out_err_used:
    memory_region_unref(vring->mr_avail);
out_err_avail:
    memory_region_unref(vring->mr_desc);
out_err_desc:
    vring->broken = true;
    return false;
}