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