mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-10-26 05:30:48 +00:00 
			
		
		
		
	 69fc8f080e
			
		
	
	
		69fc8f080e
		
	
	
	
	
		
			
			Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com> Reviewed-by: Jiewen Yao <jiewen.yao@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15385 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			755 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			755 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   This module produce main entry for BDS phase - BdsEntry.
 | |
|   When this module was dispatched by DxeCore, gEfiBdsArchProtocolGuid will be installed
 | |
|   which contains interface of BdsEntry.
 | |
|   After DxeCore finish DXE phase, gEfiBdsArchProtocolGuid->BdsEntry will be invoked
 | |
|   to enter BDS phase.
 | |
| 
 | |
| Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
 | |
| 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.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "Bds.h"
 | |
| #include "Language.h"
 | |
| #include "FrontPage.h"
 | |
| #include "Hotkey.h"
 | |
| #include "HwErrRecSupport.h"
 | |
| 
 | |
| ///
 | |
| /// BDS arch protocol instance initial value.
 | |
| ///
 | |
| /// Note: Current BDS not directly get the BootMode, DefaultBoot,
 | |
| /// TimeoutDefault, MemoryTestLevel value from the BDS arch protocol.
 | |
| /// Please refer to the library useage of BdsLibGetBootMode, BdsLibGetTimeout
 | |
| /// and PlatformBdsDiagnostics in BdsPlatform.c
 | |
| ///
 | |
| EFI_HANDLE  gBdsHandle = NULL;
 | |
| 
 | |
| EFI_BDS_ARCH_PROTOCOL  gBds = {
 | |
|   BdsEntry
 | |
| };
 | |
| 
 | |
| UINT16                          *mBootNext = NULL;
 | |
| 
 | |
| ///
 | |
| /// The read-only variables defined in UEFI Spec.
 | |
| ///
 | |
| CHAR16  *mReadOnlyVariables[] = {
 | |
|   L"PlatformLangCodes",
 | |
|   L"LangCodes",
 | |
|   L"BootOptionSupport",
 | |
|   L"HwErrRecSupport",
 | |
|   L"OsIndicationsSupported"
 | |
|   };
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Install Boot Device Selection Protocol
 | |
| 
 | |
|   @param ImageHandle     The image handle.
 | |
|   @param SystemTable     The system table.
 | |
| 
 | |
|   @retval  EFI_SUCEESS  BDS has finished initializing.
 | |
|                         Return the dispatcher and recall BDS.Entry
 | |
|   @retval  Other        Return status from AllocatePool() or gBS->InstallProtocolInterface
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| BdsInitialize (
 | |
|   IN EFI_HANDLE                            ImageHandle,
 | |
|   IN EFI_SYSTEM_TABLE                      *SystemTable
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   //
 | |
|   // Install protocol interface
 | |
|   //
 | |
|   Status = gBS->InstallMultipleProtocolInterfaces (
 | |
|                   &gBdsHandle,
 | |
|                   &gEfiBdsArchProtocolGuid, &gBds,
 | |
|                   NULL
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   An empty function to pass error checking of CreateEventEx ().
 | |
| 
 | |
|   @param  Event                 Event whose notification function is being invoked.
 | |
|   @param  Context               Pointer to the notification function's context,
 | |
|                                 which is implementation-dependent.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| BdsEmptyCallbackFunction (
 | |
|   IN EFI_EVENT                Event,
 | |
|   IN VOID                     *Context
 | |
|   )
 | |
| {
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   This function attempts to boot for the boot order specified
 | |
|   by platform policy.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| BdsBootDeviceSelect (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS        Status;
 | |
|   LIST_ENTRY        *Link;
 | |
|   BDS_COMMON_OPTION *BootOption;
 | |
|   UINTN             ExitDataSize;
 | |
|   CHAR16            *ExitData;
 | |
|   UINT16            Timeout;
 | |
|   LIST_ENTRY        BootLists;
 | |
|   CHAR16            Buffer[20];
 | |
|   BOOLEAN           BootNextExist;
 | |
|   LIST_ENTRY        *LinkBootNext;
 | |
|   EFI_EVENT         ConnectConInEvent;
 | |
| 
 | |
|   //
 | |
|   // Got the latest boot option
 | |
|   //
 | |
|   BootNextExist = FALSE;
 | |
|   LinkBootNext  = NULL;
 | |
|   ConnectConInEvent = NULL;
 | |
|   InitializeListHead (&BootLists);
 | |
| 
 | |
|   //
 | |
|   // First check the boot next option
 | |
|   //
 | |
|   ZeroMem (Buffer, sizeof (Buffer));
 | |
| 
 | |
|   //
 | |
|   // Create Event to signal ConIn connection request
 | |
|   //
 | |
|   if (PcdGetBool (PcdConInConnectOnDemand)) {
 | |
|     Status = gBS->CreateEventEx (
 | |
|                     EVT_NOTIFY_SIGNAL,
 | |
|                     TPL_CALLBACK,
 | |
|                     BdsEmptyCallbackFunction,
 | |
|                     NULL,
 | |
|                     &gConnectConInEventGuid,
 | |
|                     &ConnectConInEvent
 | |
|                     );
 | |
|     if (EFI_ERROR(Status)) {
 | |
|       ConnectConInEvent = NULL;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (mBootNext != NULL) {
 | |
|     //
 | |
|     // Indicate we have the boot next variable, so this time
 | |
|     // boot will always have this boot option
 | |
|     //
 | |
|     BootNextExist = TRUE;
 | |
| 
 | |
|     //
 | |
|     // Clear the this variable so it's only exist in this time boot
 | |
|     //
 | |
|     Status = gRT->SetVariable (
 | |
|                     L"BootNext",
 | |
|                     &gEfiGlobalVariableGuid,
 | |
|                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
 | |
|                     0,
 | |
|                     NULL
 | |
|                     );
 | |
|     //
 | |
|     // Deleting variable with current variable implementation shouldn't fail.
 | |
|     //
 | |
|     ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|     //
 | |
|     // Add the boot next boot option
 | |
|     //
 | |
|     UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *mBootNext);
 | |
|     BootOption = BdsLibVariableToOption (&BootLists, Buffer);
 | |
| 
 | |
|     //
 | |
|     // If fail to get boot option from variable, just return and do nothing.
 | |
|     //
 | |
|     if (BootOption == NULL) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     BootOption->BootCurrent = *mBootNext;
 | |
|   }
 | |
|   //
 | |
|   // Parse the boot order to get boot option
 | |
|   //
 | |
|   BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");
 | |
| 
 | |
|   //
 | |
|   // When we didn't have chance to build boot option variables in the first 
 | |
|   // full configuration boot (e.g.: Reset in the first page or in Device Manager),
 | |
|   // we have no boot options in the following mini configuration boot.
 | |
|   // Give the last chance to enumerate the boot options.
 | |
|   //
 | |
|   if (IsListEmpty (&BootLists)) {
 | |
|     BdsLibEnumerateAllBootOption (&BootLists);
 | |
|   }
 | |
| 
 | |
|   Link = BootLists.ForwardLink;
 | |
| 
 | |
|   //
 | |
|   // Parameter check, make sure the loop will be valid
 | |
|   //
 | |
|   if (Link == NULL) {
 | |
|     return ;
 | |
|   }
 | |
|   //
 | |
|   // Here we make the boot in a loop, every boot success will
 | |
|   // return to the front page
 | |
|   //
 | |
|   for (;;) {
 | |
|     //
 | |
|     // Check the boot option list first
 | |
|     //
 | |
|     if (Link == &BootLists) {
 | |
|       //
 | |
|       // When LazyConIn enabled, signal connect ConIn event before enter UI
 | |
|       //
 | |
|       if (PcdGetBool (PcdConInConnectOnDemand) && ConnectConInEvent != NULL) {
 | |
|         gBS->SignalEvent (ConnectConInEvent);
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // There are two ways to enter here:
 | |
|       // 1. There is no active boot option, give user chance to
 | |
|       //    add new boot option
 | |
|       // 2. All the active boot option processed, and there is no
 | |
|       //    one is success to boot, then we back here to allow user
 | |
|       //    add new active boot option
 | |
|       //
 | |
|       Timeout = 0xffff;
 | |
|       PlatformBdsEnterFrontPage (Timeout, FALSE);
 | |
|       InitializeListHead (&BootLists);
 | |
|       BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");
 | |
|       Link = BootLists.ForwardLink;
 | |
|       continue;
 | |
|     }
 | |
|     //
 | |
|     // Get the boot option from the link list
 | |
|     //
 | |
|     BootOption = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);
 | |
| 
 | |
|     //
 | |
|     // According to EFI Specification, if a load option is not marked
 | |
|     // as LOAD_OPTION_ACTIVE, the boot manager will not automatically
 | |
|     // load the option.
 | |
|     //
 | |
|     if (!IS_LOAD_OPTION_TYPE (BootOption->Attribute, LOAD_OPTION_ACTIVE)) {
 | |
|       //
 | |
|       // skip the header of the link list, because it has no boot option
 | |
|       //
 | |
|       Link = Link->ForwardLink;
 | |
|       continue;
 | |
|     }
 | |
|     //
 | |
|     // Make sure the boot option device path connected,
 | |
|     // but ignore the BBS device path
 | |
|     //
 | |
|     if (DevicePathType (BootOption->DevicePath) != BBS_DEVICE_PATH) {
 | |
|       //
 | |
|       // Notes: the internal shell can not been connected with device path
 | |
|       // so we do not check the status here
 | |
|       //
 | |
|       BdsLibConnectDevicePath (BootOption->DevicePath);
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Restore to original mode before launching boot option.
 | |
|     //
 | |
|     BdsSetConsoleMode (FALSE);
 | |
|     
 | |
|     //
 | |
|     // All the driver options should have been processed since
 | |
|     // now boot will be performed.
 | |
|     //
 | |
|     Status = BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);
 | |
|     if (Status != EFI_SUCCESS) {
 | |
|       //
 | |
|       // Call platform action to indicate the boot fail
 | |
|       //
 | |
|       BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_FAILED));
 | |
|       PlatformBdsBootFail (BootOption, Status, ExitData, ExitDataSize);
 | |
| 
 | |
|       //
 | |
|       // Check the next boot option
 | |
|       //
 | |
|       Link = Link->ForwardLink;
 | |
| 
 | |
|     } else {
 | |
|       //
 | |
|       // Call platform action to indicate the boot success
 | |
|       //
 | |
|       BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED));
 | |
|       PlatformBdsBootSuccess (BootOption);
 | |
| 
 | |
|       //
 | |
|       // Boot success, then stop process the boot order, and
 | |
|       // present the boot manager menu, front page
 | |
|       //
 | |
| 
 | |
|       //
 | |
|       // When LazyConIn enabled, signal connect ConIn Event before enter UI
 | |
|       //
 | |
|       if (PcdGetBool (PcdConInConnectOnDemand) && ConnectConInEvent != NULL) {
 | |
|         gBS->SignalEvent (ConnectConInEvent);
 | |
|       }
 | |
| 
 | |
|       Timeout = 0xffff;
 | |
|       PlatformBdsEnterFrontPage (Timeout, FALSE);
 | |
| 
 | |
|       //
 | |
|       // Rescan the boot option list, avoid potential risk of the boot
 | |
|       // option change in front page
 | |
|       //
 | |
|       if (BootNextExist) {
 | |
|         LinkBootNext = BootLists.ForwardLink;
 | |
|       }
 | |
| 
 | |
|       InitializeListHead (&BootLists);
 | |
|       if (LinkBootNext != NULL) {
 | |
|         //
 | |
|         // Reserve the boot next option
 | |
|         //
 | |
|         InsertTailList (&BootLists, LinkBootNext);
 | |
|       }
 | |
| 
 | |
|       BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");
 | |
|       Link = BootLists.ForwardLink;
 | |
|     }
 | |
|   }
 | |
| 
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Validate input console variable data. 
 | |
| 
 | |
|   If found the device path is not a valid device path, remove the variable.
 | |
|   
 | |
|   @param VariableName             Input console variable name.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| BdsFormalizeConsoleVariable (
 | |
|   IN  CHAR16          *VariableName
 | |
|   )
 | |
| {
 | |
|   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
 | |
|   UINTN                     VariableSize;
 | |
|   EFI_STATUS                Status;
 | |
| 
 | |
|   DevicePath = BdsLibGetVariableAndSize (
 | |
|                       VariableName,
 | |
|                       &gEfiGlobalVariableGuid,
 | |
|                       &VariableSize
 | |
|                       );
 | |
|   if ((DevicePath != NULL) && !IsDevicePathValid (DevicePath, VariableSize)) { 
 | |
|     Status = gRT->SetVariable (
 | |
|                     VariableName,
 | |
|                     &gEfiGlobalVariableGuid,
 | |
|                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
 | |
|                     0,
 | |
|                     NULL
 | |
|                     );
 | |
|     //
 | |
|     // Deleting variable with current variable implementation shouldn't fail.
 | |
|     //
 | |
|     ASSERT_EFI_ERROR (Status);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Formalize Bds global variables. 
 | |
| 
 | |
|  1. For ConIn/ConOut/ConErr, if found the device path is not a valid device path, remove the variable.
 | |
|  2. For OsIndicationsSupported, Create a BS/RT/UINT64 variable to report caps 
 | |
|  3. Delete OsIndications variable if it is not NV/BS/RT UINT64
 | |
|  Item 3 is used to solve case when OS corrupts OsIndications. Here simply delete this NV variable.
 | |
|  
 | |
| **/
 | |
| VOID 
 | |
| BdsFormalizeEfiGlobalVariable (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS Status;
 | |
|   UINT64     OsIndicationSupport;
 | |
|   UINT64     OsIndication;
 | |
|   UINTN      DataSize;
 | |
|   UINT32     Attributes;
 | |
|   
 | |
|   //
 | |
|   // Validate Console variable.
 | |
|   //
 | |
|   BdsFormalizeConsoleVariable (L"ConIn");
 | |
|   BdsFormalizeConsoleVariable (L"ConOut");
 | |
|   BdsFormalizeConsoleVariable (L"ErrOut");
 | |
| 
 | |
|   //
 | |
|   // OS indicater support variable
 | |
|   //
 | |
|   OsIndicationSupport = EFI_OS_INDICATIONS_BOOT_TO_FW_UI \
 | |
|                       | EFI_OS_INDICATIONS_FMP_CAPSULE_SUPPORTED;
 | |
| 
 | |
|   BdsDxeSetVariableAndReportStatusCodeOnError (
 | |
|     L"OsIndicationsSupported",
 | |
|     &gEfiGlobalVariableGuid,
 | |
|     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
 | |
|     sizeof(UINT64),
 | |
|     &OsIndicationSupport
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // If OsIndications is invalid, remove it.
 | |
|   // Invalid case
 | |
|   //   1. Data size != UINT64
 | |
|   //   2. OsIndication value inconsistence
 | |
|   //   3. OsIndication attribute inconsistence
 | |
|   //
 | |
|   OsIndication = 0;
 | |
|   Attributes = 0;
 | |
|   DataSize = sizeof(UINT64);
 | |
|   Status = gRT->GetVariable (
 | |
|                   L"OsIndications",
 | |
|                   &gEfiGlobalVariableGuid,
 | |
|                   &Attributes,
 | |
|                   &DataSize,
 | |
|                   &OsIndication
 | |
|                   );
 | |
| 
 | |
|   if (!EFI_ERROR(Status)) {
 | |
|     if (DataSize != sizeof(UINT64) ||
 | |
|         (OsIndication & ~OsIndicationSupport) != 0 ||
 | |
|         Attributes != (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE)){
 | |
| 
 | |
|       DEBUG ((EFI_D_ERROR, "Unformalized OsIndications variable exists. Delete it\n"));
 | |
|       Status = gRT->SetVariable (
 | |
|                       L"OsIndications",
 | |
|                       &gEfiGlobalVariableGuid,
 | |
|                       0,
 | |
|                       0,
 | |
|                       NULL
 | |
|                       );
 | |
|       //
 | |
|       // Deleting variable with current variable implementation shouldn't fail.
 | |
|       //
 | |
|       ASSERT_EFI_ERROR (Status);
 | |
|     }
 | |
|   }
 | |
| 
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Allocate a block of memory that will contain performance data to OS.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| BdsAllocateMemoryForPerformanceData (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                    Status;
 | |
|   EFI_PHYSICAL_ADDRESS          AcpiLowMemoryBase;
 | |
|   EDKII_VARIABLE_LOCK_PROTOCOL  *VariableLock;
 | |
| 
 | |
|   AcpiLowMemoryBase = 0x0FFFFFFFFULL;
 | |
| 
 | |
|   //
 | |
|   // Allocate a block of memory that will contain performance data to OS.
 | |
|   //
 | |
|   Status = gBS->AllocatePages (
 | |
|                   AllocateMaxAddress,
 | |
|                   EfiReservedMemoryType,
 | |
|                   EFI_SIZE_TO_PAGES (PERF_DATA_MAX_LENGTH),
 | |
|                   &AcpiLowMemoryBase
 | |
|                   );
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // Save the pointer to variable for use in S3 resume.
 | |
|     //
 | |
|     BdsDxeSetVariableAndReportStatusCodeOnError (
 | |
|       L"PerfDataMemAddr",
 | |
|       &gPerformanceProtocolGuid,
 | |
|       EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
 | |
|       sizeof (EFI_PHYSICAL_ADDRESS),
 | |
|       &AcpiLowMemoryBase
 | |
|       );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       DEBUG ((EFI_D_ERROR, "[Bds] PerfDataMemAddr (%08x) cannot be saved to NV storage.\n", AcpiLowMemoryBase));
 | |
|     }
 | |
|     //
 | |
|     // Mark L"PerfDataMemAddr" variable to read-only if the Variable Lock protocol exists
 | |
|     // Still lock it even the variable cannot be saved to prevent it's set by 3rd party code.
 | |
|     //
 | |
|     Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       Status = VariableLock->RequestToLock (VariableLock, L"PerfDataMemAddr", &gPerformanceProtocolGuid);
 | |
|       ASSERT_EFI_ERROR (Status);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Service routine for BdsInstance->Entry(). Devices are connected, the
 | |
|   consoles are initialized, and the boot options are tried.
 | |
| 
 | |
|   @param This             Protocol Instance structure.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| BdsEntry (
 | |
|   IN EFI_BDS_ARCH_PROTOCOL  *This
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY                      DriverOptionList;
 | |
|   LIST_ENTRY                      BootOptionList;
 | |
|   UINTN                           BootNextSize;
 | |
|   CHAR16                          *FirmwareVendor;
 | |
|   EFI_STATUS                      Status;
 | |
|   UINT16                          BootTimeOut;
 | |
|   UINTN                           Index;
 | |
|   EDKII_VARIABLE_LOCK_PROTOCOL    *VariableLock;
 | |
| 
 | |
|   //
 | |
|   // Insert the performance probe
 | |
|   //
 | |
|   PERF_END (NULL, "DXE", NULL, 0);
 | |
|   PERF_START (NULL, "BDS", NULL, 0);
 | |
| 
 | |
|   PERF_CODE (
 | |
|     BdsAllocateMemoryForPerformanceData ();
 | |
|   );
 | |
| 
 | |
|   //
 | |
|   // Initialize the global system boot option and driver option
 | |
|   //
 | |
|   InitializeListHead (&DriverOptionList);
 | |
|   InitializeListHead (&BootOptionList);
 | |
| 
 | |
|   //
 | |
|   // Initialize hotkey service
 | |
|   //
 | |
|   InitializeHotkeyService ();
 | |
| 
 | |
|   //
 | |
|   // Fill in FirmwareVendor and FirmwareRevision from PCDs
 | |
|   //
 | |
|   FirmwareVendor = (CHAR16 *)PcdGetPtr (PcdFirmwareVendor);
 | |
|   gST->FirmwareVendor = AllocateRuntimeCopyPool (StrSize (FirmwareVendor), FirmwareVendor);
 | |
|   ASSERT (gST->FirmwareVendor != NULL);
 | |
|   gST->FirmwareRevision = PcdGet32 (PcdFirmwareRevision);
 | |
| 
 | |
|   //
 | |
|   // Fixup Tasble CRC after we updated Firmware Vendor and Revision
 | |
|   //
 | |
|   gST->Hdr.CRC32 = 0;
 | |
|   gBS->CalculateCrc32 ((VOID *)gST, sizeof(EFI_SYSTEM_TABLE), &gST->Hdr.CRC32);
 | |
| 
 | |
|   //
 | |
|   // Validate Variable.
 | |
|   //
 | |
|   BdsFormalizeEfiGlobalVariable();
 | |
| 
 | |
|   //
 | |
|   // Mark the read-only variables if the Variable Lock protocol exists
 | |
|   //
 | |
|   Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);
 | |
|   DEBUG ((EFI_D_INFO, "[BdsDxe] Locate Variable Lock protocol - %r\n", Status));
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     for (Index = 0; Index < sizeof (mReadOnlyVariables) / sizeof (mReadOnlyVariables[0]); Index++) {
 | |
|       Status = VariableLock->RequestToLock (VariableLock, mReadOnlyVariables[Index], &gEfiGlobalVariableGuid);
 | |
|       ASSERT_EFI_ERROR (Status);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Report Status Code to indicate connecting drivers will happen
 | |
|   //
 | |
|   REPORT_STATUS_CODE (
 | |
|     EFI_PROGRESS_CODE,
 | |
|     (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_BEGIN_CONNECTING_DRIVERS)
 | |
|     );
 | |
| 
 | |
|   InitializeHwErrRecSupport();
 | |
| 
 | |
|   //
 | |
|   // Initialize L"Timeout" EFI global variable.
 | |
|   //
 | |
|   BootTimeOut = PcdGet16 (PcdPlatformBootTimeOut);
 | |
|   if (BootTimeOut != 0xFFFF) {
 | |
|     //
 | |
|     // If time out value equal 0xFFFF, no need set to 0xFFFF to variable area because UEFI specification
 | |
|     // define same behavior between no value or 0xFFFF value for L"Timeout".
 | |
|     //
 | |
|     BdsDxeSetVariableAndReportStatusCodeOnError (
 | |
|                     L"Timeout",
 | |
|                     &gEfiGlobalVariableGuid,
 | |
|                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
 | |
|                     sizeof (UINT16),
 | |
|                     &BootTimeOut
 | |
|                     );
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // bugbug: platform specific code
 | |
|   // Initialize the platform specific string and language
 | |
|   //
 | |
|   InitializeStringSupport ();
 | |
|   InitializeLanguage (TRUE);
 | |
|   InitializeFrontPage (TRUE);
 | |
| 
 | |
|   //
 | |
|   // Do the platform init, can be customized by OEM/IBV
 | |
|   //
 | |
|   PERF_START (NULL, "PlatformBds", "BDS", 0);
 | |
|   PlatformBdsInit ();
 | |
| 
 | |
|   //
 | |
|   // Set up the device list based on EFI 1.1 variables
 | |
|   // process Driver#### and Load the driver's in the
 | |
|   // driver option list
 | |
|   //
 | |
|   BdsLibBuildOptionFromVar (&DriverOptionList, L"DriverOrder");
 | |
|   if (!IsListEmpty (&DriverOptionList)) {
 | |
|     BdsLibLoadDrivers (&DriverOptionList);
 | |
|   }
 | |
|   //
 | |
|   // Check if we have the boot next option
 | |
|   //
 | |
|   mBootNext = BdsLibGetVariableAndSize (
 | |
|                 L"BootNext",
 | |
|                 &gEfiGlobalVariableGuid,
 | |
|                 &BootNextSize
 | |
|                 );
 | |
| 
 | |
|   //
 | |
|   // Setup some platform policy here
 | |
|   //
 | |
|   PlatformBdsPolicyBehavior (&DriverOptionList, &BootOptionList, BdsProcessCapsules, BdsMemoryTest);
 | |
|   PERF_END (NULL, "PlatformBds", "BDS", 0);
 | |
| 
 | |
|   //
 | |
|   // BDS select the boot device to load OS
 | |
|   //
 | |
|   BdsBootDeviceSelect ();
 | |
| 
 | |
|   //
 | |
|   // Only assert here since this is the right behavior, we should never
 | |
|   // return back to DxeCore.
 | |
|   //
 | |
|   ASSERT (FALSE);
 | |
| 
 | |
|   return ;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Set the variable and report the error through status code upon failure.
 | |
| 
 | |
|   @param  VariableName           A Null-terminated string that is the name of the vendor's variable.
 | |
|                                  Each VariableName is unique for each VendorGuid. VariableName must
 | |
|                                  contain 1 or more characters. If VariableName is an empty string,
 | |
|                                  then EFI_INVALID_PARAMETER is returned.
 | |
|   @param  VendorGuid             A unique identifier for the vendor.
 | |
|   @param  Attributes             Attributes bitmask to set for the variable.
 | |
|   @param  DataSize               The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE, 
 | |
|                                  EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or 
 | |
|                                  EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero 
 | |
|                                  causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is 
 | |
|                                  set, then a SetVariable() call with a DataSize of zero will not cause any change to 
 | |
|                                  the variable value (the timestamp associated with the variable may be updated however 
 | |
|                                  even if no new data value is provided,see the description of the 
 | |
|                                  EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not 
 | |
|                                  be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated). 
 | |
|   @param  Data                   The contents for the variable.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The firmware has successfully stored the variable and its data as
 | |
|                                  defined by the Attributes.
 | |
|   @retval EFI_INVALID_PARAMETER  An invalid combination of attribute bits, name, and GUID was supplied, or the
 | |
|                                  DataSize exceeds the maximum allowed.
 | |
|   @retval EFI_INVALID_PARAMETER  VariableName is an empty string.
 | |
|   @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the variable and its data.
 | |
|   @retval EFI_DEVICE_ERROR       The variable could not be retrieved due to a hardware error.
 | |
|   @retval EFI_WRITE_PROTECTED    The variable in question is read-only.
 | |
|   @retval EFI_WRITE_PROTECTED    The variable in question cannot be deleted.
 | |
|   @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 
 | |
|                                  or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo 
 | |
|                                  does NOT pass the validation check carried out by the firmware.
 | |
| 
 | |
|   @retval EFI_NOT_FOUND          The variable trying to be updated or deleted was not found.
 | |
| **/
 | |
| EFI_STATUS
 | |
| BdsDxeSetVariableAndReportStatusCodeOnError (
 | |
|   IN CHAR16     *VariableName,
 | |
|   IN EFI_GUID   *VendorGuid,
 | |
|   IN UINT32     Attributes,
 | |
|   IN UINTN      DataSize,
 | |
|   IN VOID       *Data
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                 Status;
 | |
|   EDKII_SET_VARIABLE_STATUS  *SetVariableStatus;
 | |
|   UINTN                      NameSize;
 | |
| 
 | |
|   Status = gRT->SetVariable (
 | |
|                   VariableName,
 | |
|                   VendorGuid,
 | |
|                   Attributes,
 | |
|                   DataSize,
 | |
|                   Data
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     NameSize = StrSize (VariableName);
 | |
|     SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize);
 | |
|     if (SetVariableStatus != NULL) {
 | |
|       CopyGuid (&SetVariableStatus->Guid, VendorGuid);
 | |
|       SetVariableStatus->NameSize   = NameSize;
 | |
|       SetVariableStatus->DataSize   = DataSize;
 | |
|       SetVariableStatus->SetStatus  = Status;
 | |
|       SetVariableStatus->Attributes = Attributes;
 | |
|       CopyMem (SetVariableStatus + 1,                          VariableName, NameSize);
 | |
|       CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Data,         DataSize);
 | |
| 
 | |
|       REPORT_STATUS_CODE_EX (
 | |
|         EFI_ERROR_CODE,
 | |
|         PcdGet32 (PcdErrorCodeSetVariable),
 | |
|         0,
 | |
|         NULL,
 | |
|         &gEdkiiStatusCodeDataTypeVariableGuid,
 | |
|         SetVariableStatus,
 | |
|         sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize
 | |
|         );
 | |
| 
 | |
|       FreePool (SetVariableStatus);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 |