]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Library/UefiBootManagerLib/BmHotkey.c
MdeModulePkg/UefiBootManagerLib: Remove assertion
[mirror_edk2.git] / MdeModulePkg / Library / UefiBootManagerLib / BmHotkey.c
index 8d398fb4c68afa895f38f1ec47c39399c6e2121b..d18ce02eb3461a0ad52cedcbea73ec130ec9383c 100644 (file)
@@ -1,7 +1,8 @@
 /** @file\r
   Hotkey library functions.\r
 \r
-Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2011 - 2017, Intel Corporation. All rights reserved.<BR>\r
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
 which accompanies this distribution.  The full text of the license may be found at\r
@@ -31,29 +32,55 @@ EFI_BOOT_MANAGER_LOAD_OPTION mBmHotkeyBootOption      = { LoadOptionNumberUnassi
 EFI_BOOT_MANAGER_KEY_OPTION  *mBmContinueKeyOption    = NULL;\r
 VOID                         *mBmTxtInExRegistration  = NULL;\r
 \r
+\r
+/**\r
+  Return the buffer size of the EFI_BOOT_MANAGER_KEY_OPTION data.\r
+\r
+  @param   KeyOption            The input key option info.\r
+\r
+  @retval  The buffer size of the key option data.\r
+**/\r
+UINTN\r
+BmSizeOfKeyOption (\r
+  IN CONST EFI_BOOT_MANAGER_KEY_OPTION  *KeyOption\r
+  )\r
+{\r
+  return OFFSET_OF (EFI_BOOT_MANAGER_KEY_OPTION, Keys)\r
+    + KeyOption->KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY);\r
+}\r
+\r
 /**\r
 \r
   Check whether the input key option is valid.\r
 \r
-  @param   KeyOption               Input key option info.\r
+  @param   KeyOption          Key option.\r
+  @param   KeyOptionSize      Size of the key option.\r
 \r
   @retval  TRUE               Input key option is valid.\r
   @retval  FALSE              Input key option is not valid.\r
 **/\r
 BOOLEAN\r
 BmIsKeyOptionValid (\r
-  IN EFI_BOOT_MANAGER_KEY_OPTION     *KeyOption\r
+  IN CONST EFI_BOOT_MANAGER_KEY_OPTION *KeyOption,\r
+  IN       UINTN                       KeyOptionSize\r
 )\r
 {\r
-  UINT16   OptionName[sizeof (L"Boot####")];\r
+  UINT16   OptionName[BM_OPTION_NAME_LEN];\r
   UINT8    *BootOption;\r
   UINTN    BootOptionSize;\r
   UINT32   Crc;\r
 \r
+  if (BmSizeOfKeyOption (KeyOption) != KeyOptionSize) {\r
+    return FALSE;\r
+  }\r
+\r
   //\r
   // Check whether corresponding Boot Option exist\r
   //\r
-  UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", KeyOption->BootOption);\r
+  UnicodeSPrint (\r
+    OptionName, sizeof (OptionName), L"%s%04x",\r
+    mBmLoadOptionName[LoadOptionTypeBoot], KeyOption->BootOption\r
+    );\r
   GetEfiGlobalVariable2 (OptionName, (VOID **) &BootOption, &BootOptionSize);\r
 \r
   if (BootOption == NULL) {\r
@@ -88,6 +115,7 @@ BmIsKeyOptionVariable (
   )\r
 {\r
   UINTN         Index;\r
+  UINTN         Uint;\r
   \r
   if (!CompareGuid (Guid, &gEfiGlobalVariableGuid) ||\r
       (StrSize (Name) != sizeof (L"Key####")) ||\r
@@ -98,32 +126,69 @@ BmIsKeyOptionVariable (
 \r
   *OptionNumber = 0;\r
   for (Index = 3; Index < 7; Index++) {\r
-    if ((Name[Index] >= L'0') && (Name[Index] <= L'9')) {\r
-      *OptionNumber = *OptionNumber * 16 + Name[Index] - L'0';\r
-    } else if ((Name[Index] >= L'A') && (Name[Index] <= L'F')) {\r
-      *OptionNumber = *OptionNumber * 16 + Name[Index] - L'A' + 10;\r
-    } else {\r
+    Uint = BmCharToUint (Name[Index]);\r
+    if (Uint == -1) {\r
       return FALSE;\r
+    } else {\r
+      *OptionNumber = (UINT16) Uint + *OptionNumber * 0x10;\r
     }\r
   }\r
 \r
   return TRUE;\r
 }\r
 \r
-/**\r
-  Return the buffer size of the EFI_BOOT_MANAGER_KEY_OPTION data.\r
+typedef struct {\r
+  EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions;\r
+  UINTN                       KeyOptionCount;\r
+} BM_COLLECT_KEY_OPTIONS_PARAM;\r
 \r
-  @param   KeyOption            The input key option info.\r
+/**\r
+  Visitor function to collect the key options from NV storage.\r
 \r
-  @retval  The buffer size of the key option data.\r
+  @param Name    Variable name.\r
+  @param Guid    Variable GUID.\r
+  @param Context The same context passed to BmForEachVariable.\r
 **/\r
-UINTN\r
-BmSizeOfKeyOption (\r
-  EFI_BOOT_MANAGER_KEY_OPTION  *KeyOption\r
+VOID\r
+BmCollectKeyOptions (\r
+  CHAR16               *Name,\r
+  EFI_GUID             *Guid,\r
+  VOID                 *Context\r
   )\r
 {\r
-  return OFFSET_OF (EFI_BOOT_MANAGER_KEY_OPTION, Keys)\r
-    + KeyOption->KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY);\r
+  UINTN                        Index;\r
+  BM_COLLECT_KEY_OPTIONS_PARAM *Param;\r
+  VOID                         *KeyOption;\r
+  UINT16                       OptionNumber;\r
+  UINTN                        KeyOptionSize;\r
+\r
+  Param = (BM_COLLECT_KEY_OPTIONS_PARAM *) Context;\r
+\r
+  if (BmIsKeyOptionVariable (Name, Guid, &OptionNumber)) {\r
+    GetEfiGlobalVariable2 (Name, &KeyOption, &KeyOptionSize);\r
+    ASSERT (KeyOption != NULL);\r
+    if (BmIsKeyOptionValid (KeyOption, KeyOptionSize)) {\r
+      Param->KeyOptions = ReallocatePool (\r
+                            Param->KeyOptionCount * sizeof (EFI_BOOT_MANAGER_KEY_OPTION),\r
+                            (Param->KeyOptionCount + 1) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION),\r
+                            Param->KeyOptions\r
+                            );\r
+      ASSERT (Param->KeyOptions != NULL);\r
+      //\r
+      // Insert the key option in order\r
+      //\r
+      for (Index = 0; Index < Param->KeyOptionCount; Index++) {\r
+        if (OptionNumber < Param->KeyOptions[Index].OptionNumber) {\r
+          break;\r
+        }\r
+      }\r
+      CopyMem (&Param->KeyOptions[Index + 1], &Param->KeyOptions[Index], (Param->KeyOptionCount - Index) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION));\r
+      CopyMem (&Param->KeyOptions[Index], KeyOption, KeyOptionSize);\r
+      Param->KeyOptions[Index].OptionNumber = OptionNumber;\r
+      Param->KeyOptionCount++;\r
+    }\r
+    FreePool (KeyOption);\r
+  }\r
 }\r
 \r
 /**\r
@@ -139,86 +204,20 @@ BmGetKeyOptions (
   OUT UINTN     *Count\r
   )\r
 {\r
-  EFI_STATUS                  Status;\r
-  UINTN                       Index;\r
-  CHAR16                      *Name;\r
-  EFI_GUID                    Guid;\r
-  UINTN                       NameSize;\r
-  UINTN                       NewNameSize;\r
-  EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions;\r
-  EFI_BOOT_MANAGER_KEY_OPTION *KeyOption;\r
-  UINT16                      OptionNumber;\r
+  BM_COLLECT_KEY_OPTIONS_PARAM Param;\r
 \r
   if (Count == NULL) {\r
     return NULL;\r
   }\r
 \r
-  *Count     = 0;\r
-  KeyOptions = NULL;\r
-\r
-  NameSize = sizeof (CHAR16);\r
-  Name     = AllocateZeroPool (NameSize);\r
-  ASSERT (Name != NULL);\r
-  while (TRUE) {\r
-    NewNameSize = NameSize;\r
-    Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);\r
-    if (Status == EFI_BUFFER_TOO_SMALL) {\r
-      Name = ReallocatePool (NameSize, NewNameSize, Name);\r
-      ASSERT (Name != NULL);\r
-      Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);\r
-      NameSize = NewNameSize;\r
-    }\r
-\r
-    if (Status == EFI_NOT_FOUND) {\r
-      break;\r
-    }\r
-    ASSERT_EFI_ERROR (Status);\r
-\r
-    if (BmIsKeyOptionVariable (Name ,&Guid, &OptionNumber)) {\r
-      GetEfiGlobalVariable2 (Name, (VOID**) &KeyOption, NULL);\r
-      ASSERT (KeyOption != NULL);\r
-      if (BmIsKeyOptionValid (KeyOption)) {\r
-        KeyOptions = ReallocatePool (\r
-                       *Count * sizeof (EFI_BOOT_MANAGER_KEY_OPTION),\r
-                       (*Count + 1) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION),\r
-                       KeyOptions\r
-                       );\r
-        ASSERT (KeyOptions != NULL);\r
-        //\r
-        // Insert the key option in order\r
-        //\r
-        for (Index = 0; Index < *Count; Index++) {\r
-          if (OptionNumber < KeyOptions[Index].OptionNumber) {\r
-            break;\r
-          }\r
-        }\r
-        CopyMem (&KeyOptions[Index + 1], &KeyOptions[Index], (*Count - Index) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION));\r
-        CopyMem (&KeyOptions[Index], KeyOption, BmSizeOfKeyOption (KeyOption));\r
-        KeyOptions[Index].OptionNumber = OptionNumber;\r
-        (*Count)++;\r
-      }\r
-      FreePool (KeyOption);\r
-    }\r
-  }\r
+  Param.KeyOptions = NULL;\r
+  Param.KeyOptionCount = 0;\r
 \r
-  FreePool (Name);\r
+  BmForEachVariable (BmCollectKeyOptions, (VOID *) &Param);\r
 \r
-  return KeyOptions;\r
-}\r
+  *Count = Param.KeyOptionCount;\r
 \r
-/**\r
-  Callback function for event.\r
-  \r
-  @param    Event          Event for this callback function.\r
-  @param    Context        Context pass to this function.\r
-**/\r
-VOID\r
-EFIAPI\r
-BmEmptyFunction (\r
-  IN EFI_EVENT                Event,\r
-  IN VOID                     *Context\r
-  )\r
-{\r
+  return Param.KeyOptions;\r
 }\r
 \r
 /**\r
@@ -349,7 +348,7 @@ BmHotkeyCallback (
 {\r
   LIST_ENTRY                    *Link;\r
   BM_HOTKEY                     *Hotkey;\r
-  CHAR16                        OptionName[sizeof ("Boot####")];\r
+  CHAR16                        OptionName[BM_OPTION_NAME_LEN];\r
   EFI_STATUS                    Status;\r
   EFI_KEY_DATA                  *HotkeyData;\r
 \r
@@ -401,7 +400,10 @@ BmHotkeyCallback (
           //\r
           // Launch its BootOption\r
           //\r
-          UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", Hotkey->BootOption);\r
+          UnicodeSPrint (\r
+            OptionName, sizeof (OptionName), L"%s%04x",\r
+            mBmLoadOptionName[LoadOptionTypeBoot], Hotkey->BootOption\r
+            );\r
           Status = EfiBootManagerVariableToLoadOption (OptionName, &mBmHotkeyBootOption);\r
           DEBUG ((EFI_D_INFO, "[Bds]Hotkey for %s pressed - %r\n", OptionName, Status));\r
           if (EFI_ERROR (Status)) {\r
@@ -424,6 +426,55 @@ BmHotkeyCallback (
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Return the active Simple Text Input Ex handle array.\r
+  If the SystemTable.ConsoleInHandle is NULL, the function returns all\r
+  founded Simple Text Input Ex handles.\r
+  Otherwise, it just returns the ConsoleInHandle.\r
+\r
+  @param Count  Return the handle count.\r
+\r
+  @retval The active console handles.\r
+**/\r
+EFI_HANDLE *\r
+BmGetActiveConsoleIn (\r
+  OUT UINTN                             *Count\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  EFI_HANDLE                            *Handles;\r
+\r
+  Handles = NULL;\r
+  *Count  = 0;\r
+\r
+  if (gST->ConsoleInHandle != NULL) {\r
+    Status = gBS->OpenProtocol (\r
+                    gST->ConsoleInHandle,\r
+                    &gEfiSimpleTextInputExProtocolGuid,\r
+                    NULL,\r
+                    gImageHandle,\r
+                    NULL,\r
+                    EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                    );\r
+    if (!EFI_ERROR (Status)) {\r
+      Handles = AllocateCopyPool (sizeof (EFI_HANDLE), &gST->ConsoleInHandle);\r
+      if (Handles != NULL) {\r
+        *Count = 1;\r
+      }\r
+    }\r
+  } else {\r
+    Status = gBS->LocateHandleBuffer (\r
+                    ByProtocol,\r
+                    &gEfiSimpleTextInputExProtocolGuid,\r
+                    NULL,\r
+                    Count,\r
+                    &Handles\r
+                    );\r
+  }\r
+\r
+  return Handles;\r
+}\r
+\r
 /**\r
   Unregister hotkey notify list.\r
 \r
@@ -445,13 +496,7 @@ BmUnregisterHotkeyNotify (
   EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL     *TxtInEx;\r
   VOID                                  *NotifyHandle;\r
 \r
-  gBS->LocateHandleBuffer (\r
-          ByProtocol,\r
-          &gEfiSimpleTextInputExProtocolGuid,\r
-          NULL,\r
-          &HandleCount,\r
-          &Handles\r
-          );\r
+  Handles = BmGetActiveConsoleIn (&HandleCount);\r
   for (Index = 0; Index < HandleCount; Index++) {\r
     Status = gBS->HandleProtocol (Handles[Index], &gEfiSimpleTextInputExProtocolGuid, (VOID **) &TxtInEx);\r
     ASSERT_EFI_ERROR (Status);\r
@@ -469,6 +514,10 @@ BmUnregisterHotkeyNotify (
     }\r
   }\r
 \r
+  if (Handles != NULL) {\r
+    FreePool (Handles);\r
+  }\r
+\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -616,10 +665,12 @@ BmProcessKeyOption (
 \r
   KeyShiftStateCount = 0;\r
   BmGenerateKeyShiftState (0, KeyOption, EFI_SHIFT_STATE_VALID, KeyShiftStates, &KeyShiftStateCount);\r
-  ASSERT (KeyShiftStateCount <= sizeof (KeyShiftStates) / sizeof (KeyShiftStates[0]));\r
+  ASSERT (KeyShiftStateCount <= ARRAY_SIZE (KeyShiftStates));\r
 \r
   EfiAcquireLock (&mBmHotkeyLock);\r
 \r
+  Handles = BmGetActiveConsoleIn (&HandleCount);\r
+\r
   for (Index = 0; Index < KeyShiftStateCount; Index++) {\r
     Hotkey = AllocateZeroPool (sizeof (BM_HOTKEY));\r
     ASSERT (Hotkey != NULL);\r
@@ -635,13 +686,6 @@ BmProcessKeyOption (
     }\r
     InsertTailList (&mBmHotkeyList, &Hotkey->Link);\r
 \r
-    gBS->LocateHandleBuffer (\r
-            ByProtocol,\r
-            &gEfiSimpleTextInputExProtocolGuid,\r
-            NULL,\r
-            &HandleCount,\r
-            &Handles\r
-            );\r
     for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {\r
       Status = gBS->HandleProtocol (Handles[HandleIndex], &gEfiSimpleTextInputExProtocolGuid, (VOID **) &TxtInEx);\r
       ASSERT_EFI_ERROR (Status);\r
@@ -649,6 +693,9 @@ BmProcessKeyOption (
     }\r
   }\r
 \r
+  if (Handles != NULL) {\r
+    FreePool (Handles);\r
+  }\r
   EfiReleaseLock (&mBmHotkeyLock);\r
 \r
   return EFI_SUCCESS;\r
@@ -823,13 +870,13 @@ EfiBootManagerStartHotkeyService (
   EFI_EVENT                    Event;\r
   UINT32                       *BootOptionSupport;\r
 \r
-  Status = GetEfiGlobalVariable2 (EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME, (VOID **) &BootOptionSupport, NULL);\r
-  ASSERT (BootOptionSupport != NULL);\r
-\r
-  if ((*BootOptionSupport & EFI_BOOT_OPTION_SUPPORT_KEY)  != 0) {\r
-    mBmHotkeySupportCount = ((*BootOptionSupport & EFI_BOOT_OPTION_SUPPORT_COUNT) >> LowBitSet32 (EFI_BOOT_OPTION_SUPPORT_COUNT));\r
+  GetEfiGlobalVariable2 (EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME, (VOID **) &BootOptionSupport, NULL);\r
+  if (BootOptionSupport != NULL) {\r
+    if ((*BootOptionSupport & EFI_BOOT_OPTION_SUPPORT_KEY)  != 0) {\r
+      mBmHotkeySupportCount = ((*BootOptionSupport & EFI_BOOT_OPTION_SUPPORT_COUNT) >> LowBitSet32 (EFI_BOOT_OPTION_SUPPORT_COUNT));\r
+    }\r
+    FreePool (BootOptionSupport);\r
   }\r
-  FreePool (BootOptionSupport);\r
 \r
   if (mBmHotkeySupportCount == 0) {\r
     DEBUG ((EFI_D_INFO, "Bds: BootOptionSupport NV variable forbids starting the hotkey service.\n"));\r
@@ -839,7 +886,7 @@ EfiBootManagerStartHotkeyService (
   Status = gBS->CreateEvent (\r
                   EVT_NOTIFY_WAIT,\r
                   TPL_CALLBACK,\r
-                  BmEmptyFunction,\r
+                  EfiEventEmptyFunction,\r
                   NULL,\r
                   &mBmHotkeyTriggered\r
                   );\r
@@ -859,13 +906,20 @@ EfiBootManagerStartHotkeyService (
     BmProcessKeyOption (mBmContinueKeyOption);\r
   }\r
 \r
-  EfiCreateProtocolNotifyEvent (\r
-    &gEfiSimpleTextInputExProtocolGuid,\r
-    TPL_CALLBACK,\r
-    BmTxtInExCallback,\r
-    NULL,\r
-    &mBmTxtInExRegistration\r
-    );\r
+  //\r
+  // Hook hotkey on every future SimpleTextInputEx instance when\r
+  // SystemTable.ConsoleInHandle == NULL, which means the console\r
+  // manager (ConSplitter) is absent.\r
+  //\r
+  if (gST->ConsoleInHandle == NULL) {\r
+    EfiCreateProtocolNotifyEvent (\r
+      &gEfiSimpleTextInputExProtocolGuid,\r
+      TPL_CALLBACK,\r
+      BmTxtInExCallback,\r
+      NULL,\r
+      &mBmTxtInExRegistration\r
+      );\r
+  }\r
 \r
   Status = EfiCreateEventReadyToBootEx (\r
              TPL_CALLBACK,\r
@@ -875,7 +929,6 @@ EfiBootManagerStartHotkeyService (
              );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
-\r
   mBmHotkeyServiceStarted = TRUE;\r
   return Status;\r
 }\r
@@ -905,15 +958,18 @@ EfiBootManagerAddKeyOptionVariable (
   VA_LIST                        Args;\r
   VOID                           *BootOption;\r
   UINTN                          BootOptionSize;\r
-  CHAR16                         BootOptionName[sizeof (L"Boot####")];\r
+  CHAR16                         BootOptionName[BM_OPTION_NAME_LEN];\r
   EFI_BOOT_MANAGER_KEY_OPTION    KeyOption;\r
   EFI_BOOT_MANAGER_KEY_OPTION    *KeyOptions;\r
   UINTN                          KeyOptionCount;\r
   UINTN                          Index;\r
   UINTN                          KeyOptionNumber;\r
-  CHAR16                         KeyOptionName[sizeof (L"Key####")];\r
+  CHAR16                         KeyOptionName[sizeof ("Key####")];\r
 \r
-  UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", BootOptionNumber);\r
+  UnicodeSPrint (\r
+    BootOptionName, sizeof (BootOptionName), L"%s%04x",\r
+    mBmLoadOptionName[LoadOptionTypeBoot], BootOptionNumber\r
+    );\r
   GetEfiGlobalVariable2 (BootOptionName, &BootOption, &BootOptionSize);\r
 \r
   if (BootOption == NULL) {\r
@@ -1018,7 +1074,7 @@ EfiBootManagerDeleteKeyOptionVariable (
   BM_HOTKEY                      *Hotkey;\r
   UINT32                         ShiftState;\r
   BOOLEAN                        Match;\r
-  CHAR16                         KeyOptionName[sizeof (L"Key####")];\r
+  CHAR16                         KeyOptionName[sizeof ("Key####")];\r
 \r
   ZeroMem (&KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));\r
   VA_START (Args, Modifier);\r