]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - UefiPayloadPkg/Library/PlatformBootManagerLib/PlatformBootManager.c
UefiPayloadPkg: Add a Macro to enable Boot Logo
[mirror_edk2.git] / UefiPayloadPkg / Library / PlatformBootManagerLib / PlatformBootManager.c
... / ...
CommitLineData
1/** @file\r
2 This file include all platform action which can be customized\r
3 by IBV/OEM.\r
4\r
5Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>\r
6SPDX-License-Identifier: BSD-2-Clause-Patent\r
7\r
8**/\r
9\r
10#include "PlatformBootManager.h"\r
11#include "PlatformConsole.h"\r
12#include <Protocol/PlatformBootManagerOverride.h>\r
13#include <Guid/BootManagerMenu.h>\r
14#include <Library/HobLib.h>\r
15\r
16UNIVERSAL_PAYLOAD_PLATFORM_BOOT_MANAGER_OVERRIDE_PROTOCOL *mUniversalPayloadPlatformBootManagerOverrideInstance = NULL;\r
17\r
18/**\r
19 Signal EndOfDxe event and install SMM Ready to lock protocol.\r
20\r
21**/\r
22VOID\r
23InstallReadyToLock (\r
24 VOID\r
25 )\r
26{\r
27 EFI_STATUS Status;\r
28 EFI_HANDLE Handle;\r
29 EFI_SMM_ACCESS2_PROTOCOL *SmmAccess;\r
30\r
31 DEBUG ((DEBUG_INFO, "InstallReadyToLock entering......\n"));\r
32 //\r
33 // Inform the SMM infrastructure that we're entering BDS and may run 3rd party code hereafter\r
34 // Since PI1.2.1, we need signal EndOfDxe as ExitPmAuth\r
35 //\r
36 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);\r
37 DEBUG ((DEBUG_INFO, "All EndOfDxe callbacks have returned successfully\n"));\r
38\r
39 //\r
40 // Install DxeSmmReadyToLock protocol in order to lock SMM\r
41 //\r
42 Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&SmmAccess);\r
43 if (!EFI_ERROR (Status)) {\r
44 Handle = NULL;\r
45 Status = gBS->InstallProtocolInterface (\r
46 &Handle,\r
47 &gEfiDxeSmmReadyToLockProtocolGuid,\r
48 EFI_NATIVE_INTERFACE,\r
49 NULL\r
50 );\r
51 ASSERT_EFI_ERROR (Status);\r
52 }\r
53\r
54 DEBUG ((DEBUG_INFO, "InstallReadyToLock end\n"));\r
55 return;\r
56}\r
57\r
58/**\r
59 Return the index of the load option in the load option array.\r
60\r
61 The function consider two load options are equal when the\r
62 OptionType, Attributes, Description, FilePath and OptionalData are equal.\r
63\r
64 @param Key Pointer to the load option to be found.\r
65 @param Array Pointer to the array of load options to be found.\r
66 @param Count Number of entries in the Array.\r
67\r
68 @retval -1 Key wasn't found in the Array.\r
69 @retval 0 ~ Count-1 The index of the Key in the Array.\r
70**/\r
71INTN\r
72PlatformFindLoadOption (\r
73 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Key,\r
74 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Array,\r
75 IN UINTN Count\r
76 )\r
77{\r
78 UINTN Index;\r
79\r
80 for (Index = 0; Index < Count; Index++) {\r
81 if ((Key->OptionType == Array[Index].OptionType) &&\r
82 (Key->Attributes == Array[Index].Attributes) &&\r
83 (StrCmp (Key->Description, Array[Index].Description) == 0) &&\r
84 (CompareMem (Key->FilePath, Array[Index].FilePath, GetDevicePathSize (Key->FilePath)) == 0) &&\r
85 (Key->OptionalDataSize == Array[Index].OptionalDataSize) &&\r
86 (CompareMem (Key->OptionalData, Array[Index].OptionalData, Key->OptionalDataSize) == 0))\r
87 {\r
88 return (INTN)Index;\r
89 }\r
90 }\r
91\r
92 return -1;\r
93}\r
94\r
95/**\r
96 Register a boot option using a file GUID in the FV.\r
97\r
98 @param FileGuid The file GUID name in FV.\r
99 @param Description The boot option description.\r
100 @param Attributes The attributes used for the boot option loading.\r
101**/\r
102VOID\r
103PlatformRegisterFvBootOption (\r
104 EFI_GUID *FileGuid,\r
105 CHAR16 *Description,\r
106 UINT32 Attributes\r
107 )\r
108{\r
109 EFI_STATUS Status;\r
110 UINTN OptionIndex;\r
111 EFI_BOOT_MANAGER_LOAD_OPTION NewOption;\r
112 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
113 UINTN BootOptionCount;\r
114 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;\r
115 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
116 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
117\r
118 Status = gBS->HandleProtocol (gImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&LoadedImage);\r
119 ASSERT_EFI_ERROR (Status);\r
120\r
121 EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);\r
122 DevicePath = AppendDevicePathNode (\r
123 DevicePathFromHandle (LoadedImage->DeviceHandle),\r
124 (EFI_DEVICE_PATH_PROTOCOL *)&FileNode\r
125 );\r
126\r
127 Status = EfiBootManagerInitializeLoadOption (\r
128 &NewOption,\r
129 LoadOptionNumberUnassigned,\r
130 LoadOptionTypeBoot,\r
131 Attributes,\r
132 Description,\r
133 DevicePath,\r
134 NULL,\r
135 0\r
136 );\r
137 if (!EFI_ERROR (Status)) {\r
138 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
139\r
140 OptionIndex = PlatformFindLoadOption (&NewOption, BootOptions, BootOptionCount);\r
141\r
142 if (OptionIndex == -1) {\r
143 Status = EfiBootManagerAddLoadOptionVariable (&NewOption, (UINTN)-1);\r
144 ASSERT_EFI_ERROR (Status);\r
145 }\r
146\r
147 EfiBootManagerFreeLoadOption (&NewOption);\r
148 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
149 }\r
150}\r
151\r
152/**\r
153 Do the platform specific action before the console is connected.\r
154\r
155 Such as:\r
156 Update console variable;\r
157 Register new Driver#### or Boot####;\r
158 Signal ReadyToLock event.\r
159**/\r
160VOID\r
161EFIAPI\r
162PlatformBootManagerBeforeConsole (\r
163 VOID\r
164 )\r
165{\r
166 EFI_INPUT_KEY Enter;\r
167 EFI_INPUT_KEY CustomKey;\r
168 EFI_INPUT_KEY Down;\r
169 EFI_BOOT_MANAGER_LOAD_OPTION BootOption;\r
170 EFI_STATUS Status;\r
171\r
172 Status = gBS->LocateProtocol (&gUniversalPayloadPlatformBootManagerOverrideProtocolGuid, NULL, (VOID **)&mUniversalPayloadPlatformBootManagerOverrideInstance);\r
173 if (EFI_ERROR (Status)) {\r
174 mUniversalPayloadPlatformBootManagerOverrideInstance = NULL;\r
175 }\r
176\r
177 if (mUniversalPayloadPlatformBootManagerOverrideInstance != NULL) {\r
178 mUniversalPayloadPlatformBootManagerOverrideInstance->BeforeConsole ();\r
179 return;\r
180 }\r
181\r
182 //\r
183 // Register ENTER as CONTINUE key\r
184 //\r
185 Enter.ScanCode = SCAN_NULL;\r
186 Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;\r
187 EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);\r
188\r
189 if (FixedPcdGetBool (PcdBootManagerEscape)) {\r
190 //\r
191 // Map Esc to Boot Manager Menu\r
192 //\r
193 CustomKey.ScanCode = SCAN_ESC;\r
194 CustomKey.UnicodeChar = CHAR_NULL;\r
195 } else {\r
196 //\r
197 // Map Esc to Boot Manager Menu\r
198 //\r
199 CustomKey.ScanCode = SCAN_F2;\r
200 CustomKey.UnicodeChar = CHAR_NULL;\r
201 }\r
202\r
203 EfiBootManagerGetBootManagerMenu (&BootOption);\r
204 EfiBootManagerAddKeyOptionVariable (NULL, (UINT16)BootOption.OptionNumber, 0, &CustomKey, NULL);\r
205\r
206 //\r
207 // Also add Down key to Boot Manager Menu since some serial terminals don't support F2 key.\r
208 //\r
209 Down.ScanCode = SCAN_DOWN;\r
210 Down.UnicodeChar = CHAR_NULL;\r
211 EfiBootManagerGetBootManagerMenu (&BootOption);\r
212 EfiBootManagerAddKeyOptionVariable (NULL, (UINT16)BootOption.OptionNumber, 0, &Down, NULL);\r
213\r
214 //\r
215 // Install ready to lock.\r
216 // This needs to be done before option rom dispatched.\r
217 //\r
218 InstallReadyToLock ();\r
219\r
220 //\r
221 // Dispatch deferred images after EndOfDxe event and ReadyToLock installation.\r
222 //\r
223 EfiBootManagerDispatchDeferredImages ();\r
224\r
225 PlatformConsoleInit ();\r
226}\r
227\r
228/**\r
229 Do the platform specific action after the console is connected.\r
230\r
231 Such as:\r
232 Dynamically switch output mode;\r
233 Signal console ready platform customized event;\r
234 Run diagnostics like memory testing;\r
235 Connect certain devices;\r
236 Dispatch additional option roms.\r
237**/\r
238VOID\r
239EFIAPI\r
240PlatformBootManagerAfterConsole (\r
241 VOID\r
242 )\r
243{\r
244 EFI_GRAPHICS_OUTPUT_BLT_PIXEL Black;\r
245 EFI_GRAPHICS_OUTPUT_BLT_PIXEL White;\r
246 EDKII_PLATFORM_LOGO_PROTOCOL *PlatformLogo;\r
247 EFI_STATUS Status;\r
248\r
249 if (mUniversalPayloadPlatformBootManagerOverrideInstance != NULL) {\r
250 mUniversalPayloadPlatformBootManagerOverrideInstance->AfterConsole ();\r
251 return;\r
252 }\r
253\r
254 Black.Blue = Black.Green = Black.Red = Black.Reserved = 0;\r
255 White.Blue = White.Green = White.Red = White.Reserved = 0xFF;\r
256\r
257 Status = gBS->LocateProtocol (&gEdkiiPlatformLogoProtocolGuid, NULL, (VOID **)&PlatformLogo);\r
258\r
259 if (!EFI_ERROR (Status)) {\r
260 gST->ConOut->ClearScreen (gST->ConOut);\r
261 BootLogoEnableLogo ();\r
262 }\r
263\r
264 EfiBootManagerConnectAll ();\r
265 EfiBootManagerRefreshAllBootOption ();\r
266\r
267 //\r
268 // Register UEFI Shell\r
269 //\r
270 PlatformRegisterFvBootOption (PcdGetPtr (PcdShellFile), L"UEFI Shell", LOAD_OPTION_ACTIVE);\r
271\r
272 if (FixedPcdGetBool (PcdBootManagerEscape)) {\r
273 Print (\r
274 L"\n"\r
275 L" Esc or Down to enter Boot Manager Menu.\n"\r
276 L" ENTER to boot directly.\n"\r
277 L"\n"\r
278 );\r
279 } else {\r
280 Print (\r
281 L"\n"\r
282 L" F2 or Down to enter Boot Manager Menu.\n"\r
283 L" ENTER to boot directly.\n"\r
284 L"\n"\r
285 );\r
286 }\r
287}\r
288\r
289/**\r
290 This function is called each second during the boot manager waits the timeout.\r
291\r
292 @param TimeoutRemain The remaining timeout.\r
293**/\r
294VOID\r
295EFIAPI\r
296PlatformBootManagerWaitCallback (\r
297 UINT16 TimeoutRemain\r
298 )\r
299{\r
300 if (mUniversalPayloadPlatformBootManagerOverrideInstance != NULL) {\r
301 mUniversalPayloadPlatformBootManagerOverrideInstance->WaitCallback (TimeoutRemain);\r
302 }\r
303\r
304 return;\r
305}\r
306\r
307/**\r
308 The function is called when no boot option could be launched,\r
309 including platform recovery options and options pointing to applications\r
310 built into firmware volumes.\r
311\r
312 If this function returns, BDS attempts to enter an infinite loop.\r
313**/\r
314VOID\r
315EFIAPI\r
316PlatformBootManagerUnableToBoot (\r
317 VOID\r
318 )\r
319{\r
320 if (mUniversalPayloadPlatformBootManagerOverrideInstance != NULL) {\r
321 mUniversalPayloadPlatformBootManagerOverrideInstance->UnableToBoot ();\r
322 }\r
323\r
324 return;\r
325}\r
326\r
327/**\r
328 Get/update PcdBootManagerMenuFile from GUID HOB which will be assigned in bootloader.\r
329\r
330 @param ImageHandle The firmware allocated handle for the EFI image.\r
331 @param SystemTable A pointer to the EFI System Table.\r
332\r
333 @retval EFI_SUCCESS The entry point is executed successfully.\r
334 @retval other Some error occurs.\r
335\r
336**/\r
337EFI_STATUS\r
338EFIAPI\r
339PlatformBootManagerLibConstructor (\r
340 IN EFI_HANDLE ImageHandle,\r
341 IN EFI_SYSTEM_TABLE *SystemTable\r
342 )\r
343{\r
344 EFI_STATUS Status;\r
345 UINTN Size;\r
346 VOID *GuidHob;\r
347 UNIVERSAL_PAYLOAD_GENERIC_HEADER *GenericHeader;\r
348 UNIVERSAL_PAYLOAD_BOOT_MANAGER_MENU *BootManagerMenuFile;\r
349\r
350 GuidHob = GetFirstGuidHob (&gEdkiiBootManagerMenuFileGuid);\r
351\r
352 if (GuidHob == NULL) {\r
353 //\r
354 // If the HOB is not create, the default value of PcdBootManagerMenuFile will be used.\r
355 //\r
356 return EFI_SUCCESS;\r
357 }\r
358\r
359 GenericHeader = (UNIVERSAL_PAYLOAD_GENERIC_HEADER *)GET_GUID_HOB_DATA (GuidHob);\r
360 if ((sizeof (UNIVERSAL_PAYLOAD_GENERIC_HEADER) > GET_GUID_HOB_DATA_SIZE (GuidHob)) || (GenericHeader->Length > GET_GUID_HOB_DATA_SIZE (GuidHob))) {\r
361 return EFI_NOT_FOUND;\r
362 }\r
363\r
364 if (GenericHeader->Revision == UNIVERSAL_PAYLOAD_BOOT_MANAGER_MENU_REVISION) {\r
365 BootManagerMenuFile = (UNIVERSAL_PAYLOAD_BOOT_MANAGER_MENU *)GET_GUID_HOB_DATA (GuidHob);\r
366 if (BootManagerMenuFile->Header.Length < UNIVERSAL_PAYLOAD_SIZEOF_THROUGH_FIELD (UNIVERSAL_PAYLOAD_BOOT_MANAGER_MENU, FileName)) {\r
367 return EFI_NOT_FOUND;\r
368 }\r
369\r
370 Size = sizeof (BootManagerMenuFile->FileName);\r
371 Status = PcdSetPtrS (PcdBootManagerMenuFile, &Size, &BootManagerMenuFile->FileName);\r
372 ASSERT_EFI_ERROR (Status);\r
373 } else {\r
374 return EFI_NOT_FOUND;\r
375 }\r
376\r
377 return EFI_SUCCESS;\r
378}\r