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;
 | 
						|
}
 | 
						|
 |