mirror of https://github.com/acidanthera/audk.git
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:
parent
2946ffb6ed
commit
feca17fa4b
|
@ -33,13 +33,18 @@
|
||||||
**/
|
**/
|
||||||
#define TRANSLATION_OUTPUT_SIZE 0x100
|
#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.
|
Numbers of nodes in OpenFirmware device paths that are required and examined.
|
||||||
**/
|
**/
|
||||||
#define REQUIRED_PCI_OFW_NODES 2
|
#define REQUIRED_PCI_OFW_NODES 2
|
||||||
#define REQUIRED_MMIO_OFW_NODES 1
|
#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
|
IN OUT UINTN *TranslatedSize
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
UINTN FirstNonBridge;
|
||||||
|
CHAR16 Bridges[BRIDGE_TRANSLATION_OUTPUT_SIZE];
|
||||||
|
UINTN BridgesLen;
|
||||||
UINT64 PciDevFun[2];
|
UINT64 PciDevFun[2];
|
||||||
UINTN NumEntries;
|
UINTN NumEntries;
|
||||||
UINTN Written;
|
UINTN Written;
|
||||||
|
@ -593,10 +601,63 @@ TranslatePciOfwNodes (
|
||||||
) {
|
) {
|
||||||
return RETURN_UNSUPPORTED;
|
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;
|
PciDevFun[1] = 0;
|
||||||
NumEntries = sizeof (PciDevFun) / sizeof (PciDevFun[0]);
|
NumEntries = sizeof (PciDevFun) / sizeof (PciDevFun[0]);
|
||||||
if (ParseUnitAddressHexList (
|
if (ParseUnitAddressHexList (
|
||||||
OfwNode[1].UnitAddress,
|
OfwNode[FirstNonBridge].UnitAddress,
|
||||||
PciDevFun,
|
PciDevFun,
|
||||||
&NumEntries
|
&NumEntries
|
||||||
) != RETURN_SUCCESS
|
) != RETURN_SUCCESS
|
||||||
|
@ -604,10 +665,10 @@ TranslatePciOfwNodes (
|
||||||
return RETURN_UNSUPPORTED;
|
return RETURN_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NumNodes >= 4 &&
|
if (NumNodes >= FirstNonBridge + 3 &&
|
||||||
SubstringEq (OfwNode[1].DriverName, "ide") &&
|
SubstringEq (OfwNode[FirstNonBridge + 0].DriverName, "ide") &&
|
||||||
SubstringEq (OfwNode[2].DriverName, "drive") &&
|
SubstringEq (OfwNode[FirstNonBridge + 1].DriverName, "drive") &&
|
||||||
SubstringEq (OfwNode[3].DriverName, "disk")
|
SubstringEq (OfwNode[FirstNonBridge + 2].DriverName, "disk")
|
||||||
) {
|
) {
|
||||||
//
|
//
|
||||||
// OpenFirmware device path (IDE disk, IDE CD-ROM):
|
// OpenFirmware device path (IDE disk, IDE CD-ROM):
|
||||||
|
@ -630,13 +691,13 @@ TranslatePciOfwNodes (
|
||||||
|
|
||||||
NumEntries = 1;
|
NumEntries = 1;
|
||||||
if (ParseUnitAddressHexList (
|
if (ParseUnitAddressHexList (
|
||||||
OfwNode[2].UnitAddress,
|
OfwNode[FirstNonBridge + 1].UnitAddress,
|
||||||
&Secondary,
|
&Secondary,
|
||||||
&NumEntries
|
&NumEntries
|
||||||
) != RETURN_SUCCESS ||
|
) != RETURN_SUCCESS ||
|
||||||
Secondary > 1 ||
|
Secondary > 1 ||
|
||||||
ParseUnitAddressHexList (
|
ParseUnitAddressHexList (
|
||||||
OfwNode[3].UnitAddress,
|
OfwNode[FirstNonBridge + 2].UnitAddress,
|
||||||
&Slave,
|
&Slave,
|
||||||
&NumEntries // reuse after previous single-element call
|
&NumEntries // reuse after previous single-element call
|
||||||
) != RETURN_SUCCESS ||
|
) != RETURN_SUCCESS ||
|
||||||
|
@ -648,16 +709,17 @@ TranslatePciOfwNodes (
|
||||||
Written = UnicodeSPrintAsciiFormat (
|
Written = UnicodeSPrintAsciiFormat (
|
||||||
Translated,
|
Translated,
|
||||||
*TranslatedSize * sizeof (*Translated), // BufferSize in bytes
|
*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[0],
|
||||||
PciDevFun[1],
|
PciDevFun[1],
|
||||||
Secondary ? "Secondary" : "Primary",
|
Secondary ? "Secondary" : "Primary",
|
||||||
Slave ? "Slave" : "Master"
|
Slave ? "Slave" : "Master"
|
||||||
);
|
);
|
||||||
} else if (NumNodes >= 4 &&
|
} else if (NumNodes >= FirstNonBridge + 3 &&
|
||||||
SubstringEq (OfwNode[1].DriverName, "isa") &&
|
SubstringEq (OfwNode[FirstNonBridge + 0].DriverName, "isa") &&
|
||||||
SubstringEq (OfwNode[2].DriverName, "fdc") &&
|
SubstringEq (OfwNode[FirstNonBridge + 1].DriverName, "fdc") &&
|
||||||
SubstringEq (OfwNode[3].DriverName, "floppy")
|
SubstringEq (OfwNode[FirstNonBridge + 2].DriverName, "floppy")
|
||||||
) {
|
) {
|
||||||
//
|
//
|
||||||
// OpenFirmware device path (floppy disk):
|
// OpenFirmware device path (floppy disk):
|
||||||
|
@ -679,7 +741,7 @@ TranslatePciOfwNodes (
|
||||||
|
|
||||||
NumEntries = 1;
|
NumEntries = 1;
|
||||||
if (ParseUnitAddressHexList (
|
if (ParseUnitAddressHexList (
|
||||||
OfwNode[3].UnitAddress,
|
OfwNode[FirstNonBridge + 2].UnitAddress,
|
||||||
&AcpiUid,
|
&AcpiUid,
|
||||||
&NumEntries
|
&NumEntries
|
||||||
) != RETURN_SUCCESS ||
|
) != RETURN_SUCCESS ||
|
||||||
|
@ -691,14 +753,15 @@ TranslatePciOfwNodes (
|
||||||
Written = UnicodeSPrintAsciiFormat (
|
Written = UnicodeSPrintAsciiFormat (
|
||||||
Translated,
|
Translated,
|
||||||
*TranslatedSize * sizeof (*Translated), // BufferSize in bytes
|
*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[0],
|
||||||
PciDevFun[1],
|
PciDevFun[1],
|
||||||
AcpiUid
|
AcpiUid
|
||||||
);
|
);
|
||||||
} else if (NumNodes >= 3 &&
|
} else if (NumNodes >= FirstNonBridge + 2 &&
|
||||||
SubstringEq (OfwNode[1].DriverName, "scsi") &&
|
SubstringEq (OfwNode[FirstNonBridge + 0].DriverName, "scsi") &&
|
||||||
SubstringEq (OfwNode[2].DriverName, "disk")
|
SubstringEq (OfwNode[FirstNonBridge + 1].DriverName, "disk")
|
||||||
) {
|
) {
|
||||||
//
|
//
|
||||||
// OpenFirmware device path (virtio-blk disk):
|
// OpenFirmware device path (virtio-blk disk):
|
||||||
|
@ -718,14 +781,15 @@ TranslatePciOfwNodes (
|
||||||
Written = UnicodeSPrintAsciiFormat (
|
Written = UnicodeSPrintAsciiFormat (
|
||||||
Translated,
|
Translated,
|
||||||
*TranslatedSize * sizeof (*Translated), // BufferSize in bytes
|
*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[0],
|
||||||
PciDevFun[1]
|
PciDevFun[1]
|
||||||
);
|
);
|
||||||
} else if (NumNodes >= 4 &&
|
} else if (NumNodes >= FirstNonBridge + 3 &&
|
||||||
SubstringEq (OfwNode[1].DriverName, "scsi") &&
|
SubstringEq (OfwNode[FirstNonBridge + 0].DriverName, "scsi") &&
|
||||||
SubstringEq (OfwNode[2].DriverName, "channel") &&
|
SubstringEq (OfwNode[FirstNonBridge + 1].DriverName, "channel") &&
|
||||||
SubstringEq (OfwNode[3].DriverName, "disk")
|
SubstringEq (OfwNode[FirstNonBridge + 2].DriverName, "disk")
|
||||||
) {
|
) {
|
||||||
//
|
//
|
||||||
// OpenFirmware device path (virtio-scsi disk):
|
// OpenFirmware device path (virtio-scsi disk):
|
||||||
|
@ -750,7 +814,7 @@ TranslatePciOfwNodes (
|
||||||
TargetLun[1] = 0;
|
TargetLun[1] = 0;
|
||||||
NumEntries = sizeof (TargetLun) / sizeof (TargetLun[0]);
|
NumEntries = sizeof (TargetLun) / sizeof (TargetLun[0]);
|
||||||
if (ParseUnitAddressHexList (
|
if (ParseUnitAddressHexList (
|
||||||
OfwNode[3].UnitAddress,
|
OfwNode[FirstNonBridge + 2].UnitAddress,
|
||||||
TargetLun,
|
TargetLun,
|
||||||
&NumEntries
|
&NumEntries
|
||||||
) != RETURN_SUCCESS
|
) != RETURN_SUCCESS
|
||||||
|
@ -761,7 +825,8 @@ TranslatePciOfwNodes (
|
||||||
Written = UnicodeSPrintAsciiFormat (
|
Written = UnicodeSPrintAsciiFormat (
|
||||||
Translated,
|
Translated,
|
||||||
*TranslatedSize * sizeof (*Translated), // BufferSize in bytes
|
*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[0],
|
||||||
PciDevFun[1],
|
PciDevFun[1],
|
||||||
TargetLun[0],
|
TargetLun[0],
|
||||||
|
@ -784,7 +849,8 @@ TranslatePciOfwNodes (
|
||||||
Written = UnicodeSPrintAsciiFormat (
|
Written = UnicodeSPrintAsciiFormat (
|
||||||
Translated,
|
Translated,
|
||||||
*TranslatedSize * sizeof (*Translated), // BufferSize in bytes
|
*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[0],
|
||||||
PciDevFun[1]
|
PciDevFun[1]
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue