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