diff --git a/OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.c b/OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.c index 276d675f50..2e9634359d 100644 --- a/OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.c +++ b/OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.c @@ -27,6 +27,7 @@ #include #include +#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);