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