PlatformBootManager.c 13 KB

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