[edk2-devel] [PATCH 2/5] OvmfPkg/PciHostBridgeUtilityLib: Initialize RootBridges apertures with spec

Nicolas Ojeda Leon via groups.io posted 5 patches 4 years, 5 months ago
[edk2-devel] [PATCH 2/5] OvmfPkg/PciHostBridgeUtilityLib: Initialize RootBridges apertures with spec
Posted by Nicolas Ojeda Leon via groups.io 4 years, 5 months ago
Considering the "host-bridge-info" item from fw-cfg, the apertures for
all root bridges are initialized and used in the creation of the
root bridge objects that determine the resources each host bridge
can use.

PCI MMIO apertures are merged to produce a single low memory and a
single high memory apertures matching current Ovmf allocation strategy
which includes the EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM attribute.

Prefetchable and non-prefetchable ranges are merged together to
produce a single aperture covering both ranges. Therefore, if both
prefetchable and non-prefetchable apertures are defined for one of
the address spaces (32-bit or 64-bit), these 2 must be contiguous.

For platforms having multiple PCI host bridges, hypervisor builds and
propagates the resource specification (MMIO apertures) for each of the
host bridges over fw-cfg. These specifications determine the usable
windows in low and high memory, overwriting any calculated range and
providing both control for the hypervisor to configure the apertures
as well as possibility to use multiple host bridges.

Signed-off-by: Nicolas Ojeda Leon <ncoleon@amazon.com>
Cc: Alexander Graf <graf@amazon.de>
---
 .../PciHostBridgeUtilityLib.c                 | 128 +++++++++++++++++-
 1 file changed, 126 insertions(+), 2 deletions(-)

diff --git a/OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.c b/OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.c
index d2296f3308..7567da8423 100644
--- a/OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.c
+++ b/OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.c
@@ -18,6 +18,7 @@
 #include <Library/MemoryAllocationLib.h>
 #include <Library/PciHostBridgeUtilityLib.h>
 #include <Library/PciLib.h>
+#include <Library/PciHostBridgeInfoLib.h>
 #include <Library/QemuFwCfgLib.h>
 
 
@@ -186,6 +187,66 @@ PciHostBridgeUtilityUninitRootBridge (
   FreePool (RootBus->DevicePath);
 }
 
+/**
+  Interpret the MMIO resources in HostBridge and set the apertures
+  in 32-bit space (Mem) and 64-bit space (MemABove4G) accordingly.
+
+  The 2 types of apertures in each space (prefetchable and
+  non-prefetchable) are merged into a single window, hence if both
+  types of apertures are defined for a root bridges, these must be
+  contiguous.
+
+  @param[in]  HostBridge   Root bridge's resources specification
+
+  @param[out] Mem          32-bit MMIO aperture
+
+  @param[out] MemAbove4G   64-bit MMIO aperture
+**/
+STATIC
+VOID
+InitRootBridgeApertures (
+  IN  HOST_BRIDGE_INFO           *HostBridge,
+  OUT PCI_ROOT_BRIDGE_APERTURE   *Mem,
+  OUT PCI_ROOT_BRIDGE_APERTURE   *MemAbove4G
+
+  )
+{
+  if (HostBridge == NULL || Mem == NULL || MemAbove4G == NULL) {
+    return;
+  }
+
+  MemAbove4G->Base = MAX_UINT64;
+  MemAbove4G->Limit = 0;
+
+  if (HostBridge->highmem_start != MAX_UINT64 &&
+      HostBridge->highmem_end != MAX_UINT64) {
+    MemAbove4G->Base = HostBridge->highmem_start;
+    MemAbove4G->Limit = HostBridge->highmem_end;
+  }
+
+  if (HostBridge->highmem_pref_start != MAX_UINT64 &&
+      HostBridge->highmem_pref_end != MAX_UINT64) {
+    if (HostBridge->highmem_pref_start < MemAbove4G->Base)
+      MemAbove4G->Base = HostBridge->highmem_pref_start;
+
+    if (HostBridge->highmem_pref_end > MemAbove4G->Limit)
+      MemAbove4G->Limit = HostBridge->highmem_pref_end;
+  }
+
+  //
+  // Check if prefetchable range is valid and merge both ranges into a single
+  // 32-bit aperture.
+  // In case both prefetchable and non-prefetchable ranges are defined,
+  // these must be contiguous.
+  //
+  Mem->Base = HostBridge->lowmem_start;
+  if (HostBridge->lowmem_pref_end != MAX_UINT32) {
+    Mem->Limit = HostBridge->lowmem_pref_end;
+  } else {
+    Mem->Limit = HostBridge->lowmem_end;
+  }
+}
+
 
 /**
   Utility function to return all the root bridge instances in an array.
@@ -241,6 +302,7 @@ PciHostBridgeUtilityGetRootBridges (
   UINTN                Initialized;
   UINTN                LastRootBridgeNumber;
   UINTN                RootBridgeNumber;
+  HOST_BRIDGE_INFO     *RootBridgesInfo;
 
   *Count = 0;
 
@@ -277,13 +339,54 @@ PciHostBridgeUtilityGetRootBridges (
       __FUNCTION__, ExtraRootBridges));
   }
 
+  //
+  // Initialize RootBridgeInfo pointer, so in case no fw-cfg item is found
+  // the default configuration is used.
+  //
+  RootBridgesInfo =  NULL;
+  Initialized = 0;
+  Bridges = NULL;
+
+  //
+  // Hypervisor can provide, over fw-cfg, resource specifications for one or
+  // more PCI host bridges.
+  //
+  Status = QemuFwCfgFindFile ("etc/host-bridge-info", &FwCfgItem, &FwCfgSize);
+
+  if (!EFI_ERROR (Status)) {
+    UINTN RootBridgesInfoSize = (1 + (UINTN)ExtraRootBridges) *
+                                 sizeof(HOST_BRIDGE_INFO);
+    RootBridgesInfo = AllocatePool (RootBridgesInfoSize);
+
+    if (RootBridgesInfo == NULL) {
+      DEBUG ((DEBUG_ERROR,
+        "%a: Failed to allocate memory for resources info\n", __FUNCTION__));
+      return NULL;
+    }
+
+    //
+    // Read the resource information of all Root Bridges from fw-cfg
+    //
+    QemuFwCfgSelectItem (FwCfgItem);
+    QemuFwCfgReadBytes (FwCfgSize, RootBridgesInfo);
+
+    if (FwCfgSize != RootBridgesInfoSize) {
+      DEBUG ((DEBUG_ERROR,
+        "%a: Invalid HostBridgeInfo fw-cfg item size. Expected %ld, got %ld\n",
+        __FUNCTION__, RootBridgesInfoSize, FwCfgSize));
+        goto FreeBridges;
+    }
+    DEBUG ((DEBUG_INFO, "%a: Resources for %Lu root buses found in fw-cfg\n",
+      __FUNCTION__, ExtraRootBridges + 1));
+  }
+
   //
   // Allocate the "main" root bridge, and any extra root bridges.
   //
   Bridges = AllocatePool ((1 + (UINTN)ExtraRootBridges) * sizeof *Bridges);
   if (Bridges == NULL) {
     DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, EFI_OUT_OF_RESOURCES));
-    return NULL;
+    goto FreeBridges;
   }
   Initialized = 0;
 
@@ -309,6 +412,11 @@ PciHostBridgeUtilityGetRootBridges (
       }
     }
     if (Device <= PCI_MAX_DEVICE) {
+      //
+      // If resources obtained from fw-cfg, use those values
+      //
+      InitRootBridgeApertures(&RootBridgesInfo[Initialized], Mem, MemAbove4G);
+
       //
       // Found the next root bus. We can now install the *previous* one,
       // because now we know how big a bus number range *that* one has, for any
@@ -341,6 +449,8 @@ PciHostBridgeUtilityGetRootBridges (
   // Install the last root bus (which might be the only, ie. main, root bus, if
   // we've found no extra root buses).
   //
+  InitRootBridgeApertures(&RootBridgesInfo[Initialized], Mem, MemAbove4G);
+
   Status = PciHostBridgeUtilityInitRootBridge (
     Attributes,
     Attributes,
@@ -362,6 +472,14 @@ PciHostBridgeUtilityGetRootBridges (
   ++Initialized;
 
   *Count = Initialized;
+
+  //
+  // If resources were allocated for host bridges info, release them
+  //
+  if (RootBridgesInfo) {
+    FreePool(RootBridgesInfo);
+  }
+
   return Bridges;
 
 FreeBridges:
@@ -370,7 +488,13 @@ FreeBridges:
     PciHostBridgeUtilityUninitRootBridge (&Bridges[Initialized]);
   }
 
-  FreePool (Bridges);
+  if (Bridges) {
+    FreePool (Bridges);
+  }
+
+  if (RootBridgesInfo) {
+    FreePool(RootBridgesInfo);
+  }
   return NULL;
 }
 
-- 
2.17.1




Amazon Development Center Germany GmbH
Krausenstr. 38
10117 Berlin
Geschaeftsfuehrung: Christian Schlaeger, Jonathan Weiss
Eingetragen am Amtsgericht Charlottenburg unter HRB 149173 B
Sitz: Berlin
Ust-ID: DE 289 237 879





-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#80300): https://edk2.groups.io/g/devel/message/80300
Mute This Topic: https://groups.io/mt/85437210/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-