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