OvmfPkg, ArmVirtPkg: rename QemuNewBootOrderLib to QemuBootOrderLib
authorLaszlo Ersek <lersek@redhat.com>
Tue, 17 May 2016 17:30:24 +0000 (19:30 +0200)
committerLaszlo Ersek <lersek@redhat.com>
Wed, 25 May 2016 10:25:28 +0000 (12:25 +0200)
This completes the transition to the new BDS.

The FILE_GUID in "QemuBootOrderLib.inf" is intentionally not changed.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Gary Ching-Pang Lin <glin@suse.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ruiyu Ni <ruiyu.ni@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
13 files changed:
ArmVirtPkg/ArmVirtQemu.dsc
ArmVirtPkg/ArmVirtQemuKernel.dsc
OvmfPkg/Library/QemuBootOrderLib/ExtraRootBusMap.c [new file with mode: 0644]
OvmfPkg/Library/QemuBootOrderLib/ExtraRootBusMap.h [new file with mode: 0644]
OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.c [new file with mode: 0644]
OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.inf [new file with mode: 0644]
OvmfPkg/Library/QemuNewBootOrderLib/ExtraRootBusMap.c [deleted file]
OvmfPkg/Library/QemuNewBootOrderLib/ExtraRootBusMap.h [deleted file]
OvmfPkg/Library/QemuNewBootOrderLib/QemuBootOrderLib.c [deleted file]
OvmfPkg/Library/QemuNewBootOrderLib/QemuBootOrderLib.inf [deleted file]
OvmfPkg/OvmfPkgIa32.dsc
OvmfPkg/OvmfPkgIa32X64.dsc
OvmfPkg/OvmfPkgX64.dsc

index d07593b45e2758d40341127f734f8e5889b7669f..cd4a50d5eaa3e0bd0e0594736a265bdf430bd2f9 100644 (file)
@@ -62,7 +62,7 @@
   UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf\r
   PlatformBootManagerLib|ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf\r
   CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf\r
-  QemuBootOrderLib|OvmfPkg/Library/QemuNewBootOrderLib/QemuBootOrderLib.inf\r
+  QemuBootOrderLib|OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.inf\r
   FileExplorerLib|MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf\r
   PciPcdProducerLib|ArmVirtPkg/Library/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf\r
 \r
index 65e6c875204f70cdf1f38e4f3613ec33d0d7de12..9982dee9365d752ea3494158ffb3eebd03286eef 100644 (file)
@@ -61,7 +61,7 @@
   UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf\r
   PlatformBootManagerLib|ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf\r
   CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf\r
-  QemuBootOrderLib|OvmfPkg/Library/QemuNewBootOrderLib/QemuBootOrderLib.inf\r
+  QemuBootOrderLib|OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.inf\r
   FileExplorerLib|MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf\r
   PciPcdProducerLib|ArmVirtPkg/Library/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf\r
 \r
diff --git a/OvmfPkg/Library/QemuBootOrderLib/ExtraRootBusMap.c b/OvmfPkg/Library/QemuBootOrderLib/ExtraRootBusMap.c
new file mode 100644 (file)
index 0000000..ec42214
--- /dev/null
@@ -0,0 +1,313 @@
+/** @file\r
+  Map positions of extra PCI root buses to bus numbers.\r
+\r
+  Copyright (C) 2015, Red Hat, Inc.\r
+\r
+  This program and the accompanying materials are licensed and made available\r
+  under the terms and conditions of the BSD License which accompanies this\r
+  distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
+  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/OrderedCollectionLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Protocol/DevicePath.h>\r
+#include <Protocol/PciRootBridgeIo.h>\r
+\r
+#include "ExtraRootBusMap.h"\r
+\r
+//\r
+// The BusNumbers field is an array with Count elements. The elements increase\r
+// strictry monotonically. Zero is not an element (because the zero bus number\r
+// belongs to the "main" root bus, never to an extra root bus). Offset N in the\r
+// array maps the extra root bus with position (N+1) to its bus number (because\r
+// the root bus with position 0 is always the main root bus, therefore we don't\r
+// store it).\r
+//\r
+// If there are no extra root buses in the system, then Count is 0, and\r
+// BusNumbers is NULL.\r
+//\r
+struct EXTRA_ROOT_BUS_MAP_STRUCT {\r
+  UINT32 *BusNumbers;\r
+  UINTN  Count;\r
+};\r
+\r
+\r
+/**\r
+  An ORDERED_COLLECTION_USER_COMPARE function that compares root bridge\r
+  protocol device paths based on UID.\r
+\r
+  @param[in] UserStruct1  Pointer to the first ACPI_HID_DEVICE_PATH.\r
+\r
+  @param[in] UserStruct2  Pointer to the second ACPI_HID_DEVICE_PATH.\r
+\r
+  @retval <0  If UserStruct1 compares less than UserStruct2.\r
+\r
+  @retval  0  If UserStruct1 compares equal to UserStruct2.\r
+\r
+  @retval >0  If UserStruct1 compares greater than UserStruct2.\r
+**/\r
+STATIC\r
+INTN\r
+EFIAPI\r
+RootBridgePathCompare (\r
+  IN CONST VOID *UserStruct1,\r
+  IN CONST VOID *UserStruct2\r
+  )\r
+{\r
+  CONST ACPI_HID_DEVICE_PATH *Acpi1;\r
+  CONST ACPI_HID_DEVICE_PATH *Acpi2;\r
+\r
+  Acpi1 = UserStruct1;\r
+  Acpi2 = UserStruct2;\r
+\r
+  return Acpi1->UID < Acpi2->UID ? -1 :\r
+         Acpi1->UID > Acpi2->UID ?  1 :\r
+         0;\r
+}\r
+\r
+\r
+/**\r
+  An ORDERED_COLLECTION_KEY_COMPARE function that compares a root bridge\r
+  protocol device path against a UID.\r
+\r
+  @param[in] StandaloneKey  Pointer to the bare UINT32 UID.\r
+\r
+  @param[in] UserStruct     Pointer to the ACPI_HID_DEVICE_PATH with the\r
+                            embedded UINT32 UID.\r
+\r
+  @retval <0  If StandaloneKey compares less than UserStruct's key.\r
+\r
+  @retval  0  If StandaloneKey compares equal to UserStruct's key.\r
+\r
+  @retval >0  If StandaloneKey compares greater than UserStruct's key.\r
+**/\r
+STATIC\r
+INTN\r
+EFIAPI\r
+RootBridgePathKeyCompare (\r
+  IN CONST VOID *StandaloneKey,\r
+  IN CONST VOID *UserStruct\r
+  )\r
+{\r
+  CONST UINT32               *Uid;\r
+  CONST ACPI_HID_DEVICE_PATH *Acpi;\r
+\r
+  Uid  = StandaloneKey;\r
+  Acpi = UserStruct;\r
+\r
+  return *Uid < Acpi->UID ? -1 :\r
+         *Uid > Acpi->UID ?  1 :\r
+         0;\r
+}\r
+\r
+\r
+/**\r
+  Create a structure that maps the relative positions of PCI root buses to bus\r
+  numbers.\r
+\r
+  In the "bootorder" fw_cfg file, QEMU refers to extra PCI root buses by their\r
+  positions, in relative root bus number order, not by their actual PCI bus\r
+  numbers. The ACPI HID device path nodes however that are associated with\r
+  PciRootBridgeIo protocol instances in the system have their UID fields set to\r
+  the bus numbers. Create a map that gives, for each extra PCI root bus's\r
+  position (ie. "serial number") its actual PCI bus number.\r
+\r
+  @param[out] ExtraRootBusMap  The data structure implementing the map.\r
+\r
+  @retval EFI_SUCCESS           ExtraRootBusMap has been populated.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES  Memory allocation failed.\r
+\r
+  @retval EFI_ALREADY_STARTED   A duplicate root bus number has been found in\r
+                                the system. (This should never happen.)\r
+\r
+  @return                       Error codes returned by\r
+                                gBS->LocateHandleBuffer() and\r
+                                gBS->HandleProtocol().\r
+\r
+**/\r
+EFI_STATUS\r
+CreateExtraRootBusMap (\r
+  OUT EXTRA_ROOT_BUS_MAP **ExtraRootBusMap\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  UINTN                    NumHandles;\r
+  EFI_HANDLE               *Handles;\r
+  ORDERED_COLLECTION       *Collection;\r
+  EXTRA_ROOT_BUS_MAP       *Map;\r
+  UINTN                    Idx;\r
+  ORDERED_COLLECTION_ENTRY *Entry, *Entry2;\r
+\r
+  //\r
+  // Handles and Collection are temporary / helper variables, while in Map we\r
+  // build the return value.\r
+  //\r
+\r
+  Status = gBS->LocateHandleBuffer (ByProtocol,\r
+                  &gEfiPciRootBridgeIoProtocolGuid, NULL /* SearchKey */,\r
+                  &NumHandles, &Handles);\r
+  if (EFI_ERROR (Status))  {\r
+    return Status;\r
+  }\r
+\r
+  Collection = OrderedCollectionInit (RootBridgePathCompare,\r
+                 RootBridgePathKeyCompare);\r
+  if (Collection == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto FreeHandles;\r
+  }\r
+\r
+  Map = AllocateZeroPool (sizeof *Map);\r
+  if (Map == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto FreeCollection;\r
+  }\r
+\r
+  //\r
+  // Collect the ACPI device path protocols of the root bridges.\r
+  //\r
+  for (Idx = 0; Idx < NumHandles; ++Idx) {\r
+    EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+\r
+    Status = gBS->HandleProtocol (Handles[Idx], &gEfiDevicePathProtocolGuid,\r
+                    (VOID**)&DevicePath);\r
+    if (EFI_ERROR (Status)) {\r
+      goto FreeMap;\r
+    }\r
+\r
+    //\r
+    // Examine if the device path is an ACPI HID one, and if so, if UID is\r
+    // nonzero (ie. the root bridge that the bus number belongs to is "extra",\r
+    // not the main one). In that case, link the device path into Collection.\r
+    //\r
+    if (DevicePathType (DevicePath) == ACPI_DEVICE_PATH &&\r
+        DevicePathSubType (DevicePath) == ACPI_DP &&\r
+        ((ACPI_HID_DEVICE_PATH *)DevicePath)->HID == EISA_PNP_ID(0x0A03) &&\r
+        ((ACPI_HID_DEVICE_PATH *)DevicePath)->UID > 0) {\r
+      Status = OrderedCollectionInsert (Collection, NULL, DevicePath);\r
+      if (EFI_ERROR (Status)) {\r
+        goto FreeMap;\r
+      }\r
+      ++Map->Count;\r
+    }\r
+  }\r
+\r
+  if (Map->Count > 0) {\r
+    //\r
+    // At least one extra PCI root bus exists.\r
+    //\r
+    Map->BusNumbers = AllocatePool (Map->Count * sizeof *Map->BusNumbers);\r
+    if (Map->BusNumbers == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto FreeMap;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Now collect the bus numbers of the extra PCI root buses into Map.\r
+  //\r
+  Idx = 0;\r
+  Entry = OrderedCollectionMin (Collection);\r
+  while (Idx < Map->Count) {\r
+    ACPI_HID_DEVICE_PATH *Acpi;\r
+\r
+    ASSERT (Entry != NULL);\r
+    Acpi = OrderedCollectionUserStruct (Entry);\r
+    Map->BusNumbers[Idx] = Acpi->UID;\r
+    DEBUG ((EFI_D_VERBOSE,\r
+      "%a: extra bus position 0x%Lx maps to bus number (UID) 0x%x\n",\r
+      __FUNCTION__, (UINT64)(Idx + 1), Acpi->UID));\r
+    ++Idx;\r
+    Entry = OrderedCollectionNext (Entry);\r
+  }\r
+  ASSERT (Entry == NULL);\r
+\r
+  *ExtraRootBusMap = Map;\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  // Fall through in order to release temporaries.\r
+  //\r
+\r
+FreeMap:\r
+  if (EFI_ERROR (Status)) {\r
+    if (Map->BusNumbers != NULL) {\r
+      FreePool (Map->BusNumbers);\r
+    }\r
+    FreePool (Map);\r
+  }\r
+\r
+FreeCollection:\r
+  for (Entry = OrderedCollectionMin (Collection); Entry != NULL;\r
+       Entry = Entry2) {\r
+    Entry2 = OrderedCollectionNext (Entry);\r
+    OrderedCollectionDelete (Collection, Entry, NULL);\r
+  }\r
+  OrderedCollectionUninit (Collection);\r
+\r
+FreeHandles:\r
+  FreePool (Handles);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Release a map created with CreateExtraRootBusMap().\r
+\r
+  @param[in] ExtraRootBusMap  The map to release.\r
+*/\r
+VOID\r
+DestroyExtraRootBusMap (\r
+  IN EXTRA_ROOT_BUS_MAP *ExtraRootBusMap\r
+  )\r
+{\r
+  if (ExtraRootBusMap->BusNumbers != NULL) {\r
+    FreePool (ExtraRootBusMap->BusNumbers);\r
+  }\r
+  FreePool (ExtraRootBusMap);\r
+}\r
+\r
+/**\r
+  Map the position (serial number) of an extra PCI root bus to its bus number.\r
+\r
+  @param[in]  ExtraRootBusMap  The map created with CreateExtraRootBusMap();\r
+\r
+  @param[in]  RootBusPos       The extra PCI root bus position to map.\r
+\r
+  @param[out] RootBusNr        The bus number belonging to the extra PCI root\r
+                               bus identified by RootBusPos.\r
+\r
+  @retval EFI_INVALID_PARAMETER  RootBusPos is zero. The zero position\r
+                                 identifies the main root bus, whose bus number\r
+                                 is always zero, and is therefore never\r
+                                 maintained in ExtraRootBusMap.\r
+\r
+  @retval EFI_NOT_FOUND          RootBusPos is not found in ExtraRootBusMap.\r
+\r
+  @retval EFI_SUCCESS            Mapping successful.\r
+**/\r
+EFI_STATUS\r
+MapRootBusPosToBusNr (\r
+  IN  CONST EXTRA_ROOT_BUS_MAP *ExtraRootBusMap,\r
+  IN  UINT64                   RootBusPos,\r
+  OUT UINT32                   *RootBusNr\r
+  )\r
+{\r
+  if (RootBusPos == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  if (RootBusPos > ExtraRootBusMap->Count) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  *RootBusNr = ExtraRootBusMap->BusNumbers[RootBusPos - 1];\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/OvmfPkg/Library/QemuBootOrderLib/ExtraRootBusMap.h b/OvmfPkg/Library/QemuBootOrderLib/ExtraRootBusMap.h
new file mode 100644 (file)
index 0000000..e2dbc38
--- /dev/null
@@ -0,0 +1,40 @@
+/** @file\r
+  Map positions of extra PCI root buses to bus numbers.\r
+\r
+  Copyright (C) 2015, Red Hat, Inc.\r
+\r
+  This program and the accompanying materials are licensed and made available\r
+  under the terms and conditions of the BSD License which accompanies this\r
+  distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
+  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+\r
+#ifndef __EXTRA_ROOT_BUS_MAP_H__\r
+#define __EXTRA_ROOT_BUS_MAP_H__\r
+\r
+/**\r
+  Incomplete ("opaque") data type implementing the map.\r
+**/\r
+typedef struct EXTRA_ROOT_BUS_MAP_STRUCT EXTRA_ROOT_BUS_MAP;\r
+\r
+EFI_STATUS\r
+CreateExtraRootBusMap (\r
+  OUT EXTRA_ROOT_BUS_MAP **ExtraRootBusMap\r
+  );\r
+\r
+VOID\r
+DestroyExtraRootBusMap (\r
+  IN EXTRA_ROOT_BUS_MAP *ExtraRootBusMap\r
+  );\r
+\r
+EFI_STATUS\r
+MapRootBusPosToBusNr (\r
+  IN  CONST EXTRA_ROOT_BUS_MAP *ExtraRootBusMap,\r
+  IN  UINT64                   RootBusPos,\r
+  OUT UINT32                   *RootBusNr\r
+  );\r
+\r
+#endif\r
diff --git a/OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.c b/OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.c
new file mode 100644 (file)
index 0000000..8608230
--- /dev/null
@@ -0,0 +1,1944 @@
+/** @file\r
+  Rewrite the BootOrder NvVar based on QEMU's "bootorder" fw_cfg file.\r
+\r
+  Copyright (C) 2012 - 2014, Red Hat, Inc.\r
+  Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>\r
+\r
+  This program and the accompanying materials are licensed and made available\r
+  under the terms and conditions of the BSD License which accompanies this\r
+  distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
+  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+\r
+#include <Library/QemuFwCfgLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootManagerLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/QemuBootOrderLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Guid/GlobalVariable.h>\r
+#include <Guid/VirtioMmioTransport.h>\r
+\r
+#include "ExtraRootBusMap.h"\r
+\r
+/**\r
+  OpenFirmware to UEFI device path translation output buffer size in CHAR16's.\r
+**/\r
+#define TRANSLATION_OUTPUT_SIZE 0x100\r
+\r
+/**\r
+  Output buffer size for OpenFirmware to UEFI device path fragment translation,\r
+  in CHAR16's, for a sequence of PCI bridges.\r
+**/\r
+#define BRIDGE_TRANSLATION_OUTPUT_SIZE 0x40\r
+\r
+/**\r
+  Numbers of nodes in OpenFirmware device paths that are required and examined.\r
+**/\r
+#define REQUIRED_PCI_OFW_NODES  2\r
+#define REQUIRED_MMIO_OFW_NODES 1\r
+#define EXAMINED_OFW_NODES      6\r
+\r
+\r
+/**\r
+  Simple character classification routines, corresponding to POSIX class names\r
+  and ASCII encoding.\r
+**/\r
+STATIC\r
+BOOLEAN\r
+IsAlnum (\r
+  IN  CHAR8 Chr\r
+  )\r
+{\r
+  return (('0' <= Chr && Chr <= '9') ||\r
+          ('A' <= Chr && Chr <= 'Z') ||\r
+          ('a' <= Chr && Chr <= 'z')\r
+          );\r
+}\r
+\r
+\r
+STATIC\r
+BOOLEAN\r
+IsDriverNamePunct (\r
+  IN  CHAR8 Chr\r
+  )\r
+{\r
+  return (Chr == ',' ||  Chr == '.' || Chr == '_' ||\r
+          Chr == '+' || Chr == '-'\r
+          );\r
+}\r
+\r
+\r
+STATIC\r
+BOOLEAN\r
+IsPrintNotDelim (\r
+  IN  CHAR8 Chr\r
+  )\r
+{\r
+  return (32 <= Chr && Chr <= 126 &&\r
+          Chr != '/' && Chr != '@' && Chr != ':');\r
+}\r
+\r
+\r
+/**\r
+  Utility types and functions.\r
+**/\r
+typedef struct {\r
+  CONST CHAR8 *Ptr; // not necessarily NUL-terminated\r
+  UINTN       Len;  // number of non-NUL characters\r
+} SUBSTRING;\r
+\r
+\r
+/**\r
+\r
+  Check if Substring and String have identical contents.\r
+\r
+  The function relies on the restriction that a SUBSTRING cannot have embedded\r
+  NULs either.\r
+\r
+  @param[in] Substring  The SUBSTRING input to the comparison.\r
+\r
+  @param[in] String     The ASCII string input to the comparison.\r
+\r
+\r
+  @return  Whether the inputs have identical contents.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+SubstringEq (\r
+  IN  SUBSTRING   Substring,\r
+  IN  CONST CHAR8 *String\r
+  )\r
+{\r
+  UINTN       Pos;\r
+  CONST CHAR8 *Chr;\r
+\r
+  Pos = 0;\r
+  Chr = String;\r
+\r
+  while (Pos < Substring.Len && Substring.Ptr[Pos] == *Chr) {\r
+    ++Pos;\r
+    ++Chr;\r
+  }\r
+\r
+  return (BOOLEAN)(Pos == Substring.Len && *Chr == '\0');\r
+}\r
+\r
+\r
+/**\r
+\r
+  Parse a comma-separated list of hexadecimal integers into the elements of an\r
+  UINT64 array.\r
+\r
+  Whitespace, "0x" prefixes, leading or trailing commas, sequences of commas,\r
+  or an empty string are not allowed; they are rejected.\r
+\r
+  The function relies on ASCII encoding.\r
+\r
+  @param[in]     UnitAddress  The substring to parse.\r
+\r
+  @param[out]    Result       The array, allocated by the caller, to receive\r
+                              the parsed values. This parameter may be NULL if\r
+                              NumResults is zero on input.\r
+\r
+  @param[in out] NumResults   On input, the number of elements allocated for\r
+                              Result. On output, the number of elements it has\r
+                              taken (or would have taken) to parse the string\r
+                              fully.\r
+\r
+\r
+  @retval RETURN_SUCCESS            UnitAddress has been fully parsed.\r
+                                    NumResults is set to the number of parsed\r
+                                    values; the corresponding elements have\r
+                                    been set in Result. The rest of Result's\r
+                                    elements are unchanged.\r
+\r
+  @retval RETURN_BUFFER_TOO_SMALL   UnitAddress has been fully parsed.\r
+                                    NumResults is set to the number of parsed\r
+                                    values, but elements have been stored only\r
+                                    up to the input value of NumResults, which\r
+                                    is less than what has been parsed.\r
+\r
+  @retval RETURN_INVALID_PARAMETER  Parse error. The contents of Results is\r
+                                    indeterminate. NumResults has not been\r
+                                    changed.\r
+\r
+**/\r
+STATIC\r
+RETURN_STATUS\r
+ParseUnitAddressHexList (\r
+  IN      SUBSTRING  UnitAddress,\r
+  OUT     UINT64     *Result,\r
+  IN OUT  UINTN      *NumResults\r
+  )\r
+{\r
+  UINTN         Entry;    // number of entry currently being parsed\r
+  UINT64        EntryVal; // value being constructed for current entry\r
+  CHAR8         PrevChr;  // UnitAddress character previously checked\r
+  UINTN         Pos;      // current position within UnitAddress\r
+  RETURN_STATUS Status;\r
+\r
+  Entry    = 0;\r
+  EntryVal = 0;\r
+  PrevChr  = ',';\r
+\r
+  for (Pos = 0; Pos < UnitAddress.Len; ++Pos) {\r
+    CHAR8 Chr;\r
+    INT8  Val;\r
+\r
+    Chr = UnitAddress.Ptr[Pos];\r
+    Val = ('a' <= Chr && Chr <= 'f') ? (Chr - 'a' + 10) :\r
+          ('A' <= Chr && Chr <= 'F') ? (Chr - 'A' + 10) :\r
+          ('0' <= Chr && Chr <= '9') ? (Chr - '0'     ) :\r
+          -1;\r
+\r
+    if (Val >= 0) {\r
+      if (EntryVal > 0xFFFFFFFFFFFFFFFull) {\r
+        return RETURN_INVALID_PARAMETER;\r
+      }\r
+      EntryVal = LShiftU64 (EntryVal, 4) | Val;\r
+    } else if (Chr == ',') {\r
+      if (PrevChr == ',') {\r
+        return RETURN_INVALID_PARAMETER;\r
+      }\r
+      if (Entry < *NumResults) {\r
+        Result[Entry] = EntryVal;\r
+      }\r
+      ++Entry;\r
+      EntryVal = 0;\r
+    } else {\r
+      return RETURN_INVALID_PARAMETER;\r
+    }\r
+\r
+    PrevChr = Chr;\r
+  }\r
+\r
+  if (PrevChr == ',') {\r
+    return RETURN_INVALID_PARAMETER;\r
+  }\r
+  if (Entry < *NumResults) {\r
+    Result[Entry] = EntryVal;\r
+    Status = RETURN_SUCCESS;\r
+  } else {\r
+    Status = RETURN_BUFFER_TOO_SMALL;\r
+  }\r
+  ++Entry;\r
+\r
+  *NumResults = Entry;\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  A simple array of Boot Option ID's.\r
+**/\r
+typedef struct {\r
+  UINT16 *Data;\r
+  UINTN  Allocated;\r
+  UINTN  Produced;\r
+} BOOT_ORDER;\r
+\r
+\r
+/**\r
+  Array element tracking an enumerated boot option that has the\r
+  LOAD_OPTION_ACTIVE attribute.\r
+**/\r
+typedef struct {\r
+  CONST EFI_BOOT_MANAGER_LOAD_OPTION *BootOption; // reference only, no\r
+                                                  //   ownership\r
+  BOOLEAN                            Appended;    // has been added to a\r
+                                                  //   BOOT_ORDER?\r
+} ACTIVE_OPTION;\r
+\r
+\r
+/**\r
+\r
+  Append an active boot option to BootOrder, reallocating the latter if needed.\r
+\r
+  @param[in out] BootOrder     The structure pointing to the array and holding\r
+                               allocation and usage counters.\r
+\r
+  @param[in]     ActiveOption  The active boot option whose ID should be\r
+                               appended to the array.\r
+\r
+\r
+  @retval RETURN_SUCCESS           ID of ActiveOption appended.\r
+\r
+  @retval RETURN_OUT_OF_RESOURCES  Memory reallocation failed.\r
+\r
+**/\r
+STATIC\r
+RETURN_STATUS\r
+BootOrderAppend (\r
+  IN OUT  BOOT_ORDER    *BootOrder,\r
+  IN OUT  ACTIVE_OPTION *ActiveOption\r
+  )\r
+{\r
+  if (BootOrder->Produced == BootOrder->Allocated) {\r
+    UINTN  AllocatedNew;\r
+    UINT16 *DataNew;\r
+\r
+    ASSERT (BootOrder->Allocated > 0);\r
+    AllocatedNew = BootOrder->Allocated * 2;\r
+    DataNew = ReallocatePool (\r
+                BootOrder->Allocated * sizeof (*BootOrder->Data),\r
+                AllocatedNew         * sizeof (*DataNew),\r
+                BootOrder->Data\r
+                );\r
+    if (DataNew == NULL) {\r
+      return RETURN_OUT_OF_RESOURCES;\r
+    }\r
+    BootOrder->Allocated = AllocatedNew;\r
+    BootOrder->Data      = DataNew;\r
+  }\r
+\r
+  BootOrder->Data[BootOrder->Produced++] =\r
+                               (UINT16) ActiveOption->BootOption->OptionNumber;\r
+  ActiveOption->Appended = TRUE;\r
+  return RETURN_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+\r
+  Create an array of ACTIVE_OPTION elements for a boot option array.\r
+\r
+  @param[in]  BootOptions      A boot option array, created with\r
+                               EfiBootManagerRefreshAllBootOption () and\r
+                               EfiBootManagerGetLoadOptions ().\r
+\r
+  @param[in]  BootOptionCount  The number of elements in BootOptions.\r
+\r
+  @param[out] ActiveOption     Pointer to the first element in the new array.\r
+                               The caller is responsible for freeing the array\r
+                               with FreePool() after use.\r
+\r
+  @param[out] Count            Number of elements in the new array.\r
+\r
+\r
+  @retval RETURN_SUCCESS           The ActiveOption array has been created.\r
+\r
+  @retval RETURN_NOT_FOUND         No active entry has been found in\r
+                                   BootOptions.\r
+\r
+  @retval RETURN_OUT_OF_RESOURCES  Memory allocation failed.\r
+\r
+**/\r
+STATIC\r
+RETURN_STATUS\r
+CollectActiveOptions (\r
+  IN   CONST EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,\r
+  IN   UINTN                              BootOptionCount,\r
+  OUT  ACTIVE_OPTION                      **ActiveOption,\r
+  OUT  UINTN                              *Count\r
+  )\r
+{\r
+  UINTN Index;\r
+  UINTN ScanMode;\r
+\r
+  *ActiveOption = NULL;\r
+\r
+  //\r
+  // Scan the list twice:\r
+  // - count active entries,\r
+  // - store links to active entries.\r
+  //\r
+  for (ScanMode = 0; ScanMode < 2; ++ScanMode) {\r
+    *Count = 0;\r
+    for (Index = 0; Index < BootOptionCount; Index++) {\r
+      if ((BootOptions[Index].Attributes & LOAD_OPTION_ACTIVE) != 0) {\r
+        if (ScanMode == 1) {\r
+          (*ActiveOption)[*Count].BootOption = &BootOptions[Index];\r
+          (*ActiveOption)[*Count].Appended   = FALSE;\r
+        }\r
+        ++*Count;\r
+      }\r
+    }\r
+\r
+    if (ScanMode == 0) {\r
+      if (*Count == 0) {\r
+        return RETURN_NOT_FOUND;\r
+      }\r
+      *ActiveOption = AllocatePool (*Count * sizeof **ActiveOption);\r
+      if (*ActiveOption == NULL) {\r
+        return RETURN_OUT_OF_RESOURCES;\r
+      }\r
+    }\r
+  }\r
+  return RETURN_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  OpenFirmware device path node\r
+**/\r
+typedef struct {\r
+  SUBSTRING DriverName;\r
+  SUBSTRING UnitAddress;\r
+  SUBSTRING DeviceArguments;\r
+} OFW_NODE;\r
+\r
+\r
+/**\r
+\r
+  Parse an OpenFirmware device path node into the caller-allocated OFW_NODE\r
+  structure, and advance in the input string.\r
+\r
+  The node format is mostly parsed after IEEE 1275-1994, 3.2.1.1 "Node names"\r
+  (a leading slash is expected and not returned):\r
+\r
+    /driver-name@unit-address[:device-arguments][<LF>]\r
+\r
+  A single trailing <LF> character is consumed but not returned. A trailing\r
+  <LF> or NUL character terminates the device path.\r
+\r
+  The function relies on ASCII encoding.\r
+\r
+  @param[in out] Ptr      Address of the pointer pointing to the start of the\r
+                          node string. After successful parsing *Ptr is set to\r
+                          the byte immediately following the consumed\r
+                          characters. On error it points to the byte that\r
+                          caused the error. The input string is never modified.\r
+\r
+  @param[out]    OfwNode  The members of this structure point into the input\r
+                          string, designating components of the node.\r
+                          Separators are never included. If "device-arguments"\r
+                          is missing, then DeviceArguments.Ptr is set to NULL.\r
+                          All components that are present have nonzero length.\r
+\r
+                          If the call doesn't succeed, the contents of this\r
+                          structure is indeterminate.\r
+\r
+  @param[out]    IsFinal  In case of successul parsing, this parameter signals\r
+                          whether the node just parsed is the final node in the\r
+                          device path. The call after a final node will attempt\r
+                          to start parsing the next path. If the call doesn't\r
+                          succeed, then this parameter is not changed.\r
+\r
+\r
+  @retval RETURN_SUCCESS            Parsing successful.\r
+\r
+  @retval RETURN_NOT_FOUND          Parsing terminated. *Ptr was (and is)\r
+                                    pointing to an empty string.\r
+\r
+  @retval RETURN_INVALID_PARAMETER  Parse error.\r
+\r
+**/\r
+STATIC\r
+RETURN_STATUS\r
+ParseOfwNode (\r
+  IN OUT  CONST CHAR8 **Ptr,\r
+  OUT     OFW_NODE    *OfwNode,\r
+  OUT     BOOLEAN     *IsFinal\r
+  )\r
+{\r
+  //\r
+  // A leading slash is expected. End of string is tolerated.\r
+  //\r
+  switch (**Ptr) {\r
+  case '\0':\r
+    return RETURN_NOT_FOUND;\r
+\r
+  case '/':\r
+    ++*Ptr;\r
+    break;\r
+\r
+  default:\r
+    return RETURN_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // driver-name\r
+  //\r
+  OfwNode->DriverName.Ptr = *Ptr;\r
+  OfwNode->DriverName.Len = 0;\r
+  while (OfwNode->DriverName.Len < 32 &&\r
+         (IsAlnum (**Ptr) || IsDriverNamePunct (**Ptr))\r
+         ) {\r
+    ++*Ptr;\r
+    ++OfwNode->DriverName.Len;\r
+  }\r
+\r
+  if (OfwNode->DriverName.Len == 0 || OfwNode->DriverName.Len == 32) {\r
+    return RETURN_INVALID_PARAMETER;\r
+  }\r
+\r
+\r
+  //\r
+  // unit-address\r
+  //\r
+  if (**Ptr != '@') {\r
+    return RETURN_INVALID_PARAMETER;\r
+  }\r
+  ++*Ptr;\r
+\r
+  OfwNode->UnitAddress.Ptr = *Ptr;\r
+  OfwNode->UnitAddress.Len = 0;\r
+  while (IsPrintNotDelim (**Ptr)) {\r
+    ++*Ptr;\r
+    ++OfwNode->UnitAddress.Len;\r
+  }\r
+\r
+  if (OfwNode->UnitAddress.Len == 0) {\r
+    return RETURN_INVALID_PARAMETER;\r
+  }\r
+\r
+\r
+  //\r
+  // device-arguments, may be omitted\r
+  //\r
+  OfwNode->DeviceArguments.Len = 0;\r
+  if (**Ptr == ':') {\r
+    ++*Ptr;\r
+    OfwNode->DeviceArguments.Ptr = *Ptr;\r
+\r
+    while (IsPrintNotDelim (**Ptr)) {\r
+      ++*Ptr;\r
+      ++OfwNode->DeviceArguments.Len;\r
+    }\r
+\r
+    if (OfwNode->DeviceArguments.Len == 0) {\r
+      return RETURN_INVALID_PARAMETER;\r
+    }\r
+  }\r
+  else {\r
+    OfwNode->DeviceArguments.Ptr = NULL;\r
+  }\r
+\r
+  switch (**Ptr) {\r
+  case '\n':\r
+    ++*Ptr;\r
+    //\r
+    // fall through\r
+    //\r
+\r
+  case '\0':\r
+    *IsFinal = TRUE;\r
+    break;\r
+\r
+  case '/':\r
+    *IsFinal = FALSE;\r
+    break;\r
+\r
+  default:\r
+    return RETURN_INVALID_PARAMETER;\r
+  }\r
+\r
+  DEBUG ((\r
+    DEBUG_VERBOSE,\r
+    "%a: DriverName=\"%.*a\" UnitAddress=\"%.*a\" DeviceArguments=\"%.*a\"\n",\r
+    __FUNCTION__,\r
+    OfwNode->DriverName.Len, OfwNode->DriverName.Ptr,\r
+    OfwNode->UnitAddress.Len, OfwNode->UnitAddress.Ptr,\r
+    OfwNode->DeviceArguments.Len,\r
+    OfwNode->DeviceArguments.Ptr == NULL ? "" : OfwNode->DeviceArguments.Ptr\r
+    ));\r
+  return RETURN_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+\r
+  Translate a PCI-like array of OpenFirmware device nodes to a UEFI device path\r
+  fragment.\r
+\r
+  @param[in]     OfwNode         Array of OpenFirmware device nodes to\r
+                                 translate, constituting the beginning of an\r
+                                 OpenFirmware device path.\r
+\r
+  @param[in]     NumNodes        Number of elements in OfwNode.\r
+\r
+  @param[in]     ExtraPciRoots   An EXTRA_ROOT_BUS_MAP object created with\r
+                                 CreateExtraRootBusMap(), to be used for\r
+                                 translating positions of extra root buses to\r
+                                 bus numbers.\r
+\r
+  @param[out]    Translated      Destination array receiving the UEFI path\r
+                                 fragment, allocated by the caller. If the\r
+                                 return value differs from RETURN_SUCCESS, its\r
+                                 contents is indeterminate.\r
+\r
+  @param[in out] TranslatedSize  On input, the number of CHAR16's in\r
+                                 Translated. On RETURN_SUCCESS this parameter\r
+                                 is assigned the number of non-NUL CHAR16's\r
+                                 written to Translated. In case of other return\r
+                                 values, TranslatedSize is indeterminate.\r
+\r
+\r
+  @retval RETURN_SUCCESS           Translation successful.\r
+\r
+  @retval RETURN_BUFFER_TOO_SMALL  The translation does not fit into the number\r
+                                   of bytes provided.\r
+\r
+  @retval RETURN_UNSUPPORTED       The array of OpenFirmware device nodes can't\r
+                                   be translated in the current implementation.\r
+\r
+  @retval RETURN_PROTOCOL_ERROR    The initial OpenFirmware node refers to an\r
+                                   extra PCI root bus (by serial number) that\r
+                                   is invalid according to ExtraPciRoots.\r
+\r
+**/\r
+STATIC\r
+RETURN_STATUS\r
+TranslatePciOfwNodes (\r
+  IN      CONST OFW_NODE           *OfwNode,\r
+  IN      UINTN                    NumNodes,\r
+  IN      CONST EXTRA_ROOT_BUS_MAP *ExtraPciRoots,\r
+  OUT     CHAR16                   *Translated,\r
+  IN OUT  UINTN                    *TranslatedSize\r
+  )\r
+{\r
+  UINT32 PciRoot;\r
+  CHAR8  *Comma;\r
+  UINTN  FirstNonBridge;\r
+  CHAR16 Bridges[BRIDGE_TRANSLATION_OUTPUT_SIZE];\r
+  UINTN  BridgesLen;\r
+  UINT64 PciDevFun[2];\r
+  UINTN  NumEntries;\r
+  UINTN  Written;\r
+\r
+  //\r
+  // Resolve the PCI root bus number.\r
+  //\r
+  // The initial OFW node for the main root bus (ie. bus number 0) is:\r
+  //\r
+  //   /pci@i0cf8\r
+  //\r
+  // For extra root buses, the initial OFW node is\r
+  //\r
+  //   /pci@i0cf8,4\r
+  //              ^\r
+  //              root bus serial number (not PCI bus number)\r
+  //\r
+  if (NumNodes < REQUIRED_PCI_OFW_NODES ||\r
+      !SubstringEq (OfwNode[0].DriverName, "pci")\r
+      ) {\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  PciRoot = 0;\r
+  Comma = ScanMem8 (OfwNode[0].UnitAddress.Ptr, OfwNode[0].UnitAddress.Len,\r
+            ',');\r
+  if (Comma != NULL) {\r
+    SUBSTRING PciRootSerialSubString;\r
+    UINT64    PciRootSerial;\r
+\r
+    //\r
+    // Parse the root bus serial number from the unit address after the comma.\r
+    //\r
+    PciRootSerialSubString.Ptr = Comma + 1;\r
+    PciRootSerialSubString.Len = OfwNode[0].UnitAddress.Len -\r
+                                 (PciRootSerialSubString.Ptr -\r
+                                  OfwNode[0].UnitAddress.Ptr);\r
+    NumEntries = 1;\r
+    if (RETURN_ERROR (ParseUnitAddressHexList (PciRootSerialSubString,\r
+                      &PciRootSerial, &NumEntries))) {\r
+      return RETURN_UNSUPPORTED;\r
+    }\r
+\r
+    //\r
+    // Map the extra root bus's serial number to its actual bus number.\r
+    //\r
+    if (EFI_ERROR (MapRootBusPosToBusNr (ExtraPciRoots, PciRootSerial,\r
+                     &PciRoot))) {\r
+      return RETURN_PROTOCOL_ERROR;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Translate a sequence of PCI bridges. For each bridge, the OFW node is:\r
+  //\r
+  //   pci-bridge@1e[,0]\r
+  //              ^   ^\r
+  //              PCI slot & function on the parent, holding the bridge\r
+  //\r
+  // and the UEFI device path node is:\r
+  //\r
+  //   Pci(0x1E,0x0)\r
+  //\r
+  FirstNonBridge = 1;\r
+  Bridges[0] = L'\0';\r
+  BridgesLen = 0;\r
+  do {\r
+    UINT64 BridgeDevFun[2];\r
+    UINTN  BridgesFreeBytes;\r
+\r
+    if (!SubstringEq (OfwNode[FirstNonBridge].DriverName, "pci-bridge")) {\r
+      break;\r
+    }\r
+\r
+    BridgeDevFun[1] = 0;\r
+    NumEntries = sizeof BridgeDevFun / sizeof BridgeDevFun[0];\r
+    if (ParseUnitAddressHexList (OfwNode[FirstNonBridge].UnitAddress,\r
+          BridgeDevFun, &NumEntries) != RETURN_SUCCESS) {\r
+      return RETURN_UNSUPPORTED;\r
+    }\r
+\r
+    BridgesFreeBytes = sizeof Bridges - BridgesLen * sizeof Bridges[0];\r
+    Written = UnicodeSPrintAsciiFormat (Bridges + BridgesLen, BridgesFreeBytes,\r
+                "/Pci(0x%Lx,0x%Lx)", BridgeDevFun[0], BridgeDevFun[1]);\r
+    BridgesLen += Written;\r
+\r
+    //\r
+    // There's no way to differentiate between "completely used up without\r
+    // truncation" and "truncated", so treat the former as the latter.\r
+    //\r
+    if (BridgesLen + 1 == BRIDGE_TRANSLATION_OUTPUT_SIZE) {\r
+      return RETURN_UNSUPPORTED;\r
+    }\r
+\r
+    ++FirstNonBridge;\r
+  } while (FirstNonBridge < NumNodes);\r
+\r
+  if (FirstNonBridge == NumNodes) {\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Parse the OFW nodes starting with the first non-bridge node.\r
+  //\r
+  PciDevFun[1] = 0;\r
+  NumEntries = sizeof (PciDevFun) / sizeof (PciDevFun[0]);\r
+  if (ParseUnitAddressHexList (\r
+        OfwNode[FirstNonBridge].UnitAddress,\r
+        PciDevFun,\r
+        &NumEntries\r
+        ) != RETURN_SUCCESS\r
+      ) {\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  if (NumNodes >= FirstNonBridge + 3 &&\r
+      SubstringEq (OfwNode[FirstNonBridge + 0].DriverName, "ide") &&\r
+      SubstringEq (OfwNode[FirstNonBridge + 1].DriverName, "drive") &&\r
+      SubstringEq (OfwNode[FirstNonBridge + 2].DriverName, "disk")\r
+      ) {\r
+    //\r
+    // OpenFirmware device path (IDE disk, IDE CD-ROM):\r
+    //\r
+    //   /pci@i0cf8/ide@1,1/drive@0/disk@0\r
+    //        ^         ^ ^       ^      ^\r
+    //        |         | |       |      master or slave\r
+    //        |         | |       primary or secondary\r
+    //        |         PCI slot & function holding IDE controller\r
+    //        PCI root at system bus port, PIO\r
+    //\r
+    // UEFI device path:\r
+    //\r
+    //   PciRoot(0x0)/Pci(0x1,0x1)/Ata(Primary,Master,0x0)\r
+    //                                                ^\r
+    //                                                fixed LUN\r
+    //\r
+    UINT64 Secondary;\r
+    UINT64 Slave;\r
+\r
+    NumEntries = 1;\r
+    if (ParseUnitAddressHexList (\r
+          OfwNode[FirstNonBridge + 1].UnitAddress,\r
+          &Secondary,\r
+          &NumEntries\r
+          ) != RETURN_SUCCESS ||\r
+        Secondary > 1 ||\r
+        ParseUnitAddressHexList (\r
+          OfwNode[FirstNonBridge + 2].UnitAddress,\r
+          &Slave,\r
+          &NumEntries // reuse after previous single-element call\r
+          ) != RETURN_SUCCESS ||\r
+        Slave > 1\r
+        ) {\r
+      return RETURN_UNSUPPORTED;\r
+    }\r
+\r
+    Written = UnicodeSPrintAsciiFormat (\r
+      Translated,\r
+      *TranslatedSize * sizeof (*Translated), // BufferSize in bytes\r
+      "PciRoot(0x%x)%s/Pci(0x%Lx,0x%Lx)/Ata(%a,%a,0x0)",\r
+      PciRoot,\r
+      Bridges,\r
+      PciDevFun[0],\r
+      PciDevFun[1],\r
+      Secondary ? "Secondary" : "Primary",\r
+      Slave ? "Slave" : "Master"\r
+      );\r
+  } else if (NumNodes >= FirstNonBridge + 3 &&\r
+      SubstringEq (OfwNode[FirstNonBridge + 0].DriverName, "pci8086,2922") &&\r
+      SubstringEq (OfwNode[FirstNonBridge + 1].DriverName, "drive") &&\r
+      SubstringEq (OfwNode[FirstNonBridge + 2].DriverName, "disk")\r
+      ) {\r
+    //\r
+    // OpenFirmware device path (Q35 SATA disk and CD-ROM):\r
+    //\r
+    //   /pci@i0cf8/pci8086,2922@1f,2/drive@1/disk@0\r
+    //        ^                  ^  ^       ^      ^\r
+    //        |                  |  |       |      device number (fixed 0)\r
+    //        |                  |  |       channel (port) number\r
+    //        |                  PCI slot & function holding SATA HBA\r
+    //        PCI root at system bus port, PIO\r
+    //\r
+    // UEFI device path:\r
+    //\r
+    //   PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x1,0xFFFF,0x0)\r
+    //                                   ^   ^      ^\r
+    //                                   |   |      LUN (always 0 on Q35)\r
+    //                                   |   port multiplier port number,\r
+    //                                   |   always 0xFFFF on Q35\r
+    //                                   channel (port) number\r
+    //\r
+    UINT64 Channel;\r
+\r
+    NumEntries = 1;\r
+    if (RETURN_ERROR (ParseUnitAddressHexList (\r
+                        OfwNode[FirstNonBridge + 1].UnitAddress, &Channel,\r
+                        &NumEntries))) {\r
+      return RETURN_UNSUPPORTED;\r
+    }\r
+\r
+    Written = UnicodeSPrintAsciiFormat (\r
+      Translated,\r
+      *TranslatedSize * sizeof (*Translated), // BufferSize in bytes\r
+      "PciRoot(0x%x)%s/Pci(0x%Lx,0x%Lx)/Sata(0x%Lx,0xFFFF,0x0)",\r
+      PciRoot,\r
+      Bridges,\r
+      PciDevFun[0],\r
+      PciDevFun[1],\r
+      Channel\r
+      );\r
+  } else if (NumNodes >= FirstNonBridge + 3 &&\r
+             SubstringEq (OfwNode[FirstNonBridge + 0].DriverName, "isa") &&\r
+             SubstringEq (OfwNode[FirstNonBridge + 1].DriverName, "fdc") &&\r
+             SubstringEq (OfwNode[FirstNonBridge + 2].DriverName, "floppy")\r
+             ) {\r
+    //\r
+    // OpenFirmware device path (floppy disk):\r
+    //\r
+    //   /pci@i0cf8/isa@1/fdc@03f0/floppy@0\r
+    //        ^         ^     ^           ^\r
+    //        |         |     |           A: or B:\r
+    //        |         |     ISA controller io-port (hex)\r
+    //        |         PCI slot holding ISA controller\r
+    //        PCI root at system bus port, PIO\r
+    //\r
+    // UEFI device path:\r
+    //\r
+    //   PciRoot(0x0)/Pci(0x1,0x0)/Floppy(0x0)\r
+    //                                    ^\r
+    //                                    ACPI UID\r
+    //\r
+    UINT64 AcpiUid;\r
+\r
+    NumEntries = 1;\r
+    if (ParseUnitAddressHexList (\r
+          OfwNode[FirstNonBridge + 2].UnitAddress,\r
+          &AcpiUid,\r
+          &NumEntries\r
+          ) != RETURN_SUCCESS ||\r
+        AcpiUid > 1\r
+        ) {\r
+      return RETURN_UNSUPPORTED;\r
+    }\r
+\r
+    Written = UnicodeSPrintAsciiFormat (\r
+      Translated,\r
+      *TranslatedSize * sizeof (*Translated), // BufferSize in bytes\r
+      "PciRoot(0x%x)%s/Pci(0x%Lx,0x%Lx)/Floppy(0x%Lx)",\r
+      PciRoot,\r
+      Bridges,\r
+      PciDevFun[0],\r
+      PciDevFun[1],\r
+      AcpiUid\r
+      );\r
+  } else if (NumNodes >= FirstNonBridge + 2 &&\r
+             SubstringEq (OfwNode[FirstNonBridge + 0].DriverName, "scsi") &&\r
+             SubstringEq (OfwNode[FirstNonBridge + 1].DriverName, "disk")\r
+             ) {\r
+    //\r
+    // OpenFirmware device path (virtio-blk disk):\r
+    //\r
+    //   /pci@i0cf8/scsi@6[,3]/disk@0,0\r
+    //        ^          ^  ^       ^ ^\r
+    //        |          |  |       fixed\r
+    //        |          |  PCI function corresponding to disk (optional)\r
+    //        |          PCI slot holding disk\r
+    //        PCI root at system bus port, PIO\r
+    //\r
+    // UEFI device path prefix:\r
+    //\r
+    //   PciRoot(0x0)/Pci(0x6,0x0)/HD( -- if PCI function is 0 or absent\r
+    //   PciRoot(0x0)/Pci(0x6,0x3)/HD( -- if PCI function is present and nonzero\r
+    //\r
+    Written = UnicodeSPrintAsciiFormat (\r
+      Translated,\r
+      *TranslatedSize * sizeof (*Translated), // BufferSize in bytes\r
+      "PciRoot(0x%x)%s/Pci(0x%Lx,0x%Lx)/HD(",\r
+      PciRoot,\r
+      Bridges,\r
+      PciDevFun[0],\r
+      PciDevFun[1]\r
+      );\r
+  } else if (NumNodes >= FirstNonBridge + 3 &&\r
+             SubstringEq (OfwNode[FirstNonBridge + 0].DriverName, "scsi") &&\r
+             SubstringEq (OfwNode[FirstNonBridge + 1].DriverName, "channel") &&\r
+             SubstringEq (OfwNode[FirstNonBridge + 2].DriverName, "disk")\r
+             ) {\r
+    //\r
+    // OpenFirmware device path (virtio-scsi disk):\r
+    //\r
+    //   /pci@i0cf8/scsi@7[,3]/channel@0/disk@2,3\r
+    //        ^          ^             ^      ^ ^\r
+    //        |          |             |      | LUN\r
+    //        |          |             |      target\r
+    //        |          |             channel (unused, fixed 0)\r
+    //        |          PCI slot[, function] holding SCSI controller\r
+    //        PCI root at system bus port, PIO\r
+    //\r
+    // UEFI device path prefix:\r
+    //\r
+    //   PciRoot(0x0)/Pci(0x7,0x0)/Scsi(0x2,0x3)\r
+    //                                        -- if PCI function is 0 or absent\r
+    //   PciRoot(0x0)/Pci(0x7,0x3)/Scsi(0x2,0x3)\r
+    //                                -- if PCI function is present and nonzero\r
+    //\r
+    UINT64 TargetLun[2];\r
+\r
+    TargetLun[1] = 0;\r
+    NumEntries = sizeof (TargetLun) / sizeof (TargetLun[0]);\r
+    if (ParseUnitAddressHexList (\r
+          OfwNode[FirstNonBridge + 2].UnitAddress,\r
+          TargetLun,\r
+          &NumEntries\r
+          ) != RETURN_SUCCESS\r
+        ) {\r
+      return RETURN_UNSUPPORTED;\r
+    }\r
+\r
+    Written = UnicodeSPrintAsciiFormat (\r
+      Translated,\r
+      *TranslatedSize * sizeof (*Translated), // BufferSize in bytes\r
+      "PciRoot(0x%x)%s/Pci(0x%Lx,0x%Lx)/Scsi(0x%Lx,0x%Lx)",\r
+      PciRoot,\r
+      Bridges,\r
+      PciDevFun[0],\r
+      PciDevFun[1],\r
+      TargetLun[0],\r
+      TargetLun[1]\r
+      );\r
+  } else if (NumNodes >= FirstNonBridge + 2 &&\r
+      SubstringEq (OfwNode[FirstNonBridge + 0].DriverName, "pci8086,5845") &&\r
+      SubstringEq (OfwNode[FirstNonBridge + 1].DriverName, "namespace")\r
+      ) {\r
+    //\r
+    // OpenFirmware device path (NVMe device):\r
+    //\r
+    //   /pci@i0cf8/pci8086,5845@6[,1]/namespace@1,0\r
+    //        ^                  ^  ^            ^ ^\r
+    //        |                  |  |            | Extended Unique Identifier\r
+    //        |                  |  |            | (EUI-64), big endian interp.\r
+    //        |                  |  |            namespace ID\r
+    //        |                  PCI slot & function holding NVMe controller\r
+    //        PCI root at system bus port, PIO\r
+    //\r
+    // UEFI device path:\r
+    //\r
+    //   PciRoot(0x0)/Pci(0x6,0x1)/NVMe(0x1,00-00-00-00-00-00-00-00)\r
+    //                                  ^   ^\r
+    //                                  |   octets of the EUI-64\r
+    //                                  |   in address order\r
+    //                                  namespace ID\r
+    //\r
+    UINT64 Namespace[2];\r
+    UINTN  RequiredEntries;\r
+    UINT8  *Eui64;\r
+\r
+    RequiredEntries = sizeof (Namespace) / sizeof (Namespace[0]);\r
+    NumEntries = RequiredEntries;\r
+    if (ParseUnitAddressHexList (\r
+          OfwNode[FirstNonBridge + 1].UnitAddress,\r
+          Namespace,\r
+          &NumEntries\r
+          ) != RETURN_SUCCESS ||\r
+        NumEntries != RequiredEntries ||\r
+        Namespace[0] == 0 ||\r
+        Namespace[0] >= MAX_UINT32\r
+        ) {\r
+      return RETURN_UNSUPPORTED;\r
+    }\r
+\r
+    Eui64 = (UINT8 *)&Namespace[1];\r
+    Written = UnicodeSPrintAsciiFormat (\r
+      Translated,\r
+      *TranslatedSize * sizeof (*Translated), // BufferSize in bytes\r
+      "PciRoot(0x%x)%s/Pci(0x%Lx,0x%Lx)/"\r
+      "NVMe(0x%Lx,%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x)",\r
+      PciRoot,\r
+      Bridges,\r
+      PciDevFun[0],\r
+      PciDevFun[1],\r
+      Namespace[0],\r
+      Eui64[7], Eui64[6], Eui64[5], Eui64[4],\r
+      Eui64[3], Eui64[2], Eui64[1], Eui64[0]\r
+      );\r
+  } else {\r
+    //\r
+    // Generic OpenFirmware device path for PCI devices:\r
+    //\r
+    //   /pci@i0cf8/ethernet@3[,2]\r
+    //        ^              ^\r
+    //        |              PCI slot[, function] holding Ethernet card\r
+    //        PCI root at system bus port, PIO\r
+    //\r
+    // UEFI device path prefix (dependent on presence of nonzero PCI function):\r
+    //\r
+    //   PciRoot(0x0)/Pci(0x3,0x0)\r
+    //   PciRoot(0x0)/Pci(0x3,0x2)\r
+    //\r
+    Written = UnicodeSPrintAsciiFormat (\r
+      Translated,\r
+      *TranslatedSize * sizeof (*Translated), // BufferSize in bytes\r
+      "PciRoot(0x%x)%s/Pci(0x%Lx,0x%Lx)",\r
+      PciRoot,\r
+      Bridges,\r
+      PciDevFun[0],\r
+      PciDevFun[1]\r
+      );\r
+  }\r
+\r
+  //\r
+  // There's no way to differentiate between "completely used up without\r
+  // truncation" and "truncated", so treat the former as the latter, and return\r
+  // success only for "some room left unused".\r
+  //\r
+  if (Written + 1 < *TranslatedSize) {\r
+    *TranslatedSize = Written;\r
+    return RETURN_SUCCESS;\r
+  }\r
+\r
+  return RETURN_BUFFER_TOO_SMALL;\r
+}\r
+\r
+\r
+//\r
+// A type providing easy raw access to the base address of a virtio-mmio\r
+// transport.\r
+//\r
+typedef union {\r
+  UINT64 Uint64;\r
+  UINT8  Raw[8];\r
+} VIRTIO_MMIO_BASE_ADDRESS;\r
+\r
+\r
+/**\r
+\r
+  Translate an MMIO-like array of OpenFirmware device nodes to a UEFI device\r
+  path fragment.\r
+\r
+  @param[in]     OfwNode         Array of OpenFirmware device nodes to\r
+                                 translate, constituting the beginning of an\r
+                                 OpenFirmware device path.\r
+\r
+  @param[in]     NumNodes        Number of elements in OfwNode.\r
+\r
+  @param[out]    Translated      Destination array receiving the UEFI path\r
+                                 fragment, allocated by the caller. If the\r
+                                 return value differs from RETURN_SUCCESS, its\r
+                                 contents is indeterminate.\r
+\r
+  @param[in out] TranslatedSize  On input, the number of CHAR16's in\r
+                                 Translated. On RETURN_SUCCESS this parameter\r
+                                 is assigned the number of non-NUL CHAR16's\r
+                                 written to Translated. In case of other return\r
+                                 values, TranslatedSize is indeterminate.\r
+\r
+\r
+  @retval RETURN_SUCCESS           Translation successful.\r
+\r
+  @retval RETURN_BUFFER_TOO_SMALL  The translation does not fit into the number\r
+                                   of bytes provided.\r
+\r
+  @retval RETURN_UNSUPPORTED       The array of OpenFirmware device nodes can't\r
+                                   be translated in the current implementation.\r
+\r
+**/\r
+STATIC\r
+RETURN_STATUS\r
+TranslateMmioOfwNodes (\r
+  IN      CONST OFW_NODE *OfwNode,\r
+  IN      UINTN          NumNodes,\r
+  OUT     CHAR16         *Translated,\r
+  IN OUT  UINTN          *TranslatedSize\r
+  )\r
+{\r
+  VIRTIO_MMIO_BASE_ADDRESS VirtioMmioBase;\r
+  CHAR16                   VenHwString[60 + 1];\r
+  UINTN                    NumEntries;\r
+  UINTN                    Written;\r
+\r
+  //\r
+  // Get the base address of the virtio-mmio transport.\r
+  //\r
+  if (NumNodes < REQUIRED_MMIO_OFW_NODES ||\r
+      !SubstringEq (OfwNode[0].DriverName, "virtio-mmio")\r
+      ) {\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+  NumEntries = 1;\r
+  if (ParseUnitAddressHexList (\r
+        OfwNode[0].UnitAddress,\r
+        &VirtioMmioBase.Uint64,\r
+        &NumEntries\r
+        ) != RETURN_SUCCESS\r
+      ) {\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  UnicodeSPrintAsciiFormat (VenHwString, sizeof VenHwString,\r
+    "VenHw(%g,%02X%02X%02X%02X%02X%02X%02X%02X)", &gVirtioMmioTransportGuid,\r
+    VirtioMmioBase.Raw[0], VirtioMmioBase.Raw[1], VirtioMmioBase.Raw[2],\r
+    VirtioMmioBase.Raw[3], VirtioMmioBase.Raw[4], VirtioMmioBase.Raw[5],\r
+    VirtioMmioBase.Raw[6], VirtioMmioBase.Raw[7]);\r
+\r
+  if (NumNodes >= 2 &&\r
+      SubstringEq (OfwNode[1].DriverName, "disk")) {\r
+    //\r
+    // OpenFirmware device path (virtio-blk disk):\r
+    //\r
+    //   /virtio-mmio@000000000a003c00/disk@0,0\r
+    //                ^                     ^ ^\r
+    //                |                     fixed\r
+    //                base address of virtio-mmio register block\r
+    //\r
+    // UEFI device path prefix:\r
+    //\r
+    //   <VenHwString>/HD(\r
+    //\r
+    Written = UnicodeSPrintAsciiFormat (\r
+                Translated,\r
+                *TranslatedSize * sizeof (*Translated), // BufferSize in bytes\r
+                "%s/HD(",\r
+                VenHwString\r
+                );\r
+  } else if (NumNodes >= 3 &&\r
+             SubstringEq (OfwNode[1].DriverName, "channel") &&\r
+             SubstringEq (OfwNode[2].DriverName, "disk")) {\r
+    //\r
+    // OpenFirmware device path (virtio-scsi disk):\r
+    //\r
+    //   /virtio-mmio@000000000a003a00/channel@0/disk@2,3\r
+    //                ^                        ^      ^ ^\r
+    //                |                        |      | LUN\r
+    //                |                        |      target\r
+    //                |                        channel (unused, fixed 0)\r
+    //                base address of virtio-mmio register block\r
+    //\r
+    // UEFI device path prefix:\r
+    //\r
+    //   <VenHwString>/Scsi(0x2,0x3)\r
+    //\r
+    UINT64 TargetLun[2];\r
+\r
+    TargetLun[1] = 0;\r
+    NumEntries = sizeof (TargetLun) / sizeof (TargetLun[0]);\r
+    if (ParseUnitAddressHexList (\r
+          OfwNode[2].UnitAddress,\r
+          TargetLun,\r
+          &NumEntries\r
+          ) != RETURN_SUCCESS\r
+        ) {\r
+      return RETURN_UNSUPPORTED;\r
+    }\r
+\r
+    Written = UnicodeSPrintAsciiFormat (\r
+                Translated,\r
+                *TranslatedSize * sizeof (*Translated), // BufferSize in bytes\r
+                "%s/Scsi(0x%Lx,0x%Lx)",\r
+                VenHwString,\r
+                TargetLun[0],\r
+                TargetLun[1]\r
+                );\r
+  } else if (NumNodes >= 2 &&\r
+             SubstringEq (OfwNode[1].DriverName, "ethernet-phy")) {\r
+    //\r
+    // OpenFirmware device path (virtio-net NIC):\r
+    //\r
+    //   /virtio-mmio@000000000a003e00/ethernet-phy@0\r
+    //                ^                             ^\r
+    //                |                             fixed\r
+    //                base address of virtio-mmio register block\r
+    //\r
+    // UEFI device path prefix (dependent on presence of nonzero PCI function):\r
+    //\r
+    //   <VenHwString>/MAC(\r
+    //\r
+    Written = UnicodeSPrintAsciiFormat (\r
+                Translated,\r
+                *TranslatedSize * sizeof (*Translated), // BufferSize in bytes\r
+                "%s/MAC(",\r
+                VenHwString\r
+                );\r
+  } else {\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // There's no way to differentiate between "completely used up without\r
+  // truncation" and "truncated", so treat the former as the latter, and return\r
+  // success only for "some room left unused".\r
+  //\r
+  if (Written + 1 < *TranslatedSize) {\r
+    *TranslatedSize = Written;\r
+    return RETURN_SUCCESS;\r
+  }\r
+\r
+  return RETURN_BUFFER_TOO_SMALL;\r
+}\r
+\r
+\r
+/**\r
+\r
+  Translate an array of OpenFirmware device nodes to a UEFI device path\r
+  fragment.\r
+\r
+  @param[in]     OfwNode         Array of OpenFirmware device nodes to\r
+                                 translate, constituting the beginning of an\r
+                                 OpenFirmware device path.\r
+\r
+  @param[in]     NumNodes        Number of elements in OfwNode.\r
+\r
+  @param[in]     ExtraPciRoots   An EXTRA_ROOT_BUS_MAP object created with\r
+                                 CreateExtraRootBusMap(), to be used for\r
+                                 translating positions of extra root buses to\r
+                                 bus numbers.\r
+\r
+  @param[out]    Translated      Destination array receiving the UEFI path\r
+                                 fragment, allocated by the caller. If the\r
+                                 return value differs from RETURN_SUCCESS, its\r
+                                 contents is indeterminate.\r
+\r
+  @param[in out] TranslatedSize  On input, the number of CHAR16's in\r
+                                 Translated. On RETURN_SUCCESS this parameter\r
+                                 is assigned the number of non-NUL CHAR16's\r
+                                 written to Translated. In case of other return\r
+                                 values, TranslatedSize is indeterminate.\r
+\r
+\r
+  @retval RETURN_SUCCESS           Translation successful.\r
+\r
+  @retval RETURN_BUFFER_TOO_SMALL  The translation does not fit into the number\r
+                                   of bytes provided.\r
+\r
+  @retval RETURN_UNSUPPORTED       The array of OpenFirmware device nodes can't\r
+                                   be translated in the current implementation.\r
+\r
+  @retval RETURN_PROTOCOL_ERROR    The array of OpenFirmware device nodes has\r
+                                   been (partially) recognized, but it contains\r
+                                   a logic error / doesn't match system state.\r
+\r
+**/\r
+STATIC\r
+RETURN_STATUS\r
+TranslateOfwNodes (\r
+  IN      CONST OFW_NODE           *OfwNode,\r
+  IN      UINTN                    NumNodes,\r
+  IN      CONST EXTRA_ROOT_BUS_MAP *ExtraPciRoots,\r
+  OUT     CHAR16                   *Translated,\r
+  IN OUT  UINTN                    *TranslatedSize\r
+  )\r
+{\r
+  RETURN_STATUS Status;\r
+\r
+  Status = RETURN_UNSUPPORTED;\r
+\r
+  if (FeaturePcdGet (PcdQemuBootOrderPciTranslation)) {\r
+    Status = TranslatePciOfwNodes (OfwNode, NumNodes, ExtraPciRoots,\r
+               Translated, TranslatedSize);\r
+  }\r
+  if (Status == RETURN_UNSUPPORTED &&\r
+      FeaturePcdGet (PcdQemuBootOrderMmioTranslation)) {\r
+    Status = TranslateMmioOfwNodes (OfwNode, NumNodes, Translated,\r
+               TranslatedSize);\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+\r
+  Translate an OpenFirmware device path fragment to a UEFI device path\r
+  fragment, and advance in the input string.\r
+\r
+  @param[in out] Ptr             Address of the pointer pointing to the start\r
+                                 of the path string. After successful\r
+                                 translation (RETURN_SUCCESS) or at least\r
+                                 successful parsing (RETURN_UNSUPPORTED,\r
+                                 RETURN_BUFFER_TOO_SMALL), *Ptr is set to the\r
+                                 byte immediately following the consumed\r
+                                 characters. In other error cases, it points to\r
+                                 the byte that caused the error.\r
+\r
+  @param[in]     ExtraPciRoots   An EXTRA_ROOT_BUS_MAP object created with\r
+                                 CreateExtraRootBusMap(), to be used for\r
+                                 translating positions of extra root buses to\r
+                                 bus numbers.\r
+\r
+  @param[out]    Translated      Destination array receiving the UEFI path\r
+                                 fragment, allocated by the caller. If the\r
+                                 return value differs from RETURN_SUCCESS, its\r
+                                 contents is indeterminate.\r
+\r
+  @param[in out] TranslatedSize  On input, the number of CHAR16's in\r
+                                 Translated. On RETURN_SUCCESS this parameter\r
+                                 is assigned the number of non-NUL CHAR16's\r
+                                 written to Translated. In case of other return\r
+                                 values, TranslatedSize is indeterminate.\r
+\r
+\r
+  @retval RETURN_SUCCESS            Translation successful.\r
+\r
+  @retval RETURN_BUFFER_TOO_SMALL   The OpenFirmware device path was parsed\r
+                                    successfully, but its translation did not\r
+                                    fit into the number of bytes provided.\r
+                                    Further calls to this function are\r
+                                    possible.\r
+\r
+  @retval RETURN_UNSUPPORTED        The OpenFirmware device path was parsed\r
+                                    successfully, but it can't be translated in\r
+                                    the current implementation. Further calls\r
+                                    to this function are possible.\r
+\r
+  @retval RETURN_PROTOCOL_ERROR     The OpenFirmware device path has been\r
+                                    (partially) recognized, but it contains a\r
+                                    logic error / doesn't match system state.\r
+                                    Further calls to this function are\r
+                                    possible.\r
+\r
+  @retval RETURN_NOT_FOUND          Translation terminated. On input, *Ptr was\r
+                                    pointing to the empty string or "HALT". On\r
+                                    output, *Ptr points to the empty string\r
+                                    (ie. "HALT" is consumed transparently when\r
+                                    present).\r
+\r
+  @retval RETURN_INVALID_PARAMETER  Parse error. This is a permanent error.\r
+\r
+**/\r
+STATIC\r
+RETURN_STATUS\r
+TranslateOfwPath (\r
+  IN OUT  CONST CHAR8              **Ptr,\r
+  IN      CONST EXTRA_ROOT_BUS_MAP *ExtraPciRoots,\r
+  OUT     CHAR16                   *Translated,\r
+  IN OUT  UINTN                    *TranslatedSize\r
+  )\r
+{\r
+  UINTN         NumNodes;\r
+  RETURN_STATUS Status;\r
+  OFW_NODE      Node[EXAMINED_OFW_NODES];\r
+  BOOLEAN       IsFinal;\r
+  OFW_NODE      Skip;\r
+\r
+  IsFinal = FALSE;\r
+  NumNodes = 0;\r
+  if (AsciiStrCmp (*Ptr, "HALT") == 0) {\r
+    *Ptr += 4;\r
+    Status = RETURN_NOT_FOUND;\r
+  } else {\r
+    Status = ParseOfwNode (Ptr, &Node[NumNodes], &IsFinal);\r
+  }\r
+\r
+  if (Status == RETURN_NOT_FOUND) {\r
+    DEBUG ((DEBUG_VERBOSE, "%a: no more nodes\n", __FUNCTION__));\r
+    return RETURN_NOT_FOUND;\r
+  }\r
+\r
+  while (Status == RETURN_SUCCESS && !IsFinal) {\r
+    ++NumNodes;\r
+    Status = ParseOfwNode (\r
+               Ptr,\r
+               (NumNodes < EXAMINED_OFW_NODES) ? &Node[NumNodes] : &Skip,\r
+               &IsFinal\r
+               );\r
+  }\r
+\r
+  switch (Status) {\r
+  case RETURN_SUCCESS:\r
+    ++NumNodes;\r
+    break;\r
+\r
+  case RETURN_INVALID_PARAMETER:\r
+    DEBUG ((DEBUG_VERBOSE, "%a: parse error\n", __FUNCTION__));\r
+    return RETURN_INVALID_PARAMETER;\r
+\r
+  default:\r
+    ASSERT (0);\r
+  }\r
+\r
+  Status = TranslateOfwNodes (\r
+             Node,\r
+             NumNodes < EXAMINED_OFW_NODES ? NumNodes : EXAMINED_OFW_NODES,\r
+             ExtraPciRoots,\r
+             Translated,\r
+             TranslatedSize);\r
+  switch (Status) {\r
+  case RETURN_SUCCESS:\r
+    DEBUG ((DEBUG_VERBOSE, "%a: success: \"%s\"\n", __FUNCTION__, Translated));\r
+    break;\r
+\r
+  case RETURN_BUFFER_TOO_SMALL:\r
+    DEBUG ((DEBUG_VERBOSE, "%a: buffer too small\n", __FUNCTION__));\r
+    break;\r
+\r
+  case RETURN_UNSUPPORTED:\r
+    DEBUG ((DEBUG_VERBOSE, "%a: unsupported\n", __FUNCTION__));\r
+    break;\r
+\r
+  case RETURN_PROTOCOL_ERROR:\r
+    DEBUG ((DEBUG_VERBOSE, "%a: logic error / system state mismatch\n",\r
+      __FUNCTION__));\r
+    break;\r
+\r
+  default:\r
+    ASSERT (0);\r
+  }\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+\r
+  Convert the UEFI DevicePath to full text representation with DevPathToText,\r
+  then match the UEFI device path fragment in Translated against it.\r
+\r
+  @param[in] Translated        UEFI device path fragment, translated from\r
+                               OpenFirmware format, to search for.\r
+\r
+  @param[in] TranslatedLength  The length of Translated in CHAR16's.\r
+\r
+  @param[in] DevicePath        Boot option device path whose textual rendering\r
+                               to search in.\r
+\r
+  @param[in] DevPathToText  Binary-to-text conversion protocol for DevicePath.\r
+\r
+\r
+  @retval TRUE   If Translated was found at the beginning of DevicePath after\r
+                 converting the latter to text.\r
+\r
+  @retval FALSE  If DevicePath was NULL, or it could not be converted, or there\r
+                 was no match.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+Match (\r
+  IN  CONST CHAR16                           *Translated,\r
+  IN  UINTN                                  TranslatedLength,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL               *DevicePath\r
+  )\r
+{\r
+  CHAR16                   *Converted;\r
+  BOOLEAN                  Result;\r
+  VOID                     *FileBuffer;\r
+  UINTN                    FileSize;\r
+  EFI_DEVICE_PATH_PROTOCOL *AbsDevicePath;\r
+  CHAR16                   *AbsConverted;\r
+  BOOLEAN                  Shortform;\r
+  EFI_DEVICE_PATH_PROTOCOL *Node;\r
+\r
+  Converted = ConvertDevicePathToText (\r
+                DevicePath,\r
+                FALSE, // DisplayOnly\r
+                FALSE  // AllowShortcuts\r
+                );\r
+  if (Converted == NULL) {\r
+    return FALSE;\r
+  }\r
+\r
+  Result = FALSE;\r
+  Shortform = FALSE;\r
+  //\r
+  // Expand the short-form device path to full device path\r
+  //\r
+  if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&\r
+      (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)) {\r
+    //\r
+    // Harddrive shortform device path\r
+    //\r
+    Shortform = TRUE;\r
+  } else if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&\r
+             (DevicePathSubType (DevicePath) == MEDIA_FILEPATH_DP)) {\r
+    //\r
+    // File-path shortform device path\r
+    //\r
+    Shortform = TRUE;\r
+  } else if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&\r
+             (DevicePathSubType (DevicePath) == MSG_URI_DP)) {\r
+    //\r
+    // URI shortform device path\r
+    //\r
+    Shortform = TRUE;\r
+  } else {\r
+    for ( Node = DevicePath\r
+        ; !IsDevicePathEnd (Node)\r
+        ; Node = NextDevicePathNode (Node)\r
+        ) {\r
+      if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) &&\r
+          ((DevicePathSubType (Node) == MSG_USB_CLASS_DP) ||\r
+           (DevicePathSubType (Node) == MSG_USB_WWID_DP))) {\r
+        Shortform = TRUE;\r
+        break;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Attempt to expand any relative UEFI device path to\r
+  // an absolute device path first.\r
+  //\r
+  if (Shortform) {\r
+    FileBuffer = EfiBootManagerGetLoadOptionBuffer (\r
+                   DevicePath, &AbsDevicePath, &FileSize\r
+                   );\r
+    if (FileBuffer == NULL) {\r
+      goto Exit;\r
+    }\r
+    FreePool (FileBuffer);\r
+    AbsConverted = ConvertDevicePathToText (AbsDevicePath, FALSE, FALSE);\r
+    FreePool (AbsDevicePath);\r
+    if (AbsConverted == NULL) {\r
+      goto Exit;\r
+    }\r
+    DEBUG ((DEBUG_VERBOSE,\r
+      "%a: expanded relative device path \"%s\" for prefix matching\n",\r
+      __FUNCTION__, Converted));\r
+    FreePool (Converted);\r
+    Converted = AbsConverted;\r
+  }\r
+\r
+  //\r
+  // Is Translated a prefix of Converted?\r
+  //\r
+  Result = (BOOLEAN)(StrnCmp (Converted, Translated, TranslatedLength) == 0);\r
+  DEBUG ((\r
+    DEBUG_VERBOSE,\r
+    "%a: against \"%s\": %a\n",\r
+    __FUNCTION__,\r
+    Converted,\r
+    Result ? "match" : "no match"\r
+    ));\r
+Exit:\r
+  FreePool (Converted);\r
+  return Result;\r
+}\r
+\r
+\r
+/**\r
+  Append some of the unselected active boot options to the boot order.\r
+\r
+  This function should accommodate any further policy changes in "boot option\r
+  survival". Currently we're adding back everything that starts with neither\r
+  PciRoot() nor HD() nor a virtio-mmio VenHw() node.\r
+\r
+  @param[in,out] BootOrder     The structure holding the boot order to\r
+                               complete. The caller is responsible for\r
+                               initializing (and potentially populating) it\r
+                               before calling this function.\r
+\r
+  @param[in,out] ActiveOption  The array of active boot options to scan.\r
+                               Entries marked as Appended will be skipped.\r
+                               Those of the rest that satisfy the survival\r
+                               policy will be added to BootOrder with\r
+                               BootOrderAppend().\r
+\r
+  @param[in]     ActiveCount   Number of elements in ActiveOption.\r
+\r
+\r
+  @retval RETURN_SUCCESS  BootOrder has been extended with any eligible boot\r
+                          options.\r
+\r
+  @return                 Error codes returned by BootOrderAppend().\r
+**/\r
+STATIC\r
+RETURN_STATUS\r
+BootOrderComplete (\r
+  IN OUT  BOOT_ORDER    *BootOrder,\r
+  IN OUT  ACTIVE_OPTION *ActiveOption,\r
+  IN      UINTN         ActiveCount\r
+  )\r
+{\r
+  RETURN_STATUS Status;\r
+  UINTN         Idx;\r
+\r
+  Status = RETURN_SUCCESS;\r
+  Idx = 0;\r
+  while (!RETURN_ERROR (Status) && Idx < ActiveCount) {\r
+    if (!ActiveOption[Idx].Appended) {\r
+      CONST EFI_BOOT_MANAGER_LOAD_OPTION *Current;\r
+      CONST EFI_DEVICE_PATH_PROTOCOL     *FirstNode;\r
+\r
+      Current = ActiveOption[Idx].BootOption;\r
+      FirstNode = Current->FilePath;\r
+      if (FirstNode != NULL) {\r
+        CHAR16        *Converted;\r
+        STATIC CHAR16 ConvFallBack[] = L"<unable to convert>";\r
+        BOOLEAN       Keep;\r
+\r
+        Converted = ConvertDevicePathToText (FirstNode, FALSE, FALSE);\r
+        if (Converted == NULL) {\r
+          Converted = ConvFallBack;\r
+        }\r
+\r
+        Keep = TRUE;\r
+        if (DevicePathType(FirstNode) == MEDIA_DEVICE_PATH &&\r
+            DevicePathSubType(FirstNode) == MEDIA_HARDDRIVE_DP) {\r
+          //\r
+          // drop HD()\r
+          //\r
+          Keep = FALSE;\r
+        } else if (DevicePathType(FirstNode) == ACPI_DEVICE_PATH &&\r
+                   DevicePathSubType(FirstNode) == ACPI_DP) {\r
+          ACPI_HID_DEVICE_PATH *Acpi;\r
+\r
+          Acpi = (ACPI_HID_DEVICE_PATH *) FirstNode;\r
+          if ((Acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST &&\r
+              EISA_ID_TO_NUM (Acpi->HID) == 0x0a03) {\r
+            //\r
+            // drop PciRoot() if we enabled the user to select PCI-like boot\r
+            // options, by providing translation for such OFW device path\r
+            // fragments\r
+            //\r
+            Keep = !FeaturePcdGet (PcdQemuBootOrderPciTranslation);\r
+          }\r
+        } else if (DevicePathType(FirstNode) == HARDWARE_DEVICE_PATH &&\r
+                   DevicePathSubType(FirstNode) == HW_VENDOR_DP) {\r
+          VENDOR_DEVICE_PATH *VenHw;\r
+\r
+          VenHw = (VENDOR_DEVICE_PATH *)FirstNode;\r
+          if (CompareGuid (&VenHw->Guid, &gVirtioMmioTransportGuid)) {\r
+            //\r
+            // drop virtio-mmio if we enabled the user to select boot options\r
+            // referencing such device paths\r
+            //\r
+            Keep = !FeaturePcdGet (PcdQemuBootOrderMmioTranslation);\r
+          }\r
+        }\r
+\r
+        if (Keep) {\r
+          Status = BootOrderAppend (BootOrder, &ActiveOption[Idx]);\r
+          if (!RETURN_ERROR (Status)) {\r
+            DEBUG ((DEBUG_VERBOSE, "%a: keeping \"%s\"\n", __FUNCTION__,\r
+              Converted));\r
+          }\r
+        } else {\r
+          DEBUG ((DEBUG_VERBOSE, "%a: dropping \"%s\"\n", __FUNCTION__,\r
+            Converted));\r
+        }\r
+\r
+        if (Converted != ConvFallBack) {\r
+          FreePool (Converted);\r
+        }\r
+      }\r
+    }\r
+    ++Idx;\r
+  }\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Delete Boot#### variables that stand for such active boot options that have\r
+  been dropped (ie. have not been selected by either matching or "survival\r
+  policy").\r
+\r
+  @param[in]  ActiveOption  The array of active boot options to scan. Each\r
+                            entry not marked as appended will trigger the\r
+                            deletion of the matching Boot#### variable.\r
+\r
+  @param[in]  ActiveCount   Number of elements in ActiveOption.\r
+**/\r
+STATIC\r
+VOID\r
+PruneBootVariables (\r
+  IN  CONST ACTIVE_OPTION *ActiveOption,\r
+  IN  UINTN               ActiveCount\r
+  )\r
+{\r
+  UINTN Idx;\r
+\r
+  for (Idx = 0; Idx < ActiveCount; ++Idx) {\r
+    if (!ActiveOption[Idx].Appended) {\r
+      CHAR16 VariableName[9];\r
+\r
+      UnicodeSPrintAsciiFormat (VariableName, sizeof VariableName, "Boot%04x",\r
+        ActiveOption[Idx].BootOption->OptionNumber);\r
+\r
+      //\r
+      // "The space consumed by the deleted variable may not be available until\r
+      // the next power cycle", but that's good enough.\r
+      //\r
+      gRT->SetVariable (VariableName, &gEfiGlobalVariableGuid,\r
+             0,   // Attributes, 0 means deletion\r
+             0,   // DataSize, 0 means deletion\r
+             NULL // Data\r
+             );\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/**\r
+\r
+  Set the boot order based on configuration retrieved from QEMU.\r
+\r
+  Attempt to retrieve the "bootorder" fw_cfg file from QEMU. Translate the\r
+  OpenFirmware device paths therein to UEFI device path fragments. Match the\r
+  translated fragments against the current list of boot options, and rewrite\r
+  the BootOrder NvVar so that it corresponds to the order described in fw_cfg.\r
+\r
+  Platform BDS should call this function after EfiBootManagerConnectAll () and\r
+  EfiBootManagerRefreshAllBootOption () return.\r
+\r
+  @retval RETURN_SUCCESS            BootOrder NvVar rewritten.\r
+\r
+  @retval RETURN_UNSUPPORTED        QEMU's fw_cfg is not supported.\r
+\r
+  @retval RETURN_NOT_FOUND          Empty or nonexistent "bootorder" fw_cfg\r
+                                    file, or no match found between the\r
+                                    "bootorder" fw_cfg file and BootOptionList.\r
+\r
+  @retval RETURN_INVALID_PARAMETER  Parse error in the "bootorder" fw_cfg file.\r
+\r
+  @retval RETURN_OUT_OF_RESOURCES   Memory allocation failed.\r
+\r
+  @return                           Values returned by gBS->LocateProtocol ()\r
+                                    or gRT->SetVariable ().\r
+\r
+**/\r
+RETURN_STATUS\r
+SetBootOrderFromQemu (\r
+  VOID\r
+  )\r
+{\r
+  RETURN_STATUS                    Status;\r
+  FIRMWARE_CONFIG_ITEM             FwCfgItem;\r
+  UINTN                            FwCfgSize;\r
+  CHAR8                            *FwCfg;\r
+  CONST CHAR8                      *FwCfgPtr;\r
+\r
+  BOOT_ORDER                       BootOrder;\r
+  ACTIVE_OPTION                    *ActiveOption;\r
+  UINTN                            ActiveCount;\r
+\r
+  EXTRA_ROOT_BUS_MAP               *ExtraPciRoots;\r
+\r
+  UINTN                            TranslatedSize;\r
+  CHAR16                           Translated[TRANSLATION_OUTPUT_SIZE];\r
+  EFI_BOOT_MANAGER_LOAD_OPTION     *BootOptions;\r
+  UINTN                            BootOptionCount;\r
+\r
+  Status = QemuFwCfgFindFile ("bootorder", &FwCfgItem, &FwCfgSize);\r
+  if (Status != RETURN_SUCCESS) {\r
+    return Status;\r
+  }\r
+\r
+  if (FwCfgSize == 0) {\r
+    return RETURN_NOT_FOUND;\r
+  }\r
+\r
+  FwCfg = AllocatePool (FwCfgSize);\r
+  if (FwCfg == NULL) {\r
+    return RETURN_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  QemuFwCfgSelectItem (FwCfgItem);\r
+  QemuFwCfgReadBytes (FwCfgSize, FwCfg);\r
+  if (FwCfg[FwCfgSize - 1] != '\0') {\r
+    Status = RETURN_INVALID_PARAMETER;\r
+    goto ErrorFreeFwCfg;\r
+  }\r
+\r
+  DEBUG ((DEBUG_VERBOSE, "%a: FwCfg:\n", __FUNCTION__));\r
+  DEBUG ((DEBUG_VERBOSE, "%a\n", FwCfg));\r
+  DEBUG ((DEBUG_VERBOSE, "%a: FwCfg: <end>\n", __FUNCTION__));\r
+  FwCfgPtr = FwCfg;\r
+\r
+  BootOrder.Produced  = 0;\r
+  BootOrder.Allocated = 1;\r
+  BootOrder.Data = AllocatePool (\r
+                     BootOrder.Allocated * sizeof (*BootOrder.Data)\r
+                     );\r
+  if (BootOrder.Data == NULL) {\r
+    Status = RETURN_OUT_OF_RESOURCES;\r
+    goto ErrorFreeFwCfg;\r
+  }\r
+\r
+  BootOptions = EfiBootManagerGetLoadOptions (\r
+                  &BootOptionCount, LoadOptionTypeBoot\r
+                  );\r
+  if (BootOptions == NULL) {\r
+    Status = RETURN_NOT_FOUND;\r
+    goto ErrorFreeBootOrder;\r
+  }\r
+\r
+  Status = CollectActiveOptions (\r
+             BootOptions, BootOptionCount, &ActiveOption, &ActiveCount\r
+             );\r
+  if (RETURN_ERROR (Status)) {\r
+    goto ErrorFreeBootOptions;\r
+  }\r
+\r
+  if (FeaturePcdGet (PcdQemuBootOrderPciTranslation)) {\r
+    Status = CreateExtraRootBusMap (&ExtraPciRoots);\r
+    if (EFI_ERROR (Status)) {\r
+      goto ErrorFreeActiveOption;\r
+    }\r
+  } else {\r
+    ExtraPciRoots = NULL;\r
+  }\r
+\r
+  //\r
+  // translate each OpenFirmware path\r
+  //\r
+  TranslatedSize = sizeof (Translated) / sizeof (Translated[0]);\r
+  Status = TranslateOfwPath (&FwCfgPtr, ExtraPciRoots, Translated,\r
+             &TranslatedSize);\r
+  while (Status == RETURN_SUCCESS ||\r
+         Status == RETURN_UNSUPPORTED ||\r
+         Status == RETURN_PROTOCOL_ERROR ||\r
+         Status == RETURN_BUFFER_TOO_SMALL) {\r
+    if (Status == RETURN_SUCCESS) {\r
+      UINTN Idx;\r
+\r
+      //\r
+      // match translated OpenFirmware path against all active boot options\r
+      //\r
+      for (Idx = 0; Idx < ActiveCount; ++Idx) {\r
+        if (Match (\r
+              Translated,\r
+              TranslatedSize, // contains length, not size, in CHAR16's here\r
+              ActiveOption[Idx].BootOption->FilePath\r
+              )\r
+            ) {\r
+          //\r
+          // match found, store ID and continue with next OpenFirmware path\r
+          //\r
+          Status = BootOrderAppend (&BootOrder, &ActiveOption[Idx]);\r
+          if (Status != RETURN_SUCCESS) {\r
+            goto ErrorFreeExtraPciRoots;\r
+          }\r
+          break;\r
+        }\r
+      } // scanned all active boot options\r
+    }   // translation successful\r
+\r
+    TranslatedSize = sizeof (Translated) / sizeof (Translated[0]);\r
+    Status = TranslateOfwPath (&FwCfgPtr, ExtraPciRoots, Translated,\r
+               &TranslatedSize);\r
+  } // scanning of OpenFirmware paths done\r
+\r
+  if (Status == RETURN_NOT_FOUND && BootOrder.Produced > 0) {\r
+    //\r
+    // No more OpenFirmware paths, some matches found: rewrite BootOrder NvVar.\r
+    // Some of the active boot options that have not been selected over fw_cfg\r
+    // should be preserved at the end of the boot order.\r
+    //\r
+    Status = BootOrderComplete (&BootOrder, ActiveOption, ActiveCount);\r
+    if (RETURN_ERROR (Status)) {\r
+      goto ErrorFreeExtraPciRoots;\r
+    }\r
+\r
+    //\r
+    // See Table 10 in the UEFI Spec 2.3.1 with Errata C for the required\r
+    // attributes.\r
+    //\r
+    Status = gRT->SetVariable (\r
+                    L"BootOrder",\r
+                    &gEfiGlobalVariableGuid,\r
+                    EFI_VARIABLE_NON_VOLATILE |\r
+                      EFI_VARIABLE_BOOTSERVICE_ACCESS |\r
+                      EFI_VARIABLE_RUNTIME_ACCESS,\r
+                    BootOrder.Produced * sizeof (*BootOrder.Data),\r
+                    BootOrder.Data\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((DEBUG_ERROR, "%a: setting BootOrder: %r\n", __FUNCTION__, Status));\r
+      goto ErrorFreeExtraPciRoots;\r
+    }\r
+\r
+    DEBUG ((DEBUG_INFO, "%a: setting BootOrder: success\n", __FUNCTION__));\r
+    PruneBootVariables (ActiveOption, ActiveCount);\r
+  }\r
+\r
+ErrorFreeExtraPciRoots:\r
+  if (ExtraPciRoots != NULL) {\r
+    DestroyExtraRootBusMap (ExtraPciRoots);\r
+  }\r
+\r
+ErrorFreeActiveOption:\r
+  FreePool (ActiveOption);\r
+\r
+ErrorFreeBootOptions:\r
+  EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
+\r
+ErrorFreeBootOrder:\r
+  FreePool (BootOrder.Data);\r
+\r
+ErrorFreeFwCfg:\r
+  FreePool (FwCfg);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Calculate the number of seconds we should be showing the FrontPage progress\r
+  bar for.\r
+\r
+  @return  The TimeoutDefault argument for PlatformBdsEnterFrontPage().\r
+**/\r
+UINT16\r
+GetFrontPageTimeoutFromQemu (\r
+  VOID\r
+  )\r
+{\r
+  FIRMWARE_CONFIG_ITEM BootMenuWaitItem;\r
+  UINTN                BootMenuWaitSize;\r
+\r
+  QemuFwCfgSelectItem (QemuFwCfgItemBootMenu);\r
+  if (QemuFwCfgRead16 () == 0) {\r
+    //\r
+    // The user specified "-boot menu=off", or didn't specify "-boot\r
+    // menu=(on|off)" at all. Return the platform default.\r
+    //\r
+    return PcdGet16 (PcdPlatformBootTimeOut);\r
+  }\r
+\r
+  if (RETURN_ERROR (QemuFwCfgFindFile ("etc/boot-menu-wait", &BootMenuWaitItem,\r
+                      &BootMenuWaitSize)) ||\r
+      BootMenuWaitSize != sizeof (UINT16)) {\r
+    //\r
+    // "-boot menu=on" was specified without "splash-time=N". In this case,\r
+    // return three seconds if the platform default would cause us to skip the\r
+    // front page, and return the platform default otherwise.\r
+    //\r
+    UINT16 Timeout;\r
+\r
+    Timeout = PcdGet16 (PcdPlatformBootTimeOut);\r
+    if (Timeout == 0) {\r
+      Timeout = 3;\r
+    }\r
+    return Timeout;\r
+  }\r
+\r
+  //\r
+  // "-boot menu=on,splash-time=N" was specified, where N is in units of\r
+  // milliseconds. The Intel BDS Front Page progress bar only supports whole\r
+  // seconds, round N up.\r
+  //\r
+  QemuFwCfgSelectItem (BootMenuWaitItem);\r
+  return (UINT16)((QemuFwCfgRead16 () + 999) / 1000);\r
+}\r
diff --git a/OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.inf b/OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.inf
new file mode 100644 (file)
index 0000000..eec938f
--- /dev/null
@@ -0,0 +1,68 @@
+## @file\r
+#  Rewrite the BootOrder NvVar based on QEMU's "bootorder" fw_cfg file.\r
+#\r
+#  Copyright (C) 2012 - 2014, Red Hat, Inc.\r
+#  Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>\r
+#\r
+#  This program and the accompanying materials are licensed and made available\r
+#  under the terms and conditions of the BSD License which accompanies this\r
+#  distribution.  The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\r
+#\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR\r
+#  IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = QemuBootOrderLib\r
+  FILE_GUID                      = 1D677A58-C753-4AF1-B552-EFE142DF8F57\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  LIBRARY_CLASS                  = QemuBootOrderLib|DXE_DRIVER\r
+\r
+#\r
+# The following information is for reference only and not required by the build\r
+# tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC ARM AARCH64\r
+#\r
+\r
+[Sources]\r
+  QemuBootOrderLib.c\r
+  ExtraRootBusMap.c\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  OvmfPkg/OvmfPkg.dec\r
+\r
+[LibraryClasses]\r
+  QemuFwCfgLib\r
+  DebugLib\r
+  MemoryAllocationLib\r
+  UefiBootManagerLib\r
+  UefiBootServicesTableLib\r
+  UefiRuntimeServicesTableLib\r
+  BaseLib\r
+  PrintLib\r
+  DevicePathLib\r
+  BaseMemoryLib\r
+  OrderedCollectionLib\r
+\r
+[Guids]\r
+  gEfiGlobalVariableGuid\r
+  gVirtioMmioTransportGuid\r
+\r
+[FeaturePcd]\r
+  gUefiOvmfPkgTokenSpaceGuid.PcdQemuBootOrderPciTranslation\r
+  gUefiOvmfPkgTokenSpaceGuid.PcdQemuBootOrderMmioTranslation\r
+\r
+[Pcd]\r
+  gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut\r
+\r
+[Protocols]\r
+  gEfiDevicePathProtocolGuid                            ## CONSUMES\r
+  gEfiPciRootBridgeIoProtocolGuid                       ## CONSUMES\r
diff --git a/OvmfPkg/Library/QemuNewBootOrderLib/ExtraRootBusMap.c b/OvmfPkg/Library/QemuNewBootOrderLib/ExtraRootBusMap.c
deleted file mode 100644 (file)
index ec42214..0000000
+++ /dev/null
@@ -1,313 +0,0 @@
-/** @file\r
-  Map positions of extra PCI root buses to bus numbers.\r
-\r
-  Copyright (C) 2015, Red Hat, Inc.\r
-\r
-  This program and the accompanying materials are licensed and made available\r
-  under the terms and conditions of the BSD License which accompanies this\r
-  distribution.  The full text of the license may be found at\r
-  http://opensource.org/licenses/bsd-license.php\r
-\r
-  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
-  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-**/\r
-\r
-#include <Library/DebugLib.h>\r
-#include <Library/DevicePathLib.h>\r
-#include <Library/MemoryAllocationLib.h>\r
-#include <Library/OrderedCollectionLib.h>\r
-#include <Library/UefiBootServicesTableLib.h>\r
-#include <Protocol/DevicePath.h>\r
-#include <Protocol/PciRootBridgeIo.h>\r
-\r
-#include "ExtraRootBusMap.h"\r
-\r
-//\r
-// The BusNumbers field is an array with Count elements. The elements increase\r
-// strictry monotonically. Zero is not an element (because the zero bus number\r
-// belongs to the "main" root bus, never to an extra root bus). Offset N in the\r
-// array maps the extra root bus with position (N+1) to its bus number (because\r
-// the root bus with position 0 is always the main root bus, therefore we don't\r
-// store it).\r
-//\r
-// If there are no extra root buses in the system, then Count is 0, and\r
-// BusNumbers is NULL.\r
-//\r
-struct EXTRA_ROOT_BUS_MAP_STRUCT {\r
-  UINT32 *BusNumbers;\r
-  UINTN  Count;\r
-};\r
-\r
-\r
-/**\r
-  An ORDERED_COLLECTION_USER_COMPARE function that compares root bridge\r
-  protocol device paths based on UID.\r
-\r
-  @param[in] UserStruct1  Pointer to the first ACPI_HID_DEVICE_PATH.\r
-\r
-  @param[in] UserStruct2  Pointer to the second ACPI_HID_DEVICE_PATH.\r
-\r
-  @retval <0  If UserStruct1 compares less than UserStruct2.\r
-\r
-  @retval  0  If UserStruct1 compares equal to UserStruct2.\r
-\r
-  @retval >0  If UserStruct1 compares greater than UserStruct2.\r
-**/\r
-STATIC\r
-INTN\r
-EFIAPI\r
-RootBridgePathCompare (\r
-  IN CONST VOID *UserStruct1,\r
-  IN CONST VOID *UserStruct2\r
-  )\r
-{\r
-  CONST ACPI_HID_DEVICE_PATH *Acpi1;\r
-  CONST ACPI_HID_DEVICE_PATH *Acpi2;\r
-\r
-  Acpi1 = UserStruct1;\r
-  Acpi2 = UserStruct2;\r
-\r
-  return Acpi1->UID < Acpi2->UID ? -1 :\r
-         Acpi1->UID > Acpi2->UID ?  1 :\r
-         0;\r
-}\r
-\r
-\r
-/**\r
-  An ORDERED_COLLECTION_KEY_COMPARE function that compares a root bridge\r
-  protocol device path against a UID.\r
-\r
-  @param[in] StandaloneKey  Pointer to the bare UINT32 UID.\r
-\r
-  @param[in] UserStruct     Pointer to the ACPI_HID_DEVICE_PATH with the\r
-                            embedded UINT32 UID.\r
-\r
-  @retval <0  If StandaloneKey compares less than UserStruct's key.\r
-\r
-  @retval  0  If StandaloneKey compares equal to UserStruct's key.\r
-\r
-  @retval >0  If StandaloneKey compares greater than UserStruct's key.\r
-**/\r
-STATIC\r
-INTN\r
-EFIAPI\r
-RootBridgePathKeyCompare (\r
-  IN CONST VOID *StandaloneKey,\r
-  IN CONST VOID *UserStruct\r
-  )\r
-{\r
-  CONST UINT32               *Uid;\r
-  CONST ACPI_HID_DEVICE_PATH *Acpi;\r
-\r
-  Uid  = StandaloneKey;\r
-  Acpi = UserStruct;\r
-\r
-  return *Uid < Acpi->UID ? -1 :\r
-         *Uid > Acpi->UID ?  1 :\r
-         0;\r
-}\r
-\r
-\r
-/**\r
-  Create a structure that maps the relative positions of PCI root buses to bus\r
-  numbers.\r
-\r
-  In the "bootorder" fw_cfg file, QEMU refers to extra PCI root buses by their\r
-  positions, in relative root bus number order, not by their actual PCI bus\r
-  numbers. The ACPI HID device path nodes however that are associated with\r
-  PciRootBridgeIo protocol instances in the system have their UID fields set to\r
-  the bus numbers. Create a map that gives, for each extra PCI root bus's\r
-  position (ie. "serial number") its actual PCI bus number.\r
-\r
-  @param[out] ExtraRootBusMap  The data structure implementing the map.\r
-\r
-  @retval EFI_SUCCESS           ExtraRootBusMap has been populated.\r
-\r
-  @retval EFI_OUT_OF_RESOURCES  Memory allocation failed.\r
-\r
-  @retval EFI_ALREADY_STARTED   A duplicate root bus number has been found in\r
-                                the system. (This should never happen.)\r
-\r
-  @return                       Error codes returned by\r
-                                gBS->LocateHandleBuffer() and\r
-                                gBS->HandleProtocol().\r
-\r
-**/\r
-EFI_STATUS\r
-CreateExtraRootBusMap (\r
-  OUT EXTRA_ROOT_BUS_MAP **ExtraRootBusMap\r
-  )\r
-{\r
-  EFI_STATUS               Status;\r
-  UINTN                    NumHandles;\r
-  EFI_HANDLE               *Handles;\r
-  ORDERED_COLLECTION       *Collection;\r
-  EXTRA_ROOT_BUS_MAP       *Map;\r
-  UINTN                    Idx;\r
-  ORDERED_COLLECTION_ENTRY *Entry, *Entry2;\r
-\r
-  //\r
-  // Handles and Collection are temporary / helper variables, while in Map we\r
-  // build the return value.\r
-  //\r
-\r
-  Status = gBS->LocateHandleBuffer (ByProtocol,\r
-                  &gEfiPciRootBridgeIoProtocolGuid, NULL /* SearchKey */,\r
-                  &NumHandles, &Handles);\r
-  if (EFI_ERROR (Status))  {\r
-    return Status;\r
-  }\r
-\r
-  Collection = OrderedCollectionInit (RootBridgePathCompare,\r
-                 RootBridgePathKeyCompare);\r
-  if (Collection == NULL) {\r
-    Status = EFI_OUT_OF_RESOURCES;\r
-    goto FreeHandles;\r
-  }\r
-\r
-  Map = AllocateZeroPool (sizeof *Map);\r
-  if (Map == NULL) {\r
-    Status = EFI_OUT_OF_RESOURCES;\r
-    goto FreeCollection;\r
-  }\r
-\r
-  //\r
-  // Collect the ACPI device path protocols of the root bridges.\r
-  //\r
-  for (Idx = 0; Idx < NumHandles; ++Idx) {\r
-    EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
-\r
-    Status = gBS->HandleProtocol (Handles[Idx], &gEfiDevicePathProtocolGuid,\r
-                    (VOID**)&DevicePath);\r
-    if (EFI_ERROR (Status)) {\r
-      goto FreeMap;\r
-    }\r
-\r
-    //\r
-    // Examine if the device path is an ACPI HID one, and if so, if UID is\r
-    // nonzero (ie. the root bridge that the bus number belongs to is "extra",\r
-    // not the main one). In that case, link the device path into Collection.\r
-    //\r
-    if (DevicePathType (DevicePath) == ACPI_DEVICE_PATH &&\r
-        DevicePathSubType (DevicePath) == ACPI_DP &&\r
-        ((ACPI_HID_DEVICE_PATH *)DevicePath)->HID == EISA_PNP_ID(0x0A03) &&\r
-        ((ACPI_HID_DEVICE_PATH *)DevicePath)->UID > 0) {\r
-      Status = OrderedCollectionInsert (Collection, NULL, DevicePath);\r
-      if (EFI_ERROR (Status)) {\r
-        goto FreeMap;\r
-      }\r
-      ++Map->Count;\r
-    }\r
-  }\r
-\r
-  if (Map->Count > 0) {\r
-    //\r
-    // At least one extra PCI root bus exists.\r
-    //\r
-    Map->BusNumbers = AllocatePool (Map->Count * sizeof *Map->BusNumbers);\r
-    if (Map->BusNumbers == NULL) {\r
-      Status = EFI_OUT_OF_RESOURCES;\r
-      goto FreeMap;\r
-    }\r
-  }\r
-\r
-  //\r
-  // Now collect the bus numbers of the extra PCI root buses into Map.\r
-  //\r
-  Idx = 0;\r
-  Entry = OrderedCollectionMin (Collection);\r
-  while (Idx < Map->Count) {\r
-    ACPI_HID_DEVICE_PATH *Acpi;\r
-\r
-    ASSERT (Entry != NULL);\r
-    Acpi = OrderedCollectionUserStruct (Entry);\r
-    Map->BusNumbers[Idx] = Acpi->UID;\r
-    DEBUG ((EFI_D_VERBOSE,\r
-      "%a: extra bus position 0x%Lx maps to bus number (UID) 0x%x\n",\r
-      __FUNCTION__, (UINT64)(Idx + 1), Acpi->UID));\r
-    ++Idx;\r
-    Entry = OrderedCollectionNext (Entry);\r
-  }\r
-  ASSERT (Entry == NULL);\r
-\r
-  *ExtraRootBusMap = Map;\r
-  Status = EFI_SUCCESS;\r
-\r
-  //\r
-  // Fall through in order to release temporaries.\r
-  //\r
-\r
-FreeMap:\r
-  if (EFI_ERROR (Status)) {\r
-    if (Map->BusNumbers != NULL) {\r
-      FreePool (Map->BusNumbers);\r
-    }\r
-    FreePool (Map);\r
-  }\r
-\r
-FreeCollection:\r
-  for (Entry = OrderedCollectionMin (Collection); Entry != NULL;\r
-       Entry = Entry2) {\r
-    Entry2 = OrderedCollectionNext (Entry);\r
-    OrderedCollectionDelete (Collection, Entry, NULL);\r
-  }\r
-  OrderedCollectionUninit (Collection);\r
-\r
-FreeHandles:\r
-  FreePool (Handles);\r
-\r
-  return Status;\r
-}\r
-\r
-\r
-/**\r
-  Release a map created with CreateExtraRootBusMap().\r
-\r
-  @param[in] ExtraRootBusMap  The map to release.\r
-*/\r
-VOID\r
-DestroyExtraRootBusMap (\r
-  IN EXTRA_ROOT_BUS_MAP *ExtraRootBusMap\r
-  )\r
-{\r
-  if (ExtraRootBusMap->BusNumbers != NULL) {\r
-    FreePool (ExtraRootBusMap->BusNumbers);\r
-  }\r
-  FreePool (ExtraRootBusMap);\r
-}\r
-\r
-/**\r
-  Map the position (serial number) of an extra PCI root bus to its bus number.\r
-\r
-  @param[in]  ExtraRootBusMap  The map created with CreateExtraRootBusMap();\r
-\r
-  @param[in]  RootBusPos       The extra PCI root bus position to map.\r
-\r
-  @param[out] RootBusNr        The bus number belonging to the extra PCI root\r
-                               bus identified by RootBusPos.\r
-\r
-  @retval EFI_INVALID_PARAMETER  RootBusPos is zero. The zero position\r
-                                 identifies the main root bus, whose bus number\r
-                                 is always zero, and is therefore never\r
-                                 maintained in ExtraRootBusMap.\r
-\r
-  @retval EFI_NOT_FOUND          RootBusPos is not found in ExtraRootBusMap.\r
-\r
-  @retval EFI_SUCCESS            Mapping successful.\r
-**/\r
-EFI_STATUS\r
-MapRootBusPosToBusNr (\r
-  IN  CONST EXTRA_ROOT_BUS_MAP *ExtraRootBusMap,\r
-  IN  UINT64                   RootBusPos,\r
-  OUT UINT32                   *RootBusNr\r
-  )\r
-{\r
-  if (RootBusPos == 0) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-  if (RootBusPos > ExtraRootBusMap->Count) {\r
-    return EFI_NOT_FOUND;\r
-  }\r
-  *RootBusNr = ExtraRootBusMap->BusNumbers[RootBusPos - 1];\r
-  return EFI_SUCCESS;\r
-}\r
diff --git a/OvmfPkg/Library/QemuNewBootOrderLib/ExtraRootBusMap.h b/OvmfPkg/Library/QemuNewBootOrderLib/ExtraRootBusMap.h
deleted file mode 100644 (file)
index e2dbc38..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/** @file\r
-  Map positions of extra PCI root buses to bus numbers.\r
-\r
-  Copyright (C) 2015, Red Hat, Inc.\r
-\r
-  This program and the accompanying materials are licensed and made available\r
-  under the terms and conditions of the BSD License which accompanies this\r
-  distribution.  The full text of the license may be found at\r
-  http://opensource.org/licenses/bsd-license.php\r
-\r
-  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
-  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-**/\r
-\r
-#ifndef __EXTRA_ROOT_BUS_MAP_H__\r
-#define __EXTRA_ROOT_BUS_MAP_H__\r
-\r
-/**\r
-  Incomplete ("opaque") data type implementing the map.\r
-**/\r
-typedef struct EXTRA_ROOT_BUS_MAP_STRUCT EXTRA_ROOT_BUS_MAP;\r
-\r
-EFI_STATUS\r
-CreateExtraRootBusMap (\r
-  OUT EXTRA_ROOT_BUS_MAP **ExtraRootBusMap\r
-  );\r
-\r
-VOID\r
-DestroyExtraRootBusMap (\r
-  IN EXTRA_ROOT_BUS_MAP *ExtraRootBusMap\r
-  );\r
-\r
-EFI_STATUS\r
-MapRootBusPosToBusNr (\r
-  IN  CONST EXTRA_ROOT_BUS_MAP *ExtraRootBusMap,\r
-  IN  UINT64                   RootBusPos,\r
-  OUT UINT32                   *RootBusNr\r
-  );\r
-\r
-#endif\r
diff --git a/OvmfPkg/Library/QemuNewBootOrderLib/QemuBootOrderLib.c b/OvmfPkg/Library/QemuNewBootOrderLib/QemuBootOrderLib.c
deleted file mode 100644 (file)
index 8608230..0000000
+++ /dev/null
@@ -1,1944 +0,0 @@
-/** @file\r
-  Rewrite the BootOrder NvVar based on QEMU's "bootorder" fw_cfg file.\r
-\r
-  Copyright (C) 2012 - 2014, Red Hat, Inc.\r
-  Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>\r
-\r
-  This program and the accompanying materials are licensed and made available\r
-  under the terms and conditions of the BSD License which accompanies this\r
-  distribution.  The full text of the license may be found at\r
-  http://opensource.org/licenses/bsd-license.php\r
-\r
-  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
-  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-**/\r
-\r
-#include <Library/QemuFwCfgLib.h>\r
-#include <Library/DebugLib.h>\r
-#include <Library/MemoryAllocationLib.h>\r
-#include <Library/UefiBootManagerLib.h>\r
-#include <Library/UefiBootServicesTableLib.h>\r
-#include <Library/UefiRuntimeServicesTableLib.h>\r
-#include <Library/BaseLib.h>\r
-#include <Library/PrintLib.h>\r
-#include <Library/DevicePathLib.h>\r
-#include <Library/QemuBootOrderLib.h>\r
-#include <Library/BaseMemoryLib.h>\r
-#include <Guid/GlobalVariable.h>\r
-#include <Guid/VirtioMmioTransport.h>\r
-\r
-#include "ExtraRootBusMap.h"\r
-\r
-/**\r
-  OpenFirmware to UEFI device path translation output buffer size in CHAR16's.\r
-**/\r
-#define TRANSLATION_OUTPUT_SIZE 0x100\r
-\r
-/**\r
-  Output buffer size for OpenFirmware to UEFI device path fragment translation,\r
-  in CHAR16's, for a sequence of PCI bridges.\r
-**/\r
-#define BRIDGE_TRANSLATION_OUTPUT_SIZE 0x40\r
-\r
-/**\r
-  Numbers of nodes in OpenFirmware device paths that are required and examined.\r
-**/\r
-#define REQUIRED_PCI_OFW_NODES  2\r
-#define REQUIRED_MMIO_OFW_NODES 1\r
-#define EXAMINED_OFW_NODES      6\r
-\r
-\r
-/**\r
-  Simple character classification routines, corresponding to POSIX class names\r
-  and ASCII encoding.\r
-**/\r
-STATIC\r
-BOOLEAN\r
-IsAlnum (\r
-  IN  CHAR8 Chr\r
-  )\r
-{\r
-  return (('0' <= Chr && Chr <= '9') ||\r
-          ('A' <= Chr && Chr <= 'Z') ||\r
-          ('a' <= Chr && Chr <= 'z')\r
-          );\r
-}\r
-\r
-\r
-STATIC\r
-BOOLEAN\r
-IsDriverNamePunct (\r
-  IN  CHAR8 Chr\r
-  )\r
-{\r
-  return (Chr == ',' ||  Chr == '.' || Chr == '_' ||\r
-          Chr == '+' || Chr == '-'\r
-          );\r
-}\r
-\r
-\r
-STATIC\r
-BOOLEAN\r
-IsPrintNotDelim (\r
-  IN  CHAR8 Chr\r
-  )\r
-{\r
-  return (32 <= Chr && Chr <= 126 &&\r
-          Chr != '/' && Chr != '@' && Chr != ':');\r
-}\r
-\r
-\r
-/**\r
-  Utility types and functions.\r
-**/\r
-typedef struct {\r
-  CONST CHAR8 *Ptr; // not necessarily NUL-terminated\r
-  UINTN       Len;  // number of non-NUL characters\r
-} SUBSTRING;\r
-\r
-\r
-/**\r
-\r
-  Check if Substring and String have identical contents.\r
-\r
-  The function relies on the restriction that a SUBSTRING cannot have embedded\r
-  NULs either.\r
-\r
-  @param[in] Substring  The SUBSTRING input to the comparison.\r
-\r
-  @param[in] String     The ASCII string input to the comparison.\r
-\r
-\r
-  @return  Whether the inputs have identical contents.\r
-\r
-**/\r
-STATIC\r
-BOOLEAN\r
-SubstringEq (\r
-  IN  SUBSTRING   Substring,\r
-  IN  CONST CHAR8 *String\r
-  )\r
-{\r
-  UINTN       Pos;\r
-  CONST CHAR8 *Chr;\r
-\r
-  Pos = 0;\r
-  Chr = String;\r
-\r
-  while (Pos < Substring.Len && Substring.Ptr[Pos] == *Chr) {\r
-    ++Pos;\r
-    ++Chr;\r
-  }\r
-\r
-  return (BOOLEAN)(Pos == Substring.Len && *Chr == '\0');\r
-}\r
-\r
-\r
-/**\r
-\r
-  Parse a comma-separated list of hexadecimal integers into the elements of an\r
-  UINT64 array.\r
-\r
-  Whitespace, "0x" prefixes, leading or trailing commas, sequences of commas,\r
-  or an empty string are not allowed; they are rejected.\r
-\r
-  The function relies on ASCII encoding.\r
-\r
-  @param[in]     UnitAddress  The substring to parse.\r
-\r
-  @param[out]    Result       The array, allocated by the caller, to receive\r
-                              the parsed values. This parameter may be NULL if\r
-                              NumResults is zero on input.\r
-\r
-  @param[in out] NumResults   On input, the number of elements allocated for\r
-                              Result. On output, the number of elements it has\r
-                              taken (or would have taken) to parse the string\r
-                              fully.\r
-\r
-\r
-  @retval RETURN_SUCCESS            UnitAddress has been fully parsed.\r
-                                    NumResults is set to the number of parsed\r
-                                    values; the corresponding elements have\r
-                                    been set in Result. The rest of Result's\r
-                                    elements are unchanged.\r
-\r
-  @retval RETURN_BUFFER_TOO_SMALL   UnitAddress has been fully parsed.\r
-                                    NumResults is set to the number of parsed\r
-                                    values, but elements have been stored only\r
-                                    up to the input value of NumResults, which\r
-                                    is less than what has been parsed.\r
-\r
-  @retval RETURN_INVALID_PARAMETER  Parse error. The contents of Results is\r
-                                    indeterminate. NumResults has not been\r
-                                    changed.\r
-\r
-**/\r
-STATIC\r
-RETURN_STATUS\r
-ParseUnitAddressHexList (\r
-  IN      SUBSTRING  UnitAddress,\r
-  OUT     UINT64     *Result,\r
-  IN OUT  UINTN      *NumResults\r
-  )\r
-{\r
-  UINTN         Entry;    // number of entry currently being parsed\r
-  UINT64        EntryVal; // value being constructed for current entry\r
-  CHAR8         PrevChr;  // UnitAddress character previously checked\r
-  UINTN         Pos;      // current position within UnitAddress\r
-  RETURN_STATUS Status;\r
-\r
-  Entry    = 0;\r
-  EntryVal = 0;\r
-  PrevChr  = ',';\r
-\r
-  for (Pos = 0; Pos < UnitAddress.Len; ++Pos) {\r
-    CHAR8 Chr;\r
-    INT8  Val;\r
-\r
-    Chr = UnitAddress.Ptr[Pos];\r
-    Val = ('a' <= Chr && Chr <= 'f') ? (Chr - 'a' + 10) :\r
-          ('A' <= Chr && Chr <= 'F') ? (Chr - 'A' + 10) :\r
-          ('0' <= Chr && Chr <= '9') ? (Chr - '0'     ) :\r
-          -1;\r
-\r
-    if (Val >= 0) {\r
-      if (EntryVal > 0xFFFFFFFFFFFFFFFull) {\r
-        return RETURN_INVALID_PARAMETER;\r
-      }\r
-      EntryVal = LShiftU64 (EntryVal, 4) | Val;\r
-    } else if (Chr == ',') {\r
-      if (PrevChr == ',') {\r
-        return RETURN_INVALID_PARAMETER;\r
-      }\r
-      if (Entry < *NumResults) {\r
-        Result[Entry] = EntryVal;\r
-      }\r
-      ++Entry;\r
-      EntryVal = 0;\r
-    } else {\r
-      return RETURN_INVALID_PARAMETER;\r
-    }\r
-\r
-    PrevChr = Chr;\r
-  }\r
-\r
-  if (PrevChr == ',') {\r
-    return RETURN_INVALID_PARAMETER;\r
-  }\r
-  if (Entry < *NumResults) {\r
-    Result[Entry] = EntryVal;\r
-    Status = RETURN_SUCCESS;\r
-  } else {\r
-    Status = RETURN_BUFFER_TOO_SMALL;\r
-  }\r
-  ++Entry;\r
-\r
-  *NumResults = Entry;\r
-  return Status;\r
-}\r
-\r
-\r
-/**\r
-  A simple array of Boot Option ID's.\r
-**/\r
-typedef struct {\r
-  UINT16 *Data;\r
-  UINTN  Allocated;\r
-  UINTN  Produced;\r
-} BOOT_ORDER;\r
-\r
-\r
-/**\r
-  Array element tracking an enumerated boot option that has the\r
-  LOAD_OPTION_ACTIVE attribute.\r
-**/\r
-typedef struct {\r
-  CONST EFI_BOOT_MANAGER_LOAD_OPTION *BootOption; // reference only, no\r
-                                                  //   ownership\r
-  BOOLEAN                            Appended;    // has been added to a\r
-                                                  //   BOOT_ORDER?\r
-} ACTIVE_OPTION;\r
-\r
-\r
-/**\r
-\r
-  Append an active boot option to BootOrder, reallocating the latter if needed.\r
-\r
-  @param[in out] BootOrder     The structure pointing to the array and holding\r
-                               allocation and usage counters.\r
-\r
-  @param[in]     ActiveOption  The active boot option whose ID should be\r
-                               appended to the array.\r
-\r
-\r
-  @retval RETURN_SUCCESS           ID of ActiveOption appended.\r
-\r
-  @retval RETURN_OUT_OF_RESOURCES  Memory reallocation failed.\r
-\r
-**/\r
-STATIC\r
-RETURN_STATUS\r
-BootOrderAppend (\r
-  IN OUT  BOOT_ORDER    *BootOrder,\r
-  IN OUT  ACTIVE_OPTION *ActiveOption\r
-  )\r
-{\r
-  if (BootOrder->Produced == BootOrder->Allocated) {\r
-    UINTN  AllocatedNew;\r
-    UINT16 *DataNew;\r
-\r
-    ASSERT (BootOrder->Allocated > 0);\r
-    AllocatedNew = BootOrder->Allocated * 2;\r
-    DataNew = ReallocatePool (\r
-                BootOrder->Allocated * sizeof (*BootOrder->Data),\r
-                AllocatedNew         * sizeof (*DataNew),\r
-                BootOrder->Data\r
-                );\r
-    if (DataNew == NULL) {\r
-      return RETURN_OUT_OF_RESOURCES;\r
-    }\r
-    BootOrder->Allocated = AllocatedNew;\r
-    BootOrder->Data      = DataNew;\r
-  }\r
-\r
-  BootOrder->Data[BootOrder->Produced++] =\r
-                               (UINT16) ActiveOption->BootOption->OptionNumber;\r
-  ActiveOption->Appended = TRUE;\r
-  return RETURN_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
-\r
-  Create an array of ACTIVE_OPTION elements for a boot option array.\r
-\r
-  @param[in]  BootOptions      A boot option array, created with\r
-                               EfiBootManagerRefreshAllBootOption () and\r
-                               EfiBootManagerGetLoadOptions ().\r
-\r
-  @param[in]  BootOptionCount  The number of elements in BootOptions.\r
-\r
-  @param[out] ActiveOption     Pointer to the first element in the new array.\r
-                               The caller is responsible for freeing the array\r
-                               with FreePool() after use.\r
-\r
-  @param[out] Count            Number of elements in the new array.\r
-\r
-\r
-  @retval RETURN_SUCCESS           The ActiveOption array has been created.\r
-\r
-  @retval RETURN_NOT_FOUND         No active entry has been found in\r
-                                   BootOptions.\r
-\r
-  @retval RETURN_OUT_OF_RESOURCES  Memory allocation failed.\r
-\r
-**/\r
-STATIC\r
-RETURN_STATUS\r
-CollectActiveOptions (\r
-  IN   CONST EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,\r
-  IN   UINTN                              BootOptionCount,\r
-  OUT  ACTIVE_OPTION                      **ActiveOption,\r
-  OUT  UINTN                              *Count\r
-  )\r
-{\r
-  UINTN Index;\r
-  UINTN ScanMode;\r
-\r
-  *ActiveOption = NULL;\r
-\r
-  //\r
-  // Scan the list twice:\r
-  // - count active entries,\r
-  // - store links to active entries.\r
-  //\r
-  for (ScanMode = 0; ScanMode < 2; ++ScanMode) {\r
-    *Count = 0;\r
-    for (Index = 0; Index < BootOptionCount; Index++) {\r
-      if ((BootOptions[Index].Attributes & LOAD_OPTION_ACTIVE) != 0) {\r
-        if (ScanMode == 1) {\r
-          (*ActiveOption)[*Count].BootOption = &BootOptions[Index];\r
-          (*ActiveOption)[*Count].Appended   = FALSE;\r
-        }\r
-        ++*Count;\r
-      }\r
-    }\r
-\r
-    if (ScanMode == 0) {\r
-      if (*Count == 0) {\r
-        return RETURN_NOT_FOUND;\r
-      }\r
-      *ActiveOption = AllocatePool (*Count * sizeof **ActiveOption);\r
-      if (*ActiveOption == NULL) {\r
-        return RETURN_OUT_OF_RESOURCES;\r
-      }\r
-    }\r
-  }\r
-  return RETURN_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
-  OpenFirmware device path node\r
-**/\r
-typedef struct {\r
-  SUBSTRING DriverName;\r
-  SUBSTRING UnitAddress;\r
-  SUBSTRING DeviceArguments;\r
-} OFW_NODE;\r
-\r
-\r
-/**\r
-\r
-  Parse an OpenFirmware device path node into the caller-allocated OFW_NODE\r
-  structure, and advance in the input string.\r
-\r
-  The node format is mostly parsed after IEEE 1275-1994, 3.2.1.1 "Node names"\r
-  (a leading slash is expected and not returned):\r
-\r
-    /driver-name@unit-address[:device-arguments][<LF>]\r
-\r
-  A single trailing <LF> character is consumed but not returned. A trailing\r
-  <LF> or NUL character terminates the device path.\r
-\r
-  The function relies on ASCII encoding.\r
-\r
-  @param[in out] Ptr      Address of the pointer pointing to the start of the\r
-                          node string. After successful parsing *Ptr is set to\r
-                          the byte immediately following the consumed\r
-                          characters. On error it points to the byte that\r
-                          caused the error. The input string is never modified.\r
-\r
-  @param[out]    OfwNode  The members of this structure point into the input\r
-                          string, designating components of the node.\r
-                          Separators are never included. If "device-arguments"\r
-                          is missing, then DeviceArguments.Ptr is set to NULL.\r
-                          All components that are present have nonzero length.\r
-\r
-                          If the call doesn't succeed, the contents of this\r
-                          structure is indeterminate.\r
-\r
-  @param[out]    IsFinal  In case of successul parsing, this parameter signals\r
-                          whether the node just parsed is the final node in the\r
-                          device path. The call after a final node will attempt\r
-                          to start parsing the next path. If the call doesn't\r
-                          succeed, then this parameter is not changed.\r
-\r
-\r
-  @retval RETURN_SUCCESS            Parsing successful.\r
-\r
-  @retval RETURN_NOT_FOUND          Parsing terminated. *Ptr was (and is)\r
-                                    pointing to an empty string.\r
-\r
-  @retval RETURN_INVALID_PARAMETER  Parse error.\r
-\r
-**/\r
-STATIC\r
-RETURN_STATUS\r
-ParseOfwNode (\r
-  IN OUT  CONST CHAR8 **Ptr,\r
-  OUT     OFW_NODE    *OfwNode,\r
-  OUT     BOOLEAN     *IsFinal\r
-  )\r
-{\r
-  //\r
-  // A leading slash is expected. End of string is tolerated.\r
-  //\r
-  switch (**Ptr) {\r
-  case '\0':\r
-    return RETURN_NOT_FOUND;\r
-\r
-  case '/':\r
-    ++*Ptr;\r
-    break;\r
-\r
-  default:\r
-    return RETURN_INVALID_PARAMETER;\r
-  }\r
-\r
-  //\r
-  // driver-name\r
-  //\r
-  OfwNode->DriverName.Ptr = *Ptr;\r
-  OfwNode->DriverName.Len = 0;\r
-  while (OfwNode->DriverName.Len < 32 &&\r
-         (IsAlnum (**Ptr) || IsDriverNamePunct (**Ptr))\r
-         ) {\r
-    ++*Ptr;\r
-    ++OfwNode->DriverName.Len;\r
-  }\r
-\r
-  if (OfwNode->DriverName.Len == 0 || OfwNode->DriverName.Len == 32) {\r
-    return RETURN_INVALID_PARAMETER;\r
-  }\r
-\r
-\r
-  //\r
-  // unit-address\r
-  //\r
-  if (**Ptr != '@') {\r
-    return RETURN_INVALID_PARAMETER;\r
-  }\r
-  ++*Ptr;\r
-\r
-  OfwNode->UnitAddress.Ptr = *Ptr;\r
-  OfwNode->UnitAddress.Len = 0;\r
-  while (IsPrintNotDelim (**Ptr)) {\r
-    ++*Ptr;\r
-    ++OfwNode->UnitAddress.Len;\r
-  }\r
-\r
-  if (OfwNode->UnitAddress.Len == 0) {\r
-    return RETURN_INVALID_PARAMETER;\r
-  }\r
-\r
-\r
-  //\r
-  // device-arguments, may be omitted\r
-  //\r
-  OfwNode->DeviceArguments.Len = 0;\r
-  if (**Ptr == ':') {\r
-    ++*Ptr;\r
-    OfwNode->DeviceArguments.Ptr = *Ptr;\r
-\r
-    while (IsPrintNotDelim (**Ptr)) {\r
-      ++*Ptr;\r
-      ++OfwNode->DeviceArguments.Len;\r
-    }\r
-\r
-    if (OfwNode->DeviceArguments.Len == 0) {\r
-      return RETURN_INVALID_PARAMETER;\r
-    }\r
-  }\r
-  else {\r
-    OfwNode->DeviceArguments.Ptr = NULL;\r
-  }\r
-\r
-  switch (**Ptr) {\r
-  case '\n':\r
-    ++*Ptr;\r
-    //\r
-    // fall through\r
-    //\r
-\r
-  case '\0':\r
-    *IsFinal = TRUE;\r
-    break;\r
-\r
-  case '/':\r
-    *IsFinal = FALSE;\r
-    break;\r
-\r
-  default:\r
-    return RETURN_INVALID_PARAMETER;\r
-  }\r
-\r
-  DEBUG ((\r
-    DEBUG_VERBOSE,\r
-    "%a: DriverName=\"%.*a\" UnitAddress=\"%.*a\" DeviceArguments=\"%.*a\"\n",\r
-    __FUNCTION__,\r
-    OfwNode->DriverName.Len, OfwNode->DriverName.Ptr,\r
-    OfwNode->UnitAddress.Len, OfwNode->UnitAddress.Ptr,\r
-    OfwNode->DeviceArguments.Len,\r
-    OfwNode->DeviceArguments.Ptr == NULL ? "" : OfwNode->DeviceArguments.Ptr\r
-    ));\r
-  return RETURN_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
-\r
-  Translate a PCI-like array of OpenFirmware device nodes to a UEFI device path\r
-  fragment.\r
-\r
-  @param[in]     OfwNode         Array of OpenFirmware device nodes to\r
-                                 translate, constituting the beginning of an\r
-                                 OpenFirmware device path.\r
-\r
-  @param[in]     NumNodes        Number of elements in OfwNode.\r
-\r
-  @param[in]     ExtraPciRoots   An EXTRA_ROOT_BUS_MAP object created with\r
-                                 CreateExtraRootBusMap(), to be used for\r
-                                 translating positions of extra root buses to\r
-                                 bus numbers.\r
-\r
-  @param[out]    Translated      Destination array receiving the UEFI path\r
-                                 fragment, allocated by the caller. If the\r
-                                 return value differs from RETURN_SUCCESS, its\r
-                                 contents is indeterminate.\r
-\r
-  @param[in out] TranslatedSize  On input, the number of CHAR16's in\r
-                                 Translated. On RETURN_SUCCESS this parameter\r
-                                 is assigned the number of non-NUL CHAR16's\r
-                                 written to Translated. In case of other return\r
-                                 values, TranslatedSize is indeterminate.\r
-\r
-\r
-  @retval RETURN_SUCCESS           Translation successful.\r
-\r
-  @retval RETURN_BUFFER_TOO_SMALL  The translation does not fit into the number\r
-                                   of bytes provided.\r
-\r
-  @retval RETURN_UNSUPPORTED       The array of OpenFirmware device nodes can't\r
-                                   be translated in the current implementation.\r
-\r
-  @retval RETURN_PROTOCOL_ERROR    The initial OpenFirmware node refers to an\r
-                                   extra PCI root bus (by serial number) that\r
-                                   is invalid according to ExtraPciRoots.\r
-\r
-**/\r
-STATIC\r
-RETURN_STATUS\r
-TranslatePciOfwNodes (\r
-  IN      CONST OFW_NODE           *OfwNode,\r
-  IN      UINTN                    NumNodes,\r
-  IN      CONST EXTRA_ROOT_BUS_MAP *ExtraPciRoots,\r
-  OUT     CHAR16                   *Translated,\r
-  IN OUT  UINTN                    *TranslatedSize\r
-  )\r
-{\r
-  UINT32 PciRoot;\r
-  CHAR8  *Comma;\r
-  UINTN  FirstNonBridge;\r
-  CHAR16 Bridges[BRIDGE_TRANSLATION_OUTPUT_SIZE];\r
-  UINTN  BridgesLen;\r
-  UINT64 PciDevFun[2];\r
-  UINTN  NumEntries;\r
-  UINTN  Written;\r
-\r
-  //\r
-  // Resolve the PCI root bus number.\r
-  //\r
-  // The initial OFW node for the main root bus (ie. bus number 0) is:\r
-  //\r
-  //   /pci@i0cf8\r
-  //\r
-  // For extra root buses, the initial OFW node is\r
-  //\r
-  //   /pci@i0cf8,4\r
-  //              ^\r
-  //              root bus serial number (not PCI bus number)\r
-  //\r
-  if (NumNodes < REQUIRED_PCI_OFW_NODES ||\r
-      !SubstringEq (OfwNode[0].DriverName, "pci")\r
-      ) {\r
-    return RETURN_UNSUPPORTED;\r
-  }\r
-\r
-  PciRoot = 0;\r
-  Comma = ScanMem8 (OfwNode[0].UnitAddress.Ptr, OfwNode[0].UnitAddress.Len,\r
-            ',');\r
-  if (Comma != NULL) {\r
-    SUBSTRING PciRootSerialSubString;\r
-    UINT64    PciRootSerial;\r
-\r
-    //\r
-    // Parse the root bus serial number from the unit address after the comma.\r
-    //\r
-    PciRootSerialSubString.Ptr = Comma + 1;\r
-    PciRootSerialSubString.Len = OfwNode[0].UnitAddress.Len -\r
-                                 (PciRootSerialSubString.Ptr -\r
-                                  OfwNode[0].UnitAddress.Ptr);\r
-    NumEntries = 1;\r
-    if (RETURN_ERROR (ParseUnitAddressHexList (PciRootSerialSubString,\r
-                      &PciRootSerial, &NumEntries))) {\r
-      return RETURN_UNSUPPORTED;\r
-    }\r
-\r
-    //\r
-    // Map the extra root bus's serial number to its actual bus number.\r
-    //\r
-    if (EFI_ERROR (MapRootBusPosToBusNr (ExtraPciRoots, PciRootSerial,\r
-                     &PciRoot))) {\r
-      return RETURN_PROTOCOL_ERROR;\r
-    }\r
-  }\r
-\r
-  //\r
-  // Translate a sequence of PCI bridges. For each bridge, the OFW node is:\r
-  //\r
-  //   pci-bridge@1e[,0]\r
-  //              ^   ^\r
-  //              PCI slot & function on the parent, holding the bridge\r
-  //\r
-  // and the UEFI device path node is:\r
-  //\r
-  //   Pci(0x1E,0x0)\r
-  //\r
-  FirstNonBridge = 1;\r
-  Bridges[0] = L'\0';\r
-  BridgesLen = 0;\r
-  do {\r
-    UINT64 BridgeDevFun[2];\r
-    UINTN  BridgesFreeBytes;\r
-\r
-    if (!SubstringEq (OfwNode[FirstNonBridge].DriverName, "pci-bridge")) {\r
-      break;\r
-    }\r
-\r
-    BridgeDevFun[1] = 0;\r
-    NumEntries = sizeof BridgeDevFun / sizeof BridgeDevFun[0];\r
-    if (ParseUnitAddressHexList (OfwNode[FirstNonBridge].UnitAddress,\r
-          BridgeDevFun, &NumEntries) != RETURN_SUCCESS) {\r
-      return RETURN_UNSUPPORTED;\r
-    }\r
-\r
-    BridgesFreeBytes = sizeof Bridges - BridgesLen * sizeof Bridges[0];\r
-    Written = UnicodeSPrintAsciiFormat (Bridges + BridgesLen, BridgesFreeBytes,\r
-                "/Pci(0x%Lx,0x%Lx)", BridgeDevFun[0], BridgeDevFun[1]);\r
-    BridgesLen += Written;\r
-\r
-    //\r
-    // There's no way to differentiate between "completely used up without\r
-    // truncation" and "truncated", so treat the former as the latter.\r
-    //\r
-    if (BridgesLen + 1 == BRIDGE_TRANSLATION_OUTPUT_SIZE) {\r
-      return RETURN_UNSUPPORTED;\r
-    }\r
-\r
-    ++FirstNonBridge;\r
-  } while (FirstNonBridge < NumNodes);\r
-\r
-  if (FirstNonBridge == NumNodes) {\r
-    return RETURN_UNSUPPORTED;\r
-  }\r
-\r
-  //\r
-  // Parse the OFW nodes starting with the first non-bridge node.\r
-  //\r
-  PciDevFun[1] = 0;\r
-  NumEntries = sizeof (PciDevFun) / sizeof (PciDevFun[0]);\r
-  if (ParseUnitAddressHexList (\r
-        OfwNode[FirstNonBridge].UnitAddress,\r
-        PciDevFun,\r
-        &NumEntries\r
-        ) != RETURN_SUCCESS\r
-      ) {\r
-    return RETURN_UNSUPPORTED;\r
-  }\r
-\r
-  if (NumNodes >= FirstNonBridge + 3 &&\r
-      SubstringEq (OfwNode[FirstNonBridge + 0].DriverName, "ide") &&\r
-      SubstringEq (OfwNode[FirstNonBridge + 1].DriverName, "drive") &&\r
-      SubstringEq (OfwNode[FirstNonBridge + 2].DriverName, "disk")\r
-      ) {\r
-    //\r
-    // OpenFirmware device path (IDE disk, IDE CD-ROM):\r
-    //\r
-    //   /pci@i0cf8/ide@1,1/drive@0/disk@0\r
-    //        ^         ^ ^       ^      ^\r
-    //        |         | |       |      master or slave\r
-    //        |         | |       primary or secondary\r
-    //        |         PCI slot & function holding IDE controller\r
-    //        PCI root at system bus port, PIO\r
-    //\r
-    // UEFI device path:\r
-    //\r
-    //   PciRoot(0x0)/Pci(0x1,0x1)/Ata(Primary,Master,0x0)\r
-    //                                                ^\r
-    //                                                fixed LUN\r
-    //\r
-    UINT64 Secondary;\r
-    UINT64 Slave;\r
-\r
-    NumEntries = 1;\r
-    if (ParseUnitAddressHexList (\r
-          OfwNode[FirstNonBridge + 1].UnitAddress,\r
-          &Secondary,\r
-          &NumEntries\r
-          ) != RETURN_SUCCESS ||\r
-        Secondary > 1 ||\r
-        ParseUnitAddressHexList (\r
-          OfwNode[FirstNonBridge + 2].UnitAddress,\r
-          &Slave,\r
-          &NumEntries // reuse after previous single-element call\r
-          ) != RETURN_SUCCESS ||\r
-        Slave > 1\r
-        ) {\r
-      return RETURN_UNSUPPORTED;\r
-    }\r
-\r
-    Written = UnicodeSPrintAsciiFormat (\r
-      Translated,\r
-      *TranslatedSize * sizeof (*Translated), // BufferSize in bytes\r
-      "PciRoot(0x%x)%s/Pci(0x%Lx,0x%Lx)/Ata(%a,%a,0x0)",\r
-      PciRoot,\r
-      Bridges,\r
-      PciDevFun[0],\r
-      PciDevFun[1],\r
-      Secondary ? "Secondary" : "Primary",\r
-      Slave ? "Slave" : "Master"\r
-      );\r
-  } else if (NumNodes >= FirstNonBridge + 3 &&\r
-      SubstringEq (OfwNode[FirstNonBridge + 0].DriverName, "pci8086,2922") &&\r
-      SubstringEq (OfwNode[FirstNonBridge + 1].DriverName, "drive") &&\r
-      SubstringEq (OfwNode[FirstNonBridge + 2].DriverName, "disk")\r
-      ) {\r
-    //\r
-    // OpenFirmware device path (Q35 SATA disk and CD-ROM):\r
-    //\r
-    //   /pci@i0cf8/pci8086,2922@1f,2/drive@1/disk@0\r
-    //        ^                  ^  ^       ^      ^\r
-    //        |                  |  |       |      device number (fixed 0)\r
-    //        |                  |  |       channel (port) number\r
-    //        |                  PCI slot & function holding SATA HBA\r
-    //        PCI root at system bus port, PIO\r
-    //\r
-    // UEFI device path:\r
-    //\r
-    //   PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x1,0xFFFF,0x0)\r
-    //                                   ^   ^      ^\r
-    //                                   |   |      LUN (always 0 on Q35)\r
-    //                                   |   port multiplier port number,\r
-    //                                   |   always 0xFFFF on Q35\r
-    //                                   channel (port) number\r
-    //\r
-    UINT64 Channel;\r
-\r
-    NumEntries = 1;\r
-    if (RETURN_ERROR (ParseUnitAddressHexList (\r
-                        OfwNode[FirstNonBridge + 1].UnitAddress, &Channel,\r
-                        &NumEntries))) {\r
-      return RETURN_UNSUPPORTED;\r
-    }\r
-\r
-    Written = UnicodeSPrintAsciiFormat (\r
-      Translated,\r
-      *TranslatedSize * sizeof (*Translated), // BufferSize in bytes\r
-      "PciRoot(0x%x)%s/Pci(0x%Lx,0x%Lx)/Sata(0x%Lx,0xFFFF,0x0)",\r
-      PciRoot,\r
-      Bridges,\r
-      PciDevFun[0],\r
-      PciDevFun[1],\r
-      Channel\r
-      );\r
-  } else if (NumNodes >= FirstNonBridge + 3 &&\r
-             SubstringEq (OfwNode[FirstNonBridge + 0].DriverName, "isa") &&\r
-             SubstringEq (OfwNode[FirstNonBridge + 1].DriverName, "fdc") &&\r
-             SubstringEq (OfwNode[FirstNonBridge + 2].DriverName, "floppy")\r
-             ) {\r
-    //\r
-    // OpenFirmware device path (floppy disk):\r
-    //\r
-    //   /pci@i0cf8/isa@1/fdc@03f0/floppy@0\r
-    //        ^         ^     ^           ^\r
-    //        |         |     |           A: or B:\r
-    //        |         |     ISA controller io-port (hex)\r
-    //        |         PCI slot holding ISA controller\r
-    //        PCI root at system bus port, PIO\r
-    //\r
-    // UEFI device path:\r
-    //\r
-    //   PciRoot(0x0)/Pci(0x1,0x0)/Floppy(0x0)\r
-    //                                    ^\r
-    //                                    ACPI UID\r
-    //\r
-    UINT64 AcpiUid;\r
-\r
-    NumEntries = 1;\r
-    if (ParseUnitAddressHexList (\r
-          OfwNode[FirstNonBridge + 2].UnitAddress,\r
-          &AcpiUid,\r
-          &NumEntries\r
-          ) != RETURN_SUCCESS ||\r
-        AcpiUid > 1\r
-        ) {\r
-      return RETURN_UNSUPPORTED;\r
-    }\r
-\r
-    Written = UnicodeSPrintAsciiFormat (\r
-      Translated,\r
-      *TranslatedSize * sizeof (*Translated), // BufferSize in bytes\r
-      "PciRoot(0x%x)%s/Pci(0x%Lx,0x%Lx)/Floppy(0x%Lx)",\r
-      PciRoot,\r
-      Bridges,\r
-      PciDevFun[0],\r
-      PciDevFun[1],\r
-      AcpiUid\r
-      );\r
-  } else if (NumNodes >= FirstNonBridge + 2 &&\r
-             SubstringEq (OfwNode[FirstNonBridge + 0].DriverName, "scsi") &&\r
-             SubstringEq (OfwNode[FirstNonBridge + 1].DriverName, "disk")\r
-             ) {\r
-    //\r
-    // OpenFirmware device path (virtio-blk disk):\r
-    //\r
-    //   /pci@i0cf8/scsi@6[,3]/disk@0,0\r
-    //        ^          ^  ^       ^ ^\r
-    //        |          |  |       fixed\r
-    //        |          |  PCI function corresponding to disk (optional)\r
-    //        |          PCI slot holding disk\r
-    //        PCI root at system bus port, PIO\r
-    //\r
-    // UEFI device path prefix:\r
-    //\r
-    //   PciRoot(0x0)/Pci(0x6,0x0)/HD( -- if PCI function is 0 or absent\r
-    //   PciRoot(0x0)/Pci(0x6,0x3)/HD( -- if PCI function is present and nonzero\r
-    //\r
-    Written = UnicodeSPrintAsciiFormat (\r
-      Translated,\r
-      *TranslatedSize * sizeof (*Translated), // BufferSize in bytes\r
-      "PciRoot(0x%x)%s/Pci(0x%Lx,0x%Lx)/HD(",\r
-      PciRoot,\r
-      Bridges,\r
-      PciDevFun[0],\r
-      PciDevFun[1]\r
-      );\r
-  } else if (NumNodes >= FirstNonBridge + 3 &&\r
-             SubstringEq (OfwNode[FirstNonBridge + 0].DriverName, "scsi") &&\r
-             SubstringEq (OfwNode[FirstNonBridge + 1].DriverName, "channel") &&\r
-             SubstringEq (OfwNode[FirstNonBridge + 2].DriverName, "disk")\r
-             ) {\r
-    //\r
-    // OpenFirmware device path (virtio-scsi disk):\r
-    //\r
-    //   /pci@i0cf8/scsi@7[,3]/channel@0/disk@2,3\r
-    //        ^          ^             ^      ^ ^\r
-    //        |          |             |      | LUN\r
-    //        |          |             |      target\r
-    //        |          |             channel (unused, fixed 0)\r
-    //        |          PCI slot[, function] holding SCSI controller\r
-    //        PCI root at system bus port, PIO\r
-    //\r
-    // UEFI device path prefix:\r
-    //\r
-    //   PciRoot(0x0)/Pci(0x7,0x0)/Scsi(0x2,0x3)\r
-    //                                        -- if PCI function is 0 or absent\r
-    //   PciRoot(0x0)/Pci(0x7,0x3)/Scsi(0x2,0x3)\r
-    //                                -- if PCI function is present and nonzero\r
-    //\r
-    UINT64 TargetLun[2];\r
-\r
-    TargetLun[1] = 0;\r
-    NumEntries = sizeof (TargetLun) / sizeof (TargetLun[0]);\r
-    if (ParseUnitAddressHexList (\r
-          OfwNode[FirstNonBridge + 2].UnitAddress,\r
-          TargetLun,\r
-          &NumEntries\r
-          ) != RETURN_SUCCESS\r
-        ) {\r
-      return RETURN_UNSUPPORTED;\r
-    }\r
-\r
-    Written = UnicodeSPrintAsciiFormat (\r
-      Translated,\r
-      *TranslatedSize * sizeof (*Translated), // BufferSize in bytes\r
-      "PciRoot(0x%x)%s/Pci(0x%Lx,0x%Lx)/Scsi(0x%Lx,0x%Lx)",\r
-      PciRoot,\r
-      Bridges,\r
-      PciDevFun[0],\r
-      PciDevFun[1],\r
-      TargetLun[0],\r
-      TargetLun[1]\r
-      );\r
-  } else if (NumNodes >= FirstNonBridge + 2 &&\r
-      SubstringEq (OfwNode[FirstNonBridge + 0].DriverName, "pci8086,5845") &&\r
-      SubstringEq (OfwNode[FirstNonBridge + 1].DriverName, "namespace")\r
-      ) {\r
-    //\r
-    // OpenFirmware device path (NVMe device):\r
-    //\r
-    //   /pci@i0cf8/pci8086,5845@6[,1]/namespace@1,0\r
-    //        ^                  ^  ^            ^ ^\r
-    //        |                  |  |            | Extended Unique Identifier\r
-    //        |                  |  |            | (EUI-64), big endian interp.\r
-    //        |                  |  |            namespace ID\r
-    //        |                  PCI slot & function holding NVMe controller\r
-    //        PCI root at system bus port, PIO\r
-    //\r
-    // UEFI device path:\r
-    //\r
-    //   PciRoot(0x0)/Pci(0x6,0x1)/NVMe(0x1,00-00-00-00-00-00-00-00)\r
-    //                                  ^   ^\r
-    //                                  |   octets of the EUI-64\r
-    //                                  |   in address order\r
-    //                                  namespace ID\r
-    //\r
-    UINT64 Namespace[2];\r
-    UINTN  RequiredEntries;\r
-    UINT8  *Eui64;\r
-\r
-    RequiredEntries = sizeof (Namespace) / sizeof (Namespace[0]);\r
-    NumEntries = RequiredEntries;\r
-    if (ParseUnitAddressHexList (\r
-          OfwNode[FirstNonBridge + 1].UnitAddress,\r
-          Namespace,\r
-          &NumEntries\r
-          ) != RETURN_SUCCESS ||\r
-        NumEntries != RequiredEntries ||\r
-        Namespace[0] == 0 ||\r
-        Namespace[0] >= MAX_UINT32\r
-        ) {\r
-      return RETURN_UNSUPPORTED;\r
-    }\r
-\r
-    Eui64 = (UINT8 *)&Namespace[1];\r
-    Written = UnicodeSPrintAsciiFormat (\r
-      Translated,\r
-      *TranslatedSize * sizeof (*Translated), // BufferSize in bytes\r
-      "PciRoot(0x%x)%s/Pci(0x%Lx,0x%Lx)/"\r
-      "NVMe(0x%Lx,%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x)",\r
-      PciRoot,\r
-      Bridges,\r
-      PciDevFun[0],\r
-      PciDevFun[1],\r
-      Namespace[0],\r
-      Eui64[7], Eui64[6], Eui64[5], Eui64[4],\r
-      Eui64[3], Eui64[2], Eui64[1], Eui64[0]\r
-      );\r
-  } else {\r
-    //\r
-    // Generic OpenFirmware device path for PCI devices:\r
-    //\r
-    //   /pci@i0cf8/ethernet@3[,2]\r
-    //        ^              ^\r
-    //        |              PCI slot[, function] holding Ethernet card\r
-    //        PCI root at system bus port, PIO\r
-    //\r
-    // UEFI device path prefix (dependent on presence of nonzero PCI function):\r
-    //\r
-    //   PciRoot(0x0)/Pci(0x3,0x0)\r
-    //   PciRoot(0x0)/Pci(0x3,0x2)\r
-    //\r
-    Written = UnicodeSPrintAsciiFormat (\r
-      Translated,\r
-      *TranslatedSize * sizeof (*Translated), // BufferSize in bytes\r
-      "PciRoot(0x%x)%s/Pci(0x%Lx,0x%Lx)",\r
-      PciRoot,\r
-      Bridges,\r
-      PciDevFun[0],\r
-      PciDevFun[1]\r
-      );\r
-  }\r
-\r
-  //\r
-  // There's no way to differentiate between "completely used up without\r
-  // truncation" and "truncated", so treat the former as the latter, and return\r
-  // success only for "some room left unused".\r
-  //\r
-  if (Written + 1 < *TranslatedSize) {\r
-    *TranslatedSize = Written;\r
-    return RETURN_SUCCESS;\r
-  }\r
-\r
-  return RETURN_BUFFER_TOO_SMALL;\r
-}\r
-\r
-\r
-//\r
-// A type providing easy raw access to the base address of a virtio-mmio\r
-// transport.\r
-//\r
-typedef union {\r
-  UINT64 Uint64;\r
-  UINT8  Raw[8];\r
-} VIRTIO_MMIO_BASE_ADDRESS;\r
-\r
-\r
-/**\r
-\r
-  Translate an MMIO-like array of OpenFirmware device nodes to a UEFI device\r
-  path fragment.\r
-\r
-  @param[in]     OfwNode         Array of OpenFirmware device nodes to\r
-                                 translate, constituting the beginning of an\r
-                                 OpenFirmware device path.\r
-\r
-  @param[in]     NumNodes        Number of elements in OfwNode.\r
-\r
-  @param[out]    Translated      Destination array receiving the UEFI path\r
-                                 fragment, allocated by the caller. If the\r
-                                 return value differs from RETURN_SUCCESS, its\r
-                                 contents is indeterminate.\r
-\r
-  @param[in out] TranslatedSize  On input, the number of CHAR16's in\r
-                                 Translated. On RETURN_SUCCESS this parameter\r
-                                 is assigned the number of non-NUL CHAR16's\r
-                                 written to Translated. In case of other return\r
-                                 values, TranslatedSize is indeterminate.\r
-\r
-\r
-  @retval RETURN_SUCCESS           Translation successful.\r
-\r
-  @retval RETURN_BUFFER_TOO_SMALL  The translation does not fit into the number\r
-                                   of bytes provided.\r
-\r
-  @retval RETURN_UNSUPPORTED       The array of OpenFirmware device nodes can't\r
-                                   be translated in the current implementation.\r
-\r
-**/\r
-STATIC\r
-RETURN_STATUS\r
-TranslateMmioOfwNodes (\r
-  IN      CONST OFW_NODE *OfwNode,\r
-  IN      UINTN          NumNodes,\r
-  OUT     CHAR16         *Translated,\r
-  IN OUT  UINTN          *TranslatedSize\r
-  )\r
-{\r
-  VIRTIO_MMIO_BASE_ADDRESS VirtioMmioBase;\r
-  CHAR16                   VenHwString[60 + 1];\r
-  UINTN                    NumEntries;\r
-  UINTN                    Written;\r
-\r
-  //\r
-  // Get the base address of the virtio-mmio transport.\r
-  //\r
-  if (NumNodes < REQUIRED_MMIO_OFW_NODES ||\r
-      !SubstringEq (OfwNode[0].DriverName, "virtio-mmio")\r
-      ) {\r
-    return RETURN_UNSUPPORTED;\r
-  }\r
-  NumEntries = 1;\r
-  if (ParseUnitAddressHexList (\r
-        OfwNode[0].UnitAddress,\r
-        &VirtioMmioBase.Uint64,\r
-        &NumEntries\r
-        ) != RETURN_SUCCESS\r
-      ) {\r
-    return RETURN_UNSUPPORTED;\r
-  }\r
-\r
-  UnicodeSPrintAsciiFormat (VenHwString, sizeof VenHwString,\r
-    "VenHw(%g,%02X%02X%02X%02X%02X%02X%02X%02X)", &gVirtioMmioTransportGuid,\r
-    VirtioMmioBase.Raw[0], VirtioMmioBase.Raw[1], VirtioMmioBase.Raw[2],\r
-    VirtioMmioBase.Raw[3], VirtioMmioBase.Raw[4], VirtioMmioBase.Raw[5],\r
-    VirtioMmioBase.Raw[6], VirtioMmioBase.Raw[7]);\r
-\r
-  if (NumNodes >= 2 &&\r
-      SubstringEq (OfwNode[1].DriverName, "disk")) {\r
-    //\r
-    // OpenFirmware device path (virtio-blk disk):\r
-    //\r
-    //   /virtio-mmio@000000000a003c00/disk@0,0\r
-    //                ^                     ^ ^\r
-    //                |                     fixed\r
-    //                base address of virtio-mmio register block\r
-    //\r
-    // UEFI device path prefix:\r
-    //\r
-    //   <VenHwString>/HD(\r
-    //\r
-    Written = UnicodeSPrintAsciiFormat (\r
-                Translated,\r
-                *TranslatedSize * sizeof (*Translated), // BufferSize in bytes\r
-                "%s/HD(",\r
-                VenHwString\r
-                );\r
-  } else if (NumNodes >= 3 &&\r
-             SubstringEq (OfwNode[1].DriverName, "channel") &&\r
-             SubstringEq (OfwNode[2].DriverName, "disk")) {\r
-    //\r
-    // OpenFirmware device path (virtio-scsi disk):\r
-    //\r
-    //   /virtio-mmio@000000000a003a00/channel@0/disk@2,3\r
-    //                ^                        ^      ^ ^\r
-    //                |                        |      | LUN\r
-    //                |                        |      target\r
-    //                |                        channel (unused, fixed 0)\r
-    //                base address of virtio-mmio register block\r
-    //\r
-    // UEFI device path prefix:\r
-    //\r
-    //   <VenHwString>/Scsi(0x2,0x3)\r
-    //\r
-    UINT64 TargetLun[2];\r
-\r
-    TargetLun[1] = 0;\r
-    NumEntries = sizeof (TargetLun) / sizeof (TargetLun[0]);\r
-    if (ParseUnitAddressHexList (\r
-          OfwNode[2].UnitAddress,\r
-          TargetLun,\r
-          &NumEntries\r
-          ) != RETURN_SUCCESS\r
-        ) {\r
-      return RETURN_UNSUPPORTED;\r
-    }\r
-\r
-    Written = UnicodeSPrintAsciiFormat (\r
-                Translated,\r
-                *TranslatedSize * sizeof (*Translated), // BufferSize in bytes\r
-                "%s/Scsi(0x%Lx,0x%Lx)",\r
-                VenHwString,\r
-                TargetLun[0],\r
-                TargetLun[1]\r
-                );\r
-  } else if (NumNodes >= 2 &&\r
-             SubstringEq (OfwNode[1].DriverName, "ethernet-phy")) {\r
-    //\r
-    // OpenFirmware device path (virtio-net NIC):\r
-    //\r
-    //   /virtio-mmio@000000000a003e00/ethernet-phy@0\r
-    //                ^                             ^\r
-    //                |                             fixed\r
-    //                base address of virtio-mmio register block\r
-    //\r
-    // UEFI device path prefix (dependent on presence of nonzero PCI function):\r
-    //\r
-    //   <VenHwString>/MAC(\r
-    //\r
-    Written = UnicodeSPrintAsciiFormat (\r
-                Translated,\r
-                *TranslatedSize * sizeof (*Translated), // BufferSize in bytes\r
-                "%s/MAC(",\r
-                VenHwString\r
-                );\r
-  } else {\r
-    return RETURN_UNSUPPORTED;\r
-  }\r
-\r
-  //\r
-  // There's no way to differentiate between "completely used up without\r
-  // truncation" and "truncated", so treat the former as the latter, and return\r
-  // success only for "some room left unused".\r
-  //\r
-  if (Written + 1 < *TranslatedSize) {\r
-    *TranslatedSize = Written;\r
-    return RETURN_SUCCESS;\r
-  }\r
-\r
-  return RETURN_BUFFER_TOO_SMALL;\r
-}\r
-\r
-\r
-/**\r
-\r
-  Translate an array of OpenFirmware device nodes to a UEFI device path\r
-  fragment.\r
-\r
-  @param[in]     OfwNode         Array of OpenFirmware device nodes to\r
-                                 translate, constituting the beginning of an\r
-                                 OpenFirmware device path.\r
-\r
-  @param[in]     NumNodes        Number of elements in OfwNode.\r
-\r
-  @param[in]     ExtraPciRoots   An EXTRA_ROOT_BUS_MAP object created with\r
-                                 CreateExtraRootBusMap(), to be used for\r
-                                 translating positions of extra root buses to\r
-                                 bus numbers.\r
-\r
-  @param[out]    Translated      Destination array receiving the UEFI path\r
-                                 fragment, allocated by the caller. If the\r
-                                 return value differs from RETURN_SUCCESS, its\r
-                                 contents is indeterminate.\r
-\r
-  @param[in out] TranslatedSize  On input, the number of CHAR16's in\r
-                                 Translated. On RETURN_SUCCESS this parameter\r
-                                 is assigned the number of non-NUL CHAR16's\r
-                                 written to Translated. In case of other return\r
-                                 values, TranslatedSize is indeterminate.\r
-\r
-\r
-  @retval RETURN_SUCCESS           Translation successful.\r
-\r
-  @retval RETURN_BUFFER_TOO_SMALL  The translation does not fit into the number\r
-                                   of bytes provided.\r
-\r
-  @retval RETURN_UNSUPPORTED       The array of OpenFirmware device nodes can't\r
-                                   be translated in the current implementation.\r
-\r
-  @retval RETURN_PROTOCOL_ERROR    The array of OpenFirmware device nodes has\r
-                                   been (partially) recognized, but it contains\r
-                                   a logic error / doesn't match system state.\r
-\r
-**/\r
-STATIC\r
-RETURN_STATUS\r
-TranslateOfwNodes (\r
-  IN      CONST OFW_NODE           *OfwNode,\r
-  IN      UINTN                    NumNodes,\r
-  IN      CONST EXTRA_ROOT_BUS_MAP *ExtraPciRoots,\r
-  OUT     CHAR16                   *Translated,\r
-  IN OUT  UINTN                    *TranslatedSize\r
-  )\r
-{\r
-  RETURN_STATUS Status;\r
-\r
-  Status = RETURN_UNSUPPORTED;\r
-\r
-  if (FeaturePcdGet (PcdQemuBootOrderPciTranslation)) {\r
-    Status = TranslatePciOfwNodes (OfwNode, NumNodes, ExtraPciRoots,\r
-               Translated, TranslatedSize);\r
-  }\r
-  if (Status == RETURN_UNSUPPORTED &&\r
-      FeaturePcdGet (PcdQemuBootOrderMmioTranslation)) {\r
-    Status = TranslateMmioOfwNodes (OfwNode, NumNodes, Translated,\r
-               TranslatedSize);\r
-  }\r
-  return Status;\r
-}\r
-\r
-/**\r
-\r
-  Translate an OpenFirmware device path fragment to a UEFI device path\r
-  fragment, and advance in the input string.\r
-\r
-  @param[in out] Ptr             Address of the pointer pointing to the start\r
-                                 of the path string. After successful\r
-                                 translation (RETURN_SUCCESS) or at least\r
-                                 successful parsing (RETURN_UNSUPPORTED,\r
-                                 RETURN_BUFFER_TOO_SMALL), *Ptr is set to the\r
-                                 byte immediately following the consumed\r
-                                 characters. In other error cases, it points to\r
-                                 the byte that caused the error.\r
-\r
-  @param[in]     ExtraPciRoots   An EXTRA_ROOT_BUS_MAP object created with\r
-                                 CreateExtraRootBusMap(), to be used for\r
-                                 translating positions of extra root buses to\r
-                                 bus numbers.\r
-\r
-  @param[out]    Translated      Destination array receiving the UEFI path\r
-                                 fragment, allocated by the caller. If the\r
-                                 return value differs from RETURN_SUCCESS, its\r
-                                 contents is indeterminate.\r
-\r
-  @param[in out] TranslatedSize  On input, the number of CHAR16's in\r
-                                 Translated. On RETURN_SUCCESS this parameter\r
-                                 is assigned the number of non-NUL CHAR16's\r
-                                 written to Translated. In case of other return\r
-                                 values, TranslatedSize is indeterminate.\r
-\r
-\r
-  @retval RETURN_SUCCESS            Translation successful.\r
-\r
-  @retval RETURN_BUFFER_TOO_SMALL   The OpenFirmware device path was parsed\r
-                                    successfully, but its translation did not\r
-                                    fit into the number of bytes provided.\r
-                                    Further calls to this function are\r
-                                    possible.\r
-\r
-  @retval RETURN_UNSUPPORTED        The OpenFirmware device path was parsed\r
-                                    successfully, but it can't be translated in\r
-                                    the current implementation. Further calls\r
-                                    to this function are possible.\r
-\r
-  @retval RETURN_PROTOCOL_ERROR     The OpenFirmware device path has been\r
-                                    (partially) recognized, but it contains a\r
-                                    logic error / doesn't match system state.\r
-                                    Further calls to this function are\r
-                                    possible.\r
-\r
-  @retval RETURN_NOT_FOUND          Translation terminated. On input, *Ptr was\r
-                                    pointing to the empty string or "HALT". On\r
-                                    output, *Ptr points to the empty string\r
-                                    (ie. "HALT" is consumed transparently when\r
-                                    present).\r
-\r
-  @retval RETURN_INVALID_PARAMETER  Parse error. This is a permanent error.\r
-\r
-**/\r
-STATIC\r
-RETURN_STATUS\r
-TranslateOfwPath (\r
-  IN OUT  CONST CHAR8              **Ptr,\r
-  IN      CONST EXTRA_ROOT_BUS_MAP *ExtraPciRoots,\r
-  OUT     CHAR16                   *Translated,\r
-  IN OUT  UINTN                    *TranslatedSize\r
-  )\r
-{\r
-  UINTN         NumNodes;\r
-  RETURN_STATUS Status;\r
-  OFW_NODE      Node[EXAMINED_OFW_NODES];\r
-  BOOLEAN       IsFinal;\r
-  OFW_NODE      Skip;\r
-\r
-  IsFinal = FALSE;\r
-  NumNodes = 0;\r
-  if (AsciiStrCmp (*Ptr, "HALT") == 0) {\r
-    *Ptr += 4;\r
-    Status = RETURN_NOT_FOUND;\r
-  } else {\r
-    Status = ParseOfwNode (Ptr, &Node[NumNodes], &IsFinal);\r
-  }\r
-\r
-  if (Status == RETURN_NOT_FOUND) {\r
-    DEBUG ((DEBUG_VERBOSE, "%a: no more nodes\n", __FUNCTION__));\r
-    return RETURN_NOT_FOUND;\r
-  }\r
-\r
-  while (Status == RETURN_SUCCESS && !IsFinal) {\r
-    ++NumNodes;\r
-    Status = ParseOfwNode (\r
-               Ptr,\r
-               (NumNodes < EXAMINED_OFW_NODES) ? &Node[NumNodes] : &Skip,\r
-               &IsFinal\r
-               );\r
-  }\r
-\r
-  switch (Status) {\r
-  case RETURN_SUCCESS:\r
-    ++NumNodes;\r
-    break;\r
-\r
-  case RETURN_INVALID_PARAMETER:\r
-    DEBUG ((DEBUG_VERBOSE, "%a: parse error\n", __FUNCTION__));\r
-    return RETURN_INVALID_PARAMETER;\r
-\r
-  default:\r
-    ASSERT (0);\r
-  }\r
-\r
-  Status = TranslateOfwNodes (\r
-             Node,\r
-             NumNodes < EXAMINED_OFW_NODES ? NumNodes : EXAMINED_OFW_NODES,\r
-             ExtraPciRoots,\r
-             Translated,\r
-             TranslatedSize);\r
-  switch (Status) {\r
-  case RETURN_SUCCESS:\r
-    DEBUG ((DEBUG_VERBOSE, "%a: success: \"%s\"\n", __FUNCTION__, Translated));\r
-    break;\r
-\r
-  case RETURN_BUFFER_TOO_SMALL:\r
-    DEBUG ((DEBUG_VERBOSE, "%a: buffer too small\n", __FUNCTION__));\r
-    break;\r
-\r
-  case RETURN_UNSUPPORTED:\r
-    DEBUG ((DEBUG_VERBOSE, "%a: unsupported\n", __FUNCTION__));\r
-    break;\r
-\r
-  case RETURN_PROTOCOL_ERROR:\r
-    DEBUG ((DEBUG_VERBOSE, "%a: logic error / system state mismatch\n",\r
-      __FUNCTION__));\r
-    break;\r
-\r
-  default:\r
-    ASSERT (0);\r
-  }\r
-  return Status;\r
-}\r
-\r
-\r
-/**\r
-\r
-  Convert the UEFI DevicePath to full text representation with DevPathToText,\r
-  then match the UEFI device path fragment in Translated against it.\r
-\r
-  @param[in] Translated        UEFI device path fragment, translated from\r
-                               OpenFirmware format, to search for.\r
-\r
-  @param[in] TranslatedLength  The length of Translated in CHAR16's.\r
-\r
-  @param[in] DevicePath        Boot option device path whose textual rendering\r
-                               to search in.\r
-\r
-  @param[in] DevPathToText  Binary-to-text conversion protocol for DevicePath.\r
-\r
-\r
-  @retval TRUE   If Translated was found at the beginning of DevicePath after\r
-                 converting the latter to text.\r
-\r
-  @retval FALSE  If DevicePath was NULL, or it could not be converted, or there\r
-                 was no match.\r
-\r
-**/\r
-STATIC\r
-BOOLEAN\r
-Match (\r
-  IN  CONST CHAR16                           *Translated,\r
-  IN  UINTN                                  TranslatedLength,\r
-  IN  EFI_DEVICE_PATH_PROTOCOL               *DevicePath\r
-  )\r
-{\r
-  CHAR16                   *Converted;\r
-  BOOLEAN                  Result;\r
-  VOID                     *FileBuffer;\r
-  UINTN                    FileSize;\r
-  EFI_DEVICE_PATH_PROTOCOL *AbsDevicePath;\r
-  CHAR16                   *AbsConverted;\r
-  BOOLEAN                  Shortform;\r
-  EFI_DEVICE_PATH_PROTOCOL *Node;\r
-\r
-  Converted = ConvertDevicePathToText (\r
-                DevicePath,\r
-                FALSE, // DisplayOnly\r
-                FALSE  // AllowShortcuts\r
-                );\r
-  if (Converted == NULL) {\r
-    return FALSE;\r
-  }\r
-\r
-  Result = FALSE;\r
-  Shortform = FALSE;\r
-  //\r
-  // Expand the short-form device path to full device path\r
-  //\r
-  if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&\r
-      (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)) {\r
-    //\r
-    // Harddrive shortform device path\r
-    //\r
-    Shortform = TRUE;\r
-  } else if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&\r
-             (DevicePathSubType (DevicePath) == MEDIA_FILEPATH_DP)) {\r
-    //\r
-    // File-path shortform device path\r
-    //\r
-    Shortform = TRUE;\r
-  } else if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&\r
-             (DevicePathSubType (DevicePath) == MSG_URI_DP)) {\r
-    //\r
-    // URI shortform device path\r
-    //\r
-    Shortform = TRUE;\r
-  } else {\r
-    for ( Node = DevicePath\r
-        ; !IsDevicePathEnd (Node)\r
-        ; Node = NextDevicePathNode (Node)\r
-        ) {\r
-      if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) &&\r
-          ((DevicePathSubType (Node) == MSG_USB_CLASS_DP) ||\r
-           (DevicePathSubType (Node) == MSG_USB_WWID_DP))) {\r
-        Shortform = TRUE;\r
-        break;\r
-      }\r
-    }\r
-  }\r
-\r
-  //\r
-  // Attempt to expand any relative UEFI device path to\r
-  // an absolute device path first.\r
-  //\r
-  if (Shortform) {\r
-    FileBuffer = EfiBootManagerGetLoadOptionBuffer (\r
-                   DevicePath, &AbsDevicePath, &FileSize\r
-                   );\r
-    if (FileBuffer == NULL) {\r
-      goto Exit;\r
-    }\r
-    FreePool (FileBuffer);\r
-    AbsConverted = ConvertDevicePathToText (AbsDevicePath, FALSE, FALSE);\r
-    FreePool (AbsDevicePath);\r
-    if (AbsConverted == NULL) {\r
-      goto Exit;\r
-    }\r
-    DEBUG ((DEBUG_VERBOSE,\r
-      "%a: expanded relative device path \"%s\" for prefix matching\n",\r
-      __FUNCTION__, Converted));\r
-    FreePool (Converted);\r
-    Converted = AbsConverted;\r
-  }\r
-\r
-  //\r
-  // Is Translated a prefix of Converted?\r
-  //\r
-  Result = (BOOLEAN)(StrnCmp (Converted, Translated, TranslatedLength) == 0);\r
-  DEBUG ((\r
-    DEBUG_VERBOSE,\r
-    "%a: against \"%s\": %a\n",\r
-    __FUNCTION__,\r
-    Converted,\r
-    Result ? "match" : "no match"\r
-    ));\r
-Exit:\r
-  FreePool (Converted);\r
-  return Result;\r
-}\r
-\r
-\r
-/**\r
-  Append some of the unselected active boot options to the boot order.\r
-\r
-  This function should accommodate any further policy changes in "boot option\r
-  survival". Currently we're adding back everything that starts with neither\r
-  PciRoot() nor HD() nor a virtio-mmio VenHw() node.\r
-\r
-  @param[in,out] BootOrder     The structure holding the boot order to\r
-                               complete. The caller is responsible for\r
-                               initializing (and potentially populating) it\r
-                               before calling this function.\r
-\r
-  @param[in,out] ActiveOption  The array of active boot options to scan.\r
-                               Entries marked as Appended will be skipped.\r
-                               Those of the rest that satisfy the survival\r
-                               policy will be added to BootOrder with\r
-                               BootOrderAppend().\r
-\r
-  @param[in]     ActiveCount   Number of elements in ActiveOption.\r
-\r
-\r
-  @retval RETURN_SUCCESS  BootOrder has been extended with any eligible boot\r
-                          options.\r
-\r
-  @return                 Error codes returned by BootOrderAppend().\r
-**/\r
-STATIC\r
-RETURN_STATUS\r
-BootOrderComplete (\r
-  IN OUT  BOOT_ORDER    *BootOrder,\r
-  IN OUT  ACTIVE_OPTION *ActiveOption,\r
-  IN      UINTN         ActiveCount\r
-  )\r
-{\r
-  RETURN_STATUS Status;\r
-  UINTN         Idx;\r
-\r
-  Status = RETURN_SUCCESS;\r
-  Idx = 0;\r
-  while (!RETURN_ERROR (Status) && Idx < ActiveCount) {\r
-    if (!ActiveOption[Idx].Appended) {\r
-      CONST EFI_BOOT_MANAGER_LOAD_OPTION *Current;\r
-      CONST EFI_DEVICE_PATH_PROTOCOL     *FirstNode;\r
-\r
-      Current = ActiveOption[Idx].BootOption;\r
-      FirstNode = Current->FilePath;\r
-      if (FirstNode != NULL) {\r
-        CHAR16        *Converted;\r
-        STATIC CHAR16 ConvFallBack[] = L"<unable to convert>";\r
-        BOOLEAN       Keep;\r
-\r
-        Converted = ConvertDevicePathToText (FirstNode, FALSE, FALSE);\r
-        if (Converted == NULL) {\r
-          Converted = ConvFallBack;\r
-        }\r
-\r
-        Keep = TRUE;\r
-        if (DevicePathType(FirstNode) == MEDIA_DEVICE_PATH &&\r
-            DevicePathSubType(FirstNode) == MEDIA_HARDDRIVE_DP) {\r
-          //\r
-          // drop HD()\r
-          //\r
-          Keep = FALSE;\r
-        } else if (DevicePathType(FirstNode) == ACPI_DEVICE_PATH &&\r
-                   DevicePathSubType(FirstNode) == ACPI_DP) {\r
-          ACPI_HID_DEVICE_PATH *Acpi;\r
-\r
-          Acpi = (ACPI_HID_DEVICE_PATH *) FirstNode;\r
-          if ((Acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST &&\r
-              EISA_ID_TO_NUM (Acpi->HID) == 0x0a03) {\r
-            //\r
-            // drop PciRoot() if we enabled the user to select PCI-like boot\r
-            // options, by providing translation for such OFW device path\r
-            // fragments\r
-            //\r
-            Keep = !FeaturePcdGet (PcdQemuBootOrderPciTranslation);\r
-          }\r
-        } else if (DevicePathType(FirstNode) == HARDWARE_DEVICE_PATH &&\r
-                   DevicePathSubType(FirstNode) == HW_VENDOR_DP) {\r
-          VENDOR_DEVICE_PATH *VenHw;\r
-\r
-          VenHw = (VENDOR_DEVICE_PATH *)FirstNode;\r
-          if (CompareGuid (&VenHw->Guid, &gVirtioMmioTransportGuid)) {\r
-            //\r
-            // drop virtio-mmio if we enabled the user to select boot options\r
-            // referencing such device paths\r
-            //\r
-            Keep = !FeaturePcdGet (PcdQemuBootOrderMmioTranslation);\r
-          }\r
-        }\r
-\r
-        if (Keep) {\r
-          Status = BootOrderAppend (BootOrder, &ActiveOption[Idx]);\r
-          if (!RETURN_ERROR (Status)) {\r
-            DEBUG ((DEBUG_VERBOSE, "%a: keeping \"%s\"\n", __FUNCTION__,\r
-              Converted));\r
-          }\r
-        } else {\r
-          DEBUG ((DEBUG_VERBOSE, "%a: dropping \"%s\"\n", __FUNCTION__,\r
-            Converted));\r
-        }\r
-\r
-        if (Converted != ConvFallBack) {\r
-          FreePool (Converted);\r
-        }\r
-      }\r
-    }\r
-    ++Idx;\r
-  }\r
-  return Status;\r
-}\r
-\r
-\r
-/**\r
-  Delete Boot#### variables that stand for such active boot options that have\r
-  been dropped (ie. have not been selected by either matching or "survival\r
-  policy").\r
-\r
-  @param[in]  ActiveOption  The array of active boot options to scan. Each\r
-                            entry not marked as appended will trigger the\r
-                            deletion of the matching Boot#### variable.\r
-\r
-  @param[in]  ActiveCount   Number of elements in ActiveOption.\r
-**/\r
-STATIC\r
-VOID\r
-PruneBootVariables (\r
-  IN  CONST ACTIVE_OPTION *ActiveOption,\r
-  IN  UINTN               ActiveCount\r
-  )\r
-{\r
-  UINTN Idx;\r
-\r
-  for (Idx = 0; Idx < ActiveCount; ++Idx) {\r
-    if (!ActiveOption[Idx].Appended) {\r
-      CHAR16 VariableName[9];\r
-\r
-      UnicodeSPrintAsciiFormat (VariableName, sizeof VariableName, "Boot%04x",\r
-        ActiveOption[Idx].BootOption->OptionNumber);\r
-\r
-      //\r
-      // "The space consumed by the deleted variable may not be available until\r
-      // the next power cycle", but that's good enough.\r
-      //\r
-      gRT->SetVariable (VariableName, &gEfiGlobalVariableGuid,\r
-             0,   // Attributes, 0 means deletion\r
-             0,   // DataSize, 0 means deletion\r
-             NULL // Data\r
-             );\r
-    }\r
-  }\r
-}\r
-\r
-\r
-/**\r
-\r
-  Set the boot order based on configuration retrieved from QEMU.\r
-\r
-  Attempt to retrieve the "bootorder" fw_cfg file from QEMU. Translate the\r
-  OpenFirmware device paths therein to UEFI device path fragments. Match the\r
-  translated fragments against the current list of boot options, and rewrite\r
-  the BootOrder NvVar so that it corresponds to the order described in fw_cfg.\r
-\r
-  Platform BDS should call this function after EfiBootManagerConnectAll () and\r
-  EfiBootManagerRefreshAllBootOption () return.\r
-\r
-  @retval RETURN_SUCCESS            BootOrder NvVar rewritten.\r
-\r
-  @retval RETURN_UNSUPPORTED        QEMU's fw_cfg is not supported.\r
-\r
-  @retval RETURN_NOT_FOUND          Empty or nonexistent "bootorder" fw_cfg\r
-                                    file, or no match found between the\r
-                                    "bootorder" fw_cfg file and BootOptionList.\r
-\r
-  @retval RETURN_INVALID_PARAMETER  Parse error in the "bootorder" fw_cfg file.\r
-\r
-  @retval RETURN_OUT_OF_RESOURCES   Memory allocation failed.\r
-\r
-  @return                           Values returned by gBS->LocateProtocol ()\r
-                                    or gRT->SetVariable ().\r
-\r
-**/\r
-RETURN_STATUS\r
-SetBootOrderFromQemu (\r
-  VOID\r
-  )\r
-{\r
-  RETURN_STATUS                    Status;\r
-  FIRMWARE_CONFIG_ITEM             FwCfgItem;\r
-  UINTN                            FwCfgSize;\r
-  CHAR8                            *FwCfg;\r
-  CONST CHAR8                      *FwCfgPtr;\r
-\r
-  BOOT_ORDER                       BootOrder;\r
-  ACTIVE_OPTION                    *ActiveOption;\r
-  UINTN                            ActiveCount;\r
-\r
-  EXTRA_ROOT_BUS_MAP               *ExtraPciRoots;\r
-\r
-  UINTN                            TranslatedSize;\r
-  CHAR16                           Translated[TRANSLATION_OUTPUT_SIZE];\r
-  EFI_BOOT_MANAGER_LOAD_OPTION     *BootOptions;\r
-  UINTN                            BootOptionCount;\r
-\r
-  Status = QemuFwCfgFindFile ("bootorder", &FwCfgItem, &FwCfgSize);\r
-  if (Status != RETURN_SUCCESS) {\r
-    return Status;\r
-  }\r
-\r
-  if (FwCfgSize == 0) {\r
-    return RETURN_NOT_FOUND;\r
-  }\r
-\r
-  FwCfg = AllocatePool (FwCfgSize);\r
-  if (FwCfg == NULL) {\r
-    return RETURN_OUT_OF_RESOURCES;\r
-  }\r
-\r
-  QemuFwCfgSelectItem (FwCfgItem);\r
-  QemuFwCfgReadBytes (FwCfgSize, FwCfg);\r
-  if (FwCfg[FwCfgSize - 1] != '\0') {\r
-    Status = RETURN_INVALID_PARAMETER;\r
-    goto ErrorFreeFwCfg;\r
-  }\r
-\r
-  DEBUG ((DEBUG_VERBOSE, "%a: FwCfg:\n", __FUNCTION__));\r
-  DEBUG ((DEBUG_VERBOSE, "%a\n", FwCfg));\r
-  DEBUG ((DEBUG_VERBOSE, "%a: FwCfg: <end>\n", __FUNCTION__));\r
-  FwCfgPtr = FwCfg;\r
-\r
-  BootOrder.Produced  = 0;\r
-  BootOrder.Allocated = 1;\r
-  BootOrder.Data = AllocatePool (\r
-                     BootOrder.Allocated * sizeof (*BootOrder.Data)\r
-                     );\r
-  if (BootOrder.Data == NULL) {\r
-    Status = RETURN_OUT_OF_RESOURCES;\r
-    goto ErrorFreeFwCfg;\r
-  }\r
-\r
-  BootOptions = EfiBootManagerGetLoadOptions (\r
-                  &BootOptionCount, LoadOptionTypeBoot\r
-                  );\r
-  if (BootOptions == NULL) {\r
-    Status = RETURN_NOT_FOUND;\r
-    goto ErrorFreeBootOrder;\r
-  }\r
-\r
-  Status = CollectActiveOptions (\r
-             BootOptions, BootOptionCount, &ActiveOption, &ActiveCount\r
-             );\r
-  if (RETURN_ERROR (Status)) {\r
-    goto ErrorFreeBootOptions;\r
-  }\r
-\r
-  if (FeaturePcdGet (PcdQemuBootOrderPciTranslation)) {\r
-    Status = CreateExtraRootBusMap (&ExtraPciRoots);\r
-    if (EFI_ERROR (Status)) {\r
-      goto ErrorFreeActiveOption;\r
-    }\r
-  } else {\r
-    ExtraPciRoots = NULL;\r
-  }\r
-\r
-  //\r
-  // translate each OpenFirmware path\r
-  //\r
-  TranslatedSize = sizeof (Translated) / sizeof (Translated[0]);\r
-  Status = TranslateOfwPath (&FwCfgPtr, ExtraPciRoots, Translated,\r
-             &TranslatedSize);\r
-  while (Status == RETURN_SUCCESS ||\r
-         Status == RETURN_UNSUPPORTED ||\r
-         Status == RETURN_PROTOCOL_ERROR ||\r
-         Status == RETURN_BUFFER_TOO_SMALL) {\r
-    if (Status == RETURN_SUCCESS) {\r
-      UINTN Idx;\r
-\r
-      //\r
-      // match translated OpenFirmware path against all active boot options\r
-      //\r
-      for (Idx = 0; Idx < ActiveCount; ++Idx) {\r
-        if (Match (\r
-              Translated,\r
-              TranslatedSize, // contains length, not size, in CHAR16's here\r
-              ActiveOption[Idx].BootOption->FilePath\r
-              )\r
-            ) {\r
-          //\r
-          // match found, store ID and continue with next OpenFirmware path\r
-          //\r
-          Status = BootOrderAppend (&BootOrder, &ActiveOption[Idx]);\r
-          if (Status != RETURN_SUCCESS) {\r
-            goto ErrorFreeExtraPciRoots;\r
-          }\r
-          break;\r
-        }\r
-      } // scanned all active boot options\r
-    }   // translation successful\r
-\r
-    TranslatedSize = sizeof (Translated) / sizeof (Translated[0]);\r
-    Status = TranslateOfwPath (&FwCfgPtr, ExtraPciRoots, Translated,\r
-               &TranslatedSize);\r
-  } // scanning of OpenFirmware paths done\r
-\r
-  if (Status == RETURN_NOT_FOUND && BootOrder.Produced > 0) {\r
-    //\r
-    // No more OpenFirmware paths, some matches found: rewrite BootOrder NvVar.\r
-    // Some of the active boot options that have not been selected over fw_cfg\r
-    // should be preserved at the end of the boot order.\r
-    //\r
-    Status = BootOrderComplete (&BootOrder, ActiveOption, ActiveCount);\r
-    if (RETURN_ERROR (Status)) {\r
-      goto ErrorFreeExtraPciRoots;\r
-    }\r
-\r
-    //\r
-    // See Table 10 in the UEFI Spec 2.3.1 with Errata C for the required\r
-    // attributes.\r
-    //\r
-    Status = gRT->SetVariable (\r
-                    L"BootOrder",\r
-                    &gEfiGlobalVariableGuid,\r
-                    EFI_VARIABLE_NON_VOLATILE |\r
-                      EFI_VARIABLE_BOOTSERVICE_ACCESS |\r
-                      EFI_VARIABLE_RUNTIME_ACCESS,\r
-                    BootOrder.Produced * sizeof (*BootOrder.Data),\r
-                    BootOrder.Data\r
-                    );\r
-    if (EFI_ERROR (Status)) {\r
-      DEBUG ((DEBUG_ERROR, "%a: setting BootOrder: %r\n", __FUNCTION__, Status));\r
-      goto ErrorFreeExtraPciRoots;\r
-    }\r
-\r
-    DEBUG ((DEBUG_INFO, "%a: setting BootOrder: success\n", __FUNCTION__));\r
-    PruneBootVariables (ActiveOption, ActiveCount);\r
-  }\r
-\r
-ErrorFreeExtraPciRoots:\r
-  if (ExtraPciRoots != NULL) {\r
-    DestroyExtraRootBusMap (ExtraPciRoots);\r
-  }\r
-\r
-ErrorFreeActiveOption:\r
-  FreePool (ActiveOption);\r
-\r
-ErrorFreeBootOptions:\r
-  EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
-\r
-ErrorFreeBootOrder:\r
-  FreePool (BootOrder.Data);\r
-\r
-ErrorFreeFwCfg:\r
-  FreePool (FwCfg);\r
-\r
-  return Status;\r
-}\r
-\r
-\r
-/**\r
-  Calculate the number of seconds we should be showing the FrontPage progress\r
-  bar for.\r
-\r
-  @return  The TimeoutDefault argument for PlatformBdsEnterFrontPage().\r
-**/\r
-UINT16\r
-GetFrontPageTimeoutFromQemu (\r
-  VOID\r
-  )\r
-{\r
-  FIRMWARE_CONFIG_ITEM BootMenuWaitItem;\r
-  UINTN                BootMenuWaitSize;\r
-\r
-  QemuFwCfgSelectItem (QemuFwCfgItemBootMenu);\r
-  if (QemuFwCfgRead16 () == 0) {\r
-    //\r
-    // The user specified "-boot menu=off", or didn't specify "-boot\r
-    // menu=(on|off)" at all. Return the platform default.\r
-    //\r
-    return PcdGet16 (PcdPlatformBootTimeOut);\r
-  }\r
-\r
-  if (RETURN_ERROR (QemuFwCfgFindFile ("etc/boot-menu-wait", &BootMenuWaitItem,\r
-                      &BootMenuWaitSize)) ||\r
-      BootMenuWaitSize != sizeof (UINT16)) {\r
-    //\r
-    // "-boot menu=on" was specified without "splash-time=N". In this case,\r
-    // return three seconds if the platform default would cause us to skip the\r
-    // front page, and return the platform default otherwise.\r
-    //\r
-    UINT16 Timeout;\r
-\r
-    Timeout = PcdGet16 (PcdPlatformBootTimeOut);\r
-    if (Timeout == 0) {\r
-      Timeout = 3;\r
-    }\r
-    return Timeout;\r
-  }\r
-\r
-  //\r
-  // "-boot menu=on,splash-time=N" was specified, where N is in units of\r
-  // milliseconds. The Intel BDS Front Page progress bar only supports whole\r
-  // seconds, round N up.\r
-  //\r
-  QemuFwCfgSelectItem (BootMenuWaitItem);\r
-  return (UINT16)((QemuFwCfgRead16 () + 999) / 1000);\r
-}\r
diff --git a/OvmfPkg/Library/QemuNewBootOrderLib/QemuBootOrderLib.inf b/OvmfPkg/Library/QemuNewBootOrderLib/QemuBootOrderLib.inf
deleted file mode 100644 (file)
index 40a315b..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-## @file\r
-#  Rewrite the BootOrder NvVar based on QEMU's "bootorder" fw_cfg file.\r
-#\r
-#  Copyright (C) 2012 - 2014, Red Hat, Inc.\r
-#  Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>\r
-#\r
-#  This program and the accompanying materials are licensed and made available\r
-#  under the terms and conditions of the BSD License which accompanies this\r
-#  distribution.  The full text of the license may be found at\r
-#  http://opensource.org/licenses/bsd-license.php\r
-#\r
-#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR\r
-#  IMPLIED.\r
-#\r
-##\r
-\r
-[Defines]\r
-  INF_VERSION                    = 0x00010005\r
-  BASE_NAME                      = QemuNewBootOrderLib\r
-  FILE_GUID                      = 1D677A58-C753-4AF1-B552-EFE142DF8F57\r
-  MODULE_TYPE                    = DXE_DRIVER\r
-  VERSION_STRING                 = 1.0\r
-  LIBRARY_CLASS                  = QemuBootOrderLib|DXE_DRIVER\r
-\r
-#\r
-# The following information is for reference only and not required by the build\r
-# tools.\r
-#\r
-#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC ARM AARCH64\r
-#\r
-\r
-[Sources]\r
-  QemuBootOrderLib.c\r
-  ExtraRootBusMap.c\r
-\r
-[Packages]\r
-  MdePkg/MdePkg.dec\r
-  MdeModulePkg/MdeModulePkg.dec\r
-  OvmfPkg/OvmfPkg.dec\r
-\r
-[LibraryClasses]\r
-  QemuFwCfgLib\r
-  DebugLib\r
-  MemoryAllocationLib\r
-  UefiBootManagerLib\r
-  UefiBootServicesTableLib\r
-  UefiRuntimeServicesTableLib\r
-  BaseLib\r
-  PrintLib\r
-  DevicePathLib\r
-  BaseMemoryLib\r
-  OrderedCollectionLib\r
-\r
-[Guids]\r
-  gEfiGlobalVariableGuid\r
-  gVirtioMmioTransportGuid\r
-\r
-[FeaturePcd]\r
-  gUefiOvmfPkgTokenSpaceGuid.PcdQemuBootOrderPciTranslation\r
-  gUefiOvmfPkgTokenSpaceGuid.PcdQemuBootOrderMmioTranslation\r
-\r
-[Pcd]\r
-  gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut\r
-\r
-[Protocols]\r
-  gEfiDevicePathProtocolGuid                            ## CONSUMES\r
-  gEfiPciRootBridgeIoProtocolGuid                       ## CONSUMES\r
index 4b9759cf16a5e17e9ee1dad1404e4c5d1618d644..ccb3ffd0a5c62a94ab70d6423ca63e172f0453f6 100644 (file)
   UdpIoLib|MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf\r
   DpcLib|MdeModulePkg/Library/DxeDpcLib/DxeDpcLib.inf\r
   PlatformBootManagerLib|OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf\r
-  QemuBootOrderLib|OvmfPkg/Library/QemuNewBootOrderLib/QemuBootOrderLib.inf\r
+  QemuBootOrderLib|OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.inf\r
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf\r
 !if $(SMM_REQUIRE) == TRUE\r
   LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf\r
index 23f44dacb019b9eef9643be6d66889b3fc727e32..ee681fb1fd2b840869ccd523b2b238752d7bdd4f 100644 (file)
   UdpIoLib|MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf\r
   DpcLib|MdeModulePkg/Library/DxeDpcLib/DxeDpcLib.inf\r
   PlatformBootManagerLib|OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf\r
-  QemuBootOrderLib|OvmfPkg/Library/QemuNewBootOrderLib/QemuBootOrderLib.inf\r
+  QemuBootOrderLib|OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.inf\r
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf\r
 !if $(SMM_REQUIRE) == TRUE\r
   LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf\r
index f7e00caf5a4d0019208e7fe808cafa38a4945d1b..69916629079823b8cdc7337ae94a5f426bdbe81b 100644 (file)
   UdpIoLib|MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf\r
   DpcLib|MdeModulePkg/Library/DxeDpcLib/DxeDpcLib.inf\r
   PlatformBootManagerLib|OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf\r
-  QemuBootOrderLib|OvmfPkg/Library/QemuNewBootOrderLib/QemuBootOrderLib.inf\r
+  QemuBootOrderLib|OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.inf\r
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf\r
 !if $(SMM_REQUIRE) == TRUE\r
   LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf\r