]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/BdsDxe/BdsEntry.c
MdeModulePkg/CapsulePei: Change debug MACRO
[mirror_edk2.git] / MdeModulePkg / Universal / BdsDxe / BdsEntry.c
1 /** @file
2 This module produce main entry for BDS phase - BdsEntry.
3 When this module was dispatched by DxeCore, gEfiBdsArchProtocolGuid will be installed
4 which contains interface of BdsEntry.
5 After DxeCore finish DXE phase, gEfiBdsArchProtocolGuid->BdsEntry will be invoked
6 to enter BDS phase.
7
8 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
9 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
10 (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
11 SPDX-License-Identifier: BSD-2-Clause-Patent
12
13 **/
14
15 #include "Bds.h"
16 #include "Language.h"
17 #include "HwErrRecSupport.h"
18
19 #define SET_BOOT_OPTION_SUPPORT_KEY_COUNT(a, c) { \
20 (a) = ((a) & ~EFI_BOOT_OPTION_SUPPORT_COUNT) | (((c) << LowBitSet32 (EFI_BOOT_OPTION_SUPPORT_COUNT)) & EFI_BOOT_OPTION_SUPPORT_COUNT); \
21 }
22
23 ///
24 /// BDS arch protocol instance initial value.
25 ///
26 EFI_BDS_ARCH_PROTOCOL gBds = {
27 BdsEntry
28 };
29
30 //
31 // gConnectConInEvent - Event which is signaled when ConIn connection is required
32 //
33 EFI_EVENT gConnectConInEvent = NULL;
34
35 ///
36 /// The read-only variables defined in UEFI Spec.
37 ///
38 CHAR16 *mReadOnlyVariables[] = {
39 EFI_PLATFORM_LANG_CODES_VARIABLE_NAME,
40 EFI_LANG_CODES_VARIABLE_NAME,
41 EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME,
42 EFI_HW_ERR_REC_SUPPORT_VARIABLE_NAME,
43 EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME
44 };
45
46 CHAR16 *mBdsLoadOptionName[] = {
47 L"Driver",
48 L"SysPrep",
49 L"Boot",
50 L"PlatformRecovery"
51 };
52
53 /**
54 Event to Connect ConIn.
55
56 @param Event Event whose notification function is being invoked.
57 @param Context Pointer to the notification function's context,
58 which is implementation-dependent.
59
60 **/
61 VOID
62 EFIAPI
63 BdsDxeOnConnectConInCallBack (
64 IN EFI_EVENT Event,
65 IN VOID *Context
66 )
67 {
68 EFI_STATUS Status;
69
70 //
71 // When Osloader call ReadKeyStroke to signal this event
72 // no driver dependency is assumed existing. So use a non-dispatch version
73 //
74 Status = EfiBootManagerConnectConsoleVariable (ConIn);
75 if (EFI_ERROR (Status)) {
76 //
77 // Should not enter this case, if enter, the keyboard will not work.
78 // May need platfrom policy to connect keyboard.
79 //
80 DEBUG ((EFI_D_WARN, "[Bds] Connect ConIn failed - %r!!!\n", Status));
81 }
82 }
83 /**
84 Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT. This is used to
85 check whether there is remaining deferred load images.
86
87 @param[in] Event The Event that is being processed.
88 @param[in] Context The Event Context.
89
90 **/
91 VOID
92 EFIAPI
93 CheckDeferredLoadImageOnReadyToBoot (
94 IN EFI_EVENT Event,
95 IN VOID *Context
96 )
97 {
98 EFI_STATUS Status;
99 EFI_DEFERRED_IMAGE_LOAD_PROTOCOL *DeferredImage;
100 UINTN HandleCount;
101 EFI_HANDLE *Handles;
102 UINTN Index;
103 UINTN ImageIndex;
104 EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath;
105 VOID *Image;
106 UINTN ImageSize;
107 BOOLEAN BootOption;
108 CHAR16 *DevicePathStr;
109
110 //
111 // Find all the deferred image load protocols.
112 //
113 HandleCount = 0;
114 Handles = NULL;
115 Status = gBS->LocateHandleBuffer (
116 ByProtocol,
117 &gEfiDeferredImageLoadProtocolGuid,
118 NULL,
119 &HandleCount,
120 &Handles
121 );
122 if (EFI_ERROR (Status)) {
123 return;
124 }
125
126 for (Index = 0; Index < HandleCount; Index++) {
127 Status = gBS->HandleProtocol (Handles[Index], &gEfiDeferredImageLoadProtocolGuid, (VOID **) &DeferredImage);
128 if (EFI_ERROR (Status)) {
129 continue;
130 }
131
132 for (ImageIndex = 0; ; ImageIndex++) {
133 //
134 // Load all the deferred images in this protocol instance.
135 //
136 Status = DeferredImage->GetImageInfo (
137 DeferredImage,
138 ImageIndex,
139 &ImageDevicePath,
140 (VOID **) &Image,
141 &ImageSize,
142 &BootOption
143 );
144 if (EFI_ERROR (Status)) {
145 break;
146 }
147 DevicePathStr = ConvertDevicePathToText (ImageDevicePath, FALSE, FALSE);
148 DEBUG ((DEBUG_LOAD, "[Bds] Image was deferred but not loaded: %s.\n", DevicePathStr));
149 if (DevicePathStr != NULL) {
150 FreePool (DevicePathStr);
151 }
152 }
153 }
154 if (Handles != NULL) {
155 FreePool (Handles);
156 }
157 }
158
159 /**
160
161 Install Boot Device Selection Protocol
162
163 @param ImageHandle The image handle.
164 @param SystemTable The system table.
165
166 @retval EFI_SUCEESS BDS has finished initializing.
167 Return the dispatcher and recall BDS.Entry
168 @retval Other Return status from AllocatePool() or gBS->InstallProtocolInterface
169
170 **/
171 EFI_STATUS
172 EFIAPI
173 BdsInitialize (
174 IN EFI_HANDLE ImageHandle,
175 IN EFI_SYSTEM_TABLE *SystemTable
176 )
177 {
178 EFI_STATUS Status;
179 EFI_HANDLE Handle;
180 //
181 // Install protocol interface
182 //
183 Handle = NULL;
184 Status = gBS->InstallMultipleProtocolInterfaces (
185 &Handle,
186 &gEfiBdsArchProtocolGuid, &gBds,
187 NULL
188 );
189 ASSERT_EFI_ERROR (Status);
190
191 DEBUG_CODE (
192 EFI_EVENT Event;
193 //
194 // Register notify function to check deferred images on ReadyToBoot Event.
195 //
196 Status = gBS->CreateEventEx (
197 EVT_NOTIFY_SIGNAL,
198 TPL_CALLBACK,
199 CheckDeferredLoadImageOnReadyToBoot,
200 NULL,
201 &gEfiEventReadyToBootGuid,
202 &Event
203 );
204 ASSERT_EFI_ERROR (Status);
205 );
206 return Status;
207 }
208
209 /**
210 Function waits for a given event to fire, or for an optional timeout to expire.
211
212 @param Event The event to wait for
213 @param Timeout An optional timeout value in 100 ns units.
214
215 @retval EFI_SUCCESS Event fired before Timeout expired.
216 @retval EFI_TIME_OUT Timout expired before Event fired..
217
218 **/
219 EFI_STATUS
220 BdsWaitForSingleEvent (
221 IN EFI_EVENT Event,
222 IN UINT64 Timeout OPTIONAL
223 )
224 {
225 UINTN Index;
226 EFI_STATUS Status;
227 EFI_EVENT TimerEvent;
228 EFI_EVENT WaitList[2];
229
230 if (Timeout != 0) {
231 //
232 // Create a timer event
233 //
234 Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
235 if (!EFI_ERROR (Status)) {
236 //
237 // Set the timer event
238 //
239 gBS->SetTimer (
240 TimerEvent,
241 TimerRelative,
242 Timeout
243 );
244
245 //
246 // Wait for the original event or the timer
247 //
248 WaitList[0] = Event;
249 WaitList[1] = TimerEvent;
250 Status = gBS->WaitForEvent (2, WaitList, &Index);
251 ASSERT_EFI_ERROR (Status);
252 gBS->CloseEvent (TimerEvent);
253
254 //
255 // If the timer expired, change the return to timed out
256 //
257 if (Index == 1) {
258 Status = EFI_TIMEOUT;
259 }
260 }
261 } else {
262 //
263 // No timeout... just wait on the event
264 //
265 Status = gBS->WaitForEvent (1, &Event, &Index);
266 ASSERT (!EFI_ERROR (Status));
267 ASSERT (Index == 0);
268 }
269
270 return Status;
271 }
272
273 /**
274 The function reads user inputs.
275
276 **/
277 VOID
278 BdsReadKeys (
279 VOID
280 )
281 {
282 EFI_STATUS Status;
283 EFI_INPUT_KEY Key;
284
285 if (PcdGetBool (PcdConInConnectOnDemand)) {
286 return;
287 }
288
289 while (gST->ConIn != NULL) {
290
291 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
292
293 if (EFI_ERROR (Status)) {
294 //
295 // No more keys.
296 //
297 break;
298 }
299 }
300 }
301
302 /**
303 The function waits for the boot manager timeout expires or hotkey is pressed.
304
305 It calls PlatformBootManagerWaitCallback each second.
306
307 @param HotkeyTriggered Input hotkey event.
308 **/
309 VOID
310 BdsWait (
311 IN EFI_EVENT HotkeyTriggered
312 )
313 {
314 EFI_STATUS Status;
315 UINT16 TimeoutRemain;
316
317 DEBUG ((EFI_D_INFO, "[Bds]BdsWait ...Zzzzzzzzzzzz...\n"));
318
319 TimeoutRemain = PcdGet16 (PcdPlatformBootTimeOut);
320 while (TimeoutRemain != 0) {
321 DEBUG ((EFI_D_INFO, "[Bds]BdsWait(%d)..Zzzz...\n", (UINTN) TimeoutRemain));
322 PlatformBootManagerWaitCallback (TimeoutRemain);
323
324 BdsReadKeys (); // BUGBUG: Only reading can signal HotkeyTriggered
325 // Can be removed after all keyboard drivers invoke callback in timer callback.
326
327 if (HotkeyTriggered != NULL) {
328 Status = BdsWaitForSingleEvent (HotkeyTriggered, EFI_TIMER_PERIOD_SECONDS (1));
329 if (!EFI_ERROR (Status)) {
330 break;
331 }
332 } else {
333 gBS->Stall (1000000);
334 }
335
336 //
337 // 0xffff means waiting forever
338 // BDS with no hotkey provided and 0xffff as timeout will "hang" in the loop
339 //
340 if (TimeoutRemain != 0xffff) {
341 TimeoutRemain--;
342 }
343 }
344 DEBUG ((EFI_D_INFO, "[Bds]Exit the waiting!\n"));
345 }
346
347 /**
348 Attempt to boot each boot option in the BootOptions array.
349
350 @param BootOptions Input boot option array.
351 @param BootOptionCount Input boot option count.
352 @param BootManagerMenu Input boot manager menu.
353
354 @retval TRUE Successfully boot one of the boot options.
355 @retval FALSE Failed boot any of the boot options.
356 **/
357 BOOLEAN
358 BootBootOptions (
359 IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,
360 IN UINTN BootOptionCount,
361 IN EFI_BOOT_MANAGER_LOAD_OPTION *BootManagerMenu OPTIONAL
362 )
363 {
364 UINTN Index;
365
366 //
367 // Report Status Code to indicate BDS starts attempting booting from the UEFI BootOrder list.
368 //
369 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_ATTEMPT_BOOT_ORDER_EVENT));
370
371 //
372 // Attempt boot each boot option
373 //
374 for (Index = 0; Index < BootOptionCount; Index++) {
375 //
376 // According to EFI Specification, if a load option is not marked
377 // as LOAD_OPTION_ACTIVE, the boot manager will not automatically
378 // load the option.
379 //
380 if ((BootOptions[Index].Attributes & LOAD_OPTION_ACTIVE) == 0) {
381 continue;
382 }
383
384 //
385 // Boot#### load options with LOAD_OPTION_CATEGORY_APP are executables which are not
386 // part of the normal boot processing. Boot options with reserved category values will be
387 // ignored by the boot manager.
388 //
389 if ((BootOptions[Index].Attributes & LOAD_OPTION_CATEGORY) != LOAD_OPTION_CATEGORY_BOOT) {
390 continue;
391 }
392
393 //
394 // All the driver options should have been processed since
395 // now boot will be performed.
396 //
397 EfiBootManagerBoot (&BootOptions[Index]);
398
399 //
400 // If the boot via Boot#### returns with a status of EFI_SUCCESS, platform firmware
401 // supports boot manager menu, and if firmware is configured to boot in an
402 // interactive mode, the boot manager will stop processing the BootOrder variable and
403 // present a boot manager menu to the user.
404 //
405 if ((BootManagerMenu != NULL) && (BootOptions[Index].Status == EFI_SUCCESS)) {
406 EfiBootManagerBoot (BootManagerMenu);
407 break;
408 }
409 }
410
411 return (BOOLEAN) (Index < BootOptionCount);
412 }
413
414 /**
415 The function will load and start every Driver####, SysPrep#### or PlatformRecovery####.
416
417 @param LoadOptions Load option array.
418 @param LoadOptionCount Load option count.
419 **/
420 VOID
421 ProcessLoadOptions (
422 IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOptions,
423 IN UINTN LoadOptionCount
424 )
425 {
426 EFI_STATUS Status;
427 UINTN Index;
428 BOOLEAN ReconnectAll;
429 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType;
430
431 ReconnectAll = FALSE;
432 LoadOptionType = LoadOptionTypeMax;
433
434 //
435 // Process the driver option
436 //
437 for (Index = 0; Index < LoadOptionCount; Index++) {
438 //
439 // All the load options in the array should be of the same type.
440 //
441 if (Index == 0) {
442 LoadOptionType = LoadOptions[Index].OptionType;
443 }
444 ASSERT (LoadOptionType == LoadOptions[Index].OptionType);
445 ASSERT (LoadOptionType != LoadOptionTypeBoot);
446
447 Status = EfiBootManagerProcessLoadOption (&LoadOptions[Index]);
448
449 //
450 // Status indicates whether the load option is loaded and executed
451 // LoadOptions[Index].Status is what the load option returns
452 //
453 if (!EFI_ERROR (Status)) {
454 //
455 // Stop processing if any PlatformRecovery#### returns success.
456 //
457 if ((LoadOptions[Index].Status == EFI_SUCCESS) &&
458 (LoadOptionType == LoadOptionTypePlatformRecovery)) {
459 break;
460 }
461
462 //
463 // Only set ReconnectAll flag when the load option executes successfully.
464 //
465 if (!EFI_ERROR (LoadOptions[Index].Status) &&
466 (LoadOptions[Index].Attributes & LOAD_OPTION_FORCE_RECONNECT) != 0) {
467 ReconnectAll = TRUE;
468 }
469 }
470 }
471
472 //
473 // If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT,
474 // then all of the EFI drivers in the system will be disconnected and
475 // reconnected after the last driver load option is processed.
476 //
477 if (ReconnectAll && LoadOptionType == LoadOptionTypeDriver) {
478 EfiBootManagerDisconnectAll ();
479 EfiBootManagerConnectAll ();
480 }
481 }
482
483 /**
484
485 Validate input console variable data.
486
487 If found the device path is not a valid device path, remove the variable.
488
489 @param VariableName Input console variable name.
490
491 **/
492 VOID
493 BdsFormalizeConsoleVariable (
494 IN CHAR16 *VariableName
495 )
496 {
497 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
498 UINTN VariableSize;
499 EFI_STATUS Status;
500
501 GetEfiGlobalVariable2 (VariableName, (VOID **) &DevicePath, &VariableSize);
502 if ((DevicePath != NULL) && !IsDevicePathValid (DevicePath, VariableSize)) {
503 Status = gRT->SetVariable (
504 VariableName,
505 &gEfiGlobalVariableGuid,
506 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
507 0,
508 NULL
509 );
510 //
511 // Deleting variable with current variable implementation shouldn't fail.
512 //
513 ASSERT_EFI_ERROR (Status);
514 }
515
516 if (DevicePath != NULL) {
517 FreePool (DevicePath);
518 }
519 }
520
521 /**
522 Formalize OsIndication related variables.
523
524 For OsIndicationsSupported, Create a BS/RT/UINT64 variable to report caps
525 Delete OsIndications variable if it is not NV/BS/RT UINT64.
526
527 Item 3 is used to solve case when OS corrupts OsIndications. Here simply delete this NV variable.
528
529 Create a boot option for BootManagerMenu if it hasn't been created yet
530
531 **/
532 VOID
533 BdsFormalizeOSIndicationVariable (
534 VOID
535 )
536 {
537 EFI_STATUS Status;
538 UINT64 OsIndicationSupport;
539 UINT64 OsIndication;
540 UINTN DataSize;
541 UINT32 Attributes;
542 EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;
543
544 //
545 // OS indicater support variable
546 //
547 Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);
548 if (Status != EFI_NOT_FOUND) {
549 OsIndicationSupport = EFI_OS_INDICATIONS_BOOT_TO_FW_UI | EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY;
550 EfiBootManagerFreeLoadOption (&BootManagerMenu);
551 } else {
552 OsIndicationSupport = EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY;
553 }
554
555 Status = gRT->SetVariable (
556 EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME,
557 &gEfiGlobalVariableGuid,
558 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
559 sizeof(UINT64),
560 &OsIndicationSupport
561 );
562 //
563 // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.
564 //
565 ASSERT_EFI_ERROR (Status);
566
567 //
568 // If OsIndications is invalid, remove it.
569 // Invalid case
570 // 1. Data size != UINT64
571 // 2. OsIndication value inconsistence
572 // 3. OsIndication attribute inconsistence
573 //
574 OsIndication = 0;
575 Attributes = 0;
576 DataSize = sizeof(UINT64);
577 Status = gRT->GetVariable (
578 EFI_OS_INDICATIONS_VARIABLE_NAME,
579 &gEfiGlobalVariableGuid,
580 &Attributes,
581 &DataSize,
582 &OsIndication
583 );
584 if (Status == EFI_NOT_FOUND) {
585 return;
586 }
587
588 if ((DataSize != sizeof (OsIndication)) ||
589 ((OsIndication & ~OsIndicationSupport) != 0) ||
590 (Attributes != (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE))
591 ){
592
593 DEBUG ((EFI_D_ERROR, "[Bds] Unformalized OsIndications variable exists. Delete it\n"));
594 Status = gRT->SetVariable (
595 EFI_OS_INDICATIONS_VARIABLE_NAME,
596 &gEfiGlobalVariableGuid,
597 0,
598 0,
599 NULL
600 );
601 //
602 // Deleting variable with current variable implementation shouldn't fail.
603 //
604 ASSERT_EFI_ERROR(Status);
605 }
606 }
607
608 /**
609
610 Validate variables.
611
612 **/
613 VOID
614 BdsFormalizeEfiGlobalVariable (
615 VOID
616 )
617 {
618 //
619 // Validate Console variable.
620 //
621 BdsFormalizeConsoleVariable (EFI_CON_IN_VARIABLE_NAME);
622 BdsFormalizeConsoleVariable (EFI_CON_OUT_VARIABLE_NAME);
623 BdsFormalizeConsoleVariable (EFI_ERR_OUT_VARIABLE_NAME);
624
625 //
626 // Validate OSIndication related variable.
627 //
628 BdsFormalizeOSIndicationVariable ();
629 }
630
631 /**
632
633 Service routine for BdsInstance->Entry(). Devices are connected, the
634 consoles are initialized, and the boot options are tried.
635
636 @param This Protocol Instance structure.
637
638 **/
639 VOID
640 EFIAPI
641 BdsEntry (
642 IN EFI_BDS_ARCH_PROTOCOL *This
643 )
644 {
645 EFI_BOOT_MANAGER_LOAD_OPTION *LoadOptions;
646 UINTN LoadOptionCount;
647 CHAR16 *FirmwareVendor;
648 EFI_EVENT HotkeyTriggered;
649 UINT64 OsIndication;
650 UINTN DataSize;
651 EFI_STATUS Status;
652 UINT32 BootOptionSupport;
653 UINT16 BootTimeOut;
654 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
655 UINTN Index;
656 EFI_BOOT_MANAGER_LOAD_OPTION LoadOption;
657 UINT16 *BootNext;
658 CHAR16 BootNextVariableName[sizeof ("Boot####")];
659 EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;
660 BOOLEAN BootFwUi;
661 BOOLEAN PlatformRecovery;
662 BOOLEAN BootSuccess;
663 EFI_DEVICE_PATH_PROTOCOL *FilePath;
664 EFI_STATUS BootManagerMenuStatus;
665
666 HotkeyTriggered = NULL;
667 Status = EFI_SUCCESS;
668 BootSuccess = FALSE;
669
670 //
671 // Insert the performance probe
672 //
673 PERF_CROSSMODULE_END("DXE");
674 PERF_CROSSMODULE_BEGIN("BDS");
675 DEBUG ((EFI_D_INFO, "[Bds] Entry...\n"));
676
677 //
678 // Fill in FirmwareVendor and FirmwareRevision from PCDs
679 //
680 FirmwareVendor = (CHAR16 *) PcdGetPtr (PcdFirmwareVendor);
681 gST->FirmwareVendor = AllocateRuntimeCopyPool (StrSize (FirmwareVendor), FirmwareVendor);
682 ASSERT (gST->FirmwareVendor != NULL);
683 gST->FirmwareRevision = PcdGet32 (PcdFirmwareRevision);
684
685 //
686 // Fixup Tasble CRC after we updated Firmware Vendor and Revision
687 //
688 gST->Hdr.CRC32 = 0;
689 gBS->CalculateCrc32 ((VOID *) gST, sizeof (EFI_SYSTEM_TABLE), &gST->Hdr.CRC32);
690
691 //
692 // Validate Variable.
693 //
694 BdsFormalizeEfiGlobalVariable ();
695
696 //
697 // Mark the read-only variables if the Variable Lock protocol exists
698 //
699 Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);
700 DEBUG ((EFI_D_INFO, "[BdsDxe] Locate Variable Lock protocol - %r\n", Status));
701 if (!EFI_ERROR (Status)) {
702 for (Index = 0; Index < ARRAY_SIZE (mReadOnlyVariables); Index++) {
703 Status = VariableLock->RequestToLock (VariableLock, mReadOnlyVariables[Index], &gEfiGlobalVariableGuid);
704 ASSERT_EFI_ERROR (Status);
705 }
706 }
707
708 InitializeHwErrRecSupport ();
709
710 //
711 // Initialize L"Timeout" EFI global variable.
712 //
713 BootTimeOut = PcdGet16 (PcdPlatformBootTimeOut);
714 if (BootTimeOut != 0xFFFF) {
715 //
716 // If time out value equal 0xFFFF, no need set to 0xFFFF to variable area because UEFI specification
717 // define same behavior between no value or 0xFFFF value for L"Timeout".
718 //
719 BdsDxeSetVariableAndReportStatusCodeOnError (
720 EFI_TIME_OUT_VARIABLE_NAME,
721 &gEfiGlobalVariableGuid,
722 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
723 sizeof (UINT16),
724 &BootTimeOut
725 );
726 }
727
728 //
729 // Initialize L"BootOptionSupport" EFI global variable.
730 // Lazy-ConIn implictly disables BDS hotkey.
731 //
732 BootOptionSupport = EFI_BOOT_OPTION_SUPPORT_APP | EFI_BOOT_OPTION_SUPPORT_SYSPREP;
733 if (!PcdGetBool (PcdConInConnectOnDemand)) {
734 BootOptionSupport |= EFI_BOOT_OPTION_SUPPORT_KEY;
735 SET_BOOT_OPTION_SUPPORT_KEY_COUNT (BootOptionSupport, 3);
736 }
737 Status = gRT->SetVariable (
738 EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME,
739 &gEfiGlobalVariableGuid,
740 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
741 sizeof (BootOptionSupport),
742 &BootOptionSupport
743 );
744 //
745 // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.
746 //
747 ASSERT_EFI_ERROR (Status);
748
749 //
750 // Cache the "BootNext" NV variable before calling any PlatformBootManagerLib APIs
751 // This could avoid the "BootNext" set by PlatformBootManagerLib be consumed in this boot.
752 //
753 GetEfiGlobalVariable2 (EFI_BOOT_NEXT_VARIABLE_NAME, (VOID **) &BootNext, &DataSize);
754 if (DataSize != sizeof (UINT16)) {
755 if (BootNext != NULL) {
756 FreePool (BootNext);
757 }
758 BootNext = NULL;
759 }
760
761 //
762 // Initialize the platform language variables
763 //
764 InitializeLanguage (TRUE);
765
766 //
767 // System firmware must include a PlatformRecovery#### variable specifying
768 // a short-form File Path Media Device Path containing the platform default
769 // file path for removable media
770 //
771 FilePath = FileDevicePath (NULL, EFI_REMOVABLE_MEDIA_FILE_NAME);
772 Status = EfiBootManagerInitializeLoadOption (
773 &LoadOption,
774 LoadOptionNumberUnassigned,
775 LoadOptionTypePlatformRecovery,
776 LOAD_OPTION_ACTIVE,
777 L"Default PlatformRecovery",
778 FilePath,
779 NULL,
780 0
781 );
782 ASSERT_EFI_ERROR (Status);
783 LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypePlatformRecovery);
784 if (EfiBootManagerFindLoadOption (&LoadOption, LoadOptions, LoadOptionCount) == -1) {
785 for (Index = 0; Index < LoadOptionCount; Index++) {
786 //
787 // The PlatformRecovery#### options are sorted by OptionNumber.
788 // Find the the smallest unused number as the new OptionNumber.
789 //
790 if (LoadOptions[Index].OptionNumber != Index) {
791 break;
792 }
793 }
794 LoadOption.OptionNumber = Index;
795 Status = EfiBootManagerLoadOptionToVariable (&LoadOption);
796 ASSERT_EFI_ERROR (Status);
797 }
798 EfiBootManagerFreeLoadOption (&LoadOption);
799 FreePool (FilePath);
800 EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);
801
802 //
803 // Report Status Code to indicate connecting drivers will happen
804 //
805 REPORT_STATUS_CODE (
806 EFI_PROGRESS_CODE,
807 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_BEGIN_CONNECTING_DRIVERS)
808 );
809
810 //
811 // Initialize ConnectConIn event before calling platform code.
812 //
813 if (PcdGetBool (PcdConInConnectOnDemand)) {
814 Status = gBS->CreateEventEx (
815 EVT_NOTIFY_SIGNAL,
816 TPL_CALLBACK,
817 BdsDxeOnConnectConInCallBack,
818 NULL,
819 &gConnectConInEventGuid,
820 &gConnectConInEvent
821 );
822 if (EFI_ERROR (Status)) {
823 gConnectConInEvent = NULL;
824 }
825 }
826
827 //
828 // Do the platform init, can be customized by OEM/IBV
829 // Possible things that can be done in PlatformBootManagerBeforeConsole:
830 // > Update console variable: 1. include hot-plug devices; 2. Clear ConIn and add SOL for AMT
831 // > Register new Driver#### or Boot####
832 // > Register new Key####: e.g.: F12
833 // > Signal ReadyToLock event
834 // > Authentication action: 1. connect Auth devices; 2. Identify auto logon user.
835 //
836 PERF_INMODULE_BEGIN("PlatformBootManagerBeforeConsole");
837 PlatformBootManagerBeforeConsole ();
838 PERF_INMODULE_END("PlatformBootManagerBeforeConsole");
839
840 //
841 // Initialize hotkey service
842 //
843 EfiBootManagerStartHotkeyService (&HotkeyTriggered);
844
845 //
846 // Execute Driver Options
847 //
848 LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeDriver);
849 ProcessLoadOptions (LoadOptions, LoadOptionCount);
850 EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);
851
852 //
853 // Connect consoles
854 //
855 PERF_INMODULE_BEGIN("EfiBootManagerConnectAllDefaultConsoles");
856 if (PcdGetBool (PcdConInConnectOnDemand)) {
857 EfiBootManagerConnectConsoleVariable (ConOut);
858 EfiBootManagerConnectConsoleVariable (ErrOut);
859 //
860 // Do not connect ConIn devices when lazy ConIn feature is ON.
861 //
862 } else {
863 EfiBootManagerConnectAllDefaultConsoles ();
864 }
865 PERF_INMODULE_END("EfiBootManagerConnectAllDefaultConsoles");
866
867 //
868 // Do the platform specific action after the console is ready
869 // Possible things that can be done in PlatformBootManagerAfterConsole:
870 // > Console post action:
871 // > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
872 // > Signal console ready platform customized event
873 // > Run diagnostics like memory testing
874 // > Connect certain devices
875 // > Dispatch aditional option roms
876 // > Special boot: e.g.: USB boot, enter UI
877 //
878 PERF_INMODULE_BEGIN("PlatformBootManagerAfterConsole");
879 PlatformBootManagerAfterConsole ();
880 PERF_INMODULE_END("PlatformBootManagerAfterConsole");
881
882 //
883 // If any component set PcdTestKeyUsed to TRUE because use of a test key
884 // was detected, then display a warning message on the debug log and the console
885 //
886 if (PcdGetBool (PcdTestKeyUsed)) {
887 DEBUG ((DEBUG_ERROR, "**********************************\n"));
888 DEBUG ((DEBUG_ERROR, "** WARNING: Test Key is used. **\n"));
889 DEBUG ((DEBUG_ERROR, "**********************************\n"));
890 Print (L"** WARNING: Test Key is used. **\n");
891 }
892
893 //
894 // Boot to Boot Manager Menu when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot
895 //
896 DataSize = sizeof (UINT64);
897 Status = gRT->GetVariable (
898 EFI_OS_INDICATIONS_VARIABLE_NAME,
899 &gEfiGlobalVariableGuid,
900 NULL,
901 &DataSize,
902 &OsIndication
903 );
904 if (EFI_ERROR (Status)) {
905 OsIndication = 0;
906 }
907
908 DEBUG_CODE (
909 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType;
910 DEBUG ((EFI_D_INFO, "[Bds]OsIndication: %016x\n", OsIndication));
911 DEBUG ((EFI_D_INFO, "[Bds]=============Begin Load Options Dumping ...=============\n"));
912 for (LoadOptionType = 0; LoadOptionType < LoadOptionTypeMax; LoadOptionType++) {
913 DEBUG ((
914 EFI_D_INFO, " %s Options:\n",
915 mBdsLoadOptionName[LoadOptionType]
916 ));
917 LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionType);
918 for (Index = 0; Index < LoadOptionCount; Index++) {
919 DEBUG ((
920 EFI_D_INFO, " %s%04x: %s \t\t 0x%04x\n",
921 mBdsLoadOptionName[LoadOptionType],
922 LoadOptions[Index].OptionNumber,
923 LoadOptions[Index].Description,
924 LoadOptions[Index].Attributes
925 ));
926 }
927 EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);
928 }
929 DEBUG ((EFI_D_INFO, "[Bds]=============End Load Options Dumping=============\n"));
930 );
931
932 //
933 // BootManagerMenu doesn't contain the correct information when return status is EFI_NOT_FOUND.
934 //
935 BootManagerMenuStatus = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);
936
937 BootFwUi = (BOOLEAN) ((OsIndication & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) != 0);
938 PlatformRecovery = (BOOLEAN) ((OsIndication & EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY) != 0);
939 //
940 // Clear EFI_OS_INDICATIONS_BOOT_TO_FW_UI to acknowledge OS
941 //
942 if (BootFwUi || PlatformRecovery) {
943 OsIndication &= ~((UINT64) (EFI_OS_INDICATIONS_BOOT_TO_FW_UI | EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY));
944 Status = gRT->SetVariable (
945 EFI_OS_INDICATIONS_VARIABLE_NAME,
946 &gEfiGlobalVariableGuid,
947 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
948 sizeof(UINT64),
949 &OsIndication
950 );
951 //
952 // Changing the content without increasing its size with current variable implementation shouldn't fail.
953 //
954 ASSERT_EFI_ERROR (Status);
955 }
956
957 //
958 // Launch Boot Manager Menu directly when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot
959 //
960 if (BootFwUi && (BootManagerMenuStatus != EFI_NOT_FOUND)) {
961 //
962 // Follow generic rule, Call BdsDxeOnConnectConInCallBack to connect ConIn before enter UI
963 //
964 if (PcdGetBool (PcdConInConnectOnDemand)) {
965 BdsDxeOnConnectConInCallBack (NULL, NULL);
966 }
967
968 //
969 // Directly enter the setup page.
970 //
971 EfiBootManagerBoot (&BootManagerMenu);
972 }
973
974 if (!PlatformRecovery) {
975 //
976 // Execute SysPrep####
977 //
978 LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeSysPrep);
979 ProcessLoadOptions (LoadOptions, LoadOptionCount);
980 EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);
981
982 //
983 // Execute Key####
984 //
985 PERF_INMODULE_BEGIN ("BdsWait");
986 BdsWait (HotkeyTriggered);
987 PERF_INMODULE_END ("BdsWait");
988 //
989 // BdsReadKeys() can be removed after all keyboard drivers invoke callback in timer callback.
990 //
991 BdsReadKeys ();
992
993 EfiBootManagerHotkeyBoot ();
994
995 if (BootNext != NULL) {
996 //
997 // Delete "BootNext" NV variable before transferring control to it to prevent loops.
998 //
999 Status = gRT->SetVariable (
1000 EFI_BOOT_NEXT_VARIABLE_NAME,
1001 &gEfiGlobalVariableGuid,
1002 0,
1003 0,
1004 NULL
1005 );
1006 //
1007 // Deleting NV variable shouldn't fail unless it doesn't exist.
1008 //
1009 ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);
1010
1011 //
1012 // Boot to "BootNext"
1013 //
1014 UnicodeSPrint (BootNextVariableName, sizeof (BootNextVariableName), L"Boot%04x", *BootNext);
1015 Status = EfiBootManagerVariableToLoadOption (BootNextVariableName, &LoadOption);
1016 if (!EFI_ERROR (Status)) {
1017 EfiBootManagerBoot (&LoadOption);
1018 EfiBootManagerFreeLoadOption (&LoadOption);
1019 if ((LoadOption.Status == EFI_SUCCESS) &&
1020 (BootManagerMenuStatus != EFI_NOT_FOUND) &&
1021 (LoadOption.OptionNumber != BootManagerMenu.OptionNumber)) {
1022 //
1023 // Boot to Boot Manager Menu upon EFI_SUCCESS
1024 // Exception: Do not boot again when the BootNext points to Boot Manager Menu.
1025 //
1026 EfiBootManagerBoot (&BootManagerMenu);
1027 }
1028 }
1029 }
1030
1031 do {
1032 //
1033 // Retry to boot if any of the boot succeeds
1034 //
1035 LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeBoot);
1036 BootSuccess = BootBootOptions (LoadOptions, LoadOptionCount, (BootManagerMenuStatus != EFI_NOT_FOUND) ? &BootManagerMenu : NULL);
1037 EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);
1038 } while (BootSuccess);
1039 }
1040
1041 if (BootManagerMenuStatus != EFI_NOT_FOUND) {
1042 EfiBootManagerFreeLoadOption (&BootManagerMenu);
1043 }
1044
1045 if (!BootSuccess) {
1046 LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypePlatformRecovery);
1047 ProcessLoadOptions (LoadOptions, LoadOptionCount);
1048 EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);
1049 }
1050
1051 DEBUG ((EFI_D_ERROR, "[Bds] Unable to boot!\n"));
1052 PlatformBootManagerUnableToBoot ();
1053 CpuDeadLoop ();
1054 }
1055
1056 /**
1057 Set the variable and report the error through status code upon failure.
1058
1059 @param VariableName A Null-terminated string that is the name of the vendor's variable.
1060 Each VariableName is unique for each VendorGuid. VariableName must
1061 contain 1 or more characters. If VariableName is an empty string,
1062 then EFI_INVALID_PARAMETER is returned.
1063 @param VendorGuid A unique identifier for the vendor.
1064 @param Attributes Attributes bitmask to set for the variable.
1065 @param DataSize The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE,
1066 or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero
1067 causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is
1068 set, then a SetVariable() call with a DataSize of zero will not cause any change to
1069 the variable value (the timestamp associated with the variable may be updated however
1070 even if no new data value is provided,see the description of the
1071 EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not
1072 be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated).
1073 @param Data The contents for the variable.
1074
1075 @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
1076 defined by the Attributes.
1077 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, and GUID was supplied, or the
1078 DataSize exceeds the maximum allowed.
1079 @retval EFI_INVALID_PARAMETER VariableName is an empty string.
1080 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
1081 @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.
1082 @retval EFI_WRITE_PROTECTED The variable in question is read-only.
1083 @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.
1084 @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS
1085 being set, but the AuthInfo does NOT pass the validation check carried out by the firmware.
1086
1087 @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.
1088 **/
1089 EFI_STATUS
1090 BdsDxeSetVariableAndReportStatusCodeOnError (
1091 IN CHAR16 *VariableName,
1092 IN EFI_GUID *VendorGuid,
1093 IN UINT32 Attributes,
1094 IN UINTN DataSize,
1095 IN VOID *Data
1096 )
1097 {
1098 EFI_STATUS Status;
1099 EDKII_SET_VARIABLE_STATUS *SetVariableStatus;
1100 UINTN NameSize;
1101
1102 Status = gRT->SetVariable (
1103 VariableName,
1104 VendorGuid,
1105 Attributes,
1106 DataSize,
1107 Data
1108 );
1109 if (EFI_ERROR (Status)) {
1110 NameSize = StrSize (VariableName);
1111 SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize);
1112 if (SetVariableStatus != NULL) {
1113 CopyGuid (&SetVariableStatus->Guid, VendorGuid);
1114 SetVariableStatus->NameSize = NameSize;
1115 SetVariableStatus->DataSize = DataSize;
1116 SetVariableStatus->SetStatus = Status;
1117 SetVariableStatus->Attributes = Attributes;
1118 CopyMem (SetVariableStatus + 1, VariableName, NameSize);
1119 CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Data, DataSize);
1120
1121 REPORT_STATUS_CODE_EX (
1122 EFI_ERROR_CODE,
1123 PcdGet32 (PcdErrorCodeSetVariable),
1124 0,
1125 NULL,
1126 &gEdkiiStatusCodeDataTypeVariableGuid,
1127 SetVariableStatus,
1128 sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize
1129 );
1130
1131 FreePool (SetVariableStatus);
1132 }
1133 }
1134
1135 return Status;
1136 }