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