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
8 Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
9 This program and the accompanying materials
10 are licensed and made available under the terms and conditions of the BSD License
11 which accompanies this distribution. The full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
21 #include "HwErrRecSupport.h"
23 #define SET_BOOT_OPTION_SUPPORT_KEY_COUNT(a, c) { \
24 (a) = ((a) & ~EFI_BOOT_OPTION_SUPPORT_COUNT) | (((c) << LowBitSet32 (EFI_BOOT_OPTION_SUPPORT_COUNT)) & EFI_BOOT_OPTION_SUPPORT_COUNT); \
28 /// BDS arch protocol instance initial value.
30 EFI_BDS_ARCH_PROTOCOL gBds
= {
35 // gConnectConInEvent - Event which is signaled when ConIn connection is required
37 EFI_EVENT gConnectConInEvent
= NULL
;
40 /// The read-only variables defined in UEFI Spec.
42 CHAR16
*mReadOnlyVariables
[] = {
43 EFI_PLATFORM_LANG_CODES_VARIABLE_NAME
,
44 EFI_LANG_CODES_VARIABLE_NAME
,
45 EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME
,
46 EFI_HW_ERR_REC_SUPPORT_VARIABLE_NAME
,
47 EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME
50 CHAR16 mRecoveryBoot
[] = L
"Recovery Boot";
52 Event to Connect ConIn.
54 @param Event Event whose notification function is being invoked.
55 @param Context Pointer to the notification function's context,
56 which is implementation-dependent.
61 BdsDxeOnConnectConInCallBack (
69 // When Osloader call ReadKeyStroke to signal this event
70 // no driver dependency is assumed existing. So use a non-dispatch version
72 Status
= EfiBootManagerConnectConsoleVariable (ConIn
);
73 if (EFI_ERROR (Status
)) {
75 // Should not enter this case, if enter, the keyboard will not work.
76 // May need platfrom policy to connect keyboard.
78 DEBUG ((EFI_D_WARN
, "[Bds] ASSERT Connect ConIn failed!!!\n"));
84 Install Boot Device Selection Protocol
86 @param ImageHandle The image handle.
87 @param SystemTable The system table.
89 @retval EFI_SUCEESS BDS has finished initializing.
90 Return the dispatcher and recall BDS.Entry
91 @retval Other Return status from AllocatePool() or gBS->InstallProtocolInterface
97 IN EFI_HANDLE ImageHandle
,
98 IN EFI_SYSTEM_TABLE
*SystemTable
104 // Install protocol interface
107 Status
= gBS
->InstallMultipleProtocolInterfaces (
109 &gEfiBdsArchProtocolGuid
, &gBds
,
112 ASSERT_EFI_ERROR (Status
);
118 Emuerate all possible bootable medias in the following order:
119 1. Removable BlockIo - The boot option only points to the removable media
120 device, like USB key, DVD, Floppy etc.
121 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
123 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
124 SimpleFileSystem Protocol, but not supporting BlockIo
126 4. LoadFile - The boot option points to the media supporting
128 Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
130 @param BootOptionCount Return the boot option count which has been found.
132 @retval Pointer to the boot option array.
134 EFI_BOOT_MANAGER_LOAD_OPTION
*
135 BdsEnumerateBootOptions (
136 UINTN
*BootOptionCount
140 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
141 UINT16 NonBlockNumber
;
144 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
148 ASSERT (BootOptionCount
!= NULL
);
150 *BootOptionCount
= 0;
154 // Parse removable block io followed by fixed block io
156 gBS
->LocateHandleBuffer (
158 &gEfiBlockIoProtocolGuid
,
164 for (Removable
= 0; Removable
< 2; Removable
++) {
165 for (Index
= 0; Index
< HandleCount
; Index
++) {
166 Status
= gBS
->HandleProtocol (
168 &gEfiBlockIoProtocolGuid
,
171 if (EFI_ERROR (Status
)) {
176 // Skip the logical partitions
178 if (BlkIo
->Media
->LogicalPartition
) {
183 // Skip the fixed block io then the removable block io
185 if (BlkIo
->Media
->RemovableMedia
== ((Removable
== 0) ? FALSE
: TRUE
)) {
189 BootOptions
= ReallocatePool (
190 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
191 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
194 ASSERT (BootOptions
!= NULL
);
196 Status
= EfiBootManagerInitializeLoadOption (
197 &BootOptions
[(*BootOptionCount
)++],
198 LoadOptionNumberUnassigned
,
202 DevicePathFromHandle (Handles
[Index
]),
206 ASSERT_EFI_ERROR (Status
);
210 if (HandleCount
!= 0) {
215 // Parse simple file system not based on block io
218 gBS
->LocateHandleBuffer (
220 &gEfiSimpleFileSystemProtocolGuid
,
225 for (Index
= 0; Index
< HandleCount
; Index
++) {
226 Status
= gBS
->HandleProtocol (
228 &gEfiBlockIoProtocolGuid
,
231 if (!EFI_ERROR (Status
)) {
233 // Skip if the file system handle supports a BlkIo protocol, which we've handled in above
237 BootOptions
= ReallocatePool (
238 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
239 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
242 ASSERT (BootOptions
!= NULL
);
244 Status
= EfiBootManagerInitializeLoadOption (
245 &BootOptions
[(*BootOptionCount
)++],
246 LoadOptionNumberUnassigned
,
250 DevicePathFromHandle (Handles
[Index
]),
254 ASSERT_EFI_ERROR (Status
);
257 if (HandleCount
!= 0) {
262 // Parse load file, assuming UEFI Network boot option
264 gBS
->LocateHandleBuffer (
266 &gEfiLoadFileProtocolGuid
,
271 for (Index
= 0; Index
< HandleCount
; Index
++) {
273 BootOptions
= ReallocatePool (
274 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
),
275 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION
) * (*BootOptionCount
+ 1),
278 ASSERT (BootOptions
!= NULL
);
280 Status
= EfiBootManagerInitializeLoadOption (
281 &BootOptions
[(*BootOptionCount
)++],
282 LoadOptionNumberUnassigned
,
286 DevicePathFromHandle (Handles
[Index
]),
290 ASSERT_EFI_ERROR (Status
);
293 if (HandleCount
!= 0) {
301 Function waits for a given event to fire, or for an optional timeout to expire.
303 @param Event The event to wait for
304 @param Timeout An optional timeout value in 100 ns units.
306 @retval EFI_SUCCESS Event fired before Timeout expired.
307 @retval EFI_TIME_OUT Timout expired before Event fired..
311 BdsWaitForSingleEvent (
313 IN UINT64 Timeout OPTIONAL
318 EFI_EVENT TimerEvent
;
319 EFI_EVENT WaitList
[2];
323 // Create a timer event
325 Status
= gBS
->CreateEvent (EVT_TIMER
, 0, NULL
, NULL
, &TimerEvent
);
326 if (!EFI_ERROR (Status
)) {
328 // Set the timer event
337 // Wait for the original event or the timer
340 WaitList
[1] = TimerEvent
;
341 Status
= gBS
->WaitForEvent (2, WaitList
, &Index
);
342 ASSERT_EFI_ERROR (Status
);
343 gBS
->CloseEvent (TimerEvent
);
346 // If the timer expired, change the return to timed out
349 Status
= EFI_TIMEOUT
;
354 // No timeout... just wait on the event
356 Status
= gBS
->WaitForEvent (1, &Event
, &Index
);
357 ASSERT (!EFI_ERROR (Status
));
365 The function reads user inputs.
376 if (PcdGetBool (PcdConInConnectOnDemand
)) {
380 while (gST
->ConIn
!= NULL
) {
382 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
384 if (EFI_ERROR (Status
)) {
394 The function waits for the boot manager timeout expires or hotkey is pressed.
396 It calls PlatformBootManagerWaitCallback each second.
398 @param HotkeyTriggered Input hotkey event.
402 IN EFI_EVENT HotkeyTriggered
406 UINT16 TimeoutRemain
;
408 DEBUG ((EFI_D_INFO
, "[Bds]BdsWait ...Zzzzzzzzzzzz...\n"));
410 TimeoutRemain
= PcdGet16 (PcdPlatformBootTimeOut
);
411 while (TimeoutRemain
!= 0) {
412 DEBUG ((EFI_D_INFO
, "[Bds]BdsWait(%d)..Zzzz...\n", (UINTN
) TimeoutRemain
));
413 PlatformBootManagerWaitCallback (TimeoutRemain
);
415 BdsReadKeys (); // BUGBUG: Only reading can signal HotkeyTriggered
416 // Can be removed after all keyboard drivers invoke callback in timer callback.
418 if (HotkeyTriggered
!= NULL
) {
419 Status
= BdsWaitForSingleEvent (HotkeyTriggered
, EFI_TIMER_PERIOD_SECONDS (1));
420 if (!EFI_ERROR (Status
)) {
424 gBS
->Stall (1000000);
428 // 0xffff means waiting forever
429 // BDS with no hotkey provided and 0xffff as timeout will "hang" in the loop
431 if (TimeoutRemain
!= 0xffff) {
435 DEBUG ((EFI_D_INFO
, "[Bds]Exit the waiting!\n"));
439 Attempt to boot each boot option in the BootOptions array.
441 @param BootOptions Input boot option array.
442 @param BootOptionCount Input boot option count.
444 @retval TRUE Successfully boot one of the boot options.
445 @retval FALSE Failed boot any of the boot options.
449 IN EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
,
450 IN UINTN BootOptionCount
456 // Attempt boot each boot option
458 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
460 // According to EFI Specification, if a load option is not marked
461 // as LOAD_OPTION_ACTIVE, the boot manager will not automatically
464 if ((BootOptions
[Index
].Attributes
& LOAD_OPTION_ACTIVE
) == 0) {
469 // Boot#### load options with LOAD_OPTION_CATEGORY_APP are executables which are not
470 // part of the normal boot processing. Boot options with reserved category values will be
471 // ignored by the boot manager.
473 if ((BootOptions
[Index
].Attributes
& LOAD_OPTION_CATEGORY
) != LOAD_OPTION_CATEGORY_BOOT
) {
478 // All the driver options should have been processed since
479 // now boot will be performed.
481 EfiBootManagerBoot (&BootOptions
[Index
]);
484 // Successful boot breaks the loop, otherwise tries next boot option
486 if (BootOptions
[Index
].Status
== EFI_SUCCESS
) {
491 return (BOOLEAN
) (Index
< BootOptionCount
);
495 This function attempts to boot per the boot order specified by platform policy.
497 If the boot via Boot#### returns with a status of EFI_SUCCESS the boot manager will stop
498 processing the BootOrder variable and present a boot manager menu to the user. If a boot via
499 Boot#### returns a status other than EFI_SUCCESS, the boot has failed and the next Boot####
500 in the BootOrder variable will be tried until all possibilities are exhausted.
501 -- Chapter 3.1.1 Boot Manager Programming, the 4th paragraph
504 DefaultBootBehavior (
508 UINTN BootOptionCount
;
509 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
510 EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu
;
512 EfiBootManagerGetBootManagerMenu (&BootManagerMenu
);
514 // BootManagerMenu always contains the correct information even the above function returns failure.
517 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
519 if (BootAllBootOptions (BootOptions
, BootOptionCount
)) {
521 // Follow generic rule, Call BdsDxeOnConnectConInCallBack to connect ConIn before enter UI
523 if (PcdGetBool (PcdConInConnectOnDemand
)) {
524 BdsDxeOnConnectConInCallBack (NULL
, NULL
);
528 // Show the Boot Manager Menu after successful boot
530 EfiBootManagerBoot (&BootManagerMenu
);
532 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
534 // Re-scan all EFI boot options in case all the boot#### are deleted or failed to boot
536 // If no valid boot options exist, the boot manager will enumerate all removable media
537 // devices followed by all fixed media devices. The order within each group is undefined.
538 // These new default boot options are not saved to non volatile storage.The boot manger
539 // will then attempt toboot from each boot option.
540 // -- Chapter 3.3 Boot Manager Programming, the 2nd paragraph
542 EfiBootManagerConnectAll ();
543 BootOptions
= BdsEnumerateBootOptions (&BootOptionCount
);
545 if (!BootAllBootOptions (BootOptions
, BootOptionCount
)) {
546 DEBUG ((EFI_D_ERROR
, "[Bds]No bootable device!\n"));
547 EfiBootManagerBoot (&BootManagerMenu
);
551 EfiBootManagerFreeLoadOption (&BootManagerMenu
);
552 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
556 The function will go through the driver option link list, load and start
557 every driver the driver option device path point to.
559 @param DriverOption Input driver option array.
560 @param DriverOptionCount Input driver option count.
565 IN EFI_BOOT_MANAGER_LOAD_OPTION
*DriverOption
,
566 IN UINTN DriverOptionCount
571 EFI_HANDLE ImageHandle
;
572 EFI_LOADED_IMAGE_PROTOCOL
*ImageInfo
;
573 BOOLEAN ReconnectAll
;
575 ReconnectAll
= FALSE
;
578 // Process the driver option
580 for (Index
= 0; Index
< DriverOptionCount
; Index
++) {
582 // If a load option is not marked as LOAD_OPTION_ACTIVE,
583 // the boot manager will not automatically load the option.
585 if ((DriverOption
[Index
].Attributes
& LOAD_OPTION_ACTIVE
) == 0) {
590 // If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT,
591 // then all of the EFI drivers in the system will be disconnected and
592 // reconnected after the last driver load option is processed.
594 if ((DriverOption
[Index
].Attributes
& LOAD_OPTION_FORCE_RECONNECT
) != 0) {
599 // Make sure the driver path is connected.
601 EfiBootManagerConnectDevicePath (DriverOption
[Index
].FilePath
, NULL
);
604 // Load and start the image that Driver#### describes
606 Status
= gBS
->LoadImage (
609 DriverOption
[Index
].FilePath
,
615 if (!EFI_ERROR (Status
)) {
616 gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**) &ImageInfo
);
619 // Verify whether this image is a driver, if not,
620 // exit it and continue to parse next load option
622 if (ImageInfo
->ImageCodeType
!= EfiBootServicesCode
&& ImageInfo
->ImageCodeType
!= EfiRuntimeServicesCode
) {
623 gBS
->Exit (ImageHandle
, EFI_INVALID_PARAMETER
, 0, NULL
);
627 ImageInfo
->LoadOptionsSize
= DriverOption
[Index
].OptionalDataSize
;
628 ImageInfo
->LoadOptions
= DriverOption
[Index
].OptionalData
;
630 // Before calling the image, enable the Watchdog Timer for
631 // the 5 Minute period
633 gBS
->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL
);
635 DriverOption
[Index
].Status
= gBS
->StartImage (ImageHandle
, &DriverOption
[Index
].ExitDataSize
, &DriverOption
[Index
].ExitData
);
636 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Driver Return Status = %r\n", DriverOption
[Index
].Status
));
639 // Clear the Watchdog Timer after the image returns
641 gBS
->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL
);
646 // Process the LOAD_OPTION_FORCE_RECONNECT driver option
649 EfiBootManagerDisconnectAll ();
650 EfiBootManagerConnectAll ();
657 Validate input console variable data.
659 If found the device path is not a valid device path, remove the variable.
661 @param VariableName Input console variable name.
665 BdsFormalizeConsoleVariable (
666 IN CHAR16
*VariableName
669 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
673 GetEfiGlobalVariable2 (VariableName
, (VOID
**) &DevicePath
, &VariableSize
);
674 if ((DevicePath
!= NULL
) && !IsDevicePathValid (DevicePath
, VariableSize
)) {
675 Status
= gRT
->SetVariable (
677 &gEfiGlobalVariableGuid
,
678 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
683 // Deleting variable with current variable implementation shouldn't fail.
685 ASSERT_EFI_ERROR (Status
);
688 if (DevicePath
!= NULL
) {
689 FreePool (DevicePath
);
694 Formalize OsIndication related variables.
696 For OsIndicationsSupported, Create a BS/RT/UINT64 variable to report caps
697 Delete OsIndications variable if it is not NV/BS/RT UINT64.
699 Item 3 is used to solve case when OS corrupts OsIndications. Here simply delete this NV variable.
703 BdsFormalizeOSIndicationVariable (
708 UINT64 OsIndicationSupport
;
714 // OS indicater support variable
716 OsIndicationSupport
= EFI_OS_INDICATIONS_BOOT_TO_FW_UI
;
717 Status
= gRT
->SetVariable (
718 L
"OsIndicationsSupported",
719 &gEfiGlobalVariableGuid
,
720 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
725 // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.
727 ASSERT_EFI_ERROR (Status
);
730 // If OsIndications is invalid, remove it.
732 // 1. Data size != UINT64
733 // 2. OsIndication value inconsistence
734 // 3. OsIndication attribute inconsistence
738 DataSize
= sizeof(UINT64
);
739 Status
= gRT
->GetVariable (
741 &gEfiGlobalVariableGuid
,
746 if (Status
== EFI_NOT_FOUND
) {
750 if ((DataSize
!= sizeof (OsIndication
)) ||
751 ((OsIndication
& ~OsIndicationSupport
) != 0) ||
752 (Attributes
!= (EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
))
755 DEBUG ((EFI_D_ERROR
, "[Bds] Unformalized OsIndications variable exists. Delete it\n"));
756 Status
= gRT
->SetVariable (
758 &gEfiGlobalVariableGuid
,
764 // Deleting variable with current variable implementation shouldn't fail.
766 ASSERT_EFI_ERROR(Status
);
776 BdsFormalizeEfiGlobalVariable (
781 // Validate Console variable.
783 BdsFormalizeConsoleVariable (L
"ConIn");
784 BdsFormalizeConsoleVariable (L
"ConOut");
785 BdsFormalizeConsoleVariable (L
"ErrOut");
788 // Validate OSIndication related variable.
790 BdsFormalizeOSIndicationVariable ();
795 Allocate a block of memory that will contain performance data to OS.
799 BdsAllocateMemoryForPerformanceData (
804 EFI_PHYSICAL_ADDRESS AcpiLowMemoryBase
;
805 EDKII_VARIABLE_LOCK_PROTOCOL
*VariableLock
;
807 AcpiLowMemoryBase
= 0x0FFFFFFFFULL
;
810 // Allocate a block of memory that will contain performance data to OS.
812 Status
= gBS
->AllocatePages (
814 EfiReservedMemoryType
,
815 EFI_SIZE_TO_PAGES (PERF_DATA_MAX_LENGTH
),
818 if (!EFI_ERROR (Status
)) {
820 // Save the pointer to variable for use in S3 resume.
822 Status
= BdsDxeSetVariableAndReportStatusCodeOnError (
824 &gPerformanceProtocolGuid
,
825 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
826 sizeof (EFI_PHYSICAL_ADDRESS
),
829 if (EFI_ERROR (Status
)) {
830 DEBUG ((EFI_D_ERROR
, "[Bds] PerfDataMemAddr (%08x) cannot be saved to NV storage.\n", AcpiLowMemoryBase
));
833 // Mark L"PerfDataMemAddr" variable to read-only if the Variable Lock protocol exists
834 // Still lock it even the variable cannot be saved to prevent it's set by 3rd party code.
836 Status
= gBS
->LocateProtocol (&gEdkiiVariableLockProtocolGuid
, NULL
, (VOID
**) &VariableLock
);
837 if (!EFI_ERROR (Status
)) {
838 Status
= VariableLock
->RequestToLock (VariableLock
, L
"PerfDataMemAddr", &gPerformanceProtocolGuid
);
839 ASSERT_EFI_ERROR (Status
);
846 Service routine for BdsInstance->Entry(). Devices are connected, the
847 consoles are initialized, and the boot options are tried.
849 @param This Protocol Instance structure.
855 IN EFI_BDS_ARCH_PROTOCOL
*This
858 EFI_BOOT_MANAGER_LOAD_OPTION
*DriverOption
;
859 EFI_BOOT_MANAGER_LOAD_OPTION BootOption
;
860 UINTN DriverOptionCount
;
861 CHAR16
*FirmwareVendor
;
862 EFI_EVENT HotkeyTriggered
;
866 UINT32 BootOptionSupport
;
868 EDKII_VARIABLE_LOCK_PROTOCOL
*VariableLock
;
871 CHAR16 BootNextVariableName
[sizeof ("Boot####")];
873 HotkeyTriggered
= NULL
;
874 Status
= EFI_SUCCESS
;
877 // Insert the performance probe
879 PERF_END (NULL
, "DXE", NULL
, 0);
880 PERF_START (NULL
, "BDS", NULL
, 0);
881 DEBUG ((EFI_D_INFO
, "[Bds] Entry...\n"));
884 BdsAllocateMemoryForPerformanceData ();
888 // Fill in FirmwareVendor and FirmwareRevision from PCDs
890 FirmwareVendor
= (CHAR16
*) PcdGetPtr (PcdFirmwareVendor
);
891 gST
->FirmwareVendor
= AllocateRuntimeCopyPool (StrSize (FirmwareVendor
), FirmwareVendor
);
892 ASSERT (gST
->FirmwareVendor
!= NULL
);
893 gST
->FirmwareRevision
= PcdGet32 (PcdFirmwareRevision
);
896 // Fixup Tasble CRC after we updated Firmware Vendor and Revision
899 gBS
->CalculateCrc32 ((VOID
*) gST
, sizeof (EFI_SYSTEM_TABLE
), &gST
->Hdr
.CRC32
);
902 // Validate Variable.
904 BdsFormalizeEfiGlobalVariable ();
907 // Mark the read-only variables if the Variable Lock protocol exists
909 Status
= gBS
->LocateProtocol (&gEdkiiVariableLockProtocolGuid
, NULL
, (VOID
**) &VariableLock
);
910 DEBUG ((EFI_D_INFO
, "[BdsDxe] Locate Variable Lock protocol - %r\n", Status
));
911 if (!EFI_ERROR (Status
)) {
912 for (Index
= 0; Index
< sizeof (mReadOnlyVariables
) / sizeof (mReadOnlyVariables
[0]); Index
++) {
913 Status
= VariableLock
->RequestToLock (VariableLock
, mReadOnlyVariables
[Index
], &gEfiGlobalVariableGuid
);
914 ASSERT_EFI_ERROR (Status
);
918 InitializeHwErrRecSupport ();
921 // Initialize L"Timeout" EFI global variable.
923 BootTimeOut
= PcdGet16 (PcdPlatformBootTimeOut
);
924 if (BootTimeOut
!= 0xFFFF) {
926 // If time out value equal 0xFFFF, no need set to 0xFFFF to variable area because UEFI specification
927 // define same behavior between no value or 0xFFFF value for L"Timeout".
929 BdsDxeSetVariableAndReportStatusCodeOnError (
930 EFI_TIME_OUT_VARIABLE_NAME
,
931 &gEfiGlobalVariableGuid
,
932 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
939 // Initialize L"BootOptionSupport" EFI global variable.
940 // Lazy-ConIn implictly disables BDS hotkey.
942 BootOptionSupport
= EFI_BOOT_OPTION_SUPPORT_APP
;
943 if (!PcdGetBool (PcdConInConnectOnDemand
)) {
944 BootOptionSupport
|= EFI_BOOT_OPTION_SUPPORT_KEY
;
945 SET_BOOT_OPTION_SUPPORT_KEY_COUNT (BootOptionSupport
, 3);
947 Status
= gRT
->SetVariable (
948 EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME
,
949 &gEfiGlobalVariableGuid
,
950 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
951 sizeof (BootOptionSupport
),
955 // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.
957 ASSERT_EFI_ERROR (Status
);
960 // Cache and remove the "BootNext" NV variable.
962 GetEfiGlobalVariable2 (EFI_BOOT_NEXT_VARIABLE_NAME
, (VOID
**) &BootNext
, &DataSize
);
963 if (DataSize
!= sizeof (UINT16
)) {
964 if (BootNext
!= NULL
) {
969 Status
= gRT
->SetVariable (
970 EFI_BOOT_NEXT_VARIABLE_NAME
,
971 &gEfiGlobalVariableGuid
,
977 // Deleting NV variable shouldn't fail unless it doesn't exist.
979 ASSERT (Status
== EFI_SUCCESS
|| Status
== EFI_NOT_FOUND
);
982 // Initialize the platform language variables
984 InitializeLanguage (TRUE
);
987 // Report Status Code to indicate connecting drivers will happen
991 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_PC_BEGIN_CONNECTING_DRIVERS
)
995 // Do the platform init, can be customized by OEM/IBV
996 // Possible things that can be done in PlatformBootManagerBeforeConsole:
997 // > Update console variable: 1. include hot-plug devices; 2. Clear ConIn and add SOL for AMT
998 // > Register new Driver#### or Boot####
999 // > Register new Key####: e.g.: F12
1000 // > Signal ReadyToLock event
1001 // > Authentication action: 1. connect Auth devices; 2. Identify auto logon user.
1003 PERF_START (NULL
, "PlatformBootManagerBeforeConsole", "BDS", 0);
1004 PlatformBootManagerBeforeConsole ();
1005 PERF_END (NULL
, "PlatformBootManagerBeforeConsole", "BDS", 0);
1008 // Initialize hotkey service
1010 EfiBootManagerStartHotkeyService (&HotkeyTriggered
);
1013 // Load Driver Options
1015 DriverOption
= EfiBootManagerGetLoadOptions (&DriverOptionCount
, LoadOptionTypeDriver
);
1016 LoadDrivers (DriverOption
, DriverOptionCount
);
1017 EfiBootManagerFreeLoadOptions (DriverOption
, DriverOptionCount
);
1022 PERF_START (NULL
, "EfiBootManagerConnectAllDefaultConsoles", "BDS", 0);
1023 if (PcdGetBool (PcdConInConnectOnDemand
)) {
1024 EfiBootManagerConnectConsoleVariable (ConOut
);
1025 EfiBootManagerConnectConsoleVariable (ErrOut
);
1028 // Initialize ConnectConIn event
1030 Status
= gBS
->CreateEventEx (
1033 BdsDxeOnConnectConInCallBack
,
1035 &gConnectConInEventGuid
,
1038 if (EFI_ERROR (Status
)) {
1039 gConnectConInEvent
= NULL
;
1042 EfiBootManagerConnectAllDefaultConsoles ();
1044 PERF_END (NULL
, "EfiBootManagerConnectAllDefaultConsoles", "BDS", 0);
1047 // Do the platform specific action after the console is ready
1048 // Possible things that can be done in PlatformBootManagerAfterConsole:
1049 // > Console post action:
1050 // > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
1051 // > Signal console ready platform customized event
1052 // > Run diagnostics like memory testing
1053 // > Connect certain devices
1054 // > Dispatch aditional option roms
1055 // > Special boot: e.g.: USB boot, enter UI
1057 PERF_START (NULL
, "PlatformBootManagerAfterConsole", "BDS", 0);
1058 PlatformBootManagerAfterConsole ();
1059 PERF_END (NULL
, "PlatformBootManagerAfterConsole", "BDS", 0);
1062 EFI_BOOT_MANAGER_LOAD_OPTION
*BootOptions
;
1063 UINTN BootOptionCount
;
1066 BootOptions
= EfiBootManagerGetLoadOptions (&BootOptionCount
, LoadOptionTypeBoot
);
1067 DEBUG ((EFI_D_INFO
, "[Bds]=============Dumping Boot Options=============\n"));
1068 for (Index
= 0; Index
< BootOptionCount
; Index
++) {
1070 EFI_D_INFO
, "[Bds]Boot%04x: %s \t\t 0x%04x\n",
1071 BootOptions
[Index
].OptionNumber
,
1072 BootOptions
[Index
].Description
,
1073 BootOptions
[Index
].Attributes
1076 DEBUG ((EFI_D_INFO
, "[Bds]=============Dumping Boot Options Finished====\n"));
1077 EfiBootManagerFreeLoadOptions (BootOptions
, BootOptionCount
);
1081 // Boot to Boot Manager Menu when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot
1083 DataSize
= sizeof (UINT64
);
1084 Status
= gRT
->GetVariable (
1086 &gEfiGlobalVariableGuid
,
1091 if (!EFI_ERROR(Status
) && ((OsIndication
& EFI_OS_INDICATIONS_BOOT_TO_FW_UI
) != 0)) {
1093 // Clear EFI_OS_INDICATIONS_BOOT_TO_FW_UI to acknowledge OS
1095 OsIndication
&= ~((UINT64
) EFI_OS_INDICATIONS_BOOT_TO_FW_UI
);
1096 Status
= gRT
->SetVariable (
1098 &gEfiGlobalVariableGuid
,
1099 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
1104 // Changing the content without increasing its size with current variable implementation shouldn't fail.
1106 ASSERT_EFI_ERROR (Status
);
1109 // Follow generic rule, Call BdsDxeOnConnectConInCallBack to connect ConIn before enter UI
1111 if (PcdGetBool (PcdConInConnectOnDemand
)) {
1112 BdsDxeOnConnectConInCallBack (NULL
, NULL
);
1116 // Directly boot to Boot Manager Menu.
1118 EfiBootManagerGetBootManagerMenu (&BootOption
);
1119 EfiBootManagerBoot (&BootOption
);
1120 EfiBootManagerFreeLoadOption (&BootOption
);
1122 PERF_START (NULL
, "BdsWait", "BDS", 0);
1123 BdsWait (HotkeyTriggered
);
1124 PERF_END (NULL
, "BdsWait", "BDS", 0);
1127 // BdsReadKeys() be removed after all keyboard drivers invoke callback in timer callback.
1131 EfiBootManagerHotkeyBoot ();
1135 // Boot to "BootNext"
1137 if (BootNext
!= NULL
) {
1138 UnicodeSPrint (BootNextVariableName
, sizeof (BootNextVariableName
), L
"Boot%04x", *BootNext
);
1139 Status
= EfiBootManagerVariableToLoadOption (BootNextVariableName
, &BootOption
);
1140 if (!EFI_ERROR (Status
)) {
1141 EfiBootManagerBoot (&BootOption
);
1142 EfiBootManagerFreeLoadOption (&BootOption
);
1143 if (BootOption
.Status
== EFI_SUCCESS
) {
1145 // Boot to Boot Manager Menu upon EFI_SUCCESS
1147 EfiBootManagerGetBootManagerMenu (&BootOption
);
1148 EfiBootManagerBoot (&BootOption
);
1149 EfiBootManagerFreeLoadOption (&BootOption
);
1156 // BDS select the boot device to load OS
1157 // Try next upon boot failure
1158 // Show Boot Manager Menu upon boot success
1160 DefaultBootBehavior ();
1165 Set the variable and report the error through status code upon failure.
1167 @param VariableName A Null-terminated string that is the name of the vendor's variable.
1168 Each VariableName is unique for each VendorGuid. VariableName must
1169 contain 1 or more characters. If VariableName is an empty string,
1170 then EFI_INVALID_PARAMETER is returned.
1171 @param VendorGuid A unique identifier for the vendor.
1172 @param Attributes Attributes bitmask to set for the variable.
1173 @param DataSize The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE,
1174 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or
1175 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero
1176 causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is
1177 set, then a SetVariable() call with a DataSize of zero will not cause any change to
1178 the variable value (the timestamp associated with the variable may be updated however
1179 even if no new data value is provided,see the description of the
1180 EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not
1181 be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated).
1182 @param Data The contents for the variable.
1184 @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
1185 defined by the Attributes.
1186 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, and GUID was supplied, or the
1187 DataSize exceeds the maximum allowed.
1188 @retval EFI_INVALID_PARAMETER VariableName is an empty string.
1189 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
1190 @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.
1191 @retval EFI_WRITE_PROTECTED The variable in question is read-only.
1192 @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.
1193 @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
1194 or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo
1195 does NOT pass the validation check carried out by the firmware.
1197 @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.
1200 BdsDxeSetVariableAndReportStatusCodeOnError (
1201 IN CHAR16
*VariableName
,
1202 IN EFI_GUID
*VendorGuid
,
1203 IN UINT32 Attributes
,
1209 EDKII_SET_VARIABLE_STATUS
*SetVariableStatus
;
1212 Status
= gRT
->SetVariable (
1219 if (EFI_ERROR (Status
)) {
1220 NameSize
= StrSize (VariableName
);
1221 SetVariableStatus
= AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS
) + NameSize
+ DataSize
);
1222 if (SetVariableStatus
!= NULL
) {
1223 CopyGuid (&SetVariableStatus
->Guid
, VendorGuid
);
1224 SetVariableStatus
->NameSize
= NameSize
;
1225 SetVariableStatus
->DataSize
= DataSize
;
1226 SetVariableStatus
->SetStatus
= Status
;
1227 SetVariableStatus
->Attributes
= Attributes
;
1228 CopyMem (SetVariableStatus
+ 1, VariableName
, NameSize
);
1229 CopyMem (((UINT8
*) (SetVariableStatus
+ 1)) + NameSize
, Data
, DataSize
);
1231 REPORT_STATUS_CODE_EX (
1233 PcdGet32 (PcdErrorCodeSetVariable
),
1236 &gEdkiiStatusCodeDataTypeVariableGuid
,
1238 sizeof (EDKII_SET_VARIABLE_STATUS
) + NameSize
+ DataSize
1241 FreePool (SetVariableStatus
);