TargetLun[0],\r
TargetLun[1]\r
);\r
- } else if (NumNodes >= 3 &&\r
- SubstringEq (OfwNode[1].DriverName, "ethernet") &&\r
- SubstringEq (OfwNode[2].DriverName, "ethernet-phy")\r
- ) {\r
+ } else {\r
//\r
- // OpenFirmware device path (Ethernet NIC):\r
+ // Generic OpenFirmware device path for PCI devices:\r
//\r
- // /pci@i0cf8/ethernet@3[,2]/ethernet-phy@0\r
- // ^ ^ ^\r
- // | | fixed\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)/MAC(525400E15EEF,0x1)\r
- // PciRoot(0x0)/Pci(0x3,0x2)/MAC(525400E15EEF,0x1)\r
- // ^ ^\r
- // MAC address IfType (1 == Ethernet)\r
- //\r
- // (Some UEFI NIC drivers don't set 0x1 for IfType.)\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)/MAC",\r
+ "PciRoot(0x0)/Pci(0x%x,0x%x)",\r
PciDevFun[0],\r
PciDevFun[1]\r
);\r
- } else {\r
- return RETURN_UNSUPPORTED;\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
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
}\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
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