summaryrefslogtreecommitdiff
path: root/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib
diff options
context:
space:
mode:
authorGuo Mang <mang.guo@intel.com>2016-08-03 10:19:29 +0800
committerGuo Mang <mang.guo@intel.com>2016-08-04 10:31:16 +0800
commitbaa0b78e96b18ca463ca660eeefc9806fed8a164 (patch)
tree9a36fed94dcd7f18903789600cdf12b5ff695b02 /BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib
parent3302610e68b611195a10ac34352ba0c09dbd5e21 (diff)
downloadedk2-platforms-baa0b78e96b18ca463ca660eeefc9806fed8a164.tar.xz
BraswellPlatformPkg: Move Override to Common/Override
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Guo Mang <mang.guo@intel.com> Reviewed-by: David Wei <david.wei@intel.com>
Diffstat (limited to 'BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib')
-rw-r--r--BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsBoot.c4497
-rw-r--r--BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsConnect.c435
-rw-r--r--BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsConsole.c1301
-rw-r--r--BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsMisc.c1589
-rw-r--r--BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/DevicePath.c33
-rw-r--r--BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/GenericBdsLib.inf144
-rw-r--r--BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/GenericBdsStrings.uni36
-rw-r--r--BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/InternalBdsLib.h194
-rw-r--r--BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/Performance.c358
-rw-r--r--BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/String.c32
-rw-r--r--BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/String.h48
11 files changed, 8667 insertions, 0 deletions
diff --git a/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsBoot.c b/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsBoot.c
new file mode 100644
index 0000000000..8edd9718d3
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsBoot.c
@@ -0,0 +1,4497 @@
+/** @file
+ BDS Lib functions which relate with create or process the boot option.
+
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "InternalBdsLib.h"
+#include "String.h"
+
+BOOLEAN mEnumBootDevice = FALSE;
+EFI_HII_HANDLE gBdsLibStringPackHandle = NULL;
+
+/**
+ The constructor function register UNI strings into imageHandle.
+
+ It will ASSERT() if that operation fails and it will always return EFI_SUCCESS.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor successfully added string package.
+ @retval Other value The constructor can't add string package.
+
+**/
+EFI_STATUS
+EFIAPI
+GenericBdsLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+
+ gBdsLibStringPackHandle = HiiAddPackages (
+ &gBdsLibStringPackageGuid,
+ ImageHandle,
+ GenericBdsLibStrings,
+ NULL
+ );
+
+ ASSERT (gBdsLibStringPackHandle != NULL);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Deletete the Boot Option from EFI Variable. The Boot Order Arrray
+ is also updated.
+
+ @param OptionNumber The number of Boot option want to be deleted.
+ @param BootOrder The Boot Order array.
+ @param BootOrderSize The size of the Boot Order Array.
+
+ @retval EFI_SUCCESS The Boot Option Variable was found and removed
+ @retval EFI_UNSUPPORTED The Boot Option Variable store was inaccessible
+ @retval EFI_NOT_FOUND The Boot Option Variable was not found
+**/
+EFI_STATUS
+EFIAPI
+BdsDeleteBootOption (
+ IN UINTN OptionNumber,
+ IN OUT UINT16 *BootOrder,
+ IN OUT UINTN *BootOrderSize
+ )
+{
+ CHAR16 BootOption[9];
+ UINTN Index;
+ EFI_STATUS Status;
+
+ UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", OptionNumber);
+ Status = gRT->SetVariable (
+ BootOption,
+ &gEfiGlobalVariableGuid,
+ 0,
+ 0,
+ NULL
+ );
+ //
+ // Deleting variable with existing variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // adjust boot order array
+ //
+ for (Index = 0; Index < *BootOrderSize / sizeof (UINT16); Index++) {
+ if (BootOrder[Index] == OptionNumber) {
+ CopyMem (&BootOrder[Index], &BootOrder[Index+1], *BootOrderSize - (Index+1) * sizeof (UINT16));
+ *BootOrderSize -= sizeof (UINT16);
+ break;
+ }
+ }
+
+ return Status;
+}
+/**
+
+ Translate the first n characters of an Ascii string to
+ Unicode characters. The count n is indicated by parameter
+ Size. If Size is greater than the length of string, then
+ the entire string is translated.
+
+
+ @param AStr Pointer to input Ascii string.
+ @param Size The number of characters to translate.
+ @param UStr Pointer to output Unicode string buffer.
+
+**/
+VOID
+AsciiToUnicodeSize (
+ IN UINT8 *AStr,
+ IN UINTN Size,
+ OUT UINT16 *UStr
+ )
+{
+ UINTN Idx;
+
+ Idx = 0;
+ while (AStr[Idx] != 0) {
+ UStr[Idx] = (CHAR16) AStr[Idx];
+ if (Idx == Size) {
+ break;
+ }
+
+ Idx++;
+ }
+ UStr[Idx] = 0;
+}
+
+/**
+ Build Legacy Device Name String according.
+
+ @param CurBBSEntry BBS Table.
+ @param Index Index.
+ @param BufSize The buffer size.
+ @param BootString The output string.
+
+**/
+VOID
+BdsBuildLegacyDevNameString (
+ IN BBS_TABLE *CurBBSEntry,
+ IN UINTN Index,
+ IN UINTN BufSize,
+ OUT CHAR16 *BootString
+ )
+{
+ CHAR16 *Fmt;
+ CHAR16 *Type;
+ UINT8 *StringDesc;
+ CHAR16 Temp[80];
+
+ switch (Index) {
+ //
+ // Primary Master
+ //
+ case 1:
+ Fmt = L"Primary Master %s";
+ break;
+
+ //
+ // Primary Slave
+ //
+ case 2:
+ Fmt = L"Primary Slave %s";
+ break;
+
+ //
+ // Secondary Master
+ //
+ case 3:
+ Fmt = L"Secondary Master %s";
+ break;
+
+ //
+ // Secondary Slave
+ //
+ case 4:
+ Fmt = L"Secondary Slave %s";
+ break;
+
+ default:
+ Fmt = L"%s";
+ break;
+ }
+
+ switch (CurBBSEntry->DeviceType) {
+ case BBS_FLOPPY:
+ Type = L"Floppy";
+ break;
+
+ case BBS_HARDDISK:
+ Type = L"Harddisk";
+ break;
+
+ case BBS_CDROM:
+ Type = L"CDROM";
+ break;
+
+ case BBS_PCMCIA:
+ Type = L"PCMCIAe";
+ break;
+
+ case BBS_USB:
+ Type = L"USB";
+ break;
+
+ case BBS_EMBED_NETWORK:
+ Type = L"Network";
+ break;
+
+ case BBS_BEV_DEVICE:
+ Type = L"BEVe";
+ break;
+
+ case BBS_UNKNOWN:
+ default:
+ Type = L"Unknown";
+ break;
+ }
+ //
+ // If current BBS entry has its description then use it.
+ //
+ StringDesc = (UINT8 *) (UINTN) ((CurBBSEntry->DescStringSegment << 4) + CurBBSEntry->DescStringOffset);
+ if (NULL != StringDesc) {
+ //
+ // Only get fisrt 32 characters, this is suggested by BBS spec
+ //
+ AsciiToUnicodeSize (StringDesc, 32, Temp);
+ Fmt = L"%s";
+ Type = Temp;
+ }
+
+ //
+ // BbsTable 16 entries are for onboard IDE.
+ // Set description string for SATA harddisks, Harddisk 0 ~ Harddisk 11
+ //
+ if (Index >= 5 && Index <= 16 && (CurBBSEntry->DeviceType == BBS_HARDDISK || CurBBSEntry->DeviceType == BBS_CDROM)) {
+ Fmt = L"%s %d";
+ UnicodeSPrint (BootString, BufSize, Fmt, Type, Index - 5);
+ } else {
+ UnicodeSPrint (BootString, BufSize, Fmt, Type);
+ }
+}
+
+/**
+
+ Create a legacy boot option for the specified entry of
+ BBS table, save it as variable, and append it to the boot
+ order list.
+
+
+ @param CurrentBbsEntry Pointer to current BBS table.
+ @param CurrentBbsDevPath Pointer to the Device Path Protocol instance of BBS
+ @param Index Index of the specified entry in BBS table.
+ @param BootOrderList On input, the original boot order list.
+ On output, the new boot order list attached with the
+ created node.
+ @param BootOrderListSize On input, the original size of boot order list.
+ On output, the size of new boot order list.
+
+ @retval EFI_SUCCESS Boot Option successfully created.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory.
+ @retval Other Error occurs while setting variable.
+
+**/
+EFI_STATUS
+BdsCreateLegacyBootOption (
+ IN BBS_TABLE *CurrentBbsEntry,
+ IN EFI_DEVICE_PATH_PROTOCOL *CurrentBbsDevPath,
+ IN UINTN Index,
+ IN OUT UINT16 **BootOrderList,
+ IN OUT UINTN *BootOrderListSize
+ )
+{
+ EFI_STATUS Status;
+ UINT16 CurrentBootOptionNo;
+ UINT16 BootString[10];
+ CHAR16 BootDesc[100];
+ CHAR8 HelpString[100];
+ UINT16 *NewBootOrderList;
+ UINTN BufferSize;
+ UINTN StringLen;
+ VOID *Buffer;
+ UINT8 *Ptr;
+ UINT16 CurrentBbsDevPathSize;
+ UINTN BootOrderIndex;
+ UINTN BootOrderLastIndex;
+ UINTN ArrayIndex;
+ BOOLEAN IndexNotFound;
+ BBS_BBS_DEVICE_PATH *NewBbsDevPathNode;
+
+ if ((*BootOrderList) == NULL) {
+ CurrentBootOptionNo = 0;
+ } else {
+ for (ArrayIndex = 0; ArrayIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); ArrayIndex++) {
+ IndexNotFound = TRUE;
+ for (BootOrderIndex = 0; BootOrderIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); BootOrderIndex++) {
+ if ((*BootOrderList)[BootOrderIndex] == ArrayIndex) {
+ IndexNotFound = FALSE;
+ break;
+ }
+ }
+
+ if (!IndexNotFound) {
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ CurrentBootOptionNo = (UINT16) ArrayIndex;
+ }
+
+ UnicodeSPrint (
+ BootString,
+ sizeof (BootString),
+ L"Boot%04x",
+ CurrentBootOptionNo
+ );
+
+ BdsBuildLegacyDevNameString (CurrentBbsEntry, Index, sizeof (BootDesc), BootDesc);
+
+ //
+ // Create new BBS device path node with description string
+ //
+ UnicodeStrToAsciiStr (BootDesc, HelpString);
+
+ StringLen = AsciiStrLen (HelpString);
+ NewBbsDevPathNode = AllocateZeroPool (sizeof (BBS_BBS_DEVICE_PATH) + StringLen);
+ if (NewBbsDevPathNode == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (NewBbsDevPathNode, CurrentBbsDevPath, sizeof (BBS_BBS_DEVICE_PATH));
+ CopyMem (NewBbsDevPathNode->String, HelpString, StringLen + 1);
+ SetDevicePathNodeLength (&(NewBbsDevPathNode->Header), sizeof (BBS_BBS_DEVICE_PATH) + StringLen);
+
+ //
+ // Create entire new CurrentBbsDevPath with end node
+ //
+ CurrentBbsDevPath = AppendDevicePathNode (
+ NULL,
+ (EFI_DEVICE_PATH_PROTOCOL *) NewBbsDevPathNode
+ );
+ if (CurrentBbsDevPath == NULL) {
+ FreePool (NewBbsDevPathNode);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CurrentBbsDevPathSize = (UINT16) (GetDevicePathSize (CurrentBbsDevPath));
+
+ BufferSize = sizeof (UINT32) +
+ sizeof (UINT16) +
+ StrSize (BootDesc) +
+ CurrentBbsDevPathSize +
+ sizeof (BBS_TABLE) +
+ sizeof (UINT16);
+
+ Buffer = AllocateZeroPool (BufferSize);
+ if (Buffer == NULL) {
+ FreePool (NewBbsDevPathNode);
+ FreePool (CurrentBbsDevPath);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Ptr = (UINT8 *) Buffer;
+
+ *((UINT32 *) Ptr) = LOAD_OPTION_ACTIVE;
+ Ptr += sizeof (UINT32);
+
+ *((UINT16 *) Ptr) = CurrentBbsDevPathSize;
+ Ptr += sizeof (UINT16);
+
+ CopyMem (
+ Ptr,
+ BootDesc,
+ StrSize (BootDesc)
+ );
+ Ptr += StrSize (BootDesc);
+
+ CopyMem (
+ Ptr,
+ CurrentBbsDevPath,
+ CurrentBbsDevPathSize
+ );
+ Ptr += CurrentBbsDevPathSize;
+
+ CopyMem (
+ Ptr,
+ CurrentBbsEntry,
+ sizeof (BBS_TABLE)
+ );
+
+ Ptr += sizeof (BBS_TABLE);
+ *((UINT16 *) Ptr) = (UINT16) Index;
+
+ Status = gRT->SetVariable (
+ BootString,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ BufferSize,
+ Buffer
+ );
+
+ FreePool (Buffer);
+
+ Buffer = NULL;
+
+ NewBootOrderList = AllocateZeroPool (*BootOrderListSize + sizeof (UINT16));
+ if (NULL == NewBootOrderList) {
+ FreePool (NewBbsDevPathNode);
+ FreePool (CurrentBbsDevPath);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (*BootOrderList != NULL) {
+ CopyMem (NewBootOrderList, *BootOrderList, *BootOrderListSize);
+ FreePool (*BootOrderList);
+ }
+
+ BootOrderLastIndex = (UINTN) (*BootOrderListSize / sizeof (UINT16));
+ NewBootOrderList[BootOrderLastIndex] = CurrentBootOptionNo;
+ *BootOrderListSize += sizeof (UINT16);
+ *BootOrderList = NewBootOrderList;
+
+ FreePool (NewBbsDevPathNode);
+ FreePool (CurrentBbsDevPath);
+ return Status;
+}
+
+/**
+ Check if the boot option is a legacy one.
+
+ @param BootOptionVar The boot option data payload.
+ @param BbsEntry The BBS Table.
+ @param BbsIndex The table index.
+
+ @retval TRUE It is a legacy boot option.
+ @retval FALSE It is not a legacy boot option.
+
+**/
+BOOLEAN
+BdsIsLegacyBootOption (
+ IN UINT8 *BootOptionVar,
+ OUT BBS_TABLE **BbsEntry,
+ OUT UINT16 *BbsIndex
+ )
+{
+ UINT8 *Ptr;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ BOOLEAN Ret;
+ UINT16 DevPathLen;
+
+ Ptr = BootOptionVar;
+ Ptr += sizeof (UINT32);
+ DevPathLen = *(UINT16 *) Ptr;
+ Ptr += sizeof (UINT16);
+ Ptr += StrSize ((UINT16 *) Ptr);
+ DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
+ if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {
+ Ptr += DevPathLen;
+ *BbsEntry = (BBS_TABLE *) Ptr;
+ Ptr += sizeof (BBS_TABLE);
+ *BbsIndex = *(UINT16 *) Ptr;
+ Ret = TRUE;
+ } else {
+ *BbsEntry = NULL;
+ Ret = FALSE;
+ }
+
+ return Ret;
+}
+
+/**
+ Delete all the invalid legacy boot options.
+
+ @retval EFI_SUCCESS All invalide legacy boot options are deleted.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory.
+ @retval EFI_NOT_FOUND Fail to retrive variable of boot order.
+**/
+EFI_STATUS
+EFIAPI
+BdsDeleteAllInvalidLegacyBootOptions (
+ VOID
+ )
+{
+ UINT16 *BootOrder;
+ UINT8 *BootOptionVar;
+ UINTN BootOrderSize;
+ UINTN BootOptionSize;
+ EFI_STATUS Status;
+ UINT16 HddCount;
+ UINT16 BbsCount;
+ HDD_INFO *LocalHddInfo;
+ BBS_TABLE *LocalBbsTable;
+ BBS_TABLE *BbsEntry;
+ UINT16 BbsIndex;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ UINTN Index;
+ UINT16 BootOption[10];
+ UINT16 BootDesc[100];
+ BOOLEAN DescStringMatch;
+
+ Status = EFI_SUCCESS;
+ BootOrder = NULL;
+ BootOrderSize = 0;
+ HddCount = 0;
+ BbsCount = 0;
+ LocalHddInfo = NULL;
+ LocalBbsTable = NULL;
+ BbsEntry = NULL;
+
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BootOrder = BdsLibGetVariableAndSize (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ &BootOrderSize
+ );
+ if (BootOrder == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ LegacyBios->GetBbsInfo (
+ LegacyBios,
+ &HddCount,
+ &LocalHddInfo,
+ &BbsCount,
+ &LocalBbsTable
+ );
+
+ Index = 0;
+ while (Index < BootOrderSize / sizeof (UINT16)) {
+ UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
+ BootOptionVar = BdsLibGetVariableAndSize (
+ BootOption,
+ &gEfiGlobalVariableGuid,
+ &BootOptionSize
+ );
+ if (NULL == BootOptionVar) {
+ BootOptionSize = 0;
+ Status = gRT->GetVariable (
+ BootOption,
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &BootOptionSize,
+ BootOptionVar
+ );
+ if (Status == EFI_NOT_FOUND) {
+ //
+ // Update BootOrder
+ //
+ BdsDeleteBootOption (
+ BootOrder[Index],
+ BootOrder,
+ &BootOrderSize
+ );
+ continue;
+ } else {
+ FreePool (BootOrder);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ //
+ // Skip Non-Legacy boot option
+ //
+ if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, &BbsIndex)) {
+ if (BootOptionVar!= NULL) {
+ FreePool (BootOptionVar);
+ }
+ Index++;
+ continue;
+ }
+
+ if (BbsIndex < BbsCount) {
+ //
+ // Check if BBS Description String is changed
+ //
+ DescStringMatch = FALSE;
+ BdsBuildLegacyDevNameString (
+ &LocalBbsTable[BbsIndex],
+ BbsIndex,
+ sizeof (BootDesc),
+ BootDesc
+ );
+
+ if (StrCmp (BootDesc, (UINT16*)(BootOptionVar + sizeof (UINT32) + sizeof (UINT16))) == 0) {
+ DescStringMatch = TRUE;
+ }
+
+ if (!((LocalBbsTable[BbsIndex].BootPriority == BBS_IGNORE_ENTRY) ||
+ (LocalBbsTable[BbsIndex].BootPriority == BBS_DO_NOT_BOOT_FROM)) &&
+ (LocalBbsTable[BbsIndex].DeviceType == BbsEntry->DeviceType) &&
+ DescStringMatch) {
+ Index++;
+ continue;
+ }
+ }
+
+ if (BootOptionVar != NULL) {
+ FreePool (BootOptionVar);
+ }
+ //
+ // should delete
+ //
+ BdsDeleteBootOption (
+ BootOrder[Index],
+ BootOrder,
+ &BootOrderSize
+ );
+ }
+
+ //
+ // Adjust the number of boot options.
+ //
+ Status = gRT->SetVariable (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ BootOrderSize,
+ BootOrder
+ );
+ //
+ // Shrinking variable with existing variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+ FreePool (BootOrder);
+
+ return Status;
+}
+
+/**
+ Find all legacy boot option by device type.
+
+ @param BootOrder The boot order array.
+ @param BootOptionNum The number of boot option.
+ @param DevType Device type.
+ @param DevName Device name.
+ @param Attribute The boot option attribute.
+ @param BbsIndex The BBS table index.
+ @param OptionNumber The boot option index.
+
+ @retval TRUE The Legacy boot option is found.
+ @retval FALSE The legacy boot option is not found.
+
+**/
+BOOLEAN
+BdsFindLegacyBootOptionByDevTypeAndName (
+ IN UINT16 *BootOrder,
+ IN UINTN BootOptionNum,
+ IN UINT16 DevType,
+ IN CHAR16 *DevName,
+ OUT UINT32 *Attribute,
+ OUT UINT16 *BbsIndex,
+ OUT UINT16 *OptionNumber
+ )
+{
+ UINTN Index;
+ CHAR16 BootOption[9];
+ UINTN BootOptionSize;
+ UINT8 *BootOptionVar;
+ BBS_TABLE *BbsEntry;
+ BOOLEAN Found;
+
+ BbsEntry = NULL;
+ Found = FALSE;
+
+ if (NULL == BootOrder) {
+ return Found;
+ }
+
+ //
+ // Loop all boot option from variable
+ //
+ for (Index = 0; Index < BootOptionNum; Index++) {
+ UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", (UINTN) BootOrder[Index]);
+ BootOptionVar = BdsLibGetVariableAndSize (
+ BootOption,
+ &gEfiGlobalVariableGuid,
+ &BootOptionSize
+ );
+ if (NULL == BootOptionVar) {
+ continue;
+ }
+
+ //
+ // Skip Non-legacy boot option
+ //
+ if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, BbsIndex)) {
+ FreePool (BootOptionVar);
+ continue;
+ }
+
+ if (
+ (BbsEntry->DeviceType != DevType) ||
+ (StrCmp (DevName, (CHAR16*)(BootOptionVar + sizeof (UINT32) + sizeof (UINT16))) != 0)
+ ) {
+ FreePool (BootOptionVar);
+ continue;
+ }
+
+ *Attribute = *(UINT32 *) BootOptionVar;
+ *OptionNumber = BootOrder[Index];
+ Found = TRUE;
+ FreePool (BootOptionVar);
+ break;
+ }
+
+ return Found;
+}
+
+/**
+ Create a legacy boot option.
+
+ @param BbsItem The BBS Table entry.
+ @param Index Index of the specified entry in BBS table.
+ @param BootOrderList The boot order list.
+ @param BootOrderListSize The size of boot order list.
+
+ @retval EFI_OUT_OF_RESOURCE No enough memory.
+ @retval EFI_SUCCESS The function complete successfully.
+ @return Other value if the legacy boot option is not created.
+
+**/
+EFI_STATUS
+BdsCreateOneLegacyBootOption (
+ IN BBS_TABLE *BbsItem,
+ IN UINTN Index,
+ IN OUT UINT16 **BootOrderList,
+ IN OUT UINTN *BootOrderListSize
+ )
+{
+ BBS_BBS_DEVICE_PATH BbsDevPathNode;
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevPath;
+
+ DevPath = NULL;
+
+ //
+ // Create device path node.
+ //
+ BbsDevPathNode.Header.Type = BBS_DEVICE_PATH;
+ BbsDevPathNode.Header.SubType = BBS_BBS_DP;
+ SetDevicePathNodeLength (&BbsDevPathNode.Header, sizeof (BBS_BBS_DEVICE_PATH));
+ BbsDevPathNode.DeviceType = BbsItem->DeviceType;
+ CopyMem (&BbsDevPathNode.StatusFlag, &BbsItem->StatusFlags, sizeof (UINT16));
+
+ DevPath = AppendDevicePathNode (
+ NULL,
+ (EFI_DEVICE_PATH_PROTOCOL *) &BbsDevPathNode
+ );
+ if (NULL == DevPath) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = BdsCreateLegacyBootOption (
+ BbsItem,
+ DevPath,
+ Index,
+ BootOrderList,
+ BootOrderListSize
+ );
+ BbsItem->BootPriority = 0x00;
+
+ FreePool (DevPath);
+
+ return Status;
+}
+
+/**
+ Add the legacy boot options from BBS table if they do not exist.
+
+ @retval EFI_SUCCESS The boot options are added successfully
+ or they are already in boot options.
+ @retval EFI_NOT_FOUND No legacy boot options is found.
+ @retval EFI_OUT_OF_RESOURCE No enough memory.
+ @return Other value LegacyBoot options are not added.
+**/
+EFI_STATUS
+EFIAPI
+BdsAddNonExistingLegacyBootOptions (
+ VOID
+ )
+{
+ UINT16 *BootOrder;
+ UINTN BootOrderSize;
+ EFI_STATUS Status;
+ CHAR16 Desc[100];
+ UINT16 HddCount;
+ UINT16 BbsCount;
+ HDD_INFO *LocalHddInfo;
+ BBS_TABLE *LocalBbsTable;
+ UINT16 BbsIndex;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ UINT16 Index;
+ UINT32 Attribute;
+ UINT16 OptionNumber;
+ BOOLEAN Exist;
+
+ HddCount = 0;
+ BbsCount = 0;
+ LocalHddInfo = NULL;
+ LocalBbsTable = NULL;
+
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ LegacyBios->GetBbsInfo (
+ LegacyBios,
+ &HddCount,
+ &LocalHddInfo,
+ &BbsCount,
+ &LocalBbsTable
+ );
+
+ BootOrder = BdsLibGetVariableAndSize (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ &BootOrderSize
+ );
+ if (BootOrder == NULL) {
+ BootOrderSize = 0;
+ }
+
+ for (Index = 0; Index < BbsCount; Index++) {
+ if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||
+ (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)
+ ) {
+ continue;
+ }
+
+ BdsBuildLegacyDevNameString (&LocalBbsTable[Index], Index, sizeof (Desc), Desc);
+
+ Exist = BdsFindLegacyBootOptionByDevTypeAndName (
+ BootOrder,
+ BootOrderSize / sizeof (UINT16),
+ LocalBbsTable[Index].DeviceType,
+ Desc,
+ &Attribute,
+ &BbsIndex,
+ &OptionNumber
+ );
+ if (!Exist) {
+ //
+ // Not found such type of legacy device in boot options or we found but it's disabled
+ // so we have to create one and put it to the tail of boot order list
+ //
+ Status = BdsCreateOneLegacyBootOption (
+ &LocalBbsTable[Index],
+ Index,
+ &BootOrder,
+ &BootOrderSize
+ );
+ if (!EFI_ERROR (Status)) {
+ ASSERT (BootOrder != NULL);
+ BbsIndex = Index;
+ OptionNumber = BootOrder[BootOrderSize / sizeof (UINT16) - 1];
+ }
+ }
+
+ ASSERT (BbsIndex == Index);
+ }
+
+ Status = gRT->SetVariable (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ BootOrderSize,
+ BootOrder
+ );
+ if (BootOrder != NULL) {
+ FreePool (BootOrder);
+ }
+
+ return Status;
+}
+
+/**
+ Fill the device order buffer.
+
+ @param BbsTable The BBS table.
+ @param BbsType The BBS Type.
+ @param BbsCount The BBS Count.
+ @param Buf device order buffer.
+
+ @return The device order buffer.
+
+**/
+UINT16 *
+BdsFillDevOrderBuf (
+ IN BBS_TABLE *BbsTable,
+ IN BBS_TYPE BbsType,
+ IN UINTN BbsCount,
+ OUT UINT16 *Buf
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < BbsCount; Index++) {
+ if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) {
+ continue;
+ }
+
+ if (BbsTable[Index].DeviceType != BbsType) {
+ continue;
+ }
+
+ *Buf = (UINT16) (Index & 0xFF);
+ Buf++;
+ }
+
+ return Buf;
+}
+
+/**
+ Create the device order buffer.
+
+ @param BbsTable The BBS table.
+ @param BbsCount The BBS Count.
+
+ @retval EFI_SUCCES The buffer is created and the EFI variable named
+ VAR_LEGACY_DEV_ORDER and gEfiLegacyDevOrderVariableGuid is
+ set correctly.
+ @retval EFI_OUT_OF_RESOURCES Memmory or storage is not enough.
+ @retval EFI_DEVICE_ERROR Fail to add the device order into EFI variable fail
+ because of hardware error.
+**/
+EFI_STATUS
+BdsCreateDevOrder (
+ IN BBS_TABLE *BbsTable,
+ IN UINT16 BbsCount
+ )
+{
+ UINTN Index;
+ UINTN FDCount;
+ UINTN HDCount;
+ UINTN CDCount;
+ UINTN NETCount;
+ UINTN BEVCount;
+ UINTN TotalSize;
+ UINTN HeaderSize;
+ LEGACY_DEV_ORDER_ENTRY *DevOrder;
+ LEGACY_DEV_ORDER_ENTRY *DevOrderPtr;
+ EFI_STATUS Status;
+
+ FDCount = 0;
+ HDCount = 0;
+ CDCount = 0;
+ NETCount = 0;
+ BEVCount = 0;
+ TotalSize = 0;
+ HeaderSize = sizeof (BBS_TYPE) + sizeof (UINT16);
+ DevOrder = NULL;
+ Status = EFI_SUCCESS;
+
+ //
+ // Count all boot devices
+ //
+ for (Index = 0; Index < BbsCount; Index++) {
+ if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) {
+ continue;
+ }
+
+ switch (BbsTable[Index].DeviceType) {
+ case BBS_FLOPPY:
+ FDCount++;
+ break;
+
+ case BBS_HARDDISK:
+ HDCount++;
+ break;
+
+ case BBS_CDROM:
+ CDCount++;
+ break;
+
+ case BBS_EMBED_NETWORK:
+ NETCount++;
+ break;
+
+ case BBS_BEV_DEVICE:
+ BEVCount++;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ TotalSize += (HeaderSize + sizeof (UINT16) * FDCount);
+ TotalSize += (HeaderSize + sizeof (UINT16) * HDCount);
+ TotalSize += (HeaderSize + sizeof (UINT16) * CDCount);
+ TotalSize += (HeaderSize + sizeof (UINT16) * NETCount);
+ TotalSize += (HeaderSize + sizeof (UINT16) * BEVCount);
+
+ //
+ // Create buffer to hold all boot device order
+ //
+ DevOrder = AllocateZeroPool (TotalSize);
+ if (NULL == DevOrder) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ DevOrderPtr = DevOrder;
+
+ DevOrderPtr->BbsType = BBS_FLOPPY;
+ DevOrderPtr->Length = (UINT16) (sizeof (DevOrderPtr->Length) + FDCount * sizeof (UINT16));
+ DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_FLOPPY, BbsCount, DevOrderPtr->Data);
+
+ DevOrderPtr->BbsType = BBS_HARDDISK;
+ DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));
+ DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_HARDDISK, BbsCount, DevOrderPtr->Data);
+
+ DevOrderPtr->BbsType = BBS_CDROM;
+ DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));
+ DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_CDROM, BbsCount, DevOrderPtr->Data);
+
+ DevOrderPtr->BbsType = BBS_EMBED_NETWORK;
+ DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));
+ DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_EMBED_NETWORK, BbsCount, DevOrderPtr->Data);
+
+ DevOrderPtr->BbsType = BBS_BEV_DEVICE;
+ DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));
+ DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_BEV_DEVICE, BbsCount, DevOrderPtr->Data);
+
+ ASSERT (TotalSize == (UINTN) ((UINT8 *) DevOrderPtr - (UINT8 *) DevOrder));
+
+ //
+ // Save device order for legacy boot device to variable.
+ //
+ Status = gRT->SetVariable (
+ VAR_LEGACY_DEV_ORDER,
+ &gEfiLegacyDevOrderVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ TotalSize,
+ DevOrder
+ );
+ FreePool (DevOrder);
+
+ return Status;
+}
+
+/**
+ Add the legacy boot devices from BBS table into
+ the legacy device boot order.
+
+ @retval EFI_SUCCESS The boot devices are added successfully.
+ @retval EFI_NOT_FOUND The legacy boot devices are not found.
+ @retval EFI_OUT_OF_RESOURCES Memmory or storage is not enough.
+ @retval EFI_DEVICE_ERROR Fail to add the legacy device boot order into EFI variable
+ because of hardware error.
+**/
+EFI_STATUS
+EFIAPI
+BdsUpdateLegacyDevOrder (
+ VOID
+ )
+{
+ LEGACY_DEV_ORDER_ENTRY *DevOrder;
+ LEGACY_DEV_ORDER_ENTRY *NewDevOrder;
+ LEGACY_DEV_ORDER_ENTRY *Ptr;
+ LEGACY_DEV_ORDER_ENTRY *NewPtr;
+ UINTN DevOrderSize;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ EFI_STATUS Status;
+ UINT16 HddCount;
+ UINT16 BbsCount;
+ HDD_INFO *LocalHddInfo;
+ BBS_TABLE *LocalBbsTable;
+ UINTN Index;
+ UINTN Index2;
+ UINTN *Idx;
+ UINTN FDCount;
+ UINTN HDCount;
+ UINTN CDCount;
+ UINTN NETCount;
+ UINTN BEVCount;
+ UINTN TotalSize;
+ UINTN HeaderSize;
+ UINT16 *NewFDPtr;
+ UINT16 *NewHDPtr;
+ UINT16 *NewCDPtr;
+ UINT16 *NewNETPtr;
+ UINT16 *NewBEVPtr;
+ UINT16 *NewDevPtr;
+ UINTN FDIndex;
+ UINTN HDIndex;
+ UINTN CDIndex;
+ UINTN NETIndex;
+ UINTN BEVIndex;
+
+ Idx = NULL;
+ FDCount = 0;
+ HDCount = 0;
+ CDCount = 0;
+ NETCount = 0;
+ BEVCount = 0;
+ TotalSize = 0;
+ HeaderSize = sizeof (BBS_TYPE) + sizeof (UINT16);
+ FDIndex = 0;
+ HDIndex = 0;
+ CDIndex = 0;
+ NETIndex = 0;
+ BEVIndex = 0;
+ NewDevPtr = NULL;
+
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = LegacyBios->GetBbsInfo (
+ LegacyBios,
+ &HddCount,
+ &LocalHddInfo,
+ &BbsCount,
+ &LocalBbsTable
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DevOrder = BdsLibGetVariableAndSize (
+ VAR_LEGACY_DEV_ORDER,
+ &gEfiLegacyDevOrderVariableGuid,
+ &DevOrderSize
+ );
+ if (NULL == DevOrder) {
+ return BdsCreateDevOrder (LocalBbsTable, BbsCount);
+ }
+ //
+ // First we figure out how many boot devices with same device type respectively
+ //
+ for (Index = 0; Index < BbsCount; Index++) {
+ if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||
+ (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)
+ ) {
+ continue;
+ }
+
+ switch (LocalBbsTable[Index].DeviceType) {
+ case BBS_FLOPPY:
+ FDCount++;
+ break;
+
+ case BBS_HARDDISK:
+ HDCount++;
+ break;
+
+ case BBS_CDROM:
+ CDCount++;
+ break;
+
+ case BBS_EMBED_NETWORK:
+ NETCount++;
+ break;
+
+ case BBS_BEV_DEVICE:
+ BEVCount++;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ TotalSize += (HeaderSize + FDCount * sizeof (UINT16));
+ TotalSize += (HeaderSize + HDCount * sizeof (UINT16));
+ TotalSize += (HeaderSize + CDCount * sizeof (UINT16));
+ TotalSize += (HeaderSize + NETCount * sizeof (UINT16));
+ TotalSize += (HeaderSize + BEVCount * sizeof (UINT16));
+
+ NewDevOrder = AllocateZeroPool (TotalSize);
+ if (NULL == NewDevOrder) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+
+
+ //
+ // copy FD
+ //
+ Ptr = DevOrder;
+ NewPtr = NewDevOrder;
+ NewPtr->BbsType = Ptr->BbsType;
+ NewPtr->Length = (UINT16) (sizeof (UINT16) + FDCount * sizeof (UINT16));
+ for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
+ if (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_FLOPPY
+ ) {
+ continue;
+ }
+
+ NewPtr->Data[FDIndex] = Ptr->Data[Index];
+ FDIndex++;
+ }
+ NewFDPtr = NewPtr->Data;
+
+ //
+ // copy HD
+ //
+ Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);
+ NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);
+ NewPtr->BbsType = Ptr->BbsType;
+ NewPtr->Length = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));
+ for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
+ if (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_HARDDISK
+ ) {
+ continue;
+ }
+
+ NewPtr->Data[HDIndex] = Ptr->Data[Index];
+ HDIndex++;
+ }
+ NewHDPtr = NewPtr->Data;
+
+ //
+ // copy CD
+ //
+ Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);
+ NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);
+ NewPtr->BbsType = Ptr->BbsType;
+ NewPtr->Length = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));
+ for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
+ if (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_CDROM
+ ) {
+ continue;
+ }
+
+ NewPtr->Data[CDIndex] = Ptr->Data[Index];
+ CDIndex++;
+ }
+ NewCDPtr = NewPtr->Data;
+
+ //
+ // copy NET
+ //
+ Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);
+ NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);
+ NewPtr->BbsType = Ptr->BbsType;
+ NewPtr->Length = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));
+ for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
+ if (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_EMBED_NETWORK
+ ) {
+ continue;
+ }
+
+ NewPtr->Data[NETIndex] = Ptr->Data[Index];
+ NETIndex++;
+ }
+ NewNETPtr = NewPtr->Data;
+
+ //
+ // copy BEV
+ //
+ Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);
+ NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);
+ NewPtr->BbsType = Ptr->BbsType;
+ NewPtr->Length = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));
+ for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
+ if (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_BEV_DEVICE
+ ) {
+ continue;
+ }
+
+ NewPtr->Data[BEVIndex] = Ptr->Data[Index];
+ BEVIndex++;
+ }
+ NewBEVPtr = NewPtr->Data;
+
+ for (Index = 0; Index < BbsCount; Index++) {
+ if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||
+ (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)
+ ) {
+ continue;
+ }
+
+ switch (LocalBbsTable[Index].DeviceType) {
+ case BBS_FLOPPY:
+ Idx = &FDIndex;
+ NewDevPtr = NewFDPtr;
+ break;
+
+ case BBS_HARDDISK:
+ Idx = &HDIndex;
+ NewDevPtr = NewHDPtr;
+ break;
+
+ case BBS_CDROM:
+ Idx = &CDIndex;
+ NewDevPtr = NewCDPtr;
+ break;
+
+ case BBS_EMBED_NETWORK:
+ Idx = &NETIndex;
+ NewDevPtr = NewNETPtr;
+ break;
+
+ case BBS_BEV_DEVICE:
+ Idx = &BEVIndex;
+ NewDevPtr = NewBEVPtr;
+ break;
+
+ default:
+ Idx = NULL;
+ break;
+ }
+ //
+ // at this point we have copied those valid indexes to new buffer
+ // and we should check if there is any new appeared boot device
+ //
+ if (Idx != NULL) {
+ for (Index2 = 0; Index2 < *Idx; Index2++) {
+ if ((NewDevPtr[Index2] & 0xFF) == (UINT16) Index) {
+ break;
+ }
+ }
+
+ if (Index2 == *Idx) {
+ //
+ // Index2 == *Idx means we didn't find Index
+ // so Index is a new appeared device's index in BBS table
+ // insert it before disabled indexes.
+ //
+ for (Index2 = 0; Index2 < *Idx; Index2++) {
+ if ((NewDevPtr[Index2] & 0xFF00) == 0xFF00) {
+ break;
+ }
+ }
+ CopyMem (&NewDevPtr[Index2 + 1], &NewDevPtr[Index2], (*Idx - Index2) * sizeof (UINT16));
+ NewDevPtr[Index2] = (UINT16) (Index & 0xFF);
+ (*Idx)++;
+ }
+ }
+ }
+
+ FreePool (DevOrder);
+
+ Status = gRT->SetVariable (
+ VAR_LEGACY_DEV_ORDER,
+ &gEfiLegacyDevOrderVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ TotalSize,
+ NewDevOrder
+ );
+ FreePool (NewDevOrder);
+
+ return Status;
+}
+
+/**
+ Set Boot Priority for specified device type.
+
+ @param DeviceType The device type.
+ @param BbsIndex The BBS index to set the highest priority. Ignore when -1.
+ @param LocalBbsTable The BBS table.
+ @param Priority The prority table.
+
+ @retval EFI_SUCCESS The function completes successfully.
+ @retval EFI_NOT_FOUND Failed to find device.
+ @retval EFI_OUT_OF_RESOURCES Failed to get the efi variable of device order.
+
+**/
+EFI_STATUS
+BdsSetBootPriority4SameTypeDev (
+ IN UINT16 DeviceType,
+ IN UINTN BbsIndex,
+ IN OUT BBS_TABLE *LocalBbsTable,
+ IN OUT UINT16 *Priority
+ )
+{
+ LEGACY_DEV_ORDER_ENTRY *DevOrder;
+ LEGACY_DEV_ORDER_ENTRY *DevOrderPtr;
+ UINTN DevOrderSize;
+ UINTN Index;
+
+ DevOrder = BdsLibGetVariableAndSize (
+ VAR_LEGACY_DEV_ORDER,
+ &gEfiLegacyDevOrderVariableGuid,
+ &DevOrderSize
+ );
+ if (NULL == DevOrder) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DevOrderPtr = DevOrder;
+ while ((UINT8 *) DevOrderPtr < (UINT8 *) DevOrder + DevOrderSize) {
+ if (DevOrderPtr->BbsType == DeviceType) {
+ break;
+ }
+
+ DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) ((UINTN) DevOrderPtr + sizeof (BBS_TYPE) + DevOrderPtr->Length);
+ }
+
+ if ((UINT8 *) DevOrderPtr >= (UINT8 *) DevOrder + DevOrderSize) {
+ FreePool (DevOrder);
+ return EFI_NOT_FOUND;
+ }
+
+ if (BbsIndex != (UINTN) -1) {
+ LocalBbsTable[BbsIndex].BootPriority = *Priority;
+ (*Priority)++;
+ }
+ //
+ // If the high byte of the DevIndex is 0xFF, it indicates that this device has been disabled.
+ //
+ for (Index = 0; Index < DevOrderPtr->Length / sizeof (UINT16) - 1; Index++) {
+ if ((DevOrderPtr->Data[Index] & 0xFF00) == 0xFF00) {
+ //
+ // LocalBbsTable[DevIndex[Index] & 0xFF].BootPriority = BBS_DISABLED_ENTRY;
+ //
+ } else if (DevOrderPtr->Data[Index] != BbsIndex) {
+ LocalBbsTable[DevOrderPtr->Data[Index]].BootPriority = *Priority;
+ (*Priority)++;
+ }
+ }
+
+ FreePool (DevOrder);
+ return EFI_SUCCESS;
+}
+
+/**
+ Print the BBS Table.
+
+ @param LocalBbsTable The BBS table.
+ @param BbsCount The count of entry in BBS table.
+**/
+VOID
+PrintBbsTable (
+ IN BBS_TABLE *LocalBbsTable,
+ IN UINT16 BbsCount
+ )
+{
+ UINT16 Idx;
+
+ DEBUG ((DEBUG_ERROR, "\n"));
+ DEBUG ((DEBUG_ERROR, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs\n"));
+ DEBUG ((DEBUG_ERROR, "=============================================\n"));
+ for (Idx = 0; Idx < BbsCount; Idx++) {
+ if ((LocalBbsTable[Idx].BootPriority == BBS_IGNORE_ENTRY) ||
+ (LocalBbsTable[Idx].BootPriority == BBS_DO_NOT_BOOT_FROM) ||
+ (LocalBbsTable[Idx].BootPriority == BBS_LOWEST_PRIORITY)
+ ) {
+ continue;
+ }
+
+ DEBUG (
+ (DEBUG_ERROR,
+ " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x %04x:%04x\n",
+ (UINTN) Idx,
+ (UINTN) LocalBbsTable[Idx].BootPriority,
+ (UINTN) LocalBbsTable[Idx].Bus,
+ (UINTN) LocalBbsTable[Idx].Device,
+ (UINTN) LocalBbsTable[Idx].Function,
+ (UINTN) LocalBbsTable[Idx].Class,
+ (UINTN) LocalBbsTable[Idx].SubClass,
+ (UINTN) LocalBbsTable[Idx].DeviceType,
+ (UINTN) * (UINT16 *) &LocalBbsTable[Idx].StatusFlags,
+ (UINTN) LocalBbsTable[Idx].BootHandlerSegment,
+ (UINTN) LocalBbsTable[Idx].BootHandlerOffset,
+ (UINTN) ((LocalBbsTable[Idx].MfgStringSegment << 4) + LocalBbsTable[Idx].MfgStringOffset),
+ (UINTN) ((LocalBbsTable[Idx].DescStringSegment << 4) + LocalBbsTable[Idx].DescStringOffset))
+ );
+ }
+
+ DEBUG ((DEBUG_ERROR, "\n"));
+}
+
+/**
+ Set the boot priority for BBS entries based on boot option entry and boot order.
+
+ @param Entry The boot option is to be checked for refresh BBS table.
+
+ @retval EFI_SUCCESS The boot priority for BBS entries is refreshed successfully.
+ @retval EFI_NOT_FOUND BBS entries can't be found.
+ @retval EFI_OUT_OF_RESOURCES Failed to get the legacy device boot order.
+**/
+EFI_STATUS
+EFIAPI
+BdsRefreshBbsTableForBoot (
+ IN BDS_COMMON_OPTION *Entry
+ )
+{
+ EFI_STATUS Status;
+ UINT16 BbsIndex;
+ UINT16 HddCount;
+ UINT16 BbsCount;
+ HDD_INFO *LocalHddInfo;
+ BBS_TABLE *LocalBbsTable;
+ UINT16 DevType;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ UINTN Index;
+ UINT16 Priority;
+ UINT16 *BootOrder;
+ UINTN BootOrderSize;
+ UINT8 *BootOptionVar;
+ UINTN BootOptionSize;
+ CHAR16 BootOption[9];
+ UINT8 *Ptr;
+ UINT16 DevPathLen;
+ EFI_DEVICE_PATH_PROTOCOL *DevPath;
+ UINT16 *DeviceType;
+ UINTN DeviceTypeCount;
+ UINTN DeviceTypeIndex;
+
+ HddCount = 0;
+ BbsCount = 0;
+ LocalHddInfo = NULL;
+ LocalBbsTable = NULL;
+ DevType = BBS_UNKNOWN;
+
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ LegacyBios->GetBbsInfo (
+ LegacyBios,
+ &HddCount,
+ &LocalHddInfo,
+ &BbsCount,
+ &LocalBbsTable
+ );
+ //
+ // First, set all the present devices' boot priority to BBS_UNPRIORITIZED_ENTRY
+ // We will set them according to the settings setup by user
+ //
+ for (Index = 0; Index < BbsCount; Index++) {
+ if (!((BBS_IGNORE_ENTRY == LocalBbsTable[Index].BootPriority) ||
+ (BBS_DO_NOT_BOOT_FROM == LocalBbsTable[Index].BootPriority) ||
+ (BBS_LOWEST_PRIORITY == LocalBbsTable[Index].BootPriority))) {
+ LocalBbsTable[Index].BootPriority = BBS_UNPRIORITIZED_ENTRY;
+ }
+ }
+ //
+ // boot priority always starts at 0
+ //
+ Priority = 0;
+ if (Entry->LoadOptionsSize == sizeof (BBS_TABLE) + sizeof (UINT16)) {
+ //
+ // If Entry stands for a legacy boot option, we prioritize the devices with the same type first.
+ //
+ DevType = ((BBS_TABLE *) Entry->LoadOptions)->DeviceType;
+ BbsIndex = *(UINT16 *) ((BBS_TABLE *) Entry->LoadOptions + 1);
+ Status = BdsSetBootPriority4SameTypeDev (
+ DevType,
+ BbsIndex,
+ LocalBbsTable,
+ &Priority
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ //
+ // we have to set the boot priority for other BBS entries with different device types
+ //
+ BootOrder = BdsLibGetVariableAndSize (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ &BootOrderSize
+ );
+ DeviceType = AllocatePool (BootOrderSize + sizeof (UINT16));
+ ASSERT (DeviceType != NULL);
+
+ DeviceType[0] = DevType;
+ DeviceTypeCount = 1;
+ for (Index = 0; ((BootOrder != NULL) && (Index < BootOrderSize / sizeof (UINT16))); Index++) {
+ UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
+ BootOptionVar = BdsLibGetVariableAndSize (
+ BootOption,
+ &gEfiGlobalVariableGuid,
+ &BootOptionSize
+ );
+ if (NULL == BootOptionVar) {
+ continue;
+ }
+
+ Ptr = BootOptionVar;
+
+ Ptr += sizeof (UINT32);
+ DevPathLen = *(UINT16 *) Ptr;
+ Ptr += sizeof (UINT16);
+ Ptr += StrSize ((UINT16 *) Ptr);
+ DevPath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
+ if (BBS_DEVICE_PATH != DevPath->Type || BBS_BBS_DP != DevPath->SubType) {
+ FreePool (BootOptionVar);
+ continue;
+ }
+
+ Ptr += DevPathLen;
+ DevType = ((BBS_TABLE *) Ptr)->DeviceType;
+ for (DeviceTypeIndex = 0; DeviceTypeIndex < DeviceTypeCount; DeviceTypeIndex++) {
+ if (DeviceType[DeviceTypeIndex] == DevType) {
+ break;
+ }
+ }
+ if (DeviceTypeIndex < DeviceTypeCount) {
+ //
+ // We don't want to process twice for a device type
+ //
+ FreePool (BootOptionVar);
+ continue;
+ }
+
+ DeviceType[DeviceTypeCount] = DevType;
+ DeviceTypeCount++;
+
+ Status = BdsSetBootPriority4SameTypeDev (
+ DevType,
+ (UINTN) -1,
+ LocalBbsTable,
+ &Priority
+ );
+ FreePool (BootOptionVar);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ FreePool (DeviceType);
+
+ if (BootOrder != NULL) {
+ FreePool (BootOrder);
+ }
+
+ DEBUG_CODE_BEGIN();
+ PrintBbsTable (LocalBbsTable, BbsCount);
+ DEBUG_CODE_END();
+
+ return Status;
+}
+
+/**
+ Connect SATA Device and SDCard Device.
+
+ @param None
+
+ @retval EFI_SUCCESS Connect SATA Device and SDCard Device successfully.
+ @retval EFI_UNSUPPORTED
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformBdsConnectStorageDevice (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 PciData;
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ for (Index = 0; Index < HandleCount; Index++) {
+
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0,
+ sizeof (PciData),
+ &PciData
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if ((PciData.Hdr.ClassCode[2] == PCI_CLASS_MASS_STORAGE && PciData.Hdr.ClassCode[1] == PCI_CLASS_MASS_STORAGE_IDE)
+ || (PciData.Hdr.ClassCode[2] == PCI_CLASS_MASS_STORAGE && PciData.Hdr.ClassCode[1] == PCI_CLASS_MASS_STORAGE_SATADPA)
+ || ((PciData.Hdr.ClassCode[2] == 0x08 && PciData.Hdr.ClassCode[1] == 0x05 && PciData.Hdr.ClassCode[0] == 0x01) && (PciData.Hdr.DeviceId == 0x2296))) {
+ //
+ //IDE Controller or AHCI Controller or SDCard Controller
+ //
+ gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);
+ }
+ }
+
+ for (Index = 0; Index < HandleCount; Index++) {
+
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0,
+ sizeof (PciData),
+ &PciData
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if ((PciData.Hdr.ClassCode[2] == PCI_CLASS_MASS_STORAGE && PciData.Hdr.ClassCode[1] == PCI_CLASS_MASS_STORAGE_IDE)
+ || (PciData.Hdr.ClassCode[2] == PCI_CLASS_MASS_STORAGE && PciData.Hdr.ClassCode[1] == PCI_CLASS_MASS_STORAGE_SATADPA)
+ || ((PciData.Hdr.ClassCode[2] == 0x08 && PciData.Hdr.ClassCode[1] == 0x05 && PciData.Hdr.ClassCode[0] == 0x01) && (PciData.Hdr.DeviceId == 0x2296))) {
+ //
+ //IDE Controller or AHCI Controller or SDCard Controller
+ //
+ gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
+ }
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Connect SATA Device and SDCard Device according to Device Path.
+
+ @param[in] DevicePath
+
+**/
+VOID
+PlatformBdsConnectStorageDeviceFromDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+
+ TempDevicePath = DevicePath;
+
+ while (!IsDevicePathEnd (TempDevicePath)) {
+ if ((((DevicePathType (TempDevicePath) == MESSAGING_DEVICE_PATH)) && ((DevicePathSubType (TempDevicePath) == MSG_SATA_DP)))
+ || (((DevicePathType (TempDevicePath) == MESSAGING_DEVICE_PATH)) && ((DevicePathSubType (TempDevicePath) == 0x11)))) {
+ PlatformBdsConnectStorageDevice();
+ break;
+ }
+ TempDevicePath = NextDevicePathNode (TempDevicePath);
+ }
+}
+
+/**
+ Boot the legacy system with the boot option
+
+ @param Option The legacy boot option which have BBS device path
+
+ @retval EFI_UNSUPPORTED There is no legacybios protocol, do not support
+ legacy boot.
+ @retval EFI_STATUS Return the status of LegacyBios->LegacyBoot ().
+
+**/
+EFI_STATUS
+BdsLibDoLegacyBoot (
+ IN BDS_COMMON_OPTION *Option
+ )
+{
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ EFI_EVENT LegacyBootEvent;
+
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ //
+ // If no LegacyBios protocol we do not support legacy boot
+ //
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Notes: if we separate the int 19, then we don't need to refresh BBS
+ //
+ BdsRefreshBbsTableForBoot (Option);
+
+ //
+ // Write boot to OS performance data for legacy boot.
+ //
+ PERF_CODE (
+ //
+ // Create an event to be signalled when Legacy Boot occurs to write performance data.
+ //
+ Status = EfiCreateEventLegacyBootEx(
+ TPL_NOTIFY,
+ WriteBootToOsPerformanceData,
+ NULL,
+ &LegacyBootEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+ );
+
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Legacy Boot: %S\n", Option->Description));
+ return LegacyBios->LegacyBoot (
+ LegacyBios,
+ (BBS_BBS_DEVICE_PATH *) Option->DevicePath,
+ Option->LoadOptionsSize,
+ Option->LoadOptions
+ );
+}
+
+/**
+ Internal function to check if the input boot option is a valid EFI NV Boot####.
+
+ @param OptionToCheck Boot option to be checked.
+
+ @retval TRUE This boot option matches a valid EFI NV Boot####.
+ @retval FALSE If not.
+
+**/
+BOOLEAN
+IsBootOptionValidNVVarialbe (
+ IN BDS_COMMON_OPTION *OptionToCheck
+ )
+{
+ LIST_ENTRY TempList;
+ BDS_COMMON_OPTION *BootOption;
+ BOOLEAN Valid;
+ CHAR16 OptionName[20];
+
+ Valid = FALSE;
+
+ InitializeListHead (&TempList);
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", OptionToCheck->BootCurrent);
+
+ BootOption = BdsLibVariableToOption (&TempList, OptionName);
+ if (BootOption == NULL) {
+ return FALSE;
+ }
+
+ //
+ // If the Boot Option Number and Device Path matches, OptionToCheck matches a
+ // valid EFI NV Boot####.
+ //
+ if ((OptionToCheck->BootCurrent == BootOption->BootCurrent) &&
+ (CompareMem (OptionToCheck->DevicePath, BootOption->DevicePath, GetDevicePathSize (OptionToCheck->DevicePath)) == 0))
+ {
+ Valid = TRUE;
+ }
+
+ FreePool (BootOption);
+
+ return Valid;
+}
+
+/**
+ Check whether a USB device match the specified USB Class device path. This
+ function follows "Load Option Processing" behavior in UEFI specification.
+
+ @param UsbIo USB I/O protocol associated with the USB device.
+ @param UsbClass The USB Class device path to match.
+
+ @retval TRUE The USB device match the USB Class device path.
+ @retval FALSE The USB device does not match the USB Class device path.
+
+**/
+BOOLEAN
+BdsMatchUsbClass (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ IN USB_CLASS_DEVICE_PATH *UsbClass
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_DEVICE_DESCRIPTOR DevDesc;
+ EFI_USB_INTERFACE_DESCRIPTOR IfDesc;
+ UINT8 DeviceClass;
+ UINT8 DeviceSubClass;
+ UINT8 DeviceProtocol;
+
+ if ((DevicePathType (UsbClass) != MESSAGING_DEVICE_PATH) ||
+ (DevicePathSubType (UsbClass) != MSG_USB_CLASS_DP)){
+ return FALSE;
+ }
+
+ //
+ // Check Vendor Id and Product Id.
+ //
+ Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ if ((UsbClass->VendorId != 0xffff) &&
+ (UsbClass->VendorId != DevDesc.IdVendor)) {
+ return FALSE;
+ }
+
+ if ((UsbClass->ProductId != 0xffff) &&
+ (UsbClass->ProductId != DevDesc.IdProduct)) {
+ return FALSE;
+ }
+
+ DeviceClass = DevDesc.DeviceClass;
+ DeviceSubClass = DevDesc.DeviceSubClass;
+ DeviceProtocol = DevDesc.DeviceProtocol;
+ if (DeviceClass == 0) {
+ //
+ // If Class in Device Descriptor is set to 0, use the Class, SubClass and
+ // Protocol in Interface Descriptor instead.
+ //
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ DeviceClass = IfDesc.InterfaceClass;
+ DeviceSubClass = IfDesc.InterfaceSubClass;
+ DeviceProtocol = IfDesc.InterfaceProtocol;
+ }
+
+ //
+ // Check Class, SubClass and Protocol.
+ //
+ if ((UsbClass->DeviceClass != 0xff) &&
+ (UsbClass->DeviceClass != DeviceClass)) {
+ return FALSE;
+ }
+
+ if ((UsbClass->DeviceSubClass != 0xff) &&
+ (UsbClass->DeviceSubClass != DeviceSubClass)) {
+ return FALSE;
+ }
+
+ if ((UsbClass->DeviceProtocol != 0xff) &&
+ (UsbClass->DeviceProtocol != DeviceProtocol)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Check whether a USB device match the specified USB WWID device path. This
+ function follows "Load Option Processing" behavior in UEFI specification.
+
+ @param UsbIo USB I/O protocol associated with the USB device.
+ @param UsbWwid The USB WWID device path to match.
+
+ @retval TRUE The USB device match the USB WWID device path.
+ @retval FALSE The USB device does not match the USB WWID device path.
+
+**/
+BOOLEAN
+BdsMatchUsbWwid (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ IN USB_WWID_DEVICE_PATH *UsbWwid
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_DEVICE_DESCRIPTOR DevDesc;
+ EFI_USB_INTERFACE_DESCRIPTOR IfDesc;
+ UINT16 *LangIdTable;
+ UINT16 TableSize;
+ UINT16 Index;
+ CHAR16 *CompareStr;
+ UINTN CompareLen;
+ CHAR16 *SerialNumberStr;
+ UINTN Length;
+
+ if ((DevicePathType (UsbWwid) != MESSAGING_DEVICE_PATH) ||
+ (DevicePathSubType (UsbWwid) != MSG_USB_WWID_DP )){
+ return FALSE;
+ }
+
+ //
+ // Check Vendor Id and Product Id.
+ //
+ Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+ if ((DevDesc.IdVendor != UsbWwid->VendorId) ||
+ (DevDesc.IdProduct != UsbWwid->ProductId)) {
+ return FALSE;
+ }
+
+ //
+ // Check Interface Number.
+ //
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+ if (IfDesc.InterfaceNumber != UsbWwid->InterfaceNumber) {
+ return FALSE;
+ }
+
+ //
+ // Check Serial Number.
+ //
+ if (DevDesc.StrSerialNumber == 0) {
+ return FALSE;
+ }
+
+ //
+ // Get all supported languages.
+ //
+ TableSize = 0;
+ LangIdTable = NULL;
+ Status = UsbIo->UsbGetSupportedLanguages (UsbIo, &LangIdTable, &TableSize);
+ if (EFI_ERROR (Status) || (TableSize == 0) || (LangIdTable == NULL)) {
+ return FALSE;
+ }
+
+ //
+ // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
+ //
+ CompareStr = (CHAR16 *) (UINTN) (UsbWwid + 1);
+ CompareLen = (DevicePathNodeLength (UsbWwid) - sizeof (USB_WWID_DEVICE_PATH)) / sizeof (CHAR16);
+ if (CompareStr[CompareLen - 1] == L'\0') {
+ CompareLen--;
+ }
+
+ //
+ // Compare serial number in each supported language.
+ //
+ for (Index = 0; Index < TableSize / sizeof (UINT16); Index++) {
+ SerialNumberStr = NULL;
+ Status = UsbIo->UsbGetStringDescriptor (
+ UsbIo,
+ LangIdTable[Index],
+ DevDesc.StrSerialNumber,
+ &SerialNumberStr
+ );
+ if (EFI_ERROR (Status) || (SerialNumberStr == NULL)) {
+ continue;
+ }
+
+ Length = StrLen (SerialNumberStr);
+ if ((Length >= CompareLen) &&
+ (CompareMem (SerialNumberStr + Length - CompareLen, CompareStr, CompareLen * sizeof (CHAR16)) == 0)) {
+ FreePool (SerialNumberStr);
+ return TRUE;
+ }
+
+ FreePool (SerialNumberStr);
+ }
+
+ return FALSE;
+}
+
+/**
+ Find a USB device path which match the specified short-form device path start
+ with USB Class or USB WWID device path and load the boot file then return the
+ image handle. If ParentDevicePath is NULL, this function will search in all USB
+ devices of the platform. If ParentDevicePath is not NULL,this function will only
+ search in its child devices.
+
+ @param ParentDevicePath The device path of the parent.
+ @param ShortFormDevicePath The USB Class or USB WWID device path to match.
+
+ @return The image Handle if find load file from specified short-form device path
+ or NULL if not found.
+
+**/
+EFI_HANDLE *
+BdsFindUsbDevice (
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *ShortFormDevicePath
+ )
+{
+ EFI_STATUS Status;
+ UINTN UsbIoHandleCount;
+ EFI_HANDLE *UsbIoHandleBuffer;
+ EFI_DEVICE_PATH_PROTOCOL *UsbIoDevicePath;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ UINTN Index;
+ UINTN ParentSize;
+ UINTN Size;
+ EFI_HANDLE ImageHandle;
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *NextDevicePath;
+
+ FullDevicePath = NULL;
+ ImageHandle = NULL;
+
+ //
+ // Get all UsbIo Handles.
+ //
+ UsbIoHandleCount = 0;
+ UsbIoHandleBuffer = NULL;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiUsbIoProtocolGuid,
+ NULL,
+ &UsbIoHandleCount,
+ &UsbIoHandleBuffer
+ );
+ if (EFI_ERROR (Status) || (UsbIoHandleCount == 0) || (UsbIoHandleBuffer == NULL)) {
+ return NULL;
+ }
+
+ ParentSize = (ParentDevicePath == NULL) ? 0 : GetDevicePathSize (ParentDevicePath);
+ for (Index = 0; Index < UsbIoHandleCount; Index++) {
+ //
+ // Get the Usb IO interface.
+ //
+ Status = gBS->HandleProtocol(
+ UsbIoHandleBuffer[Index],
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ UsbIoDevicePath = DevicePathFromHandle (UsbIoHandleBuffer[Index]);
+ if (UsbIoDevicePath == NULL) {
+ continue;
+ }
+
+ if (ParentDevicePath != NULL) {
+ //
+ // Compare starting part of UsbIoHandle's device path with ParentDevicePath.
+ //
+ Size = GetDevicePathSize (UsbIoDevicePath);
+ if ((Size < ParentSize) ||
+ (CompareMem (UsbIoDevicePath, ParentDevicePath, ParentSize - END_DEVICE_PATH_LENGTH) != 0)) {
+ continue;
+ }
+ }
+
+ if (BdsMatchUsbClass (UsbIo, (USB_CLASS_DEVICE_PATH *) ShortFormDevicePath) ||
+ BdsMatchUsbWwid (UsbIo, (USB_WWID_DEVICE_PATH *) ShortFormDevicePath)) {
+ //
+ // Try to find if there is the boot file in this DevicePath
+ //
+ NextDevicePath = NextDevicePathNode (ShortFormDevicePath);
+ if (!IsDevicePathEnd (NextDevicePath)) {
+ FullDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePath);
+ //
+ // Connect the full device path, so that Simple File System protocol
+ // could be installed for this USB device.
+ //
+ BdsLibConnectDevicePath (FullDevicePath);
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));
+ Status = gBS->LoadImage (
+ TRUE,
+ gImageHandle,
+ FullDevicePath,
+ NULL,
+ 0,
+ &ImageHandle
+ );
+ FreePool (FullDevicePath);
+ } else {
+ FullDevicePath = UsbIoDevicePath;
+ Status = EFI_NOT_FOUND;
+ }
+
+ //
+ // If we didn't find an image directly, we need to try as if it is a removable device boot option
+ // and load the image according to the default boot behavior for removable device.
+ //
+ if (EFI_ERROR (Status)) {
+ //
+ // check if there is a bootable removable media could be found in this device path ,
+ // and get the bootable media handle
+ //
+ Handle = BdsLibGetBootableHandle(UsbIoDevicePath);
+ if (Handle == NULL) {
+ continue;
+ }
+ //
+ // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
+ // machinename is ia32, ia64, x64, ...
+ //
+ FullDevicePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
+ if (FullDevicePath != NULL) {
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));
+ Status = gBS->LoadImage (
+ TRUE,
+ gImageHandle,
+ FullDevicePath,
+ NULL,
+ 0,
+ &ImageHandle
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // The DevicePath failed, and it's not a valid
+ // removable media device.
+ //
+ continue;
+ }
+ } else {
+ continue;
+ }
+ }
+ break;
+ }
+ }
+
+ FreePool (UsbIoHandleBuffer);
+ return ImageHandle;
+}
+
+/**
+ Expand USB Class or USB WWID device path node to be full device path of a USB
+ device in platform then load the boot file on this full device path and return the
+ image handle.
+
+ This function support following 4 cases:
+ 1) Boot Option device path starts with a USB Class or USB WWID device path,
+ and there is no Media FilePath device path in the end.
+ In this case, it will follow Removable Media Boot Behavior.
+ 2) Boot Option device path starts with a USB Class or USB WWID device path,
+ and ended with Media FilePath device path.
+ 3) Boot Option device path starts with a full device path to a USB Host Controller,
+ contains a USB Class or USB WWID device path node, while not ended with Media
+ FilePath device path. In this case, it will follow Removable Media Boot Behavior.
+ 4) Boot Option device path starts with a full device path to a USB Host Controller,
+ contains a USB Class or USB WWID device path node, and ended with Media
+ FilePath device path.
+
+ @param DevicePath The Boot Option device path.
+
+ @return The image handle of boot file, or NULL if there is no boot file found in
+ the specified USB Class or USB WWID device path.
+
+**/
+EFI_HANDLE *
+BdsExpandUsbShortFormDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_HANDLE *ImageHandle;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *ShortFormDevicePath;
+
+ //
+ // Search for USB Class or USB WWID device path node.
+ //
+ ShortFormDevicePath = NULL;
+ ImageHandle = NULL;
+ TempDevicePath = DevicePath;
+ while (!IsDevicePathEnd (TempDevicePath)) {
+ if ((DevicePathType (TempDevicePath) == MESSAGING_DEVICE_PATH) &&
+ ((DevicePathSubType (TempDevicePath) == MSG_USB_CLASS_DP) ||
+ (DevicePathSubType (TempDevicePath) == MSG_USB_WWID_DP))) {
+ ShortFormDevicePath = TempDevicePath;
+ break;
+ }
+ TempDevicePath = NextDevicePathNode (TempDevicePath);
+ }
+
+ if (ShortFormDevicePath == NULL) {
+ //
+ // No USB Class or USB WWID device path node found, do nothing.
+ //
+ return NULL;
+ }
+
+ if (ShortFormDevicePath == DevicePath) {
+ //
+ // Boot Option device path starts with USB Class or USB WWID device path.
+ //
+ ImageHandle = BdsFindUsbDevice (NULL, ShortFormDevicePath);
+ if (ImageHandle == NULL) {
+ //
+ // Failed to find a match in existing devices, connect the short form USB
+ // device path and try again.
+ //
+ BdsLibConnectUsbDevByShortFormDP (0xff, ShortFormDevicePath);
+ ImageHandle = BdsFindUsbDevice (NULL, ShortFormDevicePath);
+ }
+ } else {
+ //
+ // Boot Option device path contains USB Class or USB WWID device path node.
+ //
+
+ //
+ // Prepare the parent device path for search.
+ //
+ TempDevicePath = DuplicateDevicePath (DevicePath);
+ ASSERT (TempDevicePath != NULL);
+ SetDevicePathEndNode (((UINT8 *) TempDevicePath) + ((UINTN) ShortFormDevicePath - (UINTN) DevicePath));
+
+ //
+ // The USB Host Controller device path is already in Boot Option device path
+ // and USB Bus driver already support RemainingDevicePath starts with USB
+ // Class or USB WWID device path, so just search in existing USB devices and
+ // doesn't perform ConnectController here.
+ //
+ ImageHandle = BdsFindUsbDevice (TempDevicePath, ShortFormDevicePath);
+ FreePool (TempDevicePath);
+ }
+
+ return ImageHandle;
+}
+
+/**
+ Process the boot option follow the UEFI specification and
+ special treat the legacy boot option with BBS_DEVICE_PATH.
+
+ @param Option The boot option need to be processed
+ @param DevicePath The device path which describe where to load the
+ boot image or the legacy BBS device path to boot
+ the legacy OS
+ @param ExitDataSize The size of exit data.
+ @param ExitData Data returned when Boot image failed.
+
+ @retval EFI_SUCCESS Boot from the input boot option successfully.
+ @retval EFI_NOT_FOUND If the Device Path is not found in the system
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibBootViaBootOption (
+ IN BDS_COMMON_OPTION *Option,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT UINTN *ExitDataSize,
+ OUT CHAR16 **ExitData OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS StatusLogo;
+ EFI_HANDLE Handle;
+ EFI_HANDLE ImageHandle;
+ EFI_DEVICE_PATH_PROTOCOL *FilePath;
+ EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
+ EFI_DEVICE_PATH_PROTOCOL *WorkingDevicePath;
+ LIST_ENTRY TempBootLists;
+ EFI_BOOT_LOGO_PROTOCOL *BootLogo;
+ EFI_BOOT_MODE BootMode;
+
+ Status = EFI_SUCCESS;
+ *ExitDataSize = 0;
+ *ExitData = NULL;
+
+ //
+ // If it's Device Path that starts with a hard drive path, append it with the front part to compose a
+ // full device path
+ //
+ WorkingDevicePath = NULL;
+ if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
+ (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)) {
+ WorkingDevicePath = BdsExpandPartitionPartialDevicePathToFull (
+ (HARDDRIVE_DEVICE_PATH *)DevicePath
+ );
+ if (WorkingDevicePath != NULL) {
+ DevicePath = WorkingDevicePath;
+ }
+ }
+
+ //
+ // Set Boot Current
+ //
+ if (IsBootOptionValidNVVarialbe (Option)) {
+ //
+ // For a temporary boot (i.e. a boot by selected a EFI Shell using "Boot From File"), Boot Current is actually not valid.
+ // In this case, "BootCurrent" is not created.
+ // Only create the BootCurrent variable when it points to a valid Boot#### variable.
+ //
+ SetVariableAndReportStatusCodeOnError (
+ L"BootCurrent",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof (UINT16),
+ &Option->BootCurrent
+ );
+ }
+
+ //
+ // Signal the EVT_SIGNAL_READY_TO_BOOT event
+ //
+ EfiSignalEventReadyToBoot();
+
+ //
+ // Get current Boot Mode
+ //
+ BootMode = GetBootModeHob();
+
+ if ((BootMode != BOOT_WITH_MINIMAL_CONFIGURATION) && (BootMode != BOOT_ASSUMING_NO_CONFIGURATION_CHANGES)) {
+ //
+ // Connect Storage Device.(eg:SATA Device and SDCard Device)
+ //
+ PlatformBdsConnectStorageDevice();
+ } else {
+ //
+ // If it is Fast Boot, we only connect SATA Devices or SD Card Devices. Otherwise, we do nothing.
+ //
+ PlatformBdsConnectStorageDeviceFromDevicePath (DevicePath);
+ }
+
+ //
+ // Report Status Code to indicate ReadyToBoot event was signalled
+ //
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT));
+
+ //
+ // Expand USB Class or USB WWID device path node to be full device path of a USB
+ // device in platform then load the boot file on this full device path and get the
+ // image handle.
+ //
+ ImageHandle = BdsExpandUsbShortFormDevicePath (DevicePath);
+
+ //
+ // Adjust the different type memory page number just before booting
+ // and save the updated info into the variable for next boot to use
+ //
+ BdsSetMemoryTypeInformationVariable ();
+
+ //
+ // By expanding the USB Class or WWID device path, the ImageHandle has returnned.
+ // Here get the ImageHandle for the non USB class or WWID device path.
+ //
+ if (ImageHandle == NULL) {
+ ASSERT (Option->DevicePath != NULL);
+ if ((DevicePathType (Option->DevicePath) == BBS_DEVICE_PATH) &&
+ (DevicePathSubType (Option->DevicePath) == BBS_BBS_DP)
+ ) {
+ //
+ // Check to see if we should legacy BOOT. If yes then do the legacy boot
+ //
+ return BdsLibDoLegacyBoot (Option);
+ }
+
+ //
+ // If the boot option point to Internal FV shell, make sure it is valid
+ //
+ Status = BdsLibUpdateFvFileDevicePath (&DevicePath, PcdGetPtr(PcdShellFile));
+ if (!EFI_ERROR(Status)) {
+ if (Option->DevicePath != NULL) {
+ FreePool(Option->DevicePath);
+ }
+ Option->DevicePath = AllocateZeroPool (GetDevicePathSize (DevicePath));
+ ASSERT(Option->DevicePath != NULL);
+ CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath));
+ //
+ // Update the shell boot option
+ //
+ InitializeListHead (&TempBootLists);
+ BdsLibRegisterNewOption (&TempBootLists, DevicePath, L"EFI Internal Shell", L"BootOrder");
+
+ //
+ // free the temporary device path created by BdsLibUpdateFvFileDevicePath()
+ //
+ FreePool (DevicePath);
+ DevicePath = Option->DevicePath;
+ }
+
+ DEBUG_CODE_BEGIN();
+
+ if (Option->Description == NULL) {
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Booting from unknown device path\n"));
+ } else {
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Booting %S\n", Option->Description));
+ }
+
+ DEBUG_CODE_END();
+
+ //
+ // Report status code for OS Loader LoadImage.
+ //
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));
+ Status = gBS->LoadImage (
+ TRUE,
+ gImageHandle,
+ DevicePath,
+ NULL,
+ 0,
+ &ImageHandle
+ );
+
+ //
+ // If we didn't find an image directly, we need to try as if it is a removable device boot option
+ // and load the image according to the default boot behavior for removable device.
+ //
+ if (EFI_ERROR (Status)) {
+ //
+ // check if there is a bootable removable media could be found in this device path ,
+ // and get the bootable media handle
+ //
+ Handle = BdsLibGetBootableHandle(DevicePath);
+ if (Handle != NULL) {
+ //
+ // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
+ // machinename is ia32, ia64, x64, ...
+ //
+ FilePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
+ if (FilePath != NULL) {
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));
+ Status = gBS->LoadImage (
+ TRUE,
+ gImageHandle,
+ FilePath,
+ NULL,
+ 0,
+ &ImageHandle
+ );
+ }
+ }
+ }
+ }
+ //
+ // Provide the image with it's load options
+ //
+ if ((ImageHandle == NULL) || (EFI_ERROR(Status))) {
+ //
+ // Report Status Code to indicate that the failure to load boot option
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR)
+ );
+ goto Done;
+ }
+
+ Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
+ ASSERT_EFI_ERROR (Status);
+
+ if (Option->LoadOptionsSize != 0) {
+ ImageInfo->LoadOptionsSize = Option->LoadOptionsSize;
+ ImageInfo->LoadOptions = Option->LoadOptions;
+ }
+
+ //
+ // Clean to NULL because the image is loaded directly from the firmwares boot manager.
+ //
+ ImageInfo->ParentHandle = NULL;
+
+ //
+ // Before calling the image, enable the Watchdog Timer for
+ // the 5 Minute period
+ //
+ gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
+
+ //
+ // Write boot to OS performance data for UEFI boot
+ //
+ PERF_CODE (
+ WriteBootToOsPerformanceData (NULL, NULL);
+ );
+
+ //
+ // Report status code for OS Loader StartImage.
+ //
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderStart));
+
+ Status = gBS->StartImage (ImageHandle, ExitDataSize, ExitData);
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status));
+ if (EFI_ERROR (Status)) {
+ //
+ // Report Status Code to indicate that boot failure
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED)
+ );
+ }
+
+ //
+ // Clear the Watchdog Timer after the image returns
+ //
+ gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
+
+Done:
+ //
+ // Set Logo status invalid after trying one boot option
+ //
+ BootLogo = NULL;
+ StatusLogo = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
+ if (!EFI_ERROR (StatusLogo) && (BootLogo != NULL)) {
+ BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);
+ }
+
+ //
+ // Clear Boot Current
+ // Deleting variable with current implementation shouldn't fail.
+ //
+ gRT->SetVariable (
+ L"BootCurrent",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ 0,
+ NULL
+ );
+
+ return Status;
+}
+
+
+/**
+ Expand a device path that starts with a hard drive media device path node to be a
+ full device path that includes the full hardware path to the device. We need
+ to do this so it can be booted. As an optimization the front match (the part point
+ to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
+ so a connect all is not required on every boot. All successful history device path
+ which point to partition node (the front part) will be saved.
+
+ @param HardDriveDevicePath EFI Device Path to boot, if it starts with a hard
+ drive media device path.
+ @return A Pointer to the full device path or NULL if a valid Hard Drive devic path
+ cannot be found.
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+EFIAPI
+BdsExpandPartitionPartialDevicePathToFull (
+ IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
+ )
+{
+ EFI_STATUS Status;
+ UINTN BlockIoHandleCount;
+ EFI_HANDLE *BlockIoBuffer;
+ EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINTN Index;
+ UINTN InstanceNum;
+ EFI_DEVICE_PATH_PROTOCOL *CachedDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;
+ UINTN CachedDevicePathSize;
+ BOOLEAN DeviceExist;
+ BOOLEAN NeedAdjust;
+ EFI_DEVICE_PATH_PROTOCOL *Instance;
+ UINTN Size;
+
+ FullDevicePath = NULL;
+ //
+ // Check if there is prestore HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable.
+ // If exist, search the front path which point to partition node in the variable instants.
+ // If fail to find or HD_BOOT_DEVICE_PATH_VARIABLE_NAME not exist, reconnect all and search in all system
+ //
+ GetVariable2 (
+ HD_BOOT_DEVICE_PATH_VARIABLE_NAME,
+ &gHdBootDevicePathVariablGuid,
+ (VOID **) &CachedDevicePath,
+ &CachedDevicePathSize
+ );
+
+ //
+ // Delete the invalid HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable.
+ //
+ if ((CachedDevicePath != NULL) && !IsDevicePathValid (CachedDevicePath, CachedDevicePathSize)) {
+ FreePool (CachedDevicePath);
+ CachedDevicePath = NULL;
+ Status = gRT->SetVariable (
+ HD_BOOT_DEVICE_PATH_VARIABLE_NAME,
+ &gHdBootDevicePathVariablGuid,
+ 0,
+ 0,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ if (CachedDevicePath != NULL) {
+ TempNewDevicePath = CachedDevicePath;
+ DeviceExist = FALSE;
+ NeedAdjust = FALSE;
+ do {
+ //
+ // Check every instance of the variable
+ // First, check whether the instance contain the partition node, which is needed for distinguishing multi
+ // partial partition boot option. Second, check whether the instance could be connected.
+ //
+ Instance = GetNextDevicePathInstance (&TempNewDevicePath, &Size);
+ if (MatchPartitionDevicePathNode (Instance, HardDriveDevicePath)) {
+ //
+ // Connect the device path instance, the device path point to hard drive media device path node
+ // e.g. ACPI() /PCI()/ATA()/Partition()
+ //
+ Status = BdsLibConnectDevicePath (Instance);
+ if (!EFI_ERROR (Status)) {
+ DeviceExist = TRUE;
+ break;
+ }
+ }
+ //
+ // Come here means the first instance is not matched
+ //
+ NeedAdjust = TRUE;
+ FreePool(Instance);
+ } while (TempNewDevicePath != NULL);
+
+ if (DeviceExist) {
+ //
+ // Find the matched device path.
+ // Append the file path information from the boot option and return the fully expanded device path.
+ //
+ DevicePath = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);
+ FullDevicePath = AppendDevicePath (Instance, DevicePath);
+
+ //
+ // Adjust the HD_BOOT_DEVICE_PATH_VARIABLE_NAME instances sequence if the matched one is not first one.
+ //
+ if (NeedAdjust) {
+ //
+ // First delete the matched instance.
+ //
+ TempNewDevicePath = CachedDevicePath;
+ CachedDevicePath = BdsLibDelPartMatchInstance (CachedDevicePath, Instance );
+ FreePool (TempNewDevicePath);
+
+ //
+ // Second, append the remaining path after the matched instance
+ //
+ TempNewDevicePath = CachedDevicePath;
+ CachedDevicePath = AppendDevicePathInstance (Instance, CachedDevicePath );
+ FreePool (TempNewDevicePath);
+ //
+ // Save the matching Device Path so we don't need to do a connect all next time
+ // Failure to set the variable only impacts the performance when next time expanding the short-form device path.
+ //
+ Status = gRT->SetVariable (
+ HD_BOOT_DEVICE_PATH_VARIABLE_NAME,
+ &gHdBootDevicePathVariablGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ GetDevicePathSize (CachedDevicePath),
+ CachedDevicePath
+ );
+ }
+
+ FreePool (Instance);
+ FreePool (CachedDevicePath);
+ return FullDevicePath;
+ }
+ }
+
+ //
+ // If we get here we fail to find or HD_BOOT_DEVICE_PATH_VARIABLE_NAME not exist, and now we need
+ // to search all devices in the system for a matched partition
+ //
+ BdsLibConnectAllDriversToAllControllers ();
+ Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);
+ if (EFI_ERROR (Status) || BlockIoHandleCount == 0 || BlockIoBuffer == NULL) {
+ //
+ // If there was an error or there are no device handles that support
+ // the BLOCK_IO Protocol, then return.
+ //
+ return NULL;
+ }
+ //
+ // Loop through all the device handles that support the BLOCK_IO Protocol
+ //
+ for (Index = 0; Index < BlockIoHandleCount; Index++) {
+
+ Status = gBS->HandleProtocol (BlockIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &BlockIoDevicePath);
+ if (EFI_ERROR (Status) || BlockIoDevicePath == NULL) {
+ continue;
+ }
+
+ if (MatchPartitionDevicePathNode (BlockIoDevicePath, HardDriveDevicePath)) {
+ //
+ // Find the matched partition device path
+ //
+ DevicePath = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);
+ FullDevicePath = AppendDevicePath (BlockIoDevicePath, DevicePath);
+
+ //
+ // Save the matched partition device path in HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable
+ //
+ if (CachedDevicePath != NULL) {
+ //
+ // Save the matched partition device path as first instance of HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable
+ //
+ if (BdsLibMatchDevicePaths (CachedDevicePath, BlockIoDevicePath)) {
+ TempNewDevicePath = CachedDevicePath;
+ CachedDevicePath = BdsLibDelPartMatchInstance (CachedDevicePath, BlockIoDevicePath);
+ FreePool(TempNewDevicePath);
+ }
+
+ if (CachedDevicePath != NULL) {
+ TempNewDevicePath = CachedDevicePath;
+ CachedDevicePath = AppendDevicePathInstance (BlockIoDevicePath, CachedDevicePath);
+ FreePool(TempNewDevicePath);
+ } else {
+ CachedDevicePath = DuplicateDevicePath (BlockIoDevicePath);
+ }
+
+ //
+ // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
+ // If the user try to boot many OS in different HDs or partitions, in theory,
+ // the HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable maybe become larger and larger.
+ //
+ InstanceNum = 0;
+ ASSERT (CachedDevicePath != NULL);
+ TempNewDevicePath = CachedDevicePath;
+ while (!IsDevicePathEnd (TempNewDevicePath)) {
+ TempNewDevicePath = NextDevicePathNode (TempNewDevicePath);
+ //
+ // Parse one instance
+ //
+ while (!IsDevicePathEndType (TempNewDevicePath)) {
+ TempNewDevicePath = NextDevicePathNode (TempNewDevicePath);
+ }
+ InstanceNum++;
+ //
+ // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
+ //
+ if (InstanceNum >= 12) {
+ SetDevicePathEndNode (TempNewDevicePath);
+ break;
+ }
+ }
+ } else {
+ CachedDevicePath = DuplicateDevicePath (BlockIoDevicePath);
+ }
+
+ //
+ // Save the matching Device Path so we don't need to do a connect all next time
+ // Failure to set the variable only impacts the performance when next time expanding the short-form device path.
+ //
+ Status = gRT->SetVariable (
+ HD_BOOT_DEVICE_PATH_VARIABLE_NAME,
+ &gHdBootDevicePathVariablGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ GetDevicePathSize (CachedDevicePath),
+ CachedDevicePath
+ );
+
+ break;
+ }
+ }
+
+ if (CachedDevicePath != NULL) {
+ FreePool (CachedDevicePath);
+ }
+ if (BlockIoBuffer != NULL) {
+ FreePool (BlockIoBuffer);
+ }
+ return FullDevicePath;
+}
+
+/**
+ Check whether there is a instance in BlockIoDevicePath, which contain multi device path
+ instances, has the same partition node with HardDriveDevicePath device path
+
+ @param BlockIoDevicePath Multi device path instances which need to check
+ @param HardDriveDevicePath A device path which starts with a hard drive media
+ device path.
+
+ @retval TRUE There is a matched device path instance.
+ @retval FALSE There is no matched device path instance.
+
+**/
+BOOLEAN
+EFIAPI
+MatchPartitionDevicePathNode (
+ IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath,
+ IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
+ )
+{
+ HARDDRIVE_DEVICE_PATH *TmpHdPath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ BOOLEAN Match;
+ EFI_DEVICE_PATH_PROTOCOL *BlockIoHdDevicePathNode;
+
+ if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {
+ return FALSE;
+ }
+
+ //
+ // Make PreviousDevicePath == the device path node before the end node
+ //
+ DevicePath = BlockIoDevicePath;
+ BlockIoHdDevicePathNode = NULL;
+
+ //
+ // find the partition device path node
+ //
+ while (!IsDevicePathEnd (DevicePath)) {
+ if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
+ (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)
+ ) {
+ BlockIoHdDevicePathNode = DevicePath;
+ break;
+ }
+
+ DevicePath = NextDevicePathNode (DevicePath);
+ }
+
+ if (BlockIoHdDevicePathNode == NULL) {
+ return FALSE;
+ }
+ //
+ // See if the harddrive device path in blockio matches the orig Hard Drive Node
+ //
+ TmpHdPath = (HARDDRIVE_DEVICE_PATH *) BlockIoHdDevicePathNode;
+ Match = FALSE;
+
+ //
+ // Check for the match
+ //
+ if ((TmpHdPath->MBRType == HardDriveDevicePath->MBRType) &&
+ (TmpHdPath->SignatureType == HardDriveDevicePath->SignatureType)) {
+ switch (TmpHdPath->SignatureType) {
+ case SIGNATURE_TYPE_GUID:
+ Match = CompareGuid ((EFI_GUID *)TmpHdPath->Signature, (EFI_GUID *)HardDriveDevicePath->Signature);
+ break;
+ case SIGNATURE_TYPE_MBR:
+ Match = (BOOLEAN)(*((UINT32 *)(&(TmpHdPath->Signature[0]))) == ReadUnaligned32((UINT32 *)(&(HardDriveDevicePath->Signature[0]))));
+ break;
+ default:
+ Match = FALSE;
+ break;
+ }
+ }
+
+ return Match;
+}
+
+/**
+ Delete the boot option associated with the handle passed in.
+
+ @param Handle The handle which present the device path to create
+ boot option
+
+ @retval EFI_SUCCESS Delete the boot option success
+ @retval EFI_NOT_FOUND If the Device Path is not found in the system
+ @retval EFI_OUT_OF_RESOURCES Lack of memory resource
+ @retval Other Error return value from SetVariable()
+
+**/
+EFI_STATUS
+BdsLibDeleteOptionFromHandle (
+ IN EFI_HANDLE Handle
+ )
+{
+ UINT16 *BootOrder;
+ UINT8 *BootOptionVar;
+ UINTN BootOrderSize;
+ UINTN BootOptionSize;
+ EFI_STATUS Status;
+ UINTN Index;
+ UINT16 BootOption[BOOT_OPTION_MAX_CHAR];
+ UINTN DevicePathSize;
+ UINTN OptionDevicePathSize;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
+ UINT8 *TempPtr;
+
+ Status = EFI_SUCCESS;
+ BootOrder = NULL;
+ BootOrderSize = 0;
+
+ //
+ // Check "BootOrder" variable, if no, means there is no any boot order.
+ //
+ BootOrder = BdsLibGetVariableAndSize (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ &BootOrderSize
+ );
+ if (BootOrder == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Convert device handle to device path protocol instance
+ //
+ DevicePath = DevicePathFromHandle (Handle);
+ if (DevicePath == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ DevicePathSize = GetDevicePathSize (DevicePath);
+
+ //
+ // Loop all boot order variable and find the matching device path
+ //
+ Index = 0;
+ while (Index < BootOrderSize / sizeof (UINT16)) {
+ UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
+ BootOptionVar = BdsLibGetVariableAndSize (
+ BootOption,
+ &gEfiGlobalVariableGuid,
+ &BootOptionSize
+ );
+
+ if (BootOptionVar == NULL) {
+ FreePool (BootOrder);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (!ValidateOption(BootOptionVar, BootOptionSize)) {
+ BdsDeleteBootOption (BootOrder[Index], BootOrder, &BootOrderSize);
+ FreePool (BootOptionVar);
+ Index++;
+ continue;
+ }
+
+ TempPtr = BootOptionVar;
+ TempPtr += sizeof (UINT32) + sizeof (UINT16);
+ TempPtr += StrSize ((CHAR16 *) TempPtr);
+ OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
+ OptionDevicePathSize = GetDevicePathSize (OptionDevicePath);
+
+ //
+ // Check whether the device path match
+ //
+ if ((OptionDevicePathSize == DevicePathSize) &&
+ (CompareMem (DevicePath, OptionDevicePath, DevicePathSize) == 0)) {
+ BdsDeleteBootOption (BootOrder[Index], BootOrder, &BootOrderSize);
+ FreePool (BootOptionVar);
+ break;
+ }
+
+ FreePool (BootOptionVar);
+ Index++;
+ }
+
+ //
+ // Adjust number of boot option for "BootOrder" variable.
+ //
+ Status = gRT->SetVariable (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ BootOrderSize,
+ BootOrder
+ );
+ //
+ // Shrinking variable with existing variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ FreePool (BootOrder);
+
+ return Status;
+}
+
+
+/**
+ Delete all invalid EFI boot options.
+
+ @retval EFI_SUCCESS Delete all invalid boot option success
+ @retval EFI_NOT_FOUND Variable "BootOrder" is not found
+ @retval EFI_OUT_OF_RESOURCES Lack of memory resource
+ @retval Other Error return value from SetVariable()
+
+**/
+EFI_STATUS
+BdsDeleteAllInvalidEfiBootOption (
+ VOID
+ )
+{
+ UINT16 *BootOrder;
+ UINT8 *BootOptionVar;
+ UINTN BootOrderSize;
+ UINTN BootOptionSize;
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN Index2;
+ UINT16 BootOption[BOOT_OPTION_MAX_CHAR];
+ EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
+ UINT8 *TempPtr;
+ CHAR16 *Description;
+ BOOLEAN Corrupted;
+
+ Status = EFI_SUCCESS;
+ BootOrder = NULL;
+ Description = NULL;
+ OptionDevicePath = NULL;
+ BootOrderSize = 0;
+ Corrupted = FALSE;
+
+ //
+ // Check "BootOrder" variable firstly, this variable hold the number of boot options
+ //
+ BootOrder = BdsLibGetVariableAndSize (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ &BootOrderSize
+ );
+ if (NULL == BootOrder) {
+ return EFI_NOT_FOUND;
+ }
+
+ Index = 0;
+ while (Index < BootOrderSize / sizeof (UINT16)) {
+ UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
+ BootOptionVar = BdsLibGetVariableAndSize (
+ BootOption,
+ &gEfiGlobalVariableGuid,
+ &BootOptionSize
+ );
+ if (NULL == BootOptionVar) {
+ FreePool (BootOrder);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (!ValidateOption(BootOptionVar, BootOptionSize)) {
+ Corrupted = TRUE;
+ } else {
+ TempPtr = BootOptionVar;
+ TempPtr += sizeof (UINT32) + sizeof (UINT16);
+ Description = (CHAR16 *) TempPtr;
+ TempPtr += StrSize ((CHAR16 *) TempPtr);
+ OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
+
+ //
+ // Skip legacy boot option (BBS boot device)
+ //
+ if ((DevicePathType (OptionDevicePath) == BBS_DEVICE_PATH) &&
+ (DevicePathSubType (OptionDevicePath) == BBS_BBS_DP)) {
+ FreePool (BootOptionVar);
+ Index++;
+ continue;
+ }
+ }
+
+ if (Corrupted || !BdsLibIsValidEFIBootOptDevicePathExt (OptionDevicePath, FALSE, Description)) {
+ //
+ // Delete this invalid boot option "Boot####"
+ //
+ Status = gRT->SetVariable (
+ BootOption,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ 0,
+ NULL
+ );
+ //
+ // Deleting variable with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Mark this boot option in boot order as deleted
+ //
+ BootOrder[Index] = 0xffff;
+ Corrupted = FALSE;
+ }
+
+ FreePool (BootOptionVar);
+ Index++;
+ }
+
+ //
+ // Adjust boot order array
+ //
+ Index2 = 0;
+ for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
+ if (BootOrder[Index] != 0xffff) {
+ BootOrder[Index2] = BootOrder[Index];
+ Index2 ++;
+ }
+ }
+ Status = gRT->SetVariable (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ Index2 * sizeof (UINT16),
+ BootOrder
+ );
+ //
+ // Shrinking variable with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ FreePool (BootOrder);
+
+ return Status;
+}
+
+
+/**
+ For EFI boot option, BDS separate them as six types:
+ 1. Network - The boot option points to the SimpleNetworkProtocol device.
+ Bds will try to automatically create this type boot option when enumerate.
+ 2. Shell - The boot option points to internal flash shell.
+ Bds will try to automatically create this type boot option when enumerate.
+ 3. Removable BlockIo - The boot option only points to the removable media
+ device, like USB flash disk, DVD, Floppy etc.
+ These device should contain a *removable* blockIo
+ protocol in their device handle.
+ Bds will try to automatically create this type boot option
+ when enumerate.
+ 4. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
+ like HardDisk.
+ These device should contain a *fixed* blockIo
+ protocol in their device handle.
+ BDS will skip fixed blockIo devices, and NOT
+ automatically create boot option for them. But BDS
+ will help to delete those fixed blockIo boot option,
+ whose description rule conflict with other auto-created
+ boot options.
+ 5. Non-BlockIo Simplefile - The boot option points to a device whose handle
+ has SimpleFileSystem Protocol, but has no blockio
+ protocol. These devices do not offer blockIo
+ protocol, but BDS still can get the
+ \EFI\BOOT\boot{machinename}.EFI by SimpleFileSystem
+ Protocol.
+ 6. File - The boot option points to a file. These boot options are usually
+ created by user manually or OS loader. BDS will not delete or modify
+ these boot options.
+
+ This function will enumerate all possible boot device in the system, and
+ automatically create boot options for Network, Shell, Removable BlockIo,
+ and Non-BlockIo Simplefile devices.
+ It will only execute once of every boot.
+
+ @param BdsBootOptionList The header of the link list which indexed all
+ current boot options
+
+ @retval EFI_SUCCESS Finished all the boot device enumerate and create
+ the boot option base on that boot device
+
+ @retval EFI_OUT_OF_RESOURCES Failed to enumerate the boot device and create the boot option list
+**/
+EFI_STATUS
+EFIAPI
+BdsLibEnumerateAllBootOption (
+ IN OUT LIST_ENTRY *BdsBootOptionList
+ )
+{
+ EFI_STATUS Status;
+ UINT16 FloppyNumber;
+ UINT16 HarddriveNumber;
+ UINT16 CdromNumber;
+ UINT16 UsbNumber;
+ UINT16 MiscNumber;
+ UINT16 ScsiNumber;
+ UINT16 NonBlockNumber;
+ UINTN NumberBlockIoHandles;
+ EFI_HANDLE *BlockIoHandles;
+ EFI_BLOCK_IO_PROTOCOL *BlkIo;
+ BOOLEAN Removable[2];
+ UINTN RemovableIndex;
+ UINTN Index;
+ UINTN NumOfLoadFileHandles;
+ EFI_HANDLE *LoadFileHandles;
+ UINTN FvHandleCount;
+ EFI_HANDLE *FvHandleBuffer;
+ EFI_FV_FILETYPE Type;
+ UINTN Size;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ UINT32 AuthenticationStatus;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINTN DevicePathType;
+ CHAR16 Buffer[40];
+ EFI_HANDLE *FileSystemHandles;
+ UINTN NumberFileSystemHandles;
+ BOOLEAN NeedDelete;
+ EFI_IMAGE_DOS_HEADER DosHeader;
+ CHAR8 *PlatLang;
+ CHAR8 *LastLang;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+
+ FloppyNumber = 0;
+ HarddriveNumber = 0;
+ CdromNumber = 0;
+ UsbNumber = 0;
+ MiscNumber = 0;
+ ScsiNumber = 0;
+ PlatLang = NULL;
+ LastLang = NULL;
+ ZeroMem (Buffer, sizeof (Buffer));
+
+ //
+ // If the boot device enumerate happened, just get the boot
+ // device from the boot order variable
+ //
+ if (mEnumBootDevice) {
+ GetVariable2 (LAST_ENUM_LANGUAGE_VARIABLE_NAME, &gLastEnumLangGuid, (VOID**)&LastLang, NULL);
+ GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&PlatLang, NULL);
+ ASSERT (PlatLang != NULL);
+ if ((LastLang != NULL) && (AsciiStrCmp (LastLang, PlatLang) == 0)) {
+ Status = BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");
+ FreePool (LastLang);
+ FreePool (PlatLang);
+ return Status;
+ } else {
+ Status = gRT->SetVariable (
+ LAST_ENUM_LANGUAGE_VARIABLE_NAME,
+ &gLastEnumLangGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ AsciiStrSize (PlatLang),
+ PlatLang
+ );
+ //
+ // Failure to set the variable only impacts the performance next time enumerating the boot options.
+ //
+
+ if (LastLang != NULL) {
+ FreePool (LastLang);
+ }
+ FreePool (PlatLang);
+ }
+ }
+
+ //
+ // Notes: this dirty code is to get the legacy boot option from the
+ // BBS table and create to variable as the EFI boot option, it should
+ // be removed after the CSM can provide legacy boot option directly
+ //
+ REFRESH_LEGACY_BOOT_OPTIONS;
+
+ //
+ // Delete invalid boot option
+ //
+ BdsDeleteAllInvalidEfiBootOption ();
+
+ //
+ // Parse removable media followed by fixed media.
+ // The Removable[] array is used by the for-loop below to create removable media boot options
+ // at first, and then to create fixed media boot options.
+ //
+ Removable[0] = FALSE;
+ Removable[1] = TRUE;
+
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiBlockIoProtocolGuid,
+ NULL,
+ &NumberBlockIoHandles,
+ &BlockIoHandles
+ );
+
+ for (RemovableIndex = 0; RemovableIndex < 2; RemovableIndex++) {
+ for (Index = 0; Index < NumberBlockIoHandles; Index++) {
+ Status = gBS->HandleProtocol (
+ BlockIoHandles[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlkIo
+ );
+ //
+ // skip the logical partition
+ //
+ if (EFI_ERROR (Status) || BlkIo->Media->LogicalPartition) {
+ continue;
+ }
+
+ //
+ // firstly fixed block io then the removable block io
+ //
+ if (BlkIo->Media->RemovableMedia == Removable[RemovableIndex]) {
+ continue;
+ }
+ DevicePath = DevicePathFromHandle (BlockIoHandles[Index]);
+ DevicePathType = BdsGetBootTypeFromDevicePath (DevicePath);
+
+ switch (DevicePathType) {
+ case BDS_EFI_ACPI_FLOPPY_BOOT:
+ if (FloppyNumber != 0) {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_FLOPPY)), FloppyNumber);
+ } else {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_FLOPPY)));
+ }
+ BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
+ FloppyNumber++;
+ break;
+
+ //
+ // Assume a removable SATA device should be the DVD/CD device, a fixed SATA device should be the Hard Drive device.
+ //
+ case BDS_EFI_MESSAGE_ATAPI_BOOT:
+ case BDS_EFI_MESSAGE_SATA_BOOT:
+ if (BlkIo->Media->RemovableMedia) {
+ if (CdromNumber != 0) {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_CD_DVD)), CdromNumber);
+ } else {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_CD_DVD)));
+ }
+ CdromNumber++;
+ } else {
+ if (HarddriveNumber != 0) {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_HARDDRIVE)), HarddriveNumber);
+ } else {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_HARDDRIVE)));
+ }
+ HarddriveNumber++;
+ }
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Buffer: %S\n", Buffer));
+ BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
+ break;
+
+ case BDS_EFI_MESSAGE_USB_DEVICE_BOOT:
+ if (UsbNumber != 0) {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_USB)), UsbNumber);
+ } else {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_USB)));
+ }
+ BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
+ UsbNumber++;
+ break;
+
+ case BDS_EFI_MESSAGE_SCSI_BOOT:
+ if (ScsiNumber != 0) {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_SCSI)), ScsiNumber);
+ } else {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_SCSI)));
+ }
+ BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
+ ScsiNumber++;
+ break;
+
+ case BDS_EFI_MESSAGE_MISC_BOOT:
+ default:
+ if (MiscNumber != 0) {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_MISC)), MiscNumber);
+ } else {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_MISC)));
+ }
+ BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
+ MiscNumber++;
+ break;
+ }
+ }
+ }
+
+ if (NumberBlockIoHandles != 0) {
+ FreePool (BlockIoHandles);
+ }
+
+ //
+ // If there is simple file protocol which does not consume block Io protocol, create a boot option for it here.
+ //
+ NonBlockNumber = 0;
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleFileSystemProtocolGuid,
+ NULL,
+ &NumberFileSystemHandles,
+ &FileSystemHandles
+ );
+ for (Index = 0; Index < NumberFileSystemHandles; Index++) {
+ Status = gBS->HandleProtocol (
+ FileSystemHandles[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlkIo
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Skip if the file system handle supports a BlkIo protocol,
+ //
+ continue;
+ }
+
+ //
+ // Do the removable Media thing. \EFI\BOOT\boot{machinename}.EFI
+ // machinename is ia32, ia64, x64, ...
+ //
+ Hdr.Union = &HdrData;
+ NeedDelete = TRUE;
+ Status = BdsLibGetImageHeader (
+ FileSystemHandles[Index],
+ EFI_REMOVABLE_MEDIA_FILE_NAME,
+ &DosHeader,
+ Hdr
+ );
+ if (!EFI_ERROR (Status) &&
+ EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine) &&
+ Hdr.Pe32->OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
+ NeedDelete = FALSE;
+ }
+
+ if (NeedDelete) {
+ //
+ // No such file or the file is not a EFI application, delete this boot option
+ //
+ BdsLibDeleteOptionFromHandle (FileSystemHandles[Index]);
+ } else {
+ if (NonBlockNumber != 0) {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NON_BLOCK)), NonBlockNumber);
+ } else {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NON_BLOCK)));
+ }
+ BdsLibBuildOptionFromHandle (FileSystemHandles[Index], BdsBootOptionList, Buffer);
+ NonBlockNumber++;
+ }
+ }
+
+ if (NumberFileSystemHandles != 0) {
+ FreePool (FileSystemHandles);
+ }
+
+ //
+ // Parse Network Boot Device
+ //
+ NumOfLoadFileHandles = 0;
+ //
+ // Search Load File protocol for PXE boot option.
+ //
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiLoadFileProtocolGuid,
+ NULL,
+ &NumOfLoadFileHandles,
+ &LoadFileHandles
+ );
+
+ for (Index = 0; Index < NumOfLoadFileHandles; Index++) {
+ if (Index != 0) {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NETWORK)), Index);
+ } else {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NETWORK)));
+ }
+ BdsLibBuildOptionFromHandle (LoadFileHandles[Index], BdsBootOptionList, Buffer);
+ }
+
+ if (NumOfLoadFileHandles != 0) {
+ FreePool (LoadFileHandles);
+ }
+
+ //
+ // Check if we have on flash shell
+ //
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ &FvHandleCount,
+ &FvHandleBuffer
+ );
+ for (Index = 0; Index < FvHandleCount; Index++) {
+ gBS->HandleProtocol (
+ FvHandleBuffer[Index],
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **) &Fv
+ );
+
+ Status = Fv->ReadFile (
+ Fv,
+ PcdGetPtr(PcdShellFile),
+ NULL,
+ &Size,
+ &Type,
+ &Attributes,
+ &AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Skip if no shell file in the FV
+ //
+ continue;
+ }
+ //
+ // Build the shell boot option
+ //
+ BdsLibBuildOptionFromShell (FvHandleBuffer[Index], BdsBootOptionList);
+ }
+
+ if (FvHandleCount != 0) {
+ FreePool (FvHandleBuffer);
+ }
+ //
+ // Make sure every boot only have one time
+ // boot device enumerate
+ //
+ Status = BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");
+ mEnumBootDevice = TRUE;
+
+ return Status;
+}
+
+/**
+ Build the boot option with the handle parsed in
+
+ @param Handle The handle which present the device path to create
+ boot option
+ @param BdsBootOptionList The header of the link list which indexed all
+ current boot options
+ @param String The description of the boot option.
+
+**/
+VOID
+EFIAPI
+BdsLibBuildOptionFromHandle (
+ IN EFI_HANDLE Handle,
+ IN LIST_ENTRY *BdsBootOptionList,
+ IN CHAR16 *String
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ DevicePath = DevicePathFromHandle (Handle);
+
+ //
+ // Create and register new boot option
+ //
+ BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, String, L"BootOrder");
+}
+
+
+/**
+ Build the on flash shell boot option with the handle parsed in.
+
+ @param Handle The handle which present the device path to create
+ on flash shell boot option
+ @param BdsBootOptionList The header of the link list which indexed all
+ current boot options
+
+**/
+VOID
+EFIAPI
+BdsLibBuildOptionFromShell (
+ IN EFI_HANDLE Handle,
+ IN OUT LIST_ENTRY *BdsBootOptionList
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH ShellNode;
+
+ DevicePath = DevicePathFromHandle (Handle);
+
+ //
+ // Build the shell device path
+ //
+ EfiInitializeFwVolDevicepathNode (&ShellNode, PcdGetPtr(PcdShellFile));
+
+ DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &ShellNode);
+
+ //
+ // Create and register the shell boot option
+ //
+ BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, L"EFI Internal Shell", L"BootOrder");
+
+}
+
+/**
+ Boot from the UEFI spec defined "BootNext" variable.
+
+**/
+VOID
+EFIAPI
+BdsLibBootNext (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT16 *BootNext;
+ UINTN BootNextSize;
+ CHAR16 Buffer[20];
+ BDS_COMMON_OPTION *BootOption;
+ LIST_ENTRY TempList;
+ UINTN ExitDataSize;
+ CHAR16 *ExitData;
+
+ //
+ // Init the boot option name buffer and temp link list
+ //
+ InitializeListHead (&TempList);
+ ZeroMem (Buffer, sizeof (Buffer));
+
+ BootNext = BdsLibGetVariableAndSize (
+ L"BootNext",
+ &gEfiGlobalVariableGuid,
+ &BootNextSize
+ );
+
+ //
+ // Clear the boot next variable first
+ //
+ if (BootNext != NULL) {
+ Status = gRT->SetVariable (
+ L"BootNext",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ 0,
+ NULL
+ );
+ //
+ // Deleting variable with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Start to build the boot option and try to boot
+ //
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *BootNext);
+ BootOption = BdsLibVariableToOption (&TempList, Buffer);
+ ASSERT (BootOption != NULL);
+ BdsLibConnectDevicePath (BootOption->DevicePath);
+ BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);
+ FreePool(BootOption);
+ FreePool(BootNext);
+ }
+
+}
+
+/**
+ Return the bootable media handle.
+ First, check the device is connected
+ Second, check whether the device path point to a device which support SimpleFileSystemProtocol,
+ Third, detect the the default boot file in the Media, and return the removable Media handle.
+
+ @param DevicePath Device Path to a bootable device
+
+ @return The bootable media handle. If the media on the DevicePath is not bootable, NULL will return.
+
+**/
+EFI_HANDLE
+EFIAPI
+BdsLibGetBootableHandle (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+ EFI_DEVICE_PATH_PROTOCOL *UpdatedDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DupDevicePath;
+ EFI_HANDLE Handle;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ VOID *Buffer;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ UINTN Size;
+ UINTN TempSize;
+ EFI_HANDLE ReturnHandle;
+ EFI_HANDLE *SimpleFileSystemHandles;
+
+ UINTN NumberSimpleFileSystemHandles;
+ UINTN Index;
+ EFI_IMAGE_DOS_HEADER DosHeader;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+
+ UpdatedDevicePath = DevicePath;
+
+ //
+ // Enter to critical section to protect the acquired BlockIo instance
+ // from getting released due to the USB mass storage hotplug event
+ //
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // Check whether the device is connected
+ //
+ Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &UpdatedDevicePath, &Handle);
+ if (EFI_ERROR (Status)) {
+ //
+ // Skip the case that the boot option point to a simple file protocol which does not consume block Io protocol,
+ //
+ Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &UpdatedDevicePath, &Handle);
+ if (EFI_ERROR (Status)) {
+ //
+ // Fail to find the proper BlockIo and simple file protocol, maybe because device not present, we need to connect it firstly
+ //
+ UpdatedDevicePath = DevicePath;
+ Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &UpdatedDevicePath, &Handle);
+ gBS->ConnectController (Handle, NULL, NULL, TRUE);
+ }
+ } else {
+ //
+ // For removable device boot option, its contained device path only point to the removable device handle,
+ // should make sure all its children handles (its child partion or media handles) are created and connected.
+ //
+ gBS->ConnectController (Handle, NULL, NULL, TRUE);
+ //
+ // Get BlockIo protocol and check removable attribute
+ //
+ Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Issue a dummy read to the device to check for media change.
+ // When the removable media is changed, any Block IO read/write will
+ // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
+ // returned. After the Block IO protocol is reinstalled, subsequent
+ // Block IO read/write will success.
+ //
+ Buffer = AllocatePool (BlockIo->Media->BlockSize);
+ if (Buffer != NULL) {
+ BlockIo->ReadBlocks (
+ BlockIo,
+ BlockIo->Media->MediaId,
+ 0,
+ BlockIo->Media->BlockSize,
+ Buffer
+ );
+ FreePool(Buffer);
+ }
+ }
+
+ //
+ // Detect the the default boot file from removable Media
+ //
+
+ //
+ // If fail to get bootable handle specified by a USB boot option, the BDS should try to find other bootable device in the same USB bus
+ // Try to locate the USB node device path first, if fail then use its previous PCI node to search
+ //
+ DupDevicePath = DuplicateDevicePath (DevicePath);
+ ASSERT (DupDevicePath != NULL);
+
+ UpdatedDevicePath = DupDevicePath;
+ Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &UpdatedDevicePath, &Handle);
+ //
+ // if the resulting device path point to a usb node, and the usb node is a dummy node, should only let device path only point to the previous Pci node
+ // Acpi()/Pci()/Usb() --> Acpi()/Pci()
+ //
+ if ((DevicePathType (UpdatedDevicePath) == MESSAGING_DEVICE_PATH) &&
+ (DevicePathSubType (UpdatedDevicePath) == MSG_USB_DP)) {
+ //
+ // Remove the usb node, let the device path only point to PCI node
+ //
+ SetDevicePathEndNode (UpdatedDevicePath);
+ UpdatedDevicePath = DupDevicePath;
+ } else {
+ UpdatedDevicePath = DevicePath;
+ }
+
+ //
+ // Get the device path size of boot option
+ //
+ Size = GetDevicePathSize(UpdatedDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL); // minus the end node
+ ReturnHandle = NULL;
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleFileSystemProtocolGuid,
+ NULL,
+ &NumberSimpleFileSystemHandles,
+ &SimpleFileSystemHandles
+ );
+ for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
+ //
+ // Get the device path size of SimpleFileSystem handle
+ //
+ TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
+ TempSize = GetDevicePathSize (TempDevicePath)- sizeof (EFI_DEVICE_PATH_PROTOCOL); // minus the end node
+ //
+ // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
+ //
+ if (Size <= TempSize && CompareMem (TempDevicePath, UpdatedDevicePath, Size)==0) {
+ //
+ // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
+ // machinename is ia32, ia64, x64, ...
+ //
+ Hdr.Union = &HdrData;
+ Status = BdsLibGetImageHeader (
+ SimpleFileSystemHandles[Index],
+ EFI_REMOVABLE_MEDIA_FILE_NAME,
+ &DosHeader,
+ Hdr
+ );
+ if (!EFI_ERROR (Status) &&
+ EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine) &&
+ Hdr.Pe32->OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
+ ReturnHandle = SimpleFileSystemHandles[Index];
+ break;
+ }
+ }
+ }
+
+ FreePool(DupDevicePath);
+
+ if (SimpleFileSystemHandles != NULL) {
+ FreePool(SimpleFileSystemHandles);
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ return ReturnHandle;
+}
+
+/**
+ Check to see if the network cable is plugged in. If the DevicePath is not
+ connected it will be connected.
+
+ @param DevicePath Device Path to check
+
+ @retval TRUE DevicePath points to an Network that is connected
+ @retval FALSE DevicePath does not point to a bootable network
+
+**/
+BOOLEAN
+BdsLibNetworkBootWithMediaPresent (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *UpdatedDevicePath;
+ EFI_HANDLE Handle;
+ EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
+ BOOLEAN MediaPresent;
+ UINT32 InterruptStatus;
+
+ MediaPresent = FALSE;
+
+ UpdatedDevicePath = DevicePath;
+ //
+ // Locate Load File Protocol for PXE boot option first
+ //
+ Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &UpdatedDevicePath, &Handle);
+ if (EFI_ERROR (Status)) {
+ //
+ // Device not present so see if we need to connect it
+ //
+ Status = BdsLibConnectDevicePath (DevicePath);
+ if (!EFI_ERROR (Status)) {
+ //
+ // This one should work after we did the connect
+ //
+ Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &UpdatedDevicePath, &Handle);
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->HandleProtocol (Handle, &gEfiSimpleNetworkProtocolGuid, (VOID **)&Snp);
+ if (EFI_ERROR (Status)) {
+ //
+ // Failed to open SNP from this handle, try to get SNP from parent handle
+ //
+ UpdatedDevicePath = DevicePathFromHandle (Handle);
+ if (UpdatedDevicePath != NULL) {
+ Status = gBS->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid, &UpdatedDevicePath, &Handle);
+ if (!EFI_ERROR (Status)) {
+ //
+ // SNP handle found, get SNP from it
+ //
+ Status = gBS->HandleProtocol (Handle, &gEfiSimpleNetworkProtocolGuid, (VOID **) &Snp);
+ }
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ if (Snp->Mode->MediaPresentSupported) {
+ if (Snp->Mode->State == EfiSimpleNetworkInitialized) {
+ //
+ // Invoke Snp->GetStatus() to refresh the media status
+ //
+ Snp->GetStatus (Snp, &InterruptStatus, NULL);
+
+ //
+ // In case some one else is using the SNP check to see if it's connected
+ //
+ MediaPresent = Snp->Mode->MediaPresent;
+ } else {
+ //
+ // No one is using SNP so we need to Start and Initialize so
+ // MediaPresent will be valid.
+ //
+ Status = Snp->Start (Snp);
+ if (!EFI_ERROR (Status)) {
+ Status = Snp->Initialize (Snp, 0, 0);
+ if (!EFI_ERROR (Status)) {
+ MediaPresent = Snp->Mode->MediaPresent;
+ Snp->Shutdown (Snp);
+ }
+ Snp->Stop (Snp);
+ }
+ }
+ } else {
+ MediaPresent = TRUE;
+ }
+ }
+ }
+
+ return MediaPresent;
+}
+
+/**
+ For a bootable Device path, return its boot type.
+
+ @param DevicePath The bootable device Path to check
+
+ @retval BDS_EFI_MEDIA_HD_BOOT If given device path contains MEDIA_DEVICE_PATH type device path node
+ which subtype is MEDIA_HARDDRIVE_DP
+ @retval BDS_EFI_MEDIA_CDROM_BOOT If given device path contains MEDIA_DEVICE_PATH type device path node
+ which subtype is MEDIA_CDROM_DP
+ @retval BDS_EFI_ACPI_FLOPPY_BOOT If given device path contains ACPI_DEVICE_PATH type device path node
+ which HID is floppy device.
+ @retval BDS_EFI_MESSAGE_ATAPI_BOOT If given device path contains MESSAGING_DEVICE_PATH type device path node
+ and its last device path node's subtype is MSG_ATAPI_DP.
+ @retval BDS_EFI_MESSAGE_SCSI_BOOT If given device path contains MESSAGING_DEVICE_PATH type device path node
+ and its last device path node's subtype is MSG_SCSI_DP.
+ @retval BDS_EFI_MESSAGE_USB_DEVICE_BOOT If given device path contains MESSAGING_DEVICE_PATH type device path node
+ and its last device path node's subtype is MSG_USB_DP.
+ @retval BDS_EFI_MESSAGE_MISC_BOOT If the device path not contains any media device path node, and
+ its last device path node point to a message device path node.
+ @retval BDS_LEGACY_BBS_BOOT If given device path contains BBS_DEVICE_PATH type device path node.
+ @retval BDS_EFI_UNSUPPORT An EFI Removable BlockIO device path not point to a media and message device,
+
+**/
+UINT32
+EFIAPI
+BdsGetBootTypeFromDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ ACPI_HID_DEVICE_PATH *Acpi;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;
+ UINT32 BootType;
+
+ if (NULL == DevicePath) {
+ return BDS_EFI_UNSUPPORT;
+ }
+
+ TempDevicePath = DevicePath;
+
+ while (!IsDevicePathEndType (TempDevicePath)) {
+ switch (DevicePathType (TempDevicePath)) {
+ case BBS_DEVICE_PATH:
+ return BDS_LEGACY_BBS_BOOT;
+ case MEDIA_DEVICE_PATH:
+ if (DevicePathSubType (TempDevicePath) == MEDIA_HARDDRIVE_DP) {
+ return BDS_EFI_MEDIA_HD_BOOT;
+ } else if (DevicePathSubType (TempDevicePath) == MEDIA_CDROM_DP) {
+ return BDS_EFI_MEDIA_CDROM_BOOT;
+ }
+ break;
+ case ACPI_DEVICE_PATH:
+ Acpi = (ACPI_HID_DEVICE_PATH *) TempDevicePath;
+ if (EISA_ID_TO_NUM (Acpi->HID) == 0x0604) {
+ return BDS_EFI_ACPI_FLOPPY_BOOT;
+ }
+ break;
+ case MESSAGING_DEVICE_PATH:
+ //
+ // Get the last device path node
+ //
+ LastDeviceNode = NextDevicePathNode (TempDevicePath);
+ if (DevicePathSubType(LastDeviceNode) == MSG_DEVICE_LOGICAL_UNIT_DP) {
+ //
+ // if the next node type is Device Logical Unit, which specify the Logical Unit Number (LUN),
+ // skip it
+ //
+ LastDeviceNode = NextDevicePathNode (LastDeviceNode);
+ }
+ //
+ // if the device path not only point to driver device, it is not a messaging device path,
+ //
+ if (!IsDevicePathEndType (LastDeviceNode)) {
+ break;
+ }
+
+ switch (DevicePathSubType (TempDevicePath)) {
+ case MSG_ATAPI_DP:
+ BootType = BDS_EFI_MESSAGE_ATAPI_BOOT;
+ break;
+
+ case MSG_USB_DP:
+ BootType = BDS_EFI_MESSAGE_USB_DEVICE_BOOT;
+ break;
+
+ case MSG_SCSI_DP:
+ BootType = BDS_EFI_MESSAGE_SCSI_BOOT;
+ break;
+
+ case MSG_SATA_DP:
+ BootType = BDS_EFI_MESSAGE_SATA_BOOT;
+ break;
+
+ case MSG_MAC_ADDR_DP:
+ case MSG_VLAN_DP:
+ case MSG_IPv4_DP:
+ case MSG_IPv6_DP:
+ BootType = BDS_EFI_MESSAGE_MAC_BOOT;
+ break;
+
+ default:
+ BootType = BDS_EFI_MESSAGE_MISC_BOOT;
+ break;
+ }
+ return BootType;
+
+ default:
+ break;
+ }
+ TempDevicePath = NextDevicePathNode (TempDevicePath);
+ }
+
+ return BDS_EFI_UNSUPPORT;
+}
+
+/**
+ Check whether the Device path in a boot option point to a valid bootable device,
+ And if CheckMedia is true, check the device is ready to boot now.
+
+ @param DevPath the Device path in a boot option
+ @param CheckMedia if true, check the device is ready to boot now.
+
+ @retval TRUE the Device path is valid
+ @retval FALSE the Device path is invalid .
+
+**/
+BOOLEAN
+EFIAPI
+BdsLibIsValidEFIBootOptDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevPath,
+ IN BOOLEAN CheckMedia
+ )
+{
+ return BdsLibIsValidEFIBootOptDevicePathExt (DevPath, CheckMedia, NULL);
+}
+
+/**
+ Check whether the Device path in a boot option point to a valid bootable device,
+ And if CheckMedia is true, check the device is ready to boot now.
+ If Description is not NULL and the device path point to a fixed BlockIo
+ device, check the description whether conflict with other auto-created
+ boot options.
+
+ @param DevPath the Device path in a boot option
+ @param CheckMedia if true, check the device is ready to boot now.
+ @param Description the description in a boot option
+
+ @retval TRUE the Device path is valid
+ @retval FALSE the Device path is invalid .
+
+**/
+BOOLEAN
+EFIAPI
+BdsLibIsValidEFIBootOptDevicePathExt (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevPath,
+ IN BOOLEAN CheckMedia,
+ IN CHAR16 *Description
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+
+ TempDevicePath = DevPath;
+ LastDeviceNode = DevPath;
+
+ //
+ // Check if it's a valid boot option for network boot device.
+ // Check if there is EfiLoadFileProtocol installed.
+ // If yes, that means there is a boot option for network.
+ //
+ Status = gBS->LocateDevicePath (
+ &gEfiLoadFileProtocolGuid,
+ &TempDevicePath,
+ &Handle
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Device not present so see if we need to connect it
+ //
+ TempDevicePath = DevPath;
+ BdsLibConnectDevicePath (TempDevicePath);
+ Status = gBS->LocateDevicePath (
+ &gEfiLoadFileProtocolGuid,
+ &TempDevicePath,
+ &Handle
+ );
+ }
+
+ if (!EFI_ERROR (Status)) {
+ if (!IsDevicePathEnd (TempDevicePath)) {
+ //
+ // LoadFile protocol is not installed on handle with exactly the same DevPath
+ //
+ return FALSE;
+ }
+
+ if (CheckMedia) {
+ //
+ // Test if it is ready to boot now
+ //
+ if (BdsLibNetworkBootWithMediaPresent(DevPath)) {
+ return TRUE;
+ }
+ } else {
+ return TRUE;
+ }
+ }
+
+ //
+ // If the boot option point to a file, it is a valid EFI boot option,
+ // and assume it is ready to boot now
+ //
+ while (!IsDevicePathEnd (TempDevicePath)) {
+ //
+ // If there is USB Class or USB WWID device path node, treat it as valid EFI
+ // Boot Option. BdsExpandUsbShortFormDevicePath () will be used to expand it
+ // to full device path.
+ //
+ if ((DevicePathType (TempDevicePath) == MESSAGING_DEVICE_PATH) &&
+ ((DevicePathSubType (TempDevicePath) == MSG_USB_CLASS_DP) ||
+ (DevicePathSubType (TempDevicePath) == MSG_USB_WWID_DP))) {
+ return TRUE;
+ }
+
+ LastDeviceNode = TempDevicePath;
+ TempDevicePath = NextDevicePathNode (TempDevicePath);
+ }
+ if ((DevicePathType (LastDeviceNode) == MEDIA_DEVICE_PATH) &&
+ (DevicePathSubType (LastDeviceNode) == MEDIA_FILEPATH_DP)) {
+ return TRUE;
+ }
+
+ //
+ // Check if it's a valid boot option for internal FV application
+ //
+ if (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode) != NULL) {
+ //
+ // If the boot option point to internal FV application, make sure it is valid
+ //
+ TempDevicePath = DevPath;
+ Status = BdsLibUpdateFvFileDevicePath (
+ &TempDevicePath,
+ EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode)
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ return TRUE;
+ } else {
+ if (Status == EFI_SUCCESS) {
+ FreePool (TempDevicePath);
+ }
+ return FALSE;
+ }
+ }
+
+ //
+ // If the boot option point to a blockIO device:
+ // if it is a removable blockIo device, it is valid.
+ // if it is a fixed blockIo device, check its description confliction.
+ //
+ TempDevicePath = DevPath;
+ Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
+ if (EFI_ERROR (Status)) {
+ //
+ // Device not present so see if we need to connect it
+ //
+ Status = BdsLibConnectDevicePath (DevPath);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Try again to get the Block Io protocol after we did the connect
+ //
+ TempDevicePath = DevPath;
+ Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
+ if (!EFI_ERROR (Status)) {
+ if (CheckMedia) {
+ //
+ // Test if it is ready to boot now
+ //
+ if (BdsLibGetBootableHandle (DevPath) != NULL) {
+ return TRUE;
+ }
+ } else {
+ return TRUE;
+ }
+ }
+ } else {
+ //
+ // if the boot option point to a simple file protocol which does not consume block Io protocol, it is also a valid EFI boot option,
+ //
+ Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle);
+ if (!EFI_ERROR (Status)) {
+ if (CheckMedia) {
+ //
+ // Test if it is ready to boot now
+ //
+ if (BdsLibGetBootableHandle (DevPath) != NULL) {
+ return TRUE;
+ }
+ } else {
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+
+/**
+ According to a file guild, check a Fv file device path is valid. If it is invalid,
+ try to return the valid device path.
+ FV address maybe changes for memory layout adjust from time to time, use this function
+ could promise the Fv file device path is right.
+
+ @param DevicePath on input, the Fv file device path need to check on
+ output, the updated valid Fv file device path
+ @param FileGuid the Fv file guild
+
+ @retval EFI_INVALID_PARAMETER the input DevicePath or FileGuid is invalid
+ parameter
+ @retval EFI_UNSUPPORTED the input DevicePath does not contain Fv file
+ guild at all
+ @retval EFI_ALREADY_STARTED the input DevicePath has pointed to Fv file, it is
+ valid
+ @retval EFI_SUCCESS has successfully updated the invalid DevicePath,
+ and return the updated device path in DevicePath
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibUpdateFvFileDevicePath (
+ IN OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath,
+ IN EFI_GUID *FileGuid
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;
+ EFI_STATUS Status;
+ EFI_GUID *GuidPoint;
+ UINTN Index;
+ UINTN FvHandleCount;
+ EFI_HANDLE *FvHandleBuffer;
+ EFI_FV_FILETYPE Type;
+ UINTN Size;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ UINT32 AuthenticationStatus;
+ BOOLEAN FindFvFile;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FvFileNode;
+ EFI_HANDLE FoundFvHandle;
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
+
+ if ((DevicePath == NULL) || (*DevicePath == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (FileGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether the device path point to the default the input Fv file
+ //
+ TempDevicePath = *DevicePath;
+ LastDeviceNode = TempDevicePath;
+ while (!IsDevicePathEnd (TempDevicePath)) {
+ LastDeviceNode = TempDevicePath;
+ TempDevicePath = NextDevicePathNode (TempDevicePath);
+ }
+ GuidPoint = EfiGetNameGuidFromFwVolDevicePathNode (
+ (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode
+ );
+ if (GuidPoint == NULL) {
+ //
+ // if this option does not points to a Fv file, just return EFI_UNSUPPORTED
+ //
+ return EFI_UNSUPPORTED;
+ }
+ if (!CompareGuid (GuidPoint, FileGuid)) {
+ //
+ // If the Fv file is not the input file guid, just return EFI_UNSUPPORTED
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Check whether the input Fv file device path is valid
+ //
+ TempDevicePath = *DevicePath;
+ FoundFvHandle = NULL;
+ Status = gBS->LocateDevicePath (
+ &gEfiFirmwareVolume2ProtocolGuid,
+ &TempDevicePath,
+ &FoundFvHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->HandleProtocol (
+ FoundFvHandle,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **) &Fv
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Set FV ReadFile Buffer as NULL, only need to check whether input Fv file exist there
+ //
+ Status = Fv->ReadFile (
+ Fv,
+ FileGuid,
+ NULL,
+ &Size,
+ &Type,
+ &Attributes,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ return EFI_ALREADY_STARTED;
+ }
+ }
+ }
+
+ //
+ // Look for the input wanted FV file in current FV
+ // First, try to look for in Bds own FV. Bds and input wanted FV file usually are in the same FV
+ //
+ FindFvFile = FALSE;
+ FoundFvHandle = NULL;
+ Status = gBS->HandleProtocol (
+ gImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **) &LoadedImage
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->HandleProtocol (
+ LoadedImage->DeviceHandle,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **) &Fv
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = Fv->ReadFile (
+ Fv,
+ FileGuid,
+ NULL,
+ &Size,
+ &Type,
+ &Attributes,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ FindFvFile = TRUE;
+ FoundFvHandle = LoadedImage->DeviceHandle;
+ }
+ }
+ }
+ //
+ // Second, if fail to find, try to enumerate all FV
+ //
+ if (!FindFvFile) {
+ FvHandleBuffer = NULL;
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ &FvHandleCount,
+ &FvHandleBuffer
+ );
+ for (Index = 0; Index < FvHandleCount; Index++) {
+ gBS->HandleProtocol (
+ FvHandleBuffer[Index],
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **) &Fv
+ );
+
+ Status = Fv->ReadFile (
+ Fv,
+ FileGuid,
+ NULL,
+ &Size,
+ &Type,
+ &Attributes,
+ &AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Skip if input Fv file not in the FV
+ //
+ continue;
+ }
+ FindFvFile = TRUE;
+ FoundFvHandle = FvHandleBuffer[Index];
+ break;
+ }
+
+ if (FvHandleBuffer != NULL) {
+ FreePool (FvHandleBuffer);
+ }
+ }
+
+ if (FindFvFile) {
+ //
+ // Build the shell device path
+ //
+ NewDevicePath = DevicePathFromHandle (FoundFvHandle);
+ EfiInitializeFwVolDevicepathNode (&FvFileNode, FileGuid);
+ NewDevicePath = AppendDevicePathNode (NewDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &FvFileNode);
+ ASSERT (NewDevicePath != NULL);
+ *DevicePath = NewDevicePath;
+ return EFI_SUCCESS;
+ }
+ return EFI_NOT_FOUND;
+}
diff --git a/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsConnect.c b/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsConnect.c
new file mode 100644
index 0000000000..1970c84aee
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsConnect.c
@@ -0,0 +1,435 @@
+/** @file
+ BDS Lib functions which relate with connect the device
+
+Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "InternalBdsLib.h"
+
+
+/**
+ This function will connect all the system driver to controller
+ first, and then special connect the default console, this make
+ sure all the system controller available and the platform default
+ console connected.
+
+**/
+VOID
+EFIAPI
+BdsLibConnectAll (
+ VOID
+ )
+{
+ //
+ // Connect the platform console first
+ //
+ BdsLibConnectAllDefaultConsoles ();
+
+ //
+ // Generic way to connect all the drivers
+ //
+ BdsLibConnectAllDriversToAllControllers ();
+
+ //
+ // Here we have the assumption that we have already had
+ // platform default console
+ //
+ BdsLibConnectAllDefaultConsoles ();
+}
+
+
+/**
+ This function will connect all the system drivers to all controllers
+ first, and then connect all the console devices the system current
+ have. After this we should get all the device work and console available
+ if the system have console device.
+
+**/
+VOID
+BdsLibGenericConnectAll (
+ VOID
+ )
+{
+ //
+ // Most generic way to connect all the drivers
+ //
+ BdsLibConnectAllDriversToAllControllers ();
+ BdsLibConnectAllConsoles ();
+}
+
+/**
+ This function will create all handles associate with every device
+ path node. If the handle associate with one device path node can not
+ be created successfully, then still give chance to do the dispatch,
+ which load the missing drivers if possible.
+
+ @param DevicePathToConnect The device path which will be connected, it can be
+ a multi-instance device path
+
+ @retval EFI_SUCCESS All handles associate with every device path node
+ have been created
+ @retval EFI_OUT_OF_RESOURCES There is no resource to create new handles
+ @retval EFI_NOT_FOUND Create the handle associate with one device path
+ node failed
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibConnectDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePathToConnect
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *CopyOfDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *Instance;
+ EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *Next;
+ EFI_HANDLE Handle;
+ EFI_HANDLE PreviousHandle;
+ UINTN Size;
+ EFI_TPL CurrentTpl;
+
+ if (DevicePathToConnect == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ CurrentTpl = EfiGetCurrentTpl ();
+
+ DevicePath = DuplicateDevicePath (DevicePathToConnect);
+ if (DevicePath == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyOfDevicePath = DevicePath;
+
+ do {
+ //
+ // The outer loop handles multi instance device paths.
+ // Only console variables contain multiple instance device paths.
+ //
+ // After this call DevicePath points to the next Instance
+ //
+ Instance = GetNextDevicePathInstance (&DevicePath, &Size);
+ if (Instance == NULL) {
+ FreePool (CopyOfDevicePath);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Next = Instance;
+ while (!IsDevicePathEndType (Next)) {
+ Next = NextDevicePathNode (Next);
+ }
+
+ SetDevicePathEndNode (Next);
+
+ //
+ // Start the real work of connect with RemainingDevicePath
+ //
+ PreviousHandle = NULL;
+ do {
+ //
+ // Find the handle that best matches the Device Path. If it is only a
+ // partial match the remaining part of the device path is returned in
+ // RemainingDevicePath.
+ //
+ RemainingDevicePath = Instance;
+ Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &Handle);
+
+ if (!EFI_ERROR (Status)) {
+ if (Handle == PreviousHandle) {
+ //
+ // If no forward progress is made try invoking the Dispatcher.
+ // A new FV may have been added to the system an new drivers
+ // may now be found.
+ // Status == EFI_SUCCESS means a driver was dispatched
+ // Status == EFI_NOT_FOUND means no new drivers were dispatched
+ //
+ if (CurrentTpl == TPL_APPLICATION) {
+ //
+ // Dispatch calls LoadImage/StartImage which cannot run at TPL > TPL_APPLICATION
+ //
+ Status = gDS->Dispatch ();
+ } else {
+ //
+ // Always return EFI_NOT_FOUND here
+ // to prevent dead loop when control handle is found but connection failded case
+ //
+ Status = EFI_NOT_FOUND;
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ PreviousHandle = Handle;
+ //
+ // Connect all drivers that apply to Handle and RemainingDevicePath,
+ // the Recursive flag is FALSE so only one level will be expanded.
+ //
+ // Do not check the connect status here, if the connect controller fail,
+ // then still give the chance to do dispatch, because partial
+ // RemainingDevicepath may be in the new FV
+ //
+ // 1. If the connect fail, RemainingDevicepath and handle will not
+ // change, so next time will do the dispatch, then dispatch's status
+ // will take effect
+ // 2. If the connect success, the RemainingDevicepath and handle will
+ // change, then avoid the dispatch, we have chance to continue the
+ // next connection
+ //
+ gBS->ConnectController (Handle, NULL, RemainingDevicePath, FALSE);
+ }
+ }
+ //
+ // Loop until RemainingDevicePath is an empty device path
+ //
+ } while (!EFI_ERROR (Status) && !IsDevicePathEnd (RemainingDevicePath));
+
+ } while (DevicePath != NULL);
+
+ if (CopyOfDevicePath != NULL) {
+ FreePool (CopyOfDevicePath);
+ }
+ //
+ // All handle with DevicePath exists in the handle database
+ //
+ return Status;
+}
+
+/**
+ This function will connect all current system handles recursively.
+
+ gBS->ConnectController() service is invoked for each handle exist in system handler buffer.
+ If the handle is bus type handler, all childrens also will be connected recursively
+ by gBS->ConnectController().
+
+ @retval EFI_SUCCESS All handles and it's child handle have been connected
+ @retval EFI_STATUS Error status returned by of gBS->LocateHandleBuffer().
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibConnectAllEfi (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+
+ Status = gBS->LocateHandleBuffer (
+ AllHandles,
+ NULL,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function will disconnect all current system handles.
+
+ gBS->DisconnectController() is invoked for each handle exists in system handle buffer.
+ If handle is a bus type handle, all childrens also are disconnected recursively by
+ gBS->DisconnectController().
+
+ @retval EFI_SUCCESS All handles have been disconnected
+ @retval EFI_STATUS Error status returned by of gBS->LocateHandleBuffer().
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibDisconnectAllEfi (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+
+ //
+ // Disconnect all
+ //
+ Status = gBS->LocateHandleBuffer (
+ AllHandles,
+ NULL,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Connects all drivers to all controllers.
+ This function make sure all the current system driver will manage
+ the correspoinding controllers if have. And at the same time, make
+ sure all the system controllers have driver to manage it if have.
+
+**/
+VOID
+EFIAPI
+BdsLibConnectAllDriversToAllControllers (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ do {
+ //
+ // Connect All EFI 1.10 drivers following EFI 1.10 algorithm
+ //
+ BdsLibConnectAllEfi ();
+
+ //
+ // Check to see if it's possible to dispatch an more DXE drivers.
+ // The BdsLibConnectAllEfi () may have made new DXE drivers show up.
+ // If anything is Dispatched Status == EFI_SUCCESS and we will try
+ // the connect again.
+ //
+ Status = gDS->Dispatch ();
+
+ } while (!EFI_ERROR (Status));
+
+}
+
+
+/**
+ Connect the specific Usb device which match the short form device path,
+ and whose bus is determined by Host Controller (Uhci or Ehci).
+
+ @param HostControllerPI Uhci (0x00) or Ehci (0x20) or Both uhci and ehci
+ (0xFF)
+ @param RemainingDevicePath a short-form device path that starts with the first
+ element being a USB WWID or a USB Class device
+ path
+
+ @return EFI_INVALID_PARAMETER RemainingDevicePath is NULL pointer.
+ RemainingDevicePath is not a USB device path.
+ Invalid HostControllerPI type.
+ @return EFI_SUCCESS Success to connect USB device
+ @return EFI_NOT_FOUND Fail to find handle for USB controller to connect.
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibConnectUsbDevByShortFormDP(
+ IN UINT8 HostControllerPI,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleArray;
+ UINTN HandleArrayCount;
+ UINTN Index;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 Class[3];
+ BOOLEAN AtLeastOneConnected;
+
+ //
+ // Check the passed in parameters
+ //
+ if (RemainingDevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((DevicePathType (RemainingDevicePath) != MESSAGING_DEVICE_PATH) ||
+ ((DevicePathSubType (RemainingDevicePath) != MSG_USB_CLASS_DP)
+ && (DevicePathSubType (RemainingDevicePath) != MSG_USB_WWID_DP)
+ )) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (HostControllerPI != 0xFF &&
+ HostControllerPI != 0x00 &&
+ HostControllerPI != 0x20) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Find the usb host controller firstly, then connect with the remaining device path
+ //
+ AtLeastOneConnected = FALSE;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleArrayCount,
+ &HandleArray
+ );
+ if (!EFI_ERROR (Status)) {
+ for (Index = 0; Index < HandleArrayCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleArray[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **)&PciIo
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Check whether the Pci device is the wanted usb host controller
+ //
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x09, 3, &Class);
+ if (!EFI_ERROR (Status)) {
+ if ((PCI_CLASS_SERIAL == Class[2]) &&
+ (PCI_CLASS_SERIAL_USB == Class[1])) {
+ if (HostControllerPI == Class[0] || HostControllerPI == 0xFF) {
+ Status = gBS->ConnectController (
+ HandleArray[Index],
+ NULL,
+ RemainingDevicePath,
+ FALSE
+ );
+ if (!EFI_ERROR(Status)) {
+ AtLeastOneConnected = TRUE;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (HandleArray != NULL) {
+ FreePool (HandleArray);
+ }
+
+ if (AtLeastOneConnected) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
diff --git a/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsConsole.c b/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsConsole.c
new file mode 100644
index 0000000000..7832fc49c7
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsConsole.c
@@ -0,0 +1,1301 @@
+/** @file
+ BDS Lib functions which contain all the code to connect console device
+
+Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "InternalBdsLib.h"
+#include <IndustryStandard/Bmp.h>
+
+
+/**
+ Check if we need to save the EFI variable with "ConVarName" as name
+ as NV type
+ If ConVarName is NULL, then ASSERT().
+
+ @param ConVarName The name of the EFI variable.
+
+ @retval TRUE Set the EFI variable as NV type.
+ @retval FALSE EFI variable as NV type can be set NonNV.
+**/
+BOOLEAN
+IsNvNeed (
+ IN CHAR16 *ConVarName
+ )
+{
+ CHAR16 *Ptr;
+
+ ASSERT (ConVarName != NULL);
+
+ Ptr = ConVarName;
+
+ //
+ // If the variable includes "Dev" at last, we consider
+ // it does not support NV attribute.
+ //
+ while (*Ptr != L'\0') {
+ Ptr++;
+ }
+
+ if (((INTN)((UINTN)Ptr - (UINTN)ConVarName) / sizeof (CHAR16)) <= 3) {
+ return TRUE;
+ }
+
+ if ((*(Ptr - 3) == 'D') && (*(Ptr - 2) == 'e') && (*(Ptr - 1) == 'v')) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+/**
+ Fill console handle in System Table if there are no valid console handle in.
+
+ Firstly, check the validation of console handle in System Table. If it is invalid,
+ update it by the first console device handle from EFI console variable.
+
+ @param VarName The name of the EFI console variable.
+ @param ConsoleGuid Specified Console protocol GUID.
+ @param ConsoleHandle On IN, console handle in System Table to be checked.
+ On OUT, new console handle in system table.
+ @param ProtocolInterface On IN, console protocol on console handle in System Table to be checked.
+ On OUT, new console protocol on new console handle in system table.
+
+ @retval TRUE System Table has been updated.
+ @retval FALSE System Table hasn't been updated.
+
+**/
+BOOLEAN
+UpdateSystemTableConsole (
+ IN CHAR16 *VarName,
+ IN EFI_GUID *ConsoleGuid,
+ IN OUT EFI_HANDLE *ConsoleHandle,
+ IN OUT VOID **ProtocolInterface
+ )
+{
+ EFI_STATUS Status;
+ UINTN DevicePathSize;
+ EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *VarConsole;
+ EFI_DEVICE_PATH_PROTOCOL *Instance;
+ VOID *Interface;
+ EFI_HANDLE NewHandle;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut;
+
+ ASSERT (VarName != NULL);
+ ASSERT (ConsoleHandle != NULL);
+ ASSERT (ConsoleGuid != NULL);
+ ASSERT (ProtocolInterface != NULL);
+
+ if (*ConsoleHandle != NULL) {
+ Status = gBS->HandleProtocol (
+ *ConsoleHandle,
+ ConsoleGuid,
+ &Interface
+ );
+ if (Status == EFI_SUCCESS && Interface == *ProtocolInterface) {
+ //
+ // If ConsoleHandle is valid and console protocol on this handle also
+ // also matched, just return.
+ //
+ return FALSE;
+ }
+ }
+
+ //
+ // Get all possible consoles device path from EFI variable
+ //
+ VarConsole = BdsLibGetVariableAndSize (
+ VarName,
+ &gEfiGlobalVariableGuid,
+ &DevicePathSize
+ );
+ if (VarConsole == NULL) {
+ //
+ // If there is no any console device, just return.
+ //
+ return FALSE;
+ }
+
+ FullDevicePath = VarConsole;
+
+ do {
+ //
+ // Check every instance of the console variable
+ //
+ Instance = GetNextDevicePathInstance (&VarConsole, &DevicePathSize);
+ if (Instance == NULL) {
+ FreePool (FullDevicePath);
+ ASSERT (FALSE);
+ }
+
+ //
+ // Find console device handle by device path instance
+ //
+ Status = gBS->LocateDevicePath (
+ ConsoleGuid,
+ &Instance,
+ &NewHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Get the console protocol on this console device handle
+ //
+ Status = gBS->HandleProtocol (
+ NewHandle,
+ ConsoleGuid,
+ &Interface
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Update new console handle in System Table.
+ //
+ *ConsoleHandle = NewHandle;
+ *ProtocolInterface = Interface;
+ if (CompareGuid (ConsoleGuid, &gEfiSimpleTextOutProtocolGuid)) {
+ //
+ // If it is console out device, set console mode 80x25 if current mode is invalid.
+ //
+ TextOut = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *) Interface;
+ if (TextOut->Mode->Mode == -1) {
+ TextOut->SetMode (TextOut, 0);
+ }
+ }
+ return TRUE;
+ }
+ }
+
+ } while (Instance != NULL);
+
+ //
+ // No any available console devcie found.
+ //
+ return FALSE;
+}
+
+/**
+ This function update console variable based on ConVarName, it can
+ add or remove one specific console device path from the variable
+
+ @param ConVarName Console related variable name, ConIn, ConOut,
+ ErrOut.
+ @param CustomizedConDevicePath The console device path which will be added to
+ the console variable ConVarName, this parameter
+ can not be multi-instance.
+ @param ExclusiveDevicePath The console device path which will be removed
+ from the console variable ConVarName, this
+ parameter can not be multi-instance.
+
+ @retval EFI_UNSUPPORTED The added device path is same to the removed one.
+ @retval EFI_SUCCESS Success add or remove the device path from the
+ console variable.
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibUpdateConsoleVariable (
+ IN CHAR16 *ConVarName,
+ IN EFI_DEVICE_PATH_PROTOCOL *CustomizedConDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *ExclusiveDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *VarConsole;
+ UINTN DevicePathSize;
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;
+ UINT32 Attributes;
+
+ VarConsole = NULL;
+ DevicePathSize = 0;
+
+ //
+ // Notes: check the device path point, here should check
+ // with compare memory
+ //
+ if (CustomizedConDevicePath == ExclusiveDevicePath) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Delete the ExclusiveDevicePath from current default console
+ //
+ VarConsole = BdsLibGetVariableAndSize (
+ ConVarName,
+ &gEfiGlobalVariableGuid,
+ &DevicePathSize
+ );
+
+ //
+ // Initialize NewDevicePath
+ //
+ NewDevicePath = VarConsole;
+
+ //
+ // If ExclusiveDevicePath is even the part of the instance in VarConsole, delete it.
+ // In the end, NewDevicePath is the final device path.
+ //
+ if (ExclusiveDevicePath != NULL && VarConsole != NULL) {
+ NewDevicePath = BdsLibDelPartMatchInstance (VarConsole, ExclusiveDevicePath);
+ }
+ //
+ // Try to append customized device path to NewDevicePath.
+ //
+ if (CustomizedConDevicePath != NULL) {
+ if (!BdsLibMatchDevicePaths (NewDevicePath, CustomizedConDevicePath)) {
+ //
+ // Check if there is part of CustomizedConDevicePath in NewDevicePath, delete it.
+ //
+ NewDevicePath = BdsLibDelPartMatchInstance (NewDevicePath, CustomizedConDevicePath);
+ //
+ // In the first check, the default console variable will be _ModuleEntryPoint,
+ // just append current customized device path
+ //
+ TempNewDevicePath = NewDevicePath;
+ NewDevicePath = AppendDevicePathInstance (NewDevicePath, CustomizedConDevicePath);
+ if (TempNewDevicePath != NULL) {
+ FreePool(TempNewDevicePath);
+ }
+ }
+ }
+
+ //
+ // The attribute for ConInDev, ConOutDev and ErrOutDev does not include NV.
+ //
+ if (IsNvNeed(ConVarName)) {
+ //
+ // ConVarName has NV attribute.
+ //
+ Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE;
+ } else {
+ //
+ // ConVarName does not have NV attribute.
+ //
+ Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
+ }
+
+ //
+ // Finally, Update the variable of the default console by NewDevicePath
+ //
+ DevicePathSize = GetDevicePathSize (NewDevicePath);
+ Status = SetVariableAndReportStatusCodeOnError (
+ ConVarName,
+ &gEfiGlobalVariableGuid,
+ Attributes,
+ DevicePathSize,
+ NewDevicePath
+ );
+ if ((DevicePathSize == 0) && (Status == EFI_NOT_FOUND)) {
+ Status = EFI_SUCCESS;
+ }
+
+ if (VarConsole == NewDevicePath) {
+ if (VarConsole != NULL) {
+ FreePool(VarConsole);
+ }
+ } else {
+ if (VarConsole != NULL) {
+ FreePool(VarConsole);
+ }
+ if (NewDevicePath != NULL) {
+ FreePool(NewDevicePath);
+ }
+ }
+
+ return Status;
+
+}
+
+
+/**
+ Connect the console device base on the variable ConVarName, if
+ device path of the ConVarName is multi-instance device path and
+ anyone of the instances is connected success, then this function
+ will return success.
+ If the handle associate with one device path node can not
+ be created successfully, then still give chance to do the dispatch,
+ which load the missing drivers if possible..
+
+ @param ConVarName Console related variable name, ConIn, ConOut,
+ ErrOut.
+
+ @retval EFI_NOT_FOUND There is not any console devices connected
+ success
+ @retval EFI_SUCCESS Success connect any one instance of the console
+ device path base on the variable ConVarName.
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibConnectConsoleVariable (
+ IN CHAR16 *ConVarName
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *StartDevicePath;
+ UINTN VariableSize;
+ EFI_DEVICE_PATH_PROTOCOL *Instance;
+ EFI_DEVICE_PATH_PROTOCOL *Next;
+ EFI_DEVICE_PATH_PROTOCOL *CopyOfDevicePath;
+ UINTN Size;
+ BOOLEAN DeviceExist;
+
+ Status = EFI_SUCCESS;
+ DeviceExist = FALSE;
+
+ //
+ // Check if the console variable exist
+ //
+ StartDevicePath = BdsLibGetVariableAndSize (
+ ConVarName,
+ &gEfiGlobalVariableGuid,
+ &VariableSize
+ );
+ if (StartDevicePath == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ CopyOfDevicePath = StartDevicePath;
+ do {
+ //
+ // Check every instance of the console variable
+ //
+ Instance = GetNextDevicePathInstance (&CopyOfDevicePath, &Size);
+ if (Instance == NULL) {
+ FreePool (StartDevicePath);
+ return EFI_UNSUPPORTED;
+ }
+
+ Next = Instance;
+ while (!IsDevicePathEndType (Next)) {
+ Next = NextDevicePathNode (Next);
+ }
+
+ SetDevicePathEndNode (Next);
+ //
+ // Connect the USB console
+ // USB console device path is a short-form device path that
+ // starts with the first element being a USB WWID
+ // or a USB Class device path
+ //
+ if ((DevicePathType (Instance) == MESSAGING_DEVICE_PATH) &&
+ ((DevicePathSubType (Instance) == MSG_USB_CLASS_DP)
+ || (DevicePathSubType (Instance) == MSG_USB_WWID_DP)
+ )) {
+ Status = BdsLibConnectUsbDevByShortFormDP (0xFF, Instance);
+ if (!EFI_ERROR (Status)) {
+ DeviceExist = TRUE;
+ }
+ } else {
+ //
+ // Connect the instance device path
+ //
+ Status = BdsLibConnectDevicePath (Instance);
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Delete the instance from the console varialbe
+ //
+ BdsLibUpdateConsoleVariable (ConVarName, NULL, Instance);
+ } else {
+ DeviceExist = TRUE;
+ }
+ }
+ FreePool(Instance);
+ } while (CopyOfDevicePath != NULL);
+
+ FreePool (StartDevicePath);
+
+ if (!DeviceExist) {
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function will search every simpletext device in current system,
+ and make every simpletext device as pertantial console device.
+
+**/
+VOID
+EFIAPI
+BdsLibConnectAllConsoles (
+ VOID
+ )
+{
+ UINTN Index;
+ EFI_DEVICE_PATH_PROTOCOL *ConDevicePath;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+
+ Index = 0;
+ HandleCount = 0;
+ HandleBuffer = NULL;
+ ConDevicePath = NULL;
+
+ //
+ // Update all the console variables
+ //
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleTextInProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ConDevicePath
+ );
+ BdsLibUpdateConsoleVariable (L"ConIn", ConDevicePath, NULL);
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool(HandleBuffer);
+ HandleBuffer = NULL;
+ }
+
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleTextOutProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ for (Index = 0; Index < HandleCount; Index++) {
+ gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ConDevicePath
+ );
+ BdsLibUpdateConsoleVariable (L"ConOut", ConDevicePath, NULL);
+ BdsLibUpdateConsoleVariable (L"ErrOut", ConDevicePath, NULL);
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool(HandleBuffer);
+ }
+
+ //
+ // Connect all console variables
+ //
+ BdsLibConnectAllDefaultConsoles ();
+
+}
+
+/**
+ This function will connect console device base on the console
+ device variable ConIn, ConOut and ErrOut.
+
+ @retval EFI_SUCCESS At least one of the ConIn and ConOut device have
+ been connected success.
+ @retval EFI_STATUS Return the status of BdsLibConnectConsoleVariable ().
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibConnectAllDefaultConsoles (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN SystemTableUpdated;
+
+ //
+ // Connect all default console variables
+ //
+
+ //
+ // It seems impossible not to have any ConOut device on platform,
+ // so we check the status here.
+ //
+ Status = BdsLibConnectConsoleVariable (L"ConOut");
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Insert the performance probe for Console Out
+ //
+ PERF_START (NULL, "ConOut", "BDS", 1);
+ PERF_END (NULL, "ConOut", "BDS", 0);
+
+ //
+ // Because possibly the platform is legacy free, in such case,
+ // ConIn devices (Serial Port and PS2 Keyboard ) does not exist,
+ // so we need not check the status.
+ //
+ BdsLibConnectConsoleVariable (L"ConIn");
+
+ //
+ // The _ModuleEntryPoint err out var is legal.
+ //
+ BdsLibConnectConsoleVariable (L"ErrOut");
+
+ SystemTableUpdated = FALSE;
+ //
+ // Fill console handles in System Table if no console device assignd.
+ //
+ if (UpdateSystemTableConsole (L"ConIn", &gEfiSimpleTextInProtocolGuid, &gST->ConsoleInHandle, (VOID **) &gST->ConIn)) {
+ SystemTableUpdated = TRUE;
+ }
+ if (UpdateSystemTableConsole (L"ConOut", &gEfiSimpleTextOutProtocolGuid, &gST->ConsoleOutHandle, (VOID **) &gST->ConOut)) {
+ SystemTableUpdated = TRUE;
+ }
+ if (UpdateSystemTableConsole (L"ErrOut", &gEfiSimpleTextOutProtocolGuid, &gST->StandardErrorHandle, (VOID **) &gST->StdErr)) {
+ SystemTableUpdated = TRUE;
+ }
+
+ if (SystemTableUpdated) {
+ //
+ // Update the CRC32 in the EFI System Table header
+ //
+ gST->Hdr.CRC32 = 0;
+ gBS->CalculateCrc32 (
+ (UINT8 *) &gST->Hdr,
+ gST->Hdr.HeaderSize,
+ &gST->Hdr.CRC32
+ );
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ This function will connect console device except ConIn base on the console
+ device variable ConOut and ErrOut.
+
+ @retval EFI_SUCCESS At least one of the ConOut device have
+ been connected success.
+ @retval EFI_STATUS Return the status of BdsLibConnectConsoleVariable ().
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibConnectAllDefaultConsolesWithOutConIn (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN SystemTableUpdated;
+
+ //
+ // Connect all default console variables except ConIn
+ //
+
+ //
+ // It seems impossible not to have any ConOut device on platform,
+ // so we check the status here.
+ //
+ Status = BdsLibConnectConsoleVariable (L"ConOut");
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Insert the performance probe for Console Out
+ //
+ PERF_START (NULL, "ConOut", "BDS", 1);
+ PERF_END (NULL, "ConOut", "BDS", 0);
+
+ //
+ // The _ModuleEntryPoint err out var is legal.
+ //
+ BdsLibConnectConsoleVariable (L"ErrOut");
+
+ SystemTableUpdated = FALSE;
+ //
+ // Fill console handles in System Table if no console device assignd.
+ //
+ if (UpdateSystemTableConsole (L"ConOut", &gEfiSimpleTextOutProtocolGuid, &gST->ConsoleOutHandle, (VOID **) &gST->ConOut)) {
+ SystemTableUpdated = TRUE;
+ }
+ if (UpdateSystemTableConsole (L"ErrOut", &gEfiSimpleTextOutProtocolGuid, &gST->StandardErrorHandle, (VOID **) &gST->StdErr)) {
+ SystemTableUpdated = TRUE;
+ }
+
+ if (SystemTableUpdated) {
+ //
+ // Update the CRC32 in the EFI System Table header
+ //
+ gST->Hdr.CRC32 = 0;
+ gBS->CalculateCrc32 (
+ (UINT8 *) &gST->Hdr,
+ gST->Hdr.HeaderSize,
+ &gST->Hdr.CRC32
+ );
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Convert a *.BMP graphics image to a GOP blt buffer. If a NULL Blt buffer
+ is passed in a GopBlt buffer will be allocated by this routine. If a GopBlt
+ buffer is passed in it will be used if it is big enough.
+
+ @param BmpImage Pointer to BMP file
+ @param BmpImageSize Number of bytes in BmpImage
+ @param GopBlt Buffer containing GOP version of BmpImage.
+ @param GopBltSize Size of GopBlt in bytes.
+ @param PixelHeight Height of GopBlt/BmpImage in pixels
+ @param PixelWidth Width of GopBlt/BmpImage in pixels
+
+ @retval EFI_SUCCESS GopBlt and GopBltSize are returned.
+ @retval EFI_UNSUPPORTED BmpImage is not a valid *.BMP image
+ @retval EFI_BUFFER_TOO_SMALL The passed in GopBlt buffer is not big enough.
+ GopBltSize will contain the required size.
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate.
+
+**/
+EFI_STATUS
+ConvertBmpToGopBlt (
+ IN VOID *BmpImage,
+ IN UINTN BmpImageSize,
+ IN OUT VOID **GopBlt,
+ IN OUT UINTN *GopBltSize,
+ OUT UINTN *PixelHeight,
+ OUT UINTN *PixelWidth
+ )
+{
+ UINT8 *Image;
+ UINT8 *ImageHeader;
+ BMP_IMAGE_HEADER *BmpHeader;
+ BMP_COLOR_MAP *BmpColorMap;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
+ UINT64 BltBufferSize;
+ UINTN Index;
+ UINTN Height;
+ UINTN Width;
+ UINTN ImageIndex;
+ UINT32 DataSizePerLine;
+ BOOLEAN IsAllocated;
+ UINT32 ColorMapNum;
+
+ if (sizeof (BMP_IMAGE_HEADER) > BmpImageSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BmpHeader = (BMP_IMAGE_HEADER *) BmpImage;
+
+ if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M') {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Doesn't support compress.
+ //
+ if (BmpHeader->CompressionType != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Only support BITMAPINFOHEADER format.
+ // BITMAPFILEHEADER + BITMAPINFOHEADER = BMP_IMAGE_HEADER
+ //
+ if (BmpHeader->HeaderSize != sizeof (BMP_IMAGE_HEADER) - OFFSET_OF(BMP_IMAGE_HEADER, HeaderSize)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // The data size in each line must be 4 byte alignment.
+ //
+ DataSizePerLine = ((BmpHeader->PixelWidth * BmpHeader->BitPerPixel + 31) >> 3) & (~0x3);
+ BltBufferSize = MultU64x32 (DataSizePerLine, BmpHeader->PixelHeight);
+ if (BltBufferSize > (UINT32) ~0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((BmpHeader->Size != BmpImageSize) ||
+ (BmpHeader->Size < BmpHeader->ImageOffset) ||
+ (BmpHeader->Size - BmpHeader->ImageOffset != BmpHeader->PixelHeight * DataSizePerLine)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Calculate Color Map offset in the image.
+ //
+ Image = BmpImage;
+ BmpColorMap = (BMP_COLOR_MAP *) (Image + sizeof (BMP_IMAGE_HEADER));
+ if (BmpHeader->ImageOffset < sizeof (BMP_IMAGE_HEADER)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BmpHeader->ImageOffset > sizeof (BMP_IMAGE_HEADER)) {
+ switch (BmpHeader->BitPerPixel) {
+ case 1:
+ ColorMapNum = 2;
+ break;
+ case 4:
+ ColorMapNum = 16;
+ break;
+ case 8:
+ ColorMapNum = 256;
+ break;
+ default:
+ ColorMapNum = 0;
+ break;
+ }
+ //
+ // BMP file may has padding data between the bmp header section and the bmp data section.
+ //
+ if (BmpHeader->ImageOffset - sizeof (BMP_IMAGE_HEADER) < sizeof (BMP_COLOR_MAP) * ColorMapNum) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // Calculate graphics image data address in the image
+ //
+ Image = ((UINT8 *) BmpImage) + BmpHeader->ImageOffset;
+ ImageHeader = Image;
+
+ //
+ // Calculate the BltBuffer needed size.
+ //
+ BltBufferSize = MultU64x32 ((UINT64) BmpHeader->PixelWidth, BmpHeader->PixelHeight);
+ //
+ // Ensure the BltBufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
+ //
+ if (BltBufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
+ return EFI_UNSUPPORTED;
+ }
+ BltBufferSize = MultU64x32 (BltBufferSize, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+
+ IsAllocated = FALSE;
+ if (*GopBlt == NULL) {
+ //
+ // GopBlt is not allocated by caller.
+ //
+ *GopBltSize = (UINTN) BltBufferSize;
+ *GopBlt = AllocatePool (*GopBltSize);
+ IsAllocated = TRUE;
+ if (*GopBlt == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ //
+ // GopBlt has been allocated by caller.
+ //
+ if (*GopBltSize < (UINTN) BltBufferSize) {
+ *GopBltSize = (UINTN) BltBufferSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ }
+
+ *PixelWidth = BmpHeader->PixelWidth;
+ *PixelHeight = BmpHeader->PixelHeight;
+
+ //
+ // Convert image from BMP to Blt buffer format
+ //
+ BltBuffer = *GopBlt;
+ for (Height = 0; Height < BmpHeader->PixelHeight; Height++) {
+ Blt = &BltBuffer[(BmpHeader->PixelHeight - Height - 1) * BmpHeader->PixelWidth];
+ for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Image++, Blt++) {
+ switch (BmpHeader->BitPerPixel) {
+ case 1:
+ //
+ // Convert 1-bit (2 colors) BMP to 24-bit color
+ //
+ for (Index = 0; Index < 8 && Width < BmpHeader->PixelWidth; Index++) {
+ Blt->Red = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Red;
+ Blt->Green = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Green;
+ Blt->Blue = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Blue;
+ Blt++;
+ Width++;
+ }
+
+ Blt--;
+ Width--;
+ break;
+
+ case 4:
+ //
+ // Convert 4-bit (16 colors) BMP Palette to 24-bit color
+ //
+ Index = (*Image) >> 4;
+ Blt->Red = BmpColorMap[Index].Red;
+ Blt->Green = BmpColorMap[Index].Green;
+ Blt->Blue = BmpColorMap[Index].Blue;
+ if (Width < (BmpHeader->PixelWidth - 1)) {
+ Blt++;
+ Width++;
+ Index = (*Image) & 0x0f;
+ Blt->Red = BmpColorMap[Index].Red;
+ Blt->Green = BmpColorMap[Index].Green;
+ Blt->Blue = BmpColorMap[Index].Blue;
+ }
+ break;
+
+ case 8:
+ //
+ // Convert 8-bit (256 colors) BMP Palette to 24-bit color
+ //
+ Blt->Red = BmpColorMap[*Image].Red;
+ Blt->Green = BmpColorMap[*Image].Green;
+ Blt->Blue = BmpColorMap[*Image].Blue;
+ break;
+
+ case 24:
+ //
+ // It is 24-bit BMP.
+ //
+ Blt->Blue = *Image++;
+ Blt->Green = *Image++;
+ Blt->Red = *Image;
+ break;
+
+ default:
+ //
+ // Other bit format BMP is not supported.
+ //
+ if (IsAllocated) {
+ FreePool (*GopBlt);
+ *GopBlt = NULL;
+ }
+ return EFI_UNSUPPORTED;
+ break;
+ };
+
+ }
+
+ ImageIndex = (UINTN) (Image - ImageHeader);
+ if ((ImageIndex % 4) != 0) {
+ //
+ // Bmp Image starts each row on a 32-bit boundary!
+ //
+ Image = Image + (4 - (ImageIndex % 4));
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Use SystemTable Conout to stop video based Simple Text Out consoles from going
+ to the video device. Put up LogoFile on every video device that is a console.
+
+ @param[in] LogoFile File name of logo to display on the center of the screen.
+
+ @retval EFI_SUCCESS ConsoleControl has been flipped to graphics and logo displayed.
+ @retval EFI_UNSUPPORTED Logo not found
+
+**/
+EFI_STATUS
+EFIAPI
+EnableQuietBoot (
+ IN EFI_GUID *LogoFile
+ )
+{
+ EFI_STATUS Status;
+ EFI_OEM_BADGING_PROTOCOL *Badging;
+ UINT32 SizeOfX;
+ UINT32 SizeOfY;
+ INTN DestX;
+ INTN DestY;
+ UINT8 *ImageData;
+ UINTN ImageSize;
+ UINTN BltSize;
+ UINT32 Instance;
+ EFI_BADGING_FORMAT Format;
+ EFI_BADGING_DISPLAY_ATTRIBUTE Attribute;
+ UINTN CoordinateX;
+ UINTN CoordinateY;
+ UINTN Height;
+ UINTN Width;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
+ EFI_UGA_DRAW_PROTOCOL *UgaDraw;
+ UINT32 ColorDepth;
+ UINT32 RefreshRate;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_BOOT_LOGO_PROTOCOL *BootLogo;
+ UINTN NumberOfLogos;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *LogoBlt;
+ UINTN LogoDestX;
+ UINTN LogoDestY;
+ UINTN LogoHeight;
+ UINTN LogoWidth;
+ UINTN NewDestX;
+ UINTN NewDestY;
+ UINTN NewHeight;
+ UINTN NewWidth;
+ UINT64 BufferSize;
+
+ UgaDraw = NULL;
+ //
+ // Try to open GOP first
+ //
+ Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput);
+ if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {
+ GraphicsOutput = NULL;
+ //
+ // Open GOP failed, try to open UGA
+ //
+ Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID **) &UgaDraw);
+ }
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Try to open Boot Logo Protocol.
+ //
+ BootLogo = NULL;
+ gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
+
+ //
+ // Erase Cursor from screen
+ //
+ gST->ConOut->EnableCursor (gST->ConOut, FALSE);
+
+ Badging = NULL;
+ Status = gBS->LocateProtocol (&gEfiOEMBadgingProtocolGuid, NULL, (VOID **) &Badging);
+
+ if (GraphicsOutput != NULL) {
+ SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;
+ SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;
+
+ } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
+ Status = UgaDraw->GetMode (UgaDraw, &SizeOfX, &SizeOfY, &ColorDepth, &RefreshRate);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+
+ Blt = NULL;
+ NumberOfLogos = 0;
+ LogoDestX = 0;
+ LogoDestY = 0;
+ LogoHeight = 0;
+ LogoWidth = 0;
+ NewDestX = 0;
+ NewDestY = 0;
+ NewHeight = 0;
+ NewWidth = 0;
+ Instance = 0;
+ while (1) {
+ ImageData = NULL;
+ ImageSize = 0;
+
+ if (Badging != NULL) {
+ //
+ // Get image from OEMBadging protocol.
+ //
+ Status = Badging->GetImage (
+ Badging,
+ &Instance,
+ &Format,
+ &ImageData,
+ &ImageSize,
+ &Attribute,
+ &CoordinateX,
+ &CoordinateY
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Currently only support BMP format.
+ //
+ if (Format != EfiBadgingFormatBMP) {
+ if (ImageData != NULL) {
+ FreePool (ImageData);
+ }
+ continue;
+ }
+ } else {
+ //
+ // Get the specified image from FV.
+ //
+ Status = GetSectionFromAnyFv (LogoFile, EFI_SECTION_RAW, 0, (VOID **) &ImageData, &ImageSize);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ CoordinateX = 0;
+ CoordinateY = 0;
+ if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) {
+ Attribute = EfiBadgingDisplayAttributeCenter;
+ } else {
+ Attribute = EfiBadgingDisplayAttributeCustomized;
+ }
+ }
+
+ if (Blt != NULL) {
+ FreePool (Blt);
+ }
+ Blt = NULL;
+ Status = ConvertBmpToGopBlt (
+ ImageData,
+ ImageSize,
+ (VOID **) &Blt,
+ &BltSize,
+ &Height,
+ &Width
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (ImageData);
+
+ if (Badging == NULL) {
+ return Status;
+ } else {
+ continue;
+ }
+ }
+
+ //
+ // Calculate the display position according to Attribute.
+ //
+ switch (Attribute) {
+ case EfiBadgingDisplayAttributeLeftTop:
+ DestX = CoordinateX;
+ DestY = CoordinateY;
+ break;
+
+ case EfiBadgingDisplayAttributeCenterTop:
+ DestX = (SizeOfX - Width) / 2;
+ DestY = CoordinateY;
+ break;
+
+ case EfiBadgingDisplayAttributeRightTop:
+ DestX = (SizeOfX - Width - CoordinateX);
+ DestY = CoordinateY;;
+ break;
+
+ case EfiBadgingDisplayAttributeCenterRight:
+ DestX = (SizeOfX - Width - CoordinateX);
+ DestY = (SizeOfY - Height) / 2;
+ break;
+
+ case EfiBadgingDisplayAttributeRightBottom:
+ DestX = (SizeOfX - Width - CoordinateX);
+ DestY = (SizeOfY - Height - CoordinateY);
+ break;
+
+ case EfiBadgingDisplayAttributeCenterBottom:
+ DestX = (SizeOfX - Width) / 2;
+ DestY = (SizeOfY - Height - CoordinateY);
+ break;
+
+ case EfiBadgingDisplayAttributeLeftBottom:
+ DestX = CoordinateX;
+ DestY = (SizeOfY - Height - CoordinateY);
+ break;
+
+ case EfiBadgingDisplayAttributeCenterLeft:
+ DestX = CoordinateX;
+ DestY = (SizeOfY - Height) / 2;
+ break;
+
+ case EfiBadgingDisplayAttributeCenter:
+ DestX = (SizeOfX - Width) / 2;
+ DestY = (SizeOfY - Height) / 2;
+ break;
+
+ case EfiBadgingDisplayAttributeCustomized:
+ DestX = (SizeOfX - Width) / 2;
+ DestY = ((SizeOfY * 382) / 1000) - Height / 2;
+ break;
+
+ default:
+ DestX = CoordinateX;
+ DestY = CoordinateY;
+ break;
+ }
+
+ if ((DestX >= 0) && (DestY >= 0)) {
+ if (GraphicsOutput != NULL) {
+ Status = GraphicsOutput->Blt (
+ GraphicsOutput,
+ Blt,
+ EfiBltBufferToVideo,
+ 0,
+ 0,
+ (UINTN) DestX,
+ (UINTN) DestY,
+ Width,
+ Height,
+ Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+ );
+ } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
+ Status = UgaDraw->Blt (
+ UgaDraw,
+ (EFI_UGA_PIXEL *) Blt,
+ EfiUgaBltBufferToVideo,
+ 0,
+ 0,
+ (UINTN) DestX,
+ (UINTN) DestY,
+ Width,
+ Height,
+ Width * sizeof (EFI_UGA_PIXEL)
+ );
+ } else {
+ Status = EFI_UNSUPPORTED;
+ }
+
+ //
+ // Report displayed Logo information.
+ //
+ if (!EFI_ERROR (Status)) {
+ NumberOfLogos++;
+
+ if (LogoWidth == 0) {
+ //
+ // The first Logo.
+ //
+ LogoDestX = (UINTN) DestX;
+ LogoDestY = (UINTN) DestY;
+ LogoWidth = Width;
+ LogoHeight = Height;
+ } else {
+ //
+ // Merge new logo with old one.
+ //
+ NewDestX = MIN ((UINTN) DestX, LogoDestX);
+ NewDestY = MIN ((UINTN) DestY, LogoDestY);
+ NewWidth = MAX ((UINTN) DestX + Width, LogoDestX + LogoWidth) - NewDestX;
+ NewHeight = MAX ((UINTN) DestY + Height, LogoDestY + LogoHeight) - NewDestY;
+
+ LogoDestX = NewDestX;
+ LogoDestY = NewDestY;
+ LogoWidth = NewWidth;
+ LogoHeight = NewHeight;
+ }
+ }
+ }
+
+ FreePool (ImageData);
+
+ if (Badging == NULL) {
+ break;
+ }
+ }
+
+Done:
+ if (BootLogo == NULL || NumberOfLogos == 0) {
+ //
+ // No logo displayed.
+ //
+ if (Blt != NULL) {
+ FreePool (Blt);
+ }
+
+ return Status;
+ }
+
+ //
+ // Advertise displayed Logo information.
+ //
+ if (NumberOfLogos == 1) {
+ //
+ // Only one logo displayed, use its Blt buffer directly for BootLogo protocol.
+ //
+ LogoBlt = Blt;
+ Status = EFI_SUCCESS;
+ } else {
+ //
+ // More than one Logo displayed, get merged BltBuffer using VideoToBuffer operation.
+ //
+ if (Blt != NULL) {
+ FreePool (Blt);
+ }
+
+ //
+ // Ensure the LogoHeight * LogoWidth doesn't overflow
+ //
+ if (LogoHeight > DivU64x64Remainder ((UINTN) ~0, LogoWidth, NULL)) {
+ return EFI_UNSUPPORTED;
+ }
+ BufferSize = MultU64x64 (LogoWidth, LogoHeight);
+
+ //
+ // Ensure the BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
+ //
+ if (BufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
+ return EFI_UNSUPPORTED;
+ }
+
+ LogoBlt = AllocateZeroPool ((UINTN)BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+ if (LogoBlt == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (GraphicsOutput != NULL) {
+ Status = GraphicsOutput->Blt (
+ GraphicsOutput,
+ LogoBlt,
+ EfiBltVideoToBltBuffer,
+ LogoDestX,
+ LogoDestY,
+ 0,
+ 0,
+ LogoWidth,
+ LogoHeight,
+ LogoWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+ );
+ } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
+ Status = UgaDraw->Blt (
+ UgaDraw,
+ (EFI_UGA_PIXEL *) LogoBlt,
+ EfiUgaVideoToBltBuffer,
+ LogoDestX,
+ LogoDestY,
+ 0,
+ 0,
+ LogoWidth,
+ LogoHeight,
+ LogoWidth * sizeof (EFI_UGA_PIXEL)
+ );
+ } else {
+ Status = EFI_UNSUPPORTED;
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ BootLogo->SetBootLogo (BootLogo, LogoBlt, LogoDestX, LogoDestY, LogoWidth, LogoHeight);
+ }
+ FreePool (LogoBlt);
+
+ return Status;
+}
+
+/**
+ Use SystemTable Conout to turn on video based Simple Text Out consoles. The
+ Simple Text Out screens will now be synced up with all non video output devices
+
+ @retval EFI_SUCCESS UGA devices are back in text mode and synced up.
+
+**/
+EFI_STATUS
+EFIAPI
+DisableQuietBoot (
+ VOID
+ )
+{
+
+ //
+ // Enable Cursor on Screen
+ //
+ gST->ConOut->EnableCursor (gST->ConOut, TRUE);
+ return EFI_SUCCESS;
+}
+
diff --git a/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsMisc.c b/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsMisc.c
new file mode 100644
index 0000000000..29854563f5
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsMisc.c
@@ -0,0 +1,1589 @@
+/** @file
+ Misc BDS library function
+
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "InternalBdsLib.h"
+
+
+#define MAX_STRING_LEN 200
+
+BOOLEAN mFeaturerSwitch = TRUE;
+BOOLEAN mResetRequired = FALSE;
+
+extern UINT16 gPlatformBootTimeOutDefault;
+
+/**
+ The function will go through the driver option link list, load and start
+ every driver the driver option device path point to.
+
+ @param BdsDriverLists The header of the current driver option link list
+
+**/
+VOID
+EFIAPI
+BdsLibLoadDrivers (
+ IN LIST_ENTRY *BdsDriverLists
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ BDS_COMMON_OPTION *Option;
+ EFI_HANDLE ImageHandle;
+ EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
+ UINTN ExitDataSize;
+ CHAR16 *ExitData;
+ BOOLEAN ReconnectAll;
+
+ ReconnectAll = FALSE;
+
+ //
+ // Process the driver option
+ //
+ for (Link = BdsDriverLists->ForwardLink; Link != BdsDriverLists; Link = Link->ForwardLink) {
+ Option = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);
+
+ //
+ // If a load option is not marked as LOAD_OPTION_ACTIVE,
+ // the boot manager will not automatically load the option.
+ //
+ if (!IS_LOAD_OPTION_TYPE (Option->Attribute, LOAD_OPTION_ACTIVE)) {
+ continue;
+ }
+
+ //
+ // If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT,
+ // then all of the EFI drivers in the system will be disconnected and
+ // reconnected after the last driver load option is processed.
+ //
+ if (IS_LOAD_OPTION_TYPE (Option->Attribute, LOAD_OPTION_FORCE_RECONNECT)) {
+ ReconnectAll = TRUE;
+ }
+
+ //
+ // Make sure the driver path is connected.
+ //
+ BdsLibConnectDevicePath (Option->DevicePath);
+
+ //
+ // Load and start the image that Driver#### describes
+ //
+ Status = gBS->LoadImage (
+ FALSE,
+ gImageHandle,
+ Option->DevicePath,
+ NULL,
+ 0,
+ &ImageHandle
+ );
+
+ if (!EFI_ERROR (Status)) {
+ gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
+
+ //
+ // Verify whether this image is a driver, if not,
+ // exit it and continue to parse next load option
+ //
+ if (ImageInfo->ImageCodeType != EfiBootServicesCode && ImageInfo->ImageCodeType != EfiRuntimeServicesCode) {
+ gBS->Exit (ImageHandle, EFI_INVALID_PARAMETER, 0, NULL);
+ continue;
+ }
+
+ if (Option->LoadOptionsSize != 0) {
+ ImageInfo->LoadOptionsSize = Option->LoadOptionsSize;
+ ImageInfo->LoadOptions = Option->LoadOptions;
+ }
+ //
+ // Before calling the image, enable the Watchdog Timer for
+ // the 5 Minute period
+ //
+ gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
+
+ Status = gBS->StartImage (ImageHandle, &ExitDataSize, &ExitData);
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Driver Return Status = %r\n", Status));
+
+ //
+ // Clear the Watchdog Timer after the image returns
+ //
+ gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
+ }
+ }
+
+ //
+ // Process the LOAD_OPTION_FORCE_RECONNECT driver option
+ //
+ if (ReconnectAll) {
+ BdsLibDisconnectAllEfi ();
+ BdsLibConnectAll ();
+ }
+
+}
+
+/**
+ Get the Option Number that does not used.
+ Try to locate the specific option variable one by one utile find a free number.
+
+ @param VariableName Indicate if the boot#### or driver#### option
+
+ @return The Minimal Free Option Number
+
+**/
+UINT16
+BdsLibGetFreeOptionNumber (
+ IN CHAR16 *VariableName
+ )
+{
+ UINTN Index;
+ CHAR16 StrTemp[10];
+ UINT16 *OptionBuffer;
+ UINTN OptionSize;
+
+ //
+ // Try to find the minimum free number from 0, 1, 2, 3....
+ //
+ Index = 0;
+ do {
+ if (*VariableName == 'B') {
+ UnicodeSPrint (StrTemp, sizeof (StrTemp), L"Boot%04x", Index);
+ } else {
+ UnicodeSPrint (StrTemp, sizeof (StrTemp), L"Driver%04x", Index);
+ }
+ //
+ // try if the option number is used
+ //
+ OptionBuffer = BdsLibGetVariableAndSize (
+ StrTemp,
+ &gEfiGlobalVariableGuid,
+ &OptionSize
+ );
+ if (OptionBuffer == NULL) {
+ break;
+ }
+ FreePool(OptionBuffer);
+ Index++;
+ } while (TRUE);
+
+ return ((UINT16) Index);
+}
+
+
+/**
+ This function will register the new boot#### or driver#### option base on
+ the VariableName. The new registered boot#### or driver#### will be linked
+ to BdsOptionList and also update to the VariableName. After the boot#### or
+ driver#### updated, the BootOrder or DriverOrder will also be updated.
+
+ @param BdsOptionList The header of the boot#### or driver#### link list
+ @param DevicePath The device path which the boot#### or driver####
+ option present
+ @param String The description of the boot#### or driver####
+ @param VariableName Indicate if the boot#### or driver#### option
+
+ @retval EFI_SUCCESS The boot#### or driver#### have been success
+ registered
+ @retval EFI_STATUS Return the status of gRT->SetVariable ().
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibRegisterNewOption (
+ IN LIST_ENTRY *BdsOptionList,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN CHAR16 *String,
+ IN CHAR16 *VariableName
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINT16 RegisterOptionNumber;
+ UINT16 *TempOptionPtr;
+ UINTN TempOptionSize;
+ UINT16 *OptionOrderPtr;
+ VOID *OptionPtr;
+ UINTN OptionSize;
+ UINT8 *TempPtr;
+ EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
+ CHAR16 *Description;
+ CHAR16 OptionName[10];
+ BOOLEAN UpdateDescription;
+ UINT16 BootOrderEntry;
+ UINTN OrderItemNum;
+
+ if (DevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OptionPtr = NULL;
+ OptionSize = 0;
+ TempPtr = NULL;
+ OptionDevicePath = NULL;
+ Description = NULL;
+ OptionOrderPtr = NULL;
+ UpdateDescription = FALSE;
+ Status = EFI_SUCCESS;
+ ZeroMem (OptionName, sizeof (OptionName));
+
+ TempOptionSize = 0;
+ TempOptionPtr = BdsLibGetVariableAndSize (
+ VariableName,
+ &gEfiGlobalVariableGuid,
+ &TempOptionSize
+ );
+ //
+ // Compare with current option variable if the previous option is set in global variable.
+ //
+ for (Index = 0; Index < TempOptionSize / sizeof (UINT16); Index++) {
+ //
+ // TempOptionPtr must not be NULL if we have non-zero TempOptionSize.
+ //
+ ASSERT (TempOptionPtr != NULL);
+
+ if (*VariableName == 'B') {
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", TempOptionPtr[Index]);
+ } else {
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", TempOptionPtr[Index]);
+ }
+
+ OptionPtr = BdsLibGetVariableAndSize (
+ OptionName,
+ &gEfiGlobalVariableGuid,
+ &OptionSize
+ );
+ if (OptionPtr == NULL) {
+ continue;
+ }
+
+ //
+ // Validate the variable.
+ //
+ if (!ValidateOption(OptionPtr, OptionSize)) {
+ FreePool(OptionPtr);
+ continue;
+ }
+
+ TempPtr = OptionPtr;
+ TempPtr += sizeof (UINT32) + sizeof (UINT16);
+ Description = (CHAR16 *) TempPtr;
+ TempPtr += StrSize ((CHAR16 *) TempPtr);
+ OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
+
+ //
+ // Notes: the description may will change base on the GetStringToken
+ //
+ if (CompareMem (OptionDevicePath, DevicePath, GetDevicePathSize (OptionDevicePath)) == 0) {
+ if (CompareMem (Description, String, StrSize (Description)) == 0) {
+ //
+ // Got the option, so just return
+ //
+ FreePool (OptionPtr);
+ FreePool (TempOptionPtr);
+ return EFI_SUCCESS;
+ } else {
+ //
+ // Option description changed, need update.
+ //
+ UpdateDescription = TRUE;
+ FreePool (OptionPtr);
+ break;
+ }
+ }
+
+ FreePool (OptionPtr);
+ }
+
+ OptionSize = sizeof (UINT32) + sizeof (UINT16) + StrSize (String);
+ OptionSize += GetDevicePathSize (DevicePath);
+ OptionPtr = AllocateZeroPool (OptionSize);
+ ASSERT (OptionPtr != NULL);
+
+ TempPtr = OptionPtr;
+ *(UINT32 *) TempPtr = LOAD_OPTION_ACTIVE;
+ TempPtr += sizeof (UINT32);
+ *(UINT16 *) TempPtr = (UINT16) GetDevicePathSize (DevicePath);
+ TempPtr += sizeof (UINT16);
+ CopyMem (TempPtr, String, StrSize (String));
+ TempPtr += StrSize (String);
+ CopyMem (TempPtr, DevicePath, GetDevicePathSize (DevicePath));
+
+ if (UpdateDescription) {
+ //
+ // The number in option#### to be updated.
+ // In this case, we must have non-NULL TempOptionPtr.
+ //
+ ASSERT (TempOptionPtr != NULL);
+ RegisterOptionNumber = TempOptionPtr[Index];
+ } else {
+ //
+ // The new option#### number
+ //
+ RegisterOptionNumber = BdsLibGetFreeOptionNumber(VariableName);
+ }
+
+ if (*VariableName == 'B') {
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", RegisterOptionNumber);
+ } else {
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", RegisterOptionNumber);
+ }
+
+ Status = gRT->SetVariable (
+ OptionName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ OptionSize,
+ OptionPtr
+ );
+ //
+ // Return if only need to update a changed description or fail to set option.
+ //
+ if (EFI_ERROR (Status) || UpdateDescription) {
+ FreePool (OptionPtr);
+ if (TempOptionPtr != NULL) {
+ FreePool (TempOptionPtr);
+ }
+ return Status;
+ }
+
+ FreePool (OptionPtr);
+
+ //
+ // Update the option order variable
+ //
+
+ //
+ // If no option order
+ //
+ if (TempOptionSize == 0) {
+ BootOrderEntry = 0;
+ Status = gRT->SetVariable (
+ VariableName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ sizeof (UINT16),
+ &BootOrderEntry
+ );
+ if (TempOptionPtr != NULL) {
+ FreePool (TempOptionPtr);
+ }
+ return Status;
+ }
+
+ //
+ // TempOptionPtr must not be NULL if TempOptionSize is not zero.
+ //
+ ASSERT (TempOptionPtr != NULL);
+ //
+ // Append the new option number to the original option order
+ //
+ OrderItemNum = (TempOptionSize / sizeof (UINT16)) + 1 ;
+ OptionOrderPtr = AllocateZeroPool ( OrderItemNum * sizeof (UINT16));
+ ASSERT (OptionOrderPtr!= NULL);
+ CopyMem (OptionOrderPtr, TempOptionPtr, (OrderItemNum - 1) * sizeof (UINT16));
+
+ OptionOrderPtr[Index] = RegisterOptionNumber;
+
+ Status = gRT->SetVariable (
+ VariableName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ OrderItemNum * sizeof (UINT16),
+ OptionOrderPtr
+ );
+ FreePool (TempOptionPtr);
+ FreePool (OptionOrderPtr);
+
+ return Status;
+}
+
+/**
+ Returns the size of a device path in bytes.
+
+ This function returns the size, in bytes, of the device path data structure
+ specified by DevicePath including the end of device path node. If DevicePath
+ is NULL, then 0 is returned. If the length of the device path is bigger than
+ MaxSize, also return 0 to indicate this is an invalidate device path.
+
+ @param DevicePath A pointer to a device path data structure.
+ @param MaxSize Max valid device path size. If big than this size,
+ return error.
+
+ @retval 0 An invalid device path.
+ @retval Others The size of a device path in bytes.
+
+**/
+UINTN
+GetDevicePathSizeEx (
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN UINTN MaxSize
+ )
+{
+ UINTN Size;
+ UINTN NodeSize;
+
+ if (DevicePath == NULL) {
+ return 0;
+ }
+
+ //
+ // Search for the end of the device path structure
+ //
+ Size = 0;
+ while (!IsDevicePathEnd (DevicePath)) {
+ NodeSize = DevicePathNodeLength (DevicePath);
+ if (NodeSize < END_DEVICE_PATH_LENGTH) {
+ return 0;
+ }
+ Size += NodeSize;
+ if (Size > MaxSize) {
+ return 0;
+ }
+ DevicePath = NextDevicePathNode (DevicePath);
+ }
+ Size += DevicePathNodeLength (DevicePath);
+ if (Size > MaxSize) {
+ return 0;
+ }
+
+ return Size;
+}
+
+/**
+ Returns the length of a Null-terminated Unicode string. If the length is
+ bigger than MaxStringLen, return length 0 to indicate that this is an
+ invalidate string.
+
+ This function returns the byte length of Unicode characters in the Null-terminated
+ Unicode string specified by String.
+
+ If String is NULL, then ASSERT().
+ If String is not aligned on a 16-bit boundary, then ASSERT().
+
+ @param String A pointer to a Null-terminated Unicode string.
+ @param MaxStringLen Max string len in this string.
+
+ @retval 0 An invalid string.
+ @retval Others The length of String.
+
+**/
+UINTN
+StrSizeEx (
+ IN CONST CHAR16 *String,
+ IN UINTN MaxStringLen
+ )
+{
+ UINTN Length;
+
+ ASSERT (String != NULL && MaxStringLen != 0);
+ ASSERT (((UINTN) String & BIT0) == 0);
+
+ for (Length = 0; *String != L'\0' && MaxStringLen != Length; String++, Length+=2);
+
+ if (*String != L'\0' && MaxStringLen == Length) {
+ return 0;
+ }
+
+ return Length + 2;
+}
+
+/**
+ Validate the EFI Boot#### variable (VendorGuid/Name)
+
+ @param Variable Boot#### variable data.
+ @param VariableSize Returns the size of the EFI variable that was read
+
+ @retval TRUE The variable data is correct.
+ @retval FALSE The variable data is corrupted.
+
+**/
+BOOLEAN
+ValidateOption (
+ UINT8 *Variable,
+ UINTN VariableSize
+ )
+{
+ UINT16 FilePathSize;
+ UINT8 *TempPtr;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINTN TempSize;
+
+ if (VariableSize <= sizeof (UINT16) + sizeof (UINT32)) {
+ return FALSE;
+ }
+
+ //
+ // Skip the option attribute
+ //
+ TempPtr = Variable;
+ TempPtr += sizeof (UINT32);
+
+ //
+ // Get the option's device path size
+ //
+ FilePathSize = *(UINT16 *) TempPtr;
+ TempPtr += sizeof (UINT16);
+
+ //
+ // Get the option's description string size
+ //
+ TempSize = StrSizeEx ((CHAR16 *) TempPtr, VariableSize - sizeof (UINT16) - sizeof (UINT32));
+ TempPtr += TempSize;
+
+ //
+ // Get the option's device path
+ //
+ DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
+ TempPtr += FilePathSize;
+
+ //
+ // Validation boot option variable.
+ //
+ if ((FilePathSize == 0) || (TempSize == 0)) {
+ return FALSE;
+ }
+
+ if (TempSize + FilePathSize + sizeof (UINT16) + sizeof (UINT32) > VariableSize) {
+ return FALSE;
+ }
+
+ return (BOOLEAN) (GetDevicePathSizeEx (DevicePath, FilePathSize) != 0);
+}
+
+/**
+ Convert a single character to number.
+ It assumes the input Char is in the scope of L'0' ~ L'9' and L'A' ~ L'F'
+
+ @param Char The input char which need to change to a hex number.
+
+**/
+UINTN
+CharToUint (
+ IN CHAR16 Char
+ )
+{
+ if ((Char >= L'0') && (Char <= L'9')) {
+ return (UINTN) (Char - L'0');
+ }
+
+ if ((Char >= L'A') && (Char <= L'F')) {
+ return (UINTN) (Char - L'A' + 0xA);
+ }
+
+ ASSERT (FALSE);
+ return 0;
+}
+
+/**
+ Build the boot#### or driver#### option from the VariableName, the
+ build boot#### or driver#### will also be linked to BdsCommonOptionList.
+
+ @param BdsCommonOptionList The header of the boot#### or driver#### option
+ link list
+ @param VariableName EFI Variable name indicate if it is boot#### or
+ driver####
+
+ @retval BDS_COMMON_OPTION Get the option just been created
+ @retval NULL Failed to get the new option
+
+**/
+BDS_COMMON_OPTION *
+EFIAPI
+BdsLibVariableToOption (
+ IN OUT LIST_ENTRY *BdsCommonOptionList,
+ IN CHAR16 *VariableName
+ )
+{
+ UINT32 Attribute;
+ UINT16 FilePathSize;
+ UINT8 *Variable;
+ UINT8 *TempPtr;
+ UINTN VariableSize;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ BDS_COMMON_OPTION *Option;
+ VOID *LoadOptions;
+ UINT32 LoadOptionsSize;
+ CHAR16 *Description;
+ UINT8 NumOff;
+
+ //
+ // Read the variable. We will never free this data.
+ //
+ Variable = BdsLibGetVariableAndSize (
+ VariableName,
+ &gEfiGlobalVariableGuid,
+ &VariableSize
+ );
+ if (Variable == NULL) {
+ return NULL;
+ }
+
+ //
+ // Validate Boot#### variable data.
+ //
+ if (!ValidateOption(Variable, VariableSize)) {
+ FreePool (Variable);
+ return NULL;
+ }
+
+ //
+ // Notes: careful defined the variable of Boot#### or
+ // Driver####, consider use some macro to abstract the code
+ //
+ //
+ // Get the option attribute
+ //
+ TempPtr = Variable;
+ Attribute = *(UINT32 *) Variable;
+ TempPtr += sizeof (UINT32);
+
+ //
+ // Get the option's device path size
+ //
+ FilePathSize = *(UINT16 *) TempPtr;
+ TempPtr += sizeof (UINT16);
+
+ //
+ // Get the option's description string
+ //
+ Description = (CHAR16 *) TempPtr;
+
+ //
+ // Get the option's description string size
+ //
+ TempPtr += StrSize((CHAR16 *) TempPtr);
+
+ //
+ // Get the option's device path
+ //
+ DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
+ TempPtr += FilePathSize;
+
+ //
+ // Get load opion data.
+ //
+ LoadOptions = TempPtr;
+ LoadOptionsSize = (UINT32) (VariableSize - (UINTN) (TempPtr - Variable));
+
+ //
+ // The Console variables may have multiple device paths, so make
+ // an Entry for each one.
+ //
+ Option = AllocateZeroPool (sizeof (BDS_COMMON_OPTION));
+ if (Option == NULL) {
+ FreePool (Variable);
+ return NULL;
+ }
+
+ Option->Signature = BDS_LOAD_OPTION_SIGNATURE;
+ Option->DevicePath = AllocateZeroPool (GetDevicePathSize (DevicePath));
+ ASSERT(Option->DevicePath != NULL);
+ CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath));
+
+ Option->Attribute = Attribute;
+ Option->Description = AllocateZeroPool (StrSize (Description));
+ ASSERT(Option->Description != NULL);
+ CopyMem (Option->Description, Description, StrSize (Description));
+
+ Option->LoadOptions = AllocateZeroPool (LoadOptionsSize);
+ ASSERT(Option->LoadOptions != NULL);
+ CopyMem (Option->LoadOptions, LoadOptions, LoadOptionsSize);
+ Option->LoadOptionsSize = LoadOptionsSize;
+
+ //
+ // Get the value from VariableName Unicode string
+ // since the ISO standard assumes ASCII equivalent abbreviations, we can be safe in converting this
+ // Unicode stream to ASCII without any loss in meaning.
+ //
+ if (*VariableName == 'B') {
+ NumOff = (UINT8) (sizeof (L"Boot") / sizeof (CHAR16) - 1);
+ Option->BootCurrent = (UINT16) (CharToUint (VariableName[NumOff+0]) * 0x1000)
+ + (UINT16) (CharToUint (VariableName[NumOff+1]) * 0x100)
+ + (UINT16) (CharToUint (VariableName[NumOff+2]) * 0x10)
+ + (UINT16) (CharToUint (VariableName[NumOff+3]) * 0x1);
+ }
+ InsertTailList (BdsCommonOptionList, &Option->Link);
+ FreePool (Variable);
+ return Option;
+}
+
+/**
+ Process BootOrder, or DriverOrder variables, by calling
+ BdsLibVariableToOption () for each UINT16 in the variables.
+
+ @param BdsCommonOptionList The header of the option list base on variable
+ VariableName
+ @param VariableName EFI Variable name indicate the BootOrder or
+ DriverOrder
+
+ @retval EFI_SUCCESS Success create the boot option or driver option
+ list
+ @retval EFI_OUT_OF_RESOURCES Failed to get the boot option or driver option list
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibBuildOptionFromVar (
+ IN LIST_ENTRY *BdsCommonOptionList,
+ IN CHAR16 *VariableName
+ )
+{
+ UINT16 *OptionOrder;
+ UINTN OptionOrderSize;
+ UINTN Index;
+ BDS_COMMON_OPTION *Option;
+ CHAR16 OptionName[20];
+
+ //
+ // Zero Buffer in order to get all BOOT#### variables
+ //
+ ZeroMem (OptionName, sizeof (OptionName));
+
+ //
+ // Read the BootOrder, or DriverOrder variable.
+ //
+ OptionOrder = BdsLibGetVariableAndSize (
+ VariableName,
+ &gEfiGlobalVariableGuid,
+ &OptionOrderSize
+ );
+ if (OptionOrder == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
+ if (*VariableName == 'B') {
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", OptionOrder[Index]);
+ } else {
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", OptionOrder[Index]);
+ }
+
+ Option = BdsLibVariableToOption (BdsCommonOptionList, OptionName);
+ if (Option != NULL) {
+ Option->BootCurrent = OptionOrder[Index];
+ }
+ }
+
+ FreePool (OptionOrder);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get boot mode by looking up configuration table and parsing HOB list
+
+ @param BootMode Boot mode from PEI handoff HOB.
+
+ @retval EFI_SUCCESS Successfully get boot mode
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibGetBootMode (
+ OUT EFI_BOOT_MODE *BootMode
+ )
+{
+ *BootMode = GetBootModeHob ();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read the EFI variable (VendorGuid/Name) and return a dynamically allocated
+ buffer, and the size of the buffer. If failure return NULL.
+
+ @param Name String part of EFI variable name
+ @param VendorGuid GUID part of EFI variable name
+ @param VariableSize Returns the size of the EFI variable that was read
+
+ @return Dynamically allocated memory that contains a copy of the EFI variable
+ Caller is responsible freeing the buffer.
+ @retval NULL Variable was not read
+
+**/
+VOID *
+EFIAPI
+BdsLibGetVariableAndSize (
+ IN CHAR16 *Name,
+ IN EFI_GUID *VendorGuid,
+ OUT UINTN *VariableSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ VOID *Buffer;
+
+ Buffer = NULL;
+
+ //
+ // Pass in a zero size buffer to find the required buffer size.
+ //
+ BufferSize = 0;
+ Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ //
+ // Allocate the buffer to return
+ //
+ Buffer = AllocateZeroPool (BufferSize);
+ if (Buffer == NULL) {
+ *VariableSize = 0;
+ return NULL;
+ }
+ //
+ // Read variable into the allocated buffer.
+ //
+ Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
+ if (EFI_ERROR (Status)) {
+ FreePool (Buffer);
+ BufferSize = 0;
+ Buffer = NULL;
+ }
+ }
+
+ ASSERT (((Buffer == NULL) && (BufferSize == 0)) ||
+ ((Buffer != NULL) && (BufferSize != 0))
+ );
+ *VariableSize = BufferSize;
+ return Buffer;
+}
+
+/**
+ Delete the instance in Multi which matches partly with Single instance
+
+ @param Multi A pointer to a multi-instance device path data
+ structure.
+ @param Single A pointer to a single-instance device path data
+ structure.
+
+ @return This function will remove the device path instances in Multi which partly
+ match with the Single, and return the result device path. If there is no
+ remaining device path as a result, this function will return NULL.
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+EFIAPI
+BdsLibDelPartMatchInstance (
+ IN EFI_DEVICE_PATH_PROTOCOL *Multi,
+ IN EFI_DEVICE_PATH_PROTOCOL *Single
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *Instance;
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;
+ UINTN InstanceSize;
+ UINTN SingleDpSize;
+ UINTN Size;
+
+ NewDevicePath = NULL;
+ TempNewDevicePath = NULL;
+
+ if (Multi == NULL || Single == NULL) {
+ return Multi;
+ }
+
+ Instance = GetNextDevicePathInstance (&Multi, &InstanceSize);
+ SingleDpSize = GetDevicePathSize (Single) - END_DEVICE_PATH_LENGTH;
+ InstanceSize -= END_DEVICE_PATH_LENGTH;
+
+ while (Instance != NULL) {
+
+ Size = (SingleDpSize < InstanceSize) ? SingleDpSize : InstanceSize;
+
+ if ((CompareMem (Instance, Single, Size) != 0)) {
+ //
+ // Append the device path instance which does not match with Single
+ //
+ TempNewDevicePath = NewDevicePath;
+ NewDevicePath = AppendDevicePathInstance (NewDevicePath, Instance);
+ if (TempNewDevicePath != NULL) {
+ FreePool(TempNewDevicePath);
+ }
+ }
+ FreePool(Instance);
+ Instance = GetNextDevicePathInstance (&Multi, &InstanceSize);
+ InstanceSize -= END_DEVICE_PATH_LENGTH;
+ }
+
+ return NewDevicePath;
+}
+
+/**
+ Function compares a device path data structure to that of all the nodes of a
+ second device path instance.
+
+ @param Multi A pointer to a multi-instance device path data
+ structure.
+ @param Single A pointer to a single-instance device path data
+ structure.
+
+ @retval TRUE If the Single device path is contained within Multi device path.
+ @retval FALSE The Single device path is not match within Multi device path.
+
+**/
+BOOLEAN
+EFIAPI
+BdsLibMatchDevicePaths (
+ IN EFI_DEVICE_PATH_PROTOCOL *Multi,
+ IN EFI_DEVICE_PATH_PROTOCOL *Single
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;
+ UINTN Size;
+
+ if (Multi == NULL || Single == NULL) {
+ return FALSE;
+ }
+
+ DevicePath = Multi;
+ DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
+
+ //
+ // Search for the match of 'Single' in 'Multi'
+ //
+ while (DevicePathInst != NULL) {
+ //
+ // If the single device path is found in multiple device paths,
+ // return success
+ //
+ if (CompareMem (Single, DevicePathInst, Size) == 0) {
+ FreePool (DevicePathInst);
+ return TRUE;
+ }
+
+ FreePool (DevicePathInst);
+ DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
+ }
+
+ return FALSE;
+}
+
+/**
+ This function prints a series of strings.
+
+ @param ConOut Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
+ @param ... A variable argument list containing series of
+ strings, the last string must be NULL.
+
+ @retval EFI_SUCCESS Success print out the string using ConOut.
+ @retval EFI_STATUS Return the status of the ConOut->OutputString ().
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibOutputStrings (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut,
+ ...
+ )
+{
+ VA_LIST Args;
+ EFI_STATUS Status;
+ CHAR16 *String;
+
+ Status = EFI_SUCCESS;
+ VA_START (Args, ConOut);
+
+ while (!EFI_ERROR (Status)) {
+ //
+ // If String is NULL, then it's the end of the list
+ //
+ String = VA_ARG (Args, CHAR16 *);
+ if (String == NULL) {
+ break;
+ }
+
+ Status = ConOut->OutputString (ConOut, String);
+
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ VA_END(Args);
+ return Status;
+}
+
+//
+// Following are BDS Lib functions which contain all the code about setup browser reset reminder feature.
+// Setup Browser reset reminder feature is that an reset reminder will be given before user leaves the setup browser if
+// user change any option setting which needs a reset to be effective, and the reset will be applied according to the user selection.
+//
+
+
+/**
+ Enable the setup browser reset reminder feature.
+ This routine is used in platform tip. If the platform policy need the feature, use the routine to enable it.
+
+**/
+VOID
+EFIAPI
+EnableResetReminderFeature (
+ VOID
+ )
+{
+ mFeaturerSwitch = TRUE;
+}
+
+
+/**
+ Disable the setup browser reset reminder feature.
+ This routine is used in platform tip. If the platform policy do not want the feature, use the routine to disable it.
+
+**/
+VOID
+EFIAPI
+DisableResetReminderFeature (
+ VOID
+ )
+{
+ mFeaturerSwitch = FALSE;
+}
+
+
+/**
+ Record the info that a reset is required.
+ A module boolean variable is used to record whether a reset is required.
+
+**/
+VOID
+EFIAPI
+EnableResetRequired (
+ VOID
+ )
+{
+ mResetRequired = TRUE;
+}
+
+
+/**
+ Record the info that no reset is required.
+ A module boolean variable is used to record whether a reset is required.
+
+**/
+VOID
+EFIAPI
+DisableResetRequired (
+ VOID
+ )
+{
+ mResetRequired = FALSE;
+}
+
+
+/**
+ Check whether platform policy enable the reset reminder feature. The default is enabled.
+
+**/
+BOOLEAN
+EFIAPI
+IsResetReminderFeatureEnable (
+ VOID
+ )
+{
+ return mFeaturerSwitch;
+}
+
+
+/**
+ Check if user changed any option setting which needs a system reset to be effective.
+
+**/
+BOOLEAN
+EFIAPI
+IsResetRequired (
+ VOID
+ )
+{
+ return mResetRequired;
+}
+
+
+/**
+ Check whether a reset is needed, and finish the reset reminder feature.
+ If a reset is needed, Popup a menu to notice user, and finish the feature
+ according to the user selection.
+
+**/
+VOID
+EFIAPI
+SetupResetReminder (
+ VOID
+ )
+{
+ EFI_INPUT_KEY Key;
+ CHAR16 *StringBuffer1;
+ CHAR16 *StringBuffer2;
+
+
+ //
+ //check any reset required change is applied? if yes, reset system
+ //
+ if (IsResetReminderFeatureEnable ()) {
+ if (IsResetRequired ()) {
+
+ StringBuffer1 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));
+ ASSERT (StringBuffer1 != NULL);
+ StringBuffer2 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));
+ ASSERT (StringBuffer2 != NULL);
+ StrCpyS (
+ StringBuffer1,
+ MAX_STRING_LEN,
+ L"Configuration changed. Reset to apply it Now."
+ );
+ StrCpyS (
+ StringBuffer2,
+ MAX_STRING_LEN,
+ L"Press ENTER to reset"
+ );
+ //
+ // Popup a menu to notice user
+ //
+ do {
+ CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, StringBuffer1, StringBuffer2, NULL);
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
+
+ FreePool (StringBuffer1);
+ FreePool (StringBuffer2);
+
+ gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
+ }
+ }
+}
+
+/**
+ Get the headers (dos, image, optional header) from an image
+
+ @param Device SimpleFileSystem device handle
+ @param FileName File name for the image
+ @param DosHeader Pointer to dos header
+ @param Hdr The buffer in which to return the PE32, PE32+, or TE header.
+
+ @retval EFI_SUCCESS Successfully get the machine type.
+ @retval EFI_NOT_FOUND The file is not found.
+ @retval EFI_LOAD_ERROR File is not a valid image file.
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibGetImageHeader (
+ IN EFI_HANDLE Device,
+ IN CHAR16 *FileName,
+ OUT EFI_IMAGE_DOS_HEADER *DosHeader,
+ OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
+ EFI_FILE_HANDLE Root;
+ EFI_FILE_HANDLE ThisFile;
+ UINTN BufferSize;
+ UINT64 FileSize;
+ EFI_FILE_INFO *Info;
+
+ Root = NULL;
+ ThisFile = NULL;
+ //
+ // Handle the file system interface to the device
+ //
+ Status = gBS->HandleProtocol (
+ Device,
+ &gEfiSimpleFileSystemProtocolGuid,
+ (VOID *) &Volume
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = Volume->OpenVolume (
+ Volume,
+ &Root
+ );
+ if (EFI_ERROR (Status)) {
+ Root = NULL;
+ goto Done;
+ }
+ ASSERT (Root != NULL);
+ Status = Root->Open (Root, &ThisFile, FileName, EFI_FILE_MODE_READ, 0);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ ASSERT (ThisFile != NULL);
+
+ //
+ // Get file size
+ //
+ BufferSize = SIZE_OF_EFI_FILE_INFO + 200;
+ do {
+ Info = NULL;
+ Status = gBS->AllocatePool (EfiBootServicesData, BufferSize, (VOID **) &Info);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ Status = ThisFile->GetInfo (
+ ThisFile,
+ &gEfiFileInfoGuid,
+ &BufferSize,
+ Info
+ );
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ FreePool (Info);
+ goto Done;
+ }
+ FreePool (Info);
+ } while (TRUE);
+
+ FileSize = Info->FileSize;
+ FreePool (Info);
+
+ //
+ // Read dos header
+ //
+ BufferSize = sizeof (EFI_IMAGE_DOS_HEADER);
+ Status = ThisFile->Read (ThisFile, &BufferSize, DosHeader);
+ if (EFI_ERROR (Status) ||
+ BufferSize < sizeof (EFI_IMAGE_DOS_HEADER) ||
+ FileSize <= DosHeader->e_lfanew ||
+ DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
+ Status = EFI_LOAD_ERROR;
+ goto Done;
+ }
+
+ //
+ // Move to PE signature
+ //
+ Status = ThisFile->SetPosition (ThisFile, DosHeader->e_lfanew);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_LOAD_ERROR;
+ goto Done;
+ }
+
+ //
+ // Read and check PE signature
+ //
+ BufferSize = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);
+ Status = ThisFile->Read (ThisFile, &BufferSize, Hdr.Pe32);
+ if (EFI_ERROR (Status) ||
+ BufferSize < sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION) ||
+ Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
+ Status = EFI_LOAD_ERROR;
+ goto Done;
+ }
+
+ //
+ // Check PE32 or PE32+ magic
+ //
+ if (Hdr.Pe32->OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC &&
+ Hdr.Pe32->OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ Status = EFI_LOAD_ERROR;
+ goto Done;
+ }
+
+ Done:
+ if (ThisFile != NULL) {
+ ThisFile->Close (ThisFile);
+ }
+ if (Root != NULL) {
+ Root->Close (Root);
+ }
+ return Status;
+}
+
+/**
+ This routine adjust the memory information for different memory type and
+ save them into the variables for next boot.
+**/
+VOID
+BdsSetMemoryTypeInformationVariable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_MEMORY_TYPE_INFORMATION *PreviousMemoryTypeInformation;
+ EFI_MEMORY_TYPE_INFORMATION *CurrentMemoryTypeInformation;
+ UINTN VariableSize;
+ UINTN Index;
+ UINTN Index1;
+ UINT32 Previous;
+ UINT32 Current;
+ UINT32 Next;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ BOOLEAN MemoryTypeInformationModified;
+ BOOLEAN MemoryTypeInformationVariableExists;
+ EFI_BOOT_MODE BootMode;
+
+ MemoryTypeInformationModified = FALSE;
+ MemoryTypeInformationVariableExists = FALSE;
+
+
+ BootMode = GetBootModeHob ();
+ //
+ // In BOOT_IN_RECOVERY_MODE, Variable region is not reliable.
+ //
+ if (BootMode == BOOT_IN_RECOVERY_MODE) {
+ return;
+ }
+
+ //
+ // Only check the the Memory Type Information variable in the boot mode
+ // other than BOOT_WITH_DEFAULT_SETTINGS because the Memory Type
+ // Information is not valid in this boot mode.
+ //
+ if (BootMode != BOOT_WITH_DEFAULT_SETTINGS) {
+ VariableSize = 0;
+ Status = gRT->GetVariable (
+ EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
+ &gEfiMemoryTypeInformationGuid,
+ NULL,
+ &VariableSize,
+ NULL
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ MemoryTypeInformationVariableExists = TRUE;
+ }
+ }
+
+ //
+ // Retrieve the current memory usage statistics. If they are not found, then
+ // no adjustments can be made to the Memory Type Information variable.
+ //
+ Status = EfiGetSystemConfigurationTable (
+ &gEfiMemoryTypeInformationGuid,
+ (VOID **) &CurrentMemoryTypeInformation
+ );
+ if (EFI_ERROR (Status) || CurrentMemoryTypeInformation == NULL) {
+ return;
+ }
+
+ //
+ // Get the Memory Type Information settings from Hob if they exist,
+ // PEI is responsible for getting them from variable and build a Hob to save them.
+ // If the previous Memory Type Information is not available, then set defaults
+ //
+ GuidHob = GetFirstGuidHob (&gEfiMemoryTypeInformationGuid);
+ if (GuidHob == NULL) {
+ //
+ // If Platform has not built Memory Type Info into the Hob, just return.
+ //
+ return;
+ }
+ PreviousMemoryTypeInformation = GET_GUID_HOB_DATA (GuidHob);
+ VariableSize = GET_GUID_HOB_DATA_SIZE (GuidHob);
+
+ //
+ // Use a heuristic to adjust the Memory Type Information for the next boot
+ //
+ DEBUG ((EFI_D_INFO, "Memory Previous Current Next \n"));
+ DEBUG ((EFI_D_INFO, " Type Pages Pages Pages \n"));
+ DEBUG ((EFI_D_INFO, "====== ======== ======== ========\n"));
+
+ for (Index = 0; PreviousMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
+
+ for (Index1 = 0; CurrentMemoryTypeInformation[Index1].Type != EfiMaxMemoryType; Index1++) {
+ if (PreviousMemoryTypeInformation[Index].Type == CurrentMemoryTypeInformation[Index1].Type) {
+ break;
+ }
+ }
+ if (CurrentMemoryTypeInformation[Index1].Type == EfiMaxMemoryType) {
+ continue;
+ }
+
+ //
+ // Previous is the number of pages pre-allocated
+ // Current is the number of pages actually needed
+ //
+ Previous = PreviousMemoryTypeInformation[Index].NumberOfPages;
+ Current = CurrentMemoryTypeInformation[Index1].NumberOfPages;
+ Next = Previous;
+
+ //
+ // Inconsistent Memory Reserved across bootings may lead to S4 fail
+ // Write next varible to 125% * current when the pre-allocated memory is:
+ // 1. More than 150% of needed memory and boot mode is BOOT_WITH_DEFAULT_SETTING
+ // 2. Less than the needed memory
+ //
+ if ((Current + (Current >> 1)) < Previous) {
+ if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) {
+ Next = Current + (Current >> 2);
+ }
+ } else if (Current > Previous) {
+ Next = Current + (Current >> 2);
+ }
+ if (Next > 0 && Next < 4) {
+ Next = 4;
+ }
+
+ if (Next != Previous) {
+ PreviousMemoryTypeInformation[Index].NumberOfPages = Next;
+ MemoryTypeInformationModified = TRUE;
+ }
+
+ DEBUG ((EFI_D_INFO, " %02x %08x %08x %08x\n", PreviousMemoryTypeInformation[Index].Type, Previous, Current, Next));
+ }
+
+ //
+ // If any changes were made to the Memory Type Information settings, then set the new variable value;
+ // Or create the variable in first boot.
+ //
+ if (MemoryTypeInformationModified || !MemoryTypeInformationVariableExists) {
+ Status = SetVariableAndReportStatusCodeOnError (
+ EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
+ &gEfiMemoryTypeInformationGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ VariableSize,
+ PreviousMemoryTypeInformation
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // If the Memory Type Information settings have been modified, then reset the platform
+ // so the new Memory Type Information setting will be used to guarantee that an S4
+ // entry/resume cycle will not fail.
+ //
+ if (MemoryTypeInformationModified && PcdGetBool (PcdResetOnMemoryTypeInformationChange)) {
+ DEBUG ((EFI_D_INFO, "Memory Type Information settings change. Warm Reset!!!\n"));
+ gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
+ }
+ } else {
+ DEBUG ((EFI_D_ERROR, "Memory Type Information settings cannot be saved. OS S4 may fail!\n"));
+ }
+ }
+}
+
+/**
+ This routine is kept for backward compatibility.
+**/
+VOID
+EFIAPI
+BdsLibSaveMemoryTypeInformation (
+ VOID
+ )
+{
+}
+
+
+/**
+ Identify a user and, if authenticated, returns the current user profile handle.
+
+ @param[out] User Point to user profile handle.
+
+ @retval EFI_SUCCESS User is successfully identified, or user identification
+ is not supported.
+ @retval EFI_ACCESS_DENIED User is not successfully identified
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibUserIdentify (
+ OUT EFI_USER_PROFILE_HANDLE *User
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_MANAGER_PROTOCOL *Manager;
+
+ Status = gBS->LocateProtocol (
+ &gEfiUserManagerProtocolGuid,
+ NULL,
+ (VOID **) &Manager
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+
+ return Manager->Identify (Manager, User);
+}
+
+/**
+ Set the variable and report the error through status code upon failure.
+
+ @param VariableName A Null-terminated string that is the name of the vendor's variable.
+ Each VariableName is unique for each VendorGuid. VariableName must
+ contain 1 or more characters. If VariableName is an empty string,
+ then EFI_INVALID_PARAMETER is returned.
+ @param VendorGuid A unique identifier for the vendor.
+ @param Attributes Attributes bitmask to set for the variable.
+ @param DataSize The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE,
+ EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero
+ causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is
+ set, then a SetVariable() call with a DataSize of zero will not cause any change to
+ the variable value (the timestamp associated with the variable may be updated however
+ even if no new data value is provided,see the description of the
+ EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not
+ be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated).
+ @param Data The contents for the variable.
+
+ @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
+ defined by the Attributes.
+ @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, and GUID was supplied, or the
+ DataSize exceeds the maximum allowed.
+ @retval EFI_INVALID_PARAMETER VariableName is an empty string.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.
+ @retval EFI_WRITE_PROTECTED The variable in question is read-only.
+ @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.
+ @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
+ or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo
+ does NOT pass the validation check carried out by the firmware.
+
+ @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.
+**/
+EFI_STATUS
+SetVariableAndReportStatusCodeOnError (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ EFI_STATUS Status;
+ EDKII_SET_VARIABLE_STATUS *SetVariableStatus;
+ UINTN NameSize;
+
+ Status = gRT->SetVariable (
+ VariableName,
+ VendorGuid,
+ Attributes,
+ DataSize,
+ Data
+ );
+ if (EFI_ERROR (Status)) {
+ NameSize = StrSize (VariableName);
+ SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize);
+ if (SetVariableStatus != NULL) {
+ CopyGuid (&SetVariableStatus->Guid, VendorGuid);
+ SetVariableStatus->NameSize = NameSize;
+ SetVariableStatus->DataSize = DataSize;
+ SetVariableStatus->SetStatus = Status;
+ SetVariableStatus->Attributes = Attributes;
+ CopyMem (SetVariableStatus + 1, VariableName, NameSize);
+ if ((Data != NULL) && (DataSize != 0)) {
+ CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Data, DataSize);
+ }
+
+ REPORT_STATUS_CODE_EX (
+ EFI_ERROR_CODE,
+ PcdGet32 (PcdErrorCodeSetVariable),
+ 0,
+ NULL,
+ &gEdkiiStatusCodeDataTypeVariableGuid,
+ SetVariableStatus,
+ sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize
+ );
+
+ FreePool (SetVariableStatus);
+ }
+ }
+
+ return Status;
+}
+
diff --git a/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/DevicePath.c b/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/DevicePath.c
new file mode 100644
index 0000000000..2f22e7df7f
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/DevicePath.c
@@ -0,0 +1,33 @@
+/** @file
+ BDS internal function define the default device path string, it can be
+ replaced by platform device path.
+
+Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "InternalBdsLib.h"
+
+/**
+ This function converts an input device structure to a Unicode string.
+
+ @param DevPath A pointer to the device path structure.
+
+ @return A new allocated Unicode string that represents the device path.
+
+**/
+CHAR16 *
+EFIAPI
+DevicePathToStr (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevPath
+ )
+{
+ return ConvertDevicePathToText (DevPath, TRUE, TRUE);
+}
diff --git a/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/GenericBdsLib.inf b/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/GenericBdsLib.inf
new file mode 100644
index 0000000000..a4c1165e30
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/GenericBdsLib.inf
@@ -0,0 +1,144 @@
+## @file
+# General BDS library.
+#
+# General BDS defines and produce general interfaces for platform BDS driver including:
+# 1) BDS boot policy interface;
+# 2) BDS boot device connect interface;
+# 3) BDS Misc interfaces for mainting boot variable, ouput string, etc.
+#
+# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010018
+ BASE_NAME = GenericBdsLib
+ FILE_GUID = e405ec31-ccaa-4dd4-83e8-0aec01703f7e
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = GenericBdsLib|DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION
+ CONSTRUCTOR = GenericBdsLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ DevicePath.c
+ Performance.c
+ BdsConnect.c
+ BdsMisc.c
+ BdsConsole.c
+ BdsBoot.c
+ InternalBdsLib.h
+ String.h
+ String.c
+ GenericBdsStrings.uni
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+[LibraryClasses]
+ DevicePathLib
+ PeCoffGetEntryPointLib
+ BaseLib
+ HobLib
+ UefiRuntimeServicesTableLib
+ DxeServicesTableLib
+ MemoryAllocationLib
+ UefiLib
+ UefiBootServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ PrintLib
+ PcdLib
+ PerformanceLib
+ TimerLib
+ DxeServicesLib
+ HiiLib
+ ReportStatusCodeLib
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## HOB # The hob holding memory type information
+ ## SOMETIMES_CONSUMES ## SystemTable # The identifier of memory type information type in system table
+ ## SOMETIMES_CONSUMES ## Variable:L"MemoryTypeInformation"
+ ## SOMETIMES_PRODUCES ## Variable:L"MemoryTypeInformation"
+ gEfiMemoryTypeInformationGuid
+ ## SOMETIMES_CONSUMES ## Variable:L"BootXXXX" # Boot option variable
+ ## SOMETIMES_PRODUCES ## Variable:L"BootXXXX" # Boot option variable
+ ## SOMETIMES_CONSUMES ## Variable:L"DriverXXXX" # Driver load option.
+ ## SOMETIMES_PRODUCES ## Variable:L"DriverXXXX" # Driver load option.
+ ## SOMETIMES_CONSUMES ## Variable:L"BootNext" # Next Boot Option
+ ## SOMETIMES_PRODUCES ## Variable:L"BootNext" # Next Boot Option
+ ## SOMETIMES_CONSUMES ## Variable:L"BootOrder" # The boot option array
+ ## SOMETIMES_PRODUCES ## Variable:L"BootOrder" # The boot option array
+ ## SOMETIMES_CONSUMES ## Variable:L"DriverOrder" # The driver order list
+ ## SOMETIMES_CONSUMES ## Variable:L"ConIn" # The device path of console in device
+ ## SOMETIMES_PRODUCES ## Variable:L"ConIn" # The device path of console in device
+ ## SOMETIMES_CONSUMES ## Variable:L"ConOut" # The device path of console out device
+ ## SOMETIMES_PRODUCES ## Variable:L"ConOut" # The device path of console out device
+ ## SOMETIMES_CONSUMES ## Variable:L"ErrOut" # The device path of error out device
+ ## SOMETIMES_PRODUCES ## Variable:L"ErrOut" # The device path of error out device
+ ## SOMETIMES_PRODUCES ## Variable:L"BootCurrent" # The boot option of current boot
+ ## SOMETIMES_PRODUCES ## Variable:L"BootNext" # The number of next boot option
+ gEfiGlobalVariableGuid
+ gEfiFileInfoGuid ## SOMETIMES_CONSUMES ## GUID
+ gPerformanceProtocolGuid ## SOMETIMES_PRODUCES ## Variable:L"PerfDataMemAddr" # The ACPI address of performance data
+ gLastEnumLangGuid ## SOMETIMES_PRODUCES ## Variable:L"LastEnumLang" # Platform language at last time enumeration.
+ gHdBootDevicePathVariablGuid ## SOMETIMES_PRODUCES ## Variable:L"HDDP" # The device path of Boot file on Hard device.
+ gBdsLibStringPackageGuid ## CONSUMES ## HII # HII String PackageList Guid
+ ## SOMETIMES_PRODUCES ## Variable:L"LegacyDevOrder"
+ ## SOMETIMES_CONSUMES ## Variable:L"LegacyDevOrder"
+ gEfiLegacyDevOrderVariableGuid
+ gEdkiiStatusCodeDataTypeVariableGuid ## SOMETIMES_CONSUMES ## GUID
+
+[Protocols]
+ gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiLoadFileProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSimpleTextOutProtocolGuid ## CONSUMES
+ gEfiPciIoProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiLoadedImageProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSimpleNetworkProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDebugPortProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSimpleTextInProtocolGuid ## CONSUMES
+ gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiFirmwareVolume2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiLegacyBiosProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiCpuArchProtocolGuid ## CONSUMES
+ gEfiDevicePathProtocolGuid ## CONSUMES
+ gEfiGraphicsOutputProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiUgaDrawProtocolGuid |gEfiMdePkgTokenSpaceGuid.PcdUgaConsumeSupport ## SOMETIMES_CONSUMES
+ gEfiOEMBadgingProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiHiiFontProtocolGuid ## CONSUMES
+ gEfiUserManagerProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiUsbIoProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiBootLogoProtocolGuid ## SOMETIMES_CONSUMES
+
+[FeaturePcd]
+ gEfiMdePkgTokenSpaceGuid.PcdUgaConsumeSupport ## CONSUMES
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBootlogoOnlyEnable ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdProgressCodeOsLoaderLoad ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdProgressCodeOsLoaderStart ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdErrorCodeSetVariable ## CONSUMES
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdShellFile ## CONSUMES
+
+#
+# [BootMode]
+# RECOVERY_FULL ## SOMETIMES_CONSUMES # Memory Type Information variable
+#
+
diff --git a/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/GenericBdsStrings.uni b/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/GenericBdsStrings.uni
new file mode 100644
index 0000000000..568774b59a
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/GenericBdsStrings.uni
@@ -0,0 +1,36 @@
+///** @file
+//
+// String definitions for Boot Option description.
+//
+// Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+//**/
+
+/=#
+
+#langdef en-US "English"
+#langdef fr "Français"
+
+#string STR_DESCRIPTION_FLOPPY #language en-US "EFI Floppy"
+ #language fr "fr: EFI Floppy"
+#string STR_DESCRIPTION_CD_DVD #language en-US "EFI DVD/CDROM"
+ #language fr "fr: EFI DVD/CDROM"
+#string STR_DESCRIPTION_HARDDRIVE #language en-US "EFI Hard Drive"
+ #language fr "fr: EFI Hard Drive"
+#string STR_DESCRIPTION_USB #language en-US "EFI USB Device"
+ #language fr "fr: EFI USB Device"
+#string STR_DESCRIPTION_SCSI #language en-US "EFI SCSI Device"
+ #language fr "fr: EFI SCSI Device"
+#string STR_DESCRIPTION_MISC #language en-US "EFI Misc Device"
+ #language fr "fr: EFI Misc Device"
+#string STR_DESCRIPTION_NETWORK #language en-US "EFI Network"
+ #language fr "fr: EFI Network"
+#string STR_DESCRIPTION_NON_BLOCK #language en-US "EFI Non-Block Boot Device"
+ #language fr "fr: EFI Non-Block Boot Device"
diff --git a/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/InternalBdsLib.h b/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/InternalBdsLib.h
new file mode 100644
index 0000000000..4f2817a284
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/InternalBdsLib.h
@@ -0,0 +1,194 @@
+/** @file
+ BDS library definition, include the file and data structure
+
+Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _INTERNAL_BDS_LIB_H_
+#define _INTERNAL_BDS_LIB_H_
+
+#include <FrameworkDxe.h>
+
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/PeImage.h>
+
+#include <Protocol/BlockIo.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/Cpu.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/LoadFile.h>
+#include <Protocol/DebugPort.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/LegacyBios.h>
+#include <Protocol/SimpleTextOut.h>
+#include <Protocol/SimpleNetwork.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/OEMBadging.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/UgaDraw.h>
+#include <Protocol/HiiFont.h>
+#include <Protocol/HiiImage.h>
+#include <Protocol/UsbIo.h>
+#include <Protocol/BootLogo.h>
+
+#include <Guid/MemoryTypeInformation.h>
+#include <Guid/FileInfo.h>
+#include <Guid/GlobalVariable.h>
+#include <Guid/PcAnsi.h>
+#include <Guid/Performance.h>
+#include <Guid/BdsLibHii.h>
+#include <Guid/HdBootVariable.h>
+#include <Guid/LastEnumLang.h>
+#include <Guid/LegacyDevOrder.h>
+#include <Guid/StatusCodeDataTypeVariable.h>
+
+#include <Library/PrintLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/HobLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PerformanceLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/GenericBdsLib.h>
+#include <Library/TimerLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/ReportStatusCodeLib.h>
+
+#if !defined (EFI_REMOVABLE_MEDIA_FILE_NAME)
+ #if defined (MDE_CPU_EBC)
+ //
+ // Uefi specification only defines the default boot file name for IA32, X64
+ // and IPF processor, so need define boot file name for EBC architecture here.
+ //
+ #define EFI_REMOVABLE_MEDIA_FILE_NAME L"\\EFI\\BOOT\\BOOTEBC.EFI"
+ #else
+ #error "Can not determine the default boot file name for unknown processor type!"
+ #endif
+#endif
+
+/**
+
+ Writes performance data of booting into the allocated memory.
+ OS can process these records.
+
+ @param Event The triggered event.
+ @param Context Context for this event.
+
+**/
+VOID
+EFIAPI
+WriteBootToOsPerformanceData (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Get the headers (dos, image, optional header) from an image
+
+ @param Device SimpleFileSystem device handle
+ @param FileName File name for the image
+ @param DosHeader Pointer to dos header
+ @param Hdr The buffer in which to return the PE32, PE32+, or TE header.
+
+ @retval EFI_SUCCESS Successfully get the machine type.
+ @retval EFI_NOT_FOUND The file is not found.
+ @retval EFI_LOAD_ERROR File is not a valid image file.
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibGetImageHeader (
+ IN EFI_HANDLE Device,
+ IN CHAR16 *FileName,
+ OUT EFI_IMAGE_DOS_HEADER *DosHeader,
+ OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
+ );
+
+/**
+ This routine adjust the memory information for different memory type and
+ save them into the variables for next boot.
+**/
+VOID
+BdsSetMemoryTypeInformationVariable (
+ VOID
+ );
+
+/**
+ Validate the EFI Boot#### or Driver#### variable (VendorGuid/Name)
+
+ @param Variable Boot#### variable data.
+ @param VariableSize Returns the size of the EFI variable that was read
+
+ @retval TRUE The variable data is correct.
+ @retval FALSE The variable data is corrupted.
+
+**/
+BOOLEAN
+ValidateOption (
+ UINT8 *Variable,
+ UINTN VariableSize
+ );
+
+/**
+ Set the variable and report the error through status code upon failure.
+
+ @param VariableName A Null-terminated string that is the name of the vendor's variable.
+ Each VariableName is unique for each VendorGuid. VariableName must
+ contain 1 or more characters. If VariableName is an empty string,
+ then EFI_INVALID_PARAMETER is returned.
+ @param VendorGuid A unique identifier for the vendor.
+ @param Attributes Attributes bitmask to set for the variable.
+ @param DataSize The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE,
+ EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero
+ causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is
+ set, then a SetVariable() call with a DataSize of zero will not cause any change to
+ the variable value (the timestamp associated with the variable may be updated however
+ even if no new data value is provided,see the description of the
+ EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not
+ be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated).
+ @param Data The contents for the variable.
+
+ @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
+ defined by the Attributes.
+ @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, and GUID was supplied, or the
+ DataSize exceeds the maximum allowed.
+ @retval EFI_INVALID_PARAMETER VariableName is an empty string.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.
+ @retval EFI_WRITE_PROTECTED The variable in question is read-only.
+ @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.
+ @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
+ or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo
+ does NOT pass the validation check carried out by the firmware.
+
+ @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.
+**/
+EFI_STATUS
+SetVariableAndReportStatusCodeOnError (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ );
+
+#endif // _BDS_LIB_H_
diff --git a/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/Performance.c b/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/Performance.c
new file mode 100644
index 0000000000..9786fc7e24
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/Performance.c
@@ -0,0 +1,358 @@
+/** @file
+ This file include the file which can help to get the system
+ performance, all the function will only include if the performance
+ switch is set.
+
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "InternalBdsLib.h"
+
+PERF_HEADER mPerfHeader;
+PERF_DATA mPerfData;
+EFI_PHYSICAL_ADDRESS mAcpiLowMemoryBase = 0x0FFFFFFFFULL;
+
+/**
+ Get the short verion of PDB file name to be
+ used in performance data logging.
+
+ @param PdbFileName The long PDB file name.
+ @param GaugeString The output string to be logged by performance logger.
+
+**/
+VOID
+GetShortPdbFileName (
+ IN CONST CHAR8 *PdbFileName,
+ OUT CHAR8 *GaugeString
+ )
+{
+ UINTN Index;
+ UINTN Index1;
+ UINTN StartIndex;
+ UINTN EndIndex;
+
+ if (PdbFileName == NULL) {
+ AsciiStrCpyS (GaugeString, PERF_TOKEN_SIZE, " ");
+ } else {
+ StartIndex = 0;
+ for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++)
+ ;
+
+ for (Index = 0; PdbFileName[Index] != 0; Index++) {
+ if (PdbFileName[Index] == '\\') {
+ StartIndex = Index + 1;
+ }
+
+ if (PdbFileName[Index] == '.') {
+ EndIndex = Index;
+ }
+ }
+
+ Index1 = 0;
+ for (Index = StartIndex; Index < EndIndex; Index++) {
+ GaugeString[Index1] = PdbFileName[Index];
+ Index1++;
+ if (Index1 == PERF_TOKEN_LENGTH) {
+ break;
+ }
+ }
+
+ GaugeString[Index1] = 0;
+ }
+
+ return ;
+}
+
+/**
+ Get the name from the Driver handle, which can be a handle with
+ EFI_LOADED_IMAGE_PROTOCOL or EFI_DRIVER_BINDING_PROTOCOL installed.
+ This name can be used in performance data logging.
+
+ @param Handle Driver handle.
+ @param GaugeString The output string to be logged by performance logger.
+
+**/
+VOID
+GetNameFromHandle (
+ IN EFI_HANDLE Handle,
+ OUT CHAR8 *GaugeString
+ )
+{
+ EFI_STATUS Status;
+ EFI_LOADED_IMAGE_PROTOCOL *Image;
+ CHAR8 *PdbFileName;
+ EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
+
+ AsciiStrCpyS (GaugeString, PERF_TOKEN_SIZE, " ");
+
+ //
+ // Get handle name from image protocol
+ //
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **) &Image
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiDriverBindingProtocolGuid,
+ (VOID **) &DriverBinding,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+ //
+ // Get handle name from image protocol
+ //
+ Status = gBS->HandleProtocol (
+ DriverBinding->ImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **) &Image
+ );
+ }
+
+ PdbFileName = PeCoffLoaderGetPdbPointer (Image->ImageBase);
+
+ if (PdbFileName != NULL) {
+ GetShortPdbFileName (PdbFileName, GaugeString);
+ }
+
+ return ;
+}
+
+/**
+
+ Writes performance data of booting into the allocated memory.
+ OS can process these records.
+
+ @param Event The triggered event.
+ @param Context Context for this event.
+
+**/
+VOID
+EFIAPI
+WriteBootToOsPerformanceData (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ UINT32 LimitCount;
+ EFI_HANDLE *Handles;
+ UINTN NoHandles;
+ CHAR8 GaugeString[PERF_TOKEN_SIZE];
+ UINT8 *Ptr;
+ UINT32 Index;
+ UINT64 Ticker;
+ UINT64 Freq;
+ UINT32 Duration;
+ UINTN LogEntryKey;
+ CONST VOID *Handle;
+ CONST CHAR8 *Token;
+ CONST CHAR8 *Module;
+ UINT64 StartTicker;
+ UINT64 EndTicker;
+ UINT64 StartValue;
+ UINT64 EndValue;
+ BOOLEAN CountUp;
+ UINTN EntryIndex;
+ UINTN NumPerfEntries;
+ //
+ // List of flags indicating PerfEntry contains DXE handle
+ //
+ BOOLEAN *PerfEntriesAsDxeHandle;
+ UINTN VarSize;
+
+ //
+ // Record the performance data for End of BDS
+ //
+ PERF_END(NULL, "BDS", NULL, 0);
+
+ //
+ // Retrieve time stamp count as early as possible
+ //
+ Ticker = GetPerformanceCounter ();
+
+ Freq = GetPerformanceCounterProperties (&StartValue, &EndValue);
+
+ Freq = DivU64x32 (Freq, 1000);
+
+ mPerfHeader.CpuFreq = Freq;
+
+ //
+ // Record BDS raw performance data
+ //
+ if (EndValue >= StartValue) {
+ mPerfHeader.BDSRaw = Ticker - StartValue;
+ CountUp = TRUE;
+ } else {
+ mPerfHeader.BDSRaw = StartValue - Ticker;
+ CountUp = FALSE;
+ }
+
+ if (mAcpiLowMemoryBase == 0x0FFFFFFFF) {
+ VarSize = sizeof (EFI_PHYSICAL_ADDRESS);
+ Status = gRT->GetVariable (
+ L"PerfDataMemAddr",
+ &gPerformanceProtocolGuid,
+ NULL,
+ &VarSize,
+ &mAcpiLowMemoryBase
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Fail to get the variable, return.
+ //
+ return;
+ }
+ }
+
+ //
+ // Put Detailed performance data into memory
+ //
+ Handles = NULL;
+ Status = gBS->LocateHandleBuffer (
+ AllHandles,
+ NULL,
+ NULL,
+ &NoHandles,
+ &Handles
+ );
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ Ptr = (UINT8 *) ((UINT32) mAcpiLowMemoryBase + sizeof (PERF_HEADER));
+ LimitCount = (UINT32) (PERF_DATA_MAX_LENGTH - sizeof (PERF_HEADER)) / sizeof (PERF_DATA);
+
+ NumPerfEntries = 0;
+ LogEntryKey = 0;
+ while ((LogEntryKey = GetPerformanceMeasurement (
+ LogEntryKey,
+ &Handle,
+ &Token,
+ &Module,
+ &StartTicker,
+ &EndTicker)) != 0) {
+ NumPerfEntries++;
+ }
+ PerfEntriesAsDxeHandle = AllocateZeroPool (NumPerfEntries * sizeof (BOOLEAN));
+ ASSERT (PerfEntriesAsDxeHandle != NULL);
+
+ //
+ // Get DXE drivers performance
+ //
+ for (Index = 0; Index < NoHandles; Index++) {
+ Ticker = 0;
+ LogEntryKey = 0;
+ EntryIndex = 0;
+ while ((LogEntryKey = GetPerformanceMeasurement (
+ LogEntryKey,
+ &Handle,
+ &Token,
+ &Module,
+ &StartTicker,
+ &EndTicker)) != 0) {
+ if (Handle == Handles[Index] && !PerfEntriesAsDxeHandle[EntryIndex]) {
+ PerfEntriesAsDxeHandle[EntryIndex] = TRUE;
+ }
+ EntryIndex++;
+ if ((Handle == Handles[Index]) && (EndTicker != 0)) {
+ if (StartTicker == 1) {
+ StartTicker = StartValue;
+ }
+ if (EndTicker == 1) {
+ EndTicker = StartValue;
+ }
+ Ticker += CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker);
+ }
+ }
+
+ Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq);
+
+ if (Duration > 0) {
+
+ GetNameFromHandle (Handles[Index], GaugeString);
+
+ AsciiStrCpyS (mPerfData.Token, PERF_TOKEN_SIZE, GaugeString);
+ mPerfData.Duration = Duration;
+
+ CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA));
+ Ptr += sizeof (PERF_DATA);
+
+ mPerfHeader.Count++;
+ if (mPerfHeader.Count == LimitCount) {
+ goto Done;
+ }
+ }
+ }
+
+ //
+ // Get inserted performance data
+ //
+ LogEntryKey = 0;
+ EntryIndex = 0;
+ while ((LogEntryKey = GetPerformanceMeasurement (
+ LogEntryKey,
+ &Handle,
+ &Token,
+ &Module,
+ &StartTicker,
+ &EndTicker)) != 0) {
+ if (!PerfEntriesAsDxeHandle[EntryIndex] && EndTicker != 0) {
+
+ ZeroMem (&mPerfData, sizeof (PERF_DATA));
+
+ AsciiStrnCpyS (mPerfData.Token, PERF_TOKEN_SIZE, Token, PERF_TOKEN_LENGTH);
+ if (StartTicker == 1) {
+ StartTicker = StartValue;
+ }
+ if (EndTicker == 1) {
+ EndTicker = StartValue;
+ }
+ Ticker = CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker);
+
+ mPerfData.Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq);
+
+ CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA));
+ Ptr += sizeof (PERF_DATA);
+
+ mPerfHeader.Count++;
+ if (mPerfHeader.Count == LimitCount) {
+ goto Done;
+ }
+ }
+ EntryIndex++;
+ }
+
+Done:
+
+ FreePool (Handles);
+ FreePool (PerfEntriesAsDxeHandle);
+
+ mPerfHeader.Signiture = PERFORMANCE_SIGNATURE;
+
+ //
+ // Put performance data to Reserved memory
+ //
+ CopyMem (
+ (UINTN *) (UINTN) mAcpiLowMemoryBase,
+ &mPerfHeader,
+ sizeof (PERF_HEADER)
+ );
+
+ return ;
+}
diff --git a/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/String.c b/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/String.c
new file mode 100644
index 0000000000..762871605d
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/String.c
@@ -0,0 +1,32 @@
+/** @file
+ String support
+
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include "String.h"
+
+/**
+ Get string by string id from HII Interface
+
+
+ @param Id String ID.
+
+ @retval CHAR16 * String from ID.
+ @retval NULL If error occurs.
+
+**/
+CHAR16 *
+BdsLibGetStringById (
+ IN EFI_STRING_ID Id
+ )
+{
+ return HiiGetString (gBdsLibStringPackHandle, Id, NULL);
+}
diff --git a/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/String.h b/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/String.h
new file mode 100644
index 0000000000..13b745de87
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/String.h
@@ -0,0 +1,48 @@
+/** @file
+ String support
+
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _STRING_H_
+#define _STRING_H_
+
+#include <Library/HiiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+extern EFI_HII_HANDLE gBdsLibStringPackHandle;
+
+//
+// This is the VFR compiler generated header file which defines the
+// string identifiers.
+//
+
+extern UINT8 GenericBdsLibStrings[];
+
+/**
+ Get string by string id from HII Interface
+
+
+ @param Id String ID.
+
+ @retval CHAR16 * String from ID.
+ @retval NULL If error occurs.
+
+**/
+CHAR16 *
+BdsLibGetStringById (
+ IN EFI_STRING_ID Id
+ );
+
+#endif // _STRING_H_