]> git.proxmox.com Git - mirror_edk2.git/blobdiff - EdkNt32Pkg/Library/EdkGenericBdsLib/BdsMisc.c
Update video card preference policy, together with some memory leaks in Generic BDS...
[mirror_edk2.git] / EdkNt32Pkg / Library / EdkGenericBdsLib / BdsMisc.c
index 576ae7237f721dd065cb7d383d1ef3d4da21ac55..e7add072e18c30da4dfc828356c74df5b92bafc3 100644 (file)
@@ -19,6 +19,9 @@ Abstract:
 \r
 --*/\r
 \r
+#define MAX_STRING_LEN        200\r
+static BOOLEAN   mFeaturerSwitch = TRUE;\r
+static BOOLEAN   mResetRequired  = FALSE;\r
 extern UINT16 gPlatformBootTimeOutDefault;\r
 \r
 UINT16\r
@@ -648,6 +651,95 @@ Returns:
   return Buffer;\r
 }\r
 \r
+VOID\r
+BdsLibSafeFreePool (\r
+  IN  VOID             *Buffer\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Free pool safely.\r
+\r
+Arguments:\r
+  \r
+  Buffer          - The allocated pool entry to free\r
+\r
+Returns:\r
+\r
+  Pointer of the buffer allocated.\r
+\r
+--*/\r
+{\r
+  if (Buffer != NULL) {\r
+    gBS->FreePool (Buffer);\r
+    Buffer = NULL;\r
+  }\r
+}\r
+\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+BdsLibDelPartMatchInstance (\r
+  IN     EFI_DEVICE_PATH_PROTOCOL  *Multi,\r
+  IN     EFI_DEVICE_PATH_PROTOCOL  *Single\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Delete the instance in Multi which matches partly with Single instance\r
+\r
+Arguments:\r
+\r
+  Multi        - A pointer to a multi-instance device path data structure.\r
+\r
+  Single       - A pointer to a single-instance device path data structure.\r
+\r
+Returns:\r
+\r
+  This function will remove the device path instances in Multi which partly \r
+  match with the Single, and return the result device path. If there is no\r
+  remaining device path as a result, this function will return NULL.\r
+\r
+--*/\r
+{\r
+  EFI_DEVICE_PATH_PROTOCOL  *Instance;\r
+  EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  *TempNewDevicePath;\r
+  UINTN                     InstanceSize;\r
+  UINTN                     SingleDpSize;  \r
+  UINTN                     Size; \r
+  \r
+  NewDevicePath     = NULL;\r
+  TempNewDevicePath = NULL;\r
+\r
+  if (Multi == NULL || Single == NULL) {\r
+    return Multi;\r
+  }\r
+  \r
+  Instance        =  GetNextDevicePathInstance (&Multi, &InstanceSize);\r
+  SingleDpSize    =  GetDevicePathSize (Single) - END_DEVICE_PATH_LENGTH;\r
+  InstanceSize    -= END_DEVICE_PATH_LENGTH;\r
+\r
+  while (Instance != NULL) {\r
+\r
+    Size = (SingleDpSize < InstanceSize) ? SingleDpSize : InstanceSize;    \r
+        \r
+    if ((CompareMem (Instance, Single, Size) != 0)) {\r
+      //\r
+      // Append the device path instance which does not match with Single\r
+      //\r
+      TempNewDevicePath = NewDevicePath;\r
+      NewDevicePath = AppendDevicePathInstance (NewDevicePath, Instance);\r
+      BdsLibSafeFreePool(TempNewDevicePath);\r
+    }\r
+    BdsLibSafeFreePool(Instance);\r
+    Instance = GetNextDevicePathInstance (&Multi, &InstanceSize);\r
+    InstanceSize  -= END_DEVICE_PATH_LENGTH;\r
+  }\r
+  \r
+  return NewDevicePath;\r
+}\r
+\r
 BOOLEAN\r
 BdsLibMatchDevicePaths (\r
   IN  EFI_DEVICE_PATH_PROTOCOL  *Multi,\r
@@ -685,7 +777,6 @@ Returns:
 \r
   DevicePath      = Multi;\r
   DevicePathInst  = GetNextDevicePathInstance (&DevicePath, &Size);\r
-  Size -= sizeof (EFI_DEVICE_PATH_PROTOCOL);\r
 \r
   //\r
   // Search for the match of 'Single' in 'Multi'\r
@@ -695,17 +786,13 @@ Returns:
     // If the single device path is found in multiple device paths,\r
     // return success\r
     //\r
-    if (Size == 0) {\r
-      return FALSE;\r
-    }\r
-\r
     if (CompareMem (Single, DevicePathInst, Size) == 0) {\r
+      gBS->FreePool (DevicePathInst);\r
       return TRUE;\r
     }\r
 \r
     gBS->FreePool (DevicePathInst);\r
     DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);\r
-    Size -= sizeof (EFI_DEVICE_PATH_PROTOCOL);\r
   }\r
 \r
   return FALSE;\r
@@ -762,3 +849,271 @@ Returns:
 \r
   return Status;\r
 }\r
+\r
+//\r
+//  Following are BDS Lib functions which  contain all the code about setup browser reset reminder feature.\r
+//  Setup Browser reset reminder feature is that an reset reminder will be given before user leaves the setup browser  if \r
+//  user change any option setting which needs a reset to be effective, and  the reset will be applied according to  the user selection.\r
+//\r
+\r
+VOID\r
+EnableResetReminderFeature (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
\r
+  Enable the setup browser reset reminder feature.\r
+  This routine is used in platform tip. If the platform policy need the feature, use the routine to enable it.\r
+\r
+Arguments:\r
+\r
+  VOID\r
+\r
+Returns:\r
+\r
+  VOID\r
+\r
+--*/\r
+{\r
+  mFeaturerSwitch = TRUE;\r
+} \r
+\r
+VOID\r
+DisableResetReminderFeature (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
\r
+  Disable the setup browser reset reminder feature.\r
+  This routine is used in platform tip. If the platform policy do not want the feature, use the routine to disable it.\r
+  \r
+Arguments:\r
+\r
+  VOID\r
+\r
+Returns:\r
+\r
+  VOID\r
+\r
+--*/\r
+{\r
+  mFeaturerSwitch = FALSE;\r
+} \r
+\r
+VOID\r
+EnableResetRequired (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
\r
+   Record the info that  a reset is required.\r
+   A  module boolean variable is used to record whether a reset is required. \r
+  \r
+Arguments:\r
+\r
+  VOID\r
+\r
+Returns:\r
+\r
+  VOID\r
+\r
+--*/\r
+{\r
+  mResetRequired = TRUE;\r
+} \r
+\r
+VOID\r
+DisableResetRequired (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+   Record the info that  no reset is required.\r
+   A  module boolean variable is used to record whether a reset is required. \r
+\r
+Arguments:\r
+\r
+  VOID\r
+\r
+Returns:\r
+\r
+  VOID\r
+\r
+--*/\r
+{\r
+  mResetRequired = FALSE;\r
+} \r
+\r
+BOOLEAN\r
+IsResetReminderFeatureEnable (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
\r
+  Check whether platform policy enable the reset reminder feature. The default is enabled.\r
+\r
+Arguments:\r
+\r
+  VOID\r
+\r
+Returns:\r
+\r
+  VOID\r
+\r
+--*/\r
+{\r
+  return mFeaturerSwitch;\r
+}\r
+\r
+BOOLEAN\r
+IsResetRequired (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
\r
+  Check if  user changed any option setting which needs a system reset to be effective.\r
+  \r
+Arguments:\r
+\r
+  VOID\r
+\r
+Returns:\r
+\r
+  VOID\r
+\r
+--*/\r
+{\r
+  return mResetRequired;\r
+}\r
+\r
+VOID\r
+SetupResetReminder (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
\r
+  Check whether a reset is needed, and finish the reset reminder feature.\r
+  If a reset is needed, Popup a menu to notice user, and finish the feature \r
+  according to the user selection.\r
+\r
+Arguments:\r
+\r
+  VOID\r
+\r
+Returns:\r
+\r
+  VOID\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_FORM_BROWSER_PROTOCOL     *Browser;\r
+  EFI_INPUT_KEY                 Key;  \r
+  CHAR16                        *StringBuffer1;\r
+  CHAR16                        *StringBuffer2;    \r
+\r
+\r
+  //\r
+  //check any reset required change is applied? if yes, reset system\r
+  //\r
+  if (IsResetReminderFeatureEnable ()) {\r
+    if (IsResetRequired ()) {\r
+    \r
+      Status = gBS->LocateProtocol (\r
+                      &gEfiFormBrowserProtocolGuid,\r
+                      NULL,\r
+                      &Browser\r
+                      );      \r
+                      \r
+      StringBuffer1 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));\r
+      ASSERT (StringBuffer1 != NULL);\r
+      StringBuffer2 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));\r
+      ASSERT (StringBuffer2 != NULL);      \r
+      StrCpy (StringBuffer1, L"Configuration changed. Reset to apply it Now ? ");\r
+      StrCpy (StringBuffer2, L"Enter (YES)  /   Esc (NO)");      \r
+      //\r
+      // Popup a menu to notice user\r
+      // \r
+      do {\r
+        Browser->CreatePopUp (2, TRUE, 0, NULL, &Key, StringBuffer1, StringBuffer2);\r
+      } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN)); \r
+      \r
+      gBS->FreePool (StringBuffer1);      \r
+      gBS->FreePool (StringBuffer2);            \r
+      //\r
+      // If the user hits the YES Response key, reset\r
+      //\r
+      if ((Key.UnicodeChar == CHAR_CARRIAGE_RETURN)) {\r
+        gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);\r
+      }\r
+      gST->ConOut->ClearScreen (gST->ConOut);\r
+    } \r
+  } \r
+} \r
+\r
+EFI_STATUS\r
+BdsLibGetHiiHandles (\r
+  IN     EFI_HII_PROTOCOL *Hii,\r
+  IN OUT UINT16           *HandleBufferLength,\r
+  OUT    EFI_HII_HANDLE   **HiiHandleBuffer\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Determines the handles that are currently active in the database.\r
+  It's the caller's responsibility to free handle buffer.\r
+\r
+Arguments:\r
+\r
+  This                  - A pointer to the EFI_HII_PROTOCOL instance.\r
+  HandleBufferLength    - On input, a pointer to the length of the handle buffer. On output, \r
+                          the length of the handle buffer that is required for the handles found.\r
+  HiiHandleBuffer       - Pointer to an array of EFI_HII_PROTOCOL instances returned.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - Get an array of EFI_HII_PROTOCOL instances successfully.\r
+  EFI_INVALID_PARAMETER - Hii is NULL.\r
+  EFI_NOT_FOUND         - Database not found.\r
+  \r
+--*/\r
+{\r
+  UINT16      TempBufferLength;\r
+  EFI_STATUS  Status;\r
+  \r
+  TempBufferLength = 0;\r
+  \r
+  //\r
+  // Try to find the actual buffer size for HiiHandle Buffer.\r
+  //\r
+  Status = Hii->FindHandles (Hii, &TempBufferLength, *HiiHandleBuffer);\r
+  \r
+  if (Status == EFI_BUFFER_TOO_SMALL) {\r
+    *HiiHandleBuffer = AllocateZeroPool (TempBufferLength);\r
+    Status = Hii->FindHandles (Hii, &TempBufferLength, *HiiHandleBuffer);\r
+    //\r
+    // we should not fail here.\r
+    //\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+  \r
+  *HandleBufferLength = TempBufferLength;\r
+  \r
+  return Status;\r
+  \r
+}\r