From: Laszlo Ersek Date: Fri, 8 May 2015 18:12:44 +0000 (+0000) Subject: OvmfPkg: QemuBootOrderLib: parse OFW device path nodes of PCI bridges X-Git-Tag: edk2-stable201903~9870 X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=commitdiff_plain;h=feca17fa4bf15b5994d520969a6756fff8f809fb OvmfPkg: QemuBootOrderLib: parse OFW device path nodes of PCI bridges When the Q35 machine type(s) of QEMU are used with libvirt, libvirt tends to place some devices behind PCI bridges. This is then reflected in the "bootorder" fw_cfg file. For example: /pci@i0cf8/pci-bridge@1e/pci-bridge@1/scsi@5/disk@0,0 /pci@i0cf8/pci-bridge@1e/pci-bridge@1/scsi@3/channel@0/disk@0,0 As yet QemuBootOrderLib doesn't support such OFW device paths. Add code that translates a sequence of pci-bridge nodes. In practice libvirt seems to insert two such nodes (*), hence increment EXAMINED_OFW_NODES with the same number. (* Background, paraphrasing Laine Stump's words: When the machine type is Q35, we create a dmi-to-pci bridge coming off of the pcie root controller, and a pci-to-pci bridge coming off of that, then attach most devices to the pci-to-pci bridge. This is done because you can't hotplug into pcie-root, can't (or at least shouldn't) plug a pci-to-pci bridge into pcie-root (so the next one has to be dmi-to-pci-bridge), and can't hotplug into dmi-to-pci-bridge (so you need to have a pci-to-pci bridge).) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek Reviewed-by: Jordan Justen git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17385 6f19259b-4bc3-4df7-8a09-765794883524 --- diff --git a/OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.c b/OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.c index e63ad26224..276d675f50 100644 --- a/OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.c +++ b/OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.c @@ -33,13 +33,18 @@ **/ #define TRANSLATION_OUTPUT_SIZE 0x100 +/** + Output buffer size for OpenFirmware to UEFI device path fragment translation, + in CHAR16's, for a sequence of PCI bridges. +**/ +#define BRIDGE_TRANSLATION_OUTPUT_SIZE 0x40 /** Numbers of nodes in OpenFirmware device paths that are required and examined. **/ #define REQUIRED_PCI_OFW_NODES 2 #define REQUIRED_MMIO_OFW_NODES 1 -#define EXAMINED_OFW_NODES 4 +#define EXAMINED_OFW_NODES 6 /** @@ -581,6 +586,9 @@ TranslatePciOfwNodes ( IN OUT UINTN *TranslatedSize ) { + UINTN FirstNonBridge; + CHAR16 Bridges[BRIDGE_TRANSLATION_OUTPUT_SIZE]; + UINTN BridgesLen; UINT64 PciDevFun[2]; UINTN NumEntries; UINTN Written; @@ -593,10 +601,63 @@ TranslatePciOfwNodes ( ) { return RETURN_UNSUPPORTED; } + + // + // Translate a sequence of PCI bridges. For each bridge, the OFW node is: + // + // pci-bridge@1e[,0] + // ^ ^ + // PCI slot & function on the parent, holding the bridge + // + // and the UEFI device path node is: + // + // Pci(0x1E,0x0) + // + FirstNonBridge = 1; + Bridges[0] = L'\0'; + BridgesLen = 0; + do { + UINT64 BridgeDevFun[2]; + UINTN BridgesFreeBytes; + + if (!SubstringEq (OfwNode[FirstNonBridge].DriverName, "pci-bridge")) { + break; + } + + BridgeDevFun[1] = 0; + NumEntries = sizeof BridgeDevFun / sizeof BridgeDevFun[0]; + if (ParseUnitAddressHexList (OfwNode[FirstNonBridge].UnitAddress, + BridgeDevFun, &NumEntries) != RETURN_SUCCESS) { + return RETURN_UNSUPPORTED; + } + + BridgesFreeBytes = sizeof Bridges - BridgesLen * sizeof Bridges[0]; + Written = UnicodeSPrintAsciiFormat (Bridges + BridgesLen, BridgesFreeBytes, + "/Pci(0x%Lx,0x%Lx)", BridgeDevFun[0], BridgeDevFun[1]); + BridgesLen += Written; + + // + // There's no way to differentiate between "completely used up without + // truncation" and "truncated", so treat the former as the latter. + // + if (BridgesLen + 1 == BRIDGE_TRANSLATION_OUTPUT_SIZE) { + return RETURN_UNSUPPORTED; + } + + ++FirstNonBridge; + } while (FirstNonBridge < NumNodes); + + if (FirstNonBridge == NumNodes) { + return RETURN_UNSUPPORTED; + } + + // + // Parse the OFW nodes starting with the first non-bridge node. + // PciDevFun[1] = 0; NumEntries = sizeof (PciDevFun) / sizeof (PciDevFun[0]); if (ParseUnitAddressHexList ( - OfwNode[1].UnitAddress, + OfwNode[FirstNonBridge].UnitAddress, PciDevFun, &NumEntries ) != RETURN_SUCCESS @@ -604,10 +665,10 @@ TranslatePciOfwNodes ( return RETURN_UNSUPPORTED; } - if (NumNodes >= 4 && - SubstringEq (OfwNode[1].DriverName, "ide") && - SubstringEq (OfwNode[2].DriverName, "drive") && - SubstringEq (OfwNode[3].DriverName, "disk") + if (NumNodes >= FirstNonBridge + 3 && + SubstringEq (OfwNode[FirstNonBridge + 0].DriverName, "ide") && + SubstringEq (OfwNode[FirstNonBridge + 1].DriverName, "drive") && + SubstringEq (OfwNode[FirstNonBridge + 2].DriverName, "disk") ) { // // OpenFirmware device path (IDE disk, IDE CD-ROM): @@ -630,13 +691,13 @@ TranslatePciOfwNodes ( NumEntries = 1; if (ParseUnitAddressHexList ( - OfwNode[2].UnitAddress, + OfwNode[FirstNonBridge + 1].UnitAddress, &Secondary, &NumEntries ) != RETURN_SUCCESS || Secondary > 1 || ParseUnitAddressHexList ( - OfwNode[3].UnitAddress, + OfwNode[FirstNonBridge + 2].UnitAddress, &Slave, &NumEntries // reuse after previous single-element call ) != RETURN_SUCCESS || @@ -648,16 +709,17 @@ TranslatePciOfwNodes ( Written = UnicodeSPrintAsciiFormat ( Translated, *TranslatedSize * sizeof (*Translated), // BufferSize in bytes - "PciRoot(0x0)/Pci(0x%Lx,0x%Lx)/Ata(%a,%a,0x0)", + "PciRoot(0x0)%s/Pci(0x%Lx,0x%Lx)/Ata(%a,%a,0x0)", + Bridges, PciDevFun[0], PciDevFun[1], Secondary ? "Secondary" : "Primary", Slave ? "Slave" : "Master" ); - } else if (NumNodes >= 4 && - SubstringEq (OfwNode[1].DriverName, "isa") && - SubstringEq (OfwNode[2].DriverName, "fdc") && - SubstringEq (OfwNode[3].DriverName, "floppy") + } else if (NumNodes >= FirstNonBridge + 3 && + SubstringEq (OfwNode[FirstNonBridge + 0].DriverName, "isa") && + SubstringEq (OfwNode[FirstNonBridge + 1].DriverName, "fdc") && + SubstringEq (OfwNode[FirstNonBridge + 2].DriverName, "floppy") ) { // // OpenFirmware device path (floppy disk): @@ -679,7 +741,7 @@ TranslatePciOfwNodes ( NumEntries = 1; if (ParseUnitAddressHexList ( - OfwNode[3].UnitAddress, + OfwNode[FirstNonBridge + 2].UnitAddress, &AcpiUid, &NumEntries ) != RETURN_SUCCESS || @@ -691,14 +753,15 @@ TranslatePciOfwNodes ( Written = UnicodeSPrintAsciiFormat ( Translated, *TranslatedSize * sizeof (*Translated), // BufferSize in bytes - "PciRoot(0x0)/Pci(0x%Lx,0x%Lx)/Floppy(0x%Lx)", + "PciRoot(0x0)%s/Pci(0x%Lx,0x%Lx)/Floppy(0x%Lx)", + Bridges, PciDevFun[0], PciDevFun[1], AcpiUid ); - } else if (NumNodes >= 3 && - SubstringEq (OfwNode[1].DriverName, "scsi") && - SubstringEq (OfwNode[2].DriverName, "disk") + } else if (NumNodes >= FirstNonBridge + 2 && + SubstringEq (OfwNode[FirstNonBridge + 0].DriverName, "scsi") && + SubstringEq (OfwNode[FirstNonBridge + 1].DriverName, "disk") ) { // // OpenFirmware device path (virtio-blk disk): @@ -718,14 +781,15 @@ TranslatePciOfwNodes ( Written = UnicodeSPrintAsciiFormat ( Translated, *TranslatedSize * sizeof (*Translated), // BufferSize in bytes - "PciRoot(0x0)/Pci(0x%Lx,0x%Lx)/HD(", + "PciRoot(0x0)%s/Pci(0x%Lx,0x%Lx)/HD(", + Bridges, PciDevFun[0], PciDevFun[1] ); - } else if (NumNodes >= 4 && - SubstringEq (OfwNode[1].DriverName, "scsi") && - SubstringEq (OfwNode[2].DriverName, "channel") && - SubstringEq (OfwNode[3].DriverName, "disk") + } else if (NumNodes >= FirstNonBridge + 3 && + SubstringEq (OfwNode[FirstNonBridge + 0].DriverName, "scsi") && + SubstringEq (OfwNode[FirstNonBridge + 1].DriverName, "channel") && + SubstringEq (OfwNode[FirstNonBridge + 2].DriverName, "disk") ) { // // OpenFirmware device path (virtio-scsi disk): @@ -750,7 +814,7 @@ TranslatePciOfwNodes ( TargetLun[1] = 0; NumEntries = sizeof (TargetLun) / sizeof (TargetLun[0]); if (ParseUnitAddressHexList ( - OfwNode[3].UnitAddress, + OfwNode[FirstNonBridge + 2].UnitAddress, TargetLun, &NumEntries ) != RETURN_SUCCESS @@ -761,7 +825,8 @@ TranslatePciOfwNodes ( Written = UnicodeSPrintAsciiFormat ( Translated, *TranslatedSize * sizeof (*Translated), // BufferSize in bytes - "PciRoot(0x0)/Pci(0x%Lx,0x%Lx)/Scsi(0x%Lx,0x%Lx)", + "PciRoot(0x0)%s/Pci(0x%Lx,0x%Lx)/Scsi(0x%Lx,0x%Lx)", + Bridges, PciDevFun[0], PciDevFun[1], TargetLun[0], @@ -784,7 +849,8 @@ TranslatePciOfwNodes ( Written = UnicodeSPrintAsciiFormat ( Translated, *TranslatedSize * sizeof (*Translated), // BufferSize in bytes - "PciRoot(0x0)/Pci(0x%Lx,0x%Lx)", + "PciRoot(0x0)%s/Pci(0x%Lx,0x%Lx)", + Bridges, PciDevFun[0], PciDevFun[1] );