virtio,pci,pc: fixes for 10.2
small fixes all over the place. UDP tunnel and TSEG tweaks are kind of borderline, but I feel not making the change now will just add to compatibility headaches down the road. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> -----BEGIN PGP SIGNATURE----- iQFDBAABCgAtFiEEXQn9CHHI+FuUyooNKB8NuNKNVGkFAmkQplIPHG1zdEByZWRo YXQuY29tAAoJECgfDbjSjVRpFDsIAMlScYTW0fugUaP4B/a8xjgRFwBSk2CoU7aE l0k5ihyadecpnMLswkvoLfH9jl5Mu3MOZ6bpfcIHOWXMusGyiYcds6wupb8qcATP Ud4ZjybuNrpoGUul1ECkNTE3xvUtSBOVu8z9ac4ojP+w0LVDiuWyg1bl5QiRuzEg K87OjbdTIgCKKJi5QRw/dMJfoOofay98g0kbcuhkBiudvu3FtOpJW0g/aiY1m2sY MXYeBZjGbYGkAOXLKRcSr3nYtZbY4sg/onJ3Xb0HPbUZfRMTm7KKApwhH9jsHmlO VgaRGcF+dNDC7XIsaZt6k/YTsWCApYvuCcEQbjR1rW1d4ZmZU/Y= =ocWR -----END PGP SIGNATURE----- Merge tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu into staging virtio,pci,pc: fixes for 10.2 small fixes all over the place. UDP tunnel and TSEG tweaks are kind of borderline, but I feel not making the change now will just add to compatibility headaches down the road. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # -----BEGIN PGP SIGNATURE----- # # iQFDBAABCgAtFiEEXQn9CHHI+FuUyooNKB8NuNKNVGkFAmkQplIPHG1zdEByZWRo # YXQuY29tAAoJECgfDbjSjVRpFDsIAMlScYTW0fugUaP4B/a8xjgRFwBSk2CoU7aE # l0k5ihyadecpnMLswkvoLfH9jl5Mu3MOZ6bpfcIHOWXMusGyiYcds6wupb8qcATP # Ud4ZjybuNrpoGUul1ECkNTE3xvUtSBOVu8z9ac4ojP+w0LVDiuWyg1bl5QiRuzEg # K87OjbdTIgCKKJi5QRw/dMJfoOofay98g0kbcuhkBiudvu3FtOpJW0g/aiY1m2sY # MXYeBZjGbYGkAOXLKRcSr3nYtZbY4sg/onJ3Xb0HPbUZfRMTm7KKApwhH9jsHmlO # VgaRGcF+dNDC7XIsaZt6k/YTsWCApYvuCcEQbjR1rW1d4ZmZU/Y= # =ocWR # -----END PGP SIGNATURE----- # gpg: Signature made Sun 09 Nov 2025 03:33:54 PM CET # gpg: using RSA key 5D09FD0871C8F85B94CA8A0D281F0DB8D28D5469 # gpg: issuer "mst@redhat.com" # gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" [unknown] # gpg: aka "Michael S. Tsirkin <mst@redhat.com>" [unknown] # gpg: WARNING: The key's User ID is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 0270 606B 6F3C DF3D 0B17 0970 C350 3912 AFBE 8E67 # Subkey fingerprint: 5D09 FD08 71C8 F85B 94CA 8A0D 281F 0DB8 D28D 5469 * tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu: vhost-user.rst: clarify when FDs can be sent q35: increase default tseg size virtio-net: Advertise UDP tunnel GSO support by default tests/qtest/bios-tables-test: Update DSDT blobs after GPEX _DSM change hw/pci-host/gpex-acpi: Fix _DSM function 0 support return value tests/qtest/bios-tables-test: Prepare for _DSM change in the DSDT table vhost-user: make vhost_set_vring_file() synchronous intel_iommu: Fix DMA failure when guest switches IOMMU domain intel_iommu: Reset pasid cache when system level reset intel_iommu: Handle PASID cache invalidation vhost-user: fix shared object lookup handler logic amd_iommu: Support 64-bit address for IOTLB lookup amd_iommu: Fix handling of devices on buses != 0 MAINTAINERS: Update entry for AMD-Vi Emulation Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
593aee5df9
30 changed files with 371 additions and 119 deletions
|
|
@ -3933,8 +3933,10 @@ F: tests/functional/x86_64/test_intel_iommu.py
|
|||
F: tests/qtest/intel-iommu-test.c
|
||||
|
||||
AMD-Vi Emulation
|
||||
S: Orphan
|
||||
F: hw/i386/amd_iommu.?
|
||||
M: Alejandro Jimenez <alejandro.j.jimenez@oracle.com>
|
||||
R: Sairaj Kodilkar <sarunkod@amd.com>
|
||||
S: Supported
|
||||
F: hw/i386/amd_iommu*
|
||||
|
||||
OpenSBI Firmware
|
||||
L: qemu-riscv@nongnu.org
|
||||
|
|
|
|||
|
|
@ -411,6 +411,13 @@ in the ancillary data:
|
|||
* ``VHOST_USER_SET_INFLIGHT_FD`` (if ``VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD``)
|
||||
* ``VHOST_USER_SET_DEVICE_STATE_FD``
|
||||
|
||||
When sending file descriptors in ancilliary data, *front-end* should
|
||||
associate the ancilliary data with a ``sendmsg`` operation (or
|
||||
equivalent) that sends bytes starting with the first byte of the
|
||||
message header. *back-end* can therefore expect that file descriptors
|
||||
will only be received in the first ``recvmsg`` operation for a message
|
||||
header.
|
||||
|
||||
If *front-end* is unable to send the full message or receives a wrong
|
||||
reply it will close the connection. An optional reconnection mechanism
|
||||
can be implemented.
|
||||
|
|
|
|||
|
|
@ -40,6 +40,10 @@
|
|||
|
||||
GlobalProperty hw_compat_10_1[] = {
|
||||
{ TYPE_ACPI_GED, "x-has-hest-addr", "false" },
|
||||
{ TYPE_VIRTIO_NET, "host_tunnel", "off" },
|
||||
{ TYPE_VIRTIO_NET, "host_tunnel_csum", "off" },
|
||||
{ TYPE_VIRTIO_NET, "guest_tunnel", "off" },
|
||||
{ TYPE_VIRTIO_NET, "guest_tunnel_csum", "off" },
|
||||
};
|
||||
const size_t hw_compat_10_1_len = G_N_ELEMENTS(hw_compat_10_1);
|
||||
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ const char *amdvi_mmio_high[] = {
|
|||
};
|
||||
|
||||
struct AMDVIAddressSpace {
|
||||
uint8_t bus_num; /* bus number */
|
||||
PCIBus *bus; /* PCIBus (for bus number) */
|
||||
uint8_t devfn; /* device function */
|
||||
AMDVIState *iommu_state; /* AMDVI - one per machine */
|
||||
MemoryRegion root; /* AMDVI Root memory map region */
|
||||
|
|
@ -101,6 +101,16 @@ typedef enum AMDVIFaultReason {
|
|||
AMDVI_FR_PT_ENTRY_INV, /* Failure to read PTE from guest memory */
|
||||
} AMDVIFaultReason;
|
||||
|
||||
typedef struct AMDVIAsKey {
|
||||
PCIBus *bus;
|
||||
uint8_t devfn;
|
||||
} AMDVIAsKey;
|
||||
|
||||
typedef struct AMDVIIOTLBKey {
|
||||
uint64_t gfn;
|
||||
uint16_t devid;
|
||||
} AMDVIIOTLBKey;
|
||||
|
||||
uint64_t amdvi_extended_feature_register(AMDVIState *s)
|
||||
{
|
||||
uint64_t feature = AMDVI_DEFAULT_EXT_FEATURES;
|
||||
|
|
@ -372,21 +382,68 @@ static void amdvi_log_pagetab_error(AMDVIState *s, uint16_t devid,
|
|||
PCI_STATUS_SIG_TARGET_ABORT);
|
||||
}
|
||||
|
||||
static gboolean amdvi_uint64_equal(gconstpointer v1, gconstpointer v2)
|
||||
static gboolean amdvi_as_equal(gconstpointer v1, gconstpointer v2)
|
||||
{
|
||||
return *((const uint64_t *)v1) == *((const uint64_t *)v2);
|
||||
const AMDVIAsKey *key1 = v1;
|
||||
const AMDVIAsKey *key2 = v2;
|
||||
|
||||
return key1->bus == key2->bus && key1->devfn == key2->devfn;
|
||||
}
|
||||
|
||||
static guint amdvi_uint64_hash(gconstpointer v)
|
||||
static guint amdvi_as_hash(gconstpointer v)
|
||||
{
|
||||
return (guint)*(const uint64_t *)v;
|
||||
const AMDVIAsKey *key = v;
|
||||
guint bus = (guint)(uintptr_t)key->bus;
|
||||
|
||||
return (guint)(bus << 8 | (guint)key->devfn);
|
||||
}
|
||||
|
||||
static AMDVIAddressSpace *amdvi_as_lookup(AMDVIState *s, PCIBus *bus,
|
||||
uint8_t devfn)
|
||||
{
|
||||
const AMDVIAsKey key = { .bus = bus, .devfn = devfn };
|
||||
return g_hash_table_lookup(s->address_spaces, &key);
|
||||
}
|
||||
|
||||
static gboolean amdvi_find_as_by_devid(gpointer key, gpointer value,
|
||||
gpointer user_data)
|
||||
{
|
||||
const AMDVIAsKey *as = key;
|
||||
const uint16_t *devidp = user_data;
|
||||
|
||||
return *devidp == PCI_BUILD_BDF(pci_bus_num(as->bus), as->devfn);
|
||||
}
|
||||
|
||||
static AMDVIAddressSpace *amdvi_get_as_by_devid(AMDVIState *s, uint16_t devid)
|
||||
{
|
||||
return g_hash_table_find(s->address_spaces,
|
||||
amdvi_find_as_by_devid, &devid);
|
||||
}
|
||||
|
||||
static gboolean amdvi_iotlb_equal(gconstpointer v1, gconstpointer v2)
|
||||
{
|
||||
const AMDVIIOTLBKey *key1 = v1;
|
||||
const AMDVIIOTLBKey *key2 = v2;
|
||||
|
||||
return key1->devid == key2->devid && key1->gfn == key2->gfn;
|
||||
}
|
||||
|
||||
static guint amdvi_iotlb_hash(gconstpointer v)
|
||||
{
|
||||
const AMDVIIOTLBKey *key = v;
|
||||
/* Use GPA and DEVID to find the bucket */
|
||||
return (guint)(key->gfn << AMDVI_PAGE_SHIFT_4K |
|
||||
(key->devid & ~AMDVI_PAGE_MASK_4K));
|
||||
}
|
||||
|
||||
|
||||
static AMDVIIOTLBEntry *amdvi_iotlb_lookup(AMDVIState *s, hwaddr addr,
|
||||
uint64_t devid)
|
||||
{
|
||||
uint64_t key = (addr >> AMDVI_PAGE_SHIFT_4K) |
|
||||
((uint64_t)(devid) << AMDVI_DEVID_SHIFT);
|
||||
AMDVIIOTLBKey key = {
|
||||
.gfn = AMDVI_GET_IOTLB_GFN(addr),
|
||||
.devid = devid,
|
||||
};
|
||||
return g_hash_table_lookup(s->iotlb, &key);
|
||||
}
|
||||
|
||||
|
|
@ -408,8 +465,10 @@ static gboolean amdvi_iotlb_remove_by_devid(gpointer key, gpointer value,
|
|||
static void amdvi_iotlb_remove_page(AMDVIState *s, hwaddr addr,
|
||||
uint64_t devid)
|
||||
{
|
||||
uint64_t key = (addr >> AMDVI_PAGE_SHIFT_4K) |
|
||||
((uint64_t)(devid) << AMDVI_DEVID_SHIFT);
|
||||
AMDVIIOTLBKey key = {
|
||||
.gfn = AMDVI_GET_IOTLB_GFN(addr),
|
||||
.devid = devid,
|
||||
};
|
||||
g_hash_table_remove(s->iotlb, &key);
|
||||
}
|
||||
|
||||
|
|
@ -420,8 +479,10 @@ static void amdvi_update_iotlb(AMDVIState *s, uint16_t devid,
|
|||
/* don't cache erroneous translations */
|
||||
if (to_cache.perm != IOMMU_NONE) {
|
||||
AMDVIIOTLBEntry *entry = g_new(AMDVIIOTLBEntry, 1);
|
||||
uint64_t *key = g_new(uint64_t, 1);
|
||||
uint64_t gfn = gpa >> AMDVI_PAGE_SHIFT_4K;
|
||||
AMDVIIOTLBKey *key = g_new(AMDVIIOTLBKey, 1);
|
||||
|
||||
key->gfn = AMDVI_GET_IOTLB_GFN(gpa);
|
||||
key->devid = devid;
|
||||
|
||||
trace_amdvi_cache_update(domid, PCI_BUS_NUM(devid), PCI_SLOT(devid),
|
||||
PCI_FUNC(devid), gpa, to_cache.translated_addr);
|
||||
|
|
@ -434,7 +495,8 @@ static void amdvi_update_iotlb(AMDVIState *s, uint16_t devid,
|
|||
entry->perms = to_cache.perm;
|
||||
entry->translated_addr = to_cache.translated_addr;
|
||||
entry->page_mask = to_cache.addr_mask;
|
||||
*key = gfn | ((uint64_t)(devid) << AMDVI_DEVID_SHIFT);
|
||||
entry->devid = devid;
|
||||
|
||||
g_hash_table_replace(s->iotlb, key, entry);
|
||||
}
|
||||
}
|
||||
|
|
@ -551,7 +613,7 @@ static inline uint64_t amdvi_get_pte_entry(AMDVIState *s, uint64_t pte_addr,
|
|||
|
||||
static int amdvi_as_to_dte(AMDVIAddressSpace *as, uint64_t *dte)
|
||||
{
|
||||
uint16_t devid = PCI_BUILD_BDF(as->bus_num, as->devfn);
|
||||
uint16_t devid = PCI_BUILD_BDF(pci_bus_num(as->bus), as->devfn);
|
||||
AMDVIState *s = as->iommu_state;
|
||||
|
||||
if (!amdvi_get_dte(s, devid, dte)) {
|
||||
|
|
@ -1011,25 +1073,15 @@ static void amdvi_switch_address_space(AMDVIAddressSpace *amdvi_as)
|
|||
*/
|
||||
static void amdvi_reset_address_translation_all(AMDVIState *s)
|
||||
{
|
||||
AMDVIAddressSpace **iommu_as;
|
||||
AMDVIAddressSpace *iommu_as;
|
||||
GHashTableIter as_it;
|
||||
|
||||
for (int bus_num = 0; bus_num < PCI_BUS_MAX; bus_num++) {
|
||||
g_hash_table_iter_init(&as_it, s->address_spaces);
|
||||
|
||||
/* Nothing to do if there are no devices on the current bus */
|
||||
if (!s->address_spaces[bus_num]) {
|
||||
continue;
|
||||
}
|
||||
iommu_as = s->address_spaces[bus_num];
|
||||
|
||||
for (int devfn = 0; devfn < PCI_DEVFN_MAX; devfn++) {
|
||||
|
||||
if (!iommu_as[devfn]) {
|
||||
continue;
|
||||
}
|
||||
/* Use passthrough as default mode after reset */
|
||||
iommu_as[devfn]->addr_translation = false;
|
||||
amdvi_switch_address_space(iommu_as[devfn]);
|
||||
}
|
||||
while (g_hash_table_iter_next(&as_it, NULL, (void **)&iommu_as)) {
|
||||
/* Use passthrough as default mode after reset */
|
||||
iommu_as->addr_translation = false;
|
||||
amdvi_switch_address_space(iommu_as);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1089,27 +1141,15 @@ static void enable_nodma_mode(AMDVIAddressSpace *as)
|
|||
*/
|
||||
static void amdvi_update_addr_translation_mode(AMDVIState *s, uint16_t devid)
|
||||
{
|
||||
uint8_t bus_num, devfn, dte_mode;
|
||||
uint8_t dte_mode;
|
||||
AMDVIAddressSpace *as;
|
||||
uint64_t dte[4] = { 0 };
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Convert the devid encoded in the command to a bus and devfn in
|
||||
* order to retrieve the corresponding address space.
|
||||
*/
|
||||
bus_num = PCI_BUS_NUM(devid);
|
||||
devfn = devid & 0xff;
|
||||
|
||||
/*
|
||||
* The main buffer of size (AMDVIAddressSpace *) * (PCI_BUS_MAX) has already
|
||||
* been allocated within AMDVIState, but must be careful to not access
|
||||
* unallocated devfn.
|
||||
*/
|
||||
if (!s->address_spaces[bus_num] || !s->address_spaces[bus_num][devfn]) {
|
||||
as = amdvi_get_as_by_devid(s, devid);
|
||||
if (!as) {
|
||||
return;
|
||||
}
|
||||
as = s->address_spaces[bus_num][devfn];
|
||||
|
||||
ret = amdvi_as_to_dte(as, dte);
|
||||
|
||||
|
|
@ -1783,7 +1823,7 @@ static void amdvi_do_translate(AMDVIAddressSpace *as, hwaddr addr,
|
|||
bool is_write, IOMMUTLBEntry *ret)
|
||||
{
|
||||
AMDVIState *s = as->iommu_state;
|
||||
uint16_t devid = PCI_BUILD_BDF(as->bus_num, as->devfn);
|
||||
uint16_t devid = PCI_BUILD_BDF(pci_bus_num(as->bus), as->devfn);
|
||||
AMDVIIOTLBEntry *iotlb_entry = amdvi_iotlb_lookup(s, addr, devid);
|
||||
uint64_t entry[4];
|
||||
int dte_ret;
|
||||
|
|
@ -1858,7 +1898,7 @@ static IOMMUTLBEntry amdvi_translate(IOMMUMemoryRegion *iommu, hwaddr addr,
|
|||
}
|
||||
|
||||
amdvi_do_translate(as, addr, flag & IOMMU_WO, &ret);
|
||||
trace_amdvi_translation_result(as->bus_num, PCI_SLOT(as->devfn),
|
||||
trace_amdvi_translation_result(pci_bus_num(as->bus), PCI_SLOT(as->devfn),
|
||||
PCI_FUNC(as->devfn), addr, ret.translated_addr);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -2222,30 +2262,28 @@ static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
|
|||
{
|
||||
char name[128];
|
||||
AMDVIState *s = opaque;
|
||||
AMDVIAddressSpace **iommu_as, *amdvi_dev_as;
|
||||
int bus_num = pci_bus_num(bus);
|
||||
AMDVIAddressSpace *amdvi_dev_as;
|
||||
AMDVIAsKey *key;
|
||||
|
||||
iommu_as = s->address_spaces[bus_num];
|
||||
amdvi_dev_as = amdvi_as_lookup(s, bus, devfn);
|
||||
|
||||
/* allocate memory during the first run */
|
||||
if (!iommu_as) {
|
||||
iommu_as = g_new0(AMDVIAddressSpace *, PCI_DEVFN_MAX);
|
||||
s->address_spaces[bus_num] = iommu_as;
|
||||
}
|
||||
|
||||
/* set up AMD-Vi region */
|
||||
if (!iommu_as[devfn]) {
|
||||
if (!amdvi_dev_as) {
|
||||
snprintf(name, sizeof(name), "amd_iommu_devfn_%d", devfn);
|
||||
|
||||
iommu_as[devfn] = g_new0(AMDVIAddressSpace, 1);
|
||||
iommu_as[devfn]->bus_num = (uint8_t)bus_num;
|
||||
iommu_as[devfn]->devfn = (uint8_t)devfn;
|
||||
iommu_as[devfn]->iommu_state = s;
|
||||
iommu_as[devfn]->notifier_flags = IOMMU_NOTIFIER_NONE;
|
||||
iommu_as[devfn]->iova_tree = iova_tree_new();
|
||||
iommu_as[devfn]->addr_translation = false;
|
||||
amdvi_dev_as = g_new0(AMDVIAddressSpace, 1);
|
||||
key = g_new0(AMDVIAsKey, 1);
|
||||
|
||||
amdvi_dev_as = iommu_as[devfn];
|
||||
amdvi_dev_as->bus = bus;
|
||||
amdvi_dev_as->devfn = (uint8_t)devfn;
|
||||
amdvi_dev_as->iommu_state = s;
|
||||
amdvi_dev_as->notifier_flags = IOMMU_NOTIFIER_NONE;
|
||||
amdvi_dev_as->iova_tree = iova_tree_new();
|
||||
amdvi_dev_as->addr_translation = false;
|
||||
key->bus = bus;
|
||||
key->devfn = devfn;
|
||||
|
||||
g_hash_table_insert(s->address_spaces, key, amdvi_dev_as);
|
||||
|
||||
/*
|
||||
* Memory region relationships looks like (Address range shows
|
||||
|
|
@ -2288,7 +2326,7 @@ static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
|
|||
|
||||
amdvi_switch_address_space(amdvi_dev_as);
|
||||
}
|
||||
return &iommu_as[devfn]->as;
|
||||
return &amdvi_dev_as->as;
|
||||
}
|
||||
|
||||
static const PCIIOMMUOps amdvi_iommu_ops = {
|
||||
|
|
@ -2329,7 +2367,7 @@ static int amdvi_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu,
|
|||
if (!s->dma_remap && (new & IOMMU_NOTIFIER_MAP)) {
|
||||
error_setg_errno(errp, ENOTSUP,
|
||||
"device %02x.%02x.%x requires dma-remap=1",
|
||||
as->bus_num, PCI_SLOT(as->devfn), PCI_FUNC(as->devfn));
|
||||
pci_bus_num(as->bus), PCI_SLOT(as->devfn), PCI_FUNC(as->devfn));
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
|
|
@ -2507,8 +2545,11 @@ static void amdvi_sysbus_realize(DeviceState *dev, Error **errp)
|
|||
}
|
||||
}
|
||||
|
||||
s->iotlb = g_hash_table_new_full(amdvi_uint64_hash,
|
||||
amdvi_uint64_equal, g_free, g_free);
|
||||
s->iotlb = g_hash_table_new_full(amdvi_iotlb_hash,
|
||||
amdvi_iotlb_equal, g_free, g_free);
|
||||
|
||||
s->address_spaces = g_hash_table_new_full(amdvi_as_hash,
|
||||
amdvi_as_equal, g_free, g_free);
|
||||
|
||||
/* set up MMIO */
|
||||
memory_region_init_io(&s->mr_mmio, OBJECT(s), &mmio_mem_ops, s,
|
||||
|
|
|
|||
|
|
@ -220,8 +220,8 @@
|
|||
#define PAGE_SIZE_PTE_COUNT(pgsz) (1ULL << ((ctz64(pgsz) - 12) % 9))
|
||||
|
||||
/* IOTLB */
|
||||
#define AMDVI_IOTLB_MAX_SIZE 1024
|
||||
#define AMDVI_DEVID_SHIFT 36
|
||||
#define AMDVI_IOTLB_MAX_SIZE 1024
|
||||
#define AMDVI_GET_IOTLB_GFN(addr) (addr >> AMDVI_PAGE_SHIFT_4K)
|
||||
|
||||
/* default extended feature */
|
||||
#define AMDVI_DEFAULT_EXT_FEATURES \
|
||||
|
|
@ -408,7 +408,7 @@ struct AMDVIState {
|
|||
bool mmio_enabled;
|
||||
|
||||
/* for each served device */
|
||||
AMDVIAddressSpace **address_spaces[PCI_BUS_MAX];
|
||||
GHashTable *address_spaces;
|
||||
|
||||
/* list of address spaces with registered notifiers */
|
||||
QLIST_HEAD(, AMDVIAddressSpace) amdvi_as_with_notifiers;
|
||||
|
|
|
|||
|
|
@ -87,6 +87,20 @@ struct vtd_iotlb_key {
|
|||
static void vtd_address_space_refresh_all(IntelIOMMUState *s);
|
||||
static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n);
|
||||
|
||||
static void vtd_pasid_cache_reset_locked(IntelIOMMUState *s)
|
||||
{
|
||||
VTDAddressSpace *vtd_as;
|
||||
GHashTableIter as_it;
|
||||
|
||||
trace_vtd_pasid_cache_reset();
|
||||
|
||||
g_hash_table_iter_init(&as_it, s->vtd_address_spaces);
|
||||
while (g_hash_table_iter_next(&as_it, NULL, (void **)&vtd_as)) {
|
||||
VTDPASIDCacheEntry *pc_entry = &vtd_as->pasid_cache_entry;
|
||||
pc_entry->valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void vtd_define_quad(IntelIOMMUState *s, hwaddr addr, uint64_t val,
|
||||
uint64_t wmask, uint64_t w1cmask)
|
||||
{
|
||||
|
|
@ -381,6 +395,7 @@ static void vtd_reset_caches(IntelIOMMUState *s)
|
|||
vtd_iommu_lock(s);
|
||||
vtd_reset_iotlb_locked(s);
|
||||
vtd_reset_context_cache_locked(s);
|
||||
vtd_pasid_cache_reset_locked(s);
|
||||
vtd_iommu_unlock(s);
|
||||
}
|
||||
|
||||
|
|
@ -3051,6 +3066,155 @@ static bool vtd_process_piotlb_desc(IntelIOMMUState *s,
|
|||
return true;
|
||||
}
|
||||
|
||||
static inline int vtd_dev_get_pe_from_pasid(VTDAddressSpace *vtd_as,
|
||||
VTDPASIDEntry *pe)
|
||||
{
|
||||
IntelIOMMUState *s = vtd_as->iommu_state;
|
||||
VTDContextEntry ce;
|
||||
int ret;
|
||||
|
||||
if (!s->root_scalable) {
|
||||
return -VTD_FR_RTADDR_INV_TTM;
|
||||
}
|
||||
|
||||
ret = vtd_dev_to_context_entry(s, pci_bus_num(vtd_as->bus), vtd_as->devfn,
|
||||
&ce);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return vtd_ce_get_rid2pasid_entry(s, &ce, pe, vtd_as->pasid);
|
||||
}
|
||||
|
||||
static int vtd_pasid_entry_compare(VTDPASIDEntry *p1, VTDPASIDEntry *p2)
|
||||
{
|
||||
return memcmp(p1, p2, sizeof(*p1));
|
||||
}
|
||||
|
||||
/* Update or invalidate pasid cache based on the pasid entry in guest memory. */
|
||||
static void vtd_pasid_cache_sync_locked(gpointer key, gpointer value,
|
||||
gpointer user_data)
|
||||
{
|
||||
VTDPASIDCacheInfo *pc_info = user_data;
|
||||
VTDAddressSpace *vtd_as = value;
|
||||
VTDPASIDCacheEntry *pc_entry = &vtd_as->pasid_cache_entry;
|
||||
VTDPASIDEntry pe;
|
||||
IOMMUNotifier *n;
|
||||
uint16_t did;
|
||||
|
||||
if (vtd_dev_get_pe_from_pasid(vtd_as, &pe)) {
|
||||
if (!pc_entry->valid) {
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* No valid pasid entry in guest memory. e.g. pasid entry was modified
|
||||
* to be either all-zero or non-present. Either case means existing
|
||||
* pasid cache should be invalidated.
|
||||
*/
|
||||
pc_entry->valid = false;
|
||||
|
||||
/*
|
||||
* When a pasid entry isn't valid any more, we should unmap all
|
||||
* mappings in shadow pages instantly to ensure DMA security.
|
||||
*/
|
||||
IOMMU_NOTIFIER_FOREACH(n, &vtd_as->iommu) {
|
||||
vtd_address_space_unmap(vtd_as, n);
|
||||
}
|
||||
vtd_switch_address_space(vtd_as);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* VTD_INV_DESC_PASIDC_G_DSI and VTD_INV_DESC_PASIDC_G_PASID_SI require
|
||||
* DID check. If DID doesn't match the value in cache or memory, then
|
||||
* it's not a pasid entry we want to invalidate.
|
||||
*/
|
||||
switch (pc_info->type) {
|
||||
case VTD_INV_DESC_PASIDC_G_PASID_SI:
|
||||
if (pc_info->pasid != vtd_as->pasid) {
|
||||
return;
|
||||
}
|
||||
/* Fall through */
|
||||
case VTD_INV_DESC_PASIDC_G_DSI:
|
||||
if (pc_entry->valid) {
|
||||
did = VTD_SM_PASID_ENTRY_DID(pc_entry->pasid_entry.val[1]);
|
||||
} else {
|
||||
did = VTD_SM_PASID_ENTRY_DID(pe.val[1]);
|
||||
}
|
||||
if (pc_info->did != did) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pc_entry->valid) {
|
||||
pc_entry->pasid_entry = pe;
|
||||
pc_entry->valid = true;
|
||||
} else if (!vtd_pasid_entry_compare(&pe, &pc_entry->pasid_entry)) {
|
||||
return;
|
||||
}
|
||||
|
||||
vtd_switch_address_space(vtd_as);
|
||||
vtd_address_space_sync(vtd_as);
|
||||
}
|
||||
|
||||
static void vtd_pasid_cache_sync(IntelIOMMUState *s, VTDPASIDCacheInfo *pc_info)
|
||||
{
|
||||
if (!s->root_scalable || !s->dmar_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
vtd_iommu_lock(s);
|
||||
g_hash_table_foreach(s->vtd_address_spaces, vtd_pasid_cache_sync_locked,
|
||||
pc_info);
|
||||
vtd_iommu_unlock(s);
|
||||
}
|
||||
|
||||
static bool vtd_process_pasid_desc(IntelIOMMUState *s,
|
||||
VTDInvDesc *inv_desc)
|
||||
{
|
||||
uint16_t did;
|
||||
uint32_t pasid;
|
||||
VTDPASIDCacheInfo pc_info = {};
|
||||
uint64_t mask[4] = {VTD_INV_DESC_PASIDC_RSVD_VAL0, VTD_INV_DESC_ALL_ONE,
|
||||
VTD_INV_DESC_ALL_ONE, VTD_INV_DESC_ALL_ONE};
|
||||
|
||||
if (!vtd_inv_desc_reserved_check(s, inv_desc, mask, true,
|
||||
__func__, "pasid cache inv")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
did = VTD_INV_DESC_PASIDC_DID(inv_desc);
|
||||
pasid = VTD_INV_DESC_PASIDC_PASID(inv_desc);
|
||||
pc_info.type = VTD_INV_DESC_PASIDC_G(inv_desc);
|
||||
|
||||
switch (pc_info.type) {
|
||||
case VTD_INV_DESC_PASIDC_G_DSI:
|
||||
trace_vtd_inv_desc_pasid_cache_dsi(did);
|
||||
pc_info.did = did;
|
||||
break;
|
||||
|
||||
case VTD_INV_DESC_PASIDC_G_PASID_SI:
|
||||
/* PASID selective implies a DID selective */
|
||||
trace_vtd_inv_desc_pasid_cache_psi(did, pasid);
|
||||
pc_info.did = did;
|
||||
pc_info.pasid = pasid ?: PCI_NO_PASID;
|
||||
break;
|
||||
|
||||
case VTD_INV_DESC_PASIDC_G_GLOBAL:
|
||||
trace_vtd_inv_desc_pasid_cache_gsi();
|
||||
break;
|
||||
|
||||
default:
|
||||
error_report_once("invalid granularity field in PASID-cache invalidate "
|
||||
"descriptor, hi: 0x%"PRIx64" lo: 0x%" PRIx64,
|
||||
inv_desc->val[1], inv_desc->val[0]);
|
||||
return false;
|
||||
}
|
||||
|
||||
vtd_pasid_cache_sync(s, &pc_info);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool vtd_process_inv_iec_desc(IntelIOMMUState *s,
|
||||
VTDInvDesc *inv_desc)
|
||||
{
|
||||
|
|
@ -3266,6 +3430,13 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s)
|
|||
}
|
||||
break;
|
||||
|
||||
case VTD_INV_DESC_PC:
|
||||
trace_vtd_inv_desc("pasid-cache", inv_desc.val[1], inv_desc.val[0]);
|
||||
if (!vtd_process_pasid_desc(s, &inv_desc)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case VTD_INV_DESC_PIOTLB:
|
||||
trace_vtd_inv_desc("p-iotlb", inv_desc.val[1], inv_desc.val[0]);
|
||||
if (!vtd_process_piotlb_desc(s, &inv_desc)) {
|
||||
|
|
@ -3308,16 +3479,6 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s)
|
|||
}
|
||||
break;
|
||||
|
||||
/*
|
||||
* TODO: the entity of below two cases will be implemented in future series.
|
||||
* To make guest (which integrates scalable mode support patch set in
|
||||
* iommu driver) work, just return true is enough so far.
|
||||
*/
|
||||
case VTD_INV_DESC_PC:
|
||||
if (s->scalable_mode) {
|
||||
break;
|
||||
}
|
||||
/* fallthrough */
|
||||
default:
|
||||
error_report_once("%s: invalid inv desc: hi=%"PRIx64", lo=%"PRIx64
|
||||
" (unknown type)", __func__, inv_desc.hi,
|
||||
|
|
|
|||
|
|
@ -316,6 +316,8 @@ typedef enum VTDFaultReason {
|
|||
* request while disabled */
|
||||
VTD_FR_IR_SID_ERR = 0x26, /* Invalid Source-ID */
|
||||
|
||||
VTD_FR_RTADDR_INV_TTM = 0x31, /* Invalid TTM in RTADDR */
|
||||
|
||||
VTD_FR_SM_PRE_ABS = 0x47, /* SCT.8 : PRE bit in a present SM CE is 0 */
|
||||
|
||||
/* PASID directory entry access failure */
|
||||
|
|
@ -517,6 +519,15 @@ typedef union VTDPRDesc VTDPRDesc;
|
|||
#define VTD_INV_DESC_PIOTLB_RSVD_VAL0 0xfff000000000f1c0ULL
|
||||
#define VTD_INV_DESC_PIOTLB_RSVD_VAL1 0xf80ULL
|
||||
|
||||
/* PASID-cache Invalidate Descriptor (pc_inv_dsc) fields */
|
||||
#define VTD_INV_DESC_PASIDC_G(x) extract64((x)->val[0], 4, 2)
|
||||
#define VTD_INV_DESC_PASIDC_G_DSI 0
|
||||
#define VTD_INV_DESC_PASIDC_G_PASID_SI 1
|
||||
#define VTD_INV_DESC_PASIDC_G_GLOBAL 3
|
||||
#define VTD_INV_DESC_PASIDC_DID(x) extract64((x)->val[0], 16, 16)
|
||||
#define VTD_INV_DESC_PASIDC_PASID(x) extract64((x)->val[0], 32, 20)
|
||||
#define VTD_INV_DESC_PASIDC_RSVD_VAL0 0xfff000000000f1c0ULL
|
||||
|
||||
/* Page Request Descriptor */
|
||||
/* For the low 64-bit of 128-bit */
|
||||
#define VTD_PRD_TYPE (1ULL)
|
||||
|
|
@ -603,6 +614,12 @@ typedef struct VTDRootEntry VTDRootEntry;
|
|||
#define VTD_SM_CONTEXT_ENTRY_RSVD_VAL1 0xffffffffffe00000ULL
|
||||
#define VTD_SM_CONTEXT_ENTRY_PRE 0x10ULL
|
||||
|
||||
typedef struct VTDPASIDCacheInfo {
|
||||
uint8_t type;
|
||||
uint16_t did;
|
||||
uint32_t pasid;
|
||||
} VTDPASIDCacheInfo;
|
||||
|
||||
/* PASID Table Related Definitions */
|
||||
#define VTD_PASID_DIR_BASE_ADDR_MASK (~0xfffULL)
|
||||
#define VTD_PASID_TABLE_BASE_ADDR_MASK (~0xfffULL)
|
||||
|
|
|
|||
|
|
@ -81,7 +81,9 @@
|
|||
{ "qemu64-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },\
|
||||
{ "athlon-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },
|
||||
|
||||
GlobalProperty pc_compat_10_1[] = {};
|
||||
GlobalProperty pc_compat_10_1[] = {
|
||||
{ "mch", "extended-tseg-mbytes", "16" },
|
||||
};
|
||||
const size_t pc_compat_10_1_len = G_N_ELEMENTS(pc_compat_10_1);
|
||||
|
||||
GlobalProperty pc_compat_10_0[] = {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,10 @@ vtd_inv_qi_head(uint16_t head) "read head %d"
|
|||
vtd_inv_qi_tail(uint16_t head) "write tail %d"
|
||||
vtd_inv_qi_fetch(void) ""
|
||||
vtd_context_cache_reset(void) ""
|
||||
vtd_pasid_cache_reset(void) ""
|
||||
vtd_inv_desc_pasid_cache_gsi(void) ""
|
||||
vtd_inv_desc_pasid_cache_dsi(uint16_t domain) "Domain selective PC invalidation domain 0x%"PRIx16
|
||||
vtd_inv_desc_pasid_cache_psi(uint16_t domain, uint32_t pasid) "PASID selective PC invalidation domain 0x%"PRIx16" pasid 0x%"PRIx32
|
||||
vtd_re_not_present(uint8_t bus) "Root entry bus %"PRIu8" not present"
|
||||
vtd_ce_not_present(uint8_t bus, uint8_t devfn) "Context entry bus %"PRIu8" devfn %"PRIu8" not present"
|
||||
vtd_iotlb_page_hit(uint16_t sid, uint64_t addr, uint64_t slpte, uint16_t domain) "IOTLB page hit sid 0x%"PRIx16" iova 0x%"PRIx64" slpte 0x%"PRIx64" domain 0x%"PRIx16
|
||||
|
|
|
|||
|
|
@ -4299,19 +4299,19 @@ static const Property virtio_net_properties[] = {
|
|||
VIRTIO_DEFINE_PROP_FEATURE("host_tunnel", VirtIONet,
|
||||
host_features_ex,
|
||||
VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO,
|
||||
false),
|
||||
true),
|
||||
VIRTIO_DEFINE_PROP_FEATURE("host_tunnel_csum", VirtIONet,
|
||||
host_features_ex,
|
||||
VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO_CSUM,
|
||||
false),
|
||||
true),
|
||||
VIRTIO_DEFINE_PROP_FEATURE("guest_tunnel", VirtIONet,
|
||||
host_features_ex,
|
||||
VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO,
|
||||
false),
|
||||
true),
|
||||
VIRTIO_DEFINE_PROP_FEATURE("guest_tunnel_csum", VirtIONet,
|
||||
host_features_ex,
|
||||
VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO_CSUM,
|
||||
false),
|
||||
true),
|
||||
};
|
||||
|
||||
static void virtio_net_class_init(ObjectClass *klass, const void *data)
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ static Aml *build_pci_host_bridge_dsm_method(void)
|
|||
UUID = aml_touuid("E5C937D0-3553-4D7A-9117-EA4D19C3434D");
|
||||
ifctx = aml_if(aml_equal(aml_arg(0), UUID));
|
||||
ifctx1 = aml_if(aml_equal(aml_arg(2), aml_int(0)));
|
||||
uint8_t byte_list[1] = {1};
|
||||
uint8_t byte_list[1] = {0};
|
||||
buf = aml_buffer(1, byte_list);
|
||||
aml_append(ifctx1, aml_return(buf));
|
||||
aml_append(ifctx, ifctx1);
|
||||
|
|
|
|||
|
|
@ -663,7 +663,7 @@ static void mch_realize(PCIDevice *d, Error **errp)
|
|||
|
||||
static const Property mch_props[] = {
|
||||
DEFINE_PROP_UINT16("extended-tseg-mbytes", MCHPCIState, ext_tseg_mbytes,
|
||||
16),
|
||||
64),
|
||||
DEFINE_PROP_BOOL("smbase-smram", MCHPCIState, has_smram_at_smbase, true),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1327,8 +1327,11 @@ static int vhost_set_vring_file(struct vhost_dev *dev,
|
|||
VhostUserRequest request,
|
||||
struct vhost_vring_file *file)
|
||||
{
|
||||
int ret;
|
||||
int fds[VHOST_USER_MAX_RAM_SLOTS];
|
||||
size_t fd_num = 0;
|
||||
bool reply_supported = virtio_has_feature(dev->protocol_features,
|
||||
VHOST_USER_PROTOCOL_F_REPLY_ACK);
|
||||
VhostUserMsg msg = {
|
||||
.hdr.request = request,
|
||||
.hdr.flags = VHOST_USER_VERSION,
|
||||
|
|
@ -1336,13 +1339,32 @@ static int vhost_set_vring_file(struct vhost_dev *dev,
|
|||
.hdr.size = sizeof(msg.payload.u64),
|
||||
};
|
||||
|
||||
if (reply_supported) {
|
||||
msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK;
|
||||
}
|
||||
|
||||
if (file->fd > 0) {
|
||||
fds[fd_num++] = file->fd;
|
||||
} else {
|
||||
msg.payload.u64 |= VHOST_USER_VRING_NOFD_MASK;
|
||||
}
|
||||
|
||||
return vhost_user_write(dev, &msg, fds, fd_num);
|
||||
ret = vhost_user_write(dev, &msg, fds, fd_num);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (reply_supported) {
|
||||
/*
|
||||
* wait for the back-end's confirmation that the new FD is active,
|
||||
* otherwise guest_notifier_mask() could check for pending interrupts
|
||||
* while the back-end is still using the masked event FD, losing
|
||||
* interrupts that occur before the back-end installs the FD
|
||||
*/
|
||||
return process_message_reply(dev, &msg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vhost_user_set_vring_kick(struct vhost_dev *dev,
|
||||
|
|
@ -1668,14 +1690,6 @@ static bool vhost_user_send_resp(QIOChannel *ioc, VhostUserHeader *hdr,
|
|||
return !qio_channel_writev_all(ioc, iov, ARRAY_SIZE(iov), errp);
|
||||
}
|
||||
|
||||
static bool
|
||||
vhost_user_backend_send_dmabuf_fd(QIOChannel *ioc, VhostUserHeader *hdr,
|
||||
VhostUserPayload *payload, Error **errp)
|
||||
{
|
||||
hdr->size = sizeof(payload->u64);
|
||||
return vhost_user_send_resp(ioc, hdr, payload, errp);
|
||||
}
|
||||
|
||||
int vhost_user_get_shared_object(struct vhost_dev *dev, unsigned char *uuid,
|
||||
int *dmabuf_fd)
|
||||
{
|
||||
|
|
@ -1716,19 +1730,15 @@ int vhost_user_get_shared_object(struct vhost_dev *dev, unsigned char *uuid,
|
|||
|
||||
static int
|
||||
vhost_user_backend_handle_shared_object_lookup(struct vhost_user *u,
|
||||
QIOChannel *ioc,
|
||||
VhostUserHeader *hdr,
|
||||
VhostUserPayload *payload)
|
||||
VhostUserShared *object)
|
||||
{
|
||||
QemuUUID uuid;
|
||||
CharFrontend *chr = u->user->chr;
|
||||
Error *local_err = NULL;
|
||||
int dmabuf_fd = -1;
|
||||
int fd_num = 0;
|
||||
|
||||
memcpy(uuid.data, payload->object.uuid, sizeof(payload->object.uuid));
|
||||
memcpy(uuid.data, object->uuid, sizeof(object->uuid));
|
||||
|
||||
payload->u64 = 0;
|
||||
switch (virtio_object_type(&uuid)) {
|
||||
case TYPE_DMABUF:
|
||||
dmabuf_fd = virtio_lookup_dmabuf(&uuid);
|
||||
|
|
@ -1737,18 +1747,16 @@ vhost_user_backend_handle_shared_object_lookup(struct vhost_user *u,
|
|||
{
|
||||
struct vhost_dev *dev = virtio_lookup_vhost_device(&uuid);
|
||||
if (dev == NULL) {
|
||||
payload->u64 = -EINVAL;
|
||||
break;
|
||||
return -EINVAL;
|
||||
}
|
||||
int ret = vhost_user_get_shared_object(dev, uuid.data, &dmabuf_fd);
|
||||
if (ret < 0) {
|
||||
payload->u64 = ret;
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TYPE_INVALID:
|
||||
payload->u64 = -EINVAL;
|
||||
break;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (dmabuf_fd != -1) {
|
||||
|
|
@ -1757,11 +1765,6 @@ vhost_user_backend_handle_shared_object_lookup(struct vhost_user *u,
|
|||
|
||||
if (qemu_chr_fe_set_msgfds(chr, &dmabuf_fd, fd_num) < 0) {
|
||||
error_report("Failed to set msg fds.");
|
||||
payload->u64 = -EINVAL;
|
||||
}
|
||||
|
||||
if (!vhost_user_backend_send_dmabuf_fd(ioc, hdr, payload, &local_err)) {
|
||||
error_report_err(local_err);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -1790,6 +1793,7 @@ static gboolean backend_read(QIOChannel *ioc, GIOCondition condition,
|
|||
struct iovec iov;
|
||||
g_autofree int *fd = NULL;
|
||||
size_t fdsize = 0;
|
||||
bool reply_ack;
|
||||
int i;
|
||||
|
||||
/* Read header */
|
||||
|
|
@ -1808,6 +1812,8 @@ static gboolean backend_read(QIOChannel *ioc, GIOCondition condition,
|
|||
goto err;
|
||||
}
|
||||
|
||||
reply_ack = hdr.flags & VHOST_USER_NEED_REPLY_MASK;
|
||||
|
||||
/* Read payload */
|
||||
if (qio_channel_read_all(ioc, (char *) &payload, hdr.size, &local_err)) {
|
||||
error_report_err(local_err);
|
||||
|
|
@ -1833,8 +1839,10 @@ static gboolean backend_read(QIOChannel *ioc, GIOCondition condition,
|
|||
&payload.object);
|
||||
break;
|
||||
case VHOST_USER_BACKEND_SHARED_OBJECT_LOOKUP:
|
||||
ret = vhost_user_backend_handle_shared_object_lookup(dev->opaque, ioc,
|
||||
&hdr, &payload);
|
||||
/* The backend always expects a response */
|
||||
reply_ack = true;
|
||||
ret = vhost_user_backend_handle_shared_object_lookup(dev->opaque,
|
||||
&payload.object);
|
||||
break;
|
||||
default:
|
||||
error_report("Received unexpected msg type: %d.", hdr.request);
|
||||
|
|
@ -1845,7 +1853,7 @@ static gboolean backend_read(QIOChannel *ioc, GIOCondition condition,
|
|||
* REPLY_ACK feature handling. Other reply types has to be managed
|
||||
* directly in their request handlers.
|
||||
*/
|
||||
if (hdr.flags & VHOST_USER_NEED_REPLY_MASK) {
|
||||
if (reply_ack) {
|
||||
payload.u64 = !!ret;
|
||||
hdr.size = sizeof(payload.u64);
|
||||
|
||||
|
|
|
|||
|
|
@ -95,6 +95,11 @@ struct VTDPASIDEntry {
|
|||
uint64_t val[8];
|
||||
};
|
||||
|
||||
typedef struct VTDPASIDCacheEntry {
|
||||
struct VTDPASIDEntry pasid_entry;
|
||||
bool valid;
|
||||
} VTDPASIDCacheEntry;
|
||||
|
||||
struct VTDAddressSpace {
|
||||
PCIBus *bus;
|
||||
uint8_t devfn;
|
||||
|
|
@ -107,6 +112,7 @@ struct VTDAddressSpace {
|
|||
MemoryRegion iommu_ir_fault; /* Interrupt region for catching fault */
|
||||
IntelIOMMUState *iommu_state;
|
||||
VTDContextCacheEntry context_cache_entry;
|
||||
VTDPASIDCacheEntry pasid_cache_entry;
|
||||
QLIST_ENTRY(VTDAddressSpace) next;
|
||||
/* Superset of notifier flags that this address space has */
|
||||
IOMMUNotifierFlag notifier_flags;
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue