Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com> Reviewed-by: Eric Dong <eric.dong@intel.com> Reviewed-by: Sunny Wang <sunnywang@hpe.com>
		
			
				
	
	
		
			406 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			406 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  This file include all platform action which can be customized
 | 
						|
  by IBV/OEM.
 | 
						|
 | 
						|
Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
 | 
						|
(C) Copyright 2016 Hewlett Packard Enterprise Development LP<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 "PlatformBootManager.h"
 | 
						|
 | 
						|
EFI_GUID mBootMenuFile = {
 | 
						|
  0xEEC25BDC, 0x67F2, 0x4D95, { 0xB1, 0xD5, 0xF8, 0x1B, 0x20, 0x39, 0xD1, 0x1D }
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
  Perform the platform diagnostic, such like test memory. OEM/IBV also
 | 
						|
  can customize this function to support specific platform diagnostic.
 | 
						|
 | 
						|
  @param MemoryTestLevel  The memory test intensive level
 | 
						|
  @param QuietBoot        Indicate if need to enable the quiet boot
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
PlatformBootManagerDiagnostics (
 | 
						|
  IN EXTENDMEM_COVERAGE_LEVEL    MemoryTestLevel,
 | 
						|
  IN BOOLEAN                     QuietBoot
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                     Status;
 | 
						|
 | 
						|
  //
 | 
						|
  // Here we can decide if we need to show
 | 
						|
  // the diagnostics screen
 | 
						|
  // Notes: this quiet boot code should be remove
 | 
						|
  // from the graphic lib
 | 
						|
  //
 | 
						|
  if (QuietBoot) {
 | 
						|
    BootLogoEnableLogo ();
 | 
						|
 | 
						|
    //
 | 
						|
    // Perform system diagnostic
 | 
						|
    //
 | 
						|
    Status = PlatformBootManagerMemoryTest (MemoryTestLevel);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      BootLogoDisableLogo ();
 | 
						|
    }
 | 
						|
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Perform system diagnostic
 | 
						|
  //
 | 
						|
  Status = PlatformBootManagerMemoryTest (MemoryTestLevel);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Do the platform specific action before the console is connected.
 | 
						|
 | 
						|
  Such as:
 | 
						|
    Update console variable;
 | 
						|
    Register new Driver#### or Boot####;
 | 
						|
    Signal ReadyToLock event.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
PlatformBootManagerBeforeConsole (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN                        Index;
 | 
						|
  EFI_STATUS                   Status;
 | 
						|
  WIN_NT_SYSTEM_CONFIGURATION  *Configuration;
 | 
						|
 | 
						|
  GetVariable2 (L"Setup", &gEfiWinNtSystemConfigGuid, (VOID **) &Configuration, NULL);
 | 
						|
  if (Configuration != NULL) {
 | 
						|
    //
 | 
						|
    // SetupVariable is corrupt
 | 
						|
    //
 | 
						|
    Configuration->ConOutRow = PcdGet32 (PcdConOutColumn);
 | 
						|
    Configuration->ConOutColumn = PcdGet32 (PcdConOutRow);
 | 
						|
 | 
						|
    Status = gRT->SetVariable (
 | 
						|
                    L"Setup",
 | 
						|
                    &gEfiWinNtSystemConfigGuid,
 | 
						|
                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
 | 
						|
                    sizeof (WIN_NT_SYSTEM_CONFIGURATION),
 | 
						|
                    Configuration
 | 
						|
                    );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      DEBUG ((EFI_D_ERROR, "Failed to save Setup Variable to non-volatile storage, Status = %r\n", Status));
 | 
						|
    }
 | 
						|
    FreePool (Configuration);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Update the ocnsole variables.
 | 
						|
  //
 | 
						|
  for (Index = 0; gPlatformConsole[Index].DevicePath != NULL; Index++) {
 | 
						|
    if ((gPlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) {
 | 
						|
      EfiBootManagerUpdateConsoleVariable (ConIn, gPlatformConsole[Index].DevicePath, NULL);
 | 
						|
    }
 | 
						|
 | 
						|
    if ((gPlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) {
 | 
						|
      EfiBootManagerUpdateConsoleVariable (ConOut, gPlatformConsole[Index].DevicePath, NULL);
 | 
						|
    }
 | 
						|
 | 
						|
    if ((gPlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) {
 | 
						|
      EfiBootManagerUpdateConsoleVariable (ErrOut, gPlatformConsole[Index].DevicePath, NULL);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // From PI spec vol2:
 | 
						|
  // Prior to invoking any UEFI drivers, applications, or connecting consoles, 
 | 
						|
  // the platform should signal the event EFI_END_OF_DXE_EVENT_GUID
 | 
						|
  //
 | 
						|
  EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
 | 
						|
 | 
						|
  //
 | 
						|
  // Dispatch deferred images after EndOfDxe event.
 | 
						|
  //
 | 
						|
  EfiBootManagerDispatchDeferredImages ();
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Returns the priority number.
 | 
						|
 | 
						|
  @param BootOption
 | 
						|
**/
 | 
						|
UINTN
 | 
						|
BootOptionPriority (
 | 
						|
  CONST EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // Make sure Shell is first
 | 
						|
  //
 | 
						|
  if (StrCmp (BootOption->Description, L"UEFI Shell") == 0) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
  return 100;
 | 
						|
}
 | 
						|
 | 
						|
INTN
 | 
						|
EFIAPI
 | 
						|
CompareBootOption (
 | 
						|
  CONST EFI_BOOT_MANAGER_LOAD_OPTION  *Left,
 | 
						|
  CONST EFI_BOOT_MANAGER_LOAD_OPTION  *Right
 | 
						|
  )
 | 
						|
{
 | 
						|
  return BootOptionPriority (Left) - BootOptionPriority (Right);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Generate device path include the input file guid info.
 | 
						|
 | 
						|
  @param  FileGuid     Input file guid for the BootManagerMenuApp.
 | 
						|
 | 
						|
  @retval DevicePath for BootManagerMenuApp.
 | 
						|
**/
 | 
						|
EFI_DEVICE_PATH *
 | 
						|
FvFilePath (
 | 
						|
  EFI_GUID                     *FileGuid
 | 
						|
  )
 | 
						|
{
 | 
						|
 | 
						|
  EFI_STATUS                         Status;
 | 
						|
  EFI_LOADED_IMAGE_PROTOCOL          *LoadedImage;
 | 
						|
  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH  FileNode;
 | 
						|
 | 
						|
  EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
 | 
						|
 | 
						|
  Status = gBS->HandleProtocol (
 | 
						|
                  gImageHandle,
 | 
						|
                  &gEfiLoadedImageProtocolGuid,
 | 
						|
                  (VOID **) &LoadedImage
 | 
						|
                  );
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  return AppendDevicePathNode (
 | 
						|
           DevicePathFromHandle (LoadedImage->DeviceHandle),
 | 
						|
           (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
 | 
						|
           );
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Create one boot option for BootManagerMenuApp.
 | 
						|
 | 
						|
  @param  FileGuid          Input file guid for the BootManagerMenuApp.
 | 
						|
  @param  Description       Description of the BootManagerMenuApp boot option.
 | 
						|
  @param  Position          Position of the new load option to put in the ****Order variable.
 | 
						|
  @param  IsBootCategory    Whether this is a boot category.
 | 
						|
 | 
						|
 | 
						|
  @retval OptionNumber      Return the option number info.
 | 
						|
 | 
						|
**/
 | 
						|
UINTN
 | 
						|
RegisterBootManagerMenuAppBootOption (
 | 
						|
  EFI_GUID                         *FileGuid,
 | 
						|
  CHAR16                           *Description,
 | 
						|
  UINTN                            Position,
 | 
						|
  BOOLEAN                          IsBootCategory
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                       Status;
 | 
						|
  EFI_BOOT_MANAGER_LOAD_OPTION     NewOption;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL         *DevicePath;
 | 
						|
  UINTN                            OptionNumber;
 | 
						|
 | 
						|
  DevicePath = FvFilePath (FileGuid);
 | 
						|
  Status = EfiBootManagerInitializeLoadOption (
 | 
						|
             &NewOption,
 | 
						|
             LoadOptionNumberUnassigned,
 | 
						|
             LoadOptionTypeBoot,
 | 
						|
             IsBootCategory ? LOAD_OPTION_ACTIVE : LOAD_OPTION_CATEGORY_APP,
 | 
						|
             Description,
 | 
						|
             DevicePath,
 | 
						|
             NULL,
 | 
						|
             0
 | 
						|
             );
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
  FreePool (DevicePath);
 | 
						|
 | 
						|
  Status = EfiBootManagerAddLoadOptionVariable (&NewOption, Position);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  OptionNumber = NewOption.OptionNumber;
 | 
						|
 | 
						|
  EfiBootManagerFreeLoadOption (&NewOption);
 | 
						|
 | 
						|
  return OptionNumber;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check if it's a Device Path pointing to BootManagerMenuApp.
 | 
						|
 | 
						|
  @param  DevicePath     Input device path.
 | 
						|
 | 
						|
  @retval TRUE   The device path is BootManagerMenuApp File Device Path.
 | 
						|
  @retval FALSE  The device path is NOT BootManagerMenuApp File Device Path.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsBootManagerMenuAppFilePath (
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL     *DevicePath
 | 
						|
)
 | 
						|
{
 | 
						|
  EFI_HANDLE                      FvHandle;
 | 
						|
  VOID                            *NameGuid;
 | 
						|
  EFI_STATUS                      Status;
 | 
						|
 | 
						|
  Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &DevicePath, &FvHandle);
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    NameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) DevicePath);
 | 
						|
    if (NameGuid != NULL) {
 | 
						|
      return CompareGuid (NameGuid, &mBootMenuFile);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Return the boot option number to the BootManagerMenuApp.
 | 
						|
 | 
						|
  If not found it in the current boot option, create a new one.
 | 
						|
 | 
						|
  @retval OptionNumber   Return the boot option number to the BootManagerMenuApp.
 | 
						|
 | 
						|
**/
 | 
						|
UINTN
 | 
						|
GetBootManagerMenuAppOption (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN                        BootOptionCount;
 | 
						|
  EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
 | 
						|
  UINTN                        Index;
 | 
						|
  UINTN                        OptionNumber;
 | 
						|
 | 
						|
  OptionNumber = 0;
 | 
						|
 | 
						|
  BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
 | 
						|
 | 
						|
  for (Index = 0; Index < BootOptionCount; Index++) {
 | 
						|
    if (IsBootManagerMenuAppFilePath (BootOptions[Index].FilePath)) {
 | 
						|
      OptionNumber = BootOptions[Index].OptionNumber;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
 | 
						|
 | 
						|
  if (Index >= BootOptionCount) {
 | 
						|
    //
 | 
						|
    // If not found the BootManagerMenuApp, create it.
 | 
						|
    //
 | 
						|
    OptionNumber = (UINT16) RegisterBootManagerMenuAppBootOption (&mBootMenuFile, L"UEFI BootManagerMenuApp", (UINTN) -1, FALSE);
 | 
						|
  }
 | 
						|
 | 
						|
  return OptionNumber;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Do the platform specific action after the console is connected.
 | 
						|
 | 
						|
  Such as:
 | 
						|
    Dynamically switch output mode;
 | 
						|
    Signal console ready platform customized event;
 | 
						|
    Run diagnostics like memory testing;
 | 
						|
    Connect certain devices;
 | 
						|
    Dispatch aditional option roms.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
PlatformBootManagerAfterConsole (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_GRAPHICS_OUTPUT_BLT_PIXEL  Black;
 | 
						|
  EFI_GRAPHICS_OUTPUT_BLT_PIXEL  White;
 | 
						|
  EFI_INPUT_KEY                  Enter;
 | 
						|
  EFI_INPUT_KEY                  F2;
 | 
						|
  EFI_INPUT_KEY                  F7;
 | 
						|
  EFI_BOOT_MANAGER_LOAD_OPTION   BootOption;
 | 
						|
  UINTN                          OptionNumber;
 | 
						|
 | 
						|
  Black.Blue = Black.Green = Black.Red = Black.Reserved = 0;
 | 
						|
  White.Blue = White.Green = White.Red = White.Reserved = 0xFF;
 | 
						|
 | 
						|
  EfiBootManagerConnectAll ();
 | 
						|
  EfiBootManagerRefreshAllBootOption ();
 | 
						|
 | 
						|
  //
 | 
						|
  // Register ENTER as CONTINUE key
 | 
						|
  //
 | 
						|
  Enter.ScanCode    = SCAN_NULL;
 | 
						|
  Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
 | 
						|
  EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
 | 
						|
  //
 | 
						|
  // Map F2 to Boot Manager Menu
 | 
						|
  //
 | 
						|
  F2.ScanCode    = SCAN_F2;
 | 
						|
  F2.UnicodeChar = CHAR_NULL;
 | 
						|
  EfiBootManagerGetBootManagerMenu (&BootOption);
 | 
						|
  EfiBootManagerAddKeyOptionVariable (NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL);
 | 
						|
 | 
						|
  //
 | 
						|
  // 3. Boot Device List menu
 | 
						|
  //
 | 
						|
  F7.ScanCode     = SCAN_F7;
 | 
						|
  F7.UnicodeChar  = CHAR_NULL;
 | 
						|
  OptionNumber    = GetBootManagerMenuAppOption ();
 | 
						|
  EfiBootManagerAddKeyOptionVariable (NULL, (UINT16)OptionNumber, 0, &F7, NULL);
 | 
						|
 | 
						|
  //
 | 
						|
  // Make Shell as the first boot option
 | 
						|
  //
 | 
						|
  EfiBootManagerSortLoadOptionVariable (LoadOptionTypeBoot, (SORT_COMPARE) CompareBootOption);
 | 
						|
 | 
						|
  PlatformBootManagerDiagnostics (QUICK, TRUE);
 | 
						|
 | 
						|
  PrintXY (10, 10, &White, &Black, L"F2    to enter Setup.                              ");
 | 
						|
  PrintXY (10, 30, &White, &Black, L"F7    to enter Boot Manager Menu.");
 | 
						|
  PrintXY (10, 50, &White, &Black, L"Enter to boot directly.");
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function is called each second during the boot manager waits the timeout.
 | 
						|
 | 
						|
  @param TimeoutRemain  The remaining timeout.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
PlatformBootManagerWaitCallback (
 | 
						|
  UINT16          TimeoutRemain
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;
 | 
						|
  EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;
 | 
						|
  UINT16                              Timeout;
 | 
						|
 | 
						|
  Timeout = PcdGet16 (PcdPlatformBootTimeOut);
 | 
						|
 | 
						|
  Black.Raw = 0x00000000;
 | 
						|
  White.Raw = 0x00FFFFFF;
 | 
						|
 | 
						|
  BootLogoUpdateProgress (
 | 
						|
    White.Pixel,
 | 
						|
    Black.Pixel,
 | 
						|
    L"Start boot option",
 | 
						|
    White.Pixel,
 | 
						|
    (Timeout - TimeoutRemain) * 100 / Timeout,
 | 
						|
    0
 | 
						|
    );
 | 
						|
}
 |