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
|
||||
depends on VIRTIO
|
||||
|
||||
config VIRTIO_IOMMU
|
||||
bool
|
||||
default y
|
||||
depends on VIRTIO
|
||||
|
||||
config VIRTIO_PCI
|
||||
bool
|
||||
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
|
||||
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-$(CONFIG_VIRTIO_IOMMU) += virtio-iommu.o
|
||||
obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock.o
|
||||
|
||||
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_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"
|
||||
|
||||
# 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 New Issue
Block a user