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