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 <lersek@redhat.com>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>

git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17385 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
Laszlo Ersek 2015-05-08 18:12:44 +00:00 committed by lersek
parent 2946ffb6ed
commit feca17fa4b
1 changed files with 92 additions and 26 deletions

View File

@ -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]
);