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
PlatformFindLoadOption(IN CONST EFI_BOOT_MANAGER_LOAD_OPTION * Key,IN CONST EFI_BOOT_MANAGER_LOAD_OPTION * Array,IN UINTN Count)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
PlatformRegisterFvBootOption(EFI_GUID * FileGuid,CHAR16 * Description,UINT32 Attributes)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
InternalBdsEmptyCallbackFuntion(IN EFI_EVENT Event,IN VOID * Context)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
PlatformBootManagerBeforeConsole(VOID)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 // Dispatch deferred images after EndOfDxe event and ReadyToLock installation.
327 //
328 EfiBootManagerDispatchDeferredImages ();
329 }
330
331 /**
332 Do the platform specific action after the console is connected.
333
334 Such as:
335 Dynamically switch output mode;
336 Signal console ready platform customized event;
337 Run diagnostics like memory testing;
338 Connect certain devices;
339 Dispatch additional option ROMs
340 **/
341 VOID
342 EFIAPI
PlatformBootManagerAfterConsole(VOID)343 PlatformBootManagerAfterConsole (
344 VOID
345 )
346 {
347 EFI_STATUS Status;
348 EFI_BOOT_MODE BootMode;
349 ESRT_MANAGEMENT_PROTOCOL *EsrtManagement;
350 VOID *Buffer;
351 UINTN Size;
352
353 Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtManagement);
354 if (EFI_ERROR(Status)) {
355 EsrtManagement = NULL;
356 }
357
358 BootMode = GetBootModeHob();
359 switch (BootMode) {
360 case BOOT_ON_FLASH_UPDATE:
361 DEBUG((DEBUG_INFO, "Capsule Mode detected\n"));
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 case BOOT_IN_RECOVERY_MODE:
380 DEBUG((DEBUG_INFO, "Recovery Mode detected\n"));
381 // Passthrough
382
383 case BOOT_ASSUMING_NO_CONFIGURATION_CHANGES:
384 case BOOT_WITH_MINIMAL_CONFIGURATION:
385 case BOOT_WITH_FULL_CONFIGURATION:
386 case BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS:
387 case BOOT_WITH_DEFAULT_SETTINGS:
388 default:
389 EfiBootManagerConnectAll ();
390 EfiBootManagerRefreshAllBootOption ();
391
392 //
393 // Sync ESRT Cache from FMP Instance on demand after Connect All
394 //
395 if ((BootMode != BOOT_ASSUMING_NO_CONFIGURATION_CHANGES) &&
396 (BootMode != BOOT_WITH_MINIMAL_CONFIGURATION) &&
397 (BootMode != BOOT_ON_S4_RESUME)) {
398 if (EsrtManagement != NULL) {
399 EsrtManagement->SyncEsrtFmp();
400 }
401 }
402
403 break;
404 }
405
406 Print (
407 L"\n"
408 L"F2 to enter Boot Manager Menu.\n"
409 L"ENTER to boot directly.\n"
410 L"\n"
411 );
412
413 //
414 // Check if the platform is using test key.
415 //
416 Status = GetSectionFromAnyFv(
417 PcdGetPtr(PcdEdkiiRsa2048Sha256TestPublicKeyFileGuid),
418 EFI_SECTION_RAW,
419 0,
420 &Buffer,
421 &Size
422 );
423 if (!EFI_ERROR(Status)) {
424 if ((Size == PcdGetSize(PcdRsa2048Sha256PublicKeyBuffer)) &&
425 (CompareMem(Buffer, PcdGetPtr(PcdRsa2048Sha256PublicKeyBuffer), Size) == 0)) {
426 Print(L"WARNING: Recovery Test Key is used.\n");
427 PcdSetBoolS(PcdTestKeyUsed, TRUE);
428 }
429 FreePool(Buffer);
430 }
431 Status = GetSectionFromAnyFv(
432 PcdGetPtr(PcdEdkiiPkcs7TestPublicKeyFileGuid),
433 EFI_SECTION_RAW,
434 0,
435 &Buffer,
436 &Size
437 );
438 if (!EFI_ERROR(Status)) {
439 if ((Size == PcdGetSize(PcdPkcs7CertBuffer)) &&
440 (CompareMem(Buffer, PcdGetPtr(PcdPkcs7CertBuffer), Size) == 0)) {
441 Print(L"WARNING: Capsule Test Key is used.\n");
442 PcdSetBoolS(PcdTestKeyUsed, TRUE);
443 }
444 FreePool(Buffer);
445 }
446
447 //
448 // Use a DynamicHii type pcd to save the boot status, which is used to
449 // control configuration mode, such as FULL/MINIMAL/NO_CHANGES configuration.
450 //
451 if (PcdGetBool(PcdBootState)) {
452 Status = PcdSetBoolS (PcdBootState, FALSE);
453 ASSERT_EFI_ERROR (Status);
454 }
455 }
456
457 /**
458 This function is called each second during the boot manager waits the timeout.
459
460 @param TimeoutRemain The remaining timeout.
461 **/
462 VOID
463 EFIAPI
PlatformBootManagerWaitCallback(UINT16 TimeoutRemain)464 PlatformBootManagerWaitCallback (
465 UINT16 TimeoutRemain
466 )
467 {
468 Print (L"\r%-2d seconds remained...", TimeoutRemain);
469 }
470