]> git.proxmox.com Git - mirror_edk2.git/blobdiff - EdkUnixPkg/Dxe/PlatformBds/Generic/BootMngr/BootManager.c
Unix version of EFI emulator
[mirror_edk2.git] / EdkUnixPkg / Dxe / PlatformBds / Generic / BootMngr / BootManager.c
diff --git a/EdkUnixPkg/Dxe/PlatformBds/Generic/BootMngr/BootManager.c b/EdkUnixPkg/Dxe/PlatformBds/Generic/BootMngr/BootManager.c
new file mode 100644 (file)
index 0000000..23b8789
--- /dev/null
@@ -0,0 +1,355 @@
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation                                                         \r
+All rights reserved. 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
+http://opensource.org/licenses/bsd-license.php                                            \r
+                                                                                          \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+\r
+Module Name: \r
+\r
+  BootManager.c\r
+\r
+Abstract:\r
+\r
+  The platform boot manager reference implement\r
+\r
+--*/\r
+#include "BootManager.h"\r
+\r
+UINT16                            mKeyInput;\r
+LIST_ENTRY                        *mBootOptionsList;\r
+BDS_COMMON_OPTION                 *gOption;\r
+EFI_HII_HANDLE                    gBootManagerHandle;\r
+EFI_HANDLE                        BootManagerCallbackHandle;\r
+EFI_FORM_CALLBACK_PROTOCOL        BootManagerCallback;\r
+EFI_GUID                          gBmGuid = BOOT_MANAGER_GUID;\r
+\r
+extern EFI_FORM_BROWSER_PROTOCOL  *gBrowser;\r
+extern UINT8                      BootManagerVfrBin[];\r
+extern UINT8                      BdsStrings[];\r
+extern BOOLEAN                    gConnectAllHappened;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+BootManagerCallbackRoutine (\r
+  IN EFI_FORM_CALLBACK_PROTOCOL       *This,\r
+  IN UINT16                           KeyValue,\r
+  IN EFI_IFR_DATA_ARRAY               *DataArray,\r
+  OUT EFI_HII_CALLBACK_PACKET         **Packet\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  This is the function that is called to provide results data to the driver.  This data\r
+  consists of a unique key which is used to identify what data is either being passed back\r
+  or being asked for. \r
+\r
+Arguments:\r
+\r
+  KeyValue -        A unique value which is sent to the original exporting driver so that it\r
+                    can identify the type of data to expect.  The format of the data tends to\r
+                    vary based on the op-code that geerated the callback.\r
+\r
+  Data -            A pointer to the data being sent to the original exporting driver.\r
+\r
+Returns: \r
+\r
+--*/\r
+{\r
+  BDS_COMMON_OPTION       *Option;\r
+  LIST_ENTRY              *Link;\r
+  UINT16                  KeyCount;\r
+  EFI_HII_CALLBACK_PACKET *DataPacket;\r
+\r
+  //\r
+  // Initialize the key count\r
+  //\r
+  KeyCount = 0;\r
+\r
+  for (Link = mBootOptionsList->ForwardLink; Link != mBootOptionsList; Link = Link->ForwardLink) {\r
+    Option = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);\r
+\r
+    KeyCount++;\r
+\r
+    gOption = Option;\r
+\r
+    //\r
+    // Is this device the one chosen?\r
+    //\r
+    if (KeyCount == KeyValue) {\r
+      //\r
+      // Assigning the returned Key to a global allows the original routine to know what was chosen\r
+      //\r
+      mKeyInput = KeyValue;\r
+\r
+      *Packet   = AllocateZeroPool (sizeof (EFI_HII_CALLBACK_PACKET) + 2);\r
+      ASSERT (*Packet != NULL);\r
+\r
+      //\r
+      // Assign the buffer address to DataPacket\r
+      //\r
+      DataPacket                        = *Packet;\r
+\r
+      DataPacket->DataArray.EntryCount  = 1;\r
+      DataPacket->DataArray.NvRamMap    = NULL;\r
+      ((EFI_IFR_DATA_ENTRY *) (((EFI_IFR_DATA_ARRAY *)DataPacket) + 1))->Flags = EXIT_REQUIRED | NV_NOT_CHANGED;\r
+      return EFI_SUCCESS;\r
+    } else {\r
+      continue;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+VOID\r
+CallBootManager (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Hook to enable UI timeout override behavior.\r
+\r
+Arguments:\r
+  BdsDeviceList - Device List that BDS needs to connect.\r
+\r
+  Entry - Pointer to current Boot Entry.\r
+\r
+Returns:\r
+  NONE\r
+\r
+--*/\r
+{\r
+  EFI_STATUS          Status;\r
+  EFI_HII_PACKAGES    *PackageList;\r
+  BDS_COMMON_OPTION   *Option;\r
+  LIST_ENTRY          *Link;\r
+  EFI_HII_UPDATE_DATA *UpdateData;\r
+  CHAR16              *ExitData;\r
+  UINTN               ExitDataSize;\r
+  STRING_REF          Token;\r
+  STRING_REF          LastToken;\r
+  EFI_INPUT_KEY       Key;\r
+  UINT8               *Location;\r
+  EFI_GUID            BmGuid;\r
+  LIST_ENTRY          BdsBootOptionList;\r
+  BOOLEAN                BootMngrMenuResetRequired;\r
+\r
+  gOption = NULL;\r
+  InitializeListHead (&BdsBootOptionList);\r
+\r
+  //\r
+  // Connect all prior to entering the platform setup menu.\r
+  //\r
+  if (!gConnectAllHappened) {\r
+    BdsLibConnectAllDriversToAllControllers ();\r
+    gConnectAllHappened = TRUE;\r
+  }\r
+  //\r
+  // BugBug: Here we can not remove the legacy refresh macro, so we need\r
+  // get the boot order every time from "BootOrder" variable.\r
+  // Recreate the boot option list base on the BootOrder variable\r
+  //\r
+  BdsLibEnumerateAllBootOption (&BdsBootOptionList);\r
+\r
+  //\r
+  // This GUID must be the same as what is defined in BootManagerVfr.vfr\r
+  //\r
+  BmGuid            = gBmGuid;\r
+\r
+  mBootOptionsList  = &BdsBootOptionList;\r
+\r
+  //\r
+  // Post our VFR to the HII database\r
+  //\r
+  PackageList = PreparePackages (2, &BmGuid, BootManagerVfrBin, BdsStrings);\r
+  Status      = Hii->NewPack (Hii, PackageList, &gBootManagerHandle);\r
+  gBS->FreePool (PackageList);\r
+\r
+  //\r
+  // This example does not implement worker functions\r
+  // for the NV accessor functions.  Only a callback evaluator\r
+  //\r
+  BootManagerCallback.NvRead    = NULL;\r
+  BootManagerCallback.NvWrite   = NULL;\r
+  BootManagerCallback.Callback  = BootManagerCallbackRoutine;\r
+\r
+  //\r
+  // Install protocol interface\r
+  //\r
+  BootManagerCallbackHandle = NULL;\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &BootManagerCallbackHandle,\r
+                  &gEfiFormCallbackProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  &BootManagerCallback\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  LastToken = 0;\r
+  Hii->NewString (Hii, NULL, gBootManagerHandle, &LastToken, L" ");\r
+\r
+  //\r
+  // Allocate space for creation of UpdateData Buffer\r
+  //\r
+  UpdateData = AllocateZeroPool (0x1000);\r
+  ASSERT (UpdateData != NULL);\r
+\r
+  //\r
+  // Flag update pending in FormSet\r
+  //\r
+  UpdateData->FormSetUpdate = TRUE;\r
+  //\r
+  // Register CallbackHandle data for FormSet\r
+  //\r
+  UpdateData->FormCallbackHandle = (EFI_PHYSICAL_ADDRESS) (UINTN) BootManagerCallbackHandle;\r
+  UpdateData->FormUpdate  = FALSE;\r
+  UpdateData->FormTitle   = 0;\r
+  UpdateData->DataCount   = 1;\r
+\r
+  //\r
+  // Create blank space.  Since when we update the contents of IFR data at a label, it is\r
+  // inserted at the location of the label.  So if you want to add a string with an empty\r
+  // space afterwards, you need to add the space first and then the string like below.\r
+  //\r
+  Status = CreateSubTitleOpCode (\r
+            LastToken,        // Token Value for the string\r
+            &UpdateData->Data // Buffer containing created op-code\r
+            );\r
+\r
+  Hii->UpdateForm (Hii, gBootManagerHandle, (EFI_FORM_LABEL) 0x0000, TRUE, UpdateData);\r
+\r
+  //\r
+  // Create "Boot Option Menu" title\r
+  //\r
+  Status = CreateSubTitleOpCode (\r
+            STRING_TOKEN (STR_BOOT_OPTION_BANNER),  // Token Value for the string\r
+            &UpdateData->Data                       // Buffer containing created op-code\r
+            );\r
+\r
+  Hii->UpdateForm (Hii, gBootManagerHandle, (EFI_FORM_LABEL) 0x0000, TRUE, UpdateData);\r
+\r
+  Token                 = LastToken;\r
+  mKeyInput             = 0;\r
+\r
+  UpdateData->DataCount = 0;\r
+  Location              = (UINT8 *) &UpdateData->Data;\r
+\r
+  for (Link = BdsBootOptionList.ForwardLink; Link != &BdsBootOptionList; Link = Link->ForwardLink) {\r
+    Option = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);\r
+\r
+    //\r
+    // At this stage we are creating a menu entry, thus the Keys are reproduceable\r
+    //\r
+    mKeyInput++;\r
+    Token++;\r
+\r
+    Status = Hii->NewString (Hii, NULL, gBootManagerHandle, &Token, Option->Description);\r
+\r
+    //\r
+    // If we got an error it is almost certainly due to the token value being invalid.\r
+    // Therefore we will set the Token to 0 to automatically add a token.\r
+    //\r
+    if (EFI_ERROR (Status)) {\r
+      Token   = 0;\r
+      Status  = Hii->NewString (Hii, NULL, gBootManagerHandle, &Token, Option->Description);\r
+    }\r
+\r
+    Status = CreateGotoOpCode (\r
+              0x1000, // Form ID\r
+              Token,  // Token Value for the string\r
+              0,      // Help String (none)\r
+              EFI_IFR_FLAG_INTERACTIVE | EFI_IFR_FLAG_NV_ACCESS,  // The Op-Code flags\r
+              mKeyInput,                                          // The Key to get a callback on\r
+              Location  // Buffer containing created op-code\r
+              );\r
+\r
+    UpdateData->DataCount++;\r
+    Location = Location + ((EFI_IFR_OP_HEADER *) Location)->Length;\r
+\r
+  }\r
+\r
+  Hii->UpdateForm (Hii, gBootManagerHandle, (EFI_FORM_LABEL) 0x0001, TRUE, UpdateData);\r
+\r
+  UpdateData->DataCount = 1;\r
+\r
+  //\r
+  // Create "Boot Option Menu" title\r
+  //\r
+  Status = CreateSubTitleOpCode (\r
+            STRING_TOKEN (STR_HELP_FOOTER), // Token Value for the string\r
+            &UpdateData->Data               // Buffer containing created op-code\r
+            );\r
+\r
+  Hii->UpdateForm (Hii, gBootManagerHandle, (EFI_FORM_LABEL) 0x0002, TRUE, UpdateData);\r
+\r
+  Status = CreateSubTitleOpCode (\r
+            LastToken,                      // Token Value for the string\r
+            &UpdateData->Data               // Buffer containing created op-code\r
+            );\r
+\r
+  Hii->UpdateForm (Hii, gBootManagerHandle, (EFI_FORM_LABEL) 0x0002, TRUE, UpdateData);\r
+\r
+  gBS->FreePool (UpdateData);\r
+\r
+  ASSERT (gBrowser);\r
+\r
+  BootMngrMenuResetRequired = FALSE;\r
+  gBrowser->SendForm (\r
+              gBrowser, \r
+              TRUE, \r
+              &gBootManagerHandle, \r
+              1, \r
+              NULL, \r
+              NULL, \r
+              NULL, \r
+              NULL, \r
+              &BootMngrMenuResetRequired\r
+              );\r
+\r
+  if (BootMngrMenuResetRequired) {\r
+    EnableResetRequired ();\r
+  }\r
+\r
+  Hii->ResetStrings (Hii, gBootManagerHandle);\r
+\r
+  if (gOption == NULL) {\r
+    return ;\r
+  }\r
+  \r
+  //\r
+  //Will leave browser, check any reset required change is applied? if yes, reset system\r
+  //\r
+  SetupResetReminder ();\r
+  \r
+  //\r
+  // BugBug: This code looks repeated from the BDS. Need to save code space.\r
+  //\r
+\r
+  //\r
+  // parse the selected option\r
+  //\r
+  Status = BdsLibBootViaBootOption (gOption, gOption->DevicePath, &ExitDataSize, &ExitData);\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    PlatformBdsBootSuccess (gOption);\r
+  } else {\r
+    PlatformBdsBootFail (gOption, Status, ExitData, ExitDataSize);\r
+    gST->ConOut->OutputString (\r
+                  gST->ConOut,\r
+                  GetStringById (STRING_TOKEN (STR_ANY_KEY_CONTINUE))\r
+                  );\r
+\r
+    //\r
+    // BdsLibUiWaitForSingleEvent (gST->ConIn->WaitForKey, 0);\r
+    //\r
+\r
+    gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
+  }\r
+}\r