--- /dev/null
+/** @file\r
+ This module produce main entry for BDS phase - BdsEntry.\r
+ When this module was dispatched by DxeCore, gEfiBdsArchProtocolGuid will be installed\r
+ which contains interface of BdsEntry.\r
+ After DxeCore finish DXE phase, gEfiBdsArchProtocolGuid->BdsEntry will be invoked\r
+ to enter BDS phase.\r
+\r
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "Bds.h"\r
+#include "Language.h"\r
+#include "HwErrRecSupport.h"\r
+\r
+#define SET_BOOT_OPTION_SUPPORT_KEY_COUNT(a, c) { \\r
+ (a) = ((a) & ~EFI_BOOT_OPTION_SUPPORT_COUNT) | (((c) << LowBitSet32 (EFI_BOOT_OPTION_SUPPORT_COUNT)) & EFI_BOOT_OPTION_SUPPORT_COUNT); \\r
+ }\r
+\r
+///\r
+/// BDS arch protocol instance initial value.\r
+///\r
+EFI_BDS_ARCH_PROTOCOL gBds = {\r
+ BdsEntry\r
+};\r
+\r
+//\r
+// gConnectConInEvent - Event which is signaled when ConIn connection is required\r
+//\r
+EFI_EVENT gConnectConInEvent = NULL;\r
+\r
+///\r
+/// The read-only variables defined in UEFI Spec.\r
+///\r
+CHAR16 *mReadOnlyVariables[] = {\r
+ EFI_PLATFORM_LANG_CODES_VARIABLE_NAME,\r
+ EFI_LANG_CODES_VARIABLE_NAME,\r
+ EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME,\r
+ EFI_HW_ERR_REC_SUPPORT_VARIABLE_NAME,\r
+ EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME\r
+ };\r
+\r
+CHAR16 mRecoveryBoot[] = L"Recovery Boot";\r
+/**\r
+ Event to Connect ConIn.\r
+\r
+ @param Event Event whose notification function is being invoked.\r
+ @param Context Pointer to the notification function's context,\r
+ which is implementation-dependent.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+BdsDxeOnConnectConInCallBack (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // When Osloader call ReadKeyStroke to signal this event\r
+ // no driver dependency is assumed existing. So use a non-dispatch version\r
+ //\r
+ Status = EfiBootManagerConnectConsoleVariable (ConIn);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Should not enter this case, if enter, the keyboard will not work.\r
+ // May need platfrom policy to connect keyboard.\r
+ //\r
+ DEBUG ((EFI_D_WARN, "[Bds] ASSERT Connect ConIn failed!!!\n"));\r
+ }\r
+}\r
+\r
+/**\r
+\r
+ Install Boot Device Selection Protocol\r
+\r
+ @param ImageHandle The image handle.\r
+ @param SystemTable The system table.\r
+\r
+ @retval EFI_SUCEESS BDS has finished initializing.\r
+ Return the dispatcher and recall BDS.Entry\r
+ @retval Other Return status from AllocatePool() or gBS->InstallProtocolInterface\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BdsInitialize (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE Handle;\r
+ //\r
+ // Install protocol interface\r
+ //\r
+ Handle = NULL;\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &Handle,\r
+ &gEfiBdsArchProtocolGuid, &gBds,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Emuerate all possible bootable medias in the following order:\r
+ 1. Removable BlockIo - The boot option only points to the removable media\r
+ device, like USB key, DVD, Floppy etc.\r
+ 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,\r
+ like HardDisk.\r
+ 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting\r
+ SimpleFileSystem Protocol, but not supporting BlockIo\r
+ protocol.\r
+ 4. LoadFile - The boot option points to the media supporting \r
+ LoadFile protocol.\r
+ Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior\r
+\r
+ @param BootOptionCount Return the boot option count which has been found.\r
+\r
+ @retval Pointer to the boot option array.\r
+**/\r
+EFI_BOOT_MANAGER_LOAD_OPTION *\r
+BdsEnumerateBootOptions (\r
+ UINTN *BootOptionCount\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
+ UINT16 NonBlockNumber;\r
+ UINTN HandleCount;\r
+ EFI_HANDLE *Handles;\r
+ EFI_BLOCK_IO_PROTOCOL *BlkIo;\r
+ UINTN Removable;\r
+ UINTN Index;\r
+\r
+ ASSERT (BootOptionCount != NULL);\r
+\r
+ *BootOptionCount = 0;\r
+ BootOptions = NULL;\r
+\r
+ //\r
+ // Parse removable block io followed by fixed block io\r
+ //\r
+ gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiBlockIoProtocolGuid,\r
+ NULL,\r
+ &HandleCount,\r
+ &Handles\r
+ );\r
+\r
+ for (Removable = 0; Removable < 2; Removable++) {\r
+ for (Index = 0; Index < HandleCount; Index++) {\r
+ Status = gBS->HandleProtocol (\r
+ Handles[Index],\r
+ &gEfiBlockIoProtocolGuid,\r
+ (VOID **) &BlkIo\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Skip the logical partitions\r
+ //\r
+ if (BlkIo->Media->LogicalPartition) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Skip the fixed block io then the removable block io\r
+ //\r
+ if (BlkIo->Media->RemovableMedia == ((Removable == 0) ? FALSE : TRUE)) {\r
+ continue;\r
+ }\r
+\r
+ BootOptions = ReallocatePool (\r
+ sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),\r
+ sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),\r
+ BootOptions\r
+ );\r
+ ASSERT (BootOptions != NULL);\r
+\r
+ Status = EfiBootManagerInitializeLoadOption (\r
+ &BootOptions[(*BootOptionCount)++],\r
+ LoadOptionNumberUnassigned,\r
+ LoadOptionTypeBoot,\r
+ LOAD_OPTION_ACTIVE,\r
+ mRecoveryBoot,\r
+ DevicePathFromHandle (Handles[Index]),\r
+ NULL,\r
+ 0\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+ }\r
+\r
+ if (HandleCount != 0) {\r
+ FreePool (Handles);\r
+ }\r
+\r
+ //\r
+ // Parse simple file system not based on block io\r
+ //\r
+ NonBlockNumber = 0;\r
+ gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiSimpleFileSystemProtocolGuid,\r
+ NULL,\r
+ &HandleCount,\r
+ &Handles\r
+ );\r
+ for (Index = 0; Index < HandleCount; Index++) {\r
+ Status = gBS->HandleProtocol (\r
+ Handles[Index],\r
+ &gEfiBlockIoProtocolGuid,\r
+ (VOID **) &BlkIo\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Skip if the file system handle supports a BlkIo protocol, which we've handled in above\r
+ //\r
+ continue;\r
+ }\r
+ BootOptions = ReallocatePool (\r
+ sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),\r
+ sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),\r
+ BootOptions\r
+ );\r
+ ASSERT (BootOptions != NULL);\r
+\r
+ Status = EfiBootManagerInitializeLoadOption (\r
+ &BootOptions[(*BootOptionCount)++],\r
+ LoadOptionNumberUnassigned,\r
+ LoadOptionTypeBoot,\r
+ LOAD_OPTION_ACTIVE,\r
+ mRecoveryBoot,\r
+ DevicePathFromHandle (Handles[Index]),\r
+ NULL,\r
+ 0\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+ if (HandleCount != 0) {\r
+ FreePool (Handles);\r
+ }\r
+\r
+ //\r
+ // Parse load file, assuming UEFI Network boot option\r
+ //\r
+ gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiLoadFileProtocolGuid,\r
+ NULL,\r
+ &HandleCount,\r
+ &Handles\r
+ );\r
+ for (Index = 0; Index < HandleCount; Index++) {\r
+\r
+ BootOptions = ReallocatePool (\r
+ sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),\r
+ sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),\r
+ BootOptions\r
+ );\r
+ ASSERT (BootOptions != NULL);\r
+\r
+ Status = EfiBootManagerInitializeLoadOption (\r
+ &BootOptions[(*BootOptionCount)++],\r
+ LoadOptionNumberUnassigned,\r
+ LoadOptionTypeBoot,\r
+ LOAD_OPTION_ACTIVE,\r
+ mRecoveryBoot,\r
+ DevicePathFromHandle (Handles[Index]),\r
+ NULL,\r
+ 0\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+ if (HandleCount != 0) {\r
+ FreePool (Handles);\r
+ }\r
+\r
+ return BootOptions;\r
+}\r
+\r
+/**\r
+ Function waits for a given event to fire, or for an optional timeout to expire.\r
+\r
+ @param Event The event to wait for\r
+ @param Timeout An optional timeout value in 100 ns units.\r
+\r
+ @retval EFI_SUCCESS Event fired before Timeout expired.\r
+ @retval EFI_TIME_OUT Timout expired before Event fired..\r
+\r
+**/\r
+EFI_STATUS\r
+BdsWaitForSingleEvent (\r
+ IN EFI_EVENT Event,\r
+ IN UINT64 Timeout OPTIONAL\r
+ )\r
+{\r
+ UINTN Index;\r
+ EFI_STATUS Status;\r
+ EFI_EVENT TimerEvent;\r
+ EFI_EVENT WaitList[2];\r
+\r
+ if (Timeout != 0) {\r
+ //\r
+ // Create a timer event\r
+ //\r
+ Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Set the timer event\r
+ //\r
+ gBS->SetTimer (\r
+ TimerEvent,\r
+ TimerRelative,\r
+ Timeout\r
+ );\r
+\r
+ //\r
+ // Wait for the original event or the timer\r
+ //\r
+ WaitList[0] = Event;\r
+ WaitList[1] = TimerEvent;\r
+ Status = gBS->WaitForEvent (2, WaitList, &Index);\r
+ ASSERT_EFI_ERROR (Status);\r
+ gBS->CloseEvent (TimerEvent);\r
+\r
+ //\r
+ // If the timer expired, change the return to timed out\r
+ //\r
+ if (Index == 1) {\r
+ Status = EFI_TIMEOUT;\r
+ }\r
+ }\r
+ } else {\r
+ //\r
+ // No timeout... just wait on the event\r
+ //\r
+ Status = gBS->WaitForEvent (1, &Event, &Index);\r
+ ASSERT (!EFI_ERROR (Status));\r
+ ASSERT (Index == 0);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ The function reads user inputs.\r
+\r
+**/\r
+VOID\r
+BdsReadKeys (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_INPUT_KEY Key;\r
+\r
+ if (PcdGetBool (PcdConInConnectOnDemand)) {\r
+ return;\r
+ }\r
+\r
+ while (gST->ConIn != NULL) {\r
+ \r
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
+ \r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // No more keys.\r
+ //\r
+ break;\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ The function waits for the boot manager timeout expires or hotkey is pressed.\r
+\r
+ It calls PlatformBootManagerWaitCallback each second.\r
+\r
+ @param HotkeyTriggered Input hotkey event.\r
+**/\r
+VOID\r
+BdsWait (\r
+ IN EFI_EVENT HotkeyTriggered\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT16 TimeoutRemain;\r
+\r
+ DEBUG ((EFI_D_INFO, "[Bds]BdsWait ...Zzzzzzzzzzzz...\n"));\r
+\r
+ TimeoutRemain = PcdGet16 (PcdPlatformBootTimeOut);\r
+ while (TimeoutRemain != 0) {\r
+ DEBUG ((EFI_D_INFO, "[Bds]BdsWait(%d)..Zzzz...\n", (UINTN) TimeoutRemain));\r
+ PlatformBootManagerWaitCallback (TimeoutRemain);\r
+\r
+ BdsReadKeys (); // BUGBUG: Only reading can signal HotkeyTriggered\r
+ // Can be removed after all keyboard drivers invoke callback in timer callback.\r
+\r
+ if (HotkeyTriggered != NULL) {\r
+ Status = BdsWaitForSingleEvent (HotkeyTriggered, EFI_TIMER_PERIOD_SECONDS (1));\r
+ if (!EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ } else {\r
+ gBS->Stall (1000000);\r
+ }\r
+\r
+ //\r
+ // 0xffff means waiting forever\r
+ // BDS with no hotkey provided and 0xffff as timeout will "hang" in the loop\r
+ //\r
+ if (TimeoutRemain != 0xffff) {\r
+ TimeoutRemain--;\r
+ }\r
+ }\r
+ DEBUG ((EFI_D_INFO, "[Bds]Exit the waiting!\n"));\r
+}\r
+\r
+/**\r
+ Attempt to boot each boot option in the BootOptions array.\r
+\r
+ @param BootOptions Input boot option array.\r
+ @param BootOptionCount Input boot option count.\r
+\r
+ @retval TRUE Successfully boot one of the boot options.\r
+ @retval FALSE Failed boot any of the boot options.\r
+**/\r
+BOOLEAN\r
+BootAllBootOptions (\r
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,\r
+ IN UINTN BootOptionCount\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ //\r
+ // Attempt boot each boot option\r
+ //\r
+ for (Index = 0; Index < BootOptionCount; Index++) {\r
+ //\r
+ // According to EFI Specification, if a load option is not marked\r
+ // as LOAD_OPTION_ACTIVE, the boot manager will not automatically\r
+ // load the option.\r
+ //\r
+ if ((BootOptions[Index].Attributes & LOAD_OPTION_ACTIVE) == 0) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Boot#### load options with LOAD_OPTION_CATEGORY_APP are executables which are not\r
+ // part of the normal boot processing. Boot options with reserved category values will be\r
+ // ignored by the boot manager.\r
+ //\r
+ if ((BootOptions[Index].Attributes & LOAD_OPTION_CATEGORY) != LOAD_OPTION_CATEGORY_BOOT) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // All the driver options should have been processed since\r
+ // now boot will be performed.\r
+ //\r
+ EfiBootManagerBoot (&BootOptions[Index]);\r
+\r
+ //\r
+ // Successful boot breaks the loop, otherwise tries next boot option\r
+ //\r
+ if (BootOptions[Index].Status == EFI_SUCCESS) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ return (BOOLEAN) (Index < BootOptionCount);\r
+}\r
+\r
+/**\r
+ This function attempts to boot per the boot order specified by platform policy.\r
+\r
+ If the boot via Boot#### returns with a status of EFI_SUCCESS the boot manager will stop \r
+ processing the BootOrder variable and present a boot manager menu to the user. If a boot via \r
+ Boot#### returns a status other than EFI_SUCCESS, the boot has failed and the next Boot####\r
+ in the BootOrder variable will be tried until all possibilities are exhausted.\r
+ -- Chapter 3.1.1 Boot Manager Programming, the 4th paragraph\r
+**/\r
+VOID\r
+DefaultBootBehavior (\r
+ VOID\r
+ )\r
+{\r
+ UINTN BootOptionCount;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;\r
+\r
+ EfiBootManagerGetBootManagerMenu (&BootManagerMenu);\r
+ //\r
+ // BootManagerMenu always contains the correct information even the above function returns failure.\r
+ //\r
+\r
+ BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
+\r
+ if (BootAllBootOptions (BootOptions, BootOptionCount)) {\r
+ //\r
+ // Follow generic rule, Call BdsDxeOnConnectConInCallBack to connect ConIn before enter UI\r
+ //\r
+ if (PcdGetBool (PcdConInConnectOnDemand)) {\r
+ BdsDxeOnConnectConInCallBack (NULL, NULL);\r
+ }\r
+\r
+ //\r
+ // Show the Boot Manager Menu after successful boot\r
+ //\r
+ EfiBootManagerBoot (&BootManagerMenu);\r
+ } else {\r
+ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
+ //\r
+ // Re-scan all EFI boot options in case all the boot#### are deleted or failed to boot\r
+ //\r
+ // If no valid boot options exist, the boot manager will enumerate all removable media\r
+ // devices followed by all fixed media devices. The order within each group is undefined.\r
+ // These new default boot options are not saved to non volatile storage.The boot manger\r
+ // will then attempt toboot from each boot option.\r
+ // -- Chapter 3.3 Boot Manager Programming, the 2nd paragraph\r
+ //\r
+ EfiBootManagerConnectAll ();\r
+ BootOptions = BdsEnumerateBootOptions (&BootOptionCount);\r
+\r
+ if (!BootAllBootOptions (BootOptions, BootOptionCount)) {\r
+ DEBUG ((EFI_D_ERROR, "[Bds]No bootable device!\n"));\r
+ EfiBootManagerBoot (&BootManagerMenu);\r
+ }\r
+ }\r
+\r
+ EfiBootManagerFreeLoadOption (&BootManagerMenu);\r
+ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
+}\r
+\r
+/**\r
+ The function will go through the driver option link list, load and start\r
+ every driver the driver option device path point to.\r
+\r
+ @param DriverOption Input driver option array.\r
+ @param DriverOptionCount Input driver option count.\r
+\r
+**/\r
+VOID\r
+LoadDrivers (\r
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *DriverOption,\r
+ IN UINTN DriverOptionCount\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ EFI_HANDLE ImageHandle;\r
+ EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;\r
+ BOOLEAN ReconnectAll;\r
+\r
+ ReconnectAll = FALSE;\r
+\r
+ //\r
+ // Process the driver option\r
+ //\r
+ for (Index = 0; Index < DriverOptionCount; Index++) {\r
+ //\r
+ // If a load option is not marked as LOAD_OPTION_ACTIVE,\r
+ // the boot manager will not automatically load the option.\r
+ //\r
+ if ((DriverOption[Index].Attributes & LOAD_OPTION_ACTIVE) == 0) {\r
+ continue;\r
+ }\r
+ \r
+ //\r
+ // If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT,\r
+ // then all of the EFI drivers in the system will be disconnected and\r
+ // reconnected after the last driver load option is processed.\r
+ //\r
+ if ((DriverOption[Index].Attributes & LOAD_OPTION_FORCE_RECONNECT) != 0) {\r
+ ReconnectAll = TRUE;\r
+ }\r
+ \r
+ //\r
+ // Make sure the driver path is connected.\r
+ //\r
+ EfiBootManagerConnectDevicePath (DriverOption[Index].FilePath, NULL);\r
+\r
+ //\r
+ // Load and start the image that Driver#### describes\r
+ //\r
+ Status = gBS->LoadImage (\r
+ FALSE,\r
+ gImageHandle,\r
+ DriverOption[Index].FilePath,\r
+ NULL,\r
+ 0,\r
+ &ImageHandle\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);\r
+\r
+ //\r
+ // Verify whether this image is a driver, if not,\r
+ // exit it and continue to parse next load option\r
+ //\r
+ if (ImageInfo->ImageCodeType != EfiBootServicesCode && ImageInfo->ImageCodeType != EfiRuntimeServicesCode) {\r
+ gBS->Exit (ImageHandle, EFI_INVALID_PARAMETER, 0, NULL);\r
+ continue;\r
+ }\r
+\r
+ ImageInfo->LoadOptionsSize = DriverOption[Index].OptionalDataSize;\r
+ ImageInfo->LoadOptions = DriverOption[Index].OptionalData;\r
+ //\r
+ // Before calling the image, enable the Watchdog Timer for\r
+ // the 5 Minute period\r
+ //\r
+ gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);\r
+\r
+ DriverOption[Index].Status = gBS->StartImage (ImageHandle, &DriverOption[Index].ExitDataSize, &DriverOption[Index].ExitData);\r
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Driver Return Status = %r\n", DriverOption[Index].Status));\r
+\r
+ //\r
+ // Clear the Watchdog Timer after the image returns\r
+ //\r
+ gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);\r
+ }\r
+ }\r
+ \r
+ //\r
+ // Process the LOAD_OPTION_FORCE_RECONNECT driver option\r
+ //\r
+ if (ReconnectAll) {\r
+ EfiBootManagerDisconnectAll ();\r
+ EfiBootManagerConnectAll ();\r
+ }\r
+\r
+}\r
+\r
+/**\r
+\r
+ Validate input console variable data. \r
+\r
+ If found the device path is not a valid device path, remove the variable.\r
+ \r
+ @param VariableName Input console variable name.\r
+\r
+**/\r
+VOID\r
+BdsFormalizeConsoleVariable (\r
+ IN CHAR16 *VariableName\r
+ )\r
+{\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ UINTN VariableSize;\r
+ EFI_STATUS Status;\r
+\r
+ GetEfiGlobalVariable2 (VariableName, (VOID **) &DevicePath, &VariableSize);\r
+ if ((DevicePath != NULL) && !IsDevicePathValid (DevicePath, VariableSize)) { \r
+ Status = gRT->SetVariable (\r
+ VariableName,\r
+ &gEfiGlobalVariableGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+ 0,\r
+ NULL\r
+ );\r
+ //\r
+ // Deleting variable with current variable implementation shouldn't fail.\r
+ //\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+ if (DevicePath != NULL) {\r
+ FreePool (DevicePath);\r
+ }\r
+}\r
+\r
+/**\r
+ Formalize OsIndication related variables. \r
+ \r
+ For OsIndicationsSupported, Create a BS/RT/UINT64 variable to report caps \r
+ Delete OsIndications variable if it is not NV/BS/RT UINT64.\r
+ \r
+ Item 3 is used to solve case when OS corrupts OsIndications. Here simply delete this NV variable.\r
+\r
+**/\r
+VOID \r
+BdsFormalizeOSIndicationVariable (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 OsIndicationSupport;\r
+ UINT64 OsIndication;\r
+ UINTN DataSize;\r
+ UINT32 Attributes;\r
+\r
+ //\r
+ // OS indicater support variable\r
+ //\r
+ OsIndicationSupport = EFI_OS_INDICATIONS_BOOT_TO_FW_UI;\r
+ Status = gRT->SetVariable (\r
+ L"OsIndicationsSupported",\r
+ &gEfiGlobalVariableGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+ sizeof(UINT64),\r
+ &OsIndicationSupport\r
+ );\r
+ //\r
+ // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.\r
+ //\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // If OsIndications is invalid, remove it.\r
+ // Invalid case\r
+ // 1. Data size != UINT64\r
+ // 2. OsIndication value inconsistence\r
+ // 3. OsIndication attribute inconsistence\r
+ //\r
+ OsIndication = 0;\r
+ Attributes = 0;\r
+ DataSize = sizeof(UINT64);\r
+ Status = gRT->GetVariable (\r
+ L"OsIndications",\r
+ &gEfiGlobalVariableGuid,\r
+ &Attributes,\r
+ &DataSize,\r
+ &OsIndication\r
+ );\r
+ if (Status == EFI_NOT_FOUND) {\r
+ return;\r
+ }\r
+\r
+ if ((DataSize != sizeof (OsIndication)) ||\r
+ ((OsIndication & ~OsIndicationSupport) != 0) ||\r
+ (Attributes != (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE))\r
+ ){\r
+\r
+ DEBUG ((EFI_D_ERROR, "[Bds] Unformalized OsIndications variable exists. Delete it\n"));\r
+ Status = gRT->SetVariable (\r
+ L"OsIndications",\r
+ &gEfiGlobalVariableGuid,\r
+ 0,\r
+ 0,\r
+ NULL\r
+ );\r
+ //\r
+ // Deleting variable with current variable implementation shouldn't fail.\r
+ //\r
+ ASSERT_EFI_ERROR(Status);\r
+ }\r
+}\r
+\r
+/**\r
+\r
+ Validate variables. \r
+\r
+**/\r
+VOID \r
+BdsFormalizeEfiGlobalVariable (\r
+ VOID\r
+ )\r
+{\r
+ //\r
+ // Validate Console variable.\r
+ //\r
+ BdsFormalizeConsoleVariable (L"ConIn");\r
+ BdsFormalizeConsoleVariable (L"ConOut");\r
+ BdsFormalizeConsoleVariable (L"ErrOut");\r
+\r
+ //\r
+ // Validate OSIndication related variable.\r
+ //\r
+ BdsFormalizeOSIndicationVariable ();\r
+}\r
+\r
+/**\r
+\r
+ Allocate a block of memory that will contain performance data to OS.\r
+\r
+**/\r
+VOID\r
+BdsAllocateMemoryForPerformanceData (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS AcpiLowMemoryBase;\r
+ EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;\r
+\r
+ AcpiLowMemoryBase = 0x0FFFFFFFFULL;\r
+\r
+ //\r
+ // Allocate a block of memory that will contain performance data to OS.\r
+ //\r
+ Status = gBS->AllocatePages (\r
+ AllocateMaxAddress,\r
+ EfiReservedMemoryType,\r
+ EFI_SIZE_TO_PAGES (PERF_DATA_MAX_LENGTH),\r
+ &AcpiLowMemoryBase\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Save the pointer to variable for use in S3 resume.\r
+ //\r
+ Status = BdsDxeSetVariableAndReportStatusCodeOnError (\r
+ L"PerfDataMemAddr",\r
+ &gPerformanceProtocolGuid,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+ sizeof (EFI_PHYSICAL_ADDRESS),\r
+ &AcpiLowMemoryBase\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "[Bds] PerfDataMemAddr (%08x) cannot be saved to NV storage.\n", AcpiLowMemoryBase));\r
+ }\r
+ //\r
+ // Mark L"PerfDataMemAddr" variable to read-only if the Variable Lock protocol exists\r
+ // Still lock it even the variable cannot be saved to prevent it's set by 3rd party code.\r
+ //\r
+ Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = VariableLock->RequestToLock (VariableLock, L"PerfDataMemAddr", &gPerformanceProtocolGuid);\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+\r
+ Service routine for BdsInstance->Entry(). Devices are connected, the\r
+ consoles are initialized, and the boot options are tried.\r
+\r
+ @param This Protocol Instance structure.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+BdsEntry (\r
+ IN EFI_BDS_ARCH_PROTOCOL *This\r
+ )\r
+{\r
+ EFI_BOOT_MANAGER_LOAD_OPTION *DriverOption;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION BootOption;\r
+ UINTN DriverOptionCount;\r
+ CHAR16 *FirmwareVendor;\r
+ EFI_EVENT HotkeyTriggered;\r
+ UINT64 OsIndication;\r
+ UINTN DataSize;\r
+ EFI_STATUS Status;\r
+ UINT32 BootOptionSupport;\r
+ UINT16 BootTimeOut;\r
+ EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;\r
+ UINTN Index;\r
+ UINT16 *BootNext;\r
+ CHAR16 BootNextVariableName[sizeof ("Boot####")];\r
+\r
+ HotkeyTriggered = NULL;\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // Insert the performance probe\r
+ //\r
+ PERF_END (NULL, "DXE", NULL, 0);\r
+ PERF_START (NULL, "BDS", NULL, 0);\r
+ DEBUG ((EFI_D_INFO, "[Bds] Entry...\n"));\r
+\r
+ PERF_CODE (\r
+ BdsAllocateMemoryForPerformanceData ();\r
+ );\r
+\r
+ //\r
+ // Fill in FirmwareVendor and FirmwareRevision from PCDs\r
+ //\r
+ FirmwareVendor = (CHAR16 *) PcdGetPtr (PcdFirmwareVendor);\r
+ gST->FirmwareVendor = AllocateRuntimeCopyPool (StrSize (FirmwareVendor), FirmwareVendor);\r
+ ASSERT (gST->FirmwareVendor != NULL);\r
+ gST->FirmwareRevision = PcdGet32 (PcdFirmwareRevision);\r
+\r
+ //\r
+ // Fixup Tasble CRC after we updated Firmware Vendor and Revision\r
+ //\r
+ gST->Hdr.CRC32 = 0;\r
+ gBS->CalculateCrc32 ((VOID *) gST, sizeof (EFI_SYSTEM_TABLE), &gST->Hdr.CRC32);\r
+\r
+ //\r
+ // Validate Variable.\r
+ //\r
+ BdsFormalizeEfiGlobalVariable ();\r
+\r
+ //\r
+ // Mark the read-only variables if the Variable Lock protocol exists\r
+ //\r
+ Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);\r
+ DEBUG ((EFI_D_INFO, "[BdsDxe] Locate Variable Lock protocol - %r\n", Status));\r
+ if (!EFI_ERROR (Status)) {\r
+ for (Index = 0; Index < sizeof (mReadOnlyVariables) / sizeof (mReadOnlyVariables[0]); Index++) {\r
+ Status = VariableLock->RequestToLock (VariableLock, mReadOnlyVariables[Index], &gEfiGlobalVariableGuid);\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+ }\r
+\r
+ InitializeHwErrRecSupport ();\r
+\r
+ //\r
+ // Initialize L"Timeout" EFI global variable.\r
+ //\r
+ BootTimeOut = PcdGet16 (PcdPlatformBootTimeOut);\r
+ if (BootTimeOut != 0xFFFF) {\r
+ //\r
+ // If time out value equal 0xFFFF, no need set to 0xFFFF to variable area because UEFI specification\r
+ // define same behavior between no value or 0xFFFF value for L"Timeout".\r
+ //\r
+ BdsDxeSetVariableAndReportStatusCodeOnError (\r
+ EFI_TIME_OUT_VARIABLE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+ sizeof (UINT16),\r
+ &BootTimeOut\r
+ );\r
+ }\r
+\r
+ //\r
+ // Initialize L"BootOptionSupport" EFI global variable.\r
+ // Lazy-ConIn implictly disables BDS hotkey.\r
+ //\r
+ BootOptionSupport = EFI_BOOT_OPTION_SUPPORT_APP;\r
+ if (!PcdGetBool (PcdConInConnectOnDemand)) {\r
+ BootOptionSupport |= EFI_BOOT_OPTION_SUPPORT_KEY;\r
+ SET_BOOT_OPTION_SUPPORT_KEY_COUNT (BootOptionSupport, 3);\r
+ }\r
+ Status = gRT->SetVariable (\r
+ EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+ sizeof (BootOptionSupport),\r
+ &BootOptionSupport\r
+ );\r
+ //\r
+ // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.\r
+ //\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Cache and remove the "BootNext" NV variable.\r
+ //\r
+ GetEfiGlobalVariable2 (EFI_BOOT_NEXT_VARIABLE_NAME, (VOID **) &BootNext, &DataSize);\r
+ if (DataSize != sizeof (UINT16)) {\r
+ if (BootNext != NULL) {\r
+ FreePool (BootNext);\r
+ }\r
+ BootNext = NULL;\r
+ }\r
+ Status = gRT->SetVariable (\r
+ EFI_BOOT_NEXT_VARIABLE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ 0,\r
+ 0,\r
+ NULL\r
+ );\r
+ //\r
+ // Deleting NV variable shouldn't fail unless it doesn't exist.\r
+ //\r
+ ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);\r
+\r
+ //\r
+ // Initialize the platform language variables\r
+ //\r
+ InitializeLanguage (TRUE);\r
+\r
+ //\r
+ // Report Status Code to indicate connecting drivers will happen\r
+ //\r
+ REPORT_STATUS_CODE (\r
+ EFI_PROGRESS_CODE,\r
+ (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_BEGIN_CONNECTING_DRIVERS)\r
+ );\r
+\r
+ //\r
+ // Do the platform init, can be customized by OEM/IBV\r
+ // Possible things that can be done in PlatformBootManagerBeforeConsole:\r
+ // > Update console variable: 1. include hot-plug devices; 2. Clear ConIn and add SOL for AMT\r
+ // > Register new Driver#### or Boot####\r
+ // > Register new Key####: e.g.: F12 \r
+ // > Signal ReadyToLock event\r
+ // > Authentication action: 1. connect Auth devices; 2. Identify auto logon user.\r
+ //\r
+ PERF_START (NULL, "PlatformBootManagerBeforeConsole", "BDS", 0);\r
+ PlatformBootManagerBeforeConsole ();\r
+ PERF_END (NULL, "PlatformBootManagerBeforeConsole", "BDS", 0);\r
+\r
+ //\r
+ // Initialize hotkey service\r
+ //\r
+ EfiBootManagerStartHotkeyService (&HotkeyTriggered);\r
+\r
+ //\r
+ // Load Driver Options\r
+ //\r
+ DriverOption = EfiBootManagerGetLoadOptions (&DriverOptionCount, LoadOptionTypeDriver);\r
+ LoadDrivers (DriverOption, DriverOptionCount);\r
+ EfiBootManagerFreeLoadOptions (DriverOption, DriverOptionCount);\r
+\r
+ //\r
+ // Connect consoles\r
+ //\r
+ PERF_START (NULL, "EfiBootManagerConnectAllDefaultConsoles", "BDS", 0);\r
+ if (PcdGetBool (PcdConInConnectOnDemand)) {\r
+ EfiBootManagerConnectConsoleVariable (ConOut);\r
+ EfiBootManagerConnectConsoleVariable (ErrOut);\r
+\r
+ //\r
+ // Initialize ConnectConIn event\r
+ //\r
+ Status = gBS->CreateEventEx (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ BdsDxeOnConnectConInCallBack,\r
+ NULL,\r
+ &gConnectConInEventGuid,\r
+ &gConnectConInEvent\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ gConnectConInEvent = NULL;\r
+ }\r
+ } else {\r
+ EfiBootManagerConnectAllDefaultConsoles ();\r
+ }\r
+ PERF_END (NULL, "EfiBootManagerConnectAllDefaultConsoles", "BDS", 0);\r
+\r
+ //\r
+ // Do the platform specific action after the console is ready\r
+ // Possible things that can be done in PlatformBootManagerAfterConsole:\r
+ // > Console post action:\r
+ // > Dynamically switch output mode from 100x31 to 80x25 for certain senarino\r
+ // > Signal console ready platform customized event\r
+ // > Run diagnostics like memory testing\r
+ // > Connect certain devices\r
+ // > Dispatch aditional option roms\r
+ // > Special boot: e.g.: USB boot, enter UI\r
+ // \r
+ PERF_START (NULL, "PlatformBootManagerAfterConsole", "BDS", 0);\r
+ PlatformBootManagerAfterConsole ();\r
+ PERF_END (NULL, "PlatformBootManagerAfterConsole", "BDS", 0);\r
+\r
+ DEBUG_CODE (\r
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
+ UINTN BootOptionCount;\r
+ UINTN Index;\r
+\r
+ BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
+ DEBUG ((EFI_D_INFO, "[Bds]=============Dumping Boot Options=============\n"));\r
+ for (Index = 0; Index < BootOptionCount; Index++) {\r
+ DEBUG ((\r
+ EFI_D_INFO, "[Bds]Boot%04x: %s \t\t 0x%04x\n",\r
+ BootOptions[Index].OptionNumber, \r
+ BootOptions[Index].Description, \r
+ BootOptions[Index].Attributes\r
+ ));\r
+ }\r
+ DEBUG ((EFI_D_INFO, "[Bds]=============Dumping Boot Options Finished====\n"));\r
+ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
+ );\r
+\r
+ //\r
+ // Boot to Boot Manager Menu when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot\r
+ //\r
+ DataSize = sizeof (UINT64);\r
+ Status = gRT->GetVariable (\r
+ L"OsIndications",\r
+ &gEfiGlobalVariableGuid,\r
+ NULL,\r
+ &DataSize,\r
+ &OsIndication\r
+ );\r
+ if (!EFI_ERROR(Status) && ((OsIndication & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) != 0)) {\r
+ //\r
+ // Clear EFI_OS_INDICATIONS_BOOT_TO_FW_UI to acknowledge OS\r
+ // \r
+ OsIndication &= ~((UINT64) EFI_OS_INDICATIONS_BOOT_TO_FW_UI);\r
+ Status = gRT->SetVariable (\r
+ L"OsIndications",\r
+ &gEfiGlobalVariableGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+ sizeof(UINT64),\r
+ &OsIndication\r
+ );\r
+ //\r
+ // Changing the content without increasing its size with current variable implementation shouldn't fail.\r
+ //\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Follow generic rule, Call BdsDxeOnConnectConInCallBack to connect ConIn before enter UI\r
+ //\r
+ if (PcdGetBool (PcdConInConnectOnDemand)) {\r
+ BdsDxeOnConnectConInCallBack (NULL, NULL);\r
+ }\r
+\r
+ //\r
+ // Directly boot to Boot Manager Menu.\r
+ //\r
+ EfiBootManagerGetBootManagerMenu (&BootOption);\r
+ EfiBootManagerBoot (&BootOption);\r
+ EfiBootManagerFreeLoadOption (&BootOption);\r
+ } else {\r
+ PERF_START (NULL, "BdsWait", "BDS", 0);\r
+ BdsWait (HotkeyTriggered);\r
+ PERF_END (NULL, "BdsWait", "BDS", 0);\r
+\r
+ //\r
+ // BdsReadKeys() be removed after all keyboard drivers invoke callback in timer callback.\r
+ //\r
+ BdsReadKeys ();\r
+ \r
+ EfiBootManagerHotkeyBoot ();\r
+ }\r
+\r
+ //\r
+ // Boot to "BootNext"\r
+ //\r
+ if (BootNext != NULL) {\r
+ UnicodeSPrint (BootNextVariableName, sizeof (BootNextVariableName), L"Boot%04x", *BootNext);\r
+ Status = EfiBootManagerVariableToLoadOption (BootNextVariableName, &BootOption);\r
+ if (!EFI_ERROR (Status)) {\r
+ EfiBootManagerBoot (&BootOption);\r
+ EfiBootManagerFreeLoadOption (&BootOption);\r
+ if (BootOption.Status == EFI_SUCCESS) {\r
+ //\r
+ // Boot to Boot Manager Menu upon EFI_SUCCESS\r
+ //\r
+ EfiBootManagerGetBootManagerMenu (&BootOption);\r
+ EfiBootManagerBoot (&BootOption);\r
+ EfiBootManagerFreeLoadOption (&BootOption);\r
+ }\r
+ }\r
+ }\r
+\r
+ while (TRUE) {\r
+ //\r
+ // BDS select the boot device to load OS\r
+ // Try next upon boot failure\r
+ // Show Boot Manager Menu upon boot success\r
+ //\r
+ DefaultBootBehavior ();\r
+ }\r
+}\r
+\r
+/**\r
+ Set the variable and report the error through status code upon failure.\r
+\r
+ @param VariableName A Null-terminated string that is the name of the vendor's variable.\r
+ Each VariableName is unique for each VendorGuid. VariableName must\r
+ contain 1 or more characters. If VariableName is an empty string,\r
+ then EFI_INVALID_PARAMETER is returned.\r
+ @param VendorGuid A unique identifier for the vendor.\r
+ @param Attributes Attributes bitmask to set for the variable.\r
+ @param DataSize The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE, \r
+ EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or \r
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero \r
+ causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is \r
+ set, then a SetVariable() call with a DataSize of zero will not cause any change to \r
+ the variable value (the timestamp associated with the variable may be updated however \r
+ even if no new data value is provided,see the description of the \r
+ EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not \r
+ be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated). \r
+ @param Data The contents for the variable.\r
+\r
+ @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as\r
+ defined by the Attributes.\r
+ @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, and GUID was supplied, or the\r
+ DataSize exceeds the maximum allowed.\r
+ @retval EFI_INVALID_PARAMETER VariableName is an empty string.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.\r
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.\r
+ @retval EFI_WRITE_PROTECTED The variable in question is read-only.\r
+ @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.\r
+ @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS \r
+ or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo \r
+ does NOT pass the validation check carried out by the firmware.\r
+\r
+ @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.\r
+**/\r
+EFI_STATUS\r
+BdsDxeSetVariableAndReportStatusCodeOnError (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid,\r
+ IN UINT32 Attributes,\r
+ IN UINTN DataSize,\r
+ IN VOID *Data\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EDKII_SET_VARIABLE_STATUS *SetVariableStatus;\r
+ UINTN NameSize;\r
+\r
+ Status = gRT->SetVariable (\r
+ VariableName,\r
+ VendorGuid,\r
+ Attributes,\r
+ DataSize,\r
+ Data\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ NameSize = StrSize (VariableName);\r
+ SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize);\r
+ if (SetVariableStatus != NULL) {\r
+ CopyGuid (&SetVariableStatus->Guid, VendorGuid);\r
+ SetVariableStatus->NameSize = NameSize;\r
+ SetVariableStatus->DataSize = DataSize;\r
+ SetVariableStatus->SetStatus = Status;\r
+ SetVariableStatus->Attributes = Attributes;\r
+ CopyMem (SetVariableStatus + 1, VariableName, NameSize);\r
+ CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Data, DataSize);\r
+\r
+ REPORT_STATUS_CODE_EX (\r
+ EFI_ERROR_CODE,\r
+ PcdGet32 (PcdErrorCodeSetVariable),\r
+ 0,\r
+ NULL,\r
+ &gEdkiiStatusCodeDataTypeVariableGuid,\r
+ SetVariableStatus,\r
+ sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize\r
+ );\r
+\r
+ FreePool (SetVariableStatus);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r