virtio-iommu: Add skeleton
This patchs adds the skeleton for the virtio-iommu device. Signed-off-by: Eric Auger <eric.auger@redhat.com> Reviewed-by: Peter Xu <peterx@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Message-Id: <20200214132745.23392-2-eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
parent
abdd16f468
commit
22c37a10f3
|
@ -9,6 +9,11 @@ config VIRTIO_RNG
|
||||||
default y
|
default y
|
||||||
depends on VIRTIO
|
depends on VIRTIO
|
||||||
|
|
||||||
|
config VIRTIO_IOMMU
|
||||||
|
bool
|
||||||
|
default y
|
||||||
|
depends on VIRTIO
|
||||||
|
|
||||||
config VIRTIO_PCI
|
config VIRTIO_PCI
|
||||||
bool
|
bool
|
||||||
default y if PCI_DEVICES
|
default y if PCI_DEVICES
|
||||||
|
|
|
@ -16,6 +16,7 @@ obj-$(call land,$(CONFIG_VIRTIO_CRYPTO),$(CONFIG_VIRTIO_PCI)) += virtio-crypto-p
|
||||||
obj-$(CONFIG_VIRTIO_PMEM) += virtio-pmem.o
|
obj-$(CONFIG_VIRTIO_PMEM) += virtio-pmem.o
|
||||||
common-obj-$(call land,$(CONFIG_VIRTIO_PMEM),$(CONFIG_VIRTIO_PCI)) += virtio-pmem-pci.o
|
common-obj-$(call land,$(CONFIG_VIRTIO_PMEM),$(CONFIG_VIRTIO_PCI)) += virtio-pmem-pci.o
|
||||||
obj-$(call land,$(CONFIG_VHOST_USER_FS),$(CONFIG_VIRTIO_PCI)) += vhost-user-fs-pci.o
|
obj-$(call land,$(CONFIG_VHOST_USER_FS),$(CONFIG_VIRTIO_PCI)) += vhost-user-fs-pci.o
|
||||||
|
obj-$(CONFIG_VIRTIO_IOMMU) += virtio-iommu.o
|
||||||
obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock.o
|
obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock.o
|
||||||
|
|
||||||
ifeq ($(CONFIG_VIRTIO_PCI),y)
|
ifeq ($(CONFIG_VIRTIO_PCI),y)
|
||||||
|
|
|
@ -53,3 +53,10 @@ virtio_mmio_write_offset(uint64_t offset, uint64_t value) "virtio_mmio_write off
|
||||||
virtio_mmio_guest_page(uint64_t size, int shift) "guest page size 0x%" PRIx64 " shift %d"
|
virtio_mmio_guest_page(uint64_t size, int shift) "guest page size 0x%" PRIx64 " shift %d"
|
||||||
virtio_mmio_queue_write(uint64_t value, int max_size) "mmio_queue write 0x%" PRIx64 " max %d"
|
virtio_mmio_queue_write(uint64_t value, int max_size) "mmio_queue write 0x%" PRIx64 " max %d"
|
||||||
virtio_mmio_setting_irq(int level) "virtio_mmio setting IRQ %d"
|
virtio_mmio_setting_irq(int level) "virtio_mmio setting IRQ %d"
|
||||||
|
|
||||||
|
# hw/virtio/virtio-iommu.c
|
||||||
|
virtio_iommu_device_reset(void) "reset!"
|
||||||
|
virtio_iommu_get_features(uint64_t features) "device supports features=0x%"PRIx64
|
||||||
|
virtio_iommu_device_status(uint8_t status) "driver status = %d"
|
||||||
|
virtio_iommu_get_config(uint64_t page_size_mask, uint64_t start, uint64_t end, uint32_t domain_range, uint32_t probe_size) "page_size_mask=0x%"PRIx64" start=0x%"PRIx64" end=0x%"PRIx64" domain_range=%d probe_size=0x%x"
|
||||||
|
virtio_iommu_set_config(uint64_t page_size_mask, uint64_t start, uint64_t end, uint32_t domain_range, uint32_t probe_size) "page_size_mask=0x%"PRIx64" start=0x%"PRIx64" end=0x%"PRIx64" domain_bits=%d probe_size=0x%x"
|
||||||
|
|
265
hw/virtio/virtio-iommu.c
Normal file
265
hw/virtio/virtio-iommu.c
Normal file
|
@ -0,0 +1,265 @@
|
||||||
|
/*
|
||||||
|
* virtio-iommu device
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2 or later, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "qemu/iov.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "hw/qdev-properties.h"
|
||||||
|
#include "hw/virtio/virtio.h"
|
||||||
|
#include "sysemu/kvm.h"
|
||||||
|
#include "trace.h"
|
||||||
|
|
||||||
|
#include "standard-headers/linux/virtio_ids.h"
|
||||||
|
|
||||||
|
#include "hw/virtio/virtio-bus.h"
|
||||||
|
#include "hw/virtio/virtio-access.h"
|
||||||
|
#include "hw/virtio/virtio-iommu.h"
|
||||||
|
|
||||||
|
/* Max size */
|
||||||
|
#define VIOMMU_DEFAULT_QUEUE_SIZE 256
|
||||||
|
|
||||||
|
static int virtio_iommu_handle_attach(VirtIOIOMMU *s,
|
||||||
|
struct iovec *iov,
|
||||||
|
unsigned int iov_cnt)
|
||||||
|
{
|
||||||
|
return VIRTIO_IOMMU_S_UNSUPP;
|
||||||
|
}
|
||||||
|
static int virtio_iommu_handle_detach(VirtIOIOMMU *s,
|
||||||
|
struct iovec *iov,
|
||||||
|
unsigned int iov_cnt)
|
||||||
|
{
|
||||||
|
return VIRTIO_IOMMU_S_UNSUPP;
|
||||||
|
}
|
||||||
|
static int virtio_iommu_handle_map(VirtIOIOMMU *s,
|
||||||
|
struct iovec *iov,
|
||||||
|
unsigned int iov_cnt)
|
||||||
|
{
|
||||||
|
return VIRTIO_IOMMU_S_UNSUPP;
|
||||||
|
}
|
||||||
|
static int virtio_iommu_handle_unmap(VirtIOIOMMU *s,
|
||||||
|
struct iovec *iov,
|
||||||
|
unsigned int iov_cnt)
|
||||||
|
{
|
||||||
|
return VIRTIO_IOMMU_S_UNSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_iommu_handle_command(VirtIODevice *vdev, VirtQueue *vq)
|
||||||
|
{
|
||||||
|
VirtIOIOMMU *s = VIRTIO_IOMMU(vdev);
|
||||||
|
struct virtio_iommu_req_head head;
|
||||||
|
struct virtio_iommu_req_tail tail = {};
|
||||||
|
VirtQueueElement *elem;
|
||||||
|
unsigned int iov_cnt;
|
||||||
|
struct iovec *iov;
|
||||||
|
size_t sz;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
|
||||||
|
if (!elem) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iov_size(elem->in_sg, elem->in_num) < sizeof(tail) ||
|
||||||
|
iov_size(elem->out_sg, elem->out_num) < sizeof(head)) {
|
||||||
|
virtio_error(vdev, "virtio-iommu bad head/tail size");
|
||||||
|
virtqueue_detach_element(vq, elem, 0);
|
||||||
|
g_free(elem);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
iov_cnt = elem->out_num;
|
||||||
|
iov = elem->out_sg;
|
||||||
|
sz = iov_to_buf(iov, iov_cnt, 0, &head, sizeof(head));
|
||||||
|
if (unlikely(sz != sizeof(head))) {
|
||||||
|
tail.status = VIRTIO_IOMMU_S_DEVERR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
qemu_mutex_lock(&s->mutex);
|
||||||
|
switch (head.type) {
|
||||||
|
case VIRTIO_IOMMU_T_ATTACH:
|
||||||
|
tail.status = virtio_iommu_handle_attach(s, iov, iov_cnt);
|
||||||
|
break;
|
||||||
|
case VIRTIO_IOMMU_T_DETACH:
|
||||||
|
tail.status = virtio_iommu_handle_detach(s, iov, iov_cnt);
|
||||||
|
break;
|
||||||
|
case VIRTIO_IOMMU_T_MAP:
|
||||||
|
tail.status = virtio_iommu_handle_map(s, iov, iov_cnt);
|
||||||
|
break;
|
||||||
|
case VIRTIO_IOMMU_T_UNMAP:
|
||||||
|
tail.status = virtio_iommu_handle_unmap(s, iov, iov_cnt);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
tail.status = VIRTIO_IOMMU_S_UNSUPP;
|
||||||
|
}
|
||||||
|
qemu_mutex_unlock(&s->mutex);
|
||||||
|
|
||||||
|
out:
|
||||||
|
sz = iov_from_buf(elem->in_sg, elem->in_num, 0,
|
||||||
|
&tail, sizeof(tail));
|
||||||
|
assert(sz == sizeof(tail));
|
||||||
|
|
||||||
|
virtqueue_push(vq, elem, sizeof(tail));
|
||||||
|
virtio_notify(vdev, vq);
|
||||||
|
g_free(elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_iommu_get_config(VirtIODevice *vdev, uint8_t *config_data)
|
||||||
|
{
|
||||||
|
VirtIOIOMMU *dev = VIRTIO_IOMMU(vdev);
|
||||||
|
struct virtio_iommu_config *config = &dev->config;
|
||||||
|
|
||||||
|
trace_virtio_iommu_get_config(config->page_size_mask,
|
||||||
|
config->input_range.start,
|
||||||
|
config->input_range.end,
|
||||||
|
config->domain_range.end,
|
||||||
|
config->probe_size);
|
||||||
|
memcpy(config_data, &dev->config, sizeof(struct virtio_iommu_config));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_iommu_set_config(VirtIODevice *vdev,
|
||||||
|
const uint8_t *config_data)
|
||||||
|
{
|
||||||
|
struct virtio_iommu_config config;
|
||||||
|
|
||||||
|
memcpy(&config, config_data, sizeof(struct virtio_iommu_config));
|
||||||
|
trace_virtio_iommu_set_config(config.page_size_mask,
|
||||||
|
config.input_range.start,
|
||||||
|
config.input_range.end,
|
||||||
|
config.domain_range.end,
|
||||||
|
config.probe_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t virtio_iommu_get_features(VirtIODevice *vdev, uint64_t f,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
VirtIOIOMMU *dev = VIRTIO_IOMMU(vdev);
|
||||||
|
|
||||||
|
f |= dev->features;
|
||||||
|
trace_virtio_iommu_get_features(f);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Migration is not yet supported: most of the state consists
|
||||||
|
* of balanced binary trees which are not yet ready for getting
|
||||||
|
* migrated
|
||||||
|
*/
|
||||||
|
static const VMStateDescription vmstate_virtio_iommu_device = {
|
||||||
|
.name = "virtio-iommu-device",
|
||||||
|
.unmigratable = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void virtio_iommu_device_realize(DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
||||||
|
VirtIOIOMMU *s = VIRTIO_IOMMU(dev);
|
||||||
|
|
||||||
|
virtio_init(vdev, "virtio-iommu", VIRTIO_ID_IOMMU,
|
||||||
|
sizeof(struct virtio_iommu_config));
|
||||||
|
|
||||||
|
s->req_vq = virtio_add_queue(vdev, VIOMMU_DEFAULT_QUEUE_SIZE,
|
||||||
|
virtio_iommu_handle_command);
|
||||||
|
s->event_vq = virtio_add_queue(vdev, VIOMMU_DEFAULT_QUEUE_SIZE, NULL);
|
||||||
|
|
||||||
|
s->config.page_size_mask = TARGET_PAGE_MASK;
|
||||||
|
s->config.input_range.end = -1UL;
|
||||||
|
s->config.domain_range.end = 32;
|
||||||
|
|
||||||
|
virtio_add_feature(&s->features, VIRTIO_RING_F_EVENT_IDX);
|
||||||
|
virtio_add_feature(&s->features, VIRTIO_RING_F_INDIRECT_DESC);
|
||||||
|
virtio_add_feature(&s->features, VIRTIO_F_VERSION_1);
|
||||||
|
virtio_add_feature(&s->features, VIRTIO_IOMMU_F_INPUT_RANGE);
|
||||||
|
virtio_add_feature(&s->features, VIRTIO_IOMMU_F_DOMAIN_RANGE);
|
||||||
|
virtio_add_feature(&s->features, VIRTIO_IOMMU_F_MAP_UNMAP);
|
||||||
|
virtio_add_feature(&s->features, VIRTIO_IOMMU_F_BYPASS);
|
||||||
|
virtio_add_feature(&s->features, VIRTIO_IOMMU_F_MMIO);
|
||||||
|
|
||||||
|
qemu_mutex_init(&s->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_iommu_device_unrealize(DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
||||||
|
|
||||||
|
virtio_cleanup(vdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_iommu_device_reset(VirtIODevice *vdev)
|
||||||
|
{
|
||||||
|
trace_virtio_iommu_device_reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_iommu_set_status(VirtIODevice *vdev, uint8_t status)
|
||||||
|
{
|
||||||
|
trace_virtio_iommu_device_status(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void virtio_iommu_instance_init(Object *obj)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_virtio_iommu = {
|
||||||
|
.name = "virtio-iommu",
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.version_id = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_VIRTIO_DEVICE,
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static Property virtio_iommu_properties[] = {
|
||||||
|
DEFINE_PROP_LINK("primary-bus", VirtIOIOMMU, primary_bus, "PCI", PCIBus *),
|
||||||
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
|
};
|
||||||
|
|
||||||
|
static void virtio_iommu_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
|
||||||
|
|
||||||
|
device_class_set_props(dc, virtio_iommu_properties);
|
||||||
|
dc->vmsd = &vmstate_virtio_iommu;
|
||||||
|
|
||||||
|
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||||
|
vdc->realize = virtio_iommu_device_realize;
|
||||||
|
vdc->unrealize = virtio_iommu_device_unrealize;
|
||||||
|
vdc->reset = virtio_iommu_device_reset;
|
||||||
|
vdc->get_config = virtio_iommu_get_config;
|
||||||
|
vdc->set_config = virtio_iommu_set_config;
|
||||||
|
vdc->get_features = virtio_iommu_get_features;
|
||||||
|
vdc->set_status = virtio_iommu_set_status;
|
||||||
|
vdc->vmsd = &vmstate_virtio_iommu_device;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo virtio_iommu_info = {
|
||||||
|
.name = TYPE_VIRTIO_IOMMU,
|
||||||
|
.parent = TYPE_VIRTIO_DEVICE,
|
||||||
|
.instance_size = sizeof(VirtIOIOMMU),
|
||||||
|
.instance_init = virtio_iommu_instance_init,
|
||||||
|
.class_init = virtio_iommu_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void virtio_register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&virtio_iommu_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(virtio_register_types)
|
57
include/hw/virtio/virtio-iommu.h
Normal file
57
include/hw/virtio/virtio-iommu.h
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* virtio-iommu device
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2 or later, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef QEMU_VIRTIO_IOMMU_H
|
||||||
|
#define QEMU_VIRTIO_IOMMU_H
|
||||||
|
|
||||||
|
#include "standard-headers/linux/virtio_iommu.h"
|
||||||
|
#include "hw/virtio/virtio.h"
|
||||||
|
#include "hw/pci/pci.h"
|
||||||
|
|
||||||
|
#define TYPE_VIRTIO_IOMMU "virtio-iommu-device"
|
||||||
|
#define VIRTIO_IOMMU(obj) \
|
||||||
|
OBJECT_CHECK(VirtIOIOMMU, (obj), TYPE_VIRTIO_IOMMU)
|
||||||
|
|
||||||
|
typedef struct IOMMUDevice {
|
||||||
|
void *viommu;
|
||||||
|
PCIBus *bus;
|
||||||
|
int devfn;
|
||||||
|
IOMMUMemoryRegion iommu_mr;
|
||||||
|
AddressSpace as;
|
||||||
|
} IOMMUDevice;
|
||||||
|
|
||||||
|
typedef struct IOMMUPciBus {
|
||||||
|
PCIBus *bus;
|
||||||
|
IOMMUDevice *pbdev[0]; /* Parent array is sparse, so dynamically alloc */
|
||||||
|
} IOMMUPciBus;
|
||||||
|
|
||||||
|
typedef struct VirtIOIOMMU {
|
||||||
|
VirtIODevice parent_obj;
|
||||||
|
VirtQueue *req_vq;
|
||||||
|
VirtQueue *event_vq;
|
||||||
|
struct virtio_iommu_config config;
|
||||||
|
uint64_t features;
|
||||||
|
GHashTable *as_by_busptr;
|
||||||
|
PCIBus *primary_bus;
|
||||||
|
GTree *domains;
|
||||||
|
QemuMutex mutex;
|
||||||
|
GTree *endpoints;
|
||||||
|
} VirtIOIOMMU;
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue