* [PATCH v6 1/5] OvmfPkg/Library: Create base HardwareInfoLib for PCI Host Bridges
2022-06-21 21:27 [PATCH v6 0/5] Handling of multiple PCI Ojeda Leon, Nicolas
@ 2022-06-21 21:31 ` Ojeda Leon, Nicolas
2022-06-21 21:34 ` [PATCH v6 2/5] Ovmf/HardwareInfoLib: Create Pei lib to parse directly from fw-cfg Ojeda Leon, Nicolas
` (4 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Ojeda Leon, Nicolas @ 2022-06-21 21:31 UTC (permalink / raw)
To: devel
Cc: ardb+tianocore, jiewen.yao, jordan.l.justen, Nicolas Ojeda Leon,
Alexander Graf, Gerd Hoffmann
Create the Hardware Info library base together with the specifics to
describe PCI Host Bridges.
The Hardware Info library is intended to be used for disclosing
non-discoverable hardware information from the host to the guest in
Ovmf platforms. Core functionality will provide the possibility to
parse information from a generic BLOB into runtime structures. The
library is conceived in a generic way so that further hardware
elements can also be described using it. For such purpose the length
of the BLOB is not restricted but instead regarded as a sequence of
header-info elements that allow the parsing during runtime. The first
type of hardware defined will be PCI host bridges, providing the
possibility to define multiple and specify the resources each of them
can use. This enables the guest firmware to configure PCI resources
properly. Having the size of each individual element favors the reuse
of a single interface to convey descriptions of an arbitrary number
of heterogenous hardware elements. Furthermore, flexible access
mechanisms coupled with the size will grant the possibility of
interpreting them in a single run.
Define the base types of the generic Hardware Info library to parse
heterogeneous data. Also provide the specific changes to support
PCI host bridges as the first hardware type supported by the
library.
Additionally, define the HOST_BRIDGE_INFO structure to describe PCI
host bridges along with the functionality to parse such information
into proper structures used by the PCI driver in a centralized manner
and taking care of versioning.
As an example and motivation, the library will be used to define
multiple PCI host bridges for complex platforms that require it.
The first means of transportation that will be used is going to be
fw-cfg, over which a stream of bytes will be transferred and later
parsed by the hardware info library. Accordingly, the PCI driver
will make use of these host bridges definitions to populate the
list of Root Bridges and proceed with the configuration and discovery
of underlying hardware components.
As mentioned before, the binary data to be parsed by the Hardware
Info library should be organized as a sequence of Header-element
pairs in which the header describes the type and size of the associated
element that comes right after it. As an illustration, to provide
inforation of 3 host bridges the data, conceptually, would look
like this:
Header PCI Host Bridge (type and size) # 1
PCI Host Bridge info # 1
Header PCI Host Bridge (type and size) # 2
PCI Host Bridge info # 2
Header PCI Host Bridge (type and size) # 3
PCI Host Bridge info # 3
Cc: Alexander Graf <graf@amazon.de>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Nicolas Ojeda Leon <ncoleon@amazon.com>
---
Notes:
v6:
Preparation for merge:
- Updated files' copyright to follow EDK2 format
- Modified HOST_BRIDGE_INFO bitfield member to use UINT32 instead
of UINT64 to comply with coding guidelines motivated by building
on 32-bit windows system, adjusted padding as well to preserve
8-byte alignment while reducing structure size.
- Included HardwareInfoTypeMax to the enum following coding
guidelines.
v4:
- Minor change in InvalidateRootBridgeAperture to always set the
invalid base address to MAX_UINT64, thus having a universal
invalid value.
---
.../HardwareInfoPciHostBridgeLib.c | 508 ++++++++++++++++++
.../HardwareInfoPciHostBridgeLib.h | 256 +++++++++
.../HardwareInfoLib/HardwareInfoTypesLib.h | 59 ++
3 files changed, 823 insertions(+)
create mode 100644 OvmfPkg/Library/HardwareInfoLib/HardwareInfoPciHostBridgeLib.c
create mode 100644 OvmfPkg/Library/HardwareInfoLib/HardwareInfoPciHostBridgeLib.h
create mode 100644 OvmfPkg/Library/HardwareInfoLib/HardwareInfoTypesLib.h
diff --git a/OvmfPkg/Library/HardwareInfoLib/HardwareInfoPciHostBridgeLib.c b/OvmfPkg/Library/HardwareInfoLib/HardwareInfoPciHostBridgeLib.c
new file mode 100644
index 0000000000..26cd435adf
--- /dev/null
+++ b/OvmfPkg/Library/HardwareInfoLib/HardwareInfoPciHostBridgeLib.c
@@ -0,0 +1,508 @@
+/**@file
+ Hardware info library with types and accessors to parse information about
+ PCI host bridges.
+
+ Copyright 2021 - 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/DebugLib.h>
+
+#include "HardwareInfoPciHostBridgeLib.h"
+
+#define IS_RANGE_INVALID(Start, Size, MaxValue) (Start >= MaxValue || Size == 0)
+
+/**
+ Calculate the last (inclusive) address of a range.
+
+ @param[in] Start First address of the range
+ @param[in] Size Size of the range
+ @return Last address of the range
+**/
+STATIC
+UINT64
+GetRangeEnd (
+ IN UINT64 Start,
+ IN UINT64 Size,
+ IN UINT64 MaxValue
+ )
+{
+ if (IS_RANGE_INVALID (Start, Size, MaxValue)) {
+ return 0;
+ }
+
+ return Start + Size - 1;
+}
+
+/**
+ Internal helper to update LastAddress if the Limit address
+ of the Mem aperture is higher than the provided value.
+
+ @param[in] Mem Pointer to aperture whose limit is
+ to be compared against accumulative
+ last address.
+ @param[out] LastAddress Pointer to accumulative last address
+ to be updated if Limit is higher
+**/
+STATIC
+VOID
+UpdateLastAddressIfHigher (
+ IN PCI_ROOT_BRIDGE_APERTURE *Mem,
+ OUT UINT64 *LastAddress
+ )
+{
+ if (Mem->Limit > *LastAddress) {
+ *LastAddress = Mem->Limit;
+ }
+}
+
+EFI_STATUS
+HardwareInfoPciHostBridgeLastMmioAddress (
+ IN CONST HOST_BRIDGE_INFO *HostBridge,
+ IN UINTN DataSize,
+ IN BOOLEAN HighMem,
+ OUT UINT64 *LastMmioAddress
+ )
+{
+ EFI_STATUS Status;
+ PCI_ROOT_BRIDGE_APERTURE Mem;
+ PCI_ROOT_BRIDGE_APERTURE MemAbove4G;
+ PCI_ROOT_BRIDGE_APERTURE PMem;
+ PCI_ROOT_BRIDGE_APERTURE PMemAbove4G;
+
+ if (LastMmioAddress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Set the output to the lowest possible value so that if some step fails
+ // the overall outcome reflects no information found
+ //
+ *LastMmioAddress = 0;
+
+ Status = HardwareInfoPciHostBridgeGetApertures (
+ HostBridge,
+ DataSize,
+ NULL,
+ &Mem,
+ &MemAbove4G,
+ &PMem,
+ &PMemAbove4G,
+ NULL
+ );
+
+ //
+ // Forward error to caller but ignore warnings given that, very likely,
+ // the host bridge will have a PIO aperture we are explicitly
+ // ignoring here since we care only about MMIO resources.
+ //
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (HighMem) {
+ UpdateLastAddressIfHigher (&MemAbove4G, LastMmioAddress);
+ UpdateLastAddressIfHigher (&PMemAbove4G, LastMmioAddress);
+ } else {
+ UpdateLastAddressIfHigher (&Mem, LastMmioAddress);
+ UpdateLastAddressIfHigher (&PMem, LastMmioAddress);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set the boundaries of an aperture to invalid values having
+ size zero and start MaxValue (yields Start > Limit which
+ depicts an invalid range)
+
+ @param[in] MaxValue Max value of the aperture's range (depends
+ on the data type)
+ @param[out] Aperture Aperture object to invalidate
+**/
+STATIC
+VOID
+InvalidateRootBridgeAperture (
+ OUT PCI_ROOT_BRIDGE_APERTURE *Aperture
+ )
+{
+ if (Aperture == NULL) {
+ return;
+ }
+
+ Aperture->Base = MAX_UINT64;
+ Aperture->Limit = 0;
+}
+
+/**
+ Fill a PCI ROOT BRIDGE APERTURE with the proper values calculated
+ from the provided start and size.
+
+ @param[in] Start Start address of the aperture
+ @param[in] Size Size, in bytes, of the aperture
+ @param[in] MaxValue Max value a valid address could take and which
+ represents an invalid start address.
+ @param[out] Aperture Pointer to the aperture to be filled
+
+ @retval EFI_SUCCESS Aperture was filled successfully
+ @retval EFI_INVALID_PARAMETER Range depicted by Start and Size is
+ valid but ignored because aperture
+ pointer is NULL
+ @retval EFI_WARN_BUFFER_TOO_SMALL Aperture pointer is invalid but the
+ range also is so no harm.
+**/
+STATIC
+EFI_STATUS
+FillHostBridgeAperture (
+ IN UINT64 Start,
+ IN UINT64 Size,
+ IN UINT64 MaxValue,
+ OUT PCI_ROOT_BRIDGE_APERTURE *Aperture
+ )
+{
+ UINT64 End;
+
+ End = GetRangeEnd (Start, Size, MaxValue);
+
+ if (Aperture == NULL) {
+ if (!IS_RANGE_INVALID (Start, Size, MaxValue)) {
+ //
+ // Report an error to the caller since the range specified in
+ // the host bridge's resources is non-empty but the provided
+ // aperture pointer is null, thus the valid range is ignored.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_WARN_BUFFER_TOO_SMALL;
+ }
+
+ if (IS_RANGE_INVALID (Start, Size, MaxValue)) {
+ //
+ // Fill Aperture with invalid range values to signal the
+ // absence of an address space (empty range)
+ //
+ InvalidateRootBridgeAperture (Aperture);
+ } else {
+ Aperture->Base = Start;
+ Aperture->Limit = End;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Merge 2 ranges (normal and prefetchable) into a single aperture
+ comprehending the addresses encompassed by both of them. If both
+ ranges are not empty they must be contiguous for correctness.
+
+ @param[in] Start Range start address
+ @param[in] Size Range size in bytes
+ @param[in] PStart Prefetchable range start address
+ @param[in] PSize Prefetchable range size in bytes
+ @param[in] MaxValue Max value a valid address could take and which
+ represents an invalid start address.
+ @param[out] Aperture Pointer to the aperture to be filled
+
+ @retval EFI_SUCCESS Aperture was filled successfully
+ @retval EFI_INVALID_PARAMETER Either range depicted by Start, Size
+ or PStart, PSize or both are valid
+ but ignored because aperture pointer
+ is NULL
+ @retval EFI_WARN_BUFFER_TOO_SMALL Aperture pointer is invalid but both
+ ranges are too so no harm.
+**/
+STATIC
+EFI_STATUS
+MergeHostBridgeApertures (
+ IN UINT64 Start,
+ IN UINT64 Size,
+ IN UINT64 PStart,
+ IN UINT64 PSize,
+ IN UINT64 MaxValue,
+ OUT PCI_ROOT_BRIDGE_APERTURE *Aperture
+ )
+{
+ UINT64 PEnd;
+
+ if (Aperture == NULL) {
+ if (!IS_RANGE_INVALID (Start, Size, MaxValue) ||
+ !IS_RANGE_INVALID (PStart, PSize, MaxValue))
+ {
+ //
+ // Report an error to the caller since the range specified in
+ // the host bridge's resources is non-empty but the provided
+ // aperture pointer is null, thus the valid range is ignored.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_WARN_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Start from an empty range (Limit < Base)
+ //
+ InvalidateRootBridgeAperture (Aperture);
+
+ if (!IS_RANGE_INVALID (Start, Size, MaxValue)) {
+ Aperture->Base = Start;
+ Aperture->Limit = Start + Size - 1;
+ }
+
+ if (!IS_RANGE_INVALID (PStart, PSize, MaxValue)) {
+ PEnd = PStart + PSize - 1;
+
+ if (PStart < Aperture->Base) {
+ Aperture->Base = PStart;
+ }
+
+ if (PEnd > Aperture->Limit) {
+ Aperture->Limit = PEnd;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+HardwareInfoPciHostBridgeGetBusNrRange (
+ IN CONST HOST_BRIDGE_INFO *HostBridge,
+ IN UINTN DataSize,
+ OUT UINTN *BusNrStart,
+ OUT UINTN *BusNrLast
+ )
+{
+ if ((HostBridge == NULL) || (DataSize == 0) ||
+ (BusNrStart == NULL) || (BusNrLast == NULL))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // For now only version 0 is supported
+ //
+ if (HostBridge->Version != 0) {
+ return EFI_INCOMPATIBLE_VERSION;
+ }
+
+ *BusNrStart = HostBridge->BusNrStart;
+ *BusNrLast = HostBridge->BusNrLast;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+HardwareInfoPciHostBridgeGetApertures (
+ IN CONST HOST_BRIDGE_INFO *HostBridge,
+ IN UINTN DataSize,
+ OUT PCI_ROOT_BRIDGE_APERTURE *Io,
+ OUT PCI_ROOT_BRIDGE_APERTURE *Mem,
+ OUT PCI_ROOT_BRIDGE_APERTURE *MemAbove4G,
+ OUT PCI_ROOT_BRIDGE_APERTURE *PMem,
+ OUT PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G,
+ OUT PCI_ROOT_BRIDGE_APERTURE *PcieConfig
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN StickyError;
+
+ StickyError = FALSE;
+ if ((HostBridge == NULL) || (DataSize == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // For now only version 0 is supported
+ //
+ if (HostBridge->Version != 0) {
+ return EFI_INCOMPATIBLE_VERSION;
+ }
+
+ Status = FillHostBridgeAperture (
+ HostBridge->IoStart,
+ HostBridge->IoSize,
+ MAX_UINT32,
+ Io
+ );
+ StickyError |= EFI_ERROR (Status);
+
+ Status = FillHostBridgeAperture (
+ HostBridge->PcieConfigStart,
+ HostBridge->PcieConfigSize,
+ MAX_UINT64,
+ PcieConfig
+ );
+ StickyError |= EFI_ERROR (Status);
+
+ if (HostBridge->Flags.Bits.CombineMemPMem) {
+ Status = MergeHostBridgeApertures (
+ HostBridge->MemStart,
+ HostBridge->MemSize,
+ HostBridge->PMemStart,
+ HostBridge->PMemSize,
+ MAX_UINT32,
+ Mem
+ );
+ StickyError |= EFI_ERROR (Status);
+
+ Status = MergeHostBridgeApertures (
+ HostBridge->MemAbove4GStart,
+ HostBridge->MemAbove4GSize,
+ HostBridge->PMemAbove4GStart,
+ HostBridge->PMemAbove4GSize,
+ MAX_UINT64,
+ MemAbove4G
+ );
+ StickyError |= EFI_ERROR (Status);
+
+ //
+ // Invalidate unused apertures
+ //
+ InvalidateRootBridgeAperture (PMem);
+ InvalidateRootBridgeAperture (PMemAbove4G);
+ } else {
+ Status = FillHostBridgeAperture (
+ HostBridge->MemStart,
+ HostBridge->MemSize,
+ MAX_UINT32,
+ Mem
+ );
+ StickyError |= EFI_ERROR (Status);
+
+ Status = FillHostBridgeAperture (
+ HostBridge->PMemStart,
+ HostBridge->PMemSize,
+ MAX_UINT32,
+ PMem
+ );
+ StickyError |= EFI_ERROR (Status);
+
+ Status = FillHostBridgeAperture (
+ HostBridge->MemAbove4GStart,
+ HostBridge->MemAbove4GSize,
+ MAX_UINT64,
+ MemAbove4G
+ );
+ StickyError |= EFI_ERROR (Status);
+
+ Status = FillHostBridgeAperture (
+ HostBridge->PMemAbove4GStart,
+ HostBridge->PMemAbove4GSize,
+ MAX_UINT64,
+ PMem
+ );
+ StickyError |= EFI_ERROR (Status);
+ }
+
+ if (StickyError) {
+ //
+ // If any function returned an error it is due to a valid range
+ // specified in the host bridge that was ignored due to a NULL
+ // pointer. Translate it to a warning to allow for calling with
+ // only a subset of the apertures.
+ //
+ return EFI_WARN_STALE_DATA;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+HardwareInfoPciHostBridgeGetFlags (
+ IN CONST HOST_BRIDGE_INFO *HostBridge,
+ IN UINTN DataSize,
+ OUT UINT64 *Attributes OPTIONAL,
+ OUT BOOLEAN *DmaAbove4G OPTIONAL,
+ OUT BOOLEAN *NoExtendedConfigSpace OPTIONAL,
+ OUT BOOLEAN *CombineMemPMem OPTIONAL
+ )
+{
+ if ((HostBridge == NULL) || (DataSize == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // For now only version 0 is supported
+ //
+ if (HostBridge->Version != 0) {
+ return EFI_INCOMPATIBLE_VERSION;
+ }
+
+ if (Attributes) {
+ *Attributes = HostBridge->Attributes;
+ }
+
+ if (DmaAbove4G) {
+ *DmaAbove4G = !!HostBridge->Flags.Bits.DmaAbove4G;
+ }
+
+ if (NoExtendedConfigSpace) {
+ *NoExtendedConfigSpace = !!HostBridge->Flags.Bits.NoExtendedConfigSpace;
+ }
+
+ if (CombineMemPMem) {
+ *CombineMemPMem = !!HostBridge->Flags.Bits.CombineMemPMem;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+HardwareInfoPciHostBridgeGet (
+ IN CONST HOST_BRIDGE_INFO *HostBridge,
+ IN UINTN DataSize,
+ OUT UINTN *BusNrStart,
+ OUT UINTN *BusNrLast,
+ OUT UINT64 *Attributes OPTIONAL,
+ OUT BOOLEAN *DmaAbove4G OPTIONAL,
+ OUT BOOLEAN *NoExtendedConfigSpace OPTIONAL,
+ OUT BOOLEAN *CombineMemPMem OPTIONAL,
+ OUT PCI_ROOT_BRIDGE_APERTURE *Io OPTIONAL,
+ OUT PCI_ROOT_BRIDGE_APERTURE *Mem OPTIONAL,
+ OUT PCI_ROOT_BRIDGE_APERTURE *MemAbove4G OPTIONAL,
+ OUT PCI_ROOT_BRIDGE_APERTURE *PMem OPTIONAL,
+ OUT PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G OPTIONAL,
+ OUT PCI_ROOT_BRIDGE_APERTURE *PcieConfig OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+
+ Status = HardwareInfoPciHostBridgeGetBusNrRange (
+ HostBridge,
+ DataSize,
+ BusNrStart,
+ BusNrLast
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = HardwareInfoPciHostBridgeGetFlags (
+ HostBridge,
+ DataSize,
+ Attributes,
+ DmaAbove4G,
+ NoExtendedConfigSpace,
+ CombineMemPMem
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = HardwareInfoPciHostBridgeGetApertures (
+ HostBridge,
+ DataSize,
+ Io,
+ Mem,
+ MemAbove4G,
+ PMem,
+ PMemAbove4G,
+ PcieConfig
+ );
+
+ return Status;
+}
diff --git a/OvmfPkg/Library/HardwareInfoLib/HardwareInfoPciHostBridgeLib.h b/OvmfPkg/Library/HardwareInfoLib/HardwareInfoPciHostBridgeLib.h
new file mode 100644
index 0000000000..627de118d3
--- /dev/null
+++ b/OvmfPkg/Library/HardwareInfoLib/HardwareInfoPciHostBridgeLib.h
@@ -0,0 +1,256 @@
+/**@file
+ Hardware info library with types and accessors to parse information about
+ PCI host bridges.
+
+ Copyright 2021 - 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __HARDWARE_INFO_PCI_HOST_BRIDGE_LIB_H__
+#define __HARDWARE_INFO_PCI_HOST_BRIDGE_LIB_H__
+
+#include <Uefi/UefiBaseType.h>
+#include <Uefi/UefiSpec.h>
+#include <Library/PciHostBridgeLib.h>
+
+//
+// Host Bridge resources information
+//
+#pragma pack(1)
+typedef struct {
+ //
+ // Feature tracking, initially 0
+ //
+ UINT64 Version;
+
+ //
+ // Host bridge enabled attributes (EFI_PCI_ATTRIBUTE_*)
+ //
+ UINT64 Attributes;
+
+ union {
+ UINT32 Uint32;
+ struct {
+ UINT32 DmaAbove4G : 1;
+ UINT32 NoExtendedConfigSpace : 1;
+ UINT32 CombineMemPMem : 1;
+ UINT32 Reserved : 29;
+ } Bits;
+ } Flags;
+
+ //
+ // Bus number range
+ //
+ UINT8 BusNrStart;
+ UINT8 BusNrLast;
+
+ UINT8 Padding[2];
+
+ //
+ // IO aperture
+ //
+ UINT64 IoStart;
+ UINT64 IoSize;
+
+ //
+ // 32-bit MMIO aperture
+ //
+ UINT64 MemStart;
+ UINT64 MemSize;
+
+ //
+ // 32-bit prefetchable MMIO aperture
+ //
+ UINT64 PMemStart;
+ UINT64 PMemSize;
+
+ //
+ // 64-bit MMIO aperture
+ //
+ UINT64 MemAbove4GStart;
+ UINT64 MemAbove4GSize;
+
+ //
+ // 64-bit prefetchable MMIO aperture
+ //
+ UINT64 PMemAbove4GStart;
+ UINT64 PMemAbove4GSize;
+
+ //
+ // MMIO accessible PCIe config space (ECAM)
+ //
+ UINT64 PcieConfigStart;
+ UINT64 PcieConfigSize;
+} HOST_BRIDGE_INFO;
+#pragma pack()
+
+/**
+ Extract the last MMIO address, either from high (64-bit) or low (32-bit)
+ memory used by the HostBridge's apertures.
+
+ @param[in] HostBridge Root bridge's resources specification
+ @param[in] DataSize Size in bytes of the actually filled
+ data available in the HostBridge object
+ @param[in] HighMem 64-bit (true) or 32-bit (false) MMIO
+ address
+ @param[out] LastMmioAddress Pointer to last MMIO address
+
+ @retval EFI_SUCCESS Operation succeeded
+ @retval EFI_INVALID_PARAMETER One or more pointer parameters are
+ invalid
+ @retval EFI_INCOMPATIBLE_VERSION HostBridge information belongs to
+ an unsupported version
+**/
+EFI_STATUS
+HardwareInfoPciHostBridgeLastMmioAddress (
+ IN CONST HOST_BRIDGE_INFO *HostBridge,
+ IN UINTN DataSize,
+ IN BOOLEAN HighMem,
+ OUT UINT64 *LastMmioAddress
+ );
+
+/**
+ Interpret the HostBridge resources and extact the bus number
+ range.
+
+ @param[in] HostBridge Root bridge's resources specification
+ @param[in] DataSize Size in bytes of the actually filled
+ data available in the HostBridge object
+ @param[out] BusNrStart Pointer to the Bus Number range start
+ @param[out] BusNrLast Pointer to the Bus Number range end
+
+ @retval EFI_SUCCESS Retrieved the bus number range
+ without any issues.
+ @retval EFI_INVALID_PARAMETER One of the parameters is invalid,
+ either NULL pointer or size 0
+ @retval EFI_INCOMPATIBLE_VERSION HostBridge data of unsupported
+ version
+**/
+EFI_STATUS
+HardwareInfoPciHostBridgeGetBusNrRange (
+ IN CONST HOST_BRIDGE_INFO *HostBridge,
+ IN UINTN DataSize,
+ OUT UINTN *BusNrStart,
+ OUT UINTN *BusNrLast
+ );
+
+/**
+ Interpret the MMIO resources in HostBridge and set the apertures
+ in 32-bit space (Mem), 64-bit space (MemAbove4G), PIO (IO) and
+ ECAM (PcieConfig) accordingly.
+
+ The 2 types of apertures in each MMIO space (prefetchable and
+ non-prefetchable) may be merged into a single window, hence if both
+ types of apertures are defined while the CombineMemPMem flag is set,
+ the ranges must be contiguous.
+
+ @param[in] HostBridge Root bridge's resources specification
+ @param[in] DataSize Size in bytes of the actually filled
+ data available in the HostBridge object
+ @param[out] Mem Pointer to 32-bit MMIO aperture
+ @param[out] MemAbove4G Pointer to 64-bit MMIO aperture
+ @param[out] PMem Pointer to the 32-bit prefetchable MMIO aperture
+ @param[out] PMemAbove4G Pointer to the 64-bit prefetchable MMIO aperture
+ @param[out] PcieConfig Pointer to MMIO mapped PCIe config aperture (ECAM)
+
+ @retval EFI_INVALID_PARAMETER HostBridge object is invalid
+ @retval EFI_INCOMPATIBLE_VERSION HostBridge information belongs to
+ an unsupported version
+ @retval EFI_WARN_STALE_DATA One or more valid aperture in the
+ HostBridge's resources were ignored
+ because corresponding aperture pointer
+ is NULL.
+ @retval EFI_SUCCESS Operation executed cleanly, all valid
+ ranges were parsed into the corresponding
+ aperture object.
+**/
+EFI_STATUS
+HardwareInfoPciHostBridgeGetApertures (
+ IN CONST HOST_BRIDGE_INFO *HostBridge,
+ IN UINTN DataSize,
+ OUT PCI_ROOT_BRIDGE_APERTURE *Io,
+ OUT PCI_ROOT_BRIDGE_APERTURE *Mem,
+ OUT PCI_ROOT_BRIDGE_APERTURE *MemAbove4G,
+ OUT PCI_ROOT_BRIDGE_APERTURE *PMem,
+ OUT PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G,
+ OUT PCI_ROOT_BRIDGE_APERTURE *PcieConfig
+ );
+
+/**
+ Retrieve all flags and attributes of a host bridge describing the
+ resources and capabilities.
+
+ @param[in] HostBridge Host bridge information object
+ @param[in] DataSize Size in bytes of the actually filled
+ data available in the HostBridge object
+ @param[out] Attributes Pointer to the host bridge's attributes
+ @param[out] DmaAbove4G Pointer to the DMA Above 4G flag
+ @param[out] NoExtendedConfigSpace Pointer to the Extended Config Space flag
+ @param[out] CombineMemPMem Pointer to the Combine Mem and PMem flag
+
+ @retval EFI_INVALID_PARAMETER HostBridge object is invalid
+ @retval EFI_INCOMPATIBLE_VERSION HostBridge information belongs to
+ an unsupported version
+ @retval EFI_SUCCESS Operation executed cleanly
+**/
+EFI_STATUS
+HardwareInfoPciHostBridgeGetFlags (
+ IN CONST HOST_BRIDGE_INFO *HostBridge,
+ IN UINTN DataSize,
+ OUT UINT64 *Attributes OPTIONAL,
+ OUT BOOLEAN *DmaAbove4G OPTIONAL,
+ OUT BOOLEAN *NoExtendedConfigSpace OPTIONAL,
+ OUT BOOLEAN *CombineMemPMem OPTIONAL
+ );
+
+/**
+ Getter that parses information from a HOST_BRIDGE_INFO object
+ into smaller chunks of types handled by the PciHostBridgeLib.
+
+ @param[in] HostBridge Host bridge information object
+ @param[in] DataSize Size in bytes of the actually filled
+ data available in the HostBridge object
+ @param[out] BusNrStart Pointer to the Bus Number range start
+ @param[out] BusNrLast Pointer to the Bus Number range end
+ @param[out] Attributes Pointer to the host bridge's attributes
+ @param[out] DmaAbove4G Pointer to the DMA Above 4G flag
+ @param[out] NoExtendedConfigSpace Pointer to the Extended Config Space flag
+ @param[out] CombineMemPMem Pointer to the Combine Mem and PMem flag
+ @param[out] Io Pointer to the PIO aperture object
+ @param[out] Mem Pointer to the 32-bit MMIO aperture object
+ @param[out] MemAbove4G Pointer to the 64-bit MMIO aperture object
+ @param[out] PMem Pointer to the 32-bit prefetchable MMIO
+ aperture object
+ @param[out] PMemAbove4G Pointer to the 64-bit prefetchable MMIO
+ aperture object
+ @param[out] PcieConfig MMIO mapped PCIe config aperture (ECAM)
+
+ @retval EFI_SUCCESS Whole operation succeeded
+ @retval EFI_INVALID_PARAMETER HostBridge object and/or non-optional
+ output parameters are invalid
+ @retval EFI_INCOMPATIBLE_VERSION HostBridge information provided belongs to
+ and unsupported version
+ @retval EFI_WARN_STALE_DATA One or more apertures having valid ranges
+ in the HostBridge info were ignored because
+ the correspnding aperture pointer is NULL
+**/
+EFI_STATUS
+HardwareInfoPciHostBridgeGet (
+ IN CONST HOST_BRIDGE_INFO *HostBridge,
+ IN UINTN DataSize,
+ OUT UINTN *BusNrStart,
+ OUT UINTN *BusNrLast,
+ OUT UINT64 *Attributes OPTIONAL,
+ OUT BOOLEAN *DmaAbove4G OPTIONAL,
+ OUT BOOLEAN *NoExtendedConfigSpace OPTIONAL,
+ OUT BOOLEAN *CombineMemPMem OPTIONAL,
+ OUT PCI_ROOT_BRIDGE_APERTURE *Io OPTIONAL,
+ OUT PCI_ROOT_BRIDGE_APERTURE *Mem OPTIONAL,
+ OUT PCI_ROOT_BRIDGE_APERTURE *MemAbove4G OPTIONAL,
+ OUT PCI_ROOT_BRIDGE_APERTURE *PMem OPTIONAL,
+ OUT PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G OPTIONAL,
+ OUT PCI_ROOT_BRIDGE_APERTURE *PcieConfig OPTIONAL
+ );
+
+#endif // __HARDWARE_INFO_PCI_HOST_BRIDGE_LIB_H__
diff --git a/OvmfPkg/Library/HardwareInfoLib/HardwareInfoTypesLib.h b/OvmfPkg/Library/HardwareInfoLib/HardwareInfoTypesLib.h
new file mode 100644
index 0000000000..8508e42509
--- /dev/null
+++ b/OvmfPkg/Library/HardwareInfoLib/HardwareInfoTypesLib.h
@@ -0,0 +1,59 @@
+/**@file
+ Hardware info types' definitions.
+ General hardware info types to parse the binary data
+
+ Copyright 2021 - 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __HARDWARE_INFO_TYPES_LIB_H__
+#define __HARDWARE_INFO_TYPES_LIB_H__
+
+// Specific hardware types:
+#include "HardwareInfoPciHostBridgeLib.h"
+
+//
+// Hardware info types enumeration listing the supported
+// types which have an associated type definition
+//
+typedef enum {
+ HardwareInfoTypeUndefined = 0,
+ HardwareInfoTypeHostBridge = 1,
+
+ HardwareInfoTypeMax
+} HARDWARE_INFO_TYPE;
+
+//
+// Header format preceding and describing an associated hardware
+// info element
+//
+#pragma pack(1)
+typedef struct {
+ union {
+ UINT64 Uint64;
+ HARDWARE_INFO_TYPE Value;
+ } Type;
+ UINT64 Size;
+} HARDWARE_INFO_HEADER;
+#pragma pack()
+
+//
+// Generic data structure to access any supported hardware type
+// resource definition
+//
+#pragma pack(1)
+typedef struct {
+ LIST_ENTRY Link;
+ HARDWARE_INFO_HEADER Header;
+ union {
+ UINT8 *Raw;
+ HOST_BRIDGE_INFO *PciHostBridge;
+ } Data;
+} HARDWARE_INFO;
+#pragma pack()
+
+#define HARDWARE_INFO_FROM_LINK(a) \
+ BASE_CR (a, HARDWARE_INFO, Link)
+
+#endif // __HARDWARE_INFO_TYPES_LIB_H__
--
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
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v6 2/5] Ovmf/HardwareInfoLib: Create Pei lib to parse directly from fw-cfg
2022-06-21 21:27 [PATCH v6 0/5] Handling of multiple PCI Ojeda Leon, Nicolas
2022-06-21 21:31 ` [PATCH v6 1/5] OvmfPkg/Library: Create base HardwareInfoLib for PCI Host Bridges Ojeda Leon, Nicolas
@ 2022-06-21 21:34 ` Ojeda Leon, Nicolas
2022-06-21 21:37 ` [PATCH v6 3/5] Ovmf/HardwareInfoLib: Add Dxe lib to dynamically parse heterogenous data Ojeda Leon, Nicolas
` (3 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Ojeda Leon, Nicolas @ 2022-06-21 21:34 UTC (permalink / raw)
To: devel
Cc: ardb+tianocore, quic_llindhol, sami.mujawar, jiewen.yao,
jordan.l.justen, brijesh.singh, erdemaktas, jejb, min.m.xu,
thomas.lendacky, rebecca, grehan, sebastien.boeuf, anthony.perard,
julien, Nicolas Ojeda Leon, Alexander Graf, Gerd Hoffmann
Define the HardwareInfoLib API and create the PeiHardwareInfoLib
which implements it, specifically for Pei usage, supporting
only static accesses to parse data directly from a fw-cfg file.
All list-like APIs are implemented as unsupported and only a
fw-cfg wrapper to read hardware info elements is provided.
The Hardware Info library is intended to describe non-discoverable
hardware information and share that from the host to the guest in Ovmf
platforms. The QEMU fw-cfg extension for this library provides a first
variation to parse hardware info by reading it directly from a fw-cfg
file. This library offers a wrapper function to the plain
QmeuFwCfgReadBytes which, specifically, parses header-data pairs out
of the binary values in the file. For this purpose, the approach is
incremental, reading the file block by block and outputting the values
only for a specific known hardware type (e.g. PCI host bridges). One
element is returned in each call until the end of the file is reached.
Considering fw-cfg as the first means to transport hardware info from
the host to the guest, this wrapping library offers the possibility
to statically, and in steps, read a specific type of hardware info
elements out of the file. This method reads one hardware element of a
specific type at a time, without the need to pre-allocate memory and
read the whole file or dynamically allocate memory for each new
element found.
As a usage example, the static approach followed by this library
enables early UEFI stages to use and read hardware information
supplied by the host. For instance, in early times of the PEI stage,
hardware information can be parsed out from a fw-cfg file prescinding
from memory services, that may not yet be available, and avoiding
dynamic memory allocations.
Cc: Alexander Graf <graf@amazon.de>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Nicolas Ojeda Leon <ncoleon@amazon.com>
---
Notes:
v6:
Preparation for merge:
- Updated files' copyright to follow EDK2 format
- Explicitly cast header size to UINTN when reading hardware information
from a fw-cfg file.
- Before casting verify validity of values to avoid overflows as well as
check ReadIndex is inside bounds.
- Add HardwareInfoLib library class definition of to OvmfPkg.dec
- Include PeiHardwareInfoLib as part of library classes needed by several
platforms which indirectly depend on it (fix CI build for all platforms).
---
ArmVirtPkg/ArmVirtQemu.dsc | 1 +
OvmfPkg/AmdSev/AmdSevX64.dsc | 1 +
OvmfPkg/Bhyve/BhyveX64.dsc | 1 +
OvmfPkg/CloudHv/CloudHvX64.dsc | 1 +
OvmfPkg/Include/Library/HardwareInfoLib.h | 159 ++++++++++++++++++
.../Library/HardwareInfoLib/HardwareInfoPei.c | 79 +++++++++
.../HardwareInfoLib/PeiHardwareInfoLib.inf | 39 +++++
.../QemuFwCfgHardwareInfoLib.c | 88 ++++++++++
OvmfPkg/Microvm/MicrovmX64.dsc | 1 +
OvmfPkg/OvmfPkg.dec | 4 +
OvmfPkg/OvmfPkgIa32.dsc | 1 +
OvmfPkg/OvmfPkgIa32X64.dsc | 1 +
OvmfPkg/OvmfPkgX64.dsc | 1 +
OvmfPkg/OvmfXen.dsc | 1 +
14 files changed, 378 insertions(+)
create mode 100644 OvmfPkg/Include/Library/HardwareInfoLib.h
create mode 100644 OvmfPkg/Library/HardwareInfoLib/HardwareInfoPei.c
create mode 100644 OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf
create mode 100644 OvmfPkg/Library/HardwareInfoLib/QemuFwCfgHardwareInfoLib.c
diff --git a/ArmVirtPkg/ArmVirtQemu.dsc b/ArmVirtPkg/ArmVirtQemu.dsc
index aa0ce61630..9369a88858 100644
--- a/ArmVirtPkg/ArmVirtQemu.dsc
+++ b/ArmVirtPkg/ArmVirtQemu.dsc
@@ -81,6 +81,7 @@
PciSegmentLib|MdePkg/Library/BasePciSegmentLibPci/BasePciSegmentLibPci.inf
PciHostBridgeLib|OvmfPkg/Fdt/FdtPciHostBridgeLib/FdtPciHostBridgeLib.inf
PciHostBridgeUtilityLib|OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.inf
+ PeiHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf
!if $(TPM2_ENABLE) == TRUE
Tpm2CommandLib|SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.inf
diff --git a/OvmfPkg/AmdSev/AmdSevX64.dsc b/OvmfPkg/AmdSev/AmdSevX64.dsc
index 6b3827f7f6..72cbf710df 100644
--- a/OvmfPkg/AmdSev/AmdSevX64.dsc
+++ b/OvmfPkg/AmdSev/AmdSevX64.dsc
@@ -168,6 +168,7 @@
FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
BlobVerifierLib|OvmfPkg/AmdSev/BlobVerifierLibSevHashes/BlobVerifierLibSevHashes.inf
MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
+ PeiHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf
!if $(SOURCE_DEBUG_ENABLE) == TRUE
PeCoffExtraActionLib|SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf
diff --git a/OvmfPkg/Bhyve/BhyveX64.dsc b/OvmfPkg/Bhyve/BhyveX64.dsc
index f0166e136c..ada904464e 100644
--- a/OvmfPkg/Bhyve/BhyveX64.dsc
+++ b/OvmfPkg/Bhyve/BhyveX64.dsc
@@ -170,6 +170,7 @@
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf
LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
+ PeiHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf
CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
diff --git a/OvmfPkg/CloudHv/CloudHvX64.dsc b/OvmfPkg/CloudHv/CloudHvX64.dsc
index 8a111444f8..89d856e488 100644
--- a/OvmfPkg/CloudHv/CloudHvX64.dsc
+++ b/OvmfPkg/CloudHv/CloudHvX64.dsc
@@ -180,6 +180,7 @@
VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf
LoadLinuxLib|OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf
+ PeiHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf
!if $(SMM_REQUIRE) == FALSE
LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
!endif
diff --git a/OvmfPkg/Include/Library/HardwareInfoLib.h b/OvmfPkg/Include/Library/HardwareInfoLib.h
new file mode 100644
index 0000000000..66d964dab5
--- /dev/null
+++ b/OvmfPkg/Include/Library/HardwareInfoLib.h
@@ -0,0 +1,159 @@
+/*/@file
+ Hardware info parsing functions.
+ Binary data is expected as a consecutive series of header - object pairs.
+ Complete library providing static Qemu fw-cfg wrappers as well as list-like
+ interface to dynamically manipulate hardware info objects and parsing from
+ a generic blob.
+
+ Copyright 2021 - 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __HARDWARE_INFO_LIB_H__
+#define __HARDWARE_INFO_LIB_H__
+
+#include "../Library/HardwareInfoLib/HardwareInfoTypesLib.h"
+
+/**
+ Read, if available, the next Type element in the FwCfg file.
+ The FwCfg item must already be selected, this is a wrapper around
+ QemuFwCfgReadBytes and the Data pointer should be set to an existent
+ memory location with TypeSize bytes allocated for the date to be
+ properly written. If a Type element is found in the file which has a
+ size (in the header) greater than TypeSize, it is skipped.
+
+ @param[in] Type Hardware Info Type to search for
+ @param[in] TypeSize Size (in bytes) of the structure intended to
+ be used to dereference the data
+ @param[in] TotalFileSize Total size (in bytes) of the FwCfg file from
+ which the data is read.
+ @param[out] Data Pointer to a memory allocated instance into
+ which the data is written to.
+ @param[out] DataSize Size in bytes of the actually filled
+ data available in the Data object after a
+ successful operation
+ @param[inout] ReadIndex Index of the next byte to be read. Incremented
+ accordingly after a read operation to reflect
+ up to date status
+
+ @retval EFI_SUCCESS Next element found and read into Data
+ @retval EFI_INVALID_PARAMETER Operation failed
+ @retval EFI_END_OF_FILE End of the file reached, no more elements
+ to read.
+**/
+EFI_STATUS
+QemuFwCfgReadNextHardwareInfoByType (
+ IN HARDWARE_INFO_TYPE Type,
+ IN UINTN TypeSize,
+ IN UINTN TotalFileSize,
+ OUT VOID *Data,
+ OUT UINTN *DataSize OPTIONAL,
+ IN OUT UINTN *ReadIndex
+ );
+
+/**
+ Parse binary data containing resource information of multiple hardware
+ elements into a list of interpreted resources.
+ The translation is done on a copy-parse base so the blob can be freed
+ afterwards.
+
+ @param[in] Blob Binary data to be parsed
+ @param[in] BlobSize Size (in bytes) of the binary data
+ @param[in] TypeFilter Optional type to filter entries. Set to
+ undefined to disable filtering and retrieve all
+ @param[out] ListHead Head of the list to populate hardware information
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_INVALID_PARAMETER Provided Blob inforation is invalid
+ @retval EFI_OUT_OF_RESOURCES Out of memory, list populated as far as
+ possible
+**/
+EFI_STATUS
+CreateHardwareInfoList (
+ IN UINT8 *Blob,
+ IN UINTN BlobSize,
+ IN HARDWARE_INFO_TYPE TypeFilter,
+ OUT LIST_ENTRY *ListHead
+ );
+
+/**
+ Free the dynamically allocated list of HADWARE_INFO items populated
+ during parsing of Blob
+
+ @param ListHead Head of the list to be destroyed
+**/
+VOID
+FreeHardwareInfoList (
+ IN OUT LIST_ENTRY *ListHead
+ );
+
+/**
+ Retrieve the number of hardware components of a specific type
+ in the list.
+
+ @param[in] ListHead Head of the hardware info list
+ @param[in] Type Type of hardware elements to count
+ @param[in] TypeSize Size (in bytes) of the structure intended to
+ be used to dereference the data
+ @return Count of elements of Type found
+**/
+UINTN
+GetHardwareInfoCountByType (
+ IN LIST_ENTRY *ListHead,
+ IN HARDWARE_INFO_TYPE Type,
+ IN UINTN TypeSize
+ );
+
+/**
+ Get the First Hardware Info entry in the list of the specified type
+
+ @param[in] ListHead Head of the hardware info list
+ @param[in] Type Hardware Info Type to search for
+ @param[in] TypeSize Size (in bytes) of the structure intended to
+ be used to dereference the data
+ @return Link of first entry of specified type or list head if not found
+**/
+LIST_ENTRY *
+GetFirstHardwareInfoByType (
+ IN LIST_ENTRY *ListHead,
+ IN HARDWARE_INFO_TYPE Type,
+ IN UINTN TypeSize
+ );
+
+/**
+ Get the Next Hardware Info entry in the list with the specified
+ type, which follows the provided Node.
+
+ @param[in] ListHead Head of the hardware info list
+ @param[in] Node Current, already processed, node's link
+ @param[in] Type Hardware Info Type to search for
+ @param[in] TypeSize Size (in bytes) of the structure intended to
+ be used to dereference the data
+ @return Link of next entry, after Node, of the specified type.
+ List head otherwise
+**/
+LIST_ENTRY *
+GetNextHardwareInfoByType (
+ IN LIST_ENTRY *ListHead,
+ IN LIST_ENTRY *Node,
+ IN HARDWARE_INFO_TYPE Type,
+ IN UINTN TypeSize
+ );
+
+/**
+ Assess if Node stands at the end of the doubly linked list
+
+ @param[in] ListHead Head of the hardware info list
+ @param[in] Node Current Node link
+
+ @retval TRUE Node is at the end of the list
+ @retval FALSE Node is not at the end of the list
+**/
+BOOLEAN
+EndOfHardwareInfoList (
+ IN LIST_ENTRY *ListHead,
+ IN LIST_ENTRY *Node
+ );
+
+#endif // __HARDWARE_INFO_LIB_H__
diff --git a/OvmfPkg/Library/HardwareInfoLib/HardwareInfoPei.c b/OvmfPkg/Library/HardwareInfoLib/HardwareInfoPei.c
new file mode 100644
index 0000000000..beb10ba896
--- /dev/null
+++ b/OvmfPkg/Library/HardwareInfoLib/HardwareInfoPei.c
@@ -0,0 +1,79 @@
+/*/@file
+ Hardware info parsing functions.
+ Binary data is expected as a consecutive series of header - object pairs.
+ Provides static Qemu fw-cfg wrappers as well as list-like interface to
+ dynamically manipulate hardware info objects and parsing from a generic
+ blob.
+
+ Copyright 2021 - 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/DebugLib.h>
+
+#include <Library/HardwareInfoLib.h>
+
+EFI_STATUS
+CreateHardwareInfoList (
+ IN UINT8 *Blob,
+ IN UINTN BlobSize,
+ IN HARDWARE_INFO_TYPE TypeFilter,
+ OUT LIST_ENTRY *ListHead
+ )
+{
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+}
+
+VOID
+FreeHardwareInfoList (
+ IN OUT LIST_ENTRY *ListHead
+ )
+{
+ ASSERT (FALSE);
+}
+
+UINTN
+GetHardwareInfoCountByType (
+ IN LIST_ENTRY *ListHead,
+ IN HARDWARE_INFO_TYPE Type,
+ IN UINTN TypeSize
+ )
+{
+ ASSERT (FALSE);
+ return 0;
+}
+
+LIST_ENTRY *
+GetFirstHardwareInfoByType (
+ IN LIST_ENTRY *ListHead,
+ IN HARDWARE_INFO_TYPE Type,
+ IN UINTN TypeSize
+ )
+{
+ ASSERT (FALSE);
+ return ListHead;
+}
+
+LIST_ENTRY *
+GetNextHardwareInfoByType (
+ IN LIST_ENTRY *ListHead,
+ IN LIST_ENTRY *Node,
+ IN HARDWARE_INFO_TYPE Type,
+ IN UINTN TypeSize
+ )
+{
+ ASSERT (FALSE);
+ return ListHead;
+}
+
+BOOLEAN
+EndOfHardwareInfoList (
+ IN LIST_ENTRY *ListHead,
+ IN LIST_ENTRY *Node
+ )
+{
+ ASSERT (FALSE);
+ return TRUE;
+}
diff --git a/OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf b/OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf
new file mode 100644
index 0000000000..00b79bc8d6
--- /dev/null
+++ b/OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf
@@ -0,0 +1,39 @@
+## @file
+# Hardware information library wrappers over Qemu fw-cfg functionality to parse,
+# in a static manner, non-discoverable hardware information.
+#
+# Copyright 2021 - 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiHardwareInfoLib
+ FILE_GUID = 3D5011B3-9CBB-4C0B-88E8-1D758283C659
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PeiHardwareInfoLib
+
+#
+# The following information is for reference only and not required by the build
+# tools.
+#
+# VALID_ARCHITECTURES = X64
+#
+
+[Sources]
+ HardwareInfoPei.c
+ QemuFwCfgHardwareInfoLib.c
+ HardwareInfoPciHostBridgeLib.c
+
+[Packages]
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+ DebugLib
+ QemuFwCfgLib
diff --git a/OvmfPkg/Library/HardwareInfoLib/QemuFwCfgHardwareInfoLib.c b/OvmfPkg/Library/HardwareInfoLib/QemuFwCfgHardwareInfoLib.c
new file mode 100644
index 0000000000..48d9dcd8ad
--- /dev/null
+++ b/OvmfPkg/Library/HardwareInfoLib/QemuFwCfgHardwareInfoLib.c
@@ -0,0 +1,88 @@
+/*/@file
+ Qemu fw-cfg wrappers for hardware info parsing.
+ Provides an alternative to parse hardware information from a fw-cfg
+ file without relying on dynamic memory allocations.
+
+ Copyright 2021 - 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/DebugLib.h>
+#include <Library/QemuFwCfgLib.h>
+
+#include <Library/HardwareInfoLib.h>
+
+/**
+ Update an optional pointer value if possible
+
+ @param[out] DataSize Pointer to variable to be updated
+ @param[in] Value Value to set the pointed variable to.
+**/
+STATIC
+VOID
+UpdateDataSize (
+ OUT UINTN *DataSize,
+ IN UINTN Value
+ )
+{
+ if (DataSize == NULL) {
+ return;
+ }
+
+ *DataSize = Value;
+}
+
+EFI_STATUS
+QemuFwCfgReadNextHardwareInfoByType (
+ IN HARDWARE_INFO_TYPE Type,
+ IN UINTN TypeSize,
+ IN UINTN TotalFileSize,
+ OUT VOID *Data,
+ OUT UINTN *DataSize OPTIONAL,
+ IN OUT UINTN *ReadIndex
+ )
+{
+ HARDWARE_INFO_HEADER Header;
+
+ if ((Data == NULL) ||
+ (ReadIndex == NULL) ||
+ (TypeSize == 0) ||
+ (Type == HardwareInfoTypeUndefined) ||
+ (TotalFileSize == 0))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UpdateDataSize (DataSize, 0);
+
+ while (*ReadIndex < TotalFileSize) {
+ QemuFwCfgReadBytes (sizeof (Header), &Header);
+ *ReadIndex += sizeof (Header);
+
+ if ((Header.Size > MAX_UINTN) || (((UINT64)*ReadIndex + Header.Size) > TotalFileSize)) {
+ *ReadIndex = TotalFileSize;
+ return EFI_ABORTED;
+ }
+
+ if ((Header.Type.Value == Type) && (Header.Size <= TypeSize)) {
+ QemuFwCfgReadBytes ((UINTN)Header.Size, Data);
+
+ *ReadIndex += (UINTN)Header.Size;
+ UpdateDataSize (DataSize, (UINTN)Header.Size);
+
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Skip the bytes corresponding to the next element as it is
+ // not of the expected type and/or size. The TotalFileSize
+ // and individual elements sizes should match so the size
+ // check is skipped.
+ //
+ QemuFwCfgSkipBytes ((UINTN)Header.Size);
+ *ReadIndex += (UINTN)Header.Size;
+ }
+
+ return EFI_END_OF_FILE;
+}
diff --git a/OvmfPkg/Microvm/MicrovmX64.dsc b/OvmfPkg/Microvm/MicrovmX64.dsc
index 5b150a959c..38dd708477 100644
--- a/OvmfPkg/Microvm/MicrovmX64.dsc
+++ b/OvmfPkg/Microvm/MicrovmX64.dsc
@@ -183,6 +183,7 @@
CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
+ PeiHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf
!if $(SOURCE_DEBUG_ENABLE) == TRUE
PeCoffExtraActionLib|SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 7b114a5e63..5af76a5405 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -125,6 +125,10 @@
#
PeilessStartupLib|Include/Library/PeilessStartupLib.h
+ ## @libraryclass HardwareInfoLib
+ #
+ HardwareInfoLib|Include/Library/HardwareInfoLib.h
+
[Guids]
gUefiOvmfPkgTokenSpaceGuid = {0x93bb96af, 0xb9f2, 0x4eb8, {0x94, 0x62, 0xe0, 0xba, 0x74, 0x56, 0x42, 0x36}}
gEfiXenInfoGuid = {0xd3b46f3b, 0xd441, 0x1244, {0x9a, 0x12, 0x0, 0x12, 0x27, 0x3f, 0xc1, 0x4d}}
diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index a9841cbfc3..8bffcf0bca 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -178,6 +178,7 @@
LoadLinuxLib|OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf
MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLibNull.inf
+ PeiHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf
!if $(SMM_REQUIRE) == FALSE
LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
!endif
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index f7949780fa..7732b95bfa 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -182,6 +182,7 @@
LoadLinuxLib|OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf
MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLibNull.inf
+ PeiHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf
!if $(SMM_REQUIRE) == FALSE
LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
!endif
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 1448f925b7..459c6fbde1 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -194,6 +194,7 @@
LoadLinuxLib|OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf
MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
+ PeiHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf
!if $(SMM_REQUIRE) == FALSE
LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
diff --git a/OvmfPkg/OvmfXen.dsc b/OvmfPkg/OvmfXen.dsc
index 6ba4bd729a..03922b5c16 100644
--- a/OvmfPkg/OvmfXen.dsc
+++ b/OvmfPkg/OvmfXen.dsc
@@ -172,6 +172,7 @@
CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
+ PeiHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf
!if $(SOURCE_DEBUG_ENABLE) == TRUE
PeCoffExtraActionLib|SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf
--
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
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v6 3/5] Ovmf/HardwareInfoLib: Add Dxe lib to dynamically parse heterogenous data
2022-06-21 21:27 [PATCH v6 0/5] Handling of multiple PCI Ojeda Leon, Nicolas
2022-06-21 21:31 ` [PATCH v6 1/5] OvmfPkg/Library: Create base HardwareInfoLib for PCI Host Bridges Ojeda Leon, Nicolas
2022-06-21 21:34 ` [PATCH v6 2/5] Ovmf/HardwareInfoLib: Create Pei lib to parse directly from fw-cfg Ojeda Leon, Nicolas
@ 2022-06-21 21:37 ` Ojeda Leon, Nicolas
2022-06-21 21:38 ` [PATCH v6 4/5] Ovmf/PlatformPei: Use host-provided GPA end if available Ojeda Leon, Nicolas
` (2 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Ojeda Leon, Nicolas @ 2022-06-21 21:37 UTC (permalink / raw)
To: devel
Cc: ardb+tianocore, quic_llindhol, sami.mujawar, jiewen.yao,
jordan.l.justen, brijesh.singh, erdemaktas, jejb, min.m.xu,
thomas.lendacky, rebecca, grehan, sebastien.boeuf, anthony.perard,
julien, Nicolas Ojeda Leon, Alexander Graf, Gerd Hoffmann
Following the Hardware Info library, create the DxeHardwareInfoLib
which implements the whole API capable of parsing heterogeneous hardware
information. The list-like API grants callers a flexible and common
pattern to retrieve the data. Moreover, the initial source is a BLOB
which generalizes the host-to-guest transmission mechanism.
The Hardware Info library main objective is to provide a way to
describe non-discoverable hardware so that the host can share the
available resources with the guest in Ovmf platforms. This change
features and embraces the main idea behind the library by providing
an API that parses a BLOB into a linked list to retrieve hardware
data from any source. Additionally, list-like APIs are provided so
that the hardware info list can be traversed conveniently.
Similarly, the capability is provided to filter results by specific
hardware types. However, heterogeneous elements can be added to the
list, increasing the flexibility. This way, a single source, for
example a fw-cfg file, can be used to describe several instances of
multiple types of hardware.
This part of the Hardware Info library makes use of dynamic memory
and is intended for stages in which memory services are available.
A motivation example is the PciHostBridgeLib. This library, part
of the PCI driver populates the list of PCI root bridges during DXE
stage for future steps to discover the resources under them. The
hardware info library can be used to obtain the detailed description
of available host bridges, for instance in the form of a fw-cfg file,
and parse that information into a dynmaic list that allows, first to
verify consistency of the data, and second discover the resources
availabe for each root bridge.
Cc: Alexander Graf <graf@amazon.de>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Nicolas Ojeda Leon <ncoleon@amazon.com>
---
Notes:
v6:
Preparation for merge:
- Updated files' copyright to follow EDK2 format
- Explicitly cast header size to UINTN when creating hardware info list
from a blob acquired received from host.
- Before casting verify validity of values to avoid overflows as well as
check ReadIndex is inside blob boundaries.
- Include DxeHardwareInfoLib as part of library classes needed by several
platforms which indirectly depend on it (fix CI build for all platforms).
---
ArmVirtPkg/ArmVirtQemu.dsc | 1 +
OvmfPkg/AmdSev/AmdSevX64.dsc | 1 +
OvmfPkg/Bhyve/BhyveX64.dsc | 1 +
OvmfPkg/CloudHv/CloudHvX64.dsc | 1 +
.../HardwareInfoLib/DxeHardwareInfoLib.inf | 39 +++
.../Library/HardwareInfoLib/HardwareInfoDxe.c | 254 ++++++++++++++++++
OvmfPkg/Microvm/MicrovmX64.dsc | 1 +
OvmfPkg/OvmfPkgIa32.dsc | 1 +
OvmfPkg/OvmfPkgIa32X64.dsc | 1 +
OvmfPkg/OvmfPkgX64.dsc | 1 +
OvmfPkg/OvmfXen.dsc | 1 +
11 files changed, 302 insertions(+)
create mode 100644 OvmfPkg/Library/HardwareInfoLib/DxeHardwareInfoLib.inf
create mode 100644 OvmfPkg/Library/HardwareInfoLib/HardwareInfoDxe.c
diff --git a/ArmVirtPkg/ArmVirtQemu.dsc b/ArmVirtPkg/ArmVirtQemu.dsc
index 9369a88858..56eb53911d 100644
--- a/ArmVirtPkg/ArmVirtQemu.dsc
+++ b/ArmVirtPkg/ArmVirtQemu.dsc
@@ -82,6 +82,7 @@
PciHostBridgeLib|OvmfPkg/Fdt/FdtPciHostBridgeLib/FdtPciHostBridgeLib.inf
PciHostBridgeUtilityLib|OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.inf
PeiHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf
+ DxeHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/DxeHardwareInfoLib.inf
!if $(TPM2_ENABLE) == TRUE
Tpm2CommandLib|SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.inf
diff --git a/OvmfPkg/AmdSev/AmdSevX64.dsc b/OvmfPkg/AmdSev/AmdSevX64.dsc
index 72cbf710df..b265697704 100644
--- a/OvmfPkg/AmdSev/AmdSevX64.dsc
+++ b/OvmfPkg/AmdSev/AmdSevX64.dsc
@@ -169,6 +169,7 @@
BlobVerifierLib|OvmfPkg/AmdSev/BlobVerifierLibSevHashes/BlobVerifierLibSevHashes.inf
MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
PeiHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf
+ DxeHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/DxeHardwareInfoLib.inf
!if $(SOURCE_DEBUG_ENABLE) == TRUE
PeCoffExtraActionLib|SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf
diff --git a/OvmfPkg/Bhyve/BhyveX64.dsc b/OvmfPkg/Bhyve/BhyveX64.dsc
index ada904464e..ec8ad98db7 100644
--- a/OvmfPkg/Bhyve/BhyveX64.dsc
+++ b/OvmfPkg/Bhyve/BhyveX64.dsc
@@ -171,6 +171,7 @@
LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
PeiHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf
+ DxeHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/DxeHardwareInfoLib.inf
CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
diff --git a/OvmfPkg/CloudHv/CloudHvX64.dsc b/OvmfPkg/CloudHv/CloudHvX64.dsc
index 89d856e488..294a625ea8 100644
--- a/OvmfPkg/CloudHv/CloudHvX64.dsc
+++ b/OvmfPkg/CloudHv/CloudHvX64.dsc
@@ -181,6 +181,7 @@
LoadLinuxLib|OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf
PeiHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf
+ DxeHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/DxeHardwareInfoLib.inf
!if $(SMM_REQUIRE) == FALSE
LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
!endif
diff --git a/OvmfPkg/Library/HardwareInfoLib/DxeHardwareInfoLib.inf b/OvmfPkg/Library/HardwareInfoLib/DxeHardwareInfoLib.inf
new file mode 100644
index 0000000000..a2f056e117
--- /dev/null
+++ b/OvmfPkg/Library/HardwareInfoLib/DxeHardwareInfoLib.inf
@@ -0,0 +1,39 @@
+## @file
+# Hardware information library to describe non-discoverable hardware resources
+#
+# Copyright 2021 - 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeHardwareInfoLib
+ FILE_GUID = F60B206A-5C56-11EC-AEAC-67CB080BCFF2
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = DxeHardwareInfoLib
+
+#
+# The following information is for reference only and not required by the build
+# tools.
+#
+# VALID_ARCHITECTURES = X64
+#
+
+[Sources]
+ HardwareInfoDxe.c
+ HardwareInfoPciHostBridgeLib.c
+ QemuFwCfgHardwareInfoLib.c
+
+[Packages]
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
diff --git a/OvmfPkg/Library/HardwareInfoLib/HardwareInfoDxe.c b/OvmfPkg/Library/HardwareInfoLib/HardwareInfoDxe.c
new file mode 100644
index 0000000000..a74de52871
--- /dev/null
+++ b/OvmfPkg/Library/HardwareInfoLib/HardwareInfoDxe.c
@@ -0,0 +1,254 @@
+/*/@file
+ Hardware info parsing functions.
+ Binary data is expected as a consecutive series of header - object pairs.
+ Complete library providing list-like interface to dynamically manipulate
+ hardware info objects and parsing from a generic blob.
+
+ Copyright 2021 - 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi/UefiBaseType.h>
+#include <Uefi/UefiSpec.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+
+#include <Library/HardwareInfoLib.h>
+
+EFI_STATUS
+CreateHardwareInfoList (
+ IN UINT8 *Blob,
+ IN UINTN BlobSize,
+ IN HARDWARE_INFO_TYPE TypeFilter,
+ OUT LIST_ENTRY *ListHead
+ )
+{
+ UINT8 *Index;
+ UINT8 *BlobEnd;
+ HARDWARE_INFO *HwComponent;
+
+ if ((Blob == NULL) || (BlobSize <= 0) ||
+ (ListHead == NULL))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Index = Blob;
+ BlobEnd = Blob + BlobSize;
+ while (Index < BlobEnd) {
+ HwComponent = AllocateZeroPool (sizeof (HARDWARE_INFO));
+
+ if (HwComponent == NULL) {
+ goto FailedAllocate;
+ }
+
+ HwComponent->Header.Type.Uint64 = *((UINT64 *)Index);
+ Index += sizeof (HwComponent->Header.Type);
+ HwComponent->Header.Size = *((UINT64 *)(Index));
+ Index += sizeof (HwComponent->Header.Size);
+
+ if ((HwComponent->Header.Size > MAX_UINTN) || (Index < Blob) || ((Index + HwComponent->Header.Size) > BlobEnd)) {
+ goto FreeResources;
+ }
+
+ //
+ // Check if optional TypeFilter is set, skip if the current
+ // object is of a different type and release the partially
+ // allocated object
+ //
+ if ((TypeFilter != HardwareInfoTypeUndefined) &&
+ (HwComponent->Header.Type.Value != TypeFilter))
+ {
+ FreePool (HwComponent);
+ Index += HwComponent->Header.Size;
+ continue;
+ }
+
+ HwComponent->Data.Raw = AllocateZeroPool ((UINTN)HwComponent->Header.Size);
+ if (HwComponent->Data.Raw == NULL) {
+ goto FreeResources;
+ }
+
+ CopyMem (HwComponent->Data.Raw, Index, (UINTN)HwComponent->Header.Size);
+ Index += HwComponent->Header.Size;
+
+ InsertTailList (ListHead, &HwComponent->Link);
+ }
+
+ return EFI_SUCCESS;
+
+FreeResources:
+ //
+ // Clean the resources allocated in the incomplete cycle
+ //
+ FreePool (HwComponent);
+
+FailedAllocate:
+ DEBUG ((
+ EFI_D_ERROR,
+ "%a: Failed to allocate memory for hardware info\n",
+ __FUNCTION__
+ ));
+
+ return EFI_OUT_OF_RESOURCES;
+}
+
+VOID
+FreeHardwareInfoList (
+ IN OUT LIST_ENTRY *ListHead
+ )
+{
+ LIST_ENTRY *CurrentLink;
+ HARDWARE_INFO *HwComponent;
+
+ if (IsListEmpty (ListHead)) {
+ return;
+ }
+
+ CurrentLink = ListHead->ForwardLink;
+ while (CurrentLink != NULL && CurrentLink != ListHead) {
+ HwComponent = HARDWARE_INFO_FROM_LINK (CurrentLink);
+
+ //
+ // Remove item from list before invalidating the pointers
+ //
+ CurrentLink = RemoveEntryList (CurrentLink);
+
+ FreePool (HwComponent->Data.Raw);
+ FreePool (HwComponent);
+ }
+}
+
+/**
+ Validates if the specified Node has a valid data size and is of
+ specified type.
+ The data size can be less or equal to the provided type size to be
+ regarded as valid and thus accessible with the typed pointer.
+
+ For future compatibility the size is allowed to be smaller so that
+ different versions interpret fields differently and, particularly,
+ have smaller data structures. However, it cannot be larger than the
+ type size to avoid accessing memory out of bounds.
+
+ @param[in] Node Hardware Info node to be validated
+ @param[in] TypeSize Size (in bytes) of the data type intended to be
+ used to dereference the data.
+ @retval TRUE Node is valid and can be accessed
+ @retval FALSE Node is not valid
+/*/
+STATIC
+BOOLEAN
+IsHardwareInfoNodeValidByType (
+ IN LIST_ENTRY *ListHead,
+ IN LIST_ENTRY *Link,
+ IN HARDWARE_INFO_TYPE Type,
+ IN UINTN TypeSize
+ )
+{
+ HARDWARE_INFO *HwComponent;
+
+ if (IsNull (ListHead, Link)) {
+ return FALSE;
+ }
+
+ HwComponent = HARDWARE_INFO_FROM_LINK (Link);
+
+ //
+ // Verify if the node type is the specified one and the size of
+ // the data allocated to the node is greater than the size of
+ // the type intended to dereference it in order to avoid access
+ // to memory out of bondaries.
+ //
+ if ((HwComponent->Header.Type.Value == Type) &&
+ (HwComponent->Header.Size >= TypeSize))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+UINTN
+GetHardwareInfoCountByType (
+ IN LIST_ENTRY *ListHead,
+ IN HARDWARE_INFO_TYPE Type,
+ IN UINTN TypeSize
+ )
+{
+ UINTN Count;
+ LIST_ENTRY *Link;
+
+ Count = 0;
+ for (Link = GetFirstHardwareInfoByType (ListHead, Type, TypeSize);
+ !IsNull (ListHead, Link);
+ Link = GetNextHardwareInfoByType (ListHead, Link, Type, TypeSize))
+ {
+ if (IsHardwareInfoNodeValidByType (ListHead, Link, Type, TypeSize)) {
+ Count++;
+ }
+ }
+
+ return Count;
+}
+
+LIST_ENTRY *
+GetFirstHardwareInfoByType (
+ IN LIST_ENTRY *ListHead,
+ IN HARDWARE_INFO_TYPE Type,
+ IN UINTN TypeSize
+ )
+{
+ LIST_ENTRY *Link;
+
+ if (IsListEmpty (ListHead)) {
+ return ListHead;
+ }
+
+ Link = GetFirstNode (ListHead);
+
+ if (IsHardwareInfoNodeValidByType (ListHead, Link, Type, TypeSize)) {
+ return Link;
+ }
+
+ return GetNextHardwareInfoByType (ListHead, Link, Type, TypeSize);
+}
+
+LIST_ENTRY *
+GetNextHardwareInfoByType (
+ IN LIST_ENTRY *ListHead,
+ IN LIST_ENTRY *Node,
+ IN HARDWARE_INFO_TYPE Type,
+ IN UINTN TypeSize
+ )
+{
+ LIST_ENTRY *Link;
+
+ Link = GetNextNode (ListHead, Node);
+
+ while (!IsNull (ListHead, Link)) {
+ if (IsHardwareInfoNodeValidByType (ListHead, Link, Type, TypeSize)) {
+ //
+ // Found a node of specified type and with valid size. Break and
+ // return the found node.
+ //
+ break;
+ }
+
+ Link = GetNextNode (ListHead, Link);
+ }
+
+ return Link;
+}
+
+BOOLEAN
+EndOfHardwareInfoList (
+ IN LIST_ENTRY *ListHead,
+ IN LIST_ENTRY *Node
+ )
+{
+ return IsNull (ListHead, Node);
+}
diff --git a/OvmfPkg/Microvm/MicrovmX64.dsc b/OvmfPkg/Microvm/MicrovmX64.dsc
index 38dd708477..61db9b6e4c 100644
--- a/OvmfPkg/Microvm/MicrovmX64.dsc
+++ b/OvmfPkg/Microvm/MicrovmX64.dsc
@@ -184,6 +184,7 @@
FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
PeiHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf
+ DxeHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/DxeHardwareInfoLib.inf
!if $(SOURCE_DEBUG_ENABLE) == TRUE
PeCoffExtraActionLib|SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf
diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index 8bffcf0bca..b611bb6de1 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -179,6 +179,7 @@
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf
MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLibNull.inf
PeiHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf
+ DxeHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/DxeHardwareInfoLib.inf
!if $(SMM_REQUIRE) == FALSE
LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
!endif
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index 7732b95bfa..e3bfe4324d 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -183,6 +183,7 @@
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf
MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLibNull.inf
PeiHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf
+ DxeHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/DxeHardwareInfoLib.inf
!if $(SMM_REQUIRE) == FALSE
LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
!endif
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 459c6fbde1..ba09b6c72f 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -195,6 +195,7 @@
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf
MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
PeiHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf
+ DxeHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/DxeHardwareInfoLib.inf
!if $(SMM_REQUIRE) == FALSE
LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
diff --git a/OvmfPkg/OvmfXen.dsc b/OvmfPkg/OvmfXen.dsc
index 03922b5c16..58a7c97cdd 100644
--- a/OvmfPkg/OvmfXen.dsc
+++ b/OvmfPkg/OvmfXen.dsc
@@ -173,6 +173,7 @@
FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
PeiHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf
+ DxeHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/DxeHardwareInfoLib.inf
!if $(SOURCE_DEBUG_ENABLE) == TRUE
PeCoffExtraActionLib|SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf
--
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
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v6 4/5] Ovmf/PlatformPei: Use host-provided GPA end if available
2022-06-21 21:27 [PATCH v6 0/5] Handling of multiple PCI Ojeda Leon, Nicolas
` (2 preceding siblings ...)
2022-06-21 21:37 ` [PATCH v6 3/5] Ovmf/HardwareInfoLib: Add Dxe lib to dynamically parse heterogenous data Ojeda Leon, Nicolas
@ 2022-06-21 21:38 ` Ojeda Leon, Nicolas
2022-06-21 21:40 ` [PATCH v6 5/5] OvmfPkg/PciHostBridgeUtilityLib: Initialize RootBridges apertures with spec Ojeda Leon, Nicolas
2022-06-22 15:35 ` [PATCH v6 0/5] Handling of multiple PCI Ard Biesheuvel
5 siblings, 0 replies; 9+ messages in thread
From: Ojeda Leon, Nicolas @ 2022-06-21 21:38 UTC (permalink / raw)
To: devel
Cc: ardb+tianocore, jiewen.yao, jordan.l.justen, Nicolas Ojeda Leon,
Alexander Graf, Gerd Hoffmann
Read the "hardware-info" item from fw-cfg to extract specifications
of PCI host bridges and analyze the 64-bit apertures of them to
find out the highest 64-bit MMIO address required which determines
the address space required by the guest, and, consequently, the
FirstNonAddress used to calculate size of physical addresses.
Using the static PeiHardwareInfoLib, read the fw-cfg file of
hardware information to extract, one by one, all the host
bridges. Find the last 64-bit MMIO address of each host bridge,
using the HardwareInfoPciHostBridgeLib API, and compare it to an
accumulate value to discover the highest address used, which
corresponds to the highest value that must be included in the
guest's physical address space.
Given that platforms with multiple host bridges may provide the PCI
apertures' addresses, the memory detection logic must take into
account that, if the host provided the MMIO windows that can and must
be used, the guest needs to take those values. Therefore, if the
MMIO windows are found in the host-provided fw-cfg file, skip all the
logic calculating the physical address size and just use the value
provided. Since each PCI host bridge corresponds to an element in
the information provided by the host, each of these must be analyzed
looking for the highest address used.
Cc: Alexander Graf <graf@amazon.de>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Nicolas Ojeda Leon <ncoleon@amazon.com>
---
Notes:
v6:
Preparation for merge:
v5:
- Moved all changes from MemDetect.c into recently created
PlatformInitLib/MemDetect.c effectively re-basing this patch
onto latest master
- Adapted function name to use Platform____ convention without
any changes in the logic
---
OvmfPkg/Library/PlatformInitLib/MemDetect.c | 148 +++++++++++++++++-
.../PlatformInitLib/PlatformInitLib.inf | 1 +
2 files changed, 142 insertions(+), 7 deletions(-)
diff --git a/OvmfPkg/Library/PlatformInitLib/MemDetect.c b/OvmfPkg/Library/PlatformInitLib/MemDetect.c
index c28d7601f8..942eaf89cf 100644
--- a/OvmfPkg/Library/PlatformInitLib/MemDetect.c
+++ b/OvmfPkg/Library/PlatformInitLib/MemDetect.c
@@ -27,6 +27,7 @@ Module Name:
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
+#include <Library/HardwareInfoLib.h>
#include <Library/HobLib.h>
#include <Library/IoLib.h>
#include <Library/MemEncryptSevLib.h>
@@ -527,6 +528,126 @@ PlatformAddressWidthFromCpuid (
));
}
+/**
+ Iterate over the PCI host bridges resources information optionally provided
+ in fw-cfg and find the highest address contained in the PCI MMIO windows. If
+ the information is found, return the exclusive end; one past the last usable
+ address.
+
+ @param[out] PciMmioAddressEnd Pointer to one-after End Address updated with
+ information extracted from host-provided data
+ or zero if no information available or an
+ error happened
+
+ @retval EFI_SUCCESS PCI information was read and the output
+ parameter updated with the last valid
+ address in the 64-bit MMIO range.
+ @retval EFI_INVALID_PARAMETER Pointer parameter is invalid
+ @retval EFI_INCOMPATIBLE_VERSION Hardware information found in fw-cfg
+ has an incompatible format
+ @retval EFI_UNSUPPORTED Fw-cfg is not supported, thus host
+ provided information, if any, cannot be
+ read
+ @retval EFI_NOT_FOUND No PCI host bridge information provided
+ by the host.
+**/
+STATIC
+EFI_STATUS
+PlatformScanHostProvided64BitPciMmioEnd (
+ OUT UINT64 *PciMmioAddressEnd
+ )
+{
+ EFI_STATUS Status;
+ HOST_BRIDGE_INFO HostBridge;
+ FIRMWARE_CONFIG_ITEM FwCfgItem;
+ UINTN FwCfgSize;
+ UINTN FwCfgReadIndex;
+ UINTN ReadDataSize;
+ UINT64 Above4GMmioEnd;
+
+ if (PciMmioAddressEnd == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *PciMmioAddressEnd = 0;
+ Above4GMmioEnd = 0;
+
+ Status = QemuFwCfgFindFile ("etc/hardware-info", &FwCfgItem, &FwCfgSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ QemuFwCfgSelectItem (FwCfgItem);
+
+ FwCfgReadIndex = 0;
+ while (FwCfgReadIndex < FwCfgSize) {
+ Status = QemuFwCfgReadNextHardwareInfoByType (
+ HardwareInfoTypeHostBridge,
+ sizeof (HostBridge),
+ FwCfgSize,
+ &HostBridge,
+ &ReadDataSize,
+ &FwCfgReadIndex
+ );
+
+ if (Status != EFI_SUCCESS) {
+ //
+ // No more data available to read in the file, break
+ // loop and finish process
+ //
+ break;
+ }
+
+ Status = HardwareInfoPciHostBridgeLastMmioAddress (
+ &HostBridge,
+ ReadDataSize,
+ TRUE,
+ &Above4GMmioEnd
+ );
+
+ if (Status != EFI_SUCCESS) {
+ //
+ // Error parsing MMIO apertures and extracting last MMIO
+ // address, reset PciMmioAddressEnd as if no information was
+ // found, to avoid moving forward with incomplete data, and
+ // bail out
+ //
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: ignoring malformed hardware information from fw_cfg\n",
+ __FUNCTION__
+ ));
+ *PciMmioAddressEnd = 0;
+ return Status;
+ }
+
+ if (Above4GMmioEnd > *PciMmioAddressEnd) {
+ *PciMmioAddressEnd = Above4GMmioEnd;
+ }
+ }
+
+ if (*PciMmioAddressEnd > 0) {
+ //
+ // Host-provided PCI information was found and a MMIO window end
+ // derived from it.
+ // Increase the End address by one to have the output pointing to
+ // one after the address in use (exclusive end).
+ //
+ *PciMmioAddressEnd += 1;
+
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: Pci64End=0x%Lx\n",
+ __FUNCTION__,
+ *PciMmioAddressEnd
+ ));
+
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
/**
Initialize the PhysMemAddressWidth field in PlatformInfoHob based on guest RAM size.
**/
@@ -536,8 +657,9 @@ PlatformAddressWidthInitialization (
IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob
)
{
- UINT64 FirstNonAddress;
- UINT8 PhysMemAddressWidth;
+ UINT64 FirstNonAddress;
+ UINT8 PhysMemAddressWidth;
+ EFI_STATUS Status;
if (PlatformInfoHob->HostBridgeDevId == 0xffff /* microvm */) {
PlatformAddressWidthFromCpuid (PlatformInfoHob);
@@ -545,12 +667,24 @@ PlatformAddressWidthInitialization (
}
//
- // As guest-physical memory size grows, the permanent PEI RAM requirements
- // are dominated by the identity-mapping page tables built by the DXE IPL.
- // The DXL IPL keys off of the physical address bits advertized in the CPU
- // HOB. To conserve memory, we calculate the minimum address width here.
+ // First scan host-provided hardware information to assess if the address
+ // space is already known. If so, guest must use those values.
//
- FirstNonAddress = PlatformGetFirstNonAddress (PlatformInfoHob);
+ Status = PlatformScanHostProvided64BitPciMmioEnd (&FirstNonAddress);
+
+ if (EFI_ERROR (Status)) {
+ //
+ // If the host did not provide valid hardware information leading to a
+ // hard-defined 64-bit MMIO end, fold back to calculating the minimum range
+ // needed.
+ // As guest-physical memory size grows, the permanent PEI RAM requirements
+ // are dominated by the identity-mapping page tables built by the DXE IPL.
+ // The DXL IPL keys off of the physical address bits advertized in the CPU
+ // HOB. To conserve memory, we calculate the minimum address width here.
+ //
+ FirstNonAddress = PlatformGetFirstNonAddress (PlatformInfoHob);
+ }
+
PhysMemAddressWidth = (UINT8)HighBitSet64 (FirstNonAddress);
//
diff --git a/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf b/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
index d2a0bec434..d2fa2d998d 100644
--- a/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
+++ b/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
@@ -50,6 +50,7 @@
MtrrLib
PcdLib
PciLib
+ PeiHardwareInfoLib
[LibraryClasses.X64]
TdxLib
--
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
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v6 5/5] OvmfPkg/PciHostBridgeUtilityLib: Initialize RootBridges apertures with spec
2022-06-21 21:27 [PATCH v6 0/5] Handling of multiple PCI Ojeda Leon, Nicolas
` (3 preceding siblings ...)
2022-06-21 21:38 ` [PATCH v6 4/5] Ovmf/PlatformPei: Use host-provided GPA end if available Ojeda Leon, Nicolas
@ 2022-06-21 21:40 ` Ojeda Leon, Nicolas
2022-06-22 15:35 ` [PATCH v6 0/5] Handling of multiple PCI Ard Biesheuvel
5 siblings, 0 replies; 9+ messages in thread
From: Ojeda Leon, Nicolas @ 2022-06-21 21:40 UTC (permalink / raw)
To: devel
Cc: ardb+tianocore, jiewen.yao, jordan.l.justen, Nicolas Ojeda Leon,
Alexander Graf, Gerd Hoffmann
Consume the host-provided specification of PCI host bridges if
available. Using the DxeHardwareInfoLib, populate a list of
hardware descriptors based on the content of the "hardware-info"
fw-cfg file, if provided. In the affirmative case, use the
resources and attributes specified by the hypervisor for each
Host Bridge to create the RootBridge elements.
In Ovmf platforms, the host can provide the specification of
non-discoverable hardware resources like PCI host bridges. If the
proper fw-cfg file is found, parse the contents provided by the
host into a linked list by using the Hardware Info library. Then,
using the list of PCI host bridges' descriptions, populate the
PCI_ROOT_BRIDGES array with the resources and attributes specified
by the host. If the file is not provided or no Host Bridge is found
in it, fold back to the legacy method based on pre-defined
apertures and rules.
In some use cases, the host requires additional control over the
hardware resources' configurations in the guest for performance and
discoverability reasons. For instance, to disclose information about
the PCI hierarchy to the guest so that this can profit from
optimized accesses. In this case, the host can decide to describe
multiple PCI Host Bridges and provide a specific set of resources
(e.g. MMIO apertures) so that the guest uses the values provided.
Using the provided values may entitle the guest to added performance,
for example by using specific MMIO mappings that can enable peer-to-peer
communication across the PCI hierarchy or by allocating memory closer
to a device for faster DMA transactions.
Cc: Alexander Graf <graf@amazon.de>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Nicolas Ojeda Leon <ncoleon@amazon.com>
---
Notes:
v6:
Preparation for merge:
- Verify the status output of HardwareInfoPciHostBridgeGet and abort
the host-provided PCI root bridges parsing if an error happened.
- Verify the validity of bus number range (start - end) extracted
from host-provided info to avoid creating root bridges that have
an invalid range. Abort parsing if error detected.
- Cast bus number values down to UINT8 after having verified values
are in range.
v5:
- Added "Acked-by" tag
---
.../PciHostBridgeUtilityLib.c | 332 +++++++++++++++++-
.../PciHostBridgeUtilityLib.inf | 1 +
2 files changed, 328 insertions(+), 5 deletions(-)
diff --git a/OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.c b/OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.c
index 92e1ea812f..cad2bd6c96 100644
--- a/OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.c
+++ b/OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.c
@@ -12,13 +12,16 @@
#include <IndustryStandard/Acpi10.h>
#include <IndustryStandard/Pci.h>
+#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/DevicePathLib.h>
+#include <Library/HardwareInfoLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/PciHostBridgeUtilityLib.h>
#include <Library/PciLib.h>
#include <Library/QemuFwCfgLib.h>
+#include <Protocol/PciHostBridgeResourceAllocation.h>
#pragma pack(1)
typedef struct {
@@ -189,7 +192,9 @@ PciHostBridgeUtilityUninitRootBridge (
}
/**
- Utility function to return all the root bridge instances in an array.
+ Utility function to scan PCI root bridges and create instances for those
+ that are found not empty. Populate their resources from the default
+ provided parameters and return all the root bridge instances in an array.
@param[out] Count The number of root bridge instances.
@@ -217,9 +222,9 @@ PciHostBridgeUtilityUninitRootBridge (
@return All the root bridge instances in an array.
**/
+STATIC
PCI_ROOT_BRIDGE *
-EFIAPI
-PciHostBridgeUtilityGetRootBridges (
+PciHostBridgeUtilityGetRootBridgesBusScan (
OUT UINTN *Count,
IN UINT64 Attributes,
IN UINT64 AllocationAttributes,
@@ -243,8 +248,6 @@ PciHostBridgeUtilityGetRootBridges (
UINTN LastRootBridgeNumber;
UINTN RootBridgeNumber;
- *Count = 0;
-
if ((BusMin > BusMax) || (BusMax > PCI_MAX_BUS)) {
DEBUG ((
DEBUG_ERROR,
@@ -403,6 +406,325 @@ FreeBridges:
return NULL;
}
+/**
+ Utility function to read root bridges information from host-provided fw-cfg
+ file and return them in an array.
+
+ @param[out] Count The number of root bridge instances.
+
+ @return All the root bridge instances in an array parsed from
+ host-provided fw-cfg file (hardware-info).
+**/
+STATIC
+PCI_ROOT_BRIDGE *
+PciHostBridgeUtilityGetRootBridgesHostProvided (
+ OUT UINTN *Count
+ )
+{
+ EFI_STATUS Status;
+ FIRMWARE_CONFIG_ITEM FwCfgItem;
+ UINTN FwCfgSize;
+ PCI_ROOT_BRIDGE *Bridges;
+ UINTN Initialized;
+ UINTN LastRootBridgeNumber;
+ UINTN RootBridgeNumber;
+ UINTN PciHostBridgeCount;
+ UINT8 *HardwareInfoBlob;
+ LIST_ENTRY HwInfoList;
+ LIST_ENTRY *HwLink;
+ HARDWARE_INFO *HwInfo;
+ UINT64 Attributes;
+ UINT64 AllocationAttributes;
+ BOOLEAN DmaAbove4G;
+ BOOLEAN NoExtendedConfigSpace;
+ BOOLEAN CombineMemPMem;
+ PCI_ROOT_BRIDGE_APERTURE Io;
+ PCI_ROOT_BRIDGE_APERTURE Mem;
+ PCI_ROOT_BRIDGE_APERTURE MemAbove4G;
+ PCI_ROOT_BRIDGE_APERTURE PMem;
+ PCI_ROOT_BRIDGE_APERTURE PMemAbove4G;
+
+ //
+ // Initialize the Hardware Info list head to start with an empty but valid
+ // list head.
+ //
+ InitializeListHead (&HwInfoList);
+ HardwareInfoBlob = NULL;
+ Initialized = 0;
+ Bridges = NULL;
+ PciHostBridgeCount = 0;
+
+ //
+ // Hypervisor can provide the specifications (resources) for one or more
+ // PCI host bridges. Such information comes through fw-cfg as part of
+ // the hardware-info file.
+ //
+ Status = QemuFwCfgFindFile ("etc/hardware-info", &FwCfgItem, &FwCfgSize);
+
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ HardwareInfoBlob = AllocatePool (FwCfgSize);
+
+ if (HardwareInfoBlob == NULL) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Failed to allocate memory for hardware resources info\n",
+ __FUNCTION__
+ ));
+ return NULL;
+ }
+
+ QemuFwCfgSelectItem (FwCfgItem);
+ QemuFwCfgReadBytes (FwCfgSize, HardwareInfoBlob);
+
+ //
+ // Create the list of hardware info devices filtering for PCI host
+ // bridges
+ //
+ Status = CreateHardwareInfoList (
+ HardwareInfoBlob,
+ FwCfgSize,
+ HardwareInfoTypeHostBridge,
+ &HwInfoList
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Failed to create hardware info list to retrieve host "
+ "bridges information from fw-cfg\n",
+ __FUNCTION__
+ ));
+
+ goto FreeBridges;
+ }
+
+ PciHostBridgeCount = GetHardwareInfoCountByType (
+ &HwInfoList,
+ HardwareInfoTypeHostBridge,
+ sizeof (HOST_BRIDGE_INFO)
+ );
+
+ if (PciHostBridgeCount == 0) {
+ goto FreeBridges;
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: Host provided description for %Lu root bridges\n",
+ __FUNCTION__,
+ PciHostBridgeCount
+ ));
+
+ //
+ // Allocate the root bridges
+ //
+ Bridges = AllocatePool (((UINTN)PciHostBridgeCount) * sizeof *Bridges);
+ if (Bridges == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, EFI_OUT_OF_RESOURCES));
+ goto FreeBridges;
+ }
+
+ //
+ // If Host Bridges' specification was obtained from fw-cfg, the list
+ // contains information to populate all root bridges in the system
+ // including resources and attributes.
+ //
+ HwLink = GetFirstHardwareInfoByType (
+ &HwInfoList,
+ HardwareInfoTypeHostBridge,
+ sizeof (HOST_BRIDGE_INFO)
+ );
+
+ while (!EndOfHardwareInfoList (&HwInfoList, HwLink)) {
+ HwInfo = HARDWARE_INFO_FROM_LINK (HwLink);
+
+ Status = HardwareInfoPciHostBridgeGet (
+ HwInfo->Data.PciHostBridge,
+ (UINTN)HwInfo->Header.Size,
+ &RootBridgeNumber,
+ &LastRootBridgeNumber,
+ &Attributes,
+ &DmaAbove4G,
+ &NoExtendedConfigSpace,
+ &CombineMemPMem,
+ &Io,
+ &Mem,
+ &MemAbove4G,
+ &PMem,
+ &PMemAbove4G,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto FreeBridges;
+ }
+
+ if ((RootBridgeNumber > LastRootBridgeNumber) || (LastRootBridgeNumber > PCI_MAX_BUS)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: invalid bus range with BusMin %Lu and BusMax "
+ "%Lu\n",
+ __FUNCTION__,
+ (UINT64)RootBridgeNumber,
+ (UINT64)LastRootBridgeNumber
+ ));
+ goto FreeBridges;
+ }
+
+ AllocationAttributes = 0;
+ if (CombineMemPMem) {
+ AllocationAttributes |= EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM;
+ }
+
+ if ((MemAbove4G.Limit > MemAbove4G.Base) ||
+ (PMemAbove4G.Limit > PMemAbove4G.Base))
+ {
+ AllocationAttributes |= EFI_PCI_HOST_BRIDGE_MEM64_DECODE;
+ }
+
+ Status = PciHostBridgeUtilityInitRootBridge (
+ Attributes,
+ Attributes,
+ AllocationAttributes,
+ DmaAbove4G,
+ NoExtendedConfigSpace,
+ (UINT8)RootBridgeNumber,
+ (UINT8)LastRootBridgeNumber,
+ &Io,
+ &Mem,
+ &MemAbove4G,
+ &PMem,
+ &PMemAbove4G,
+ &Bridges[Initialized]
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto FreeBridges;
+ }
+
+ ++Initialized;
+
+ HwLink = GetNextHardwareInfoByType (
+ &HwInfoList,
+ HwLink,
+ HardwareInfoTypeHostBridge,
+ sizeof (HOST_BRIDGE_INFO)
+ );
+ }
+
+ *Count = Initialized;
+
+ //
+ // If resources were allocated for host bridges info, release them
+ //
+ if (HardwareInfoBlob) {
+ FreePool (HardwareInfoBlob);
+ }
+
+ FreeHardwareInfoList (&HwInfoList);
+ return Bridges;
+
+FreeBridges:
+ while (Initialized > 0) {
+ --Initialized;
+ PciHostBridgeUtilityUninitRootBridge (&Bridges[Initialized]);
+ }
+
+ if (Bridges) {
+ FreePool (Bridges);
+ }
+
+ if (HardwareInfoBlob) {
+ FreePool (HardwareInfoBlob);
+ }
+
+ FreeHardwareInfoList (&HwInfoList);
+ return NULL;
+}
+
+/**
+ Utility function to return all the root bridge instances in an array.
+
+ @param[out] Count The number of root bridge instances.
+
+ @param[in] Attributes Initial attributes.
+
+ @param[in] AllocAttributes Allocation attributes.
+
+ @param[in] DmaAbove4G DMA above 4GB memory.
+
+ @param[in] NoExtendedConfigSpace No Extended Config Space.
+
+ @param[in] BusMin Minimum Bus number, inclusive.
+
+ @param[in] BusMax Maximum Bus number, inclusive.
+
+ @param[in] Io IO aperture.
+
+ @param[in] Mem MMIO aperture.
+
+ @param[in] MemAbove4G MMIO aperture above 4G.
+
+ @param[in] PMem Prefetchable MMIO aperture.
+
+ @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G.
+
+ @return All the root bridge instances in an array.
+**/
+PCI_ROOT_BRIDGE *
+EFIAPI
+PciHostBridgeUtilityGetRootBridges (
+ OUT UINTN *Count,
+ IN UINT64 Attributes,
+ IN UINT64 AllocationAttributes,
+ IN BOOLEAN DmaAbove4G,
+ IN BOOLEAN NoExtendedConfigSpace,
+ IN UINTN BusMin,
+ IN UINTN BusMax,
+ IN PCI_ROOT_BRIDGE_APERTURE *Io,
+ IN PCI_ROOT_BRIDGE_APERTURE *Mem,
+ IN PCI_ROOT_BRIDGE_APERTURE *MemAbove4G,
+ IN PCI_ROOT_BRIDGE_APERTURE *PMem,
+ IN PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G
+ )
+{
+ PCI_ROOT_BRIDGE *Bridges;
+
+ *Count = 0;
+
+ //
+ // First attempt to get the host provided descriptions of the Root Bridges
+ // if available.
+ //
+ Bridges = PciHostBridgeUtilityGetRootBridgesHostProvided (Count);
+
+ //
+ // If host did not provide Root Bridge information, scan the buses and
+ // auto populate them with default resources.
+ //
+ if (Bridges == NULL) {
+ Bridges = PciHostBridgeUtilityGetRootBridgesBusScan (
+ Count,
+ Attributes,
+ AllocationAttributes,
+ DmaAbove4G,
+ NoExtendedConfigSpace,
+ BusMin,
+ BusMax,
+ Io,
+ Mem,
+ MemAbove4G,
+ PMem,
+ PMemAbove4G
+ );
+ }
+
+ return Bridges;
+}
+
/**
Utility function to free root bridge instances array from
PciHostBridgeUtilityGetRootBridges().
diff --git a/OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.inf b/OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.inf
index 83a734c172..e4fc903121 100644
--- a/OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.inf
+++ b/OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.inf
@@ -38,6 +38,7 @@
BaseMemoryLib
DebugLib
DevicePathLib
+ DxeHardwareInfoLib
MemoryAllocationLib
PciLib
QemuFwCfgLib
--
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
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v6 0/5] Handling of multiple PCI
2022-06-21 21:27 [PATCH v6 0/5] Handling of multiple PCI Ojeda Leon, Nicolas
` (4 preceding siblings ...)
2022-06-21 21:40 ` [PATCH v6 5/5] OvmfPkg/PciHostBridgeUtilityLib: Initialize RootBridges apertures with spec Ojeda Leon, Nicolas
@ 2022-06-22 15:35 ` Ard Biesheuvel
2022-06-23 11:00 ` Ard Biesheuvel
5 siblings, 1 reply; 9+ messages in thread
From: Ard Biesheuvel @ 2022-06-22 15:35 UTC (permalink / raw)
To: Nicolas Ojeda Leon
Cc: edk2-devel-groups-io, Alexander Graf, Leif Lindholm, Sami Mujawar,
Brijesh Singh, Erdem Aktas, James Bottomley, Min Xu, Tom Lendacky,
Rebecca Cran, Peter Grehan, Sebastien Boeuf, Anthony Perard,
Julien Grall, Ard Biesheuvel, Jiewen Yao, Jordan Justen,
Gerd Hoffmann
On Tue, 21 Jun 2022 at 23:28, Nicolas Ojeda Leon <ncoleon@amazon.com> wrote:
>
> Increased control is provided in Ovmf platforms to define and configure
> the specifications of multiple PCI host bridges in the hypervisor. The
> host propagates this information to the guest, initially through fw-cfg
> interface.
>
> In some AWS EC2 platforms, we expose a PCI topology including several
> root bridges portraying information about physical distribution that
> enables the guest to optimize accesses. Current PCI driver for Ovmf
> enables the explicit definition of multiple root bridges and contains
> the logic to fix their resources based on platform-specific PCD
> entries. However, we need a way to control, from the hypervisor, how
> many and which resources each PCI root bridge can use. For this
> reason, this patch series introduces a mechanism to provide PCI host
> bridges information like bus number range, attributes, allocation
> attributes, PIO aperture as well as 32 and 64- bit prefetchable and
> non-prefetchable MMIO ranges through a fw-cfg item created by the
> hypervisor and consumed by the guest firmware. In order to offer a
> generic and extensible way to disclose non-discoverable hardware
> information from the host to the guest, a new library called
> HardwareInfoLib is created in the OvmfPkg. In essence, this library
> offers the functionality to parse a generic BLOB into a list as well
> as the methods to iterate over such list, including filtering options.
> The library is conceived in a generic way so that further hardware
> elements can also be described using it. For such purpose the length
> of the BLOB is not restricted but instead regarded as a sequence of
> header-info elements that allow the parsing during runtime.
> Furthermore, specific functionality is provided wrapping
> QemuFwCfgReadBytes to extract hardware descriptions, in the
> aforementioned format, in a static way so that early in the Pei
> stage the library can be used to identify address space requirements.
> The core of the library offers enough flexibility to process as many
> elements, even from different hardware types (heterogenous), as needed
> in a single run. This library is extended for the particular use case
> already exposed, PCI host bridges, and this same code offers an
> example of how to tailor it for further hardware components.
>
> After acknowledgement from Gerd Hoffmann and fixing all warnings and
> errors found by the CI pipeline (via draft pull request), here I send
> a new revision of the patches for merging.
>
> ---
> Notes:
> v6:
> Prepearation for upstream merge:
> - No functional change at all.
> - Small changes to fix all builds excercised by CI
> (https://github.com/tianocore/edk2/pull/2938)
> - Added libraries to furhter platforms as per dependencies requirements
> - Explicit casting of some values as required by build and
> verification of values when demoting values.
> - Arranged added files copyright to the format required.
> - Changed HOST_BRIDGE_INFO bitfield member to UINT32 to follow
> EDK2 guidelines motivated on build in 32-bit windows systems.
> - Added verification of Bus Number range when values provided by
> host to make sure Root Bridge is initialized with valid values
>
> v5:
> - Removed last 3 patches dealing with pre-populated resources to
> encapsulate related changes in more manageable chunks and while
> pre-populated changes are finalized.
> - Added Acked-by to all commits
> - Re-based on top of latest master and refactored changes in
> MemDetect.c to adapt to recently created
> PlatformInitLib/MemDetect.c
>
> v4:
> - Minor modification to use MAX_UINT64 as global invalid base address
> when reading PCI host bridge information provided by the host
> (Patch 1)
> - Refactor PciHostBridgeUtilityGetRootBridges into a thin wrapper that
> calls 2 new function: one (BusScan) that performs the legacy bus
> scan population process and a new one (HostProvided) that populates
> Root Bridges with host provided values. (Patch 5)
> - Move code that sets value of PcdPciPreservePopulatedMappings token
> based on host-provided fw-cfg file into the function that populates
> root bridges with host provided data (Patch 6)
> - Restructured base address retrieval to leave PCI Resource Allocation
> protocol untouched and instead augment the existing services to
> enable base address retrieval before allocation. (Patch 7)
> - Use new method to retrieve Root Bridge base addresses before
> allocation and use that to handle pre-populated BARs (Patch 8)
>
>
> Nicolas Ojeda Leon (5):
> OvmfPkg/Library: Create base HardwareInfoLib for PCI Host Bridges
> Ovmf/HardwareInfoLib: Create Pei lib to parse directly from fw-cfg
> Ovmf/HardwareInfoLib: Add Dxe lib to dynamically parse heterogenous
> data
> Ovmf/PlatformPei: Use host-provided GPA end if available
> OvmfPkg/PciHostBridgeUtilityLib: Initialize RootBridges apertures with
> spec
>
Merged as #3000,
Thanks all,
> ArmVirtPkg/ArmVirtQemu.dsc | 2 +
> OvmfPkg/AmdSev/AmdSevX64.dsc | 2 +
> OvmfPkg/Bhyve/BhyveX64.dsc | 2 +
> OvmfPkg/CloudHv/CloudHvX64.dsc | 2 +
> OvmfPkg/Include/Library/HardwareInfoLib.h | 159 ++++++
> .../HardwareInfoLib/DxeHardwareInfoLib.inf | 39 ++
> .../Library/HardwareInfoLib/HardwareInfoDxe.c | 254 +++++++++
> .../HardwareInfoPciHostBridgeLib.c | 508 ++++++++++++++++++
> .../HardwareInfoPciHostBridgeLib.h | 256 +++++++++
> .../Library/HardwareInfoLib/HardwareInfoPei.c | 79 +++
> .../HardwareInfoLib/HardwareInfoTypesLib.h | 59 ++
> .../HardwareInfoLib/PeiHardwareInfoLib.inf | 39 ++
> .../QemuFwCfgHardwareInfoLib.c | 88 +++
> .../PciHostBridgeUtilityLib.c | 332 +++++++++++-
> .../PciHostBridgeUtilityLib.inf | 1 +
> OvmfPkg/Library/PlatformInitLib/MemDetect.c | 148 ++++-
> .../PlatformInitLib/PlatformInitLib.inf | 1 +
> OvmfPkg/Microvm/MicrovmX64.dsc | 2 +
> OvmfPkg/OvmfPkg.dec | 4 +
> OvmfPkg/OvmfPkgIa32.dsc | 2 +
> OvmfPkg/OvmfPkgIa32X64.dsc | 2 +
> OvmfPkg/OvmfPkgX64.dsc | 2 +
> OvmfPkg/OvmfXen.dsc | 2 +
> 23 files changed, 1973 insertions(+), 12 deletions(-)
> create mode 100644 OvmfPkg/Include/Library/HardwareInfoLib.h
> create mode 100644 OvmfPkg/Library/HardwareInfoLib/DxeHardwareInfoLib.inf
> create mode 100644 OvmfPkg/Library/HardwareInfoLib/HardwareInfoDxe.c
> create mode 100644 OvmfPkg/Library/HardwareInfoLib/HardwareInfoPciHostBridgeLib.c
> create mode 100644 OvmfPkg/Library/HardwareInfoLib/HardwareInfoPciHostBridgeLib.h
> create mode 100644 OvmfPkg/Library/HardwareInfoLib/HardwareInfoPei.c
> create mode 100644 OvmfPkg/Library/HardwareInfoLib/HardwareInfoTypesLib.h
> create mode 100644 OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf
> create mode 100644 OvmfPkg/Library/HardwareInfoLib/QemuFwCfgHardwareInfoLib.c
>
> --
> 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
>
>
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v6 0/5] Handling of multiple PCI
2022-06-22 15:35 ` [PATCH v6 0/5] Handling of multiple PCI Ard Biesheuvel
@ 2022-06-23 11:00 ` Ard Biesheuvel
2022-06-23 14:14 ` Ojeda Leon, Nicolas
0 siblings, 1 reply; 9+ messages in thread
From: Ard Biesheuvel @ 2022-06-23 11:00 UTC (permalink / raw)
To: Nicolas Ojeda Leon
Cc: edk2-devel-groups-io, Alexander Graf, Leif Lindholm, Sami Mujawar,
Erdem Aktas, James Bottomley, Min Xu, Tom Lendacky, Rebecca Cran,
Peter Grehan, Sebastien Boeuf, Anthony Perard, Julien Grall,
Ard Biesheuvel, Jiewen Yao, Jordan Justen, Gerd Hoffmann
On Wed, 22 Jun 2022 at 17:35, Ard Biesheuvel <ardb@kernel.org> wrote:
>
> On Tue, 21 Jun 2022 at 23:28, Nicolas Ojeda Leon <ncoleon@amazon.com> wrote:
> >
> > Increased control is provided in Ovmf platforms to define and configure
> > the specifications of multiple PCI host bridges in the hypervisor. The
> > host propagates this information to the guest, initially through fw-cfg
> > interface.
> >
> > In some AWS EC2 platforms, we expose a PCI topology including several
> > root bridges portraying information about physical distribution that
> > enables the guest to optimize accesses. Current PCI driver for Ovmf
> > enables the explicit definition of multiple root bridges and contains
> > the logic to fix their resources based on platform-specific PCD
> > entries. However, we need a way to control, from the hypervisor, how
> > many and which resources each PCI root bridge can use. For this
> > reason, this patch series introduces a mechanism to provide PCI host
> > bridges information like bus number range, attributes, allocation
> > attributes, PIO aperture as well as 32 and 64- bit prefetchable and
> > non-prefetchable MMIO ranges through a fw-cfg item created by the
> > hypervisor and consumed by the guest firmware. In order to offer a
> > generic and extensible way to disclose non-discoverable hardware
> > information from the host to the guest, a new library called
> > HardwareInfoLib is created in the OvmfPkg. In essence, this library
> > offers the functionality to parse a generic BLOB into a list as well
> > as the methods to iterate over such list, including filtering options.
> > The library is conceived in a generic way so that further hardware
> > elements can also be described using it. For such purpose the length
> > of the BLOB is not restricted but instead regarded as a sequence of
> > header-info elements that allow the parsing during runtime.
> > Furthermore, specific functionality is provided wrapping
> > QemuFwCfgReadBytes to extract hardware descriptions, in the
> > aforementioned format, in a static way so that early in the Pei
> > stage the library can be used to identify address space requirements.
> > The core of the library offers enough flexibility to process as many
> > elements, even from different hardware types (heterogenous), as needed
> > in a single run. This library is extended for the particular use case
> > already exposed, PCI host bridges, and this same code offers an
> > example of how to tailor it for further hardware components.
> >
> > After acknowledgement from Gerd Hoffmann and fixing all warnings and
> > errors found by the CI pipeline (via draft pull request), here I send
> > a new revision of the patches for merging.
> >
> > ---
> > Notes:
> > v6:
> > Prepearation for upstream merge:
> > - No functional change at all.
> > - Small changes to fix all builds excercised by CI
> > (https://github.com/tianocore/edk2/pull/2938)
> > - Added libraries to furhter platforms as per dependencies requirements
> > - Explicit casting of some values as required by build and
> > verification of values when demoting values.
> > - Arranged added files copyright to the format required.
> > - Changed HOST_BRIDGE_INFO bitfield member to UINT32 to follow
> > EDK2 guidelines motivated on build in 32-bit windows systems.
> > - Added verification of Bus Number range when values provided by
> > host to make sure Root Bridge is initialized with valid values
> >
> > v5:
> > - Removed last 3 patches dealing with pre-populated resources to
> > encapsulate related changes in more manageable chunks and while
> > pre-populated changes are finalized.
> > - Added Acked-by to all commits
> > - Re-based on top of latest master and refactored changes in
> > MemDetect.c to adapt to recently created
> > PlatformInitLib/MemDetect.c
> >
> > v4:
> > - Minor modification to use MAX_UINT64 as global invalid base address
> > when reading PCI host bridge information provided by the host
> > (Patch 1)
> > - Refactor PciHostBridgeUtilityGetRootBridges into a thin wrapper that
> > calls 2 new function: one (BusScan) that performs the legacy bus
> > scan population process and a new one (HostProvided) that populates
> > Root Bridges with host provided values. (Patch 5)
> > - Move code that sets value of PcdPciPreservePopulatedMappings token
> > based on host-provided fw-cfg file into the function that populates
> > root bridges with host provided data (Patch 6)
> > - Restructured base address retrieval to leave PCI Resource Allocation
> > protocol untouched and instead augment the existing services to
> > enable base address retrieval before allocation. (Patch 7)
> > - Use new method to retrieve Root Bridge base addresses before
> > allocation and use that to handle pre-populated BARs (Patch 8)
> >
> >
> > Nicolas Ojeda Leon (5):
> > OvmfPkg/Library: Create base HardwareInfoLib for PCI Host Bridges
> > Ovmf/HardwareInfoLib: Create Pei lib to parse directly from fw-cfg
> > Ovmf/HardwareInfoLib: Add Dxe lib to dynamically parse heterogenous
> > data
> > Ovmf/PlatformPei: Use host-provided GPA end if available
> > OvmfPkg/PciHostBridgeUtilityLib: Initialize RootBridges apertures with
> > spec
> >
>
> Merged as #3000,
>
> Thanks all,
>
This series appears to have triggered a failure in our CI. Could
someone propose a fix please?
https://ci.linaro.org/job/leg-virt-tianocore-edk2-upstream/4563/
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v6 0/5] Handling of multiple PCI
2022-06-23 11:00 ` Ard Biesheuvel
@ 2022-06-23 14:14 ` Ojeda Leon, Nicolas
0 siblings, 0 replies; 9+ messages in thread
From: Ojeda Leon, Nicolas @ 2022-06-23 14:14 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: edk2-devel-groups-io, Graf (AWS), Alexander, Leif Lindholm,
Sami Mujawar, Erdem Aktas, James Bottomley, Min Xu, Tom Lendacky,
Rebecca Cran, Peter Grehan, Sebastien Boeuf, Anthony Perard,
Julien Grall, Ard Biesheuvel, Jiewen Yao, Jordan Justen,
Gerd Hoffmann
> On Wed, 22 Jun 2022 at 17:35, Ard Biesheuvel <ardb@kernel.org> wrote:
> >
> > On Tue, 21 Jun 2022 at 23:28, Nicolas Ojeda Leon <ncoleon@amazon.com> wrote:
> > >
> > > Increased control is provided in Ovmf platforms to define and
> > > configure the specifications of multiple PCI host bridges in the
> > > hypervisor. The host propagates this information to the guest,
> > > initially through fw-cfg interface.
> > >
> > > In some AWS EC2 platforms, we expose a PCI topology including
> > > several root bridges portraying information about physical
> > > distribution that enables the guest to optimize accesses. Current
> > > PCI driver for Ovmf enables the explicit definition of multiple root
> > > bridges and contains the logic to fix their resources based on
> > > platform-specific PCD entries. However, we need a way to control,
> > > from the hypervisor, how many and which resources each PCI root
> > > bridge can use. For this reason, this patch series introduces a
> > > mechanism to provide PCI host bridges information like bus number
> > > range, attributes, allocation attributes, PIO aperture as well as 32
> > > and 64- bit prefetchable and non-prefetchable MMIO ranges through a
> > > fw-cfg item created by the hypervisor and consumed by the guest
> > > firmware. In order to offer a generic and extensible way to disclose
> > > non-discoverable hardware information from the host to the guest, a
> > > new library called HardwareInfoLib is created in the OvmfPkg. In
> > > essence, this library offers the functionality to parse a generic
> > > BLOB into a list as well as the methods to iterate over such list, including filtering options.
> > > The library is conceived in a generic way so that further hardware
> > > elements can also be described using it. For such purpose the length
> > > of the BLOB is not restricted but instead regarded as a sequence of
> > > header-info elements that allow the parsing during runtime.
> > > Furthermore, specific functionality is provided wrapping
> > > QemuFwCfgReadBytes to extract hardware descriptions, in the
> > > aforementioned format, in a static way so that early in the Pei
> > > stage the library can be used to identify address space requirements.
> > > The core of the library offers enough flexibility to process as many
> > > elements, even from different hardware types (heterogenous), as
> > > needed in a single run. This library is extended for the particular
> > > use case already exposed, PCI host bridges, and this same code
> > > offers an example of how to tailor it for further hardware components.
> > >
> > > After acknowledgement from Gerd Hoffmann and fixing all warnings and
> > > errors found by the CI pipeline (via draft pull request), here I
> > > send a new revision of the patches for merging.
> > >
> > > ---
> > > Notes:
> > > v6:
> > > Prepearation for upstream merge:
> > > - No functional change at all.
> > > - Small changes to fix all builds excercised by CI
> > > (https://github.com/tianocore/edk2/pull/2938)
> > > - Added libraries to furhter platforms as per dependencies requirements
> > > - Explicit casting of some values as required by build and
> > > verification of values when demoting values.
> > > - Arranged added files copyright to the format required.
> > > - Changed HOST_BRIDGE_INFO bitfield member to UINT32 to follow
> > > EDK2 guidelines motivated on build in 32-bit windows systems.
> > > - Added verification of Bus Number range when values provided by
> > > host to make sure Root Bridge is initialized with valid values
> > >
> > > v5:
> > > - Removed last 3 patches dealing with pre-populated resources to
> > > encapsulate related changes in more manageable chunks and while
> > > pre-populated changes are finalized.
> > > - Added Acked-by to all commits
> > > - Re-based on top of latest master and refactored changes in
> > > MemDetect.c to adapt to recently created
> > > PlatformInitLib/MemDetect.c
> > >
> > > v4:
> > > - Minor modification to use MAX_UINT64 as global invalid base address
> > > when reading PCI host bridge information provided by the host
> > > (Patch 1)
> > > - Refactor PciHostBridgeUtilityGetRootBridges into a thin wrapper that
> > > calls 2 new function: one (BusScan) that performs the legacy bus
> > > scan population process and a new one (HostProvided) that populates
> > > Root Bridges with host provided values. (Patch 5)
> > > - Move code that sets value of PcdPciPreservePopulatedMappings token
> > > based on host-provided fw-cfg file into the function that populates
> > > root bridges with host provided data (Patch 6)
> > > - Restructured base address retrieval to leave PCI Resource Allocation
> > > protocol untouched and instead augment the existing services to
> > > enable base address retrieval before allocation. (Patch 7)
> > > - Use new method to retrieve Root Bridge base addresses before
> > > allocation and use that to handle pre-populated BARs (Patch 8)
> > >
> > >
> > > Nicolas Ojeda Leon (5):
> > > OvmfPkg/Library: Create base HardwareInfoLib for PCI Host Bridges
> > > Ovmf/HardwareInfoLib: Create Pei lib to parse directly from fw-cfg
> > > Ovmf/HardwareInfoLib: Add Dxe lib to dynamically parse heterogenous
> > > data
> > > Ovmf/PlatformPei: Use host-provided GPA end if available
> > > OvmfPkg/PciHostBridgeUtilityLib: Initialize RootBridges apertures with
> > > spec
> > >
> >
> > Merged as #3000,
> >
> > Thanks all,
> >
>
> This series appears to have triggered a failure in our CI. Could someone propose a fix please?
>
> https://ci.linaro.org/job/leg-virt-tianocore-edk2-upstream/4563/
Thanks Ard for notifying.
I will post the fix in short, tested build locally and now running the CI pipeline (https://github.com/tianocore/edk2/pull/2938).
Best regards,
Nicolas
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
^ permalink raw reply [flat|nested] 9+ messages in thread