Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com> Reviewed-by: Eric Dong <eric.dong@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17403 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1233 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1233 lines
		
	
	
		
			39 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 - 2015, 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 "HwErrRecSupport.h"
 | 
						|
 | 
						|
#define SET_BOOT_OPTION_SUPPORT_KEY_COUNT(a, c) {  \
 | 
						|
      (a) = ((a) & ~EFI_BOOT_OPTION_SUPPORT_COUNT) | (((c) << LowBitSet32 (EFI_BOOT_OPTION_SUPPORT_COUNT)) & EFI_BOOT_OPTION_SUPPORT_COUNT); \
 | 
						|
      }
 | 
						|
 | 
						|
///
 | 
						|
/// BDS arch protocol instance initial value.
 | 
						|
///
 | 
						|
EFI_BDS_ARCH_PROTOCOL  gBds = {
 | 
						|
  BdsEntry
 | 
						|
};
 | 
						|
 | 
						|
//
 | 
						|
// gConnectConInEvent - Event which is signaled when ConIn connection is required
 | 
						|
//
 | 
						|
EFI_EVENT      gConnectConInEvent = NULL;
 | 
						|
 | 
						|
///
 | 
						|
/// The read-only variables defined in UEFI Spec.
 | 
						|
///
 | 
						|
CHAR16  *mReadOnlyVariables[] = {
 | 
						|
  EFI_PLATFORM_LANG_CODES_VARIABLE_NAME,
 | 
						|
  EFI_LANG_CODES_VARIABLE_NAME,
 | 
						|
  EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME,
 | 
						|
  EFI_HW_ERR_REC_SUPPORT_VARIABLE_NAME,
 | 
						|
  EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME
 | 
						|
  };
 | 
						|
 | 
						|
CHAR16 *mBdsLoadOptionName[] = {
 | 
						|
  L"Driver",
 | 
						|
  L"SysPrep",
 | 
						|
  L"Boot"
 | 
						|
};
 | 
						|
 | 
						|
CHAR16  mRecoveryBoot[] = L"Recovery Boot";
 | 
						|
/**
 | 
						|
  Event to Connect ConIn.
 | 
						|
 | 
						|
  @param  Event                 Event whose notification function is being invoked.
 | 
						|
  @param  Context               Pointer to the notification function's context,
 | 
						|
                                which is implementation-dependent.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
BdsDxeOnConnectConInCallBack (
 | 
						|
  IN EFI_EVENT                Event,
 | 
						|
  IN VOID                     *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS Status;
 | 
						|
 | 
						|
  //
 | 
						|
  // When Osloader call ReadKeyStroke to signal this event
 | 
						|
  // no driver dependency is assumed existing. So use a non-dispatch version
 | 
						|
  //
 | 
						|
  Status = EfiBootManagerConnectConsoleVariable (ConIn);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    //
 | 
						|
    // Should not enter this case, if enter, the keyboard will not work.
 | 
						|
    // May need platfrom policy to connect keyboard.
 | 
						|
    //
 | 
						|
    DEBUG ((EFI_D_WARN, "[Bds] Connect ConIn failed - %r!!!\n", Status));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  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;
 | 
						|
  EFI_HANDLE  Handle;
 | 
						|
  //
 | 
						|
  // Install protocol interface
 | 
						|
  //
 | 
						|
  Handle = NULL;
 | 
						|
  Status = gBS->InstallMultipleProtocolInterfaces (
 | 
						|
                  &Handle,
 | 
						|
                  &gEfiBdsArchProtocolGuid, &gBds,
 | 
						|
                  NULL
 | 
						|
                  );
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Emuerate all possible bootable medias in the following order:
 | 
						|
  1. Removable BlockIo            - The boot option only points to the removable media
 | 
						|
                                    device, like USB key, DVD, Floppy etc.
 | 
						|
  2. Fixed BlockIo                - The boot option only points to a Fixed blockIo device,
 | 
						|
                                    like HardDisk.
 | 
						|
  3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
 | 
						|
                                    SimpleFileSystem Protocol, but not supporting BlockIo
 | 
						|
                                    protocol.
 | 
						|
  4. LoadFile                     - The boot option points to the media supporting 
 | 
						|
                                    LoadFile protocol.
 | 
						|
  Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
 | 
						|
 | 
						|
  @param BootOptionCount   Return the boot option count which has been found.
 | 
						|
 | 
						|
  @retval   Pointer to the boot option array.
 | 
						|
**/
 | 
						|
EFI_BOOT_MANAGER_LOAD_OPTION *
 | 
						|
BdsEnumerateBootOptions (
 | 
						|
  UINTN                                 *BootOptionCount
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                            Status;
 | 
						|
  EFI_BOOT_MANAGER_LOAD_OPTION          *BootOptions;
 | 
						|
  UINT16                                NonBlockNumber;
 | 
						|
  UINTN                                 HandleCount;
 | 
						|
  EFI_HANDLE                            *Handles;
 | 
						|
  EFI_BLOCK_IO_PROTOCOL                 *BlkIo;
 | 
						|
  UINTN                                 Removable;
 | 
						|
  UINTN                                 Index;
 | 
						|
 | 
						|
  ASSERT (BootOptionCount != NULL);
 | 
						|
 | 
						|
  *BootOptionCount = 0;
 | 
						|
  BootOptions      = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Parse removable block io followed by fixed block io
 | 
						|
  //
 | 
						|
  gBS->LocateHandleBuffer (
 | 
						|
         ByProtocol,
 | 
						|
         &gEfiBlockIoProtocolGuid,
 | 
						|
         NULL,
 | 
						|
         &HandleCount,
 | 
						|
         &Handles
 | 
						|
         );
 | 
						|
 | 
						|
  for (Removable = 0; Removable < 2; Removable++) {
 | 
						|
    for (Index = 0; Index < HandleCount; Index++) {
 | 
						|
      Status = gBS->HandleProtocol (
 | 
						|
                      Handles[Index],
 | 
						|
                      &gEfiBlockIoProtocolGuid,
 | 
						|
                      (VOID **) &BlkIo
 | 
						|
                      );
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // Skip the logical partitions
 | 
						|
      //
 | 
						|
      if (BlkIo->Media->LogicalPartition) {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // Skip the fixed block io then the removable block io
 | 
						|
      //
 | 
						|
      if (BlkIo->Media->RemovableMedia == ((Removable == 0) ? FALSE : TRUE)) {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
 | 
						|
      BootOptions = ReallocatePool (
 | 
						|
                      sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
 | 
						|
                      sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
 | 
						|
                      BootOptions
 | 
						|
                      );
 | 
						|
      ASSERT (BootOptions != NULL);
 | 
						|
 | 
						|
      Status = EfiBootManagerInitializeLoadOption (
 | 
						|
                 &BootOptions[(*BootOptionCount)++],
 | 
						|
                 LoadOptionNumberUnassigned,
 | 
						|
                 LoadOptionTypeBoot,
 | 
						|
                 LOAD_OPTION_ACTIVE,
 | 
						|
                 mRecoveryBoot,
 | 
						|
                 DevicePathFromHandle (Handles[Index]),
 | 
						|
                 NULL,
 | 
						|
                 0
 | 
						|
                 );
 | 
						|
      ASSERT_EFI_ERROR (Status);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (HandleCount != 0) {
 | 
						|
    FreePool (Handles);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Parse simple file system not based on block io
 | 
						|
  //
 | 
						|
  NonBlockNumber = 0;
 | 
						|
  gBS->LocateHandleBuffer (
 | 
						|
         ByProtocol,
 | 
						|
         &gEfiSimpleFileSystemProtocolGuid,
 | 
						|
         NULL,
 | 
						|
         &HandleCount,
 | 
						|
         &Handles
 | 
						|
         );
 | 
						|
  for (Index = 0; Index < HandleCount; Index++) {
 | 
						|
    Status = gBS->HandleProtocol (
 | 
						|
                    Handles[Index],
 | 
						|
                    &gEfiBlockIoProtocolGuid,
 | 
						|
                    (VOID **) &BlkIo
 | 
						|
                    );
 | 
						|
     if (!EFI_ERROR (Status)) {
 | 
						|
      //
 | 
						|
      //  Skip if the file system handle supports a BlkIo protocol, which we've handled in above
 | 
						|
      //
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
    BootOptions = ReallocatePool (
 | 
						|
                    sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
 | 
						|
                    sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
 | 
						|
                    BootOptions
 | 
						|
                    );
 | 
						|
    ASSERT (BootOptions != NULL);
 | 
						|
 | 
						|
    Status = EfiBootManagerInitializeLoadOption (
 | 
						|
               &BootOptions[(*BootOptionCount)++],
 | 
						|
               LoadOptionNumberUnassigned,
 | 
						|
               LoadOptionTypeBoot,
 | 
						|
               LOAD_OPTION_ACTIVE,
 | 
						|
               mRecoveryBoot,
 | 
						|
               DevicePathFromHandle (Handles[Index]),
 | 
						|
               NULL,
 | 
						|
               0
 | 
						|
               );
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
  }
 | 
						|
 | 
						|
  if (HandleCount != 0) {
 | 
						|
    FreePool (Handles);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Parse load file, assuming UEFI Network boot option
 | 
						|
  //
 | 
						|
  gBS->LocateHandleBuffer (
 | 
						|
         ByProtocol,
 | 
						|
         &gEfiLoadFileProtocolGuid,
 | 
						|
         NULL,
 | 
						|
         &HandleCount,
 | 
						|
         &Handles
 | 
						|
         );
 | 
						|
  for (Index = 0; Index < HandleCount; Index++) {
 | 
						|
 | 
						|
    BootOptions = ReallocatePool (
 | 
						|
                    sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
 | 
						|
                    sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
 | 
						|
                    BootOptions
 | 
						|
                    );
 | 
						|
    ASSERT (BootOptions != NULL);
 | 
						|
 | 
						|
    Status = EfiBootManagerInitializeLoadOption (
 | 
						|
               &BootOptions[(*BootOptionCount)++],
 | 
						|
               LoadOptionNumberUnassigned,
 | 
						|
               LoadOptionTypeBoot,
 | 
						|
               LOAD_OPTION_ACTIVE,
 | 
						|
               mRecoveryBoot,
 | 
						|
               DevicePathFromHandle (Handles[Index]),
 | 
						|
               NULL,
 | 
						|
               0
 | 
						|
               );
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
  }
 | 
						|
 | 
						|
  if (HandleCount != 0) {
 | 
						|
    FreePool (Handles);
 | 
						|
  }
 | 
						|
 | 
						|
  return BootOptions;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Function waits for a given event to fire, or for an optional timeout to expire.
 | 
						|
 | 
						|
  @param   Event              The event to wait for
 | 
						|
  @param   Timeout            An optional timeout value in 100 ns units.
 | 
						|
 | 
						|
  @retval  EFI_SUCCESS      Event fired before Timeout expired.
 | 
						|
  @retval  EFI_TIME_OUT     Timout expired before Event fired..
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
BdsWaitForSingleEvent (
 | 
						|
  IN  EFI_EVENT                  Event,
 | 
						|
  IN  UINT64                     Timeout       OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN       Index;
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  EFI_EVENT   TimerEvent;
 | 
						|
  EFI_EVENT   WaitList[2];
 | 
						|
 | 
						|
  if (Timeout != 0) {
 | 
						|
    //
 | 
						|
    // Create a timer event
 | 
						|
    //
 | 
						|
    Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      //
 | 
						|
      // Set the timer event
 | 
						|
      //
 | 
						|
      gBS->SetTimer (
 | 
						|
             TimerEvent,
 | 
						|
             TimerRelative,
 | 
						|
             Timeout
 | 
						|
             );
 | 
						|
 | 
						|
      //
 | 
						|
      // Wait for the original event or the timer
 | 
						|
      //
 | 
						|
      WaitList[0] = Event;
 | 
						|
      WaitList[1] = TimerEvent;
 | 
						|
      Status      = gBS->WaitForEvent (2, WaitList, &Index);
 | 
						|
      ASSERT_EFI_ERROR (Status);
 | 
						|
      gBS->CloseEvent (TimerEvent);
 | 
						|
 | 
						|
      //
 | 
						|
      // If the timer expired, change the return to timed out
 | 
						|
      //
 | 
						|
      if (Index == 1) {
 | 
						|
        Status = EFI_TIMEOUT;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // No timeout... just wait on the event
 | 
						|
    //
 | 
						|
    Status = gBS->WaitForEvent (1, &Event, &Index);
 | 
						|
    ASSERT (!EFI_ERROR (Status));
 | 
						|
    ASSERT (Index == 0);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  The function reads user inputs.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
BdsReadKeys (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS         Status;
 | 
						|
  EFI_INPUT_KEY      Key;
 | 
						|
 | 
						|
  if (PcdGetBool (PcdConInConnectOnDemand)) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  while (gST->ConIn != NULL) {
 | 
						|
    
 | 
						|
    Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
 | 
						|
    
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      //
 | 
						|
      // No more keys.
 | 
						|
      //
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  The function waits for the boot manager timeout expires or hotkey is pressed.
 | 
						|
 | 
						|
  It calls PlatformBootManagerWaitCallback each second.
 | 
						|
 | 
						|
  @param     HotkeyTriggered   Input hotkey event.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
BdsWait (
 | 
						|
  IN EFI_EVENT      HotkeyTriggered
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS            Status;
 | 
						|
  UINT16                TimeoutRemain;
 | 
						|
 | 
						|
  DEBUG ((EFI_D_INFO, "[Bds]BdsWait ...Zzzzzzzzzzzz...\n"));
 | 
						|
 | 
						|
  TimeoutRemain = PcdGet16 (PcdPlatformBootTimeOut);
 | 
						|
  while (TimeoutRemain != 0) {
 | 
						|
    DEBUG ((EFI_D_INFO, "[Bds]BdsWait(%d)..Zzzz...\n", (UINTN) TimeoutRemain));
 | 
						|
    PlatformBootManagerWaitCallback (TimeoutRemain);
 | 
						|
 | 
						|
    BdsReadKeys (); // BUGBUG: Only reading can signal HotkeyTriggered
 | 
						|
                    //         Can be removed after all keyboard drivers invoke callback in timer callback.
 | 
						|
 | 
						|
    if (HotkeyTriggered != NULL) {
 | 
						|
      Status = BdsWaitForSingleEvent (HotkeyTriggered, EFI_TIMER_PERIOD_SECONDS (1));
 | 
						|
      if (!EFI_ERROR (Status)) {
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      gBS->Stall (1000000);
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // 0xffff means waiting forever
 | 
						|
    // BDS with no hotkey provided and 0xffff as timeout will "hang" in the loop
 | 
						|
    //
 | 
						|
    if (TimeoutRemain != 0xffff) {
 | 
						|
      TimeoutRemain--;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  DEBUG ((EFI_D_INFO, "[Bds]Exit the waiting!\n"));
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Attempt to boot each boot option in the BootOptions array.
 | 
						|
 | 
						|
  @param BootOptions       Input boot option array.
 | 
						|
  @param BootOptionCount   Input boot option count.
 | 
						|
 | 
						|
  @retval TRUE  Successfully boot one of the boot options.
 | 
						|
  @retval FALSE Failed boot any of the boot options.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
BootAllBootOptions (
 | 
						|
  IN EFI_BOOT_MANAGER_LOAD_OPTION    *BootOptions,
 | 
						|
  IN UINTN                           BootOptionCount
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN                              Index;
 | 
						|
 | 
						|
  //
 | 
						|
  // Attempt boot each boot option
 | 
						|
  //
 | 
						|
  for (Index = 0; Index < BootOptionCount; Index++) {
 | 
						|
    //
 | 
						|
    // 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 ((BootOptions[Index].Attributes & LOAD_OPTION_ACTIVE) == 0) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Boot#### load options with LOAD_OPTION_CATEGORY_APP are executables which are not
 | 
						|
    // part of the normal boot processing. Boot options with reserved category values will be
 | 
						|
    // ignored by the boot manager.
 | 
						|
    //
 | 
						|
    if ((BootOptions[Index].Attributes & LOAD_OPTION_CATEGORY) != LOAD_OPTION_CATEGORY_BOOT) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // All the driver options should have been processed since
 | 
						|
    // now boot will be performed.
 | 
						|
    //
 | 
						|
    EfiBootManagerBoot (&BootOptions[Index]);
 | 
						|
 | 
						|
    //
 | 
						|
    // Successful boot breaks the loop, otherwise tries next boot option
 | 
						|
    //
 | 
						|
    if (BootOptions[Index].Status == EFI_SUCCESS) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return (BOOLEAN) (Index < BootOptionCount);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function attempts to boot per the boot order specified by platform policy.
 | 
						|
 | 
						|
  If the boot via Boot#### returns with a status of EFI_SUCCESS the boot manager will stop 
 | 
						|
  processing the BootOrder variable and present a boot manager menu to the user. If a boot via 
 | 
						|
  Boot#### returns a status other than EFI_SUCCESS, the boot has failed and the next Boot####
 | 
						|
  in the BootOrder variable will be tried until all possibilities are exhausted.
 | 
						|
                                  -- Chapter 3.1.1 Boot Manager Programming, the 4th paragraph
 | 
						|
**/
 | 
						|
VOID
 | 
						|
DefaultBootBehavior (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN                        BootOptionCount;
 | 
						|
  EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
 | 
						|
  EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;
 | 
						|
 | 
						|
  EfiBootManagerGetBootManagerMenu (&BootManagerMenu);
 | 
						|
  //
 | 
						|
  // BootManagerMenu always contains the correct information even the above function returns failure.
 | 
						|
  //
 | 
						|
 | 
						|
  BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
 | 
						|
 | 
						|
  if (BootAllBootOptions (BootOptions, BootOptionCount)) {
 | 
						|
    //
 | 
						|
    // Follow generic rule, Call BdsDxeOnConnectConInCallBack to connect ConIn before enter UI
 | 
						|
    //
 | 
						|
    if (PcdGetBool (PcdConInConnectOnDemand)) {
 | 
						|
      BdsDxeOnConnectConInCallBack (NULL, NULL);
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Show the Boot Manager Menu after successful boot
 | 
						|
    //
 | 
						|
    EfiBootManagerBoot (&BootManagerMenu);
 | 
						|
  } else {
 | 
						|
    EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
 | 
						|
    //
 | 
						|
    // Re-scan all EFI boot options in case all the boot#### are deleted or failed to boot
 | 
						|
    //
 | 
						|
    // If no valid boot options exist, the boot manager will enumerate all removable media
 | 
						|
    // devices followed by all fixed media devices. The order within each group is undefined.
 | 
						|
    // These new default boot options are not saved to non volatile storage.The boot manger
 | 
						|
    // will then attempt toboot from each boot option.
 | 
						|
    //                            -- Chapter 3.3 Boot Manager Programming, the 2nd paragraph
 | 
						|
    //
 | 
						|
    EfiBootManagerConnectAll ();
 | 
						|
    BootOptions = BdsEnumerateBootOptions (&BootOptionCount);
 | 
						|
 | 
						|
    if (!BootAllBootOptions (BootOptions, BootOptionCount)) {
 | 
						|
      DEBUG ((EFI_D_ERROR, "[Bds]No bootable device!\n"));
 | 
						|
      EfiBootManagerBoot (&BootManagerMenu);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  EfiBootManagerFreeLoadOption (&BootManagerMenu);
 | 
						|
  EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  The function will load and start every Driver####/SysPrep####.
 | 
						|
 | 
						|
  @param  LoadOptions        Load option array.
 | 
						|
  @param  LoadOptionCount    Load option count.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
ProcessLoadOptions (
 | 
						|
  IN EFI_BOOT_MANAGER_LOAD_OPTION       *LoadOptions,
 | 
						|
  IN UINTN                              LoadOptionCount
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                        Status;
 | 
						|
  UINTN                             Index;
 | 
						|
  BOOLEAN                           ReconnectAll;
 | 
						|
  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType;
 | 
						|
 | 
						|
  ReconnectAll = FALSE;
 | 
						|
  LoadOptionType = LoadOptionTypeMax;
 | 
						|
 | 
						|
  //
 | 
						|
  // Process the driver option
 | 
						|
  //
 | 
						|
  for (Index = 0; Index < LoadOptionCount; Index++) {
 | 
						|
    //
 | 
						|
    // All the load options in the array should be of the same type.
 | 
						|
    //
 | 
						|
    if (LoadOptionType == LoadOptionTypeMax) {
 | 
						|
      LoadOptionType = LoadOptions[Index].OptionType;
 | 
						|
    }
 | 
						|
    ASSERT (LoadOptionType == LoadOptions[Index].OptionType);
 | 
						|
    ASSERT (LoadOptionType == LoadOptionTypeDriver || LoadOptionType == LoadOptionTypeSysPrep);
 | 
						|
 | 
						|
    Status = EfiBootManagerProcessLoadOption (&LoadOptions[Index]);
 | 
						|
 | 
						|
    if (!EFI_ERROR (Status) && ((LoadOptions[Index].Attributes & LOAD_OPTION_FORCE_RECONNECT) != 0)) {
 | 
						|
      ReconnectAll = TRUE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT,
 | 
						|
  // then all of the EFI drivers in the system will be disconnected and
 | 
						|
  // reconnected after the last driver load option is processed.
 | 
						|
  //
 | 
						|
  if (ReconnectAll && LoadOptionType == LoadOptionTypeDriver) {
 | 
						|
    EfiBootManagerDisconnectAll ();
 | 
						|
    EfiBootManagerConnectAll ();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  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;
 | 
						|
 | 
						|
  GetEfiGlobalVariable2 (VariableName, (VOID **) &DevicePath, &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);
 | 
						|
  }
 | 
						|
 | 
						|
  if (DevicePath != NULL) {
 | 
						|
    FreePool (DevicePath);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Formalize OsIndication related variables. 
 | 
						|
  
 | 
						|
  For OsIndicationsSupported, Create a BS/RT/UINT64 variable to report caps 
 | 
						|
  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 
 | 
						|
BdsFormalizeOSIndicationVariable (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS Status;
 | 
						|
  UINT64     OsIndicationSupport;
 | 
						|
  UINT64     OsIndication;
 | 
						|
  UINTN      DataSize;
 | 
						|
  UINT32     Attributes;
 | 
						|
 | 
						|
  //
 | 
						|
  // OS indicater support variable
 | 
						|
  //
 | 
						|
  OsIndicationSupport = EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
 | 
						|
  Status = gRT->SetVariable (
 | 
						|
                  L"OsIndicationsSupported",
 | 
						|
                  &gEfiGlobalVariableGuid,
 | 
						|
                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
 | 
						|
                  sizeof(UINT64),
 | 
						|
                  &OsIndicationSupport
 | 
						|
                  );
 | 
						|
  //
 | 
						|
  // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.
 | 
						|
  //
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  //
 | 
						|
  // 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 (Status == EFI_NOT_FOUND) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((DataSize != sizeof (OsIndication)) ||
 | 
						|
      ((OsIndication & ~OsIndicationSupport) != 0) ||
 | 
						|
      (Attributes != (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE))
 | 
						|
     ){
 | 
						|
 | 
						|
    DEBUG ((EFI_D_ERROR, "[Bds] 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);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Validate variables. 
 | 
						|
 | 
						|
**/
 | 
						|
VOID 
 | 
						|
BdsFormalizeEfiGlobalVariable (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // Validate Console variable.
 | 
						|
  //
 | 
						|
  BdsFormalizeConsoleVariable (L"ConIn");
 | 
						|
  BdsFormalizeConsoleVariable (L"ConOut");
 | 
						|
  BdsFormalizeConsoleVariable (L"ErrOut");
 | 
						|
 | 
						|
  //
 | 
						|
  // Validate OSIndication related variable.
 | 
						|
  //
 | 
						|
  BdsFormalizeOSIndicationVariable ();
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  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.
 | 
						|
    //
 | 
						|
    Status = 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
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_BOOT_MANAGER_LOAD_OPTION    *LoadOptions;
 | 
						|
  UINTN                           LoadOptionCount;
 | 
						|
  CHAR16                          *FirmwareVendor;
 | 
						|
  EFI_EVENT                       HotkeyTriggered;
 | 
						|
  UINT64                          OsIndication;
 | 
						|
  UINTN                           DataSize;
 | 
						|
  EFI_STATUS                      Status;
 | 
						|
  UINT32                          BootOptionSupport;
 | 
						|
  UINT16                          BootTimeOut;
 | 
						|
  EDKII_VARIABLE_LOCK_PROTOCOL    *VariableLock;
 | 
						|
  UINTN                           Index;
 | 
						|
  EFI_BOOT_MANAGER_LOAD_OPTION    BootOption;
 | 
						|
  UINT16                          *BootNext;
 | 
						|
  CHAR16                          BootNextVariableName[sizeof ("Boot####")];
 | 
						|
  EFI_BOOT_MANAGER_LOAD_OPTION    BootManagerMenu;
 | 
						|
  BOOLEAN                         BootFwUi;
 | 
						|
 | 
						|
  HotkeyTriggered = NULL;
 | 
						|
  Status          = EFI_SUCCESS;
 | 
						|
 | 
						|
  //
 | 
						|
  // Insert the performance probe
 | 
						|
  //
 | 
						|
  PERF_END (NULL, "DXE", NULL, 0);
 | 
						|
  PERF_START (NULL, "BDS", NULL, 0);
 | 
						|
  DEBUG ((EFI_D_INFO, "[Bds] Entry...\n"));
 | 
						|
 | 
						|
  PERF_CODE (
 | 
						|
    BdsAllocateMemoryForPerformanceData ();
 | 
						|
  );
 | 
						|
 | 
						|
  //
 | 
						|
  // 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);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  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 (
 | 
						|
      EFI_TIME_OUT_VARIABLE_NAME,
 | 
						|
      &gEfiGlobalVariableGuid,
 | 
						|
      EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
 | 
						|
      sizeof (UINT16),
 | 
						|
      &BootTimeOut
 | 
						|
      );
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize L"BootOptionSupport" EFI global variable.
 | 
						|
  // Lazy-ConIn implictly disables BDS hotkey.
 | 
						|
  //
 | 
						|
  BootOptionSupport = EFI_BOOT_OPTION_SUPPORT_APP | EFI_BOOT_OPTION_SUPPORT_SYSPREP;
 | 
						|
  if (!PcdGetBool (PcdConInConnectOnDemand)) {
 | 
						|
    BootOptionSupport |= EFI_BOOT_OPTION_SUPPORT_KEY;
 | 
						|
    SET_BOOT_OPTION_SUPPORT_KEY_COUNT (BootOptionSupport, 3);
 | 
						|
  }
 | 
						|
  Status = gRT->SetVariable (
 | 
						|
                  EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME,
 | 
						|
                  &gEfiGlobalVariableGuid,
 | 
						|
                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
 | 
						|
                  sizeof (BootOptionSupport),
 | 
						|
                  &BootOptionSupport
 | 
						|
                  );
 | 
						|
  //
 | 
						|
  // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.
 | 
						|
  //
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  //
 | 
						|
  // Cache and remove the "BootNext" NV variable.
 | 
						|
  //
 | 
						|
  GetEfiGlobalVariable2 (EFI_BOOT_NEXT_VARIABLE_NAME, (VOID **) &BootNext, &DataSize);
 | 
						|
  if (DataSize != sizeof (UINT16)) {
 | 
						|
    if (BootNext != NULL) {
 | 
						|
      FreePool (BootNext);
 | 
						|
    }
 | 
						|
    BootNext = NULL;
 | 
						|
  }
 | 
						|
  Status = gRT->SetVariable (
 | 
						|
                  EFI_BOOT_NEXT_VARIABLE_NAME,
 | 
						|
                  &gEfiGlobalVariableGuid,
 | 
						|
                  0,
 | 
						|
                  0,
 | 
						|
                  NULL
 | 
						|
                  );
 | 
						|
  //
 | 
						|
  // Deleting NV variable shouldn't fail unless it doesn't exist.
 | 
						|
  //
 | 
						|
  ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize the platform language variables
 | 
						|
  //
 | 
						|
  InitializeLanguage (TRUE);
 | 
						|
 | 
						|
  //
 | 
						|
  // 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)
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  // Do the platform init, can be customized by OEM/IBV
 | 
						|
  // Possible things that can be done in PlatformBootManagerBeforeConsole:
 | 
						|
  // > Update console variable: 1. include hot-plug devices; 2. Clear ConIn and add SOL for AMT
 | 
						|
  // > Register new Driver#### or Boot####
 | 
						|
  // > Register new Key####: e.g.: F12 
 | 
						|
  // > Signal ReadyToLock event
 | 
						|
  // > Authentication action: 1. connect Auth devices; 2. Identify auto logon user.
 | 
						|
  //
 | 
						|
  PERF_START (NULL, "PlatformBootManagerBeforeConsole", "BDS", 0);
 | 
						|
  PlatformBootManagerBeforeConsole ();
 | 
						|
  PERF_END   (NULL, "PlatformBootManagerBeforeConsole", "BDS", 0);
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize hotkey service
 | 
						|
  //
 | 
						|
  EfiBootManagerStartHotkeyService (&HotkeyTriggered);
 | 
						|
 | 
						|
  //
 | 
						|
  // Execute Driver Options
 | 
						|
  //
 | 
						|
  LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeDriver);
 | 
						|
  ProcessLoadOptions (LoadOptions, LoadOptionCount);
 | 
						|
  EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);
 | 
						|
 | 
						|
  //
 | 
						|
  // Connect consoles
 | 
						|
  //
 | 
						|
  PERF_START (NULL, "EfiBootManagerConnectAllDefaultConsoles", "BDS", 0);
 | 
						|
  if (PcdGetBool (PcdConInConnectOnDemand)) {
 | 
						|
    EfiBootManagerConnectConsoleVariable (ConOut);
 | 
						|
    EfiBootManagerConnectConsoleVariable (ErrOut);
 | 
						|
 | 
						|
    //
 | 
						|
    // Initialize ConnectConIn event
 | 
						|
    //
 | 
						|
    Status = gBS->CreateEventEx (
 | 
						|
                    EVT_NOTIFY_SIGNAL,
 | 
						|
                    TPL_CALLBACK,
 | 
						|
                    BdsDxeOnConnectConInCallBack,
 | 
						|
                    NULL,
 | 
						|
                    &gConnectConInEventGuid,
 | 
						|
                    &gConnectConInEvent
 | 
						|
                    );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      gConnectConInEvent = NULL;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    EfiBootManagerConnectAllDefaultConsoles ();
 | 
						|
  }
 | 
						|
  PERF_END   (NULL, "EfiBootManagerConnectAllDefaultConsoles", "BDS", 0);
 | 
						|
 | 
						|
  //
 | 
						|
  // Do the platform specific action after the console is ready
 | 
						|
  // Possible things that can be done in PlatformBootManagerAfterConsole:
 | 
						|
  // > Console post action:
 | 
						|
  //   > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
 | 
						|
  //   > Signal console ready platform customized event
 | 
						|
  // > Run diagnostics like memory testing
 | 
						|
  // > Connect certain devices
 | 
						|
  // > Dispatch aditional option roms
 | 
						|
  // > Special boot: e.g.: USB boot, enter UI
 | 
						|
  // 
 | 
						|
  PERF_START (NULL, "PlatformBootManagerAfterConsole", "BDS", 0);
 | 
						|
  PlatformBootManagerAfterConsole ();
 | 
						|
  PERF_END   (NULL, "PlatformBootManagerAfterConsole", "BDS", 0);
 | 
						|
 | 
						|
  DEBUG_CODE (
 | 
						|
    UINTN                             Index;
 | 
						|
    EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType;
 | 
						|
    DEBUG ((EFI_D_INFO, "[Bds]=============Begin Load Options Dumping ...=============\n"));
 | 
						|
    for (LoadOptionType = 0; LoadOptionType < LoadOptionTypeMax; LoadOptionType++) {
 | 
						|
      DEBUG ((
 | 
						|
        EFI_D_INFO, "  %s Options:\n",
 | 
						|
        mBdsLoadOptionName[LoadOptionType]
 | 
						|
        ));
 | 
						|
      LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionType);
 | 
						|
      for (Index = 0; Index < LoadOptionCount; Index++) {
 | 
						|
        DEBUG ((
 | 
						|
          EFI_D_INFO, "    %s%04x: %s \t\t 0x%04x\n",
 | 
						|
          mBdsLoadOptionName[LoadOptionType],
 | 
						|
          LoadOptions[Index].OptionNumber,
 | 
						|
          LoadOptions[Index].Description,
 | 
						|
          LoadOptions[Index].Attributes
 | 
						|
          ));
 | 
						|
      }
 | 
						|
      EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);
 | 
						|
    }
 | 
						|
    DEBUG ((EFI_D_INFO, "[Bds]=============End Load Options Dumping=============\n"));
 | 
						|
  );
 | 
						|
 | 
						|
  //
 | 
						|
  // Boot to Boot Manager Menu when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot
 | 
						|
  //
 | 
						|
  DataSize = sizeof (UINT64);
 | 
						|
  Status = gRT->GetVariable (
 | 
						|
                  L"OsIndications",
 | 
						|
                  &gEfiGlobalVariableGuid,
 | 
						|
                  NULL,
 | 
						|
                  &DataSize,
 | 
						|
                  &OsIndication
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    OsIndication = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  BootFwUi = (BOOLEAN) ((OsIndication & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) != 0);
 | 
						|
  //
 | 
						|
  // Clear EFI_OS_INDICATIONS_BOOT_TO_FW_UI to acknowledge OS
 | 
						|
  // 
 | 
						|
  if (BootFwUi) {
 | 
						|
    OsIndication &= ~((UINT64) EFI_OS_INDICATIONS_BOOT_TO_FW_UI);
 | 
						|
    Status = gRT->SetVariable (
 | 
						|
               L"OsIndications",
 | 
						|
               &gEfiGlobalVariableGuid,
 | 
						|
               EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
 | 
						|
               sizeof(UINT64),
 | 
						|
               &OsIndication
 | 
						|
               );
 | 
						|
    //
 | 
						|
    // Changing the content without increasing its size with current variable implementation shouldn't fail.
 | 
						|
    //
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Launch Boot Manager Menu directly when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot
 | 
						|
  //
 | 
						|
  if (BootFwUi) {
 | 
						|
    //
 | 
						|
    // Follow generic rule, Call BdsDxeOnConnectConInCallBack to connect ConIn before enter UI
 | 
						|
    //
 | 
						|
    if (PcdGetBool (PcdConInConnectOnDemand)) {
 | 
						|
      BdsDxeOnConnectConInCallBack (NULL, NULL);
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Directly enter the setup page.
 | 
						|
    // BootManagerMenu always contains the correct information even call fails.
 | 
						|
    //
 | 
						|
    EfiBootManagerGetBootManagerMenu (&BootManagerMenu);
 | 
						|
    EfiBootManagerBoot (&BootManagerMenu);
 | 
						|
    EfiBootManagerFreeLoadOption (&BootManagerMenu);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Execute SysPrep####
 | 
						|
  //
 | 
						|
  LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeSysPrep);
 | 
						|
  ProcessLoadOptions (LoadOptions, LoadOptionCount);
 | 
						|
  EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);
 | 
						|
 | 
						|
  //
 | 
						|
  // Execute Key####
 | 
						|
  //
 | 
						|
  PERF_START (NULL, "BdsWait", "BDS", 0);
 | 
						|
  BdsWait (HotkeyTriggered);
 | 
						|
  PERF_END   (NULL, "BdsWait", "BDS", 0);
 | 
						|
 | 
						|
  //
 | 
						|
  // BdsReadKeys() be removed after all keyboard drivers invoke callback in timer callback.
 | 
						|
  //
 | 
						|
  BdsReadKeys ();
 | 
						|
 | 
						|
  EfiBootManagerHotkeyBoot ();
 | 
						|
 | 
						|
  //
 | 
						|
  // Boot to "BootNext"
 | 
						|
  //
 | 
						|
  if (BootNext != NULL) {
 | 
						|
    UnicodeSPrint (BootNextVariableName, sizeof (BootNextVariableName), L"Boot%04x", *BootNext);
 | 
						|
    Status = EfiBootManagerVariableToLoadOption (BootNextVariableName, &BootOption);
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      EfiBootManagerBoot (&BootOption);
 | 
						|
      EfiBootManagerFreeLoadOption (&BootOption);
 | 
						|
      if (BootOption.Status == EFI_SUCCESS) {
 | 
						|
        //
 | 
						|
        // Boot to Boot Manager Menu upon EFI_SUCCESS
 | 
						|
        //
 | 
						|
        EfiBootManagerGetBootManagerMenu (&BootOption);
 | 
						|
        EfiBootManagerBoot (&BootOption);
 | 
						|
        EfiBootManagerFreeLoadOption (&BootOption);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  while (TRUE) {
 | 
						|
    //
 | 
						|
    // BDS select the boot device to load OS
 | 
						|
    // Try next upon boot failure
 | 
						|
    // Show Boot Manager Menu upon boot success
 | 
						|
    //
 | 
						|
    DefaultBootBehavior ();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  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;
 | 
						|
}
 |