mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-03 15:53:54 -06:00
vfio queue:
* Support for non 64b IOVA space * Introduction of a PCIIOMMUOps callback structure to ease future extensions * Fix for a buffer overrun when writing the VF token * PPC cleanups preparing ground for IOMMUFD support -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmVI+bIACgkQUaNDx8/7 7KHW4g/9FmgX0k2Elm1BAul3slJtuBT8/iHKfK19rhXICxhxS5xBWJA8FmosTWAT 91YqQJhOHARxLd9VROfv8Fq8sAo+Ys8bP3PTXh5satjY5gR9YtmMSVqvsAVLn7lv a/0xp7wPJt2UeKzvRNUqFXNr7yHPwxFxbJbmmAJbNte8p+TfE2qvojbJnu7BjJbg sTtS/vFWNJwtuNYTkMRoiZaUKEoEZ8LnslOqKUjgeO59g4i3Dq8e2JCmHANPFWUK cWmr7AqcXgXEnLSDWTtfN53bjcSCYkFVb4WV4Wv1/7hUF5jQ4UR0l3B64xWe0M3/ Prak3bWOM/o7JwLBsgaWPngXA9V0WFBTXVF4x5qTwhuR1sSV8MxUvTKxI+qqiEzA FjU89oSZ+zXId/hEUuTL6vn1Th8/6mwD0L9ORchNOQUKzCjBzI4MVPB09nM3AdPC LGThlufsZktdoU2KjMHpc+gMIXQYsxkgvm07K5iZTZ5eJ4tV5KB0aPvTZppGUxe1 YY9og9F3hxjDHQtEuSY2rzBQI7nrUpd1ZI5ut/3ZgDWkqD6aGRtMme4n4GsGsYb2 Ht9+d2RL9S8uPUh+7rV8K/N3+vXgXRaEYTuAScKtflEbA7YnZA5nUdMng8x0kMTQ Y73XCd4UGWDfSSZsgaIHGkM/MRIHgmlrfcwPkWqWW9vF+92O6Hw= =/Du0 -----END PGP SIGNATURE----- Merge tag 'pull-vfio-20231106' of https://github.com/legoater/qemu into staging vfio queue: * Support for non 64b IOVA space * Introduction of a PCIIOMMUOps callback structure to ease future extensions * Fix for a buffer overrun when writing the VF token * PPC cleanups preparing ground for IOMMUFD support # -----BEGIN PGP SIGNATURE----- # # iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmVI+bIACgkQUaNDx8/7 # 7KHW4g/9FmgX0k2Elm1BAul3slJtuBT8/iHKfK19rhXICxhxS5xBWJA8FmosTWAT # 91YqQJhOHARxLd9VROfv8Fq8sAo+Ys8bP3PTXh5satjY5gR9YtmMSVqvsAVLn7lv # a/0xp7wPJt2UeKzvRNUqFXNr7yHPwxFxbJbmmAJbNte8p+TfE2qvojbJnu7BjJbg # sTtS/vFWNJwtuNYTkMRoiZaUKEoEZ8LnslOqKUjgeO59g4i3Dq8e2JCmHANPFWUK # cWmr7AqcXgXEnLSDWTtfN53bjcSCYkFVb4WV4Wv1/7hUF5jQ4UR0l3B64xWe0M3/ # Prak3bWOM/o7JwLBsgaWPngXA9V0WFBTXVF4x5qTwhuR1sSV8MxUvTKxI+qqiEzA # FjU89oSZ+zXId/hEUuTL6vn1Th8/6mwD0L9ORchNOQUKzCjBzI4MVPB09nM3AdPC # LGThlufsZktdoU2KjMHpc+gMIXQYsxkgvm07K5iZTZ5eJ4tV5KB0aPvTZppGUxe1 # YY9og9F3hxjDHQtEuSY2rzBQI7nrUpd1ZI5ut/3ZgDWkqD6aGRtMme4n4GsGsYb2 # Ht9+d2RL9S8uPUh+7rV8K/N3+vXgXRaEYTuAScKtflEbA7YnZA5nUdMng8x0kMTQ # Y73XCd4UGWDfSSZsgaIHGkM/MRIHgmlrfcwPkWqWW9vF+92O6Hw= # =/Du0 # -----END PGP SIGNATURE----- # gpg: Signature made Mon 06 Nov 2023 22:35:30 HKT # gpg: using RSA key A0F66548F04895EBFE6B0B6051A343C7CFFBECA1 # gpg: Good signature from "Cédric Le Goater <clg@redhat.com>" [unknown] # gpg: aka "Cédric Le Goater <clg@kaod.org>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: A0F6 6548 F048 95EB FE6B 0B60 51A3 43C7 CFFB ECA1 * tag 'pull-vfio-20231106' of https://github.com/legoater/qemu: (22 commits) vfio/common: Move vfio_host_win_add/del into spapr.c vfio/spapr: Make vfio_spapr_create/remove_window static vfio/container: Move spapr specific init/deinit into spapr.c vfio/container: Move vfio_container_add/del_section_window into spapr.c vfio/container: Move IBM EEH related functions into spapr_pci_vfio.c util/uuid: Define UUID_STR_LEN from UUID_NONE string util/uuid: Remove UUID_FMT_LEN vfio/pci: Fix buffer overrun when writing the VF token util/uuid: Add UUID_STR_LEN definition hw/pci: modify pci_setup_iommu() to set PCIIOMMUOps test: Add some tests for range and resv-mem helpers virtio-iommu: Consolidate host reserved regions and property set ones virtio-iommu: Implement set_iova_ranges() callback virtio-iommu: Record whether a probe request has been issued range: Introduce range_inverse_array() virtio-iommu: Introduce per IOMMUDevice reserved regions util/reserved-region: Add new ReservedRegion helpers range: Make range_compare() public virtio-iommu: Rename reserved_regions into prop_resv_regions vfio: Collect container iova range info ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
bb59f3548f
52 changed files with 1304 additions and 453 deletions
|
@ -135,6 +135,7 @@ virtio_iommu_notify_flag_add(const char *name) "add notifier to mr %s"
|
|||
virtio_iommu_notify_flag_del(const char *name) "del notifier from mr %s"
|
||||
virtio_iommu_switch_address_space(uint8_t bus, uint8_t slot, uint8_t fn, bool on) "Device %02x:%02x.%x switching address space (iommu enabled=%d)"
|
||||
virtio_iommu_freeze_granule(uint64_t page_size_mask) "granule set to 0x%"PRIx64
|
||||
virtio_iommu_host_resv_regions(const char *name, uint32_t index, uint64_t lob, uint64_t upb) "mr=%s host-resv-reg[%d] = [0x%"PRIx64",0x%"PRIx64"]"
|
||||
|
||||
# virtio-mem.c
|
||||
virtio_mem_send_response(uint16_t type) "type=%" PRIu16
|
||||
|
|
|
@ -37,7 +37,7 @@ struct VirtIOIOMMUPCI {
|
|||
static Property virtio_iommu_pci_properties[] = {
|
||||
DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
|
||||
DEFINE_PROP_ARRAY("reserved-regions", VirtIOIOMMUPCI,
|
||||
vdev.nb_reserved_regions, vdev.reserved_regions,
|
||||
vdev.nr_prop_resv_regions, vdev.prop_resv_regions,
|
||||
qdev_prop_reserved_region, ReservedRegion),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
@ -54,9 +54,9 @@ static void virtio_iommu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
|||
"for the virtio-iommu-pci device");
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < s->nb_reserved_regions; i++) {
|
||||
if (s->reserved_regions[i].type != VIRTIO_IOMMU_RESV_MEM_T_RESERVED &&
|
||||
s->reserved_regions[i].type != VIRTIO_IOMMU_RESV_MEM_T_MSI) {
|
||||
for (int i = 0; i < s->nr_prop_resv_regions; i++) {
|
||||
if (s->prop_resv_regions[i].type != VIRTIO_IOMMU_RESV_MEM_T_RESERVED &&
|
||||
s->prop_resv_regions[i].type != VIRTIO_IOMMU_RESV_MEM_T_MSI) {
|
||||
error_setg(errp, "reserved region %d has an invalid type", i);
|
||||
error_append_hint(errp, "Valid values are 0 and 1\n");
|
||||
return;
|
||||
|
|
|
@ -20,12 +20,15 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/iov.h"
|
||||
#include "qemu/range.h"
|
||||
#include "qemu/reserved-region.h"
|
||||
#include "exec/target_page.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/virtio/virtio.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "sysemu/reset.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qemu/reserved-region.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "trace.h"
|
||||
|
@ -378,6 +381,19 @@ static void virtio_iommu_put_domain(gpointer data)
|
|||
g_free(domain);
|
||||
}
|
||||
|
||||
static void add_prop_resv_regions(IOMMUDevice *sdev)
|
||||
{
|
||||
VirtIOIOMMU *s = sdev->viommu;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < s->nr_prop_resv_regions; i++) {
|
||||
ReservedRegion *reg = g_new0(ReservedRegion, 1);
|
||||
|
||||
*reg = s->prop_resv_regions[i];
|
||||
sdev->resv_regions = resv_region_list_insert(sdev->resv_regions, reg);
|
||||
}
|
||||
}
|
||||
|
||||
static AddressSpace *virtio_iommu_find_add_as(PCIBus *bus, void *opaque,
|
||||
int devfn)
|
||||
{
|
||||
|
@ -408,6 +424,7 @@ static AddressSpace *virtio_iommu_find_add_as(PCIBus *bus, void *opaque,
|
|||
|
||||
memory_region_init(&sdev->root, OBJECT(s), name, UINT64_MAX);
|
||||
address_space_init(&sdev->as, &sdev->root, TYPE_VIRTIO_IOMMU);
|
||||
add_prop_resv_regions(sdev);
|
||||
|
||||
/*
|
||||
* Build the IOMMU disabled container with aliases to the
|
||||
|
@ -444,6 +461,10 @@ static AddressSpace *virtio_iommu_find_add_as(PCIBus *bus, void *opaque,
|
|||
return &sdev->as;
|
||||
}
|
||||
|
||||
static const PCIIOMMUOps virtio_iommu_ops = {
|
||||
.get_address_space = virtio_iommu_find_add_as,
|
||||
};
|
||||
|
||||
static int virtio_iommu_attach(VirtIOIOMMU *s,
|
||||
struct virtio_iommu_req_attach *req)
|
||||
{
|
||||
|
@ -624,29 +645,30 @@ static int virtio_iommu_unmap(VirtIOIOMMU *s,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t virtio_iommu_fill_resv_mem_prop(VirtIOIOMMU *s, uint32_t ep,
|
||||
static ssize_t virtio_iommu_fill_resv_mem_prop(IOMMUDevice *sdev, uint32_t ep,
|
||||
uint8_t *buf, size_t free)
|
||||
{
|
||||
struct virtio_iommu_probe_resv_mem prop = {};
|
||||
size_t size = sizeof(prop), length = size - sizeof(prop.head), total;
|
||||
int i;
|
||||
|
||||
total = size * s->nb_reserved_regions;
|
||||
GList *l;
|
||||
|
||||
total = size * g_list_length(sdev->resv_regions);
|
||||
if (total > free) {
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
for (i = 0; i < s->nb_reserved_regions; i++) {
|
||||
unsigned subtype = s->reserved_regions[i].type;
|
||||
for (l = sdev->resv_regions; l; l = l->next) {
|
||||
ReservedRegion *reg = l->data;
|
||||
unsigned subtype = reg->type;
|
||||
Range *range = ®->range;
|
||||
|
||||
assert(subtype == VIRTIO_IOMMU_RESV_MEM_T_RESERVED ||
|
||||
subtype == VIRTIO_IOMMU_RESV_MEM_T_MSI);
|
||||
prop.head.type = cpu_to_le16(VIRTIO_IOMMU_PROBE_T_RESV_MEM);
|
||||
prop.head.length = cpu_to_le16(length);
|
||||
prop.subtype = subtype;
|
||||
prop.start = cpu_to_le64(s->reserved_regions[i].low);
|
||||
prop.end = cpu_to_le64(s->reserved_regions[i].high);
|
||||
prop.start = cpu_to_le64(range_lob(range));
|
||||
prop.end = cpu_to_le64(range_upb(range));
|
||||
|
||||
memcpy(buf, &prop, size);
|
||||
|
||||
|
@ -666,19 +688,27 @@ static int virtio_iommu_probe(VirtIOIOMMU *s,
|
|||
uint8_t *buf)
|
||||
{
|
||||
uint32_t ep_id = le32_to_cpu(req->endpoint);
|
||||
IOMMUMemoryRegion *iommu_mr = virtio_iommu_mr(s, ep_id);
|
||||
size_t free = VIOMMU_PROBE_SIZE;
|
||||
IOMMUDevice *sdev;
|
||||
ssize_t count;
|
||||
|
||||
if (!virtio_iommu_mr(s, ep_id)) {
|
||||
if (!iommu_mr) {
|
||||
return VIRTIO_IOMMU_S_NOENT;
|
||||
}
|
||||
|
||||
count = virtio_iommu_fill_resv_mem_prop(s, ep_id, buf, free);
|
||||
sdev = container_of(iommu_mr, IOMMUDevice, iommu_mr);
|
||||
if (!sdev) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
count = virtio_iommu_fill_resv_mem_prop(sdev, ep_id, buf, free);
|
||||
if (count < 0) {
|
||||
return VIRTIO_IOMMU_S_INVAL;
|
||||
}
|
||||
buf += count;
|
||||
free -= count;
|
||||
sdev->probe_done = true;
|
||||
|
||||
return VIRTIO_IOMMU_S_OK;
|
||||
}
|
||||
|
@ -856,7 +886,7 @@ static IOMMUTLBEntry virtio_iommu_translate(IOMMUMemoryRegion *mr, hwaddr addr,
|
|||
bool bypass_allowed;
|
||||
int granule;
|
||||
bool found;
|
||||
int i;
|
||||
GList *l;
|
||||
|
||||
interval.low = addr;
|
||||
interval.high = addr + 1;
|
||||
|
@ -894,10 +924,10 @@ static IOMMUTLBEntry virtio_iommu_translate(IOMMUMemoryRegion *mr, hwaddr addr,
|
|||
goto unlock;
|
||||
}
|
||||
|
||||
for (i = 0; i < s->nb_reserved_regions; i++) {
|
||||
ReservedRegion *reg = &s->reserved_regions[i];
|
||||
for (l = sdev->resv_regions; l; l = l->next) {
|
||||
ReservedRegion *reg = l->data;
|
||||
|
||||
if (addr >= reg->low && addr <= reg->high) {
|
||||
if (range_contains(®->range, addr)) {
|
||||
switch (reg->type) {
|
||||
case VIRTIO_IOMMU_RESV_MEM_T_MSI:
|
||||
entry.perm = flag;
|
||||
|
@ -1131,6 +1161,106 @@ static int virtio_iommu_set_page_size_mask(IOMMUMemoryRegion *mr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* rebuild_resv_regions: rebuild resv regions with both the
|
||||
* info of host resv ranges and property set resv ranges
|
||||
*/
|
||||
static int rebuild_resv_regions(IOMMUDevice *sdev)
|
||||
{
|
||||
GList *l;
|
||||
int i = 0;
|
||||
|
||||
/* free the existing list and rebuild it from scratch */
|
||||
g_list_free_full(sdev->resv_regions, g_free);
|
||||
sdev->resv_regions = NULL;
|
||||
|
||||
/* First add host reserved regions if any, all tagged as RESERVED */
|
||||
for (l = sdev->host_resv_ranges; l; l = l->next) {
|
||||
ReservedRegion *reg = g_new0(ReservedRegion, 1);
|
||||
Range *r = (Range *)l->data;
|
||||
|
||||
reg->type = VIRTIO_IOMMU_RESV_MEM_T_RESERVED;
|
||||
range_set_bounds(®->range, range_lob(r), range_upb(r));
|
||||
sdev->resv_regions = resv_region_list_insert(sdev->resv_regions, reg);
|
||||
trace_virtio_iommu_host_resv_regions(sdev->iommu_mr.parent_obj.name, i,
|
||||
range_lob(®->range),
|
||||
range_upb(®->range));
|
||||
i++;
|
||||
}
|
||||
/*
|
||||
* then add higher priority reserved regions set by the machine
|
||||
* through properties
|
||||
*/
|
||||
add_prop_resv_regions(sdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* virtio_iommu_set_iova_ranges: Conveys the usable IOVA ranges
|
||||
*
|
||||
* The function turns those into reserved ranges. Once some
|
||||
* reserved ranges have been set, new reserved regions cannot be
|
||||
* added outside of the original ones.
|
||||
*
|
||||
* @mr: IOMMU MR
|
||||
* @iova_ranges: list of usable IOVA ranges
|
||||
* @errp: error handle
|
||||
*/
|
||||
static int virtio_iommu_set_iova_ranges(IOMMUMemoryRegion *mr,
|
||||
GList *iova_ranges,
|
||||
Error **errp)
|
||||
{
|
||||
IOMMUDevice *sdev = container_of(mr, IOMMUDevice, iommu_mr);
|
||||
GList *current_ranges = sdev->host_resv_ranges;
|
||||
GList *l, *tmp, *new_ranges = NULL;
|
||||
int ret = -EINVAL;
|
||||
|
||||
/* check that each new resv region is included in an existing one */
|
||||
if (sdev->host_resv_ranges) {
|
||||
range_inverse_array(iova_ranges,
|
||||
&new_ranges,
|
||||
0, UINT64_MAX);
|
||||
|
||||
for (tmp = new_ranges; tmp; tmp = tmp->next) {
|
||||
Range *newr = (Range *)tmp->data;
|
||||
bool included = false;
|
||||
|
||||
for (l = current_ranges; l; l = l->next) {
|
||||
Range * r = (Range *)l->data;
|
||||
|
||||
if (range_contains_range(r, newr)) {
|
||||
included = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!included) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
/* all new reserved ranges are included in existing ones */
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (sdev->probe_done) {
|
||||
warn_report("%s: Notified about new host reserved regions after probe",
|
||||
mr->parent_obj.name);
|
||||
}
|
||||
|
||||
range_inverse_array(iova_ranges,
|
||||
&sdev->host_resv_ranges,
|
||||
0, UINT64_MAX);
|
||||
rebuild_resv_regions(sdev);
|
||||
|
||||
return 0;
|
||||
error:
|
||||
error_setg(errp, "IOMMU mr=%s Conflicting host reserved ranges set!",
|
||||
mr->parent_obj.name);
|
||||
out:
|
||||
g_list_free_full(new_ranges, g_free);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void virtio_iommu_system_reset(void *opaque)
|
||||
{
|
||||
VirtIOIOMMU *s = opaque;
|
||||
|
@ -1206,7 +1336,7 @@ static void virtio_iommu_device_realize(DeviceState *dev, Error **errp)
|
|||
s->as_by_busptr = g_hash_table_new_full(NULL, NULL, NULL, g_free);
|
||||
|
||||
if (s->primary_bus) {
|
||||
pci_setup_iommu(s->primary_bus, virtio_iommu_find_add_as, s);
|
||||
pci_setup_iommu(s->primary_bus, &virtio_iommu_ops, s);
|
||||
} else {
|
||||
error_setg(errp, "VIRTIO-IOMMU is not attached to any PCI bus!");
|
||||
}
|
||||
|
@ -1426,6 +1556,7 @@ static void virtio_iommu_memory_region_class_init(ObjectClass *klass,
|
|||
imrc->replay = virtio_iommu_replay;
|
||||
imrc->notify_flag_changed = virtio_iommu_notify_flag_changed;
|
||||
imrc->iommu_set_page_size_mask = virtio_iommu_set_page_size_mask;
|
||||
imrc->iommu_set_iova_ranges = virtio_iommu_set_iova_ranges;
|
||||
}
|
||||
|
||||
static const TypeInfo virtio_iommu_info = {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue