PlatformBootManager.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. /** @file
  2. This file include all platform action which can be customized
  3. by IBV/OEM.
  4. Copyright (c) 2015 - 2019, 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_HANDLE Handle;
  180. EFI_EVENT EndOfDxeEvent;
  181. //
  182. // Update the console variables.
  183. //
  184. for (Index = 0; gPlatformConsole[Index].DevicePath != NULL; Index++) {
  185. if ((gPlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) {
  186. EfiBootManagerUpdateConsoleVariable (ConIn, gPlatformConsole[Index].DevicePath, NULL);
  187. }
  188. if ((gPlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) {
  189. EfiBootManagerUpdateConsoleVariable (ConOut, gPlatformConsole[Index].DevicePath, NULL);
  190. }
  191. if ((gPlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) {
  192. EfiBootManagerUpdateConsoleVariable (ErrOut, gPlatformConsole[Index].DevicePath, NULL);
  193. }
  194. }
  195. //
  196. // Register ENTER as CONTINUE key
  197. //
  198. Enter.ScanCode = SCAN_NULL;
  199. Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
  200. EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
  201. //
  202. // Map F2 to Boot Manager Menu
  203. //
  204. F2.ScanCode = SCAN_F2;
  205. F2.UnicodeChar = CHAR_NULL;
  206. EfiBootManagerGetBootManagerMenu (&BootOption);
  207. EfiBootManagerAddKeyOptionVariable (NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL);
  208. //
  209. // Register UEFI Shell
  210. //
  211. PlatformRegisterFvBootOption (&gUefiShellFileGuid, L"UEFI Shell", LOAD_OPTION_ACTIVE);
  212. Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtManagement);
  213. if (EFI_ERROR(Status)) {
  214. EsrtManagement = NULL;
  215. }
  216. BootMode = GetBootModeHob();
  217. switch (BootMode) {
  218. case BOOT_ON_FLASH_UPDATE:
  219. DEBUG((DEBUG_INFO, "ProcessCapsules Before EndOfDxe ......\n"));
  220. Status = ProcessCapsules ();
  221. DEBUG((DEBUG_INFO, "ProcessCapsules %r\n", Status));
  222. break;
  223. case BOOT_IN_RECOVERY_MODE:
  224. break;
  225. case BOOT_ASSUMING_NO_CONFIGURATION_CHANGES:
  226. case BOOT_WITH_MINIMAL_CONFIGURATION:
  227. case BOOT_ON_S4_RESUME:
  228. if (EsrtManagement != NULL) {
  229. //
  230. // Lock ESRT cache repository before EndofDxe if ESRT sync is not needed
  231. //
  232. EsrtManagement->LockEsrtRepository();
  233. }
  234. break;
  235. default:
  236. //
  237. // Require to sync ESRT from FMP in a new boot
  238. //
  239. if (EsrtManagement != NULL) {
  240. EsrtManagement->SyncEsrtFmp();
  241. }
  242. break;
  243. }
  244. //
  245. // Inform PI SMM drivers that BDS may run 3rd party code
  246. // Create and signal End of DXE event group
  247. //
  248. Status = gBS->CreateEventEx (
  249. EVT_NOTIFY_SIGNAL,
  250. TPL_CALLBACK,
  251. InternalBdsEmptyCallbackFuntion,
  252. NULL,
  253. &gEfiEndOfDxeEventGroupGuid,
  254. &EndOfDxeEvent
  255. );
  256. ASSERT_EFI_ERROR (Status);
  257. gBS->SignalEvent (EndOfDxeEvent);
  258. gBS->CloseEvent (EndOfDxeEvent);
  259. DEBUG((EFI_D_INFO,"All EndOfDxe callbacks have returned successfully\n"));
  260. //
  261. // Install SMM Ready To Lock protocol so all resources can be locked down
  262. // before BDS runs 3rd party code. This action must be done last so all
  263. // other SMM driver signals are processed before this final lock down action.
  264. //
  265. Handle = NULL;
  266. Status = gBS->InstallProtocolInterface (
  267. &Handle,
  268. &gEfiDxeSmmReadyToLockProtocolGuid,
  269. EFI_NATIVE_INTERFACE,
  270. NULL
  271. );
  272. ASSERT_EFI_ERROR (Status);
  273. //
  274. // Dispatch deferred images after EndOfDxe event and ReadyToLock installation.
  275. //
  276. EfiBootManagerDispatchDeferredImages ();
  277. }
  278. /**
  279. Do the platform specific action after the console is connected.
  280. Such as:
  281. Dynamically switch output mode;
  282. Signal console ready platform customized event;
  283. Run diagnostics like memory testing;
  284. Connect certain devices;
  285. Dispatch additional option ROMs
  286. **/
  287. VOID
  288. EFIAPI
  289. PlatformBootManagerAfterConsole (
  290. VOID
  291. )
  292. {
  293. EFI_STATUS Status;
  294. EFI_BOOT_MODE BootMode;
  295. ESRT_MANAGEMENT_PROTOCOL *EsrtManagement;
  296. VOID *Buffer;
  297. UINTN Size;
  298. Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtManagement);
  299. if (EFI_ERROR(Status)) {
  300. EsrtManagement = NULL;
  301. }
  302. BootMode = GetBootModeHob();
  303. DEBUG((DEBUG_INFO, "PlatformBootManagerAfterConsole(): BootMode = %02x\n", BootMode));
  304. switch (BootMode) {
  305. case BOOT_ASSUMING_NO_CONFIGURATION_CHANGES:
  306. case BOOT_WITH_MINIMAL_CONFIGURATION:
  307. case BOOT_ON_S4_RESUME:
  308. EfiBootManagerRefreshAllBootOption ();
  309. break;
  310. case BOOT_ON_FLASH_UPDATE:
  311. if (FeaturePcdGet(PcdSupportUpdateCapsuleReset)) {
  312. EfiBootManagerConnectAll ();
  313. EfiBootManagerRefreshAllBootOption ();
  314. //
  315. // Always sync ESRT Cache from FMP Instances after connect all and before capsule process
  316. //
  317. if (EsrtManagement != NULL) {
  318. EsrtManagement->SyncEsrtFmp();
  319. }
  320. DEBUG((DEBUG_INFO, "ProcessCapsules After ConnectAll ......\n"));
  321. Status = ProcessCapsules();
  322. DEBUG((DEBUG_INFO, "ProcessCapsules %r\n", Status));
  323. }
  324. break;
  325. default:
  326. EfiBootManagerConnectAll ();
  327. EfiBootManagerRefreshAllBootOption ();
  328. //
  329. // Sync ESRT Cache from FMP Instance on demand after Connect All
  330. //
  331. if (EsrtManagement != NULL) {
  332. EsrtManagement->SyncEsrtFmp();
  333. }
  334. break;
  335. }
  336. Print (
  337. L"\n"
  338. L"F2 to enter Boot Manager Menu.\n"
  339. L"ENTER to boot directly.\n"
  340. L"\n"
  341. );
  342. //
  343. // Check if the platform is using test key.
  344. //
  345. Status = GetSectionFromAnyFv(
  346. PcdGetPtr(PcdEdkiiRsa2048Sha256TestPublicKeyFileGuid),
  347. EFI_SECTION_RAW,
  348. 0,
  349. &Buffer,
  350. &Size
  351. );
  352. if (!EFI_ERROR(Status)) {
  353. if ((Size == PcdGetSize(PcdRsa2048Sha256PublicKeyBuffer)) &&
  354. (CompareMem(Buffer, PcdGetPtr(PcdRsa2048Sha256PublicKeyBuffer), Size) == 0)) {
  355. Print(L"WARNING: Recovery Test Key is used.\n");
  356. PcdSetBoolS(PcdTestKeyUsed, TRUE);
  357. }
  358. FreePool(Buffer);
  359. }
  360. Status = GetSectionFromAnyFv(
  361. PcdGetPtr(PcdEdkiiPkcs7TestPublicKeyFileGuid),
  362. EFI_SECTION_RAW,
  363. 0,
  364. &Buffer,
  365. &Size
  366. );
  367. if (!EFI_ERROR(Status)) {
  368. if ((Size == PcdGetSize(PcdPkcs7CertBuffer)) &&
  369. (CompareMem(Buffer, PcdGetPtr(PcdPkcs7CertBuffer), Size) == 0)) {
  370. Print(L"WARNING: Capsule Test Key is used.\n");
  371. PcdSetBoolS(PcdTestKeyUsed, TRUE);
  372. }
  373. FreePool(Buffer);
  374. }
  375. //
  376. // Use a DynamicHii type pcd to save the boot status, which is used to
  377. // control configuration mode, such as FULL/MINIMAL/NO_CHANGES configuration.
  378. //
  379. if (PcdGetBool(PcdBootState)) {
  380. Status = PcdSetBoolS (PcdBootState, FALSE);
  381. ASSERT_EFI_ERROR (Status);
  382. }
  383. }
  384. /**
  385. This function is called each second during the boot manager waits the timeout.
  386. @param TimeoutRemain The remaining timeout.
  387. **/
  388. VOID
  389. EFIAPI
  390. PlatformBootManagerWaitCallback (
  391. UINT16 TimeoutRemain
  392. )
  393. {
  394. Print (L"\r%-2d seconds remained...", TimeoutRemain);
  395. }
  396. /**
  397. The function is called when no boot option could be launched,
  398. including platform recovery options and options pointing to applications
  399. built into firmware volumes.
  400. If this function returns, BDS attempts to enter an infinite loop.
  401. **/
  402. VOID
  403. EFIAPI
  404. PlatformBootManagerUnableToBoot (
  405. VOID
  406. )
  407. {
  408. return;
  409. }