]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/Library/PlatformBdsLib/QemuBootOrder.c
ArmVirtualizationPkg: PlatformIntelBdsLib: add basic policy
[mirror_edk2.git] / OvmfPkg / Library / PlatformBdsLib / QemuBootOrder.c
index 31c3378856da2fd6458770e335a39a484d212e4d..bd0fb768779bd7c84ad4a299dfbae4bfbfb5b110 100644 (file)
@@ -763,37 +763,27 @@ TranslateOfwNodes (
       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
@@ -849,8 +839,11 @@ TranslateOfwNodes (
                                     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
@@ -869,8 +862,14 @@ TranslateOfwPath (
   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
@@ -1012,6 +1011,146 @@ Exit:
 }\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
@@ -1140,6 +1279,15 @@ SetBootOrderFromQemu (
   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
@@ -1152,12 +1300,13 @@ SetBootOrderFromQemu (
                     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