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