#include <Guid/GlobalVariable.h>\r
#include <Guid/VirtioMmioTransport.h>\r
\r
+#include "ExtraRootBusMap.h"\r
\r
/**\r
OpenFirmware to UEFI device path translation output buffer size in CHAR16's.\r
\r
@param[in] NumNodes Number of elements in OfwNode.\r
\r
+ @param[in] ExtraPciRoots An EXTRA_ROOT_BUS_MAP object created with\r
+ CreateExtraRootBusMap(), to be used for\r
+ translating positions of extra root buses to\r
+ bus numbers.\r
+\r
@param[out] Translated Destination array receiving the UEFI path\r
fragment, allocated by the caller. If the\r
return value differs from RETURN_SUCCESS, its\r
@retval RETURN_UNSUPPORTED The array of OpenFirmware device nodes can't\r
be translated in the current implementation.\r
\r
+ @retval RETURN_PROTOCOL_ERROR The initial OpenFirmware node refers to an\r
+ extra PCI root bus (by serial number) that\r
+ is invalid according to ExtraPciRoots.\r
+\r
**/\r
STATIC\r
RETURN_STATUS\r
TranslatePciOfwNodes (\r
- IN CONST OFW_NODE *OfwNode,\r
- IN UINTN NumNodes,\r
- OUT CHAR16 *Translated,\r
- IN OUT UINTN *TranslatedSize\r
+ IN CONST OFW_NODE *OfwNode,\r
+ IN UINTN NumNodes,\r
+ IN CONST EXTRA_ROOT_BUS_MAP *ExtraPciRoots,\r
+ OUT CHAR16 *Translated,\r
+ IN OUT UINTN *TranslatedSize\r
)\r
{\r
+ UINT32 PciRoot;\r
+ CHAR8 *Comma;\r
UINTN FirstNonBridge;\r
CHAR16 Bridges[BRIDGE_TRANSLATION_OUTPUT_SIZE];\r
UINTN BridgesLen;\r
UINTN Written;\r
\r
//\r
- // Get PCI device and optional PCI function. Assume a single PCI root.\r
+ // Resolve the PCI root bus number.\r
+ //\r
+ // The initial OFW node for the main root bus (ie. bus number 0) is:\r
+ //\r
+ // /pci@i0cf8\r
+ //\r
+ // For extra root buses, the initial OFW node is\r
+ //\r
+ // /pci@i0cf8,4\r
+ // ^\r
+ // root bus serial number (not PCI bus number)\r
//\r
if (NumNodes < REQUIRED_PCI_OFW_NODES ||\r
!SubstringEq (OfwNode[0].DriverName, "pci")\r
return RETURN_UNSUPPORTED;\r
}\r
\r
+ PciRoot = 0;\r
+ Comma = ScanMem8 (OfwNode[0].UnitAddress.Ptr, OfwNode[0].UnitAddress.Len,\r
+ ',');\r
+ if (Comma != NULL) {\r
+ SUBSTRING PciRootSerialSubString;\r
+ UINT64 PciRootSerial;\r
+\r
+ //\r
+ // Parse the root bus serial number from the unit address after the comma.\r
+ //\r
+ PciRootSerialSubString.Ptr = Comma + 1;\r
+ PciRootSerialSubString.Len = OfwNode[0].UnitAddress.Len -\r
+ (PciRootSerialSubString.Ptr -\r
+ OfwNode[0].UnitAddress.Ptr);\r
+ NumEntries = 1;\r
+ if (RETURN_ERROR (ParseUnitAddressHexList (PciRootSerialSubString,\r
+ &PciRootSerial, &NumEntries))) {\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Map the extra root bus's serial number to its actual bus number.\r
+ //\r
+ if (EFI_ERROR (MapRootBusPosToBusNr (ExtraPciRoots, PciRootSerial,\r
+ &PciRoot))) {\r
+ return RETURN_PROTOCOL_ERROR;\r
+ }\r
+ }\r
+\r
//\r
// Translate a sequence of PCI bridges. For each bridge, the OFW node is:\r
//\r
Written = UnicodeSPrintAsciiFormat (\r
Translated,\r
*TranslatedSize * sizeof (*Translated), // BufferSize in bytes\r
- "PciRoot(0x0)%s/Pci(0x%Lx,0x%Lx)/Ata(%a,%a,0x0)",\r
+ "PciRoot(0x%x)%s/Pci(0x%Lx,0x%Lx)/Ata(%a,%a,0x0)",\r
+ PciRoot,\r
Bridges,\r
PciDevFun[0],\r
PciDevFun[1],\r
Written = UnicodeSPrintAsciiFormat (\r
Translated,\r
*TranslatedSize * sizeof (*Translated), // BufferSize in bytes\r
- "PciRoot(0x0)%s/Pci(0x%Lx,0x%Lx)/Floppy(0x%Lx)",\r
+ "PciRoot(0x%x)%s/Pci(0x%Lx,0x%Lx)/Floppy(0x%Lx)",\r
+ PciRoot,\r
Bridges,\r
PciDevFun[0],\r
PciDevFun[1],\r
Written = UnicodeSPrintAsciiFormat (\r
Translated,\r
*TranslatedSize * sizeof (*Translated), // BufferSize in bytes\r
- "PciRoot(0x0)%s/Pci(0x%Lx,0x%Lx)/HD(",\r
+ "PciRoot(0x%x)%s/Pci(0x%Lx,0x%Lx)/HD(",\r
+ PciRoot,\r
Bridges,\r
PciDevFun[0],\r
PciDevFun[1]\r
Written = UnicodeSPrintAsciiFormat (\r
Translated,\r
*TranslatedSize * sizeof (*Translated), // BufferSize in bytes\r
- "PciRoot(0x0)%s/Pci(0x%Lx,0x%Lx)/Scsi(0x%Lx,0x%Lx)",\r
+ "PciRoot(0x%x)%s/Pci(0x%Lx,0x%Lx)/Scsi(0x%Lx,0x%Lx)",\r
+ PciRoot,\r
Bridges,\r
PciDevFun[0],\r
PciDevFun[1],\r
Written = UnicodeSPrintAsciiFormat (\r
Translated,\r
*TranslatedSize * sizeof (*Translated), // BufferSize in bytes\r
- "PciRoot(0x0)%s/Pci(0x%Lx,0x%Lx)",\r
+ "PciRoot(0x%x)%s/Pci(0x%Lx,0x%Lx)",\r
+ PciRoot,\r
Bridges,\r
PciDevFun[0],\r
PciDevFun[1]\r
\r
@param[in] NumNodes Number of elements in OfwNode.\r
\r
+ @param[in] ExtraPciRoots An EXTRA_ROOT_BUS_MAP object created with\r
+ CreateExtraRootBusMap(), to be used for\r
+ translating positions of extra root buses to\r
+ bus numbers.\r
+\r
@param[out] Translated Destination array receiving the UEFI path\r
fragment, allocated by the caller. If the\r
return value differs from RETURN_SUCCESS, its\r
@retval RETURN_UNSUPPORTED The array of OpenFirmware device nodes can't\r
be translated in the current implementation.\r
\r
+ @retval RETURN_PROTOCOL_ERROR The array of OpenFirmware device nodes has\r
+ been (partially) recognized, but it contains\r
+ a logic error / doesn't match system state.\r
+\r
**/\r
STATIC\r
RETURN_STATUS\r
TranslateOfwNodes (\r
- IN CONST OFW_NODE *OfwNode,\r
- IN UINTN NumNodes,\r
- OUT CHAR16 *Translated,\r
- IN OUT UINTN *TranslatedSize\r
+ IN CONST OFW_NODE *OfwNode,\r
+ IN UINTN NumNodes,\r
+ IN CONST EXTRA_ROOT_BUS_MAP *ExtraPciRoots,\r
+ OUT CHAR16 *Translated,\r
+ IN OUT UINTN *TranslatedSize\r
)\r
{\r
RETURN_STATUS Status;\r
Status = RETURN_UNSUPPORTED;\r
\r
if (FeaturePcdGet (PcdQemuBootOrderPciTranslation)) {\r
- Status = TranslatePciOfwNodes (OfwNode, NumNodes, Translated,\r
- TranslatedSize);\r
+ Status = TranslatePciOfwNodes (OfwNode, NumNodes, ExtraPciRoots,\r
+ Translated, TranslatedSize);\r
}\r
if (Status == RETURN_UNSUPPORTED &&\r
FeaturePcdGet (PcdQemuBootOrderMmioTranslation)) {\r
characters. In other error cases, it points to\r
the byte that caused the error.\r
\r
+ @param[in] ExtraPciRoots An EXTRA_ROOT_BUS_MAP object created with\r
+ CreateExtraRootBusMap(), to be used for\r
+ translating positions of extra root buses to\r
+ bus numbers.\r
+\r
@param[out] Translated Destination array receiving the UEFI path\r
fragment, allocated by the caller. If the\r
return value differs from RETURN_SUCCESS, its\r
the current implementation. Further calls\r
to this function are possible.\r
\r
+ @retval RETURN_PROTOCOL_ERROR The OpenFirmware device path has been\r
+ (partially) recognized, but it contains a\r
+ logic error / doesn't match system state.\r
+ Further calls to this function are\r
+ possible.\r
+\r
@retval RETURN_NOT_FOUND Translation terminated. On input, *Ptr was\r
pointing to the empty string or "HALT". On\r
output, *Ptr points to the empty string\r
STATIC\r
RETURN_STATUS\r
TranslateOfwPath (\r
- IN OUT CONST CHAR8 **Ptr,\r
- OUT CHAR16 *Translated,\r
- IN OUT UINTN *TranslatedSize\r
+ IN OUT CONST CHAR8 **Ptr,\r
+ IN CONST EXTRA_ROOT_BUS_MAP *ExtraPciRoots,\r
+ OUT CHAR16 *Translated,\r
+ IN OUT UINTN *TranslatedSize\r
)\r
{\r
UINTN NumNodes;\r
Status = TranslateOfwNodes (\r
Node,\r
NumNodes < EXAMINED_OFW_NODES ? NumNodes : EXAMINED_OFW_NODES,\r
+ ExtraPciRoots,\r
Translated,\r
TranslatedSize);\r
switch (Status) {\r
DEBUG ((DEBUG_VERBOSE, "%a: unsupported\n", __FUNCTION__));\r
break;\r
\r
+ case RETURN_PROTOCOL_ERROR:\r
+ DEBUG ((DEBUG_VERBOSE, "%a: logic error / system state mismatch\n",\r
+ __FUNCTION__));\r
+ break;\r
+\r
default:\r
ASSERT (0);\r
}\r
ACTIVE_OPTION *ActiveOption;\r
UINTN ActiveCount;\r
\r
+ EXTRA_ROOT_BUS_MAP *ExtraPciRoots;\r
+\r
UINTN TranslatedSize;\r
CHAR16 Translated[TRANSLATION_OUTPUT_SIZE];\r
\r
goto ErrorFreeBootOrder;\r
}\r
\r
+ if (FeaturePcdGet (PcdQemuBootOrderPciTranslation)) {\r
+ Status = CreateExtraRootBusMap (&ExtraPciRoots);\r
+ if (EFI_ERROR (Status)) {\r
+ goto ErrorFreeActiveOption;\r
+ }\r
+ } else {\r
+ ExtraPciRoots = NULL;\r
+ }\r
+\r
//\r
// translate each OpenFirmware path\r
//\r
TranslatedSize = sizeof (Translated) / sizeof (Translated[0]);\r
- Status = TranslateOfwPath (&FwCfgPtr, Translated, &TranslatedSize);\r
+ Status = TranslateOfwPath (&FwCfgPtr, ExtraPciRoots, Translated,\r
+ &TranslatedSize);\r
while (Status == RETURN_SUCCESS ||\r
Status == RETURN_UNSUPPORTED ||\r
+ Status == RETURN_PROTOCOL_ERROR ||\r
Status == RETURN_BUFFER_TOO_SMALL) {\r
if (Status == RETURN_SUCCESS) {\r
UINTN Idx;\r
//\r
Status = BootOrderAppend (&BootOrder, &ActiveOption[Idx]);\r
if (Status != RETURN_SUCCESS) {\r
- goto ErrorFreeActiveOption;\r
+ goto ErrorFreeExtraPciRoots;\r
}\r
break;\r
}\r
} // translation successful\r
\r
TranslatedSize = sizeof (Translated) / sizeof (Translated[0]);\r
- Status = TranslateOfwPath (&FwCfgPtr, Translated, &TranslatedSize);\r
+ Status = TranslateOfwPath (&FwCfgPtr, ExtraPciRoots, Translated,\r
+ &TranslatedSize);\r
} // scanning of OpenFirmware paths done\r
\r
if (Status == RETURN_NOT_FOUND && BootOrder.Produced > 0) {\r
//\r
Status = BootOrderComplete (&BootOrder, ActiveOption, ActiveCount);\r
if (RETURN_ERROR (Status)) {\r
- goto ErrorFreeActiveOption;\r
+ goto ErrorFreeExtraPciRoots;\r
}\r
\r
//\r
);\r
if (EFI_ERROR (Status)) {\r
DEBUG ((DEBUG_ERROR, "%a: setting BootOrder: %r\n", __FUNCTION__, Status));\r
- goto ErrorFreeActiveOption;\r
+ goto ErrorFreeExtraPciRoots;\r
}\r
\r
DEBUG ((DEBUG_INFO, "%a: setting BootOrder: success\n", __FUNCTION__));\r
PruneBootVariables (ActiveOption, ActiveCount);\r
}\r
\r
+ErrorFreeExtraPciRoots:\r
+ if (ExtraPciRoots != NULL) {\r
+ DestroyExtraRootBusMap (ExtraPciRoots);\r
+ }\r
+\r
ErrorFreeActiveOption:\r
FreePool (ActiveOption);\r
\r