Home | History | Annotate | Download | only in PlatformBootManagerLib
      1 /** @file
      2   This file include all platform action which can be customized
      3   by IBV/OEM.
      4 
      5 Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
      6 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
      7 This program and the accompanying materials
      8 are licensed and made available under the terms and conditions of the BSD License
      9 which accompanies this distribution.  The full text of the license may be found at
     10 http://opensource.org/licenses/bsd-license.php
     11 
     12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 
     17 #include "PlatformBootManager.h"
     18 
     19 EFI_GUID mBootMenuFile = {
     20   0xEEC25BDC, 0x67F2, 0x4D95, { 0xB1, 0xD5, 0xF8, 0x1B, 0x20, 0x39, 0xD1, 0x1D }
     21 };
     22 
     23 /**
     24   Perform the platform diagnostic, such like test memory. OEM/IBV also
     25   can customize this function to support specific platform diagnostic.
     26 
     27   @param MemoryTestLevel  The memory test intensive level
     28   @param QuietBoot        Indicate if need to enable the quiet boot
     29 
     30 **/
     31 VOID
     32 PlatformBootManagerDiagnostics (
     33   IN EXTENDMEM_COVERAGE_LEVEL    MemoryTestLevel,
     34   IN BOOLEAN                     QuietBoot
     35   )
     36 {
     37   EFI_STATUS                     Status;
     38 
     39   //
     40   // Here we can decide if we need to show
     41   // the diagnostics screen
     42   // Notes: this quiet boot code should be remove
     43   // from the graphic lib
     44   //
     45   if (QuietBoot) {
     46     BootLogoEnableLogo ();
     47 
     48     //
     49     // Perform system diagnostic
     50     //
     51     Status = PlatformBootManagerMemoryTest (MemoryTestLevel);
     52     if (EFI_ERROR (Status)) {
     53       BootLogoDisableLogo ();
     54     }
     55 
     56     return;
     57   }
     58 
     59   //
     60   // Perform system diagnostic
     61   //
     62   Status = PlatformBootManagerMemoryTest (MemoryTestLevel);
     63 }
     64 
     65 /**
     66   Do the platform specific action before the console is connected.
     67 
     68   Such as:
     69     Update console variable;
     70     Register new Driver#### or Boot####;
     71     Signal ReadyToLock event.
     72 **/
     73 VOID
     74 EFIAPI
     75 PlatformBootManagerBeforeConsole (
     76   VOID
     77   )
     78 {
     79   UINTN                        Index;
     80   EFI_STATUS                   Status;
     81   WIN_NT_SYSTEM_CONFIGURATION  *Configuration;
     82 
     83   GetVariable2 (L"Setup", &gEfiWinNtSystemConfigGuid, (VOID **) &Configuration, NULL);
     84   if (Configuration != NULL) {
     85     //
     86     // SetupVariable is corrupt
     87     //
     88     Configuration->ConOutRow = PcdGet32 (PcdConOutColumn);
     89     Configuration->ConOutColumn = PcdGet32 (PcdConOutRow);
     90 
     91     Status = gRT->SetVariable (
     92                     L"Setup",
     93                     &gEfiWinNtSystemConfigGuid,
     94                     EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
     95                     sizeof (WIN_NT_SYSTEM_CONFIGURATION),
     96                     Configuration
     97                     );
     98     if (EFI_ERROR (Status)) {
     99       DEBUG ((EFI_D_ERROR, "Failed to save Setup Variable to non-volatile storage, Status = %r\n", Status));
    100     }
    101     FreePool (Configuration);
    102   }
    103 
    104   //
    105   // Update the ocnsole variables.
    106   //
    107   for (Index = 0; gPlatformConsole[Index].DevicePath != NULL; Index++) {
    108     if ((gPlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) {
    109       EfiBootManagerUpdateConsoleVariable (ConIn, gPlatformConsole[Index].DevicePath, NULL);
    110     }
    111 
    112     if ((gPlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) {
    113       EfiBootManagerUpdateConsoleVariable (ConOut, gPlatformConsole[Index].DevicePath, NULL);
    114     }
    115 
    116     if ((gPlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) {
    117       EfiBootManagerUpdateConsoleVariable (ErrOut, gPlatformConsole[Index].DevicePath, NULL);
    118     }
    119   }
    120 
    121   //
    122   // From PI spec vol2:
    123   // Prior to invoking any UEFI drivers, applications, or connecting consoles,
    124   // the platform should signal the event EFI_END_OF_DXE_EVENT_GUID
    125   //
    126   EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
    127 
    128   //
    129   // Dispatch deferred images after EndOfDxe event.
    130   //
    131   EfiBootManagerDispatchDeferredImages ();
    132 }
    133 
    134 /**
    135   Returns the priority number.
    136 
    137   @param BootOption
    138 **/
    139 UINTN
    140 BootOptionPriority (
    141   CONST EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
    142   )
    143 {
    144   //
    145   // Make sure Shell is first
    146   //
    147   if (StrCmp (BootOption->Description, L"UEFI Shell") == 0) {
    148     return 0;
    149   }
    150   return 100;
    151 }
    152 
    153 INTN
    154 EFIAPI
    155 CompareBootOption (
    156   CONST EFI_BOOT_MANAGER_LOAD_OPTION  *Left,
    157   CONST EFI_BOOT_MANAGER_LOAD_OPTION  *Right
    158   )
    159 {
    160   return BootOptionPriority (Left) - BootOptionPriority (Right);
    161 }
    162 
    163 /**
    164   Generate device path include the input file guid info.
    165 
    166   @param  FileGuid     Input file guid for the BootManagerMenuApp.
    167 
    168   @retval DevicePath for BootManagerMenuApp.
    169 **/
    170 EFI_DEVICE_PATH *
    171 FvFilePath (
    172   EFI_GUID                     *FileGuid
    173   )
    174 {
    175 
    176   EFI_STATUS                         Status;
    177   EFI_LOADED_IMAGE_PROTOCOL          *LoadedImage;
    178   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH  FileNode;
    179 
    180   EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
    181 
    182   Status = gBS->HandleProtocol (
    183                   gImageHandle,
    184                   &gEfiLoadedImageProtocolGuid,
    185                   (VOID **) &LoadedImage
    186                   );
    187   ASSERT_EFI_ERROR (Status);
    188 
    189   return AppendDevicePathNode (
    190            DevicePathFromHandle (LoadedImage->DeviceHandle),
    191            (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
    192            );
    193 }
    194 
    195 /**
    196   Create one boot option for BootManagerMenuApp.
    197 
    198   @param  FileGuid          Input file guid for the BootManagerMenuApp.
    199   @param  Description       Description of the BootManagerMenuApp boot option.
    200   @param  Position          Position of the new load option to put in the ****Order variable.
    201   @param  IsBootCategory    Whether this is a boot category.
    202 
    203 
    204   @retval OptionNumber      Return the option number info.
    205 
    206 **/
    207 UINTN
    208 RegisterBootManagerMenuAppBootOption (
    209   EFI_GUID                         *FileGuid,
    210   CHAR16                           *Description,
    211   UINTN                            Position,
    212   BOOLEAN                          IsBootCategory
    213   )
    214 {
    215   EFI_STATUS                       Status;
    216   EFI_BOOT_MANAGER_LOAD_OPTION     NewOption;
    217   EFI_DEVICE_PATH_PROTOCOL         *DevicePath;
    218   UINTN                            OptionNumber;
    219 
    220   DevicePath = FvFilePath (FileGuid);
    221   Status = EfiBootManagerInitializeLoadOption (
    222              &NewOption,
    223              LoadOptionNumberUnassigned,
    224              LoadOptionTypeBoot,
    225              IsBootCategory ? LOAD_OPTION_ACTIVE : LOAD_OPTION_CATEGORY_APP,
    226              Description,
    227              DevicePath,
    228              NULL,
    229              0
    230              );
    231   ASSERT_EFI_ERROR (Status);
    232   FreePool (DevicePath);
    233 
    234   Status = EfiBootManagerAddLoadOptionVariable (&NewOption, Position);
    235   ASSERT_EFI_ERROR (Status);
    236 
    237   OptionNumber = NewOption.OptionNumber;
    238 
    239   EfiBootManagerFreeLoadOption (&NewOption);
    240 
    241   return OptionNumber;
    242 }
    243 
    244 /**
    245   Check if it's a Device Path pointing to BootManagerMenuApp.
    246 
    247   @param  DevicePath     Input device path.
    248 
    249   @retval TRUE   The device path is BootManagerMenuApp File Device Path.
    250   @retval FALSE  The device path is NOT BootManagerMenuApp File Device Path.
    251 **/
    252 BOOLEAN
    253 IsBootManagerMenuAppFilePath (
    254   EFI_DEVICE_PATH_PROTOCOL     *DevicePath
    255 )
    256 {
    257   EFI_HANDLE                      FvHandle;
    258   VOID                            *NameGuid;
    259   EFI_STATUS                      Status;
    260 
    261   Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &DevicePath, &FvHandle);
    262   if (!EFI_ERROR (Status)) {
    263     NameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) DevicePath);
    264     if (NameGuid != NULL) {
    265       return CompareGuid (NameGuid, &mBootMenuFile);
    266     }
    267   }
    268 
    269   return FALSE;
    270 }
    271 
    272 /**
    273   Return the boot option number to the BootManagerMenuApp.
    274 
    275   If not found it in the current boot option, create a new one.
    276 
    277   @retval OptionNumber   Return the boot option number to the BootManagerMenuApp.
    278 
    279 **/
    280 UINTN
    281 GetBootManagerMenuAppOption (
    282   VOID
    283   )
    284 {
    285   UINTN                        BootOptionCount;
    286   EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
    287   UINTN                        Index;
    288   UINTN                        OptionNumber;
    289 
    290   OptionNumber = 0;
    291 
    292   BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
    293 
    294   for (Index = 0; Index < BootOptionCount; Index++) {
    295     if (IsBootManagerMenuAppFilePath (BootOptions[Index].FilePath)) {
    296       OptionNumber = BootOptions[Index].OptionNumber;
    297       break;
    298     }
    299   }
    300 
    301   EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
    302 
    303   if (Index >= BootOptionCount) {
    304     //
    305     // If not found the BootManagerMenuApp, create it.
    306     //
    307     OptionNumber = (UINT16) RegisterBootManagerMenuAppBootOption (&mBootMenuFile, L"UEFI BootManagerMenuApp", (UINTN) -1, FALSE);
    308   }
    309 
    310   return OptionNumber;
    311 }
    312 
    313 /**
    314   Do the platform specific action after the console is connected.
    315 
    316   Such as:
    317     Dynamically switch output mode;
    318     Signal console ready platform customized event;
    319     Run diagnostics like memory testing;
    320     Connect certain devices;
    321     Dispatch aditional option roms.
    322 **/
    323 VOID
    324 EFIAPI
    325 PlatformBootManagerAfterConsole (
    326   VOID
    327   )
    328 {
    329   EFI_GRAPHICS_OUTPUT_BLT_PIXEL  Black;
    330   EFI_GRAPHICS_OUTPUT_BLT_PIXEL  White;
    331   EFI_INPUT_KEY                  Enter;
    332   EFI_INPUT_KEY                  F2;
    333   EFI_INPUT_KEY                  F7;
    334   EFI_BOOT_MANAGER_LOAD_OPTION   BootOption;
    335   UINTN                          OptionNumber;
    336 
    337   Black.Blue = Black.Green = Black.Red = Black.Reserved = 0;
    338   White.Blue = White.Green = White.Red = White.Reserved = 0xFF;
    339 
    340   EfiBootManagerConnectAll ();
    341   EfiBootManagerRefreshAllBootOption ();
    342 
    343   //
    344   // Register ENTER as CONTINUE key
    345   //
    346   Enter.ScanCode    = SCAN_NULL;
    347   Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
    348   EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
    349   //
    350   // Map F2 to Boot Manager Menu
    351   //
    352   F2.ScanCode    = SCAN_F2;
    353   F2.UnicodeChar = CHAR_NULL;
    354   EfiBootManagerGetBootManagerMenu (&BootOption);
    355   EfiBootManagerAddKeyOptionVariable (NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL);
    356 
    357   //
    358   // 3. Boot Device List menu
    359   //
    360   F7.ScanCode     = SCAN_F7;
    361   F7.UnicodeChar  = CHAR_NULL;
    362   OptionNumber    = GetBootManagerMenuAppOption ();
    363   EfiBootManagerAddKeyOptionVariable (NULL, (UINT16)OptionNumber, 0, &F7, NULL);
    364 
    365   //
    366   // Make Shell as the first boot option
    367   //
    368   EfiBootManagerSortLoadOptionVariable (LoadOptionTypeBoot, (SORT_COMPARE) CompareBootOption);
    369 
    370   PlatformBootManagerDiagnostics (QUICK, TRUE);
    371 
    372   PrintXY (10, 10, &White, &Black, L"F2    to enter Setup.                              ");
    373   PrintXY (10, 30, &White, &Black, L"F7    to enter Boot Manager Menu.");
    374   PrintXY (10, 50, &White, &Black, L"Enter to boot directly.");
    375 }
    376 
    377 /**
    378   This function is called each second during the boot manager waits the timeout.
    379 
    380   @param TimeoutRemain  The remaining timeout.
    381 **/
    382 VOID
    383 EFIAPI
    384 PlatformBootManagerWaitCallback (
    385   UINT16          TimeoutRemain
    386   )
    387 {
    388   EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;
    389   EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;
    390   UINT16                              Timeout;
    391 
    392   Timeout = PcdGet16 (PcdPlatformBootTimeOut);
    393 
    394   Black.Raw = 0x00000000;
    395   White.Raw = 0x00FFFFFF;
    396 
    397   BootLogoUpdateProgress (
    398     White.Pixel,
    399     Black.Pixel,
    400     L"Start boot option",
    401     White.Pixel,
    402     (Timeout - TimeoutRemain) * 100 / Timeout,
    403     0
    404     );
    405 }
    406