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