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

../..

Reply via email to