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