Example #1
0
static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,
        void *arg)
{
    VhostUserMsg msg;
    VhostUserRequest msg_request;
    struct vhost_vring_file *file = 0;
    int need_reply = 0;
    int fds[VHOST_MEMORY_MAX_NREGIONS];
    int i, fd;
    size_t fd_num = 0;

    assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);

    msg_request = vhost_user_request_translate(request);
    msg.request = msg_request;
    msg.flags = VHOST_USER_VERSION;
    msg.size = 0;

    switch (request) {
    case VHOST_GET_FEATURES:
        need_reply = 1;
        break;

    case VHOST_SET_FEATURES:
    case VHOST_SET_LOG_BASE:
        msg.u64 = *((__u64 *) arg);
        msg.size = sizeof(m.u64);
        break;

    case VHOST_SET_OWNER:
    case VHOST_RESET_OWNER:
        break;

    case VHOST_SET_MEM_TABLE:
        for (i = 0; i < dev->mem->nregions; ++i) {
            struct vhost_memory_region *reg = dev->mem->regions + i;
            ram_addr_t ram_addr;

            assert((uintptr_t)reg->userspace_addr == reg->userspace_addr);
            qemu_ram_addr_from_host((void *)(uintptr_t)reg->userspace_addr, &ram_addr);
            fd = qemu_get_ram_fd(ram_addr);
            if (fd > 0) {
                msg.memory.regions[fd_num].userspace_addr = reg->userspace_addr;
                msg.memory.regions[fd_num].memory_size  = reg->memory_size;
                msg.memory.regions[fd_num].guest_phys_addr = reg->guest_phys_addr;
                msg.memory.regions[fd_num].mmap_offset = reg->userspace_addr -
                    (uintptr_t) qemu_get_ram_block_host_ptr(ram_addr);
                assert(fd_num < VHOST_MEMORY_MAX_NREGIONS);
                fds[fd_num++] = fd;
            }
        }

        msg.memory.nregions = fd_num;

        if (!fd_num) {
            error_report("Failed initializing vhost-user memory map, "
                    "consider using -object memory-backend-file share=on");
            return -1;
        }

        msg.size = sizeof(m.memory.nregions);
        msg.size += sizeof(m.memory.padding);
        msg.size += fd_num * sizeof(VhostUserMemoryRegion);

        break;

    case VHOST_SET_LOG_FD:
        fds[fd_num++] = *((int *) arg);
        break;

    case VHOST_SET_VRING_NUM:
    case VHOST_SET_VRING_BASE:
        memcpy(&msg.state, arg, sizeof(struct vhost_vring_state));
        msg.size = sizeof(m.state);
        break;

    case VHOST_GET_VRING_BASE:
        memcpy(&msg.state, arg, sizeof(struct vhost_vring_state));
        msg.size = sizeof(m.state);
        need_reply = 1;
        break;

    case VHOST_SET_VRING_ADDR:
        memcpy(&msg.addr, arg, sizeof(struct vhost_vring_addr));
        msg.size = sizeof(m.addr);
        break;

    case VHOST_SET_VRING_KICK:
    case VHOST_SET_VRING_CALL:
    case VHOST_SET_VRING_ERR:
        file = arg;
        msg.u64 = file->index & VHOST_USER_VRING_IDX_MASK;
        msg.size = sizeof(m.u64);
        if (ioeventfd_enabled() && file->fd > 0) {
            fds[fd_num++] = file->fd;
        } else {
            msg.u64 |= VHOST_USER_VRING_NOFD_MASK;
        }
        break;
    default:
        error_report("vhost-user trying to send unhandled ioctl");
        return -1;
        break;
    }

    if (vhost_user_write(dev, &msg, fds, fd_num) < 0) {
        return 0;
    }

    if (need_reply) {
        if (vhost_user_read(dev, &msg) < 0) {
            return 0;
        }

        if (msg_request != msg.request) {
            error_report("Received unexpected msg type."
                    " Expected %d received %d", msg_request, msg.request);
            return -1;
        }

        switch (msg_request) {
        case VHOST_USER_GET_FEATURES:
            if (msg.size != sizeof(m.u64)) {
                error_report("Received bad msg size.");
                return -1;
            }
            *((__u64 *) arg) = msg.u64;
            break;
        case VHOST_USER_GET_VRING_BASE:
            if (msg.size != sizeof(m.state)) {
                error_report("Received bad msg size.");
                return -1;
            }
            memcpy(arg, &msg.state, sizeof(struct vhost_vring_state));
            break;
        default:
            error_report("Received unexpected msg type.");
            return -1;
            break;
        }
    }

    return 0;
}
Example #2
0
static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base,
                                   struct vhost_log *log)
{
    int fds[VHOST_MEMORY_MAX_NREGIONS];
    size_t fd_num = 0;
    bool shmfd = virtio_has_feature(dev->protocol_features,
                                    VHOST_USER_PROTOCOL_F_LOG_SHMFD);
    VhostUserMsg msg = {
        .request = VHOST_USER_SET_LOG_BASE,
        .flags = VHOST_USER_VERSION,
        .payload.u64 = base,
        .size = sizeof(msg.payload.u64),
    };

    if (shmfd && log->fd != -1) {
        fds[fd_num++] = log->fd;
    }

    vhost_user_write(dev, &msg, fds, fd_num);

    if (shmfd) {
        msg.size = 0;
        if (vhost_user_read(dev, &msg) < 0) {
            return 0;
        }

        if (msg.request != VHOST_USER_SET_LOG_BASE) {
            error_report("Received unexpected msg type. "
                         "Expected %d received %d",
                         VHOST_USER_SET_LOG_BASE, msg.request);
            return -1;
        }
    }

    return 0;
}

static int vhost_user_set_mem_table(struct vhost_dev *dev,
                                    struct vhost_memory *mem)
{
    int fds[VHOST_MEMORY_MAX_NREGIONS];
    int i, fd;
    size_t fd_num = 0;
    VhostUserMsg msg = {
        .request = VHOST_USER_SET_MEM_TABLE,
        .flags = VHOST_USER_VERSION,
    };

    for (i = 0; i < dev->mem->nregions; ++i) {
        struct vhost_memory_region *reg = dev->mem->regions + i;
        ram_addr_t ram_addr;

        assert((uintptr_t)reg->userspace_addr == reg->userspace_addr);
        qemu_ram_addr_from_host((void *)(uintptr_t)reg->userspace_addr,
                                &ram_addr);
        fd = qemu_get_ram_fd(ram_addr);
        if (fd > 0) {
            msg.payload.memory.regions[fd_num].userspace_addr = reg->userspace_addr;
            msg.payload.memory.regions[fd_num].memory_size  = reg->memory_size;
            msg.payload.memory.regions[fd_num].guest_phys_addr = reg->guest_phys_addr;
            msg.payload.memory.regions[fd_num].mmap_offset = reg->userspace_addr -
                (uintptr_t) qemu_get_ram_block_host_ptr(ram_addr);
            assert(fd_num < VHOST_MEMORY_MAX_NREGIONS);
            fds[fd_num++] = fd;
        }
    }

    msg.payload.memory.nregions = fd_num;

    if (!fd_num) {
        error_report("Failed initializing vhost-user memory map, "
                     "consider using -object memory-backend-file share=on");
        return -1;
    }

    msg.size = sizeof(msg.payload.memory.nregions);
    msg.size += sizeof(msg.payload.memory.padding);
    msg.size += fd_num * sizeof(VhostUserMemoryRegion);

    vhost_user_write(dev, &msg, fds, fd_num);

    return 0;
}