Reviewed-by: Jordan Justen <jordan.l.jus...@intel.com> On 2015-05-05 07:21:34, Laszlo Ersek wrote: > 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 <ler...@redhat.com> > --- > OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.c | 118 > +++++++++++++++----- > 1 file changed, 92 insertions(+), 26 deletions(-) > > diff --git a/OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.c > b/OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.c > index e63ad26..276d675 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] > ); > -- > 1.8.3.1 > > > ------------------------------------------------------------------------------ > One dashboard for servers and applications across Physical-Virtual-Cloud > Widest out-of-the-box monitoring support with 50+ applications > Performance metrics, stats and reports that give you Actionable Insights > Deep dive visibility with transaction tracing using APM Insight. > http://ad.doubleclick.net/ddm/clk/290420510;117567292;y > _______________________________________________ > edk2-devel mailing list > edk2-devel@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/edk2-devel
------------------------------------------------------------------------------ One dashboard for servers and applications across Physical-Virtual-Cloud Widest out-of-the-box monitoring support with 50+ applications Performance metrics, stats and reports that give you Actionable Insights Deep dive visibility with transaction tracing using APM Insight. http://ad.doubleclick.net/ddm/clk/290420510;117567292;y _______________________________________________ edk2-devel mailing list edk2-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/edk2-devel