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