summaryrefslogtreecommitdiff
path: root/OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.c
diff options
context:
space:
mode:
Diffstat (limited to 'OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.c')
-rw-r--r--OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.c152
1 files changed, 128 insertions, 24 deletions
diff --git a/OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.c b/OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.c
index 276d675f5..2e9634359 100644
--- a/OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.c
+++ b/OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.c
@@ -27,6 +27,7 @@
#include <Guid/GlobalVariable.h>
#include <Guid/VirtioMmioTransport.h>
+#include "ExtraRootBusMap.h"
/**
OpenFirmware to UEFI device path translation output buffer size in CHAR16's.
@@ -556,6 +557,11 @@ ParseOfwNode (
@param[in] NumNodes Number of elements in OfwNode.
+ @param[in] ExtraPciRoots An EXTRA_ROOT_BUS_MAP object created with
+ CreateExtraRootBusMap(), to be used for
+ translating positions of extra root buses to
+ bus numbers.
+
@param[out] Translated Destination array receiving the UEFI path
fragment, allocated by the caller. If the
return value differs from RETURN_SUCCESS, its
@@ -576,16 +582,23 @@ ParseOfwNode (
@retval RETURN_UNSUPPORTED The array of OpenFirmware device nodes can't
be translated in the current implementation.
+ @retval RETURN_PROTOCOL_ERROR The initial OpenFirmware node refers to an
+ extra PCI root bus (by serial number) that
+ is invalid according to ExtraPciRoots.
+
**/
STATIC
RETURN_STATUS
TranslatePciOfwNodes (
- IN CONST OFW_NODE *OfwNode,
- IN UINTN NumNodes,
- OUT CHAR16 *Translated,
- IN OUT UINTN *TranslatedSize
+ IN CONST OFW_NODE *OfwNode,
+ IN UINTN NumNodes,
+ IN CONST EXTRA_ROOT_BUS_MAP *ExtraPciRoots,
+ OUT CHAR16 *Translated,
+ IN OUT UINTN *TranslatedSize
)
{
+ UINT32 PciRoot;
+ CHAR8 *Comma;
UINTN FirstNonBridge;
CHAR16 Bridges[BRIDGE_TRANSLATION_OUTPUT_SIZE];
UINTN BridgesLen;
@@ -594,7 +607,17 @@ TranslatePciOfwNodes (
UINTN Written;
//
- // Get PCI device and optional PCI function. Assume a single PCI root.
+ // Resolve the PCI root bus number.
+ //
+ // The initial OFW node for the main root bus (ie. bus number 0) is:
+ //
+ // /pci@i0cf8
+ //
+ // For extra root buses, the initial OFW node is
+ //
+ // /pci@i0cf8,4
+ // ^
+ // root bus serial number (not PCI bus number)
//
if (NumNodes < REQUIRED_PCI_OFW_NODES ||
!SubstringEq (OfwNode[0].DriverName, "pci")
@@ -602,6 +625,35 @@ TranslatePciOfwNodes (
return RETURN_UNSUPPORTED;
}
+ PciRoot = 0;
+ Comma = ScanMem8 (OfwNode[0].UnitAddress.Ptr, OfwNode[0].UnitAddress.Len,
+ ',');
+ if (Comma != NULL) {
+ SUBSTRING PciRootSerialSubString;
+ UINT64 PciRootSerial;
+
+ //
+ // Parse the root bus serial number from the unit address after the comma.
+ //
+ PciRootSerialSubString.Ptr = Comma + 1;
+ PciRootSerialSubString.Len = OfwNode[0].UnitAddress.Len -
+ (PciRootSerialSubString.Ptr -
+ OfwNode[0].UnitAddress.Ptr);
+ NumEntries = 1;
+ if (RETURN_ERROR (ParseUnitAddressHexList (PciRootSerialSubString,
+ &PciRootSerial, &NumEntries))) {
+ return RETURN_UNSUPPORTED;
+ }
+
+ //
+ // Map the extra root bus's serial number to its actual bus number.
+ //
+ if (EFI_ERROR (MapRootBusPosToBusNr (ExtraPciRoots, PciRootSerial,
+ &PciRoot))) {
+ return RETURN_PROTOCOL_ERROR;
+ }
+ }
+
//
// Translate a sequence of PCI bridges. For each bridge, the OFW node is:
//
@@ -709,7 +761,8 @@ TranslatePciOfwNodes (
Written = UnicodeSPrintAsciiFormat (
Translated,
*TranslatedSize * sizeof (*Translated), // BufferSize in bytes
- "PciRoot(0x0)%s/Pci(0x%Lx,0x%Lx)/Ata(%a,%a,0x0)",
+ "PciRoot(0x%x)%s/Pci(0x%Lx,0x%Lx)/Ata(%a,%a,0x0)",
+ PciRoot,
Bridges,
PciDevFun[0],
PciDevFun[1],
@@ -753,7 +806,8 @@ TranslatePciOfwNodes (
Written = UnicodeSPrintAsciiFormat (
Translated,
*TranslatedSize * sizeof (*Translated), // BufferSize in bytes
- "PciRoot(0x0)%s/Pci(0x%Lx,0x%Lx)/Floppy(0x%Lx)",
+ "PciRoot(0x%x)%s/Pci(0x%Lx,0x%Lx)/Floppy(0x%Lx)",
+ PciRoot,
Bridges,
PciDevFun[0],
PciDevFun[1],
@@ -781,7 +835,8 @@ TranslatePciOfwNodes (
Written = UnicodeSPrintAsciiFormat (
Translated,
*TranslatedSize * sizeof (*Translated), // BufferSize in bytes
- "PciRoot(0x0)%s/Pci(0x%Lx,0x%Lx)/HD(",
+ "PciRoot(0x%x)%s/Pci(0x%Lx,0x%Lx)/HD(",
+ PciRoot,
Bridges,
PciDevFun[0],
PciDevFun[1]
@@ -825,7 +880,8 @@ TranslatePciOfwNodes (
Written = UnicodeSPrintAsciiFormat (
Translated,
*TranslatedSize * sizeof (*Translated), // BufferSize in bytes
- "PciRoot(0x0)%s/Pci(0x%Lx,0x%Lx)/Scsi(0x%Lx,0x%Lx)",
+ "PciRoot(0x%x)%s/Pci(0x%Lx,0x%Lx)/Scsi(0x%Lx,0x%Lx)",
+ PciRoot,
Bridges,
PciDevFun[0],
PciDevFun[1],
@@ -849,7 +905,8 @@ TranslatePciOfwNodes (
Written = UnicodeSPrintAsciiFormat (
Translated,
*TranslatedSize * sizeof (*Translated), // BufferSize in bytes
- "PciRoot(0x0)%s/Pci(0x%Lx,0x%Lx)",
+ "PciRoot(0x%x)%s/Pci(0x%Lx,0x%Lx)",
+ PciRoot,
Bridges,
PciDevFun[0],
PciDevFun[1]
@@ -1057,6 +1114,11 @@ TranslateMmioOfwNodes (
@param[in] NumNodes Number of elements in OfwNode.
+ @param[in] ExtraPciRoots An EXTRA_ROOT_BUS_MAP object created with
+ CreateExtraRootBusMap(), to be used for
+ translating positions of extra root buses to
+ bus numbers.
+
@param[out] Translated Destination array receiving the UEFI path
fragment, allocated by the caller. If the
return value differs from RETURN_SUCCESS, its
@@ -1077,14 +1139,19 @@ TranslateMmioOfwNodes (
@retval RETURN_UNSUPPORTED The array of OpenFirmware device nodes can't
be translated in the current implementation.
+ @retval RETURN_PROTOCOL_ERROR The array of OpenFirmware device nodes has
+ been (partially) recognized, but it contains
+ a logic error / doesn't match system state.
+
**/
STATIC
RETURN_STATUS
TranslateOfwNodes (
- IN CONST OFW_NODE *OfwNode,
- IN UINTN NumNodes,
- OUT CHAR16 *Translated,
- IN OUT UINTN *TranslatedSize
+ IN CONST OFW_NODE *OfwNode,
+ IN UINTN NumNodes,
+ IN CONST EXTRA_ROOT_BUS_MAP *ExtraPciRoots,
+ OUT CHAR16 *Translated,
+ IN OUT UINTN *TranslatedSize
)
{
RETURN_STATUS Status;
@@ -1092,8 +1159,8 @@ TranslateOfwNodes (
Status = RETURN_UNSUPPORTED;
if (FeaturePcdGet (PcdQemuBootOrderPciTranslation)) {
- Status = TranslatePciOfwNodes (OfwNode, NumNodes, Translated,
- TranslatedSize);
+ Status = TranslatePciOfwNodes (OfwNode, NumNodes, ExtraPciRoots,
+ Translated, TranslatedSize);
}
if (Status == RETURN_UNSUPPORTED &&
FeaturePcdGet (PcdQemuBootOrderMmioTranslation)) {
@@ -1117,6 +1184,11 @@ TranslateOfwNodes (
characters. In other error cases, it points to
the byte that caused the error.
+ @param[in] ExtraPciRoots An EXTRA_ROOT_BUS_MAP object created with
+ CreateExtraRootBusMap(), to be used for
+ translating positions of extra root buses to
+ bus numbers.
+
@param[out] Translated Destination array receiving the UEFI path
fragment, allocated by the caller. If the
return value differs from RETURN_SUCCESS, its
@@ -1142,6 +1214,12 @@ TranslateOfwNodes (
the current implementation. Further calls
to this function are possible.
+ @retval RETURN_PROTOCOL_ERROR The OpenFirmware device path has been
+ (partially) recognized, but it contains a
+ logic error / doesn't match system state.
+ Further calls to this function are
+ possible.
+
@retval RETURN_NOT_FOUND Translation terminated. On input, *Ptr was
pointing to the empty string or "HALT". On
output, *Ptr points to the empty string
@@ -1154,9 +1232,10 @@ TranslateOfwNodes (
STATIC
RETURN_STATUS
TranslateOfwPath (
- IN OUT CONST CHAR8 **Ptr,
- OUT CHAR16 *Translated,
- IN OUT UINTN *TranslatedSize
+ IN OUT CONST CHAR8 **Ptr,
+ IN CONST EXTRA_ROOT_BUS_MAP *ExtraPciRoots,
+ OUT CHAR16 *Translated,
+ IN OUT UINTN *TranslatedSize
)
{
UINTN NumNodes;
@@ -1204,6 +1283,7 @@ TranslateOfwPath (
Status = TranslateOfwNodes (
Node,
NumNodes < EXAMINED_OFW_NODES ? NumNodes : EXAMINED_OFW_NODES,
+ ExtraPciRoots,
Translated,
TranslatedSize);
switch (Status) {
@@ -1219,6 +1299,11 @@ TranslateOfwPath (
DEBUG ((DEBUG_VERBOSE, "%a: unsupported\n", __FUNCTION__));
break;
+ case RETURN_PROTOCOL_ERROR:
+ DEBUG ((DEBUG_VERBOSE, "%a: logic error / system state mismatch\n",
+ __FUNCTION__));
+ break;
+
default:
ASSERT (0);
}
@@ -1512,6 +1597,8 @@ SetBootOrderFromQemu (
ACTIVE_OPTION *ActiveOption;
UINTN ActiveCount;
+ EXTRA_ROOT_BUS_MAP *ExtraPciRoots;
+
UINTN TranslatedSize;
CHAR16 Translated[TRANSLATION_OUTPUT_SIZE];
@@ -1556,13 +1643,24 @@ SetBootOrderFromQemu (
goto ErrorFreeBootOrder;
}
+ if (FeaturePcdGet (PcdQemuBootOrderPciTranslation)) {
+ Status = CreateExtraRootBusMap (&ExtraPciRoots);
+ if (EFI_ERROR (Status)) {
+ goto ErrorFreeActiveOption;
+ }
+ } else {
+ ExtraPciRoots = NULL;
+ }
+
//
// translate each OpenFirmware path
//
TranslatedSize = sizeof (Translated) / sizeof (Translated[0]);
- Status = TranslateOfwPath (&FwCfgPtr, Translated, &TranslatedSize);
+ Status = TranslateOfwPath (&FwCfgPtr, ExtraPciRoots, Translated,
+ &TranslatedSize);
while (Status == RETURN_SUCCESS ||
Status == RETURN_UNSUPPORTED ||
+ Status == RETURN_PROTOCOL_ERROR ||
Status == RETURN_BUFFER_TOO_SMALL) {
if (Status == RETURN_SUCCESS) {
UINTN Idx;
@@ -1582,7 +1680,7 @@ SetBootOrderFromQemu (
//
Status = BootOrderAppend (&BootOrder, &ActiveOption[Idx]);
if (Status != RETURN_SUCCESS) {
- goto ErrorFreeActiveOption;
+ goto ErrorFreeExtraPciRoots;
}
break;
}
@@ -1590,7 +1688,8 @@ SetBootOrderFromQemu (
} // translation successful
TranslatedSize = sizeof (Translated) / sizeof (Translated[0]);
- Status = TranslateOfwPath (&FwCfgPtr, Translated, &TranslatedSize);
+ Status = TranslateOfwPath (&FwCfgPtr, ExtraPciRoots, Translated,
+ &TranslatedSize);
} // scanning of OpenFirmware paths done
if (Status == RETURN_NOT_FOUND && BootOrder.Produced > 0) {
@@ -1601,7 +1700,7 @@ SetBootOrderFromQemu (
//
Status = BootOrderComplete (&BootOrder, ActiveOption, ActiveCount);
if (RETURN_ERROR (Status)) {
- goto ErrorFreeActiveOption;
+ goto ErrorFreeExtraPciRoots;
}
//
@@ -1619,13 +1718,18 @@ SetBootOrderFromQemu (
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: setting BootOrder: %r\n", __FUNCTION__, Status));
- goto ErrorFreeActiveOption;
+ goto ErrorFreeExtraPciRoots;
}
DEBUG ((DEBUG_INFO, "%a: setting BootOrder: success\n", __FUNCTION__));
PruneBootVariables (ActiveOption, ActiveCount);
}
+ErrorFreeExtraPciRoots:
+ if (ExtraPciRoots != NULL) {
+ DestroyExtraRootBusMap (ExtraPciRoots);
+ }
+
ErrorFreeActiveOption:
FreePool (ActiveOption);