]> git.proxmox.com Git - mirror_edk2.git/blob - QuarkPlatformPkg/Library/PlatformBootManagerLib/PlatformBootManager.c
QuarkPlatformPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / QuarkPlatformPkg / 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 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "PlatformBootManager.h"
11
12 /**
13 Return the index of the load option in the load option array.
14
15 The function consider two load options are equal when the
16 OptionType, Attributes, Description, FilePath and OptionalData are equal.
17
18 @param Key Pointer to the load option to be found.
19 @param Array Pointer to the array of load options to be found.
20 @param Count Number of entries in the Array.
21
22 @retval -1 Key wasn't found in the Array.
23 @retval 0 ~ Count-1 The index of the Key in the Array.
24 **/
25 INTN
26 PlatformFindLoadOption (
27 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Key,
28 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Array,
29 IN UINTN Count
30 )
31 {
32 UINTN Index;
33
34 for (Index = 0; Index < Count; Index++) {
35 if ((Key->OptionType == Array[Index].OptionType) &&
36 (Key->Attributes == Array[Index].Attributes) &&
37 (StrCmp (Key->Description, Array[Index].Description) == 0) &&
38 (CompareMem (Key->FilePath, Array[Index].FilePath, GetDevicePathSize (Key->FilePath)) == 0) &&
39 (Key->OptionalDataSize == Array[Index].OptionalDataSize) &&
40 (CompareMem (Key->OptionalData, Array[Index].OptionalData, Key->OptionalDataSize) == 0)) {
41 return (INTN) Index;
42 }
43 }
44
45 return -1;
46 }
47
48 VOID
49 PlatformRegisterFvBootOption (
50 EFI_GUID *FileGuid,
51 CHAR16 *Description,
52 UINT32 Attributes
53 )
54 {
55 EFI_STATUS Status;
56 EFI_HANDLE *HandleBuffer;
57 UINTN HandleCount;
58 UINTN IndexFv;
59 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
60 CHAR16 *UiSection;
61 UINTN UiSectionLength;
62 UINT32 AuthenticationStatus;
63 EFI_HANDLE FvHandle;
64 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
65 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
66 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
67 UINTN BootOptionCount;
68 UINTN OptionIndex;
69 EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
70
71 //
72 // Locate all available FVs.
73 //
74 HandleBuffer = NULL;
75 Status = gBS->LocateHandleBuffer (
76 ByProtocol,
77 &gEfiFirmwareVolume2ProtocolGuid,
78 NULL,
79 &HandleCount,
80 &HandleBuffer
81 );
82 if (EFI_ERROR (Status)) {
83 return;
84 }
85
86 //
87 // Go through FVs one by one to find the required FFS file
88 //
89 for (IndexFv = 0, FvHandle = NULL; IndexFv < HandleCount && FvHandle == NULL; IndexFv++) {
90 Status = gBS->HandleProtocol (
91 HandleBuffer[IndexFv],
92 &gEfiFirmwareVolume2ProtocolGuid,
93 (VOID **)&Fv
94 );
95 if (EFI_ERROR (Status)) {
96 continue;
97 }
98
99 //
100 // Attempt to read a EFI_SECTION_USER_INTERFACE section from the required FFS file
101 //
102 UiSection = NULL;
103 Status = Fv->ReadSection (
104 Fv,
105 FileGuid,
106 EFI_SECTION_USER_INTERFACE,
107 0,
108 (VOID **) &UiSection,
109 &UiSectionLength,
110 &AuthenticationStatus
111 );
112 if (EFI_ERROR (Status)) {
113 continue;
114 }
115 FreePool (UiSection);
116
117 //
118 // Save the handle of the FV where the FFS file was found
119 //
120 FvHandle = HandleBuffer[IndexFv];
121 }
122
123 //
124 // Free the buffer of FV handles
125 //
126 FreePool (HandleBuffer);
127
128 //
129 // If the FFS file was not found, then return
130 //
131 if (FvHandle == NULL) {
132 return;
133 }
134
135 //
136 // Create a device path for the FFS file that was found
137 //
138 EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
139 DevicePath = AppendDevicePathNode (
140 DevicePathFromHandle (FvHandle),
141 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
142 );
143
144 //
145 // Create and add a new load option for the FFS file that was found
146 //
147 Status = EfiBootManagerInitializeLoadOption (
148 &NewOption,
149 LoadOptionNumberUnassigned,
150 LoadOptionTypeBoot,
151 Attributes,
152 Description,
153 DevicePath,
154 NULL,
155 0
156 );
157 if (!EFI_ERROR (Status)) {
158 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
159
160 OptionIndex = PlatformFindLoadOption (&NewOption, BootOptions, BootOptionCount);
161
162 if (OptionIndex == -1) {
163 Status = EfiBootManagerAddLoadOptionVariable (&NewOption, (UINTN) -1);
164 ASSERT_EFI_ERROR (Status);
165 }
166 EfiBootManagerFreeLoadOption (&NewOption);
167 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
168 }
169 }
170
171 VOID
172 EFIAPI
173 InternalBdsEmptyCallbackFuntion (
174 IN EFI_EVENT Event,
175 IN VOID *Context
176 )
177 {
178 return;
179 }
180
181 /**
182 Do the platform specific action before the console is connected.
183
184 Such as:
185 Update console variable;
186 Register new Driver#### or Boot####;
187 Signal ReadyToLock event.
188 **/
189 VOID
190 EFIAPI
191 PlatformBootManagerBeforeConsole (
192 VOID
193 )
194 {
195 EFI_STATUS Status;
196 UINTN Index;
197 EFI_INPUT_KEY Enter;
198 EFI_INPUT_KEY F2;
199 EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
200 ESRT_MANAGEMENT_PROTOCOL *EsrtManagement;
201 EFI_BOOT_MODE BootMode;
202 EFI_ACPI_S3_SAVE_PROTOCOL *AcpiS3Save;
203 EFI_HANDLE Handle;
204 EFI_EVENT EndOfDxeEvent;
205
206 //
207 // Update the console variables.
208 //
209 for (Index = 0; gPlatformConsole[Index].DevicePath != NULL; Index++) {
210 if ((gPlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) {
211 EfiBootManagerUpdateConsoleVariable (ConIn, gPlatformConsole[Index].DevicePath, NULL);
212 }
213
214 if ((gPlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) {
215 EfiBootManagerUpdateConsoleVariable (ConOut, gPlatformConsole[Index].DevicePath, NULL);
216 }
217
218 if ((gPlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) {
219 EfiBootManagerUpdateConsoleVariable (ErrOut, gPlatformConsole[Index].DevicePath, NULL);
220 }
221 }
222
223 //
224 // Register ENTER as CONTINUE key
225 //
226 Enter.ScanCode = SCAN_NULL;
227 Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
228 EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
229
230 //
231 // Map F2 to Boot Manager Menu
232 //
233 F2.ScanCode = SCAN_F2;
234 F2.UnicodeChar = CHAR_NULL;
235 EfiBootManagerGetBootManagerMenu (&BootOption);
236 EfiBootManagerAddKeyOptionVariable (NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL);
237
238 //
239 // Register UEFI Shell
240 //
241 PlatformRegisterFvBootOption (&gUefiShellFileGuid, L"UEFI Shell", LOAD_OPTION_ACTIVE);
242
243 Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtManagement);
244 if (EFI_ERROR(Status)) {
245 EsrtManagement = NULL;
246 }
247
248 BootMode = GetBootModeHob();
249 switch (BootMode) {
250 case BOOT_ON_FLASH_UPDATE:
251 DEBUG((DEBUG_INFO, "ProcessCapsules Before EndOfDxe ......\n"));
252 Status = ProcessCapsules ();
253 DEBUG((DEBUG_INFO, "ProcessCapsules %r\n", Status));
254 break;
255 case BOOT_IN_RECOVERY_MODE:
256 break;
257 case BOOT_ASSUMING_NO_CONFIGURATION_CHANGES:
258 case BOOT_WITH_MINIMAL_CONFIGURATION:
259 case BOOT_ON_S4_RESUME:
260 if (EsrtManagement != NULL) {
261 //
262 // Lock ESRT cache repository before EndofDxe if ESRT sync is not needed
263 //
264 EsrtManagement->LockEsrtRepository();
265 }
266 break;
267 default:
268 //
269 // Require to sync ESRT from FMP in a new boot
270 //
271 if (EsrtManagement != NULL) {
272 EsrtManagement->SyncEsrtFmp();
273 }
274 break;
275 }
276
277 //
278 // Prepare for S3
279 //
280 Status = gBS->LocateProtocol (&gEfiAcpiS3SaveProtocolGuid, NULL, (VOID **)&AcpiS3Save);
281 if (!EFI_ERROR (Status)) {
282 AcpiS3Save->S3Save (AcpiS3Save, NULL);
283 }
284
285 //
286 // Inform PI SMM drivers that BDS may run 3rd party code
287 // Create and signal End of DXE event group
288 //
289 Status = gBS->CreateEventEx (
290 EVT_NOTIFY_SIGNAL,
291 TPL_CALLBACK,
292 InternalBdsEmptyCallbackFuntion,
293 NULL,
294 &gEfiEndOfDxeEventGroupGuid,
295 &EndOfDxeEvent
296 );
297 ASSERT_EFI_ERROR (Status);
298 gBS->SignalEvent (EndOfDxeEvent);
299 gBS->CloseEvent (EndOfDxeEvent);
300
301 DEBUG((EFI_D_INFO,"All EndOfDxe callbacks have returned successfully\n"));
302
303 //
304 // Install SMM Ready To Lock protocol so all resources can be locked down
305 // before BDS runs 3rd party code. This action must be done last so all
306 // other SMM driver signals are processed before this final lock down action.
307 //
308 Handle = NULL;
309 Status = gBS->InstallProtocolInterface (
310 &Handle,
311 &gEfiDxeSmmReadyToLockProtocolGuid,
312 EFI_NATIVE_INTERFACE,
313 NULL
314 );
315 ASSERT_EFI_ERROR (Status);
316
317 //
318 // Dispatch deferred images after EndOfDxe event and ReadyToLock installation.
319 //
320 EfiBootManagerDispatchDeferredImages ();
321 }
322
323 /**
324 Do the platform specific action after the console is connected.
325
326 Such as:
327 Dynamically switch output mode;
328 Signal console ready platform customized event;
329 Run diagnostics like memory testing;
330 Connect certain devices;
331 Dispatch additional option ROMs
332 **/
333 VOID
334 EFIAPI
335 PlatformBootManagerAfterConsole (
336 VOID
337 )
338 {
339 EFI_STATUS Status;
340 EFI_BOOT_MODE BootMode;
341 ESRT_MANAGEMENT_PROTOCOL *EsrtManagement;
342 VOID *Buffer;
343 UINTN Size;
344
345 Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtManagement);
346 if (EFI_ERROR(Status)) {
347 EsrtManagement = NULL;
348 }
349
350 BootMode = GetBootModeHob();
351
352 DEBUG((DEBUG_INFO, "PlatformBootManagerAfterConsole(): BootMode = %02x\n", BootMode));
353
354 switch (BootMode) {
355 case BOOT_ASSUMING_NO_CONFIGURATION_CHANGES:
356 case BOOT_WITH_MINIMAL_CONFIGURATION:
357 case BOOT_ON_S4_RESUME:
358 EfiBootManagerRefreshAllBootOption ();
359 break;
360
361 case BOOT_ON_FLASH_UPDATE:
362 if (FeaturePcdGet(PcdSupportUpdateCapsuleReset)) {
363 EfiBootManagerConnectAll ();
364 EfiBootManagerRefreshAllBootOption ();
365
366 //
367 // Always sync ESRT Cache from FMP Instances after connect all and before capsule process
368 //
369 if (EsrtManagement != NULL) {
370 EsrtManagement->SyncEsrtFmp();
371 }
372
373 DEBUG((DEBUG_INFO, "ProcessCapsules After ConnectAll ......\n"));
374 Status = ProcessCapsules();
375 DEBUG((DEBUG_INFO, "ProcessCapsules %r\n", Status));
376 }
377 break;
378
379 default:
380 EfiBootManagerConnectAll ();
381 EfiBootManagerRefreshAllBootOption ();
382
383 //
384 // Sync ESRT Cache from FMP Instance on demand after Connect All
385 //
386 if (EsrtManagement != NULL) {
387 EsrtManagement->SyncEsrtFmp();
388 }
389 break;
390 }
391
392 Print (
393 L"\n"
394 L"F2 to enter Boot Manager Menu.\n"
395 L"ENTER to boot directly.\n"
396 L"\n"
397 );
398
399 //
400 // Check if the platform is using test key.
401 //
402 Status = GetSectionFromAnyFv(
403 PcdGetPtr(PcdEdkiiRsa2048Sha256TestPublicKeyFileGuid),
404 EFI_SECTION_RAW,
405 0,
406 &Buffer,
407 &Size
408 );
409 if (!EFI_ERROR(Status)) {
410 if ((Size == PcdGetSize(PcdRsa2048Sha256PublicKeyBuffer)) &&
411 (CompareMem(Buffer, PcdGetPtr(PcdRsa2048Sha256PublicKeyBuffer), Size) == 0)) {
412 Print(L"WARNING: Recovery Test Key is used.\n");
413 PcdSetBoolS(PcdTestKeyUsed, TRUE);
414 }
415 FreePool(Buffer);
416 }
417 Status = GetSectionFromAnyFv(
418 PcdGetPtr(PcdEdkiiPkcs7TestPublicKeyFileGuid),
419 EFI_SECTION_RAW,
420 0,
421 &Buffer,
422 &Size
423 );
424 if (!EFI_ERROR(Status)) {
425 if ((Size == PcdGetSize(PcdPkcs7CertBuffer)) &&
426 (CompareMem(Buffer, PcdGetPtr(PcdPkcs7CertBuffer), Size) == 0)) {
427 Print(L"WARNING: Capsule Test Key is used.\n");
428 PcdSetBoolS(PcdTestKeyUsed, TRUE);
429 }
430 FreePool(Buffer);
431 }
432
433 //
434 // Use a DynamicHii type pcd to save the boot status, which is used to
435 // control configuration mode, such as FULL/MINIMAL/NO_CHANGES configuration.
436 //
437 if (PcdGetBool(PcdBootState)) {
438 Status = PcdSetBoolS (PcdBootState, FALSE);
439 ASSERT_EFI_ERROR (Status);
440 }
441 }
442
443 /**
444 This function is called each second during the boot manager waits the timeout.
445
446 @param TimeoutRemain The remaining timeout.
447 **/
448 VOID
449 EFIAPI
450 PlatformBootManagerWaitCallback (
451 UINT16 TimeoutRemain
452 )
453 {
454 Print (L"\r%-2d seconds remained...", TimeoutRemain);
455 }
456
457 /**
458 The function is called when no boot option could be launched,
459 including platform recovery options and options pointing to applications
460 built into firmware volumes.
461
462 If this function returns, BDS attempts to enter an infinite loop.
463 **/
464 VOID
465 EFIAPI
466 PlatformBootManagerUnableToBoot (
467 VOID
468 )
469 {
470 return;
471 }
472