From 433369169003d4749844615dca4a7239dba8f48b Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Fri, 2 Jan 2015 12:08:19 +0000 Subject: [PATCH] OvmfPkg: QemuBootOrderLib: OFW-to-UEFI translation for virtio-mmio The TranslateMmioOfwNodes() function recognizes the following OpenFirmware device paths: virtio-blk: /virtio-mmio@000000000a003c00/disk@0,0 virtio-scsi disk: /virtio-mmio@000000000a003a00/channel@0/disk@2,3 virtio-net NIC: /virtio-mmio@000000000a003e00/ethernet-phy@0 The new translation can be enabled with the "PcdQemuBootOrderMmioTranslation" Feature PCD. This PCD also controls if the "survival policy" covers unselected boot options that start with the virtio-mmio VenHw() node. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek Acked-by: Jordan Justen git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16575 6f19259b-4bc3-4df7-8a09-765794883524 --- .../QemuBootOrderLib/QemuBootOrderLib.c | 198 +++++++++++++++++- .../QemuBootOrderLib/QemuBootOrderLib.inf | 3 + OvmfPkg/OvmfPkg.dec | 1 + 3 files changed, 201 insertions(+), 1 deletion(-) diff --git a/OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.c b/OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.c index 3599437998..bc2fb56954 100644 --- a/OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.c +++ b/OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.c @@ -23,7 +23,9 @@ #include #include #include +#include #include +#include /** @@ -36,6 +38,7 @@ 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 @@ -801,6 +804,182 @@ TranslatePciOfwNodes ( } +// +// A type providing easy raw access to the base address of a virtio-mmio +// transport. +// +typedef union { + UINT64 Uint64; + UINT8 Raw[8]; +} VIRTIO_MMIO_BASE_ADDRESS; + + +/** + + Translate an MMIO-like array of OpenFirmware device nodes to a UEFI device + path fragment. + + @param[in] OfwNode Array of OpenFirmware device nodes to + translate, constituting the beginning of an + OpenFirmware device path. + + @param[in] NumNodes Number of elements in OfwNode. + + @param[out] Translated Destination array receiving the UEFI path + fragment, allocated by the caller. If the + return value differs from RETURN_SUCCESS, its + contents is indeterminate. + + @param[in out] TranslatedSize On input, the number of CHAR16's in + Translated. On RETURN_SUCCESS this parameter + is assigned the number of non-NUL CHAR16's + written to Translated. In case of other return + values, TranslatedSize is indeterminate. + + + @retval RETURN_SUCCESS Translation successful. + + @retval RETURN_BUFFER_TOO_SMALL The translation does not fit into the number + of bytes provided. + + @retval RETURN_UNSUPPORTED The array of OpenFirmware device nodes can't + be translated in the current implementation. + +**/ +STATIC +RETURN_STATUS +TranslateMmioOfwNodes ( + IN CONST OFW_NODE *OfwNode, + IN UINTN NumNodes, + OUT CHAR16 *Translated, + IN OUT UINTN *TranslatedSize + ) +{ + VIRTIO_MMIO_BASE_ADDRESS VirtioMmioBase; + CHAR16 VenHwString[60 + 1]; + UINTN NumEntries; + UINTN Written; + + // + // Get the base address of the virtio-mmio transport. + // + if (NumNodes < REQUIRED_MMIO_OFW_NODES || + !SubstringEq (OfwNode[0].DriverName, "virtio-mmio") + ) { + return RETURN_UNSUPPORTED; + } + NumEntries = 1; + if (ParseUnitAddressHexList ( + OfwNode[0].UnitAddress, + &VirtioMmioBase.Uint64, + &NumEntries + ) != RETURN_SUCCESS + ) { + return RETURN_UNSUPPORTED; + } + + UnicodeSPrintAsciiFormat (VenHwString, sizeof VenHwString, + "VenHw(%g,%02X%02X%02X%02X%02X%02X%02X%02X)", &gVirtioMmioTransportGuid, + VirtioMmioBase.Raw[0], VirtioMmioBase.Raw[1], VirtioMmioBase.Raw[2], + VirtioMmioBase.Raw[3], VirtioMmioBase.Raw[4], VirtioMmioBase.Raw[5], + VirtioMmioBase.Raw[6], VirtioMmioBase.Raw[7]); + + if (NumNodes >= 2 && + SubstringEq (OfwNode[1].DriverName, "disk")) { + // + // OpenFirmware device path (virtio-blk disk): + // + // /virtio-mmio@000000000a003c00/disk@0,0 + // ^ ^ ^ + // | fixed + // base address of virtio-mmio register block + // + // UEFI device path prefix: + // + // /HD( + // + Written = UnicodeSPrintAsciiFormat ( + Translated, + *TranslatedSize * sizeof (*Translated), // BufferSize in bytes + "%s/HD(", + VenHwString + ); + } else if (NumNodes >= 3 && + SubstringEq (OfwNode[1].DriverName, "channel") && + SubstringEq (OfwNode[2].DriverName, "disk")) { + // + // OpenFirmware device path (virtio-scsi disk): + // + // /virtio-mmio@000000000a003a00/channel@0/disk@2,3 + // ^ ^ ^ ^ + // | | | LUN + // | | target + // | channel (unused, fixed 0) + // base address of virtio-mmio register block + // + // UEFI device path prefix: + // + // /Scsi(0x2,0x3) + // + UINT64 TargetLun[2]; + + TargetLun[1] = 0; + NumEntries = sizeof (TargetLun) / sizeof (TargetLun[0]); + if (ParseUnitAddressHexList ( + OfwNode[2].UnitAddress, + TargetLun, + &NumEntries + ) != RETURN_SUCCESS + ) { + return RETURN_UNSUPPORTED; + } + + Written = UnicodeSPrintAsciiFormat ( + Translated, + *TranslatedSize * sizeof (*Translated), // BufferSize in bytes + "%s/Scsi(0x%Lx,0x%Lx)", + VenHwString, + TargetLun[0], + TargetLun[1] + ); + } else if (NumNodes >= 2 && + SubstringEq (OfwNode[1].DriverName, "ethernet-phy")) { + // + // OpenFirmware device path (virtio-net NIC): + // + // /virtio-mmio@000000000a003e00/ethernet-phy@0 + // ^ ^ + // | fixed + // base address of virtio-mmio register block + // + // UEFI device path prefix (dependent on presence of nonzero PCI function): + // + // /MAC( + // + Written = UnicodeSPrintAsciiFormat ( + Translated, + *TranslatedSize * sizeof (*Translated), // BufferSize in bytes + "%s/MAC(", + VenHwString + ); + } else { + return RETURN_UNSUPPORTED; + } + + // + // There's no way to differentiate between "completely used up without + // truncation" and "truncated", so treat the former as the latter, and return + // success only for "some room left unused". + // + if (Written + 1 < *TranslatedSize) { + *TranslatedSize = Written; + return RETURN_SUCCESS; + } + + return RETURN_BUFFER_TOO_SMALL; +} + + /** Translate an array of OpenFirmware device nodes to a UEFI device path @@ -850,6 +1029,11 @@ TranslateOfwNodes ( Status = TranslatePciOfwNodes (OfwNode, NumNodes, Translated, TranslatedSize); } + if (Status == RETURN_UNSUPPORTED && + FeaturePcdGet (PcdQemuBootOrderMmioTranslation)) { + Status = TranslateMmioOfwNodes (OfwNode, NumNodes, Translated, + TranslatedSize); + } return Status; } @@ -1069,7 +1253,7 @@ Exit: This function should accommodate any further policy changes in "boot option survival". Currently we're adding back everything that starts with neither - PciRoot() nor HD(). + PciRoot() nor HD() nor a virtio-mmio VenHw() node. @param[in,out] BootOrder The structure holding the boot order to complete. The caller is responsible for @@ -1141,6 +1325,18 @@ BootOrderComplete ( // Keep = !FeaturePcdGet (PcdQemuBootOrderPciTranslation); } + } else if (DevicePathType(FirstNode) == HARDWARE_DEVICE_PATH && + DevicePathSubType(FirstNode) == HW_VENDOR_DP) { + VENDOR_DEVICE_PATH *VenHw; + + VenHw = (VENDOR_DEVICE_PATH *)FirstNode; + if (CompareGuid (&VenHw->Guid, &gVirtioMmioTransportGuid)) { + // + // drop virtio-mmio if we enabled the user to select boot options + // referencing such device paths + // + Keep = !FeaturePcdGet (PcdQemuBootOrderMmioTranslation); + } } if (Keep) { diff --git a/OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.inf b/OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.inf index 5aa4e6eff0..6289e6abe6 100644 --- a/OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.inf +++ b/OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.inf @@ -48,9 +48,12 @@ BaseLib PrintLib DevicePathLib + BaseMemoryLib [Guids] gEfiGlobalVariableGuid + gVirtioMmioTransportGuid [FeaturePcd] gUefiOvmfPkgTokenSpaceGuid.PcdQemuBootOrderPciTranslation + gUefiOvmfPkgTokenSpaceGuid.PcdQemuBootOrderMmioTranslation diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec index d61cbd69ec..6eb551a8d4 100644 --- a/OvmfPkg/OvmfPkg.dec +++ b/OvmfPkg/OvmfPkg.dec @@ -105,3 +105,4 @@ [PcdsFeatureFlag] gUefiOvmfPkgTokenSpaceGuid.PcdSecureBootEnable|FALSE|BOOLEAN|3 gUefiOvmfPkgTokenSpaceGuid.PcdQemuBootOrderPciTranslation|TRUE|BOOLEAN|0x1c + gUefiOvmfPkgTokenSpaceGuid.PcdQemuBootOrderMmioTranslation|FALSE|BOOLEAN|0x1d -- 2.39.2