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 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions of the BSD License
      8 which accompanies this distribution.  The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "PlatformBootManager.h"
     17 
     18 EFI_GUID mUefiShellFileGuid = {0x7C04A583, 0x9E3E, 0x4f1c, {0xAD, 0x65, 0xE0, 0x52, 0x68, 0xD0, 0xB4, 0xD1 }};
     19 
     20 /**
     21   Return the index of the load option in the load option array.
     22 
     23   The function consider two load options are equal when the
     24   OptionType, Attributes, Description, FilePath and OptionalData are equal.
     25 
     26   @param Key    Pointer to the load option to be found.
     27   @param Array  Pointer to the array of load options to be found.
     28   @param Count  Number of entries in the Array.
     29 
     30   @retval -1          Key wasn't found in the Array.
     31   @retval 0 ~ Count-1 The index of the Key in the Array.
     32 **/
     33 INTN
     34 PlatformFindLoadOption (
     35   IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Key,
     36   IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Array,
     37   IN UINTN                              Count
     38   )
     39 {
     40   UINTN                             Index;
     41 
     42   for (Index = 0; Index < Count; Index++) {
     43     if ((Key->OptionType == Array[Index].OptionType) &&
     44         (Key->Attributes == Array[Index].Attributes) &&
     45         (StrCmp (Key->Description, Array[Index].Description) == 0) &&
     46         (CompareMem (Key->FilePath, Array[Index].FilePath, GetDevicePathSize (Key->FilePath)) == 0) &&
     47         (Key->OptionalDataSize == Array[Index].OptionalDataSize) &&
     48         (CompareMem (Key->OptionalData, Array[Index].OptionalData, Key->OptionalDataSize) == 0)) {
     49       return (INTN) Index;
     50     }
     51   }
     52 
     53   return -1;
     54 }
     55 
     56 VOID
     57 PlatformRegisterFvBootOption (
     58   EFI_GUID  *FileGuid,
     59   CHAR16    *Description,
     60   UINT32    Attributes
     61   )
     62 {
     63   EFI_STATUS                        Status;
     64   EFI_HANDLE                        *HandleBuffer;
     65   UINTN                             HandleCount;
     66   UINTN                             IndexFv;
     67   EFI_FIRMWARE_VOLUME2_PROTOCOL     *Fv;
     68   CHAR16                            *UiSection;
     69   UINTN                             UiSectionLength;
     70   UINT32                            AuthenticationStatus;
     71   EFI_HANDLE                        FvHandle;
     72   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
     73   EFI_DEVICE_PATH_PROTOCOL          *DevicePath;
     74   EFI_BOOT_MANAGER_LOAD_OPTION      *BootOptions;
     75   UINTN                             BootOptionCount;
     76   UINTN                             OptionIndex;
     77   EFI_BOOT_MANAGER_LOAD_OPTION      NewOption;
     78 
     79   //
     80   // Locate all available FVs.
     81   //
     82   HandleBuffer = NULL;
     83   Status = gBS->LocateHandleBuffer (
     84                   ByProtocol,
     85                   &gEfiFirmwareVolume2ProtocolGuid,
     86                   NULL,
     87                   &HandleCount,
     88                   &HandleBuffer
     89                   );
     90   if (EFI_ERROR (Status)) {
     91     return;
     92   }
     93 
     94   //
     95   // Go through FVs one by one to find the required FFS file
     96   //
     97   for (IndexFv = 0, FvHandle = NULL; IndexFv < HandleCount && FvHandle == NULL; IndexFv++) {
     98     Status = gBS->HandleProtocol (
     99                     HandleBuffer[IndexFv],
    100                     &gEfiFirmwareVolume2ProtocolGuid,
    101                     (VOID **)&Fv
    102                     );
    103     if (EFI_ERROR (Status)) {
    104       continue;
    105     }
    106 
    107     //
    108     // Attempt to read a EFI_SECTION_USER_INTERFACE section from the required FFS file
    109     //
    110     UiSection = NULL;
    111     Status = Fv->ReadSection (
    112                    Fv,
    113                    FileGuid,
    114                    EFI_SECTION_USER_INTERFACE,
    115                    0,
    116                    (VOID **) &UiSection,
    117                    &UiSectionLength,
    118                    &AuthenticationStatus
    119                    );
    120     if (EFI_ERROR (Status)) {
    121       continue;
    122     }
    123     FreePool (UiSection);
    124 
    125     //
    126     // Save the handle of the FV where the FFS file was found
    127     //
    128     FvHandle = HandleBuffer[IndexFv];
    129   }
    130 
    131   //
    132   // Free the buffer of FV handles
    133   //
    134   FreePool (HandleBuffer);
    135 
    136   //
    137   // If the FFS file was not found, then return
    138   //
    139   if (FvHandle == NULL) {
    140     return;
    141   }
    142 
    143   //
    144   // Create a device path for the FFS file that was found
    145   //
    146   EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
    147   DevicePath = AppendDevicePathNode (
    148                  DevicePathFromHandle (FvHandle),
    149                  (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
    150                  );
    151 
    152   //
    153   // Create and add a new load option for the FFS file that was found
    154   //
    155   Status = EfiBootManagerInitializeLoadOption (
    156              &NewOption,
    157              LoadOptionNumberUnassigned,
    158              LoadOptionTypeBoot,
    159              Attributes,
    160              Description,
    161              DevicePath,
    162              NULL,
    163              0
    164              );
    165   if (!EFI_ERROR (Status)) {
    166     BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
    167 
    168     OptionIndex = PlatformFindLoadOption (&NewOption, BootOptions, BootOptionCount);
    169 
    170     if (OptionIndex == -1) {
    171       Status = EfiBootManagerAddLoadOptionVariable (&NewOption, (UINTN) -1);
    172       ASSERT_EFI_ERROR (Status);
    173     }
    174     EfiBootManagerFreeLoadOption (&NewOption);
    175     EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
    176   }
    177 }
    178 
    179 VOID
    180 EFIAPI
    181 InternalBdsEmptyCallbackFuntion (
    182   IN EFI_EVENT  Event,
    183   IN VOID       *Context
    184   )
    185 {
    186   return;
    187 }
    188 
    189 /**
    190   Do the platform specific action before the console is connected.
    191 
    192   Such as:
    193     Update console variable;
    194     Register new Driver#### or Boot####;
    195     Signal ReadyToLock event.
    196 **/
    197 VOID
    198 EFIAPI
    199 PlatformBootManagerBeforeConsole (
    200   VOID
    201   )
    202 {
    203   EFI_STATUS                    Status;
    204   UINTN                         Index;
    205   EFI_INPUT_KEY                 Enter;
    206   EFI_INPUT_KEY                 F2;
    207   EFI_BOOT_MANAGER_LOAD_OPTION  BootOption;
    208   ESRT_MANAGEMENT_PROTOCOL      *EsrtManagement;
    209   EFI_BOOT_MODE                 BootMode;
    210   EFI_ACPI_S3_SAVE_PROTOCOL     *AcpiS3Save;
    211   EFI_HANDLE                    Handle;
    212   EFI_EVENT                     EndOfDxeEvent;
    213 
    214   //
    215   // Update the console variables.
    216   //
    217   for (Index = 0; gPlatformConsole[Index].DevicePath != NULL; Index++) {
    218     if ((gPlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) {
    219       EfiBootManagerUpdateConsoleVariable (ConIn, gPlatformConsole[Index].DevicePath, NULL);
    220     }
    221 
    222     if ((gPlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) {
    223       EfiBootManagerUpdateConsoleVariable (ConOut, gPlatformConsole[Index].DevicePath, NULL);
    224     }
    225 
    226     if ((gPlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) {
    227       EfiBootManagerUpdateConsoleVariable (ErrOut, gPlatformConsole[Index].DevicePath, NULL);
    228     }
    229   }
    230 
    231   //
    232   // Register ENTER as CONTINUE key
    233   //
    234   Enter.ScanCode    = SCAN_NULL;
    235   Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
    236   EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
    237 
    238   //
    239   // Map F2 to Boot Manager Menu
    240   //
    241   F2.ScanCode    = SCAN_F2;
    242   F2.UnicodeChar = CHAR_NULL;
    243   EfiBootManagerGetBootManagerMenu (&BootOption);
    244   EfiBootManagerAddKeyOptionVariable (NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL);
    245 
    246   //
    247   // Register UEFI Shell
    248   //
    249   PlatformRegisterFvBootOption (&mUefiShellFileGuid, L"UEFI Shell", LOAD_OPTION_ACTIVE);
    250 
    251   Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtManagement);
    252   if (EFI_ERROR(Status)) {
    253     EsrtManagement = NULL;
    254   }
    255 
    256   BootMode = GetBootModeHob();
    257   switch (BootMode) {
    258   case BOOT_ON_FLASH_UPDATE:
    259     DEBUG((DEBUG_INFO, "ProcessCapsules Before EndOfDxe ......\n"));
    260     Status = ProcessCapsules ();
    261     DEBUG((DEBUG_INFO, "ProcessCapsules %r\n", Status));
    262     break;
    263   case BOOT_IN_RECOVERY_MODE:
    264     break;
    265   case BOOT_ASSUMING_NO_CONFIGURATION_CHANGES:
    266   case BOOT_WITH_MINIMAL_CONFIGURATION:
    267   case BOOT_ON_S4_RESUME:
    268     if (EsrtManagement != NULL) {
    269       //
    270       // Lock ESRT cache repository before EndofDxe if ESRT sync is not needed
    271       //
    272       EsrtManagement->LockEsrtRepository();
    273     }
    274     break;
    275   default:
    276     //
    277     // Require to sync ESRT from FMP in a new boot
    278     //
    279     if (EsrtManagement != NULL) {
    280       EsrtManagement->SyncEsrtFmp();
    281     }
    282     break;
    283   }
    284 
    285   //
    286   // Prepare for S3
    287   //
    288   Status = gBS->LocateProtocol (&gEfiAcpiS3SaveProtocolGuid, NULL, (VOID **)&AcpiS3Save);
    289   if (!EFI_ERROR (Status)) {
    290     AcpiS3Save->S3Save (AcpiS3Save, NULL);
    291   }
    292 
    293   //
    294   // Inform PI SMM drivers that BDS may run 3rd party code
    295   // Create and signal End of DXE event group
    296   //
    297   Status = gBS->CreateEventEx (
    298                   EVT_NOTIFY_SIGNAL,
    299                   TPL_CALLBACK,
    300                   InternalBdsEmptyCallbackFuntion,
    301                   NULL,
    302                   &gEfiEndOfDxeEventGroupGuid,
    303                   &EndOfDxeEvent
    304                   );
    305   ASSERT_EFI_ERROR (Status);
    306   gBS->SignalEvent (EndOfDxeEvent);
    307   gBS->CloseEvent (EndOfDxeEvent);
    308 
    309   DEBUG((EFI_D_INFO,"All EndOfDxe callbacks have returned successfully\n"));
    310 
    311   //
    312   // Install SMM Ready To Lock protocol so all resources can be locked down
    313   // before BDS runs 3rd party code.  This action must be done last so all
    314   // other SMM driver signals are processed before this final lock down action.
    315   //
    316   Handle = NULL;
    317   Status = gBS->InstallProtocolInterface (
    318                   &Handle,
    319                   &gEfiDxeSmmReadyToLockProtocolGuid,
    320                   EFI_NATIVE_INTERFACE,
    321                   NULL
    322                   );
    323   ASSERT_EFI_ERROR (Status);
    324 
    325   //
    326   // Dispatch deferred images after EndOfDxe event and ReadyToLock installation.
    327   //
    328   EfiBootManagerDispatchDeferredImages ();
    329 }
    330 
    331 /**
    332   Do the platform specific action after the console is connected.
    333 
    334   Such as:
    335     Dynamically switch output mode;
    336     Signal console ready platform customized event;
    337     Run diagnostics like memory testing;
    338     Connect certain devices;
    339     Dispatch additional option ROMs
    340 **/
    341 VOID
    342 EFIAPI
    343 PlatformBootManagerAfterConsole (
    344   VOID
    345   )
    346 {
    347   EFI_STATUS                     Status;
    348   EFI_BOOT_MODE                  BootMode;
    349   ESRT_MANAGEMENT_PROTOCOL       *EsrtManagement;
    350   VOID                           *Buffer;
    351   UINTN                          Size;
    352 
    353   Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtManagement);
    354   if (EFI_ERROR(Status)) {
    355     EsrtManagement = NULL;
    356   }
    357 
    358   BootMode = GetBootModeHob();
    359   switch (BootMode) {
    360   case BOOT_ON_FLASH_UPDATE:
    361     DEBUG((DEBUG_INFO, "Capsule Mode detected\n"));
    362     if (FeaturePcdGet(PcdSupportUpdateCapsuleReset)) {
    363       EfiBootManagerConnectAll ();
    364       EfiBootManagerRefreshAllBootOption ();
    365 
    366       //
    367       // Always sync ESRT Cache from FMP Instances after connect all and before capsule process
    368       //
    369       if (EsrtManagement != NULL) {
    370         EsrtManagement->SyncEsrtFmp();
    371       }
    372 
    373       DEBUG((DEBUG_INFO, "ProcessCapsules After ConnectAll ......\n"));
    374       Status = ProcessCapsules();
    375       DEBUG((DEBUG_INFO, "ProcessCapsules %r\n", Status));
    376     }
    377     break;
    378 
    379   case BOOT_IN_RECOVERY_MODE:
    380     DEBUG((DEBUG_INFO, "Recovery Mode detected\n"));
    381     // Passthrough
    382 
    383   case BOOT_ASSUMING_NO_CONFIGURATION_CHANGES:
    384   case BOOT_WITH_MINIMAL_CONFIGURATION:
    385   case BOOT_WITH_FULL_CONFIGURATION:
    386   case BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS:
    387   case BOOT_WITH_DEFAULT_SETTINGS:
    388   default:
    389     EfiBootManagerConnectAll ();
    390     EfiBootManagerRefreshAllBootOption ();
    391 
    392     //
    393     // Sync ESRT Cache from FMP Instance on demand after Connect All
    394     //
    395     if ((BootMode != BOOT_ASSUMING_NO_CONFIGURATION_CHANGES) &&
    396         (BootMode != BOOT_WITH_MINIMAL_CONFIGURATION) &&
    397         (BootMode != BOOT_ON_S4_RESUME)) {
    398       if (EsrtManagement != NULL) {
    399         EsrtManagement->SyncEsrtFmp();
    400       }
    401     }
    402 
    403     break;
    404   }
    405 
    406   Print (
    407     L"\n"
    408     L"F2      to enter Boot Manager Menu.\n"
    409     L"ENTER   to boot directly.\n"
    410     L"\n"
    411     );
    412 
    413   //
    414   // Check if the platform is using test key.
    415   //
    416   Status = GetSectionFromAnyFv(
    417              PcdGetPtr(PcdEdkiiRsa2048Sha256TestPublicKeyFileGuid),
    418              EFI_SECTION_RAW,
    419              0,
    420              &Buffer,
    421              &Size
    422              );
    423   if (!EFI_ERROR(Status)) {
    424     if ((Size == PcdGetSize(PcdRsa2048Sha256PublicKeyBuffer)) &&
    425         (CompareMem(Buffer, PcdGetPtr(PcdRsa2048Sha256PublicKeyBuffer), Size) == 0)) {
    426       Print(L"WARNING: Recovery Test Key is used.\n");
    427       PcdSetBoolS(PcdTestKeyUsed, TRUE);
    428     }
    429     FreePool(Buffer);
    430   }
    431   Status = GetSectionFromAnyFv(
    432              PcdGetPtr(PcdEdkiiPkcs7TestPublicKeyFileGuid),
    433              EFI_SECTION_RAW,
    434              0,
    435              &Buffer,
    436              &Size
    437              );
    438   if (!EFI_ERROR(Status)) {
    439     if ((Size == PcdGetSize(PcdPkcs7CertBuffer)) &&
    440         (CompareMem(Buffer, PcdGetPtr(PcdPkcs7CertBuffer), Size) == 0)) {
    441       Print(L"WARNING: Capsule Test Key is used.\n");
    442       PcdSetBoolS(PcdTestKeyUsed, TRUE);
    443     }
    444     FreePool(Buffer);
    445   }
    446 
    447   //
    448   // Use a DynamicHii type pcd to save the boot status, which is used to
    449   // control configuration mode, such as FULL/MINIMAL/NO_CHANGES configuration.
    450   //
    451   if (PcdGetBool(PcdBootState)) {
    452     Status = PcdSetBoolS (PcdBootState, FALSE);
    453     ASSERT_EFI_ERROR (Status);
    454   }
    455 }
    456 
    457 /**
    458   This function is called each second during the boot manager waits the timeout.
    459 
    460   @param TimeoutRemain  The remaining timeout.
    461 **/
    462 VOID
    463 EFIAPI
    464 PlatformBootManagerWaitCallback (
    465   UINT16  TimeoutRemain
    466   )
    467 {
    468   Print (L"\r%-2d seconds remained...", TimeoutRemain);
    469 }
    470