]> 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 f9023572557321a190b6b691f570013d453cfe6a..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,18 +32,37 @@ 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[BM_OPTION_NAME_LEN];\r
@@ -50,10 +70,17 @@ BmIsKeyOptionValid (
   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
@@ -110,20 +137,58 @@ BmIsKeyOptionVariable (
   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
@@ -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
@@ -913,7 +966,10 @@ EfiBootManagerAddKeyOptionVariable (
   UINTN                          KeyOptionNumber;\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