On 7/16/2025 8:48 PM, Ethan MILON wrote:
On 7/16/25 09:31, Sairaj Kodilkar wrote:
The AMD IOMMU is set up at boot time and uses PCI bus numbers + devfn
for indexing into DTE. The problem is that before the guest started,
all PCI bus numbers are 0 as no PCI discovery happened yet (BIOS or/and
kernel will do that later) so relying on the bus number is wrong.
The immediate effect is emulated devices cannot do DMA when places on
a bus other that 0.
Replace static array of address_space with hash table which uses devfn and
PCIBus* for key as it is not going to change after the guest is booted.
Co-developed-by: Alexey Kardashevskiy <a...@amd.com>
Signed-off-by: Alexey Kardashevskiy <a...@amd.com>
Signed-off-by: Sairaj Kodilkar <sarun...@amd.com>
---
hw/i386/amd_iommu.c | 124 +++++++++++++++++++++++++++-----------------
hw/i386/amd_iommu.h | 2 +-
2 files changed, 76 insertions(+), 50 deletions(-)
diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
index a34062153194..33916b458611 100644
--- a/hw/i386/amd_iommu.c
+++ b/hw/i386/amd_iommu.c
@@ -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,11 @@ typedef enum AMDVIFaultReason {
AMDVI_FR_PT_ENTRY_INV, /* Failure to read PTE from guest memory */
} AMDVIFaultReason;
+typedef struct amdvi_as_key {
+ PCIBus *bus;
+ int devfn;
+} amdvi_as_key;
+
uint64_t amdvi_extended_feature_register(AMDVIState *s)
{
uint64_t feature = AMDVI_DEFAULT_EXT_FEATURES;
@@ -360,6 +365,42 @@ static guint amdvi_uint64_hash(gconstpointer v)
return (guint)*(const uint64_t *)v;
}
+static gboolean amdvi_as_equal(gconstpointer v1, gconstpointer v2)
+{
+ const struct amdvi_as_key *key1 = v1;
+ const struct amdvi_as_key *key2 = v2;
+
+ return key1->bus == key2->bus && key1->devfn == key2->devfn;
+}
+
+static guint amdvi_as_hash(gconstpointer v)
+{
+ const struct amdvi_as_key *key = v;
+ return (guint)((uint64_t)key->bus | (key->devfn << 24));
I think it should at least be a xor, but a hash similar to the
intel one is probably preferable:
return (guint)((uintptr_t)key->bus << 8) | key->devfn);
Makes sense considering that guint is 32 bit on most 64 bit machines.
But I am not sure if this is a good hash function (with uniform
distribution). Nonetheless, I will still change it to intel's
implementation.
Thanks
Sairaj
../..
-
- /* 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_NONE;
s/IOMMU_NONE/IOMMU_NOTIFIER_NONE
This is part of @Alejandro's changes in DMA remapping. I already pointed
this to him on his V2.
Thanks
Sairaj
../..