--- /dev/null
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation \r
+All rights reserved. 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
+Module Name:\r
+\r
+ BdsMisc.c\r
+\r
+Abstract:\r
+\r
+ Misc BDS library function\r
+\r
+--*/\r
+\r
+#define MAX_STRING_LEN 200\r
+static BOOLEAN mFeaturerSwitch = TRUE;\r
+static BOOLEAN mResetRequired = FALSE;\r
+extern UINT16 gPlatformBootTimeOutDefault;\r
+\r
+UINT16\r
+BdsLibGetTimeout (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ \r
+ Return the default value for system Timeout variable.\r
+\r
+Arguments:\r
+\r
+ None\r
+\r
+Returns:\r
+ \r
+ Timeout value.\r
+\r
+--*/\r
+{\r
+ UINT16 Timeout;\r
+ UINTN Size;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Return Timeout variable or 0xffff if no valid\r
+ // Timeout variable exists.\r
+ //\r
+ Size = sizeof (UINT16);\r
+ Status = gRT->GetVariable (L"Timeout", &gEfiGlobalVariableGuid, NULL, &Size, &Timeout);\r
+ if (!EFI_ERROR (Status)) {\r
+ return Timeout;\r
+ }\r
+ //\r
+ // To make the current EFI Automatic-Test activity possible, just add\r
+ // following code to make AutoBoot enabled when this variable is not\r
+ // present.\r
+ // This code should be removed later.\r
+ //\r
+ Timeout = gPlatformBootTimeOutDefault;\r
+\r
+ //\r
+ // Notes: Platform should set default variable if non exists on all error cases!!!\r
+ //\r
+ Status = gRT->SetVariable (\r
+ L"Timeout",\r
+ &gEfiGlobalVariableGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+ sizeof (UINT16),\r
+ &Timeout\r
+ );\r
+ return Timeout;\r
+}\r
+\r
+VOID\r
+BdsLibLoadDrivers (\r
+ IN LIST_ENTRY *BdsDriverLists\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ \r
+ The function will go through the driver optoin link list, load and start\r
+ every driver the driver optoin device path point to.\r
+\r
+Arguments:\r
+\r
+ BdsDriverLists - The header of the current driver option link list\r
+\r
+Returns:\r
+ \r
+ None\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ LIST_ENTRY *Link;\r
+ BDS_COMMON_OPTION *Option;\r
+ EFI_HANDLE ImageHandle;\r
+ EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;\r
+ UINTN ExitDataSize;\r
+ CHAR16 *ExitData;\r
+ BOOLEAN ReconnectAll;\r
+\r
+ ReconnectAll = FALSE;\r
+\r
+ //\r
+ // Process the driver option\r
+ //\r
+ for (Link = BdsDriverLists->ForwardLink; Link != BdsDriverLists; Link = Link->ForwardLink) {\r
+ Option = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);\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 (!IS_LOAD_OPTION_TYPE (Option->Attribute, LOAD_OPTION_ACTIVE)) {\r
+ continue;\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 (IS_LOAD_OPTION_TYPE (Option->Attribute, LOAD_OPTION_FORCE_RECONNECT)) {\r
+ ReconnectAll = TRUE;\r
+ }\r
+ //\r
+ // Make sure the driver path is connected.\r
+ //\r
+ BdsLibConnectDevicePath (Option->DevicePath);\r
+\r
+ //\r
+ // Load and start the image that Driver#### describes\r
+ //\r
+ Status = gBS->LoadImage (\r
+ FALSE,\r
+ mBdsImageHandle,\r
+ Option->DevicePath,\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
+ if (Option->LoadOptionsSize != 0) {\r
+ ImageInfo->LoadOptionsSize = Option->LoadOptionsSize;\r
+ ImageInfo->LoadOptions = Option->LoadOptions;\r
+ }\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
+ Status = gBS->StartImage (ImageHandle, &ExitDataSize, &ExitData);\r
+ DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Driver Return Status = %r\n", Status));\r
+\r
+ //\r
+ // Clear the Watchdog Timer after the image returns\r
+ //\r
+ gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);\r
+ }\r
+ }\r
+ //\r
+ // Process the LOAD_OPTION_FORCE_RECONNECT driver option\r
+ //\r
+ if (ReconnectAll) {\r
+ BdsLibDisconnectAllEfi ();\r
+ BdsLibConnectAll ();\r
+ }\r
+\r
+}\r
+\r
+EFI_STATUS\r
+BdsLibRegisterNewOption (\r
+ IN LIST_ENTRY *BdsOptionList,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ IN CHAR16 *String,\r
+ IN CHAR16 *VariableName\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ \r
+ This function will register the new boot#### or driver#### option base on\r
+ the VariableName. The new registered boot#### or driver#### will be linked\r
+ to BdsOptionList and also update to the VariableName. After the boot#### or\r
+ driver#### updated, the BootOrder or DriverOrder will also be updated.\r
+\r
+Arguments:\r
+\r
+ BdsOptionList - The header of the boot#### or driver#### link list\r
+ \r
+ DevicePath - The device path which the boot####\r
+ or driver#### option present\r
+ \r
+ String - The description of the boot#### or driver####\r
+ \r
+ VariableName - Indicate if the boot#### or driver#### option\r
+\r
+Returns:\r
+ \r
+ EFI_SUCCESS - The boot#### or driver#### have been success registered\r
+ \r
+ EFI_STATUS - Return the status of gRT->SetVariable ().\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ UINT16 MaxOptionNumber;\r
+ UINT16 RegisterOptionNumber;\r
+ UINT16 *TempOptionPtr;\r
+ UINTN TempOptionSize;\r
+ UINT16 *OptionOrderPtr;\r
+ VOID *OptionPtr;\r
+ UINTN OptionSize;\r
+ UINT8 *TempPtr;\r
+ EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;\r
+ CHAR16 *Description;\r
+ CHAR16 OptionName[10];\r
+ BOOLEAN UpdateBootDevicePath;\r
+\r
+ OptionPtr = NULL;\r
+ OptionSize = 0;\r
+ TempPtr = NULL;\r
+ OptionDevicePath = NULL;\r
+ Description = NULL;\r
+ MaxOptionNumber = 0;\r
+ OptionOrderPtr = NULL;\r
+ UpdateBootDevicePath = FALSE;\r
+ ZeroMem (OptionName, sizeof (OptionName));\r
+\r
+ TempOptionSize = 0;\r
+ TempOptionPtr = BdsLibGetVariableAndSize (\r
+ VariableName,\r
+ &gEfiGlobalVariableGuid,\r
+ &TempOptionSize\r
+ );\r
+ //\r
+ // Compare with current option variable\r
+ //\r
+ for (Index = 0; Index < TempOptionSize / sizeof (UINT16); Index++) {\r
+ //\r
+ // Got the max option#### number\r
+ //\r
+ if (MaxOptionNumber < TempOptionPtr[Index]) {\r
+ MaxOptionNumber = TempOptionPtr[Index];\r
+ }\r
+\r
+ if (*VariableName == 'B') {\r
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", TempOptionPtr[Index]);\r
+ } else {\r
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", TempOptionPtr[Index]);\r
+ }\r
+\r
+ OptionPtr = BdsLibGetVariableAndSize (\r
+ OptionName,\r
+ &gEfiGlobalVariableGuid,\r
+ &OptionSize\r
+ );\r
+ TempPtr = OptionPtr;\r
+ TempPtr += sizeof (UINT32) + sizeof (UINT16);\r
+ Description = (CHAR16 *) TempPtr;\r
+ TempPtr += StrSize ((CHAR16 *) TempPtr);\r
+ OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;\r
+\r
+ //\r
+ // Notes: the description may will change base on the GetStringToken\r
+ //\r
+ if (CompareMem (Description, String, StrSize (Description)) == 0) {\r
+ if (CompareMem (OptionDevicePath, DevicePath, GetDevicePathSize (OptionDevicePath)) == 0) {\r
+ //\r
+ // Got the option, so just return\r
+ //\r
+ gBS->FreePool (OptionPtr);\r
+ gBS->FreePool (TempOptionPtr);\r
+ return EFI_SUCCESS;\r
+ } else {\r
+ //\r
+ // Boot device path changed, need update.\r
+ //\r
+ UpdateBootDevicePath = TRUE;\r
+ break;\r
+ }\r
+ }\r
+\r
+ gBS->FreePool (OptionPtr);\r
+ }\r
+\r
+ OptionSize = sizeof (UINT32) + sizeof (UINT16) + StrSize (String) + GetDevicePathSize (DevicePath);\r
+ OptionPtr = AllocateZeroPool (OptionSize);\r
+ TempPtr = OptionPtr;\r
+ *(UINT32 *) TempPtr = LOAD_OPTION_ACTIVE;\r
+ TempPtr += sizeof (UINT32);\r
+ *(UINT16 *) TempPtr = (UINT16) GetDevicePathSize (DevicePath);\r
+ TempPtr += sizeof (UINT16);\r
+ CopyMem (TempPtr, String, StrSize (String));\r
+ TempPtr += StrSize (String);\r
+ CopyMem (TempPtr, DevicePath, GetDevicePathSize (DevicePath));\r
+\r
+ if (UpdateBootDevicePath) {\r
+ //\r
+ // The number in option#### to be updated\r
+ //\r
+ RegisterOptionNumber = TempOptionPtr[Index];\r
+ } else {\r
+ //\r
+ // The new option#### number\r
+ //\r
+ RegisterOptionNumber = MaxOptionNumber + 1;\r
+ }\r
+\r
+ if (*VariableName == 'B') {\r
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", RegisterOptionNumber);\r
+ } else {\r
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", RegisterOptionNumber);\r
+ }\r
+\r
+ Status = gRT->SetVariable (\r
+ OptionName,\r
+ &gEfiGlobalVariableGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+ OptionSize,\r
+ OptionPtr\r
+ );\r
+ if (EFI_ERROR (Status) || UpdateBootDevicePath) {\r
+ gBS->FreePool (OptionPtr);\r
+ gBS->FreePool (TempOptionPtr);\r
+ return Status;\r
+ }\r
+\r
+ gBS->FreePool (OptionPtr);\r
+\r
+ //\r
+ // Update the option order variable\r
+ //\r
+ OptionOrderPtr = AllocateZeroPool ((Index + 1) * sizeof (UINT16));\r
+ CopyMem (OptionOrderPtr, TempOptionPtr, Index * sizeof (UINT16));\r
+ OptionOrderPtr[Index] = RegisterOptionNumber;\r
+ Status = gRT->SetVariable (\r
+ VariableName,\r
+ &gEfiGlobalVariableGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+ (Index + 1) * sizeof (UINT16),\r
+ OptionOrderPtr\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->FreePool (TempOptionPtr);\r
+ gBS->FreePool (OptionOrderPtr);\r
+ return Status;\r
+ }\r
+\r
+ gBS->FreePool (TempOptionPtr);\r
+ gBS->FreePool (OptionOrderPtr);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+BDS_COMMON_OPTION *\r
+BdsLibVariableToOption (\r
+ IN OUT LIST_ENTRY *BdsCommonOptionList,\r
+ IN CHAR16 *VariableName\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Build the boot#### or driver#### option from the VariableName, the \r
+ build boot#### or driver#### will also be linked to BdsCommonOptionList\r
+ \r
+Arguments:\r
+\r
+ BdsCommonOptionList - The header of the boot#### or driver#### option link list\r
+\r
+ VariableName - EFI Variable name indicate if it is boot#### or driver####\r
+\r
+Returns:\r
+\r
+ BDS_COMMON_OPTION - Get the option just been created\r
+\r
+ NULL - Failed to get the new option\r
+\r
+--*/\r
+{\r
+ UINT32 Attribute;\r
+ UINT16 FilePathSize;\r
+ UINT8 *Variable;\r
+ UINT8 *TempPtr;\r
+ UINTN VariableSize;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ BDS_COMMON_OPTION *Option;\r
+ VOID *LoadOptions;\r
+ UINT32 LoadOptionsSize;\r
+ CHAR16 *Description;\r
+\r
+ //\r
+ // Read the variable. We will never free this data.\r
+ //\r
+ Variable = BdsLibGetVariableAndSize (\r
+ VariableName,\r
+ &gEfiGlobalVariableGuid,\r
+ &VariableSize\r
+ );\r
+ if (Variable == NULL) {\r
+ return NULL;\r
+ }\r
+ //\r
+ // Notes: careful defined the variable of Boot#### or\r
+ // Driver####, consider use some macro to abstract the code\r
+ //\r
+ //\r
+ // Get the option attribute\r
+ //\r
+ TempPtr = Variable;\r
+ Attribute = *(UINT32 *) Variable;\r
+ TempPtr += sizeof (UINT32);\r
+\r
+ //\r
+ // Get the option's device path size\r
+ //\r
+ FilePathSize = *(UINT16 *) TempPtr;\r
+ TempPtr += sizeof (UINT16);\r
+\r
+ //\r
+ // Get the option's description string\r
+ //\r
+ Description = (CHAR16 *) TempPtr;\r
+\r
+ //\r
+ // Get the option's description string size\r
+ //\r
+ TempPtr += StrSize ((CHAR16 *) TempPtr);\r
+\r
+ //\r
+ // Get the option's device path\r
+ //\r
+ DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;\r
+ TempPtr += FilePathSize;\r
+\r
+ LoadOptions = TempPtr;\r
+ LoadOptionsSize = (UINT32) (VariableSize - (UINTN) (TempPtr - Variable));\r
+\r
+ //\r
+ // The Console variables may have multiple device paths, so make\r
+ // an Entry for each one.\r
+ //\r
+ Option = AllocateZeroPool (sizeof (BDS_COMMON_OPTION));\r
+ if (Option == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ Option->Signature = BDS_LOAD_OPTION_SIGNATURE;\r
+ Option->DevicePath = AllocateZeroPool (GetDevicePathSize (DevicePath));\r
+ CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath));\r
+ Option->Attribute = Attribute;\r
+ Option->Description = AllocateZeroPool (StrSize (Description));\r
+ CopyMem (Option->Description, Description, StrSize (Description));\r
+ Option->LoadOptions = AllocateZeroPool (LoadOptionsSize);\r
+ CopyMem (Option->LoadOptions, LoadOptions, LoadOptionsSize);\r
+ Option->LoadOptionsSize = LoadOptionsSize;\r
+\r
+ //\r
+ // Insert active entry to BdsDeviceList\r
+ //\r
+ if ((Option->Attribute & LOAD_OPTION_ACTIVE) == LOAD_OPTION_ACTIVE) {\r
+ InsertTailList (BdsCommonOptionList, &Option->Link);\r
+ gBS->FreePool (Variable);\r
+ return Option;\r
+ }\r
+\r
+ gBS->FreePool (Variable);\r
+ gBS->FreePool (Option);\r
+ return NULL;\r
+\r
+}\r
+\r
+EFI_STATUS\r
+BdsLibBuildOptionFromVar (\r
+ IN LIST_ENTRY *BdsCommonOptionList,\r
+ IN CHAR16 *VariableName\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Process BootOrder, or DriverOrder variables, by calling\r
+ BdsLibVariableToOption () for each UINT16 in the variables.\r
+\r
+Arguments:\r
+\r
+ BdsCommonOptionList - The header of the option list base on variable\r
+ VariableName\r
+\r
+ VariableName - EFI Variable name indicate the BootOrder or DriverOrder\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Success create the boot option or driver option list\r
+\r
+ EFI_OUT_OF_RESOURCES - Failed to get the boot option or driver option list\r
+\r
+--*/\r
+{\r
+ UINT16 *OptionOrder;\r
+ UINTN OptionOrderSize;\r
+ UINTN Index;\r
+ BDS_COMMON_OPTION *Option;\r
+ CHAR16 OptionName[20];\r
+\r
+ //\r
+ // Zero Buffer in order to get all BOOT#### variables\r
+ //\r
+ ZeroMem (OptionName, sizeof (OptionName));\r
+\r
+ //\r
+ // Read the BootOrder, or DriverOrder variable.\r
+ //\r
+ OptionOrder = BdsLibGetVariableAndSize (\r
+ VariableName,\r
+ &gEfiGlobalVariableGuid,\r
+ &OptionOrderSize\r
+ );\r
+ if (OptionOrder == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {\r
+ if (*VariableName == 'B') {\r
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", OptionOrder[Index]);\r
+ } else {\r
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", OptionOrder[Index]);\r
+ }\r
+ Option = BdsLibVariableToOption (BdsCommonOptionList, OptionName);\r
+ Option->BootCurrent = OptionOrder[Index];\r
+\r
+ }\r
+\r
+ gBS->FreePool (OptionOrder);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+BdsLibGetBootMode (\r
+ OUT EFI_BOOT_MODE *BootMode\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get boot mode by looking up configuration table and parsing HOB list\r
+\r
+Arguments:\r
+\r
+ BootMode - Boot mode from PEI handoff HOB.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Successfully get boot mode\r
+ \r
+ EFI_NOT_FOUND - Can not find the current system boot mode\r
+\r
+--*/\r
+{\r
+ EFI_HOB_HANDOFF_INFO_TABLE *HobList;\r
+\r
+ HobList = GetHobList ();\r
+ ASSERT (HobList->Header.HobType == EFI_HOB_TYPE_HANDOFF);\r
+ *BootMode = HobList->BootMode;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+VOID *\r
+BdsLibGetVariableAndSize (\r
+ IN CHAR16 *Name,\r
+ IN EFI_GUID *VendorGuid,\r
+ OUT UINTN *VariableSize\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Read the EFI variable (VendorGuid/Name) and return a dynamically allocated\r
+ buffer, and the size of the buffer. If failure return NULL.\r
+\r
+Arguments:\r
+\r
+ Name - String part of EFI variable name\r
+\r
+ VendorGuid - GUID part of EFI variable name\r
+\r
+ VariableSize - Returns the size of the EFI variable that was read\r
+\r
+Returns:\r
+\r
+ Dynamically allocated memory that contains a copy of the EFI variable.\r
+ Caller is responsible freeing the buffer.\r
+\r
+ NULL - Variable was not read\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN BufferSize;\r
+ VOID *Buffer;\r
+\r
+ Buffer = NULL;\r
+\r
+ //\r
+ // Pass in a zero size buffer to find the required buffer size.\r
+ //\r
+ BufferSize = 0;\r
+ Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ //\r
+ // Allocate the buffer to return\r
+ //\r
+ Buffer = AllocateZeroPool (BufferSize);\r
+ if (Buffer == NULL) {\r
+ return NULL;\r
+ }\r
+ //\r
+ // Read variable into the allocated buffer.\r
+ //\r
+ Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);\r
+ if (EFI_ERROR (Status)) {\r
+ BufferSize = 0;\r
+ }\r
+ }\r
+\r
+ *VariableSize = BufferSize;\r
+ return Buffer;\r
+}\r
+\r
+BOOLEAN\r
+BdsLibMatchDevicePaths (\r
+ IN EFI_DEVICE_PATH_PROTOCOL *Multi,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *Single\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Function compares a device path data structure to that of all the nodes of a\r
+ second device path instance.\r
+\r
+Arguments:\r
+\r
+ Multi - A pointer to a multi-instance device path data structure.\r
+\r
+ Single - A pointer to a single-instance device path data structure.\r
+\r
+Returns:\r
+\r
+ TRUE - If the Single is contained within Multi\r
+ \r
+ FALSE - The Single is not match within Multi\r
+ \r
+\r
+--*/\r
+{\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;\r
+ UINTN Size;\r
+\r
+ if (!Multi || !Single) {\r
+ return FALSE;\r
+ }\r
+\r
+ DevicePath = Multi;\r
+ DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);\r
+ Size -= sizeof (EFI_DEVICE_PATH_PROTOCOL);\r
+\r
+ //\r
+ // Search for the match of 'Single' in 'Multi'\r
+ //\r
+ while (DevicePathInst != NULL) {\r
+ //\r
+ // If the single device path is found in multiple device paths,\r
+ // return success\r
+ //\r
+ if (Size == 0) {\r
+ return FALSE;\r
+ }\r
+\r
+ if (CompareMem (Single, DevicePathInst, Size) == 0) {\r
+ return TRUE;\r
+ }\r
+\r
+ gBS->FreePool (DevicePathInst);\r
+ DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);\r
+ Size -= sizeof (EFI_DEVICE_PATH_PROTOCOL);\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+EFI_STATUS\r
+BdsLibOutputStrings (\r
+ IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *ConOut,\r
+ ...\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This function prints a series of strings.\r
+\r
+Arguments:\r
+\r
+ ConOut - Pointer to EFI_SIMPLE_TEXT_OUT_PROTOCOL\r
+\r
+ ... - A variable argument list containing series of strings,\r
+ the last string must be NULL.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Success print out the string using ConOut.\r
+ \r
+ EFI_STATUS - Return the status of the ConOut->OutputString ().\r
+\r
+--*/\r
+{\r
+ VA_LIST args;\r
+ EFI_STATUS Status;\r
+ CHAR16 *String;\r
+\r
+ Status = EFI_SUCCESS;\r
+ VA_START (args, ConOut);\r
+\r
+ while (!EFI_ERROR (Status)) {\r
+ //\r
+ // If String is NULL, then it's the end of the list\r
+ //\r
+ String = VA_ARG (args, CHAR16 *);\r
+ if (!String) {\r
+ break;\r
+ }\r
+\r
+ Status = ConOut->OutputString (ConOut, String);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+//\r
+// Following are BDS Lib functions which contain all the code about setup browser reset reminder feature.\r
+// Setup Browser reset reminder feature is that an reset reminder will be given before user leaves the setup browser if \r
+// user change any option setting which needs a reset to be effective, and the reset will be applied according to the user selection.\r
+//\r
+\r
+VOID\r
+EnableResetReminderFeature (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ \r
+ Enable the setup browser reset reminder feature.\r
+ This routine is used in platform tip. If the platform policy need the feature, use the routine to enable it.\r
+\r
+Arguments:\r
+\r
+ VOID\r
+\r
+Returns:\r
+\r
+ VOID\r
+\r
+--*/\r
+{\r
+ mFeaturerSwitch = TRUE;\r
+} \r
+\r
+VOID\r
+DisableResetReminderFeature (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ \r
+ Disable the setup browser reset reminder feature.\r
+ This routine is used in platform tip. If the platform policy do not want the feature, use the routine to disable it.\r
+ \r
+Arguments:\r
+\r
+ VOID\r
+\r
+Returns:\r
+\r
+ VOID\r
+\r
+--*/\r
+{\r
+ mFeaturerSwitch = FALSE;\r
+} \r
+\r
+VOID\r
+EnableResetRequired (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ \r
+ Record the info that a reset is required.\r
+ A module boolean variable is used to record whether a reset is required. \r
+ \r
+Arguments:\r
+\r
+ VOID\r
+\r
+Returns:\r
+\r
+ VOID\r
+\r
+--*/\r
+{\r
+ mResetRequired = TRUE;\r
+} \r
+\r
+VOID\r
+DisableResetRequired (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Record the info that no reset is required.\r
+ A module boolean variable is used to record whether a reset is required. \r
+\r
+Arguments:\r
+\r
+ VOID\r
+\r
+Returns:\r
+\r
+ VOID\r
+\r
+--*/\r
+{\r
+ mResetRequired = FALSE;\r
+} \r
+\r
+BOOLEAN\r
+IsResetReminderFeatureEnable (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ \r
+ Check whether platform policy enable the reset reminder feature. The default is enabled.\r
+\r
+Arguments:\r
+\r
+ VOID\r
+\r
+Returns:\r
+\r
+ VOID\r
+\r
+--*/\r
+{\r
+ return mFeaturerSwitch;\r
+}\r
+\r
+BOOLEAN\r
+IsResetRequired (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ \r
+ Check if user changed any option setting which needs a system reset to be effective.\r
+ \r
+Arguments:\r
+\r
+ VOID\r
+\r
+Returns:\r
+\r
+ VOID\r
+\r
+--*/\r
+{\r
+ return mResetRequired;\r
+}\r
+\r
+VOID\r
+SetupResetReminder (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ \r
+ Check whether a reset is needed, and finish the reset reminder feature.\r
+ If a reset is needed, Popup a menu to notice user, and finish the feature \r
+ according to the user selection.\r
+\r
+Arguments:\r
+\r
+ VOID\r
+\r
+Returns:\r
+\r
+ VOID\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_FORM_BROWSER_PROTOCOL *Browser;\r
+ EFI_INPUT_KEY Key; \r
+ CHAR16 *StringBuffer1;\r
+ CHAR16 *StringBuffer2; \r
+\r
+\r
+ //\r
+ //check any reset required change is applied? if yes, reset system\r
+ //\r
+ if (IsResetReminderFeatureEnable ()) {\r
+ if (IsResetRequired ()) {\r
+ \r
+ Status = gBS->LocateProtocol (\r
+ &gEfiFormBrowserProtocolGuid,\r
+ NULL,\r
+ (VOID **)&Browser\r
+ ); \r
+ \r
+ StringBuffer1 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));\r
+ ASSERT (StringBuffer1 != NULL);\r
+ StringBuffer2 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));\r
+ ASSERT (StringBuffer2 != NULL); \r
+ StrCpy (StringBuffer1, L"Configuration changed. Reset to apply it Now ? ");\r
+ StrCpy (StringBuffer2, L"Enter (YES) / Esc (NO)"); \r
+ //\r
+ // Popup a menu to notice user\r
+ // \r
+ do {\r
+ Browser->CreatePopUp (2, TRUE, 0, NULL, &Key, StringBuffer1, StringBuffer2);\r
+ } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN)); \r
+ \r
+ gBS->FreePool (StringBuffer1); \r
+ gBS->FreePool (StringBuffer2); \r
+ //\r
+ // If the user hits the YES Response key, reset\r
+ //\r
+ if ((Key.UnicodeChar == CHAR_CARRIAGE_RETURN)) {\r
+ gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);\r
+ }\r
+ gST->ConOut->ClearScreen (gST->ConOut);\r
+ } \r
+ } \r
+} \r