/** @file\r
Rewrite the BootOrder NvVar based on QEMU's "bootorder" fw_cfg file.\r
\r
- Copyright (C) 2012, Red Hat, Inc.\r
+ Copyright (C) 2012 - 2013, Red Hat, Inc.\r
+ Copyright (c) 2013, 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
#include <Library/UefiRuntimeServicesTableLib.h>\r
#include <Library/BaseLib.h>\r
#include <Library/PrintLib.h>\r
-#include <Protocol/DevicePathToText.h>\r
+#include <Library/DevicePathLib.h>\r
#include <Guid/GlobalVariable.h>\r
\r
\r
\r
\r
/**\r
- Number of nodes in OpenFirmware device paths that is required and examined.\r
+ Numbers of nodes in OpenFirmware device paths that are required and examined.\r
**/\r
-#define FIXED_OFW_NODES 4\r
+#define REQUIRED_OFW_NODES 2\r
+#define EXAMINED_OFW_NODES 4\r
\r
\r
/**\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 BDS_COMMON_OPTION *BootOption; // reference only, no ownership\r
+ BOOLEAN Appended; // has been added to a BOOT_ORDER?\r
+} ACTIVE_OPTION;\r
+\r
+\r
/**\r
\r
- Append BootOptionId to BootOrder, reallocating the latter if needed.\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] BootOptionId The value to append to the array.\r
+ @param[in] ActiveOption The active boot option whose ID should be\r
+ appended to the array.\r
\r
\r
- @retval RETURN_SUCCESS BootOptionId appended.\r
+ @retval RETURN_SUCCESS ID of ActiveOption appended.\r
\r
@retval RETURN_OUT_OF_RESOURCES Memory reallocation failed.\r
\r
STATIC\r
RETURN_STATUS\r
BootOrderAppend (\r
- IN OUT BOOT_ORDER *BootOrder,\r
- IN UINT16 BootOptionId\r
+ IN OUT BOOT_ORDER *BootOrder,\r
+ IN OUT ACTIVE_OPTION *ActiveOption\r
)\r
{\r
if (BootOrder->Produced == BootOrder->Allocated) {\r
BootOrder->Data = DataNew;\r
}\r
\r
- BootOrder->Data[BootOrder->Produced++] = BootOptionId;\r
+ BootOrder->Data[BootOrder->Produced++] =\r
+ ActiveOption->BootOption->BootCurrent;\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 list.\r
+\r
+ @param[in] BootOptionList A boot option list, created with\r
+ BdsLibEnumerateAllBootOption().\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
+ BootOptionList.\r
+\r
+ @retval RETURN_OUT_OF_RESOURCES Memory allocation failed.\r
+\r
+**/\r
+STATIC\r
+RETURN_STATUS\r
+CollectActiveOptions (\r
+ IN CONST LIST_ENTRY *BootOptionList,\r
+ OUT ACTIVE_OPTION **ActiveOption,\r
+ OUT UINTN *Count\r
+ )\r
+{\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
+ CONST LIST_ENTRY *Link;\r
+\r
+ Link = BootOptionList->ForwardLink;\r
+ *Count = 0;\r
+ while (Link != BootOptionList) {\r
+ CONST BDS_COMMON_OPTION *Current;\r
+\r
+ Current = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);\r
+ if (IS_LOAD_OPTION_TYPE (Current->Attribute, LOAD_OPTION_ACTIVE)) {\r
+ if (ScanMode == 1) {\r
+ (*ActiveOption)[*Count].BootOption = Current;\r
+ (*ActiveOption)[*Count].Appended = FALSE;\r
+ }\r
+ ++*Count;\r
+ }\r
+ Link = Link->ForwardLink;\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
// Get PCI device and optional PCI function. Assume a single PCI root.\r
//\r
- if (NumNodes < FIXED_OFW_NODES ||\r
+ if (NumNodes < REQUIRED_OFW_NODES ||\r
!SubstringEq (OfwNode[0].DriverName, "pci")\r
) {\r
return RETURN_UNSUPPORTED;\r
return RETURN_UNSUPPORTED;\r
}\r
\r
- if (SubstringEq (OfwNode[1].DriverName, "ide") &&\r
+ if (NumNodes >= 4 &&\r
+ SubstringEq (OfwNode[1].DriverName, "ide") &&\r
SubstringEq (OfwNode[2].DriverName, "drive") &&\r
SubstringEq (OfwNode[3].DriverName, "disk")\r
) {\r
Secondary ? "Secondary" : "Primary",\r
Slave ? "Slave" : "Master"\r
);\r
- } else if (SubstringEq (OfwNode[1].DriverName, "isa") &&\r
+ } else if (NumNodes >= 4 &&\r
+ SubstringEq (OfwNode[1].DriverName, "isa") &&\r
SubstringEq (OfwNode[2].DriverName, "fdc") &&\r
SubstringEq (OfwNode[3].DriverName, "floppy")\r
) {\r
PciDevFun[1],\r
AcpiUid\r
);\r
+ } else if (NumNodes >= 3 &&\r
+ SubstringEq (OfwNode[1].DriverName, "scsi") &&\r
+ SubstringEq (OfwNode[2].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(0x0)/Pci(0x%x,0x%x)/HD(",\r
+ PciDevFun[0],\r
+ PciDevFun[1]\r
+ );\r
+ } else if (NumNodes >= 4 &&\r
+ SubstringEq (OfwNode[1].DriverName, "scsi") &&\r
+ SubstringEq (OfwNode[2].DriverName, "channel") &&\r
+ SubstringEq (OfwNode[3].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
+ UINT32 TargetLun[2];\r
+\r
+ TargetLun[1] = 0;\r
+ NumEntries = sizeof (TargetLun) / sizeof (TargetLun[0]);\r
+ if (ParseUnitAddressHexList (\r
+ OfwNode[3].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(0x0)/Pci(0x%x,0x%x)/Scsi(0x%x,0x%x)",\r
+ PciDevFun[0],\r
+ PciDevFun[1],\r
+ TargetLun[0],\r
+ TargetLun[1]\r
+ );\r
} else {\r
- return RETURN_UNSUPPORTED;\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(0x0)/Pci(0x%x,0x%x)",\r
+ PciDevFun[0],\r
+ PciDevFun[1]\r
+ );\r
}\r
\r
//\r
the current implementation. Further calls\r
to this function are possible.\r
\r
- @retval RETURN_NOT_FOUND Translation terminated, *Ptr was (and is)\r
- pointing to an empty string.\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
UINTN NumNodes;\r
RETURN_STATUS Status;\r
- OFW_NODE Node[FIXED_OFW_NODES];\r
+ OFW_NODE Node[EXAMINED_OFW_NODES];\r
BOOLEAN IsFinal;\r
OFW_NODE Skip;\r
\r
+ IsFinal = FALSE;\r
NumNodes = 0;\r
- Status = ParseOfwNode (Ptr, &Node[NumNodes], &IsFinal);\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
++NumNodes;\r
Status = ParseOfwNode (\r
Ptr,\r
- (NumNodes < FIXED_OFW_NODES) ? &Node[NumNodes] : &Skip,\r
+ (NumNodes < EXAMINED_OFW_NODES) ? &Node[NumNodes] : &Skip,\r
&IsFinal\r
);\r
}\r
\r
Status = TranslateOfwNodes (\r
Node,\r
- NumNodes < FIXED_OFW_NODES ? NumNodes : FIXED_OFW_NODES,\r
+ NumNodes < EXAMINED_OFW_NODES ? NumNodes : EXAMINED_OFW_NODES,\r
Translated,\r
TranslatedSize);\r
switch (Status) {\r
Match (\r
IN CONST CHAR16 *Translated,\r
IN UINTN TranslatedLength,\r
- IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
- IN CONST EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText\r
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
)\r
{\r
CHAR16 *Converted;\r
BOOLEAN Result;\r
\r
- Converted = DevPathToText->ConvertDevicePathToText (\r
- DevicePath,\r
- FALSE, // DisplayOnly\r
- FALSE // AllowShortcuts\r
- );\r
+ Converted = ConvertDevicePathToText (\r
+ DevicePath,\r
+ FALSE, // DisplayOnly\r
+ FALSE // AllowShortcuts\r
+ );\r
if (Converted == NULL) {\r
return FALSE;\r
}\r
\r
+ //\r
+ // Attempt to expand any relative UEFI device path starting with HD() to an\r
+ // absolute device path first. The logic imitates BdsLibBootViaBootOption().\r
+ // We don't have to free the absolute device path,\r
+ // BdsExpandPartitionPartialDevicePathToFull() has internal caching.\r
+ //\r
+ Result = FALSE;\r
+ if (DevicePathType (DevicePath) == MEDIA_DEVICE_PATH &&\r
+ DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP) {\r
+ EFI_DEVICE_PATH_PROTOCOL *AbsDevicePath;\r
+ CHAR16 *AbsConverted;\r
+\r
+ AbsDevicePath = BdsExpandPartitionPartialDevicePathToFull (\r
+ (HARDDRIVE_DEVICE_PATH *) DevicePath);\r
+ if (AbsDevicePath == NULL) {\r
+ goto Exit;\r
+ }\r
+ AbsConverted = ConvertDevicePathToText (AbsDevicePath, FALSE, FALSE);\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
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().\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 BDS_COMMON_OPTION *Current;\r
+ CONST EFI_DEVICE_PATH_PROTOCOL *FirstNode;\r
+\r
+ Current = ActiveOption[Idx].BootOption;\r
+ FirstNode = Current->DevicePath;\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()\r
+ //\r
+ Keep = FALSE;\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->BootCurrent);\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
{\r
RETURN_STATUS Status;\r
-\r
- EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText;\r
-\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
UINTN TranslatedSize;\r
CHAR16 Translated[TRANSLATION_OUTPUT_SIZE];\r
\r
- Status = gBS->LocateProtocol (\r
- &gEfiDevicePathToTextProtocolGuid,\r
- NULL, // optional registration key\r
- (VOID **) &DevPathToText\r
- );\r
- if (Status != EFI_SUCCESS) {\r
- return Status;\r
- }\r
-\r
Status = QemuFwCfgFindFile ("bootorder", &FwCfgItem, &FwCfgSize);\r
if (Status != RETURN_SUCCESS) {\r
return Status;\r
goto ErrorFreeFwCfg;\r
}\r
\r
+ Status = CollectActiveOptions (BootOptionList, &ActiveOption, &ActiveCount);\r
+ if (RETURN_ERROR (Status)) {\r
+ goto ErrorFreeBootOrder;\r
+ }\r
+\r
//\r
// translate each OpenFirmware path\r
//\r
Status == RETURN_UNSUPPORTED ||\r
Status == RETURN_BUFFER_TOO_SMALL) {\r
if (Status == RETURN_SUCCESS) {\r
- CONST LIST_ENTRY *Link;\r
+ UINTN Idx;\r
\r
//\r
- // match translated OpenFirmware path against all enumerated boot options\r
+ // match translated OpenFirmware path against all active boot options\r
//\r
- for (Link = BootOptionList->ForwardLink; Link != BootOptionList;\r
- Link = Link->ForwardLink) {\r
- CONST BDS_COMMON_OPTION *BootOption;\r
-\r
- BootOption = CR (\r
- Link,\r
- BDS_COMMON_OPTION,\r
- Link,\r
- BDS_LOAD_OPTION_SIGNATURE\r
- );\r
- if (IS_LOAD_OPTION_TYPE (BootOption->Attribute, LOAD_OPTION_ACTIVE) &&\r
- Match (\r
+ for (Idx = 0; Idx < ActiveCount; ++Idx) {\r
+ if (Match (\r
Translated,\r
TranslatedSize, // contains length, not size, in CHAR16's here\r
- BootOption->DevicePath,\r
- DevPathToText\r
+ ActiveOption[Idx].BootOption->DevicePath\r
)\r
) {\r
//\r
// match found, store ID and continue with next OpenFirmware path\r
//\r
- Status = BootOrderAppend (&BootOrder, BootOption->BootCurrent);\r
+ Status = BootOrderAppend (&BootOrder, &ActiveOption[Idx]);\r
if (Status != RETURN_SUCCESS) {\r
- goto ErrorFreeBootOrder;\r
+ goto ErrorFreeActiveOption;\r
}\r
break;\r
}\r
- } // scanned all enumerated boot options\r
+ } // scanned all active boot options\r
} // translation successful\r
\r
TranslatedSize = sizeof (Translated) / sizeof (Translated[0]);\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 ErrorFreeActiveOption;\r
+ }\r
+\r
+ //\r
// See Table 10 in the UEFI Spec 2.3.1 with Errata C for the required\r
// attributes.\r
//\r
BootOrder.Produced * sizeof (*BootOrder.Data),\r
BootOrder.Data\r
);\r
- DEBUG ((\r
- DEBUG_INFO,\r
- "%a: setting BootOrder: %a\n",\r
- __FUNCTION__,\r
- Status == EFI_SUCCESS ? "success" : "error"\r
- ));\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "%a: setting BootOrder: %r\n", __FUNCTION__, Status));\r
+ goto ErrorFreeActiveOption;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "%a: setting BootOrder: success\n", __FUNCTION__));\r
+ PruneBootVariables (ActiveOption, ActiveCount);\r
}\r
\r
+ErrorFreeActiveOption:\r
+ FreePool (ActiveOption);\r
+\r
ErrorFreeBootOrder:\r
FreePool (BootOrder.Data);\r
\r