diff options
author | qwang12 <qwang12@6f19259b-4bc3-4df7-8a09-765794883524> | 2008-01-21 14:39:56 +0000 |
---|---|---|
committer | qwang12 <qwang12@6f19259b-4bc3-4df7-8a09-765794883524> | 2008-01-21 14:39:56 +0000 |
commit | 93e3992d1ea50fb30c48f498d257d4e66252dd9b (patch) | |
tree | b76adcd31d2017cd76317f21be967ad3cb05305e | |
parent | f79314fa8f44a79e862d2877e5a9b1a3a9f96791 (diff) | |
download | edk2-93e3992d1ea50fb30c48f498d257d4e66252dd9b.tar.gz edk2-93e3992d1ea50fb30c48f498d257d4e66252dd9b.tar.bz2 edk2-93e3992d1ea50fb30c48f498d257d4e66252dd9b.zip |
UEFI HII: Merge UEFI HII support changes from branch.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@4599 6f19259b-4bc3-4df7-8a09-765794883524
139 files changed, 59160 insertions, 380 deletions
diff --git a/MdeModulePkg/Core/Dxe/DxeMain.inf b/MdeModulePkg/Core/Dxe/DxeMain.inf index 9257fbaed4..a6b6df2b86 100644 --- a/MdeModulePkg/Core/Dxe/DxeMain.inf +++ b/MdeModulePkg/Core/Dxe/DxeMain.inf @@ -140,4 +140,5 @@ gEfiMdePkgTokenSpaceGuid.PcdStatusCodeValueDxeCoreHandoffToBds | 0x3041001 # EFI_SOFTWARE_DXE_CORE | EFI_SW_DXE_CORE_PC_HANDOFF_TO_NEXT
gEfiMdePkgTokenSpaceGuid.PcdStatusCodeValueBootServiceExit | 0x3100019 # EFI_SOFTWARE_EFI_BOOT_SERVICE | EFI_SW_BS_PC_EXIT_BOOT_SERVICES
gEfiMdePkgTokenSpaceGuid.PcdStatusCodeValueDxeDriverBegin | 0x3040002 # EFI_SOFTWARE_DXE_CORE | EFI_SW_PC_INIT_BEGIN
- gEfiMdePkgTokenSpaceGuid.PcdStatusCodeValueDxeDriverEnd | 0x3040003 # EFI_SOFTWARE_DXE_CORE | EFI_SW_PC_INIT_END
\ No newline at end of file + gEfiMdePkgTokenSpaceGuid.PcdStatusCodeValueDxeDriverEnd | 0x3040003 # EFI_SOFTWARE_DXE_CORE | EFI_SW_PC_INIT_END
+
diff --git a/MdeModulePkg/Include/Library/GenericBdsLib.h b/MdeModulePkg/Include/Library/GenericBdsLib.h new file mode 100644 index 0000000000..9266a86bfe --- /dev/null +++ b/MdeModulePkg/Include/Library/GenericBdsLib.h @@ -0,0 +1,565 @@ +/*++
+
+Copyright (c) 2004 - 2007, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ GenericBdsLib.h
+
+Abstract:
+
+ Generic BDS library definition, include the file and data structure
+
+--*/
+
+#ifndef _GENERIC_BDS_LIB_H_
+#define _GENERIC_BDS_LIB_H_
+
+//
+// WQBugBug: These Macro will be handled properly later.
+//
+//#undef EFI_SPECIFICATION_VERSION
+//#define EFI_SPECIFICATION_VERSION 0x0002000A
+
+#define PI_SPECIFICATION_VERSION 0x00010000
+
+#include <PiDxe.h>
+#include <Protocol/HiiDatabase.h>
+#include <IndustryStandard/PeImage.h>
+
+
+extern EFI_HANDLE mBdsImageHandle;
+
+//
+// Constants which are variable names used to access variables
+//
+#define VarLegacyDevOrder L"LegacyDevOrder"
+
+//
+// Data structures and defines
+//
+#define FRONT_PAGE_QUESTION_ID 0x0000
+#define FRONT_PAGE_DATA_WIDTH 0x01
+
+//
+// ConnectType
+//
+#define CONSOLE_OUT 0x00000001
+#define STD_ERROR 0x00000002
+#define CONSOLE_IN 0x00000004
+#define CONSOLE_ALL (CONSOLE_OUT | CONSOLE_IN | STD_ERROR)
+
+//
+// Load Option Attributes defined in EFI Specification
+//
+#define LOAD_OPTION_ACTIVE 0x00000001
+#define LOAD_OPTION_FORCE_RECONNECT 0x00000002
+
+#if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
+#define LOAD_OPTION_HIDDEN 0x00000008
+#define LOAD_OPTION_CATEGORY 0x00001F00
+
+#define LOAD_OPTION_CATEGORY_BOOT 0x00000000
+#define LOAD_OPTION_CATEGORY_APP 0x00000100
+
+#define EFI_BOOT_OPTION_SUPPORT_KEY 0x00000001
+#define EFI_BOOT_OPTION_SUPPORT_APP 0x00000002
+#endif
+
+#define IS_LOAD_OPTION_TYPE(_c, _Mask) (BOOLEAN) (((_c) & (_Mask)) != 0)
+
+//
+// Define Maxmim characters that will be accepted
+//
+#define MAX_CHAR 480
+#define MAX_CHAR_SIZE (MAX_CHAR * 2)
+
+#define MIN_ALIGNMENT_SIZE 4
+#define ALIGN_SIZE(a) ((a % MIN_ALIGNMENT_SIZE) ? MIN_ALIGNMENT_SIZE - (a % MIN_ALIGNMENT_SIZE) : 0)
+
+//
+// Define maximum characters for boot option variable "BootXXXX"
+//
+#define BOOT_OPTION_MAX_CHAR 10
+
+//
+// This data structure is the part of BDS_CONNECT_ENTRY that we can hard code.
+//
+#define BDS_LOAD_OPTION_SIGNATURE EFI_SIGNATURE_32 ('B', 'd', 'C', 'O')
+
+typedef struct {
+
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ CHAR16 *OptionName;
+ UINTN OptionNumber;
+ UINT16 BootCurrent;
+ UINT32 Attribute;
+ CHAR16 *Description;
+ VOID *LoadOptions;
+ UINT32 LoadOptionsSize;
+ CHAR16 *StatusString;
+
+} BDS_COMMON_OPTION;
+
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINTN ConnectType;
+} BDS_CONSOLE_CONNECT_ENTRY;
+
+//
+// Lib Functions
+//
+
+//
+// Bds boot relate lib functions
+//
+EFI_STATUS
+BdsLibUpdateBootOrderList (
+ IN LIST_ENTRY *BdsOptionList,
+ IN CHAR16 *VariableName
+ );
+
+VOID
+BdsLibBootNext (
+ VOID
+ );
+
+EFI_STATUS
+BdsLibBootViaBootOption (
+ IN BDS_COMMON_OPTION * Option,
+ IN EFI_DEVICE_PATH_PROTOCOL * DevicePath,
+ OUT UINTN *ExitDataSize,
+ OUT CHAR16 **ExitData OPTIONAL
+ );
+
+EFI_STATUS
+BdsLibEnumerateAllBootOption (
+ IN OUT LIST_ENTRY *BdsBootOptionList
+ );
+
+VOID
+BdsLibBuildOptionFromHandle (
+ IN EFI_HANDLE Handle,
+ IN LIST_ENTRY *BdsBootOptionList,
+ IN CHAR16 *String
+ );
+
+VOID
+BdsLibBuildOptionFromShell (
+ IN EFI_HANDLE Handle,
+ IN LIST_ENTRY *BdsBootOptionList
+ );
+
+//
+// Bds misc lib functions
+//
+UINT16
+BdsLibGetTimeout (
+ VOID
+ );
+
+EFI_STATUS
+BdsLibGetBootMode (
+ OUT EFI_BOOT_MODE *BootMode
+ );
+
+VOID
+BdsLibLoadDrivers (
+ IN LIST_ENTRY *BdsDriverLists
+ );
+
+EFI_STATUS
+BdsLibBuildOptionFromVar (
+ IN LIST_ENTRY *BdsCommonOptionList,
+ IN CHAR16 *VariableName
+ );
+
+VOID *
+BdsLibGetVariableAndSize (
+ IN CHAR16 *Name,
+ IN EFI_GUID *VendorGuid,
+ OUT UINTN *VariableSize
+ );
+
+EFI_STATUS
+BdsLibOutputStrings (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut,
+ ...
+ );
+
+BDS_COMMON_OPTION *
+BdsLibVariableToOption (
+ IN OUT LIST_ENTRY *BdsCommonOptionList,
+ IN CHAR16 *VariableName
+ );
+
+EFI_STATUS
+BdsLibRegisterNewOption (
+ IN LIST_ENTRY *BdsOptionList,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN CHAR16 *String,
+ IN CHAR16 *VariableName
+ );
+
+//
+// Bds connect or disconnect driver lib funcion
+//
+VOID
+BdsLibConnectAllDriversToAllControllers (
+ VOID
+ );
+
+VOID
+BdsLibConnectAll (
+ VOID
+ );
+
+EFI_STATUS
+BdsLibConnectDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePathToConnect
+ );
+
+EFI_STATUS
+BdsLibConnectAllEfi (
+ VOID
+ );
+
+EFI_STATUS
+BdsLibDisconnectAllEfi (
+ VOID
+ );
+
+//
+// Bds console relate lib functions
+//
+VOID
+BdsLibConnectAllConsoles (
+ VOID
+ );
+
+EFI_STATUS
+BdsLibConnectAllDefaultConsoles (
+ VOID
+ );
+
+EFI_STATUS
+BdsLibUpdateConsoleVariable (
+ IN CHAR16 *ConVarName,
+ IN EFI_DEVICE_PATH_PROTOCOL *CustomizedConDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *ExclusiveDevicePath
+ );
+
+EFI_STATUS
+BdsLibConnectConsoleVariable (
+ IN CHAR16 *ConVarName
+ );
+
+//
+// Bds device path relate lib functions
+//
+EFI_DEVICE_PATH_PROTOCOL *
+BdsLibUnpackDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevPath
+ );
+
+EFI_DEVICE_PATH_PROTOCOL *
+BdsLibDelPartMatchInstance (
+ IN EFI_DEVICE_PATH_PROTOCOL *Multi,
+ IN EFI_DEVICE_PATH_PROTOCOL *Single
+ );
+
+BOOLEAN
+BdsLibMatchDevicePaths (
+ IN EFI_DEVICE_PATH_PROTOCOL *Multi,
+ IN EFI_DEVICE_PATH_PROTOCOL *Single
+ );
+
+CHAR16 *
+DevicePathToStr (
+ EFI_DEVICE_PATH_PROTOCOL *DevPath
+ );
+
+VOID *
+EfiLibGetVariable (
+ IN CHAR16 *Name,
+ IN EFI_GUID *VendorGuid
+ );
+
+//
+// Internal definitions
+//
+typedef struct {
+ CHAR16 *str;
+ UINTN len;
+ UINTN maxlen;
+} POOL_PRINT;
+
+typedef struct {
+ UINT8 Type;
+ UINT8 SubType;
+ VOID (*Function) (POOL_PRINT *, VOID *);
+} DEVICE_PATH_STRING_TABLE;
+
+extern EFI_GUID mEfiDevicePathMessagingUartFlowControlGuid;
+
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ EFI_GUID Guid;
+ UINT8 VendorDefinedData[1];
+} VENDOR_DEVICE_PATH_WITH_DATA;
+
+#if (EFI_SPECIFICATION_VERSION >= 0x00020000)
+
+extern EFI_GUID mEfiDevicePathMessagingSASGuid;
+
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT16 NetworkProtocol;
+ UINT16 LoginOption;
+ UINT64 Lun;
+ UINT16 TargetPortalGroupTag;
+ CHAR16 iSCSITargetName[1];
+} ISCSI_DEVICE_PATH_WITH_NAME;
+
+#endif
+
+//
+// Internal functions
+//
+EFI_STATUS
+BdsBootByDiskSignatureAndPartition (
+ IN BDS_COMMON_OPTION * Option,
+ IN HARDDRIVE_DEVICE_PATH * HardDriveDevicePath,
+ IN UINT32 LoadOptionsSize,
+ IN VOID *LoadOptions,
+ OUT UINTN *ExitDataSize,
+ OUT CHAR16 **ExitData OPTIONAL
+ );
+
+//
+// Notes: EFI 64 shadow all option rom
+//
+#if defined (MDE_CPU_IPF)
+#define EFI64_SHADOW_ALL_LEGACY_ROM() ShadowAllOptionRom ();
+VOID
+ShadowAllOptionRom();
+#else
+#define EFI64_SHADOW_ALL_LEGACY_ROM()
+#endif
+
+//
+// BBS support macros and functions
+//
+
+#if defined(MDE_CPU_IA32) || defined(MDE_CPU_X64)
+#define REFRESH_LEGACY_BOOT_OPTIONS \
+ BdsDeleteAllInvalidLegacyBootOptions ();\
+ BdsAddNonExistingLegacyBootOptions (); \
+ BdsUpdateLegacyDevOrder ()
+#else
+#define REFRESH_LEGACY_BOOT_OPTIONS
+#endif
+
+EFI_STATUS
+BdsDeleteAllInvalidLegacyBootOptions (
+ VOID
+ );
+
+EFI_STATUS
+BdsAddNonExistingLegacyBootOptions (
+ VOID
+ );
+
+EFI_STATUS
+BdsUpdateLegacyDevOrder (
+ VOID
+ );
+
+EFI_STATUS
+BdsRefreshBbsTableForBoot (
+ IN BDS_COMMON_OPTION *Entry
+ );
+
+EFI_STATUS
+BdsDeleteBootOption (
+ IN UINTN OptionNumber,
+ IN OUT UINT16 *BootOrder,
+ IN OUT UINTN *BootOrderSize
+ );
+
+//
+//The interface functions relate with Setup Browser Reset Reminder feature
+//
+VOID
+EnableResetReminderFeature (
+ VOID
+ );
+
+VOID
+DisableResetReminderFeature (
+ VOID
+ );
+
+VOID
+EnableResetRequired (
+ VOID
+ );
+
+VOID
+DisableResetRequired (
+ VOID
+ );
+
+BOOLEAN
+IsResetReminderFeatureEnable (
+ VOID
+ );
+
+BOOLEAN
+IsResetRequired (
+ VOID
+ );
+
+VOID
+SetupResetReminder (
+ VOID
+ );
+
+EFI_STATUS
+BdsLibGetImageHeader (
+ IN EFI_HANDLE Device,
+ IN CHAR16 *FileName,
+ OUT EFI_IMAGE_DOS_HEADER *DosHeader,
+ OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
+ )
+;
+
+EFI_STATUS
+BdsLibGetHiiHandles (
+#if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
+ IN EFI_HII_DATABASE_PROTOCOL *HiiDatabase,
+#else
+ IN EFI_HII_PROTOCOL *Hii,
+#endif
+ IN OUT UINT16 *HandleBufferLength,
+ OUT EFI_HII_HANDLE **HiiHandleBuffer
+ );
+
+//
+// Define the boot type which to classify the boot option type
+// Different boot option type could have different boot behavior
+// Use their device path node (Type + SubType) as type value
+// The boot type here can be added according to requirement
+//
+//
+// ACPI boot type. For ACPI device, cannot use sub-type to distinguish device, so hardcode their value
+//
+#define BDS_EFI_ACPI_FLOPPY_BOOT 0x0201
+//
+// Message boot type
+// If a device path of boot option only point to a message node, the boot option is message boot type
+//
+#define BDS_EFI_MESSAGE_ATAPI_BOOT 0x0301 // Type 03; Sub-Type 01
+#define BDS_EFI_MESSAGE_SCSI_BOOT 0x0302 // Type 03; Sub-Type 02
+#define BDS_EFI_MESSAGE_USB_DEVICE_BOOT 0x0305 // Type 03; Sub-Type 05
+#define BDS_EFI_MESSAGE_MISC_BOOT 0x03FF
+//
+// Media boot type
+// If a device path of boot option contain a media node, the boot option is media boot type
+//
+#define BDS_EFI_MEDIA_HD_BOOT 0x0401 // Type 04; Sub-Type 01
+#define BDS_EFI_MEDIA_CDROM_BOOT 0x0402 // Type 04; Sub-Type 02
+//
+// BBS boot type
+// If a device path of boot option contain a BBS node, the boot option is BBS boot type
+//
+#define BDS_LEGACY_BBS_BOOT 0x0501 // Type 05; Sub-Type 01
+
+#define BDS_EFI_UNSUPPORT 0xFFFF
+
+//
+// USB host controller Programming Interface.
+//
+#define PCI_CLASSC_PI_UHCI 0x00
+#define PCI_CLASSC_PI_EHCI 0x20
+
+BOOLEAN
+MatchPartitionDevicePathNode (
+ IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath,
+ IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
+ );
+
+EFI_DEVICE_PATH_PROTOCOL *
+BdsExpandPartitionPartialDevicePathToFull (
+ IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
+ );
+
+EFI_HANDLE
+BdsLibGetBootableHandle (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+BOOLEAN
+BdsLibIsValidEFIBootOptDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevPath,
+ IN BOOLEAN CheckMedia
+ );
+
+UINT32
+BdsGetBootTypeFromDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+VOID
+EFIAPI
+BdsLibSaveMemoryTypeInformation (
+ VOID
+ );
+
+EFI_STATUS
+EFIAPI
+BdsLibUpdateFvFileDevicePath (
+ IN OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath,
+ IN EFI_GUID *FileGuid
+ );
+
+EFI_STATUS
+BdsLibConnectUsbDevByShortFormDP (
+ IN CHAR8 HostControllerPI,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+EFI_TPL
+BdsLibGetCurrentTpl (
+ VOID
+ );
+
+//
+// The implementation of this function is provided by Platform code.
+//
+VOID
+DevPathVendor (
+ IN OUT POOL_PRINT *Str,
+ IN VOID *DevPath
+ )
+;
+
+CHAR16 *
+CatPrint (
+ IN OUT POOL_PRINT *Str,
+ IN CHAR16 *fmt,
+ ...
+ )
+;
+#endif // _BDS_LIB_H_
diff --git a/MdeModulePkg/Include/Library/PlatformBdsLib.h b/MdeModulePkg/Include/Library/PlatformBdsLib.h new file mode 100644 index 0000000000..cc118242e2 --- /dev/null +++ b/MdeModulePkg/Include/Library/PlatformBdsLib.h @@ -0,0 +1,98 @@ +/*++
+
+Copyright (c) 2008, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ PlatformBdsLib.h
+
+Abstract:
+
+ Platform BDS library definition, include the file and data structure
+
+--*/
+
+#ifndef __PLATFORM_BDS_LIB_H_
+#define __PLATFORM_BDS_LIB_H_
+
+#include <PiDxe.h>
+#include <Protocol/Bds.h>
+#include <Protocol/GenericMemoryTest.h>
+
+//
+// Bds AP Context data
+//
+#define EFI_BDS_ARCH_PROTOCOL_INSTANCE_SIGNATURE EFI_SIGNATURE_32 ('B', 'd', 's', 'A')
+typedef struct _EFI_BDS_ARCH_PROTOCOL_INSTANCE EFI_BDS_ARCH_PROTOCOL_INSTANCE;
+
+struct _EFI_BDS_ARCH_PROTOCOL_INSTANCE {
+ UINTN Signature;
+ EFI_HANDLE Handle;
+ EFI_BDS_ARCH_PROTOCOL Bds;
+ //
+ // Save the current boot mode
+ //
+ EFI_BOOT_MODE BootMode;
+ //
+ // Set true if boot with default settings
+ //
+ BOOLEAN DefaultBoot;
+ //
+ // The system default timeout for choose the boot option
+ //
+ UINT16 TimeoutDefault;
+ //
+ // Memory Test Level
+ //
+ EXTENDMEM_COVERAGE_LEVEL MemoryTestLevel;
+};
+
+//
+// Platform BDS Functions
+//
+VOID
+EFIAPI
+PlatformBdsInit (
+ IN EFI_BDS_ARCH_PROTOCOL_INSTANCE *PrivateData
+ )
+;
+
+VOID
+EFIAPI
+PlatformBdsPolicyBehavior (
+ IN EFI_BDS_ARCH_PROTOCOL_INSTANCE *PrivateData,
+ IN LIST_ENTRY *DriverOptionList,
+ IN LIST_ENTRY *BootOptionList
+ )
+;
+
+
+VOID
+PlatformBdsBootFail (
+ IN BDS_COMMON_OPTION *Option,
+ IN EFI_STATUS Status,
+ IN CHAR16 *ExitData,
+ IN UINTN ExitDataSize
+ )
+;
+
+VOID
+PlatformBdsBootSuccess (
+ IN BDS_COMMON_OPTION *Option
+ )
+;
+
+EFI_STATUS
+EFIAPI
+PlatformBdsLockNonUpdatableFlash (
+ VOID
+ )
+;
+#endif
diff --git a/MdeModulePkg/Include/MdeModuleHii.h b/MdeModulePkg/Include/MdeModuleHii.h new file mode 100644 index 0000000000..7f99ccd47b --- /dev/null +++ b/MdeModulePkg/Include/MdeModuleHii.h @@ -0,0 +1,125 @@ +/* @file
+
+ EDK II specific HII relative definition.
+
+Copyright (c) 2006 - 2007, Intel Corporation
+All rights reserved. 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 _MDEMODULE_HII_H
+#define _MDEMODULE_HII_H
+
+#define NARROW_CHAR 0xFFF0
+#define WIDE_CHAR 0xFFF1
+#define NON_BREAKING_CHAR 0xFFF2
+
+#define GLYPH_WIDTH EFI_GLYPH_WIDTH
+#define GLYPH_HEIGHT EFI_GLYPH_HEIGHT
+
+//
+// State defined for password statemachine
+//
+#define BROWSER_STATE_VALIDATE_PASSWORD 0
+#define BROWSER_STATE_SET_PASSWORD 1
+
+
+//
+// Tiano Implementation specific Device Path definition.
+//
+typedef struct {
+ VENDOR_DEVICE_PATH VendorDevicePath;
+ UINT32 MonotonicCount;
+} HII_VENDOR_DEVICE_PATH_NODE;
+
+typedef struct {
+ HII_VENDOR_DEVICE_PATH_NODE Node;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} HII_VENDOR_DEVICE_PATH;
+
+
+//
+// References to string tokens must use this macro to enable scanning for
+// token usages.
+//
+#define STRING_TOKEN(t) t
+
+//
+// GUIDed opcodes defined for Tiano
+//
+#define EFI_IFR_TIANO_GUID \
+ { 0xf0b1735, 0x87a0, 0x4193, {0xb2, 0x66, 0x53, 0x8c, 0x38, 0xaf, 0x48, 0xce} }
+
+
+#pragma pack(1)
+
+#define EFI_IFR_EXTEND_OP_LABEL 0x0
+#define EFI_IFR_EXTEND_OP_BANNER 0x1
+#define EFI_IFR_EXTEND_OP_TIMEOUT 0x2
+#define EFI_IFR_EXTEND_OP_CLASS 0x3
+#define EFI_IFR_EXTEND_OP_SUBCLASS 0x4
+
+typedef struct _EFI_IFR_GUID_LABEL {
+ EFI_IFR_OP_HEADER Header;
+ EFI_GUID Guid;
+ UINT8 ExtendOpCode;
+ UINT16 Number;
+} EFI_IFR_GUID_LABEL;
+
+#define EFI_IFR_BANNER_ALIGN_LEFT 0
+#define EFI_IFR_BANNER_ALIGN_CENTER 1
+#define EFI_IFR_BANNER_ALIGN_RIGHT 2
+
+typedef struct _EFI_IFR_GUID_BANNER {
+ EFI_IFR_OP_HEADER Header;
+ EFI_GUID Guid;
+ UINT8 ExtendOpCode; // Extended opcode is EFI_IFR_EXTEND_OP_BANNER
+ EFI_STRING_ID Title; // The string token for the banner title
+ UINT16 LineNumber; // 1-based line number
+ UINT8 Alignment; // left, center, or right-aligned
+} EFI_IFR_GUID_BANNER;
+
+typedef struct _EFI_IFR_GUID_TIMEOUT {
+ EFI_IFR_OP_HEADER Header;
+ EFI_GUID Guid;
+ UINT8 ExtendOpCode;
+ UINT16 TimeOut;
+} EFI_IFR_GUID_TIMEOUT;
+
+#define EFI_NON_DEVICE_CLASS 0x00
+#define EFI_DISK_DEVICE_CLASS 0x01
+#define EFI_VIDEO_DEVICE_CLASS 0x02
+#define EFI_NETWORK_DEVICE_CLASS 0x04
+#define EFI_INPUT_DEVICE_CLASS 0x08
+#define EFI_ON_BOARD_DEVICE_CLASS 0x10
+#define EFI_OTHER_DEVICE_CLASS 0x20
+
+typedef struct _EFI_IFR_GUID_CLASS {
+ EFI_IFR_OP_HEADER Header;
+ EFI_GUID Guid;
+ UINT8 ExtendOpCode;
+ UINT16 Class;
+} EFI_IFR_GUID_CLASS;
+
+#define EFI_SETUP_APPLICATION_SUBCLASS 0x00
+#define EFI_GENERAL_APPLICATION_SUBCLASS 0x01
+#define EFI_FRONT_PAGE_SUBCLASS 0x02
+#define EFI_SINGLE_USE_SUBCLASS 0x03
+
+typedef struct _EFI_IFR_GUID_SUBCLASS {
+ EFI_IFR_OP_HEADER Header;
+ EFI_GUID Guid;
+ UINT8 ExtendOpCode;
+ UINT16 SubClass;
+} EFI_IFR_GUID_SUBCLASS;
+
+#pragma pack()
+
+#endif
+
diff --git a/MdeModulePkg/Library/GenericBdsLib/BdsBoot.c b/MdeModulePkg/Library/GenericBdsLib/BdsBoot.c new file mode 100644 index 0000000000..5071a679cf --- /dev/null +++ b/MdeModulePkg/Library/GenericBdsLib/BdsBoot.c @@ -0,0 +1,1912 @@ +/** @file + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. 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. + +Module Name: + + BdsBoot.c + +Abstract: + + BDS Lib functions which relate with create or process the boot + option. + + +**/ + +#include "InternalBdsLib.h" + +BOOLEAN mEnumBootDevice = FALSE; + +// +// This GUID is used for an EFI Variable that stores the front device pathes +// for a partial device path that starts with the HD node. +// +EFI_GUID mHdBootVariablePrivateGuid = { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x8, 0xe2, 0xe, 0x90, 0x6c, 0xb6, 0xde } }; + + + +/** + 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; + + 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 seperate the int 19, then we don't need to refresh BBS + // + BdsRefreshBbsTableForBoot (Option); + + // + // Write boot to OS performance data to a file + // + PERF_CODE ( + WriteBootToOsPerformanceData (); + ); + + 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 + ); +} + + +/** + Process the boot option follow the EFI 1.1 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 legcy BBS device path to boot + the legacy OS + @param ExitDataSize Returned directly from gBS->StartImage () + @param ExitData Returned directly from gBS->StartImage () + + @retval EFI_SUCCESS Status from gBS->StartImage () + @retval EFI_NOT_FOUND If the Device Path is not found in the system + +**/ +EFI_STATUS +BdsLibBootViaBootOption ( + IN BDS_COMMON_OPTION * Option, + IN EFI_DEVICE_PATH_PROTOCOL * DevicePath, + OUT UINTN *ExitDataSize, + OUT CHAR16 **ExitData OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + EFI_HANDLE ImageHandle; + EFI_DEVICE_PATH_PROTOCOL *FilePath; + EFI_LOADED_IMAGE_PROTOCOL *ImageInfo; + EFI_DEVICE_PATH_PROTOCOL *WorkingDevicePath; + EFI_ACPI_S3_SAVE_PROTOCOL *AcpiS3Save; + LIST_ENTRY TempBootLists; + + // + // Record the performance data for End of BDS + // + PERF_END (0, BDS_TOK, NULL, 0); + + *ExitDataSize = 0; + *ExitData = NULL; + + // + // Notes: put EFI64 ROM Shadow Solution + // + EFI64_SHADOW_ALL_LEGACY_ROM (); + + // + // Notes: this code can be remove after the s3 script table + // hook on the event EFI_EVENT_SIGNAL_READY_TO_BOOT or + // EFI_EVENT_SIGNAL_LEGACY_BOOT + // + Status = gBS->LocateProtocol (&gEfiAcpiS3SaveProtocolGuid, NULL, (VOID **) &AcpiS3Save); + if (!EFI_ERROR (Status)) { + AcpiS3Save->S3Save (AcpiS3Save, 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; + } + } + // + // Signal the EFI_EVENT_SIGNAL_READY_TO_BOOT event + // + EfiSignalEventReadyToBoot(); + + + // + // Set Boot Current + // + gRT->SetVariable ( + L"BootCurrent", + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof (UINT16), + &Option->BootCurrent + ); + + 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, &gEfiShellFileGuid); + if (!EFI_ERROR(Status)) { + if (Option->DevicePath != NULL) { + SafeFreePool(Option->DevicePath); + } + Option->DevicePath = AllocateZeroPool (GetDevicePathSize (DevicePath)); + CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath)); + // + // Update the shell boot option + // + InitializeListHead (&TempBootLists); + BdsLibRegisterNewOption (&TempBootLists, DevicePath, L"EFI Internal Shell", L"BootOrder"); + } + + // + // Drop the TPL level from TPL_APPLICATION to TPL_APPLICATION + // + gBS->RestoreTPL (TPL_APPLICATION); + + DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Booting EFI way %S\n", Option->Description)); + + Status = gBS->LoadImage ( + TRUE, + mBdsImageHandle, + DevicePath, + NULL, + 0, + &ImageHandle + ); + + // + // If we didn't find an image directly, we need to try as if it is a removable device boot opotion + // 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) { + goto Done; + } + // + // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media + // machinename is ia32, ia64, x64, ... + // + FilePath = FileDevicePath (Handle, DEFAULT_REMOVABLE_FILE_NAME); + if (FilePath) { + Status = gBS->LoadImage ( + TRUE, + mBdsImageHandle, + FilePath, + NULL, + 0, + &ImageHandle + ); + if (EFI_ERROR (Status)) { + // + // The DevicePath failed, and it's not a valid + // removable media device. + // + goto Done; + } + } + } + + if (EFI_ERROR (Status)) { + // + // It there is any error from the Boot attempt exit now. + // + goto Done; + } + // + // Provide the image with it's load options + // + Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo); + ASSERT_EFI_ERROR (Status); + + 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, "Image Return Status = %r\n", Status)); + + // + // Clear the Watchdog Timer after the image returns + // + gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL); + +Done: + // + // Clear Boot Current + // + gRT->SetVariable ( + L"BootCurrent", + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + 0, + &Option->BootCurrent + ); + + // + // Raise the TPL level back to TPL_APPLICATION + // + gBS->RaiseTPL (TPL_APPLICATION); + + 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 optimizaiton 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. + A Pointer to the full device path. + @retval NULL Cannot find a valid Hard Drive devic path + +**/ +EFI_DEVICE_PATH_PROTOCOL * +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 'HDDP' variable. + // If exist, search the front path which point to partition node in the variable instants. + // If fail to find or 'HDDP' not exist, reconnect all and search in all system + // + CachedDevicePath = BdsLibGetVariableAndSize ( + L"HDDP", + &mHdBootVariablePrivateGuid, + &CachedDevicePathSize + ); + if (CachedDevicePath != NULL) { + TempNewDevicePath = CachedDevicePath; + DeviceExist = FALSE; + NeedAdjust = FALSE; + do { + // + // Check every instance of the variable + // First, check wheather the instance contain the partition node, which is needed for distinguishing multi + // partial partition boot option. Second, check wheather 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; + SafeFreePool(Instance); + } while (TempNewDevicePath != NULL); + + if (DeviceExist) { + // + // Find the matched device path. + // Append the file path infomration from the boot option and return the fully expanded device path. + // + DevicePath = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath); + FullDevicePath = AppendDevicePath (Instance, DevicePath); + + // + // Adjust the 'HDDP' instances sequense if the matched one is not first one. + // + if (NeedAdjust) { + // + // First delete the matched instance. + // + TempNewDevicePath = CachedDevicePath; + CachedDevicePath = BdsLibDelPartMatchInstance ( CachedDevicePath, Instance ); + SafeFreePool (TempNewDevicePath); + // + // Second, append the remaining parth after the matched instance + // + TempNewDevicePath = CachedDevicePath; + CachedDevicePath = AppendDevicePathInstance ( Instance, CachedDevicePath ); + SafeFreePool (TempNewDevicePath); + // + // Save the matching Device Path so we don't need to do a connect all next time + // + Status = gRT->SetVariable ( + L"HDDP", + &mHdBootVariablePrivateGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + GetDevicePathSize (CachedDevicePath), + CachedDevicePath + ); + } + SafeFreePool(Instance); + gBS->FreePool (CachedDevicePath); + return FullDevicePath; + } + } + + // + // If we get here we fail to find or 'HDDP' not exist, and now we need + // to seach all devices in the system for a matched partition + // + BdsLibConnectAllDriversToAllControllers (); + Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer); + if (EFI_ERROR (Status) || BlockIoHandleCount == 0) { + // + // 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 patition device path in 'HDDP' variable + // + if (CachedDevicePath != NULL) { + // + // Save the matched patition device path as first instance of 'HDDP' variable + // + if (BdsLibMatchDevicePaths (CachedDevicePath, BlockIoDevicePath)) { + TempNewDevicePath = CachedDevicePath; + CachedDevicePath = BdsLibDelPartMatchInstance (CachedDevicePath, BlockIoDevicePath); + SafeFreePool(TempNewDevicePath); + + TempNewDevicePath = CachedDevicePath; + CachedDevicePath = AppendDevicePathInstance (BlockIoDevicePath, CachedDevicePath); + SafeFreePool(TempNewDevicePath); + } else { + TempNewDevicePath = CachedDevicePath; + CachedDevicePath = AppendDevicePathInstance (BlockIoDevicePath, CachedDevicePath); + SafeFreePool(TempNewDevicePath); + } + // + // 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 theary, the 'HDDP' variable maybe become larger and larger. + // + InstanceNum = 0; + 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 + // + Status = gRT->SetVariable ( + L"HDDP", + &mHdBootVariablePrivateGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + GetDevicePathSize (CachedDevicePath), + CachedDevicePath + ); + + break; + } + } + gBS->FreePool (CachedDevicePath); + gBS->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 FALSE + -There is no matched device path instance + +**/ +BOOLEAN +MatchPartitionDevicePathNode ( + IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath, + IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath + ) +{ + HARDDRIVE_DEVICE_PATH *TmpHdPath; + HARDDRIVE_DEVICE_PATH *TempPath; + 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; + TempPath = (HARDDRIVE_DEVICE_PATH *) BdsLibUnpackDevicePath ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath); + Match = FALSE; + // + // Check for the match + // + if ((TmpHdPath->MBRType == TempPath->MBRType) && + (TmpHdPath->SignatureType == TempPath->SignatureType)) { + switch (TmpHdPath->SignatureType) { + case SIGNATURE_TYPE_GUID: + Match = CompareGuid ((EFI_GUID *)TmpHdPath->Signature, (EFI_GUID *)TempPath->Signature); + break; + case SIGNATURE_TYPE_MBR: + Match = (BOOLEAN)(*((UINT32 *)(&(TmpHdPath->Signature[0]))) == *(UINT32 *)(&(TempPath->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; + + BootOrder = BdsLibGetVariableAndSize ( + L"BootOrder", + &gEfiGlobalVariableGuid, + &BootOrderSize + ); + if (NULL == BootOrder) { + return EFI_NOT_FOUND; + } + + DevicePath = DevicePathFromHandle (Handle); + if (DevicePath == NULL) { + return EFI_NOT_FOUND; + } + DevicePathSize = GetDevicePathSize (DevicePath); + + Index = 0; + while (Index < BootOrderSize / sizeof (UINT16)) { + UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]); + BootOptionVar = BdsLibGetVariableAndSize ( + BootOption, + &gEfiGlobalVariableGuid, + &BootOptionSize + ); + if (NULL == BootOptionVar) { + gBS->FreePool (BootOrder); + return EFI_OUT_OF_RESOURCES; + } + + 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); + gBS->FreePool (BootOptionVar); + break; + } + + gBS->FreePool (BootOptionVar); + Index++; + } + + Status = gRT->SetVariable ( + L"BootOrder", + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + BootOrderSize, + BootOrder + ); + + gBS->FreePool (BootOrder); + + return Status; +} + + +/** + Delete all invalid EFI boot options. The probable invalid boot option could + be Removable media or Network boot device. + + VOID + + @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; + + Status = EFI_SUCCESS; + BootOrder = NULL; + BootOrderSize = 0; + + 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) { + gBS->FreePool (BootOrder); + return EFI_OUT_OF_RESOURCES; + } + + TempPtr = BootOptionVar; + TempPtr += sizeof (UINT32) + sizeof (UINT16); + 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)) { + gBS->FreePool (BootOptionVar); + Index++; + continue; + } + + if (!BdsLibIsValidEFIBootOptDevicePath (OptionDevicePath, FALSE)) { + // + // 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 + ); + // + // Mark this boot option in boot order as deleted + // + BootOrder[Index] = 0xffff; + } + + gBS->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 + ); + + gBS->FreePool (BootOrder); + + return Status; +} + + +/** + This function will enumerate all possible boot device in the system, + it will only excute 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 + +**/ +EFI_STATUS +BdsLibEnumerateAllBootOption ( + IN OUT LIST_ENTRY *BdsBootOptionList + ) +{ + EFI_STATUS Status; + UINT16 FloppyNumber; + UINT16 CdromNumber; + UINT16 UsbNumber; + UINT16 MiscNumber; + UINT16 NonBlockNumber; + UINTN NumberBlockIoHandles; + EFI_HANDLE *BlockIoHandles; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + UINTN Index; + UINTN NumberSimpleNetworkHandles; + EFI_HANDLE *SimpleNetworkHandles; + UINTN FvHandleCount; + EFI_HANDLE *FvHandleBuffer; + EFI_FV_FILETYPE Type; + UINTN Size; + EFI_FV_FILE_ATTRIBUTES Attributes; + UINT32 AuthenticationStatus; +#if (PI_SPECIFICATION_VERSION < 0x00010000) + EFI_FIRMWARE_VOLUME_PROTOCOL *Fv; +#else + EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv; +#endif + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + UINTN DevicePathType; + CHAR16 Buffer[40]; + EFI_HANDLE *FileSystemHandles; + UINTN NumberFileSystemHandles; + BOOLEAN NeedDelete; + EFI_IMAGE_DOS_HEADER DosHeader; + EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData; + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; + + FloppyNumber = 0; + CdromNumber = 0; + UsbNumber = 0; + MiscNumber = 0; + ZeroMem (Buffer, sizeof (Buffer)); + // + // If the boot device enumerate happened, just get the boot + // device from the boot order variable + // + if (mEnumBootDevice) { + BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder"); + return EFI_SUCCESS; + } + // + // 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 + // + gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiBlockIoProtocolGuid, + NULL, + &NumberBlockIoHandles, + &BlockIoHandles + ); + for (Index = 0; Index < NumberBlockIoHandles; Index++) { + Status = gBS->HandleProtocol ( + BlockIoHandles[Index], + &gEfiBlockIoProtocolGuid, + (VOID **) &BlkIo + ); + if (!EFI_ERROR (Status)) { + if (!BlkIo->Media->RemovableMedia) { + // + // skip the non-removable block devices + // + continue; + } + } + DevicePath = DevicePathFromHandle (BlockIoHandles[Index]); + DevicePathType = BdsGetBootTypeFromDevicePath (DevicePath); + + switch (DevicePathType) { + case BDS_EFI_ACPI_FLOPPY_BOOT: + if (FloppyNumber == 0) { + UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Floppy"); + } else { + UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Floppy %d", FloppyNumber); + } + BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer); + FloppyNumber++; + break; + + case BDS_EFI_MESSAGE_ATAPI_BOOT: + if (CdromNumber == 0) { + UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI DVD/CDROM"); + } else { + UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI DVD/CDROM %d", CdromNumber); + } + BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer); + CdromNumber++; + break; + + case BDS_EFI_MESSAGE_USB_DEVICE_BOOT: + if (UsbNumber == 0) { + UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI USB Device"); + } else { + UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI USB Device %d", UsbNumber); + } + BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer); + UsbNumber++; + break; + + case BDS_EFI_MESSAGE_SCSI_BOOT: + if (UsbNumber == 0) { + UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI SCSI Device"); + } else { + UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI SCSI Device %d", UsbNumber); + } + BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer); + UsbNumber++; + break; + + case BDS_EFI_MESSAGE_MISC_BOOT: + if (MiscNumber == 0) { + UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Misc Device"); + } else { + UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Misc Device %d", MiscNumber); + } + BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer); + MiscNumber++; + break; + + default: + break; + } + } + + if (NumberBlockIoHandles) { + gBS->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], + DEFAULT_REMOVABLE_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"EFI Non-Block Boot Device"); + } else { + UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Non-Block Boot Device %d", NonBlockNumber); + } + BdsLibBuildOptionFromHandle (FileSystemHandles[Index], BdsBootOptionList, Buffer); + NonBlockNumber++; + } + } + + if (NumberFileSystemHandles) { + gBS->FreePool (FileSystemHandles); + } + + // + // Parse Network Boot Device + // + gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSimpleNetworkProtocolGuid, + NULL, + &NumberSimpleNetworkHandles, + &SimpleNetworkHandles + ); + for (Index = 0; Index < NumberSimpleNetworkHandles; Index++) { + if (Index == 0) { + UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Network"); + } else { + UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Network %d", Index); + } + BdsLibBuildOptionFromHandle (SimpleNetworkHandles[Index], BdsBootOptionList, Buffer); + } + + if (NumberSimpleNetworkHandles) { + gBS->FreePool (SimpleNetworkHandles); + } + + // + // Check if we have on flash shell + // + gBS->LocateHandleBuffer ( + ByProtocol, + #if (PI_SPECIFICATION_VERSION < 0x00010000) + &gEfiFirmwareVolumeProtocolGuid, + #else + &gEfiFirmwareVolume2ProtocolGuid, + #endif + NULL, + &FvHandleCount, + &FvHandleBuffer + ); + for (Index = 0; Index < FvHandleCount; Index++) { + gBS->HandleProtocol ( + FvHandleBuffer[Index], + #if (PI_SPECIFICATION_VERSION < 0x00010000) + &gEfiFirmwareVolumeProtocolGuid, + #else + &gEfiFirmwareVolume2ProtocolGuid, + #endif + (VOID **) &Fv + ); + + Status = Fv->ReadFile ( + Fv, + &gEfiShellFileGuid, + 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) { + gBS->FreePool (FvHandleBuffer); + } + // + // Make sure every boot only have one time + // boot device enumerate + // + BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder"); + mEnumBootDevice = TRUE; + + return EFI_SUCCESS; +} + + +/** + 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 + + @return VOID + +**/ +VOID +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 + + @return None + +**/ +VOID +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, &gEfiShellFileGuid); + // + //ShellNode.Header.Type = MEDIA_DEVICE_PATH; + //ShellNode.Header.SubType = MEDIA_FV_FILEPATH_DP; + //SetDevicePathNodeLength (&ShellNode.Header, sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH)); + //CopyMem (&ShellNode.NameGuid, &gEfiShellFileGuid, sizeof (EFI_GUID)); + // + 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 EFI1.1 spec defined "BootNext" variable + + None + + @return None + +**/ +VOID +BdsLibBootNext ( + VOID + ) +{ + 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) { + gRT->SetVariable ( + L"BootNext", + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + 0, + BootNext + ); + + // + // Start to build the boot option and try to boot + // + UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *BootNext); + BootOption = BdsLibVariableToOption (&TempList, Buffer); + BdsLibConnectDevicePath (BootOption->DevicePath); + BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData); + } + +} + + + +/** + 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 + + @retval NULL The device path points to an EFI bootable Media + @retval NULL The media on the DevicePath is not bootable + +**/ +EFI_HANDLE +BdsLibGetBootableHandle ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + EFI_STATUS Status; + 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; + // + // 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 { + // + // Get BlockIo protocal and check removable attribute + // + Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo); + // + // 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 + ); + gBS->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 previour PCI node to search + // + DupDevicePath = DuplicateDevicePath (DevicePath); + 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], + DEFAULT_REMOVABLE_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; + } + } + } + + if (DupDevicePath != NULL) { + SafeFreePool(DupDevicePath); + } + if (SimpleFileSystemHandles !=NULL ) { + gBS->FreePool (SimpleFileSystemHandles); + } + + 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; + + MediaPresent = FALSE; + + UpdatedDevicePath = DevicePath; + Status = gBS->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid, &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 (&gEfiSimpleNetworkProtocolGuid, &UpdatedDevicePath, &Handle); + } + } + + if (!EFI_ERROR (Status)) { + Status = gBS->HandleProtocol (Handle, &gEfiSimpleNetworkProtocolGuid, (VOID **)&Snp); + if (!EFI_ERROR (Status)) { + if (Snp->Mode->MediaPresentSupported) { + if (Snp->Mode->State == EfiSimpleNetworkInitialized) { + // + // 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 + + @return UINT32 Boot type : + @return // + @return // If the device path contains any media deviec path node, it is media boot type + @return // For the floppy node, handle it as media node + @return // + @return BDS_EFI_MEDIA_HD_BOOT + @return BDS_EFI_MEDIA_CDROM_BOOT + @return BDS_EFI_ACPI_FLOPPY_BOOT + @return // + @return // If the device path not contains any media deviec path node, and + @return // its last device path node point to a message device path node, it is + @return // a message boot type + @return // + @return BDS_EFI_MESSAGE_ATAPI_BOOT + @return BDS_EFI_MESSAGE_SCSI_BOOT + @return BDS_EFI_MESSAGE_USB_DEVICE_BOOT + @return BDS_EFI_MESSAGE_MISC_BOOT + @return // + @return // Legacy boot type + @return // + @return BDS_LEGACY_BBS_BOOT + @return // + @return // If a EFI Removable BlockIO device path not point to a media and message devie, + @return // it is unsupported + @return // + @return BDS_EFI_UNSUPPORT + +**/ +UINT32 +BdsGetBootTypeFromDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + ACPI_HID_DEVICE_PATH *Acpi; + EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; + EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode; + + + 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: + // + // if the device path not only point to driver device, it is not a messaging device path. + // + LastDeviceNode = NextDevicePathNode (TempDevicePath); + if (!IsDevicePathEndType (LastDeviceNode)) { + break; + } + + if (DevicePathSubType(TempDevicePath) == MSG_ATAPI_DP) { + return BDS_EFI_MESSAGE_ATAPI_BOOT; + } else if (DevicePathSubType(TempDevicePath) == MSG_USB_DP) { + return BDS_EFI_MESSAGE_USB_DEVICE_BOOT; + } else if (DevicePathSubType(TempDevicePath) == MSG_SCSI_DP) { + return BDS_EFI_MESSAGE_SCSI_BOOT; + } + return BDS_EFI_MESSAGE_MISC_BOOT; + default: + break; + } + TempDevicePath = NextDevicePathNode (TempDevicePath); + } + + return BDS_EFI_UNSUPPORT; +} + + +/** + Check whether the Device path in a boot option point to a valide bootable device, + And if CheckMedia is true, check the device is ready to boot now. + + DevPath -- the Device path in a boot option + CheckMedia -- if true, check the device is ready to boot now. + + @return TRUE -- the Device path is valide + @return FALSE -- the Device path is invalide . + +**/ +BOOLEAN +BdsLibIsValidEFIBootOptDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevPath, + IN BOOLEAN CheckMedia + ) +{ + 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 + // Only check if there is SimpleNetworkProtocol installed. If yes, that means + // there is the network card there. + // + Status = gBS->LocateDevicePath ( + &gEfiSimpleNetworkProtocolGuid, + &TempDevicePath, + &Handle + ); + if (EFI_ERROR (Status)) { + // + // Device not present so see if we need to connect it + // + TempDevicePath = DevPath; + BdsLibConnectDevicePath (TempDevicePath); + Status = gBS->LocateDevicePath ( + &gEfiSimpleNetworkProtocolGuid, + &TempDevicePath, + &Handle + ); + } + if (!EFI_ERROR (Status)) { + 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 (!EfiIsDevicePathEnd (TempDevicePath)) { + LastDeviceNode = TempDevicePath; + TempDevicePath = EfiNextDevicePathNode (TempDevicePath); + } + if ((DevicePathType (LastDeviceNode) == MEDIA_DEVICE_PATH) && + (DevicePathSubType (LastDeviceNode) == MEDIA_FILEPATH_DP)) { + return TRUE; + } + + // + // If the boot option point to a internal Shell, it is a valid EFI boot option, + // and assume it is ready to boot now + // + if (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode) != NULL) { + return TRUE; + } + + // + // If the boot option point to a blockIO device, no matter whether or not it is a removeable device, it is a valid EFI boot option + // + 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 funciton + 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; +#if (PI_SPECIFICATION_VERSION < 0x00010000) + EFI_FIRMWARE_VOLUME_PROTOCOL *Fv; +#else + EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv; +#endif + 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 (!EfiIsDevicePathEnd (TempDevicePath)) { + LastDeviceNode = TempDevicePath; + TempDevicePath = EfiNextDevicePathNode (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 ( + #if (PI_SPECIFICATION_VERSION < 0x00010000) + &gEfiFirmwareVolumeProtocolGuid, + #else + &gEfiFirmwareVolume2ProtocolGuid, + #endif + &TempDevicePath, + &FoundFvHandle + ); + if (!EFI_ERROR (Status)) { + Status = gBS->HandleProtocol ( + FoundFvHandle, + #if (PI_SPECIFICATION_VERSION < 0x00010000) + &gEfiFirmwareVolumeProtocolGuid, + #else + &gEfiFirmwareVolume2ProtocolGuid, + #endif + (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 ( + mBdsImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID **) &LoadedImage + ); + if (!EFI_ERROR (Status)) { + Status = gBS->HandleProtocol ( + LoadedImage->DeviceHandle, + #if (PI_SPECIFICATION_VERSION < 0x00010000) + &gEfiFirmwareVolumeProtocolGuid, + #else + &gEfiFirmwareVolume2ProtocolGuid, + #endif + (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) { + gBS->LocateHandleBuffer ( + ByProtocol, + #if (PI_SPECIFICATION_VERSION < 0x00010000) + &gEfiFirmwareVolumeProtocolGuid, + #else + &gEfiFirmwareVolume2ProtocolGuid, + #endif + NULL, + &FvHandleCount, + &FvHandleBuffer + ); + for (Index = 0; Index < FvHandleCount; Index++) { + gBS->HandleProtocol ( + FvHandleBuffer[Index], + #if (PI_SPECIFICATION_VERSION < 0x00010000) + &gEfiFirmwareVolumeProtocolGuid, + #else + &gEfiFirmwareVolume2ProtocolGuid, + #endif + (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 (FindFvFile) { + // + // Build the shell device path + // + NewDevicePath = DevicePathFromHandle (FoundFvHandle); + EfiInitializeFwVolDevicepathNode (&FvFileNode, FileGuid); + NewDevicePath = AppendDevicePathNode (NewDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &FvFileNode); + *DevicePath = NewDevicePath; + return EFI_SUCCESS; + } + return EFI_NOT_FOUND; +} diff --git a/MdeModulePkg/Library/GenericBdsLib/BdsConnect.c b/MdeModulePkg/Library/GenericBdsLib/BdsConnect.c new file mode 100644 index 0000000000..6e9068b053 --- /dev/null +++ b/MdeModulePkg/Library/GenericBdsLib/BdsConnect.c @@ -0,0 +1,424 @@ +/** @file + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. 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. + +Module Name: + + BdsConnect.c + +Abstract: + + BDS Lib functions which relate with connect the device + + +**/ + +#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 avialbe and the platform default + console connected. + + None + + @return None + +**/ +VOID +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 avariable + if the system have console device. + + None + + @return None + +**/ +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 success, then still give one 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 +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; + + if (DevicePathToConnect == NULL) { + return EFI_SUCCESS; + } + + DevicePath = DuplicateDevicePath (DevicePathToConnect); + CopyOfDevicePath = DevicePath; + if (DevicePath == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + 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); + 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 + // + Status = gDS->Dispatch (); + } + + 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) { + gBS->FreePool (CopyOfDevicePath); + } + // + // All handle with DevicePath exists in the handle database + // + return Status; +} + + +/** + This function will connect all current system handles recursively. The + connection will finish until every handle's child handle created if it have. + + None + + @retval EFI_SUCCESS All handles and it's child handle have been + connected + @retval EFI_STATUS Return the status of gBS->LocateHandleBuffer(). + +**/ +EFI_STATUS +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); + } + + gBS->FreePool (HandleBuffer); + + return EFI_SUCCESS; +} + + +/** + This function will disconnect all current system handles. The disconnection + will finish until every handle have been disconnected. + + None + + @retval EFI_SUCCESS All handles have been disconnected + @retval EFI_STATUS Return the status of gBS->LocateHandleBuffer(). + +**/ +EFI_STATUS +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); + } + + gBS->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. + + None + + @return None + +**/ +VOID +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 + @return EFI_SUCCESS + @return EFI_NOT_FOUND + +**/ +EFI_STATUS +BdsLibConnectUsbDevByShortFormDP( + IN CHAR8 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) +#if (EFI_SPECIFICATION_VERSION >= 0x00020000) + && (DevicePathSubType (RemainingDevicePath) != MSG_USB_WWID_DP) +#endif + )) { + 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 (AtLeastOneConnected) { + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} diff --git a/MdeModulePkg/Library/GenericBdsLib/BdsConsole.c b/MdeModulePkg/Library/GenericBdsLib/BdsConsole.c new file mode 100644 index 0000000000..db28b68dd0 --- /dev/null +++ b/MdeModulePkg/Library/GenericBdsLib/BdsConsole.c @@ -0,0 +1,399 @@ +/** @file + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. 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. + +Module Name: + + BdsConsole.c + +Abstract: + + BDS Lib functions which contain all the code to connect console device + + +**/ + +#include "InternalBdsLib.h" +//@MT:#include "EfiPrintLib.h" + +BOOLEAN +IsNvNeed ( + IN CHAR16 *ConVarName + ) +{ + CHAR16 *Ptr; + + Ptr = ConVarName; + + // + // If the variable includes "Dev" at last, we consider + // it does not support NV attribute. + // + while (*Ptr) { + Ptr++; + } + + if ((*(Ptr-3) == 'D') && (*(Ptr-2) == 'e') && (*(Ptr-1) == 'v')) { + return FALSE; + } else { + return TRUE; + } +} + + +/** + 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 Add or remove the same device path. + @retval EFI_SUCCESS Success add or remove the device path from the + console variable. + +**/ +EFI_STATUS +BdsLibUpdateConsoleVariable ( + IN CHAR16 *ConVarName, + IN EFI_DEVICE_PATH_PROTOCOL *CustomizedConDevicePath, + IN EFI_DEVICE_PATH_PROTOCOL *ExclusiveDevicePath + ) +{ + 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); + SafeFreePool(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 + // + gRT->SetVariable ( + ConVarName, + &gEfiGlobalVariableGuid, + Attributes, + GetDevicePathSize (NewDevicePath), + NewDevicePath + ); + + if (VarConsole == NewDevicePath) { + SafeFreePool(VarConsole); + } else { + SafeFreePool(VarConsole); + SafeFreePool(NewDevicePath); + } + + return EFI_SUCCESS; + +} + + +/** + Connect the console device base on the variable ConVarName, if + device path of the ConVarName is multi-instance device path, if + anyone of the instances is connected success, then this function + will return success. + + @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 +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); + Next = Instance; + while (!IsDevicePathEndType (Next)) { + Next = NextDevicePathNode (Next); + } + + SetDevicePathEndNode (Next); + // + // Check USB1.1 console + // + if ((DevicePathType (Instance) == MESSAGING_DEVICE_PATH) && + ((DevicePathSubType (Instance) == MSG_USB_CLASS_DP) +#if (EFI_SPECIFICATION_VERSION >= 0x00020000) + || (DevicePathSubType (Instance) == MSG_USB_WWID_DP) +#endif + )) { + // + // Check the Usb console in Usb2.0 bus firstly, then Usb1.1 bus + // + Status = BdsLibConnectUsbDevByShortFormDP (PCI_CLASSC_PI_EHCI, Instance); + if (!EFI_ERROR (Status)) { + DeviceExist = TRUE; + } + + Status = BdsLibConnectUsbDevByShortFormDP (PCI_CLASSC_PI_UHCI, 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; + } + } + SafeFreePool(Instance); + } while (CopyOfDevicePath != NULL); + + gBS->FreePool (StartDevicePath); + + if (DeviceExist == FALSE) { + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + + +/** + This function will search every simpletxt devive in current system, + and make every simpletxt device as pertantial console device. + + None + + @return None + +**/ +VOID +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 varables + // + 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); + } + + SafeFreePool(HandleBuffer); + + 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); + } + + SafeFreePool(HandleBuffer); + + // + // Connect all console variables + // + BdsLibConnectAllDefaultConsoles (); + +} + + +/** + This function will connect console device base on the console + device variable ConIn, ConOut and ErrOut. + + None + + @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 +BdsLibConnectAllDefaultConsoles ( + VOID + ) +{ + EFI_STATUS Status; + + // + // 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"); + + return EFI_SUCCESS; + +} diff --git a/MdeModulePkg/Library/GenericBdsLib/BdsMisc.c b/MdeModulePkg/Library/GenericBdsLib/BdsMisc.c new file mode 100644 index 0000000000..739913bcaa --- /dev/null +++ b/MdeModulePkg/Library/GenericBdsLib/BdsMisc.c @@ -0,0 +1,1415 @@ +/** @file + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. 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. + +Module Name: + + BdsMisc.c + +Abstract: + + Misc BDS library function + + +**/ + +#include "InternalBdsLib.h" + + +#define MAX_STRING_LEN 200 + +static BOOLEAN mFeaturerSwitch = TRUE; +static BOOLEAN mResetRequired = FALSE; + +extern UINT16 gPlatformBootTimeOutDefault; + + +/** + Return the default value for system Timeout variable. + + None + + @return Timeout value. + +**/ +UINT16 +BdsLibGetTimeout ( + VOID + ) +{ + UINT16 Timeout; + UINTN Size; + EFI_STATUS Status; + + // + // Return Timeout variable or 0xffff if no valid + // Timeout variable exists. + // + Size = sizeof (UINT16); + Status = gRT->GetVariable (L"Timeout", &gEfiGlobalVariableGuid, NULL, &Size, &Timeout); + if (!EFI_ERROR (Status)) { + return Timeout; + } + // + // To make the current EFI Automatic-Test activity possible, just add + // following code to make AutoBoot enabled when this variable is not + // present. + // This code should be removed later. + // + Timeout = PcdGet16 (PcdPlatformBootTimeOutDefault); + + // + // Notes: Platform should set default variable if non exists on all error cases!!! + // + Status = gRT->SetVariable ( + L"Timeout", + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + sizeof (UINT16), + &Timeout + ); + return Timeout; +} + + +/** + The function will go through the driver optoin link list, load and start + every driver the driver optoin device path point to. + + @param BdsDriverLists The header of the current driver option link list + + @return None + +**/ +VOID +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, + mBdsImageHandle, + 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 untile find a free number + + @param VariableName Indicate if the boot#### or driver#### option + + @return The Minimal Free Option Number + +**/ +UINT16 +BdsLibGetFreeOptionNumber ( + IN CHAR16 *VariableName + ) +{ + UINT16 Number; + 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; + } + Index++; + } while (1); + + Number = (UINT16) Index; + return Number; +} + + +/** + 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 +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 UpdateBootDevicePath; + UINT16 BootOrderEntry; + UINTN OrderItemNum; + + + OptionPtr = NULL; + OptionSize = 0; + TempPtr = NULL; + OptionDevicePath = NULL; + Description = NULL; + OptionOrderPtr = NULL; + UpdateBootDevicePath = FALSE; + ZeroMem (OptionName, sizeof (OptionName)); + + TempOptionSize = 0; + TempOptionPtr = BdsLibGetVariableAndSize ( + VariableName, + &gEfiGlobalVariableGuid, + &TempOptionSize + ); + + // + // Compare with current option variable + // + for (Index = 0; Index < TempOptionSize / sizeof (UINT16); Index++) { + + 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; + } + 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 (Description, String, StrSize (Description)) == 0) { + if (CompareMem (OptionDevicePath, DevicePath, GetDevicePathSize (OptionDevicePath)) == 0) { + // + // Got the option, so just return + // + gBS->FreePool (OptionPtr); + gBS->FreePool (TempOptionPtr); + return EFI_SUCCESS; + } else { + // + // Boot device path changed, need update. + // + UpdateBootDevicePath = TRUE; + break; + } + } + + gBS->FreePool (OptionPtr); + } + + OptionSize = sizeof (UINT32) + sizeof (UINT16) + StrSize (String); + OptionSize += GetDevicePathSize (DevicePath); + OptionPtr = AllocateZeroPool (OptionSize); + 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 (UpdateBootDevicePath) { + // + // The number in option#### to be updated + // + 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 + ); + if (EFI_ERROR (Status) || UpdateBootDevicePath) { + gBS->FreePool (OptionPtr); + gBS->FreePool (TempOptionPtr); + return Status; + } + + gBS->FreePool (OptionPtr); + + // + // Update the option order variable + // + + // + // If no BootOrder + // + 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 (EFI_ERROR (Status)) { + gBS->FreePool (TempOptionPtr); + return Status; + } + return EFI_SUCCESS; + } + + if (UpdateBootDevicePath) { + // + // If just update a old option, the new optionorder size not change + // + OrderItemNum = (TempOptionSize / sizeof (UINT16)) ; + OptionOrderPtr = AllocateZeroPool ( OrderItemNum * sizeof (UINT16)); + CopyMem (OptionOrderPtr, TempOptionPtr, OrderItemNum * sizeof (UINT16)); + } else { + OrderItemNum = (TempOptionSize / sizeof (UINT16)) + 1 ; + OptionOrderPtr = AllocateZeroPool ( OrderItemNum * sizeof (UINT16)); + 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 + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (TempOptionPtr); + gBS->FreePool (OptionOrderPtr); + return Status; + } + + gBS->FreePool (TempOptionPtr); + gBS->FreePool (OptionOrderPtr); + + return EFI_SUCCESS; +} + + +/** + 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 * +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; + } + // + // 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; + + 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) { + return NULL; + } + + Option->Signature = BDS_LOAD_OPTION_SIGNATURE; + Option->DevicePath = AllocateZeroPool (GetDevicePathSize (DevicePath)); + CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath)); + Option->Attribute = Attribute; + Option->Description = AllocateZeroPool (StrSize (Description)); + CopyMem (Option->Description, Description, StrSize (Description)); + Option->LoadOptions = AllocateZeroPool (LoadOptionsSize); + 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 = sizeof (L"Boot")/sizeof(CHAR16) -1 ; + Option->BootCurrent = (UINT16) ((VariableName[NumOff] -'0') * 0x1000); + Option->BootCurrent = (UINT16) (Option->BootCurrent + ((VariableName[NumOff+1]-'0') * 0x100)); + Option->BootCurrent = (UINT16) (Option->BootCurrent + ((VariableName[NumOff+2]-'0') * 0x10)); + Option->BootCurrent = (UINT16) (Option->BootCurrent + ((VariableName[NumOff+3]-'0'))); + } + // + // Insert active entry to BdsDeviceList + // + if ((Option->Attribute & LOAD_OPTION_ACTIVE) == LOAD_OPTION_ACTIVE) { + InsertTailList (BdsCommonOptionList, &Option->Link); + gBS->FreePool (Variable); + return Option; + } + + gBS->FreePool (Variable); + gBS->FreePool (Option); + return NULL; + +} + + +/** + 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 +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); + Option->BootCurrent = OptionOrder[Index]; + + } + + gBS->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 + @retval EFI_NOT_FOUND Can not find the current system boot mode + +**/ +EFI_STATUS +BdsLibGetBootMode ( + OUT EFI_BOOT_MODE *BootMode + ) +{ + VOID *HobList; + EFI_STATUS Status; + + // + // Get Hob list + // + Status = EfiGetSystemConfigurationTable (&gEfiHobListGuid, &HobList); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Hob list not found\n")); + *BootMode = 0; + return EFI_NOT_FOUND; + } + + Status = R8_GetHobBootMode (HobList, BootMode); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + 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. + @return Caller is responsible freeing the buffer. + @retval NULL Variable was not read + +**/ +VOID * +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) { + return NULL; + } + // + // Read variable into the allocated buffer. + // + Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer); + if (EFI_ERROR (Status)) { + 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 + @return match with the Single, and return the result device path. If there is no + @return remaining device path as a result, this function will return NULL. + +**/ +EFI_DEVICE_PATH_PROTOCOL * +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); + SafeFreePool(TempNewDevicePath); + } + SafeFreePool(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 is contained within Multi + @retval FALSE The Single is not match within Multi + +**/ +BOOLEAN +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 || !Single) { + 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) { + gBS->FreePool (DevicePathInst); + return TRUE; + } + + gBS->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 +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) { + break; + } + + Status = ConOut->OutputString (ConOut, String); + + if (EFI_ERROR (Status)) { + break; + } + } + + 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 + + @return VOID + +**/ +VOID +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 + + @return VOID + +**/ +VOID +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 + + @return VOID + +**/ +VOID +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 + + @return VOID + +**/ +VOID +DisableResetRequired ( + VOID + ) +{ + mResetRequired = FALSE; +} + + +/** + Check whether platform policy enable the reset reminder feature. The default is enabled. + + VOID + + @return VOID + +**/ +BOOLEAN +IsResetReminderFeatureEnable ( + VOID + ) +{ + return mFeaturerSwitch; +} + + +/** + Check if user changed any option setting which needs a system reset to be effective. + + VOID + + @return VOID + +**/ +BOOLEAN +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 + + @return VOID + +**/ +VOID +SetupResetReminder ( + VOID + ) +{ +#if (EFI_SPECIFICATION_VERSION < 0x0002000A) + EFI_STATUS Status; + EFI_FORM_BROWSER_PROTOCOL *Browser; +#endif + EFI_INPUT_KEY Key; + CHAR16 *StringBuffer1; + CHAR16 *StringBuffer2; + + + // + //check any reset required change is applied? if yes, reset system + // + if (IsResetReminderFeatureEnable ()) { + if (IsResetRequired ()) { + +#if (EFI_SPECIFICATION_VERSION < 0x0002000A) + Status = gBS->LocateProtocol ( + &gEfiFormBrowserProtocolGuid, + NULL, + &Browser + ); +#endif + + StringBuffer1 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16)); + ASSERT (StringBuffer1 != NULL); + StringBuffer2 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16)); + ASSERT (StringBuffer2 != NULL); + StrCpy (StringBuffer1, L"Configuration changed. Reset to apply it Now ? "); + StrCpy (StringBuffer2, L"Enter (YES) / Esc (NO)"); + // + // Popup a menu to notice user + // + do { +#if (EFI_SPECIFICATION_VERSION < 0x0002000A) + Browser->CreatePopUp (2, TRUE, 0, NULL, &Key, StringBuffer1, StringBuffer2); +#else + IfrLibCreatePopUp (2, &Key, StringBuffer1, StringBuffer2); +#endif + } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN)); + + gBS->FreePool (StringBuffer1); + gBS->FreePool (StringBuffer2); + // + // If the user hits the YES Response key, reset + // + if ((Key.UnicodeChar == CHAR_CARRIAGE_RETURN)) { + gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL); + } + gST->ConOut->ClearScreen (gST->ConOut); + } + } +} + + +/** + 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 ImageHeader Pointer to image header + @param OptionalHeader Pointer to optional 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 +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)) { + goto Done; + } + + Status = Root->Open (Root, &ThisFile, FileName, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // 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) { + goto Done; + } + gBS->FreePool (Info); + } while (TRUE); + + FileSize = Info->FileSize; + gBS->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; +} + +#if (EFI_SPECIFICATION_VERSION < 0x0002000A) +EFI_STATUS +BdsLibGetHiiHandles ( + IN EFI_HII_PROTOCOL *Hii, + IN OUT UINT16 *HandleBufferLength, + OUT EFI_HII_HANDLE **HiiHandleBuffer + ) +/*++ + +Routine Description: + + Determines the handles that are currently active in the database. + It's the caller's responsibility to free handle buffer. + +Arguments: + + This - A pointer to the EFI_HII_PROTOCOL instance. + HandleBufferLength - On input, a pointer to the length of the handle buffer. On output, + the length of the handle buffer that is required for the handles found. + HiiHandleBuffer - Pointer to an array of EFI_HII_PROTOCOL instances returned. + +Returns: + + EFI_SUCCESS - Get an array of EFI_HII_PROTOCOL instances successfully. + EFI_INVALID_PARAMETER - Hii is NULL. + EFI_NOT_FOUND - Database not found. + +--*/ +{ + UINT16 TempBufferLength; + EFI_STATUS Status; + + TempBufferLength = 0; + + // + // Try to find the actual buffer size for HiiHandle Buffer. + // + Status = Hii->FindHandles (Hii, &TempBufferLength, *HiiHandleBuffer); + + if (Status == EFI_BUFFER_TOO_SMALL) { + *HiiHandleBuffer = AllocateZeroPool (TempBufferLength); + Status = Hii->FindHandles (Hii, &TempBufferLength, *HiiHandleBuffer); + // + // we should not fail here. + // + ASSERT_EFI_ERROR (Status); + } + + *HandleBufferLength = TempBufferLength; + + return Status; + +} +#endif + +VOID +EFIAPI +BdsSetMemoryTypeInformationVariable ( + EFI_EVENT Event, + VOID *Context + ) +/*++ + +Routine Description: + + This routine is a notification function for legayc boot or exit boot + service event. It will adjust the memory information for different + memory type and save them into the variables for next boot + +Arguments: + + Event - The event that triggered this notification function + Context - Pointer to the notification functions context + +Returns: + + None. + +--*/ +{ + EFI_STATUS Status; + EFI_MEMORY_TYPE_INFORMATION *PreviousMemoryTypeInformation; + EFI_MEMORY_TYPE_INFORMATION *CurrentMemoryTypeInformation; + UINTN VariableSize; + BOOLEAN UpdateRequired; + UINTN Index; + UINTN Index1; + UINT32 Previous; + UINT32 Current; + UINT32 Next; + VOID *HobList; + + UpdateRequired = FALSE; + + // + // 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)) { + 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 + // + EfiGetSystemConfigurationTable (&gEfiHobListGuid, &HobList); + Status = R8_GetNextGuidHob (&HobList, &gEfiMemoryTypeInformationGuid, (VOID **) &PreviousMemoryTypeInformation, &VariableSize); + if (EFI_ERROR (Status) || PreviousMemoryTypeInformation == NULL) { + // + // If Platform has not built Memory Type Info into the Hob, just return. + // + return; + } + + // + // Use a heuristic to adjust the Memory Type Information for the next boot + // + for (Index = 0; PreviousMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) { + + Current = 0; + for (Index1 = 0; CurrentMemoryTypeInformation[Index1].Type != EfiMaxMemoryType; Index1++) { + if (PreviousMemoryTypeInformation[Index].Type == CurrentMemoryTypeInformation[Index1].Type) { + Current = CurrentMemoryTypeInformation[Index1].NumberOfPages; + break; + } + } + + if (CurrentMemoryTypeInformation[Index1].Type == EfiMaxMemoryType) { + continue; + } + + Previous = PreviousMemoryTypeInformation[Index].NumberOfPages; + + // + // Write next varible to 125% * current and Inconsistent Memory Reserved across bootings may lead to S4 fail + // + if (Current > Previous) { + Next = Current + (Current >> 2); + } else { + Next = Previous; + } + if (Next > 0 && Next < 4) { + Next = 4; + } + + if (Next != Previous) { + PreviousMemoryTypeInformation[Index].NumberOfPages = Next; + UpdateRequired = TRUE; + } + + } + + // + // If any changes were made to the Memory Type Information settings, then set the new variable value + // + if (UpdateRequired) { + Status = gRT->SetVariable ( + EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME, + &gEfiMemoryTypeInformationGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + VariableSize, + PreviousMemoryTypeInformation + ); + } + + return; +} + + +/** + This routine register a function to adjust the different type memory page number just before booting + and save the updated info into the variable for next boot to use + + None + + @return None. + +**/ +VOID +EFIAPI +BdsLibSaveMemoryTypeInformation ( + VOID + ) +{ + EFI_STATUS Status; + EFI_EVENT ReadyToBootEvent; + + Status = EfiCreateEventReadyToBootEx ( + TPL_CALLBACK, + BdsSetMemoryTypeInformationVariable, + NULL, + &ReadyToBootEvent + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR,"Bds Set Memory Type Informationa Variable Fails\n")); + } + +} + + +/** + return the current TPL, copied from the EDKII glue lib. + + VOID + + @return Current TPL + +**/ +EFI_TPL +BdsLibGetCurrentTpl ( + VOID + ) +{ + EFI_TPL Tpl; + + Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); + gBS->RestoreTPL (Tpl); + + return Tpl; +} diff --git a/MdeModulePkg/Library/GenericBdsLib/DevicePath.c b/MdeModulePkg/Library/GenericBdsLib/DevicePath.c new file mode 100644 index 0000000000..96a3c5daf9 --- /dev/null +++ b/MdeModulePkg/Library/GenericBdsLib/DevicePath.c @@ -0,0 +1,1321 @@ +/** @file + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. 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. + +Module Name: + + DevicePath.c + +Abstract: + + BDS internal function define the default device path string, it can be + replaced by platform device path. + + +**/ + +#include "InternalBdsLib.h" + +// +// Platform Code should implement the Vendor specific Device Path display routine. +// +extern +VOID +DevPathVendor ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +; + +EFI_GUID mEfiDevicePathMessagingUartFlowControlGuid = DEVICE_PATH_MESSAGING_UART_FLOW_CONTROL; + +EFI_GUID mEfiDevicePathMessagingSASGuid = DEVICE_PATH_MESSAGING_SAS; + + +VOID * +ReallocatePool ( + IN VOID *OldPool, + IN UINTN OldSize, + IN UINTN NewSize + ) +/*++ + +Routine Description: + + Adjusts the size of a previously allocated buffer. + +Arguments: + + OldPool - A pointer to the buffer whose size is being adjusted. + + OldSize - The size of the current buffer. + + NewSize - The size of the new buffer. + +Returns: + + EFI_SUCEESS - The requested number of bytes were allocated. + + EFI_OUT_OF_RESOURCES - The pool requested could not be allocated. + + EFI_INVALID_PARAMETER - The buffer was invalid. + +--*/ +{ + VOID *NewPool; + + NewPool = NULL; + if (NewSize) { + NewPool = AllocateZeroPool (NewSize); + } + + if (OldPool) { + if (NewPool) { + CopyMem (NewPool, OldPool, OldSize < NewSize ? OldSize : NewSize); + } + + gBS->FreePool (OldPool); + } + + return NewPool; +} + + +/** + Concatenates a formatted unicode string to allocated pool. + The caller must free the resulting buffer. + + @param Str Tracks the allocated pool, size in use, and amount of pool + allocated. + @param fmt The format string + + @return Allocated buffer with the formatted string printed in it. + @return The caller must free the allocated buffer. The buffer + @return allocation is not packed. + +**/ +CHAR16 * +CatPrint ( + IN OUT POOL_PRINT *Str, + IN CHAR16 *fmt, + ... + ) +{ + UINT16 *AppendStr; + VA_LIST args; + UINTN strsize; + + AppendStr = AllocateZeroPool (0x1000); + if (AppendStr == NULL) { + return Str->str; + } + + VA_START (args, fmt); + UnicodeVSPrint (AppendStr, 0x1000, fmt, args); + VA_END (args); + if (NULL == Str->str) { + strsize = StrSize (AppendStr); + Str->str = AllocateZeroPool (strsize); + ASSERT (Str->str != NULL); + } else { + strsize = StrSize (AppendStr); + strsize += (StrSize (Str->str) - sizeof (UINT16)); + + Str->str = ReallocatePool ( + Str->str, + StrSize (Str->str), + strsize + ); + ASSERT (Str->str != NULL); + } + + Str->maxlen = MAX_CHAR * sizeof (UINT16); + if (strsize < Str->maxlen) { + StrCat (Str->str, AppendStr); + Str->len = strsize - sizeof (UINT16); + } + + gBS->FreePool (AppendStr); + return Str->str; +} + + +/** + Function unpacks a device path data structure so that all the nodes + of a device path are naturally aligned. + + @param DevPath A pointer to a device path data structure + + @return If the memory for the device path is successfully allocated, then a + @return pointer to the new device path is returned. Otherwise, NULL is returned. + +**/ +EFI_DEVICE_PATH_PROTOCOL * +BdsLibUnpackDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevPath + ) +{ + EFI_DEVICE_PATH_PROTOCOL *Src; + EFI_DEVICE_PATH_PROTOCOL *Dest; + EFI_DEVICE_PATH_PROTOCOL *NewPath; + UINTN Size; + + // + // Walk device path and round sizes to valid boundries + // + Src = DevPath; + Size = 0; + for (;;) { + Size += DevicePathNodeLength (Src); + Size += ALIGN_SIZE (Size); + + if (IsDevicePathEnd (Src)) { + break; + } + + Src = NextDevicePathNode (Src); + } + // + // Allocate space for the unpacked path + // + NewPath = AllocateZeroPool (Size); + if (NewPath) { + + ASSERT (((UINTN) NewPath) % MIN_ALIGNMENT_SIZE == 0); + + // + // Copy each node + // + Src = DevPath; + Dest = NewPath; + for (;;) { + Size = DevicePathNodeLength (Src); + CopyMem (Dest, Src, Size); + Size += ALIGN_SIZE (Size); + SetDevicePathNodeLength (Dest, Size); + Dest->Type |= EFI_DP_TYPE_UNPACKED; + Dest = (EFI_DEVICE_PATH_PROTOCOL *) (((UINT8 *) Dest) + Size); + + if (IsDevicePathEnd (Src)) { + break; + } + + Src = NextDevicePathNode (Src); + } + } + + return NewPath; +} + +VOID +DevPathPci ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + PCI_DEVICE_PATH *Pci; + + Pci = DevPath; + CatPrint (Str, L"Pci(%x|%x)", (UINTN) Pci->Device, (UINTN) Pci->Function); +} + +VOID +DevPathPccard ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + PCCARD_DEVICE_PATH *Pccard; + + Pccard = DevPath; + CatPrint (Str, L"Pcmcia(Function%x)", (UINTN) Pccard->FunctionNumber); +} + +VOID +DevPathMemMap ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + MEMMAP_DEVICE_PATH *MemMap; + + MemMap = DevPath; + CatPrint ( + Str, + L"MemMap(%d:%lx-%lx)", + MemMap->MemoryType, + MemMap->StartingAddress, + MemMap->EndingAddress + ); +} + +VOID +DevPathController ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + CONTROLLER_DEVICE_PATH *Controller; + + Controller = DevPath; + CatPrint (Str, L"Ctrl(%d)", (UINTN) Controller->ControllerNumber); +} + + +/** + Convert Vendor device path to device name + + @param Str The buffer store device name + @param DevPath Pointer to vendor device path + + @return When it return, the device name have been stored in *Str. + +**/ +VOID +DevPathVendor ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + VENDOR_DEVICE_PATH *Vendor; + CHAR16 *Type; + UINTN DataLength; + UINTN Index; + UINT32 FlowControlMap; + + UINT16 Info; + + Vendor = DevPath; + + switch (DevicePathType (&Vendor->Header)) { + case HARDWARE_DEVICE_PATH: + Type = L"Hw"; +// bugbug: nt 32 specific definition +#if 0 + // + // If the device is a winntbus device, we will give it a readable device name. + // + if (CompareGuid (&Vendor->Guid, &mEfiWinNtThunkProtocolGuid)) { + CatPrint (Str, L"%s", L"WinNtBus"); + return ; + } else if (CompareGuid (&Vendor->Guid, &mEfiWinNtGopGuid)) { + CatPrint (Str, L"%s", L"GOP"); + return ; + } else if (CompareGuid (&Vendor->Guid, &mEfiWinNtSerialPortGuid)) { + CatPrint (Str, L"%s", L"Serial"); + return ; + } +#endif + break; + + case MESSAGING_DEVICE_PATH: + Type = L"Msg"; + if (CompareGuid (&Vendor->Guid, &gEfiPcAnsiGuid)) { + CatPrint (Str, L"VenPcAnsi()"); + return ; + } else if (CompareGuid (&Vendor->Guid, &gEfiVT100Guid)) { + CatPrint (Str, L"VenVt100()"); + return ; + } else if (CompareGuid (&Vendor->Guid, &gEfiVT100PlusGuid)) { + CatPrint (Str, L"VenVt100Plus()"); + return ; + } else if (CompareGuid (&Vendor->Guid, &gEfiVTUTF8Guid)) { + CatPrint (Str, L"VenUft8()"); + return ; + } else if (CompareGuid (&Vendor->Guid, &mEfiDevicePathMessagingUartFlowControlGuid)) { + FlowControlMap = (((UART_FLOW_CONTROL_DEVICE_PATH *) Vendor)->FlowControlMap); + switch (FlowControlMap & 0x00000003) { + case 0: + CatPrint (Str, L"UartFlowCtrl(%s)", L"None"); + break; + + case 1: + CatPrint (Str, L"UartFlowCtrl(%s)", L"Hardware"); + break; + + case 2: + CatPrint (Str, L"UartFlowCtrl(%s)", L"XonXoff"); + break; + + default: + break; + } + + return ; + + } else if (CompareGuid (&Vendor->Guid, &mEfiDevicePathMessagingSASGuid)) { + CatPrint ( + Str, + L"SAS(%lx,%lx,%x,", + ((SAS_DEVICE_PATH *) Vendor)->SasAddress, + ((SAS_DEVICE_PATH *) Vendor)->Lun, + ((SAS_DEVICE_PATH *) Vendor)->RelativeTargetPort + ); + Info = (((SAS_DEVICE_PATH *) Vendor)->DeviceTopology); + if ((Info & 0x0f) == 0) { + CatPrint (Str, L"NoTopology,0,0,0,"); + } else if (((Info & 0x0f) == 1) || ((Info & 0x0f) == 2)) { + CatPrint ( + Str, + L"%s,%s,%s,", + (Info & (0x1 << 4)) ? L"SATA" : L"SAS", + (Info & (0x1 << 5)) ? L"External" : L"Internal", + (Info & (0x1 << 6)) ? L"Expanded" : L"Direct" + ); + if ((Info & 0x0f) == 1) { + CatPrint (Str, L"0,"); + } else { + CatPrint (Str, L"%x,", (UINTN) ((Info >> 8) & 0xff)); + } + } else { + CatPrint (Str, L"0,0,0,0,"); + } + + CatPrint (Str, L"%x)", (UINTN) ((SAS_DEVICE_PATH *) Vendor)->Reserved); + return ; + + } else if (CompareGuid (&Vendor->Guid, &gEfiDebugPortProtocolGuid)) { + CatPrint (Str, L"DebugPort()"); + return ; + } + break; + + case MEDIA_DEVICE_PATH: + Type = L"Media"; + break; + + default: + Type = L"?"; + break; + } + + CatPrint (Str, L"Ven%s(%g", Type, &Vendor->Guid); + DataLength = DevicePathNodeLength (&Vendor->Header) - sizeof (VENDOR_DEVICE_PATH); + if (DataLength > 0) { + CatPrint (Str, L","); + for (Index = 0; Index < DataLength; Index++) { + CatPrint (Str, L"%02x", (UINTN) ((VENDOR_DEVICE_PATH_WITH_DATA *) Vendor)->VendorDefinedData[Index]); + } + } + CatPrint (Str, L")"); +} + + +VOID +DevPathAcpi ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + ACPI_HID_DEVICE_PATH *Acpi; + + Acpi = DevPath; + if ((Acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { + CatPrint (Str, L"Acpi(PNP%04x,%x)", (UINTN) EISA_ID_TO_NUM (Acpi->HID), (UINTN) Acpi->UID); + } else { + CatPrint (Str, L"Acpi(%08x,%x)", (UINTN) Acpi->HID, (UINTN) Acpi->UID); + } +} + +VOID +DevPathExtendedAcpi ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + ACPI_EXTENDED_HID_DEVICE_PATH *ExtendedAcpi; + // + // Index for HID, UID and CID strings, 0 for non-exist + // + UINT16 HIDSTRIdx; + UINT16 UIDSTRIdx; + UINT16 CIDSTRIdx; + UINT16 Index; + UINT16 Length; + UINT16 Anchor; + CHAR8 *AsChar8Array; + + ASSERT (Str != NULL); + ASSERT (DevPath != NULL); + + HIDSTRIdx = 0; + UIDSTRIdx = 0; + CIDSTRIdx = 0; + ExtendedAcpi = DevPath; + Length = (UINT16) DevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) ExtendedAcpi); + + ASSERT (Length >= 19); + AsChar8Array = (CHAR8 *) ExtendedAcpi; + + // + // find HIDSTR + // + Anchor = 16; + for (Index = Anchor; Index < Length && AsChar8Array[Index]; Index++) { + ; + } + if (Index > Anchor) { + HIDSTRIdx = Anchor; + } + // + // find UIDSTR + // + Anchor = (UINT16) (Index + 1); + for (Index = Anchor; Index < Length && AsChar8Array[Index]; Index++) { + ; + } + if (Index > Anchor) { + UIDSTRIdx = Anchor; + } + // + // find CIDSTR + // + Anchor = (UINT16) (Index + 1); + for (Index = Anchor; Index < Length && AsChar8Array[Index]; Index++) { + ; + } + if (Index > Anchor) { + CIDSTRIdx = Anchor; + } + + if (HIDSTRIdx == 0 && CIDSTRIdx == 0 && ExtendedAcpi->UID == 0) { + CatPrint (Str, L"AcpiExp("); + if ((ExtendedAcpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { + CatPrint (Str, L"PNP%04x,", (UINTN) EISA_ID_TO_NUM (ExtendedAcpi->HID)); + } else { + CatPrint (Str, L"%08x,", (UINTN) ExtendedAcpi->HID); + } + if ((ExtendedAcpi->CID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { + CatPrint (Str, L"PNP%04x,", (UINTN) EISA_ID_TO_NUM (ExtendedAcpi->CID)); + } else { + CatPrint (Str, L"%08x,", (UINTN) ExtendedAcpi->CID); + } + if (UIDSTRIdx != 0) { + CatPrint (Str, L"%a)", AsChar8Array + UIDSTRIdx); + } else { + CatPrint (Str, L"\"\")"); + } + } else { + CatPrint (Str, L"AcpiEx("); + if ((ExtendedAcpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { + CatPrint (Str, L"PNP%04x,", (UINTN) EISA_ID_TO_NUM (ExtendedAcpi->HID)); + } else { + CatPrint (Str, L"%08x,", (UINTN) ExtendedAcpi->HID); + } + if ((ExtendedAcpi->CID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { + CatPrint (Str, L"PNP%04x,", (UINTN) EISA_ID_TO_NUM (ExtendedAcpi->CID)); + } else { + CatPrint (Str, L"%08x,", (UINTN) ExtendedAcpi->CID); + } + CatPrint (Str, L"%x,", (UINTN) ExtendedAcpi->UID); + + if (HIDSTRIdx != 0) { + CatPrint (Str, L"%a,", AsChar8Array + HIDSTRIdx); + } else { + CatPrint (Str, L"\"\","); + } + if (CIDSTRIdx != 0) { + CatPrint (Str, L"%a,", AsChar8Array + CIDSTRIdx); + } else { + CatPrint (Str, L"\"\","); + } + if (UIDSTRIdx != 0) { + CatPrint (Str, L"%a)", AsChar8Array + UIDSTRIdx); + } else { + CatPrint (Str, L"\"\")"); + } + } + +} + +VOID +DevPathAdrAcpi ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + ACPI_ADR_DEVICE_PATH *AcpiAdr; + UINT16 Index; + UINT16 Length; + UINT16 AdditionalAdrCount; + + AcpiAdr = DevPath; + Length = (UINT16) DevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) AcpiAdr); + AdditionalAdrCount = (UINT16) ((Length - 8) / 4); + + CatPrint (Str, L"AcpiAdr(%x", (UINTN) AcpiAdr->ADR); + for (Index = 0; Index < AdditionalAdrCount; Index++) { + CatPrint (Str, L",%x", (UINTN) *(UINT32 *) ((UINT8 *) AcpiAdr + 8 + Index * 4)); + } + CatPrint (Str, L")"); +} + +VOID +DevPathAtapi ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + ATAPI_DEVICE_PATH *Atapi; + + Atapi = DevPath; + CatPrint ( + Str, + L"Ata(%s,%s)", + Atapi->PrimarySecondary ? L"Secondary" : L"Primary", + Atapi->SlaveMaster ? L"Slave" : L"Master" + ); +} + +VOID +DevPathScsi ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + SCSI_DEVICE_PATH *Scsi; + + Scsi = DevPath; + CatPrint (Str, L"Scsi(Pun%x,Lun%x)", (UINTN) Scsi->Pun, (UINTN) Scsi->Lun); +} + +VOID +DevPathFibre ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + FIBRECHANNEL_DEVICE_PATH *Fibre; + + Fibre = DevPath; + CatPrint (Str, L"Fibre(Wwn%lx,Lun%x)", Fibre->WWN, Fibre->Lun); +} + +VOID +DevPath1394 ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + F1394_DEVICE_PATH *F1394; + + F1394 = DevPath; + CatPrint (Str, L"1394(%g)", &F1394->Guid); +} + +VOID +DevPathUsb ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + USB_DEVICE_PATH *Usb; + + Usb = DevPath; + CatPrint (Str, L"Usb(%x,%x)", (UINTN) Usb->ParentPortNumber, (UINTN) Usb->InterfaceNumber); +} + +#if (EFI_SPECIFICATION_VERSION >= 0x00020000) +VOID +DevPathUsbWWID ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + USB_WWID_DEVICE_PATH *UsbWWId; + + UsbWWId = DevPath; + CatPrint ( + Str, + L"UsbWwid(%x,%x,%x,\"WWID\")", + (UINTN) UsbWWId->VendorId, + (UINTN) UsbWWId->ProductId, + (UINTN) UsbWWId->InterfaceNumber + ); +} + +VOID +DevPathLogicalUnit ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + DEVICE_LOGICAL_UNIT_DEVICE_PATH *LogicalUnit; + + LogicalUnit = DevPath; + CatPrint (Str, L"Unit(%x)", (UINTN) LogicalUnit->Lun); +} +#endif + +VOID +DevPathUsbClass ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + USB_CLASS_DEVICE_PATH *UsbClass; + + UsbClass = DevPath; + CatPrint ( + Str, + L"Usb Class(%x,%x,%x,%x,%x)", + (UINTN) UsbClass->VendorId, + (UINTN) UsbClass->ProductId, + (UINTN) UsbClass->DeviceClass, + (UINTN) UsbClass->DeviceSubClass, + (UINTN) UsbClass->DeviceProtocol + ); +} + +VOID +DevPathSata ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + SATA_DEVICE_PATH *Sata; + + Sata = DevPath; + CatPrint ( + Str, + L"Sata(%x,%x,%x)", + (UINTN) Sata->HBAPortNumber, + (UINTN) Sata->PortMultiplierPortNumber, + (UINTN) Sata->Lun + ); +} + +VOID +DevPathI2O ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + I2O_DEVICE_PATH *I2O; + + I2O = DevPath; + CatPrint (Str, L"I2O(%x)", (UINTN) I2O->Tid); +} + +VOID +DevPathMacAddr ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + MAC_ADDR_DEVICE_PATH *MAC; + UINTN HwAddressSize; + UINTN Index; + + MAC = DevPath; + + HwAddressSize = sizeof (EFI_MAC_ADDRESS); + if (MAC->IfType == 0x01 || MAC->IfType == 0x00) { + HwAddressSize = 6; + } + + CatPrint (Str, L"Mac("); + + for (Index = 0; Index < HwAddressSize; Index++) { + CatPrint (Str, L"%02x", (UINTN) MAC->MacAddress.Addr[Index]); + } + + CatPrint (Str, L")"); +} + +VOID +DevPathIPv4 ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + IPv4_DEVICE_PATH *IP; + + IP = DevPath; + CatPrint ( + Str, + L"IPv4(%d.%d.%d.%d:%d)", + (UINTN) IP->RemoteIpAddress.Addr[0], + (UINTN) IP->RemoteIpAddress.Addr[1], + (UINTN) IP->RemoteIpAddress.Addr[2], + (UINTN) IP->RemoteIpAddress.Addr[3], + (UINTN) IP->RemotePort + ); +} + +VOID +DevPathIPv6 ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + IPv6_DEVICE_PATH *IP; + + IP = DevPath; + CatPrint ( + Str, + L"IPv6(%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x)", + (UINTN) IP->RemoteIpAddress.Addr[0], + (UINTN) IP->RemoteIpAddress.Addr[1], + (UINTN) IP->RemoteIpAddress.Addr[2], + (UINTN) IP->RemoteIpAddress.Addr[3], + (UINTN) IP->RemoteIpAddress.Addr[4], + (UINTN) IP->RemoteIpAddress.Addr[5], + (UINTN) IP->RemoteIpAddress.Addr[6], + (UINTN) IP->RemoteIpAddress.Addr[7], + (UINTN) IP->RemoteIpAddress.Addr[8], + (UINTN) IP->RemoteIpAddress.Addr[9], + (UINTN) IP->RemoteIpAddress.Addr[10], + (UINTN) IP->RemoteIpAddress.Addr[11], + (UINTN) IP->RemoteIpAddress.Addr[12], + (UINTN) IP->RemoteIpAddress.Addr[13], + (UINTN) IP->RemoteIpAddress.Addr[14], + (UINTN) IP->RemoteIpAddress.Addr[15] + ); +} + +VOID +DevPathInfiniBand ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + INFINIBAND_DEVICE_PATH *InfiniBand; + + InfiniBand = DevPath; + CatPrint ( + Str, + L"Infiniband(%x,%g,%lx,%lx,%lx)", + (UINTN) InfiniBand->ResourceFlags, + InfiniBand->PortGid, + InfiniBand->ServiceId, + InfiniBand->TargetPortId, + InfiniBand->DeviceId + ); +} + +VOID +DevPathUart ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + UART_DEVICE_PATH *Uart; + CHAR8 Parity; + + Uart = DevPath; + switch (Uart->Parity) { + case 0: + Parity = 'D'; + break; + + case 1: + Parity = 'N'; + break; + + case 2: + Parity = 'E'; + break; + + case 3: + Parity = 'O'; + break; + + case 4: + Parity = 'M'; + break; + + case 5: + Parity = 'S'; + break; + + default: + Parity = 'x'; + break; + } + + if (Uart->BaudRate == 0) { + CatPrint (Str, L"Uart(DEFAULT,%c,", Parity); + } else { + CatPrint (Str, L"Uart(%d,%c,", Uart->BaudRate, Parity); + } + + if (Uart->DataBits == 0) { + CatPrint (Str, L"D,"); + } else { + CatPrint (Str, L"%d,", (UINTN) Uart->DataBits); + } + + switch (Uart->StopBits) { + case 0: + CatPrint (Str, L"D)"); + break; + + case 1: + CatPrint (Str, L"1)"); + break; + + case 2: + CatPrint (Str, L"1.5)"); + break; + + case 3: + CatPrint (Str, L"2)"); + break; + + default: + CatPrint (Str, L"x)"); + break; + } +} + +#if (EFI_SPECIFICATION_VERSION >= 0x00020000) +VOID +DevPathiSCSI ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + ISCSI_DEVICE_PATH_WITH_NAME *iSCSI; + UINT16 Options; + + ASSERT (Str != NULL); + ASSERT (DevPath != NULL); + + iSCSI = DevPath; + CatPrint ( + Str, + L"iSCSI(%s,%x,%lx,", + iSCSI->iSCSITargetName, + iSCSI->TargetPortalGroupTag, + iSCSI->Lun + ); + + Options = iSCSI->LoginOption; + CatPrint (Str, L"%s,", ((Options >> 1) & 0x0001) ? L"CRC32C" : L"None"); + CatPrint (Str, L"%s,", ((Options >> 3) & 0x0001) ? L"CRC32C" : L"None"); + if ((Options >> 11) & 0x0001) { + CatPrint (Str, L"%s,", L"None"); + } else if ((Options >> 12) & 0x0001) { + CatPrint (Str, L"%s,", L"CHAP_UNI"); + } else { + CatPrint (Str, L"%s,", L"CHAP_BI"); + + } + + CatPrint (Str, L"%s)", (iSCSI->NetworkProtocol == 0) ? L"TCP" : L"reserved"); +} +#endif + +VOID +DevPathHardDrive ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + HARDDRIVE_DEVICE_PATH *Hd; + + Hd = DevPath; + switch (Hd->SignatureType) { + case SIGNATURE_TYPE_MBR: + CatPrint ( + Str, + L"HD(Part%d,Sig%08x)", + (UINTN) Hd->PartitionNumber, + (UINTN) *((UINT32 *) (&(Hd->Signature[0]))) + ); + break; + + case SIGNATURE_TYPE_GUID: + CatPrint ( + Str, + L"HD(Part%d,Sig%g)", + (UINTN) Hd->PartitionNumber, + (EFI_GUID *) &(Hd->Signature[0]) + ); + break; + + default: + CatPrint ( + Str, + L"HD(Part%d,MBRType=%02x,SigType=%02x)", + (UINTN) Hd->PartitionNumber, + (UINTN) Hd->MBRType, + (UINTN) Hd->SignatureType + ); + break; + } +} + +VOID +DevPathCDROM ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + CDROM_DEVICE_PATH *Cd; + + Cd = DevPath; + CatPrint (Str, L"CDROM(Entry%x)", (UINTN) Cd->BootEntry); +} + +VOID +DevPathFilePath ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + FILEPATH_DEVICE_PATH *Fp; + + Fp = DevPath; + CatPrint (Str, L"%s", Fp->PathName); +} + +VOID +DevPathMediaProtocol ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + MEDIA_PROTOCOL_DEVICE_PATH *MediaProt; + + MediaProt = DevPath; + CatPrint (Str, L"Media(%g)", &MediaProt->Protocol); +} + +VOID +DevPathFvFilePath ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFilePath; + + FvFilePath = DevPath; + CatPrint (Str, L"%g", &FvFilePath->FvFileName); +} + +VOID +DevPathBssBss ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + BBS_BBS_DEVICE_PATH *Bbs; + CHAR16 *Type; + + Bbs = DevPath; + switch (Bbs->DeviceType) { + case BBS_TYPE_FLOPPY: + Type = L"Floppy"; + break; + + case BBS_TYPE_HARDDRIVE: + Type = L"Harddrive"; + break; + + case BBS_TYPE_CDROM: + Type = L"CDROM"; + break; + + case BBS_TYPE_PCMCIA: + Type = L"PCMCIA"; + break; + + case BBS_TYPE_USB: + Type = L"Usb"; + break; + + case BBS_TYPE_EMBEDDED_NETWORK: + Type = L"Net"; + break; + + case BBS_TYPE_BEV: + Type = L"BEV"; + break; + + default: + Type = L"?"; + break; + } + CatPrint (Str, L"Legacy-%s", Type); +} + +VOID +DevPathEndInstance ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + CatPrint (Str, L","); +} + +VOID +DevPathNodeUnknown ( + IN OUT POOL_PRINT *Str, + IN VOID *DevPath + ) +{ + CatPrint (Str, L"?"); +} + +DEVICE_PATH_STRING_TABLE DevPathTable[] = { + HARDWARE_DEVICE_PATH, + HW_PCI_DP, + DevPathPci, + HARDWARE_DEVICE_PATH, + HW_PCCARD_DP, + DevPathPccard, + HARDWARE_DEVICE_PATH, + HW_MEMMAP_DP, + DevPathMemMap, + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + DevPathVendor, + HARDWARE_DEVICE_PATH, + HW_CONTROLLER_DP, + DevPathController, + ACPI_DEVICE_PATH, + ACPI_DP, + DevPathAcpi, + ACPI_DEVICE_PATH, + ACPI_EXTENDED_DP, + DevPathExtendedAcpi, + ACPI_DEVICE_PATH, + ACPI_ADR_DP, + DevPathAdrAcpi, + MESSAGING_DEVICE_PATH, + MSG_ATAPI_DP, + DevPathAtapi, + MESSAGING_DEVICE_PATH, + MSG_SCSI_DP, + DevPathScsi, + MESSAGING_DEVICE_PATH, + MSG_FIBRECHANNEL_DP, + DevPathFibre, + MESSAGING_DEVICE_PATH, + MSG_1394_DP, + DevPath1394, + MESSAGING_DEVICE_PATH, + MSG_USB_DP, + DevPathUsb, +#if (EFI_SPECIFICATION_VERSION >= 0x00020000) + MESSAGING_DEVICE_PATH, + MSG_USB_WWID_DP, + DevPathUsbWWID, + MESSAGING_DEVICE_PATH, + MSG_DEVICE_LOGICAL_UNIT_DP, + DevPathLogicalUnit, +#endif + MESSAGING_DEVICE_PATH, + MSG_USB_CLASS_DP, + DevPathUsbClass, + MESSAGING_DEVICE_PATH, + MSG_SATA_DP, + DevPathSata, + MESSAGING_DEVICE_PATH, + MSG_I2O_DP, + DevPathI2O, + MESSAGING_DEVICE_PATH, + MSG_MAC_ADDR_DP, + DevPathMacAddr, + MESSAGING_DEVICE_PATH, + MSG_IPv4_DP, + DevPathIPv4, + MESSAGING_DEVICE_PATH, + MSG_IPv6_DP, + DevPathIPv6, + MESSAGING_DEVICE_PATH, + MSG_INFINIBAND_DP, + DevPathInfiniBand, + MESSAGING_DEVICE_PATH, + MSG_UART_DP, + DevPathUart, + MESSAGING_DEVICE_PATH, + MSG_VENDOR_DP, + DevPathVendor, +#if (EFI_SPECIFICATION_VERSION >= 0x00020000) + MESSAGING_DEVICE_PATH, + MSG_ISCSI_DP, + DevPathiSCSI, +#endif + MEDIA_DEVICE_PATH, + MEDIA_HARDDRIVE_DP, + DevPathHardDrive, + MEDIA_DEVICE_PATH, + MEDIA_CDROM_DP, + DevPathCDROM, + MEDIA_DEVICE_PATH, + MEDIA_VENDOR_DP, + DevPathVendor, + MEDIA_DEVICE_PATH, + MEDIA_FILEPATH_DP, + DevPathFilePath, + MEDIA_DEVICE_PATH, + MEDIA_PROTOCOL_DP, + DevPathMediaProtocol, +#if (EFI_SPECIFICATION_VERSION != 0x00020000) + MEDIA_DEVICE_PATH, + MEDIA_PIWG_FW_FILE_DP, + DevPathFvFilePath, +#endif + BBS_DEVICE_PATH, + BBS_BBS_DP, + DevPathBssBss, + END_DEVICE_PATH_TYPE, + END_INSTANCE_DEVICE_PATH_SUBTYPE, + DevPathEndInstance, + 0, + 0, + NULL +}; + + +/** + +**/ +CHAR16 * +DevicePathToStr ( + IN EFI_DEVICE_PATH_PROTOCOL *DevPath + ) +{ + POOL_PRINT Str; + EFI_DEVICE_PATH_PROTOCOL *DevPathNode; + VOID (*DumpNode) (POOL_PRINT *, VOID *); + + UINTN Index; + UINTN NewSize; + + EFI_STATUS Status; + CHAR16 *ToText; + EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText; + + ZeroMem (&Str, sizeof (Str)); + + if (DevPath == NULL) { + goto Done; + } + + Status = gBS->LocateProtocol ( + &gEfiDevicePathToTextProtocolGuid, + NULL, + (VOID **) &DevPathToText + ); + if (!EFI_ERROR (Status)) { + ToText = DevPathToText->ConvertDevicePathToText ( + DevPath, + FALSE, + TRUE + ); + ASSERT (ToText != NULL); + return ToText; + } + + // + // Unpacked the device path + // + DevPath = BdsLibUnpackDevicePath (DevPath); + ASSERT (DevPath); + + // + // Process each device path node + // + DevPathNode = DevPath; + while (!IsDevicePathEnd (DevPathNode)) { + // + // Find the handler to dump this device path node + // + DumpNode = NULL; + for (Index = 0; DevPathTable[Index].Function; Index += 1) { + + if (DevicePathType (DevPathNode) == DevPathTable[Index].Type && + DevicePathSubType (DevPathNode) == DevPathTable[Index].SubType + ) { + DumpNode = DevPathTable[Index].Function; + break; + } + } + // + // If not found, use a generic function + // + if (!DumpNode) { + DumpNode = DevPathNodeUnknown; + } + // + // Put a path seperator in if needed + // + if (Str.len && DumpNode != DevPathEndInstance) { + CatPrint (&Str, L"/"); + } + // + // Print this node of the device path + // + DumpNode (&Str, DevPathNode); + + // + // Next device path node + // + DevPathNode = NextDevicePathNode (DevPathNode); + } + // + // Shrink pool used for string allocation + // + gBS->FreePool (DevPath); + +Done: + NewSize = (Str.len + 1) * sizeof (CHAR16); + Str.str = ReallocatePool (Str.str, NewSize, NewSize); + ASSERT (Str.str != NULL); + Str.str[Str.len] = 0; + return Str.str; +} + + +/** + Function creates a device path data structure that identically matches the + device path passed in. + + @param DevPath A pointer to a device path data structure. + + @return The new copy of DevPath is created to identically match the input. + @return Otherwise, NULL is returned. + +**/ +EFI_DEVICE_PATH_PROTOCOL * +LibDuplicateDevicePathInstance ( + IN EFI_DEVICE_PATH_PROTOCOL *DevPath + ) +{ + EFI_DEVICE_PATH_PROTOCOL *NewDevPath; + EFI_DEVICE_PATH_PROTOCOL *DevicePathInst; + EFI_DEVICE_PATH_PROTOCOL *Temp; + UINTN Size; + + // + // get the size of an instance from the input + // + Temp = DevPath; + DevicePathInst = GetNextDevicePathInstance (&Temp, &Size); + + // + // Make a copy + // + NewDevPath = NULL; + if (Size) { + NewDevPath = AllocateZeroPool (Size); + ASSERT (NewDevPath != NULL); + } + + if (NewDevPath) { + CopyMem (NewDevPath, DevicePathInst, Size); + } + + return NewDevPath; +} diff --git a/MdeModulePkg/Library/GenericBdsLib/Ebc/BmMachine.h b/MdeModulePkg/Library/GenericBdsLib/Ebc/BmMachine.h new file mode 100644 index 0000000000..dc4d728733 --- /dev/null +++ b/MdeModulePkg/Library/GenericBdsLib/Ebc/BmMachine.h @@ -0,0 +1,35 @@ +/** @file + +Copyright (c) 2007, Intel Corporation +All rights reserved. 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. + +Module Name: + + BmMachine.h + +Abstract: + + Boot Manager Machine type + + + +Revision History + + +**/ + +#ifndef _BM_MACHINE_H +#define _BM_MACHINE_H + +// +// NOTE: This is not defined in UEFI spec. +// +#define DEFAULT_REMOVABLE_FILE_NAME L"\\EFI\\BOOT\\BOOTEBC.EFI" + +#endif diff --git a/MdeModulePkg/Library/GenericBdsLib/GenericBdsLib.inf b/MdeModulePkg/Library/GenericBdsLib/GenericBdsLib.inf new file mode 100644 index 0000000000..ebaed91e6a --- /dev/null +++ b/MdeModulePkg/Library/GenericBdsLib/GenericBdsLib.inf @@ -0,0 +1,119 @@ +#/** @file
+# Component name for module GenericBdsLib
+#
+# FIX ME!
+# Copyright (c) 2007, Intel Corporation. All rights reserved.
+#
+# All rights reserved. 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 = 0x00010005
+ BASE_NAME = GenericBdsLib
+ FILE_GUID = e405ec31-ccaa-4dd4-83e8-0aec01703f7e
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = GenericBdsLib|DXE_DRIVER
+ EDK_RELEASE_VERSION = 0x00020000
+ EFI_SPECIFICATION_VERSION = 0x0002000A
+
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+ DevicePath.c
+ Performance.c
+ BdsConnect.c
+ BdsMisc.c
+ R8Lib.c
+ BdsConsole.c
+ BdsBoot.c
+ InternalBdsLib.h
+ R8Lib.h
+
+[Sources.Ia32]
+ Ia32\ClearDr.asm
+ Ia32\BmMachine.h
+
+[Sources.X64]
+ x64\ClearDr.asm
+ x64\BmMachine.h
+
+[Sources.IPF]
+ Ipf\ShadowRom.c
+ Ipf\BmMachine.h
+
+[Sources.EBC]
+ Ebc\BmMachine.h
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ #
+ #This dependency is because of gEfiLegacyBiosProtocolGuid. It may be removed if a Library class is created to
+ #abstract away definition in Framework specification or PI spec incorporates the Legacy Booting Protocols.
+ #
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+
+
+[LibraryClasses]
+ DevicePathLib
+ PeCoffGetEntryPointLib
+ BaseLib
+ HobLib
+ UefiRuntimeServicesTableLib
+ DxeServicesTableLib
+ MemoryAllocationLib
+ UefiLib
+ UefiBootServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ PrintLib
+ PcdLib
+ PerformanceLib
+ TimerLib
+
+
+[Guids]
+ gEfiVT100PlusGuid # ALWAYS_CONSUMED
+ gEfiMemoryTypeInformationGuid # ALWAYS_CONSUMED
+ gEfiVTUTF8Guid # ALWAYS_CONSUMED
+ gEfiHobListGuid # ALWAYS_CONSUMED
+ gEfiShellFileGuid # ALWAYS_CONSUMED
+ gEfiGlobalVariableGuid # ALWAYS_CONSUMED
+ gEfiVT100Guid # ALWAYS_CONSUMED
+ gEfiFileInfoGuid # ALWAYS_CONSUMED
+ gEfiPcAnsiGuid # ALWAYS_CONSUMED
+ gEfiGenericPlatformVariableGuid # ALWAYS_CONSUMED
+
+
+[Protocols]
+ gEfiSimpleFileSystemProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiSimpleTextOutProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiPciIoProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiLoadedImageProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiDevicePathToTextProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiSimpleNetworkProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiDebugPortProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiSimpleTextInProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiBlockIoProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiFirmwareVolume2ProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiLegacyBiosProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiCpuArchProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPlatformBootTimeOutDefault
\ No newline at end of file diff --git a/MdeModulePkg/Library/GenericBdsLib/GenericBdsLib.msa b/MdeModulePkg/Library/GenericBdsLib/GenericBdsLib.msa new file mode 100644 index 0000000000..076d7b91dc --- /dev/null +++ b/MdeModulePkg/Library/GenericBdsLib/GenericBdsLib.msa @@ -0,0 +1,159 @@ +<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <MsaHeader>
+ <ModuleName>GenericBdsLib</ModuleName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <GuidValue>e405ec31-ccaa-4dd4-83e8-0aec01703f7e</GuidValue>
+ <Version>1.0</Version>
+ <Abstract>Component name for module GenericBdsLib</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2007, Intel Corporation. All rights reserved.</Copyright>
+ <License>All rights reserved. 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.</License>
+ <Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
+ </MsaHeader>
+ <ModuleDefinitions>
+ <SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>
+ <BinaryModule>false</BinaryModule>
+ <OutputFileBasename>GenericBdsLib</OutputFileBasename>
+ </ModuleDefinitions>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>PrintLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>DebugLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>BaseMemoryLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiBootServicesTableLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>MemoryAllocationLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>DxeServicesTableLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiRuntimeServicesTableLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>HobLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>BaseLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>DevicePathLib</Keyword>
+ </LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename SupArchList="IPF">Ipf\BmMachine.h</Filename>
+ <Filename>R8Lib.h</Filename>
+ <Filename SupArchList="X64">x64\BmMachine.h</Filename>
+ <Filename>BdsLib.h</Filename>
+ <Filename>BdsBoot.c</Filename>
+ <Filename SupArchList="IA32">Ia32\BmMachine.h</Filename>
+ <Filename SupArchList="X64">x64\ClearDr.asm</Filename>
+ <Filename SupArchList="EBC">Ebc\BmMachine.h</Filename>
+ <Filename>BdsConsole.c</Filename>
+ <Filename>R8Lib.c</Filename>
+ <Filename SupArchList="IA32">Ia32\ClearDr.asm</Filename>
+ <Filename>BdsMisc.c</Filename>
+ <Filename>BdsConnect.c</Filename>
+ <Filename>Performance.c</Filename>
+ <Filename>DevicePath.c</Filename>
+ <Filename SupArchList="IPF">Ipf\ShadowRom.c</Filename>
+ <Filename>Performance.h</Filename>
+ </SourceFiles>
+ <PackageDependencies>
+ <Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>
+ <Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>
+ </PackageDependencies>
+ <Protocols>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiDevicePathProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiCpuArchProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiLegacyBiosProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiFirmwareVolumeProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiBlockIoProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiSimpleTextInProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiDebugPortProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiSimpleNetworkProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiFormBrowserProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiDevicePathToTextProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiLoadedImageProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiPciIoProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiSimpleTextOutProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiSimpleFileSystemProtocolGuid</ProtocolCName>
+ </Protocol>
+ </Protocols>
+ <Guids>
+ <GuidCNames Usage="ALWAYS_CONSUMED">
+ <GuidCName>gEfiPcAnsiGuid</GuidCName>
+ </GuidCNames>
+ <GuidCNames Usage="ALWAYS_CONSUMED">
+ <GuidCName>gEfiFileInfoGuid</GuidCName>
+ </GuidCNames>
+ <GuidCNames Usage="ALWAYS_CONSUMED">
+ <GuidCName>gEfiVT100Guid</GuidCName>
+ </GuidCNames>
+ <GuidCNames Usage="ALWAYS_CONSUMED">
+ <GuidCName>gEfiGlobalVariableGuid</GuidCName>
+ </GuidCNames>
+ <GuidCNames Usage="ALWAYS_CONSUMED">
+ <GuidCName>gEfiShellFileGuid</GuidCName>
+ </GuidCNames>
+ <GuidCNames Usage="ALWAYS_CONSUMED">
+ <GuidCName>gEfiHobListGuid</GuidCName>
+ </GuidCNames>
+ <GuidCNames Usage="ALWAYS_CONSUMED">
+ <GuidCName>gEfiVTUTF8Guid</GuidCName>
+ </GuidCNames>
+ <GuidCNames Usage="ALWAYS_CONSUMED">
+ <GuidCName>gEfiMemoryTypeInformationGuid</GuidCName>
+ </GuidCNames>
+ <GuidCNames Usage="ALWAYS_CONSUMED">
+ <GuidCName>gEfiVT100PlusGuid</GuidCName>
+ </GuidCNames>
+ </Guids>
+ <Externs>
+ <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
+ <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
+ </Externs>
+</ModuleSurfaceArea>
\ No newline at end of file diff --git a/MdeModulePkg/Library/GenericBdsLib/Ia32/BmMachine.h b/MdeModulePkg/Library/GenericBdsLib/Ia32/BmMachine.h new file mode 100644 index 0000000000..e0b1fcace5 --- /dev/null +++ b/MdeModulePkg/Library/GenericBdsLib/Ia32/BmMachine.h @@ -0,0 +1,34 @@ +/** @file + +Copyright (c) 2004 - 2006, Intel Corporation +All rights reserved. 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. + +Module Name: + + BmMachine.h + +Abstract: + + Boot Manager Machine type + + + +Revision History + + +**/ + +#ifndef _BM_MACHINE_H +#define _BM_MACHINE_H + +//@MT:#include "CpuIA32.h" + +#define DEFAULT_REMOVABLE_FILE_NAME L"\\EFI\\BOOT\\BOOTIA32.EFI" + +#endif diff --git a/MdeModulePkg/Library/GenericBdsLib/Ia32/ClearDr.asm b/MdeModulePkg/Library/GenericBdsLib/Ia32/ClearDr.asm new file mode 100644 index 0000000000..c4c16655a4 --- /dev/null +++ b/MdeModulePkg/Library/GenericBdsLib/Ia32/ClearDr.asm @@ -0,0 +1,43 @@ + title ClearDr.asm +;------------------------------------------------------------------------------ +; +; Copyright (c) 2004, Intel Corporation +; All rights reserved. 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. +; +; Module Name: +; +; ClearDr.asm +; +; Abstract: +; +; Clear dr0 dr1 register +; +;------------------------------------------------------------------------------ + + .686 + .MODEL FLAT,C + .CODE + +;------------------------------------------------------------------------------ +; VOID +; ClearDebugRegisters ( +; VOID +; ) +;------------------------------------------------------------------------------ +ClearDebugRegisters PROC PUBLIC + push eax + xor eax, eax + mov dr0, eax + mov dr1, eax + pop eax + ret +ClearDebugRegisters ENDP + +END + diff --git a/MdeModulePkg/Library/GenericBdsLib/InternalBdsLib.h b/MdeModulePkg/Library/GenericBdsLib/InternalBdsLib.h new file mode 100644 index 0000000000..cae57b9e18 --- /dev/null +++ b/MdeModulePkg/Library/GenericBdsLib/InternalBdsLib.h @@ -0,0 +1,102 @@ +/** @file + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. 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. + +Module Name: + + InternalBdsLib.h + +Abstract: + + BDS library definition, include the file and data structure + + +**/ + +#ifndef _INTERNAL_BDS_LIB_H_ +#define _INTERNAL_BDS_LIB_H_ + +#include <PiDxe.h> + +#include <IndustryStandard/Pci22.h> + +#include <Protocol/BlockIo.h> +#include <Protocol/LoadedImage.h> +#include <Protocol/Cpu.h> +#include <Protocol/SimpleFileSystem.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/DevicePathToText.h> +#include <Protocol/FirmwareVolume2.h> +#include <Protocol/PciIo.h> +#include <Protocol/AcpiS3Save.h> +#include <Protocol/Performance.h> + +#include <Guid/MemoryTypeInformation.h> +#include <Guid/FileInfo.h> +#include <Guid/GlobalVariable.h> +#include <Guid/PcAnsi.h> +#include <Guid/ShellFile.h> +#include <Guid/HobList.h> +#include <Guid/GenericPlatformVariable.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/IfrSupportLib.h> +#include <Library/PeCoffGetEntryPointLib.h> +#include <Library/GenericBdsLib.h> +#include <Library/TimerLib.h> + +#include "BmMachine.h" + +#include "R8Lib.h" + +#define PERFORMANCE_SIGNATURE EFI_SIGNATURE_32 ('P', 'e', 'r', 'f') +#define PERF_TOKEN_SIZE 28 +#define PERF_TOKEN_LENGTH (PERF_TOKEN_SIZE - 1) +#define PERF_PEI_ENTRY_MAX_NUM 50 + +typedef struct { + CHAR8 Token[PERF_TOKEN_SIZE]; + UINT32 Duration; +} PERF_DATA; + +typedef struct { + UINT64 BootToOs; + UINT64 S3Resume; + UINT32 S3EntryNum; + PERF_DATA S3Entry[PERF_PEI_ENTRY_MAX_NUM]; + UINT64 CpuFreq; + UINT64 BDSRaw; + UINT32 Count; + UINT32 Signiture; +} PERF_HEADER; + +VOID +WriteBootToOsPerformanceData ( + VOID + ); + +#endif // _BDS_LIB_H_ diff --git a/MdeModulePkg/Library/GenericBdsLib/Ipf/BmMachine.h b/MdeModulePkg/Library/GenericBdsLib/Ipf/BmMachine.h new file mode 100644 index 0000000000..e9afc8a293 --- /dev/null +++ b/MdeModulePkg/Library/GenericBdsLib/Ipf/BmMachine.h @@ -0,0 +1,34 @@ +/** @file + +Copyright (c) 2004 - 2006, Intel Corporation +All rights reserved. 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. + +Module Name: + + BmMachine.h + +Abstract: + + Boot Manager Machine type + + + +Revision History + + +**/ + +#ifndef _BM_MACHINE_H +#define _BM_MACHINE_H + +//@MT:#include "CpuIA64.h" + +#define DEFAULT_REMOVABLE_FILE_NAME L"\\EFI\\BOOT\\BOOTIA64.EFI" + +#endif diff --git a/MdeModulePkg/Library/GenericBdsLib/Ipf/ShadowRom.c b/MdeModulePkg/Library/GenericBdsLib/Ipf/ShadowRom.c new file mode 100644 index 0000000000..b1bec9db6e --- /dev/null +++ b/MdeModulePkg/Library/GenericBdsLib/Ipf/ShadowRom.c @@ -0,0 +1,56 @@ +/** @file + +Copyright (c) 2004, Intel Corporation +All rights reserved. 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. + +Module Name: + + ShadowRom.c + +Abstract: + + Shadow all option rom + +Revision History + + +**/ + +//@MT:#include "Tiano.h" +//@MT:#include "EfiDriverLib.h" + +//@MT:#include EFI_PROTOCOL_DEFINITION (LegacyBios) + +#include "InternalBdsLib.h" + +UINT8 mShadowRomFlag = 0; + +VOID +ShadowAllOptionRom() +{ + EFI_STATUS Status; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + // + // Rom shadow only do once. + // + if (mShadowRomFlag == 0) { + Status = gBS->LocateProtocol ( + &gEfiLegacyBiosProtocolGuid, + NULL, + (VOID **) &LegacyBios + ); + if (!EFI_ERROR (Status)) { + LegacyBios->PrepareToBootEfi (LegacyBios, NULL, NULL); + } + + mShadowRomFlag = 1; + } + + return ; +} diff --git a/MdeModulePkg/Library/GenericBdsLib/Performance.c b/MdeModulePkg/Library/GenericBdsLib/Performance.c new file mode 100644 index 0000000000..0a42428a06 --- /dev/null +++ b/MdeModulePkg/Library/GenericBdsLib/Performance.c @@ -0,0 +1,326 @@ +/** @file + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. 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. + +Module Name: + + Performance.c + +Abstract: + + 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. + + +**/ + +#include "InternalBdsLib.h" + +STATIC PERF_HEADER mPerfHeader; +STATIC PERF_DATA mPerfData; + +STATIC +VOID +GetShortPdbFileName ( + CHAR8 *PdbFileName, + CHAR8 *GaugeString + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + UINTN Index; + UINTN Index1; + UINTN StartIndex; + UINTN EndIndex; + + if (PdbFileName == NULL) { + AsciiStrCpy (GaugeString, " "); + } 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 - 1) { + break; + } + } + + GaugeString[Index1] = 0; + } + + return ; +} + +STATIC +VOID +GetNameFromHandle ( + IN EFI_HANDLE Handle, + OUT CHAR8 *GaugeString + ) +{ + EFI_STATUS Status; + EFI_LOADED_IMAGE_PROTOCOL *Image; + CHAR8 *PdbFileName; + EFI_DRIVER_BINDING_PROTOCOL *DriverBinding; + + AsciiStrCpy (GaugeString, " "); + + // + // 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 ; +} + +VOID +WriteBootToOsPerformanceData ( + VOID + ) +/*++ + +Routine Description: + + Allocates a block of memory and writes performance data of booting to OS into it. + +Arguments: + + None + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS AcpiLowMemoryBase; + UINT32 AcpiLowMemoryLength; + UINT32 LimitCount; + EFI_HANDLE *Handles; + UINTN NoHandles; + CHAR8 GaugeString[PERF_TOKEN_LENGTH]; + 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; + + // + // Retrive time stamp count as early as possilbe + // + 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; + } + + AcpiLowMemoryLength = 0x2000; + + // + // Allocate a block of memory that contain performance data to OS + // + Status = gBS->AllocatePages ( + AllocateAnyPages, + EfiACPIReclaimMemory, + EFI_SIZE_TO_PAGES (AcpiLowMemoryLength), + &AcpiLowMemoryBase + ); + if (EFI_ERROR (Status)) { + return ; + } + + + Ptr = (UINT8 *) ((UINT32) AcpiLowMemoryBase + sizeof (PERF_HEADER)); + LimitCount = (AcpiLowMemoryLength - sizeof (PERF_HEADER)) / sizeof (PERF_DATA); + + // + // Put Detailed performance data into memory + // + Handles = NULL; + Status = gBS->LocateHandleBuffer ( + AllHandles, + NULL, + NULL, + &NoHandles, + &Handles + ); + if (EFI_ERROR (Status)) { + gBS->FreePages (AcpiLowMemoryBase, 1); + return ; + } + // + // Get DXE drivers performance + // + for (Index = 0; Index < NoHandles; Index++) { + Ticker = 0; + LogEntryKey = 0; + while ((LogEntryKey = GetPerformanceMeasurement ( + LogEntryKey, + &Handle, + &Token, + &Module, + &StartTicker, + &EndTicker)) != 0) { + if ((Handle == Handles[Index]) && (EndTicker != 0)) { + Ticker += CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker); + } + } + + Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq); + + if (Duration > 0) { + + GetNameFromHandle (Handles[Index], GaugeString); + + AsciiStrCpy (mPerfData.Token, GaugeString); + mPerfData.Duration = Duration; + + CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA)); + Ptr += sizeof (PERF_DATA); + + mPerfHeader.Count++; + if (mPerfHeader.Count == LimitCount) { + goto Done; + } + } + } + + FreePool (Handles); + + // + // Get inserted performance data + // + LogEntryKey = 0; + while ((LogEntryKey = GetPerformanceMeasurement ( + LogEntryKey, + &Handle, + &Token, + &Module, + &StartTicker, + &EndTicker)) != 0) { + if (Handle == NULL && EndTicker != 0) { + + ZeroMem (&mPerfData, sizeof (PERF_DATA)); + + AsciiStrnCpy (mPerfData.Token, Token, PERF_TOKEN_LENGTH); + 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; + } + } + } + +Done: + + mPerfHeader.Signiture = PERFORMANCE_SIGNATURE; + + // + // Put performance data to memory + // + CopyMem ( + (UINTN *) (UINTN) AcpiLowMemoryBase, + &mPerfHeader, + sizeof (PERF_HEADER) + ); + + gRT->SetVariable ( + L"PerfDataMemAddr", + &gEfiGenericPlatformVariableGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof (EFI_PHYSICAL_ADDRESS), + &AcpiLowMemoryBase + ); + + return ; +} diff --git a/MdeModulePkg/Library/GenericBdsLib/R8Lib.c b/MdeModulePkg/Library/GenericBdsLib/R8Lib.c new file mode 100644 index 0000000000..537dc123da --- /dev/null +++ b/MdeModulePkg/Library/GenericBdsLib/R8Lib.c @@ -0,0 +1,114 @@ +/**@file + Copyright (c) 2007, Intel Corporation + + All rights reserved. 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" + +/** + Get current boot mode. + + @param HobStart Start pointer of hob list + @param BootMode Current boot mode recorded in PHIT hob + + @retval EFI_NOT_FOUND Invalid hob header + @retval EFI_SUCCESS Boot mode found + +**/ +EFI_STATUS +R8_GetHobBootMode ( + IN VOID *HobStart, + OUT EFI_BOOT_MODE *BootMode + ) +{ + // + // Porting Guide: + // This library interface is simply obsolete. + // Include the source code to user code. + // In fact, since EFI_HANDOFF_HOB must be the first Hob, + // the following code can retrieve boot mode. + // + // EFI_HOB_HANDOFF_INFO_TABLE *HandOffHob; + // + // HandOffHob = GetHobList (); + // ASSERT (HandOffHob->Header.HobType == EFI_HOB_TYPE_HANDOFF); + // + // BootMode = HandOffHob->BootMode; + // + EFI_PEI_HOB_POINTERS Hob; + + Hob.Raw = HobStart; + if (Hob.Header->HobType != EFI_HOB_TYPE_HANDOFF) { + return EFI_NOT_FOUND; + } + + *BootMode = Hob.HandoffInformationTable->BootMode; + return EFI_SUCCESS; +} + + + + +/** + Get the next guid hob. + + @param HobStart A pointer to the start hob. + @param Guid A pointer to a guid. + @param Buffer A pointer to the buffer. + @param BufferSize Buffer size. + + @retval EFI_NOT_FOUND Next Guid hob not found + @retval EFI_SUCCESS Next Guid hob found and data for this Guid got + @retval EFI_INVALID_PARAMETER invalid parameter + +**/ +EFI_STATUS +R8_GetNextGuidHob ( + IN OUT VOID **HobStart, + IN EFI_GUID * Guid, + OUT VOID **Buffer, + OUT UINTN *BufferSize OPTIONAL + ) +{ + // + // Porting Guide: + // This library interface is changed substantially with R9 counerpart GetNextGuidHob (). + // 1. R9 GetNextGuidHob has two parameters and returns the matched GUID HOB from the StartHob. + // 2. R9 GetNextGuidHob does not strip the HOB header, so caller is required to apply + // GET_GUID_HOB_DATA () and GET_GUID_HOB_DATA_SIZE () to extract the data section and its + // size info respectively. + // 3. this function does not skip the starting HOB pointer unconditionally: + // it returns HobStart back if HobStart itself meets the requirement; + // caller is required to use GET_NEXT_HOB() if it wishes to skip current HobStart. + // + EFI_PEI_HOB_POINTERS GuidHob; + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + GuidHob.Raw = GetNextGuidHob (Guid, *HobStart); + if (GuidHob.Raw == NULL) { + return EFI_NOT_FOUND; + } + + *Buffer = GET_GUID_HOB_DATA (GuidHob.Guid); + if (BufferSize != NULL) { + *BufferSize = GET_GUID_HOB_DATA_SIZE (GuidHob.Guid); + } + + *HobStart = GET_NEXT_HOB (GuidHob); + + return EFI_SUCCESS; +} + + diff --git a/MdeModulePkg/Library/GenericBdsLib/R8Lib.h b/MdeModulePkg/Library/GenericBdsLib/R8Lib.h new file mode 100644 index 0000000000..f62de991b4 --- /dev/null +++ b/MdeModulePkg/Library/GenericBdsLib/R8Lib.h @@ -0,0 +1,59 @@ +/**@file + Copyright (c) 2007, Intel Corporation + + All rights reserved. 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. + + +**/ + + + +/** + Get current boot mode. + + @param HobStart Start pointer of hob list + @param BootMode Current boot mode recorded in PHIT hob + + @retval EFI_NOT_FOUND Invalid hob header + @retval EFI_SUCCESS Boot mode found + +**/ +EFI_STATUS +R8_GetHobBootMode ( + IN VOID *HobStart, + OUT EFI_BOOT_MODE *BootMode + ) +; + + + + +/** + Get the next guid hob. + + @param HobStart A pointer to the start hob. + @param Guid A pointer to a guid. + @param Buffer A pointer to the buffer. + @param BufferSize Buffer size. + + @retval EFI_NOT_FOUND Next Guid hob not found + @retval EFI_SUCCESS Next Guid hob found and data for this Guid got + @retval EFI_INVALID_PARAMETER invalid parameter + +**/ +EFI_STATUS +R8_GetNextGuidHob ( + IN OUT VOID **HobStart, + IN EFI_GUID * Guid, + OUT VOID **Buffer, + OUT UINTN *BufferSize OPTIONAL + ) +; + + diff --git a/MdeModulePkg/Library/GenericBdsLib/x64/BmMachine.h b/MdeModulePkg/Library/GenericBdsLib/x64/BmMachine.h new file mode 100644 index 0000000000..a646371e59 --- /dev/null +++ b/MdeModulePkg/Library/GenericBdsLib/x64/BmMachine.h @@ -0,0 +1,34 @@ +/** @file + +Copyright (c) 2005 - 2006, Intel Corporation +All rights reserved. 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. + +Module Name: + + BmMachine.h + +Abstract: + + Boot Manager Machine type + + + +Revision History + + +**/ + +#ifndef _BM_MACHINE_H +#define _BM_MACHINE_H + +//@MT:#include "CpuIA32.h" + +#define DEFAULT_REMOVABLE_FILE_NAME L"\\EFI\\BOOT\\BOOTX64.EFI" + +#endif diff --git a/MdeModulePkg/Library/GenericBdsLib/x64/ClearDr.asm b/MdeModulePkg/Library/GenericBdsLib/x64/ClearDr.asm new file mode 100644 index 0000000000..83d198df1f --- /dev/null +++ b/MdeModulePkg/Library/GenericBdsLib/x64/ClearDr.asm @@ -0,0 +1,41 @@ + title ClearDr.asm +;------------------------------------------------------------------------------ +; +; Copyright (c) 2005, Intel Corporation +; All rights reserved. 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. +; +; Module Name: +; +; ClearDr.asm +; +; Abstract: +; +; Clear dr0 dr1 register +; +;------------------------------------------------------------------------------ + +text SEGMENT + +;------------------------------------------------------------------------------ +; VOID +; ClearDebugRegisters ( +; VOID +; ) +;------------------------------------------------------------------------------ +ClearDebugRegisters PROC PUBLIC + push rax + xor rax, rax + mov dr0, rax + mov dr1, rax + pop rax + ret +ClearDebugRegisters ENDP + +END + diff --git a/MdeModulePkg/Library/GraphicsLib/Graphics.c b/MdeModulePkg/Library/GraphicsLib/Graphics.c new file mode 100644 index 0000000000..10b144c944 --- /dev/null +++ b/MdeModulePkg/Library/GraphicsLib/Graphics.c @@ -0,0 +1,892 @@ +/**@file
+ Support for Basic Graphics operations.
+
+ BugBug: Currently *.BMP files are supported. This will be replaced
+ when Tiano graphics format is supported.
+
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. 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 <PiDxe.h>
+
+#include <Protocol/SimpleTextOut.h>
+#include <Protocol/OEMBadging.h>
+#include <Protocol/ConsoleControl.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/UgaDraw.h>
+#include <Protocol/HiiFont.h>
+#include <Protocol/HiiImage.h>
+
+#include <Guid/Bmp.h>
+
+#include <Library/GraphicsLib.h>
+#include <Library/PrintLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DxePiLib.h>
+
+STATIC EFI_GRAPHICS_OUTPUT_BLT_PIXEL mEfiColors[16] = {
+ { 0x00, 0x00, 0x00, 0x00 },
+ { 0x98, 0x00, 0x00, 0x00 },
+ { 0x00, 0x98, 0x00, 0x00 },
+ { 0x98, 0x98, 0x00, 0x00 },
+ { 0x00, 0x00, 0x98, 0x00 },
+ { 0x98, 0x00, 0x98, 0x00 },
+ { 0x00, 0x98, 0x98, 0x00 },
+ { 0x98, 0x98, 0x98, 0x00 },
+ { 0x10, 0x10, 0x10, 0x00 },
+ { 0xff, 0x10, 0x10, 0x00 },
+ { 0x10, 0xff, 0x10, 0x00 },
+ { 0xff, 0xff, 0x10, 0x00 },
+ { 0x10, 0x10, 0xff, 0x00 },
+ { 0xf0, 0x10, 0xff, 0x00 },
+ { 0x10, 0xff, 0xff, 0x00 },
+ { 0xff, 0xff, 0xff, 0x00 }
+};
+
+
+EFI_STATUS
+GetGraphicsBitMapFromFV (
+ IN EFI_GUID *FileNameGuid,
+ OUT VOID **Image,
+ OUT UINTN *ImageSize
+ )
+/*++
+
+Routine Description:
+
+ Return the graphics image file named FileNameGuid into Image and return it's
+ size in ImageSize. All Firmware Volumes (FV) in the system are searched for the
+ file name.
+
+Arguments:
+
+ FileNameGuid - File Name of graphics file in the FV(s).
+
+ Image - Pointer to pointer to return graphics image. If NULL, a
+ buffer will be allocated.
+
+ ImageSize - Size of the graphics Image in bytes. Zero if no image found.
+
+
+Returns:
+
+ EFI_SUCCESS - Image and ImageSize are valid.
+ EFI_BUFFER_TOO_SMALL - Image not big enough. ImageSize has required size
+ EFI_NOT_FOUND - FileNameGuid not found
+
+--*/
+{
+ return GetGraphicsBitMapFromFVEx (NULL, FileNameGuid, Image, ImageSize);
+}
+
+EFI_STATUS
+GetGraphicsBitMapFromFVEx (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_GUID *FileNameGuid,
+ OUT VOID **Image,
+ OUT UINTN *ImageSize
+ )
+/*++
+
+Routine Description:
+
+ Return the graphics image file named FileNameGuid into Image and return it's
+ size in ImageSize. All Firmware Volumes (FV) in the system are searched for the
+ file name.
+
+Arguments:
+
+ ImageHandle - The driver image handle of the caller. The parameter is used to
+ optimize the loading of the image file so that the FV from which
+ the driver image is loaded will be tried first.
+
+ FileNameGuid - File Name of graphics file in the FV(s).
+
+ Image - Pointer to pointer to return graphics image. If NULL, a
+ buffer will be allocated.
+
+ ImageSize - Size of the graphics Image in bytes. Zero if no image found.
+
+
+Returns:
+
+ EFI_SUCCESS - Image and ImageSize are valid.
+ EFI_BUFFER_TOO_SMALL - Image not big enough. ImageSize has required size
+ EFI_NOT_FOUND - FileNameGuid not found
+
+--*/
+{
+ return PiLibGetSectionFromCurrentFv (
+ FileNameGuid,
+ EFI_SECTION_RAW,
+ 0,
+ Image,
+ ImageSize
+ );
+}
+
+
+EFI_STATUS
+ConvertBmpToGopBlt (
+ IN VOID *BmpImage,
+ IN UINTN BmpImageSize,
+ IN OUT VOID **GopBlt,
+ IN OUT UINTN *GopBltSize,
+ OUT UINTN *PixelHeight,
+ OUT UINTN *PixelWidth
+ )
+/*++
+
+Routine Description:
+
+ Convert a *.BMP graphics image to a GOP/UGA 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.
+
+Arguments:
+
+ BmpImage - Pointer to BMP file
+
+ BmpImageSize - Number of bytes in BmpImage
+
+ GopBlt - Buffer containing GOP version of BmpImage.
+
+ GopBltSize - Size of GopBlt in bytes.
+
+ PixelHeight - Height of GopBlt/BmpImage in pixels
+
+ PixelWidth - Width of GopBlt/BmpImage in pixels
+
+
+Returns:
+
+ EFI_SUCCESS - GopBlt and GopBltSize are returned.
+ EFI_UNSUPPORTED - BmpImage is not a valid *.BMP image
+ EFI_BUFFER_TOO_SMALL - The passed in GopBlt buffer is not big enough.
+ GopBltSize will contain the required size.
+ EFI_OUT_OF_RESOURCES - No enough buffer to allocate
+
+--*/
+{
+ UINT8 *Image;
+ UINT8 *ImageHeader;
+ BMP_IMAGE_HEADER *BmpHeader;
+ BMP_COLOR_MAP *BmpColorMap;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
+ UINTN BltBufferSize;
+ UINTN Index;
+ UINTN Height;
+ UINTN Width;
+ UINTN ImageIndex;
+ BOOLEAN IsAllocated;
+
+ BmpHeader = (BMP_IMAGE_HEADER *) BmpImage;
+ if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M') {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (BmpHeader->CompressionType != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Calculate Color Map offset in the image.
+ //
+ Image = BmpImage;
+ BmpColorMap = (BMP_COLOR_MAP *) (Image + sizeof (BMP_IMAGE_HEADER));
+
+ //
+ // Calculate graphics image data address in the image
+ //
+ Image = ((UINT8 *) BmpImage) + BmpHeader->ImageOffset;
+ ImageHeader = Image;
+
+ BltBufferSize = BmpHeader->PixelWidth * BmpHeader->PixelHeight * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
+ IsAllocated = FALSE;
+ if (*GopBlt == NULL) {
+ *GopBltSize = BltBufferSize;
+ *GopBlt = AllocatePool (*GopBltSize);
+ IsAllocated = TRUE;
+ if (*GopBlt == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ if (*GopBltSize < BltBufferSize) {
+ *GopBltSize = 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 1bit 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 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 BMP Palette to 24-bit color
+ //
+ Blt->Red = BmpColorMap[*Image].Red;
+ Blt->Green = BmpColorMap[*Image].Green;
+ Blt->Blue = BmpColorMap[*Image].Blue;
+ break;
+
+ case 24:
+ Blt->Blue = *Image++;
+ Blt->Green = *Image++;
+ Blt->Red = *Image;
+ break;
+
+ default:
+ if (IsAllocated) {
+ gBS->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;
+}
+
+
+EFI_STATUS
+LockKeyboards (
+ IN CHAR16 *Password
+ )
+/*++
+
+Routine Description:
+ Use Console Control Protocol to lock the Console In Spliter virtual handle.
+ This is the ConInHandle and ConIn handle in the EFI system table. All key
+ presses will be ignored until the Password is typed in. The only way to
+ disable the password is to type it in to a ConIn device.
+
+Arguments:
+ Password - Password used to lock ConIn device
+
+
+Returns:
+
+ EFI_SUCCESS - ConsoleControl has been flipped to graphics and logo
+ displayed.
+ EFI_UNSUPPORTED - Logo not found
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl;
+
+ Status = gBS->LocateProtocol (&gEfiConsoleControlProtocolGuid, NULL, (VOID **) &ConsoleControl);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = ConsoleControl->LockStdIn (ConsoleControl, Password);
+ return Status;
+}
+
+
+EFI_STATUS
+EnableQuietBoot (
+ IN EFI_GUID *LogoFile
+ )
+/*++
+
+Routine Description:
+
+ Use Console Control to turn off UGA based Simple Text Out consoles from going
+ to the UGA device. Put up LogoFile on every UGA device that is a console
+
+Arguments:
+
+ LogoFile - File name of logo to display on the center of the screen.
+
+
+Returns:
+
+ EFI_SUCCESS - ConsoleControl has been flipped to graphics and logo
+ displayed.
+ EFI_UNSUPPORTED - Logo not found
+
+--*/
+{
+ return EnableQuietBootEx (LogoFile, NULL);
+}
+
+EFI_STATUS
+EnableQuietBootEx (
+ IN EFI_GUID *LogoFile,
+ IN EFI_HANDLE ImageHandle
+ )
+/*++
+
+Routine Description:
+
+ Use Console Control to turn off GOP/UGA based Simple Text Out consoles from going
+ to the GOP/UGA device. Put up LogoFile on every GOP/UGA device that is a console
+
+Arguments:
+
+ LogoFile - File name of logo to display on the center of the screen.
+ ImageHandle - The driver image handle of the caller. The parameter is used to
+ optimize the loading of the logo file so that the FV from which
+ the driver image is loaded will be tried first.
+
+
+Returns:
+
+ EFI_SUCCESS - ConsoleControl has been flipped to graphics and logo
+ displayed.
+ EFI_UNSUPPORTED - Logo not found
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl;
+ 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;
+
+ Status = gBS->LocateProtocol (&gEfiConsoleControlProtocolGuid, NULL, (VOID**)&ConsoleControl);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ UgaDraw = NULL;
+ //
+ // Try to open GOP first
+ //
+ Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID**)&GraphicsOutput);
+ if (EFI_ERROR (Status)) {
+ GraphicsOutput = NULL;
+ //
+ // Open GOP failed, try to open UGA
+ //
+ Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID**)&UgaDraw);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ Badging = NULL;
+ Status = gBS->LocateProtocol (&gEfiOEMBadgingProtocolGuid, NULL, (VOID**)&Badging);
+
+ ConsoleControl->SetMode (ConsoleControl, EfiConsoleControlScreenGraphics);
+
+ if (GraphicsOutput != NULL) {
+ SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;
+ SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;
+ } else {
+ Status = UgaDraw->GetMode (UgaDraw, &SizeOfX, &SizeOfY, &ColorDepth, &RefreshRate);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ Instance = 0;
+ while (1) {
+ ImageData = NULL;
+ ImageSize = 0;
+
+ if (Badging != NULL) {
+ Status = Badging->GetImage (
+ Badging,
+ &Instance,
+ &Format,
+ &ImageData,
+ &ImageSize,
+ &Attribute,
+ &CoordinateX,
+ &CoordinateY
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Currently only support BMP format
+ //
+ if (Format != EfiBadgingFormatBMP) {
+ gBS->FreePool (ImageData);
+ continue;
+ }
+ } else {
+ Status = GetGraphicsBitMapFromFVEx (ImageHandle, LogoFile, (VOID **) &ImageData, &ImageSize);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ CoordinateX = 0;
+ CoordinateY = 0;
+ Attribute = EfiBadgingDisplayAttributeCenter;
+ }
+
+ Blt = NULL;
+ Status = ConvertBmpToGopBlt (
+ ImageData,
+ ImageSize,
+ (VOID**)&Blt,
+ &BltSize,
+ &Height,
+ &Width
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (ImageData);
+ if (Badging == NULL) {
+ return Status;
+ } else {
+ continue;
+ }
+ }
+
+ 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;
+
+ 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 {
+ Status = UgaDraw->Blt (
+ UgaDraw,
+ (EFI_UGA_PIXEL *) Blt,
+ EfiUgaBltBufferToVideo,
+ 0,
+ 0,
+ (UINTN) DestX,
+ (UINTN) DestY,
+ Width,
+ Height,
+ Width * sizeof (EFI_UGA_PIXEL)
+ );
+ }
+ }
+
+ gBS->FreePool (ImageData);
+ gBS->FreePool (Blt);
+
+ if (Badging == NULL) {
+ break;
+ }
+ }
+
+ return Status;
+}
+
+
+EFI_STATUS
+DisableQuietBoot (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Use Console Control to turn on GOP/UGA based Simple Text Out consoles. The GOP/UGA
+ Simple Text Out screens will now be synced up with all non GOP/UGA output devices
+
+Arguments:
+
+ NONE
+
+Returns:
+
+ EFI_SUCCESS - GOP/UGA devices are back in text mode and synced up.
+ EFI_UNSUPPORTED - Logo not found
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl;
+
+ Status = gBS->LocateProtocol (&gEfiConsoleControlProtocolGuid, NULL, (VOID **) &ConsoleControl);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return ConsoleControl->SetMode (ConsoleControl, EfiConsoleControlScreenText);
+}
+
+UINTN
+_IPrint (
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
+ IN EFI_UGA_DRAW_PROTOCOL *UgaDraw,
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Sto,
+ IN UINTN X,
+ IN UINTN Y,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Foreground,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Background,
+ IN CHAR16 *fmt,
+ IN VA_LIST args
+ )
+/*++
+
+Routine Description:
+
+ Display string worker for: Print, PrintAt, IPrint, IPrintAt
+
+Arguments:
+
+ GraphicsOutput - Graphics output protocol interface
+
+ UgaDraw - UGA draw protocol interface
+
+ Sto - Simple text out protocol interface
+
+ X - X coordinate to start printing
+
+ Y - Y coordinate to start printing
+
+ Foreground - Foreground color
+
+ Background - Background color
+
+ fmt - Format string
+
+ args - Print arguments
+
+Returns:
+
+ EFI_SUCCESS - success
+ EFI_OUT_OF_RESOURCES - out of resources
+
+--*/
+{
+ VOID *Buffer;
+ EFI_STATUS Status;
+ UINTN Index;
+ CHAR16 *UnicodeWeight;
+ UINT32 HorizontalResolution;
+ UINT32 VerticalResolution;
+ UINT32 ColorDepth;
+ UINT32 RefreshRate;
+ UINTN BufferLen;
+ UINTN LineBufferLen;
+ EFI_HII_FONT_PROTOCOL *HiiFont;
+ EFI_IMAGE_OUTPUT *Blt;
+ EFI_FONT_DISPLAY_INFO *FontInfo;
+
+ //
+ // For now, allocate an arbitrarily long buffer
+ //
+ Buffer = AllocateZeroPool (0x10000);
+ if (Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (GraphicsOutput != NULL) {
+ HorizontalResolution = GraphicsOutput->Mode->Info->HorizontalResolution;
+ VerticalResolution = GraphicsOutput->Mode->Info->VerticalResolution;
+ } else {
+ UgaDraw->GetMode (UgaDraw, &HorizontalResolution, &VerticalResolution, &ColorDepth, &RefreshRate);
+ }
+ ASSERT ((HorizontalResolution != 0) && (VerticalResolution !=0));
+
+ Blt = NULL;
+ FontInfo = NULL;
+ ASSERT (GraphicsOutput != NULL);
+ Status = gBS->LocateProtocol (&gEfiHiiFontProtocolGuid, NULL, (VOID **) &HiiFont);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ UnicodeVSPrint (Buffer, 0x10000, fmt, args);
+
+ UnicodeWeight = (CHAR16 *) Buffer;
+
+ for (Index = 0; UnicodeWeight[Index] != 0; Index++) {
+ if (UnicodeWeight[Index] == CHAR_BACKSPACE ||
+ UnicodeWeight[Index] == CHAR_LINEFEED ||
+ UnicodeWeight[Index] == CHAR_CARRIAGE_RETURN) {
+ UnicodeWeight[Index] = 0;
+ }
+ }
+
+ BufferLen = StrLen (Buffer);
+
+
+ LineBufferLen = sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * HorizontalResolution * EFI_GLYPH_HEIGHT;
+ if (EFI_GLYPH_WIDTH * EFI_GLYPH_HEIGHT * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * BufferLen > LineBufferLen) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Error;
+ }
+
+ Blt = (EFI_IMAGE_OUTPUT *) AllocateZeroPool (sizeof (EFI_IMAGE_OUTPUT));
+ if (Blt == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ Blt->Width = (UINT16) (HorizontalResolution);
+ Blt->Height = (UINT16) (VerticalResolution);
+ Blt->Image.Screen = GraphicsOutput;
+
+ FontInfo = (EFI_FONT_DISPLAY_INFO *) AllocateZeroPool (sizeof (EFI_FONT_DISPLAY_INFO));
+ if (FontInfo == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+ if (Foreground != NULL) {
+ CopyMem (&FontInfo->ForegroundColor, Foreground, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+ } else {
+ CopyMem (
+ &FontInfo->ForegroundColor,
+ &mEfiColors[Sto->Mode->Attribute & 0x0f],
+ sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+ );
+ }
+ if (Background != NULL) {
+ CopyMem (&FontInfo->BackgroundColor, Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+ } else {
+ CopyMem (
+ &FontInfo->BackgroundColor,
+ &mEfiColors[Sto->Mode->Attribute >> 4],
+ sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+ );
+ }
+
+ Status = HiiFont->StringToImage (
+ HiiFont,
+ EFI_HII_IGNORE_IF_NO_GLYPH | EFI_HII_DIRECT_TO_SCREEN,
+ Buffer,
+ FontInfo,
+ &Blt,
+ X,
+ Y,
+ NULL,
+ NULL,
+ NULL
+ );
+
+
+Error:
+ SafeFreePool (Blt);
+ SafeFreePool (FontInfo);
+ gBS->FreePool (Buffer);
+ return Status;
+}
+
+UINTN
+PrintXY (
+ IN UINTN X,
+ IN UINTN Y,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *ForeGround, OPTIONAL
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BackGround, OPTIONAL
+ IN CHAR16 *Fmt,
+ ...
+ )
+/*++
+
+Routine Description:
+
+ Prints a formatted unicode string to the default console
+
+Arguments:
+
+ X - X coordinate to start printing
+
+ Y - Y coordinate to start printing
+
+ ForeGround - Foreground color
+
+ BackGround - Background color
+
+ Fmt - Format string
+
+ ... - Print arguments
+
+Returns:
+
+ Length of string printed to the console
+
+--*/
+{
+ EFI_HANDLE Handle;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_UGA_DRAW_PROTOCOL *UgaDraw;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Sto;
+ EFI_STATUS Status;
+ VA_LIST Args;
+
+ VA_START (Args, Fmt);
+
+ Handle = gST->ConsoleOutHandle;
+
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiGraphicsOutputProtocolGuid,
+ (VOID**)&GraphicsOutput
+ );
+
+ UgaDraw = NULL;
+ if (EFI_ERROR (Status)) {
+ GraphicsOutput = NULL;
+
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiUgaDrawProtocolGuid,
+ (VOID**)&UgaDraw
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiSimpleTextOutProtocolGuid,
+ (VOID**)&Sto
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return _IPrint (GraphicsOutput, UgaDraw, Sto, X, Y, ForeGround, BackGround, Fmt, Args);
+}
+
diff --git a/MdeModulePkg/Library/GraphicsLib/GraphicsLib.inf b/MdeModulePkg/Library/GraphicsLib/GraphicsLib.inf new file mode 100644 index 0000000000..c7cb0afb72 --- /dev/null +++ b/MdeModulePkg/Library/GraphicsLib/GraphicsLib.inf @@ -0,0 +1,57 @@ +#/** @file
+# Graphics Library for UEFI drivers
+#
+# This library provides supports for basic graphic functions.
+# Copyright (c) 2006 - 2007, Intel Corporation.
+#
+# All rights reserved. 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 = 0x00010005
+ BASE_NAME = EdkGraphicsLib
+ FILE_GUID = 08c1a0e4-1208-47f8-a2c5-f42eabee653a
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = GraphicsLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+ EDK_RELEASE_VERSION = 0x00020000
+ EFI_SPECIFICATION_VERSION = 0x00020000
+
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+ Graphics.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseLib
+ PrintLib
+ DebugLib
+ DxePiLib
+ BaseMemoryLib
+
+[Protocols]
+ gEfiSimpleTextOutProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiGraphicsOutputProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiUgaDrawProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiConsoleControlProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiFirmwareVolume2ProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiOEMBadgingProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiHiiFontProtocolGuid # PROTOCOL ALWAYS_CONSUMED
\ No newline at end of file diff --git a/MdeModulePkg/Library/GraphicsLib/GraphicsLib.msa b/MdeModulePkg/Library/GraphicsLib/GraphicsLib.msa new file mode 100644 index 0000000000..2007ba062e --- /dev/null +++ b/MdeModulePkg/Library/GraphicsLib/GraphicsLib.msa @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <MsaHeader>
+ <ModuleName>EdkGraphicsLib</ModuleName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <GuidValue>08c1a0e4-1208-47f8-a2c5-f42eabee653a</GuidValue>
+ <Version>1.0</Version>
+ <Abstract>Graphics Library for UEFI drivers</Abstract>
+ <Description>This library provides supports for basic graphic functions.</Description>
+ <Copyright>Copyright (c) 2006 - 2007, Intel Corporation.</Copyright>
+ <License>All rights reserved. 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.</License>
+ <Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
+ </MsaHeader>
+ <ModuleDefinitions>
+ <SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>
+ <BinaryModule>false</BinaryModule>
+ <OutputFileBasename>EdkGraphicsLib</OutputFileBasename>
+ </ModuleDefinitions>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_PRODUCED" SupModuleList="DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER">
+ <Keyword>EdkGraphicsLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>PrintLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>BaseLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>MemoryAllocationLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiBootServicesTableLib</Keyword>
+ </LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>Graphics.c</Filename>
+ </SourceFiles>
+ <PackageDependencies>
+ <Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>
+ <Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>
+ </PackageDependencies>
+ <Protocols>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiOEMBadgingProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiFirmwareVolumeProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiConsoleControlProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiUgaDrawProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiGraphicsOutputProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiSimpleTextOutProtocolGuid</ProtocolCName>
+ </Protocol>
+ </Protocols>
+ <Externs>
+ <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
+ <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
+ </Externs>
+</ModuleSurfaceArea>
\ No newline at end of file diff --git a/MdeModulePkg/Library/IfrSupportLib/IfrSupportLib.inf b/MdeModulePkg/Library/IfrSupportLib/IfrSupportLib.inf new file mode 100644 index 0000000000..74b7c10895 --- /dev/null +++ b/MdeModulePkg/Library/IfrSupportLib/IfrSupportLib.inf @@ -0,0 +1,71 @@ +#/** @file
+# Component name for module UefiEfiIfrSupportLib
+#
+# FIX ME!
+# Copyright (c) 2007, Intel Corporation. All rights reserved.
+#
+# All rights reserved. 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 = 0x00010005
+ BASE_NAME = IfrSupportLib
+ FILE_GUID = bf38668e-e231-4baa-99e4-8c0e4c35dca6
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = IfrSupportLib
+ EDK_RELEASE_VERSION = 0x00020000
+ EFI_SPECIFICATION_VERSION = 0x00020000
+
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+ UefiIfrCommon.c
+ UefiIfrForm.c
+ UefiIfrLibraryInternal.h
+ UefiIfrOpCodeCreation.c
+ UefiIfrString.c
+ R8Lib.h
+ R8Lib.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ MemoryAllocationLib
+ DevicePathLib
+ BaseLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ PcdLib
+
+[Guids]
+ gEfiGlobalVariableGuid # ALWAYS_CONSUMED
+
+[Protocols]
+ gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiHiiDatabaseProtocolGuid
+ gEfiHiiStringProtocolGuid
+ gEfiHiiConfigRoutingProtocolGuid
+ gEfiFormBrowser2ProtocolGuid
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultPlatformLang
\ No newline at end of file diff --git a/MdeModulePkg/Library/IfrSupportLib/IfrSupportLib.msa b/MdeModulePkg/Library/IfrSupportLib/IfrSupportLib.msa new file mode 100644 index 0000000000..dc9d665a14 --- /dev/null +++ b/MdeModulePkg/Library/IfrSupportLib/IfrSupportLib.msa @@ -0,0 +1,74 @@ +<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <MsaHeader>
+ <ModuleName>UefiEfiIfrSupportLib</ModuleName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <GuidValue>bf38668e-e231-4baa-99e4-8c0e4c35dca6</GuidValue>
+ <Version>1.0</Version>
+ <Abstract>Component name for module UefiEfiIfrSupportLib</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2007, Intel Corporation. All rights reserved.</Copyright>
+ <License>All rights reserved. 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.</License>
+ <Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
+ </MsaHeader>
+ <ModuleDefinitions>
+ <SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>
+ <BinaryModule>false</BinaryModule>
+ <OutputFileBasename>UefiEfiIfrSupportLib</OutputFileBasename>
+ </ModuleDefinitions>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>DebugLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>BaseMemoryLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiRuntimeServicesTableLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiBootServicesTableLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>BaseLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>DevicePathLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>MemoryAllocationLib</Keyword>
+ </LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>R8Lib.c</Filename>
+ <Filename>R8Lib.h</Filename>
+ <Filename>UefiIfrString.c</Filename>
+ <Filename>UefiIfrOpCodeCreation.c</Filename>
+ <Filename>UefiIfrLibraryInternal.h</Filename>
+ <Filename>UefiIfrForm.c</Filename>
+ <Filename>UefiIfrCommon.c</Filename>
+ </SourceFiles>
+ <PackageDependencies>
+ <Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>
+ <Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>
+ </PackageDependencies>
+ <Protocols>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiDevicePathProtocolGuid</ProtocolCName>
+ </Protocol>
+ </Protocols>
+ <Guids>
+ <GuidCNames Usage="ALWAYS_CONSUMED">
+ <GuidCName>gEfiGlobalVariableGuid</GuidCName>
+ </GuidCNames>
+ </Guids>
+ <Externs>
+ <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
+ <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
+ </Externs>
+</ModuleSurfaceArea>
\ No newline at end of file diff --git a/MdeModulePkg/Library/IfrSupportLib/R8Lib.c b/MdeModulePkg/Library/IfrSupportLib/R8Lib.c new file mode 100644 index 0000000000..634bdb682d --- /dev/null +++ b/MdeModulePkg/Library/IfrSupportLib/R8Lib.c @@ -0,0 +1,241 @@ +/**@file + Copyright (c) 2007, Intel Corporation + + All rights reserved. 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 "UefiIfrLibraryInternal.h" + + +CHAR16 +InternalNibbleToHexChar ( + IN UINT8 Nibble + ) +/*++ + + Routine Description: + Converts the low nibble of a byte to hex unicode character. + + Arguments: + Nibble - lower nibble of a byte. + + Returns: + Hex unicode character. + +--*/ +{ + Nibble &= 0x0F; + if (Nibble <= 0x9) { + return (CHAR16)(Nibble + L'0'); + } + + return (CHAR16)(Nibble - 0xA + L'A'); +} + + +/** + Converts binary buffer to Unicode string. + At a minimum, any blob of data could be represented as a hex string. + + @param Str Pointer to the string. + @param HexStringBufferLength Length in bytes of buffer to hold the hex string. + Includes tailing '\0' character. If routine return + with EFI_SUCCESS, containing length of hex string + buffer. If routine return with + EFI_BUFFER_TOO_SMALL, containg length of hex + string buffer desired. + @param Buf Buffer to be converted from. + @param Len Length in bytes of the buffer to be converted. + + @retval EFI_SUCCESS Routine success. + @retval EFI_BUFFER_TOO_SMALL The hex string buffer is too small. + +**/ +EFI_STATUS +R8_BufToHexString ( + IN OUT CHAR16 *Str, + IN OUT UINTN *HexStringBufferLength, + IN UINT8 *Buf, + IN UINTN Len + ) +{ + // + // Porting Guide: + // This library interface is simply obsolete. + // Include the source code to user code. + // + UINTN Idx; + UINT8 Byte; + UINTN StrLen; + + // + // Make sure string is either passed or allocate enough. + // It takes 2 Unicode characters (4 bytes) to represent 1 byte of the binary buffer. + // Plus the Unicode termination character. + // + StrLen = Len * 2; + if (StrLen > ((*HexStringBufferLength) - 1)) { + *HexStringBufferLength = StrLen + 1; + return EFI_BUFFER_TOO_SMALL; + } + + *HexStringBufferLength = StrLen + 1; + // + // Ends the string. + // + Str[StrLen] = L'\0'; + + for (Idx = 0; Idx < Len; Idx++) { + + Byte = Buf[Idx]; + Str[StrLen - 1 - Idx * 2] = InternalNibbleToHexChar (Byte); + Str[StrLen - 2 - Idx * 2] = InternalNibbleToHexChar ((UINT8)(Byte >> 4)); + } + + return EFI_SUCCESS; +} + + + + +/** + Converts Unicode string to binary buffer. + The conversion may be partial. + The first character in the string that is not hex digit stops the conversion. + At a minimum, any blob of data could be represented as a hex string. + + @param Buf Pointer to buffer that receives the data. + @param Len Length in bytes of the buffer to hold converted + data. If routine return with EFI_SUCCESS, + containing length of converted data. If routine + return with EFI_BUFFER_TOO_SMALL, containg length + of buffer desired. + @param Str String to be converted from. + @param ConvertedStrLen Length of the Hex String consumed. + + @retval EFI_SUCCESS Routine Success. + @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold converted data. + +**/ +EFI_STATUS +R8_HexStringToBuf ( + IN OUT UINT8 *Buf, + IN OUT UINTN *Len, + IN CHAR16 *Str, + OUT UINTN *ConvertedStrLen OPTIONAL + ) +{ + // + // Porting Guide: + // This library interface is simply obsolete. + // Include the source code to user code. + // + + UINTN HexCnt; + UINTN Idx; + UINTN BufferLength; + UINT8 Digit; + UINT8 Byte; + + // + // Find out how many hex characters the string has. + // + for (Idx = 0, HexCnt = 0; R8_IsHexDigit (&Digit, Str[Idx]); Idx++, HexCnt++); + + if (HexCnt == 0) { + *Len = 0; + return EFI_SUCCESS; + } + // + // Two Unicode characters make up 1 buffer byte. Round up. + // + BufferLength = (HexCnt + 1) / 2; + + // + // Test if buffer is passed enough. + // + if (BufferLength > (*Len)) { + *Len = BufferLength; + return EFI_BUFFER_TOO_SMALL; + } + + *Len = BufferLength; + + for (Idx = 0; Idx < HexCnt; Idx++) { + + R8_IsHexDigit (&Digit, Str[HexCnt - 1 - Idx]); + + // + // For odd charaters, write the lower nibble for each buffer byte, + // and for even characters, the upper nibble. + // + if ((Idx & 1) == 0) { + Byte = Digit; + } else { + Byte = Buf[Idx / 2]; + Byte &= 0x0F; + Byte = (UINT8) (Byte | Digit << 4); + } + + Buf[Idx / 2] = Byte; + } + + if (ConvertedStrLen != NULL) { + *ConvertedStrLen = HexCnt; + } + + return EFI_SUCCESS; +} + + +/** + Determines if a Unicode character is a hexadecimal digit. + The test is case insensitive. + + @param Digit Pointer to byte that receives the value of the hex + character. + @param Char Unicode character to test. + + @retval TRUE If the character is a hexadecimal digit. + @retval FALSE Otherwise. + +**/ +BOOLEAN +R8_IsHexDigit ( + OUT UINT8 *Digit, + IN CHAR16 Char + ) +{ + // + // Porting Guide: + // This library interface is simply obsolete. + // Include the source code to user code. + // + + if ((Char >= L'0') && (Char <= L'9')) { + *Digit = (UINT8) (Char - L'0'); + return TRUE; + } + + if ((Char >= L'A') && (Char <= L'F')) { + *Digit = (UINT8) (Char - L'A' + 0x0A); + return TRUE; + } + + if ((Char >= L'a') && (Char <= L'f')) { + *Digit = (UINT8) (Char - L'a' + 0x0A); + return TRUE; + } + + return FALSE; +} + + diff --git a/MdeModulePkg/Library/IfrSupportLib/R8Lib.h b/MdeModulePkg/Library/IfrSupportLib/R8Lib.h new file mode 100644 index 0000000000..ca9b93989e --- /dev/null +++ b/MdeModulePkg/Library/IfrSupportLib/R8Lib.h @@ -0,0 +1,93 @@ +/**@file + Copyright (c) 2007, Intel Corporation + + All rights reserved. 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. + + +**/ + + + +/** + Converts binary buffer to Unicode string. + At a minimum, any blob of data could be represented as a hex string. + + @param Str Pointer to the string. + @param HexStringBufferLength Length in bytes of buffer to hold the hex string. + Includes tailing '\0' character. If routine return + with EFI_SUCCESS, containing length of hex string + buffer. If routine return with + EFI_BUFFER_TOO_SMALL, containg length of hex + string buffer desired. + @param Buf Buffer to be converted from. + @param Len Length in bytes of the buffer to be converted. + + @retval EFI_SUCCESS Routine success. + @retval EFI_BUFFER_TOO_SMALL The hex string buffer is too small. + +**/ +EFI_STATUS +R8_BufToHexString ( + IN OUT CHAR16 *Str, + IN OUT UINTN *HexStringBufferLength, + IN UINT8 *Buf, + IN UINTN Len + ) +; + + + + +/** + Converts Unicode string to binary buffer. + The conversion may be partial. + The first character in the string that is not hex digit stops the conversion. + At a minimum, any blob of data could be represented as a hex string. + + @param Buf Pointer to buffer that receives the data. + @param Len Length in bytes of the buffer to hold converted + data. If routine return with EFI_SUCCESS, + containing length of converted data. If routine + return with EFI_BUFFER_TOO_SMALL, containg length + of buffer desired. + @param Str String to be converted from. + @param ConvertedStrLen Length of the Hex String consumed. + + @retval EFI_SUCCESS Routine Success. + @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold converted data. + +**/ +EFI_STATUS +R8_HexStringToBuf ( + IN OUT UINT8 *Buf, + IN OUT UINTN *Len, + IN CHAR16 *Str, + OUT UINTN *ConvertedStrLen OPTIONAL + ) +; + +/** + Determines if a Unicode character is a hexadecimal digit. + The test is case insensitive. + + @param Digit Pointer to byte that receives the value of the hex + character. + @param Char Unicode character to test. + + @retval TRUE If the character is a hexadecimal digit. + @retval FALSE Otherwise. + +**/ +BOOLEAN +R8_IsHexDigit ( + OUT UINT8 *Digit, + IN CHAR16 Char + ) +; + diff --git a/MdeModulePkg/Library/IfrSupportLib/UefiIfrCommon.c b/MdeModulePkg/Library/IfrSupportLib/UefiIfrCommon.c new file mode 100644 index 0000000000..b2b92d132e --- /dev/null +++ b/MdeModulePkg/Library/IfrSupportLib/UefiIfrCommon.c @@ -0,0 +1,369 @@ +/** @file + +Copyright (c) 2007, Intel Corporation +All rights reserved. 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. + +Module Name: + + UefiIfrCommon.c + +Abstract: + + Common Library Routines to assist handle HII elements. + + +**/ + +#include "UefiIfrLibraryInternal.h" + +// +// Hii relative protocols +// +BOOLEAN mHiiProtocolsInitialized = FALSE; + +EFI_HII_DATABASE_PROTOCOL *gIfrLibHiiDatabase; +EFI_HII_STRING_PROTOCOL *gIfrLibHiiString; + + +/** + This function locate Hii relative protocols for later usage. + + None. + + @return None. + +**/ +VOID +LocateHiiProtocols ( + VOID + ) +{ + EFI_STATUS Status; + + if (mHiiProtocolsInitialized) { + return; + } + + Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **) &gIfrLibHiiDatabase); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol (&gEfiHiiStringProtocolGuid, NULL, (VOID **) &gIfrLibHiiString); + ASSERT_EFI_ERROR (Status); + + mHiiProtocolsInitialized = TRUE; +} + + +/** + Assemble EFI_HII_PACKAGE_LIST according to the passed in packages. + + @param NumberOfPackages Number of packages. + @param GuidId Package GUID. + + @return Pointer of EFI_HII_PACKAGE_LIST_HEADER. + +**/ +EFI_HII_PACKAGE_LIST_HEADER * +PreparePackageList ( + IN UINTN NumberOfPackages, + IN EFI_GUID *GuidId, + ... + ) +{ + VA_LIST Marker; + EFI_HII_PACKAGE_LIST_HEADER *PackageListHeader; + UINT8 *PackageListData; + UINT32 PackageListLength; + UINT32 PackageLength; + EFI_HII_PACKAGE_HEADER PackageHeader; + UINT8 *PackageArray; + UINTN Index; + + PackageListLength = sizeof (EFI_HII_PACKAGE_LIST_HEADER); + + VA_START (Marker, GuidId); + for (Index = 0; Index < NumberOfPackages; Index++) { + CopyMem (&PackageLength, VA_ARG (Marker, VOID *), sizeof (UINT32)); + PackageListLength += (PackageLength - sizeof (UINT32)); + } + VA_END (Marker); + + // + // Include the lenght of EFI_HII_PACKAGE_END + // + PackageListLength += sizeof (EFI_HII_PACKAGE_HEADER); + PackageListHeader = AllocateZeroPool (PackageListLength); + ASSERT (PackageListHeader != NULL); + CopyMem (&PackageListHeader->PackageListGuid, GuidId, sizeof (EFI_GUID)); + PackageListHeader->PackageLength = PackageListLength; + + PackageListData = ((UINT8 *) PackageListHeader) + sizeof (EFI_HII_PACKAGE_LIST_HEADER); + + VA_START (Marker, GuidId); + for (Index = 0; Index < NumberOfPackages; Index++) { + PackageArray = (UINT8 *) VA_ARG (Marker, VOID *); + CopyMem (&PackageLength, PackageArray, sizeof (UINT32)); + PackageLength -= sizeof (UINT32); + PackageArray += sizeof (UINT32); + CopyMem (PackageListData, PackageArray, PackageLength); + PackageListData += PackageLength; + } + VA_END (Marker); + + // + // Append EFI_HII_PACKAGE_END + // + PackageHeader.Type = EFI_HII_PACKAGE_END; + PackageHeader.Length = sizeof (EFI_HII_PACKAGE_HEADER); + CopyMem (PackageListData, &PackageHeader, PackageHeader.Length); + + return PackageListHeader; +} + + +/** + Find HII Handle associated with given Device Path. + + @param HiiDatabase Point to EFI_HII_DATABASE_PROTOCOL instance. + @param DevicePath Device Path associated with the HII package list + handle. + + @retval Handle HII package list Handle associated with the Device + Path. + @retval NULL Hii Package list handle is not found. + +**/ +EFI_HII_HANDLE +DevicePathToHiiHandle ( + IN EFI_HII_DATABASE_PROTOCOL *HiiDatabase, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath; + UINTN BufferSize; + UINTN HandleCount; + UINTN Index; + EFI_HANDLE *Handles; + EFI_HANDLE Handle; + UINTN Size; + EFI_HANDLE DriverHandle; + EFI_HII_HANDLE *HiiHandles; + EFI_HII_HANDLE HiiHandle; + + // + // Locate Device Path Protocol handle buffer + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiDevicePathProtocolGuid, + NULL, + &HandleCount, + &Handles + ); + if (EFI_ERROR (Status)) { + return NULL; + } + + // + // Search Driver Handle by Device Path + // + DriverHandle = NULL; + BufferSize = GetDevicePathSize (DevicePath); + for(Index = 0; Index < HandleCount; Index++) { + Handle = Handles[Index]; + gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **) &TmpDevicePath); + + // + // Check whether DevicePath match + // + Size = GetDevicePathSize (TmpDevicePath); + if ((Size == BufferSize) && CompareMem (DevicePath, TmpDevicePath, Size) == 0) { + DriverHandle = Handle; + break; + } + } + gBS->FreePool (Handles); + + if (DriverHandle == NULL) { + return NULL; + } + + // + // Retrieve all Hii Handles from HII database + // + BufferSize = 0x1000; + HiiHandles = AllocatePool (BufferSize); + ASSERT (HiiHandles != NULL); + Status = HiiDatabase->ListPackageLists ( + HiiDatabase, + EFI_HII_PACKAGE_TYPE_ALL, + NULL, + &BufferSize, + HiiHandles + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + gBS->FreePool (HiiHandles); + HiiHandles = AllocatePool (BufferSize); + ASSERT (HiiHandles != NULL); + + Status = HiiDatabase->ListPackageLists ( + HiiDatabase, + EFI_HII_PACKAGE_TYPE_ALL, + NULL, + &BufferSize, + HiiHandles + ); + } + + if (EFI_ERROR (Status)) { + gBS->FreePool (HiiHandles); + return NULL; + } + + // + // Search Hii Handle by Driver Handle + // + HiiHandle = NULL; + HandleCount = BufferSize / sizeof (EFI_HII_HANDLE); + for (Index = 0; Index < HandleCount; Index++) { + Status = HiiDatabase->GetPackageListHandle ( + HiiDatabase, + HiiHandles[Index], + &Handle + ); + if (!EFI_ERROR (Status) && (Handle == DriverHandle)) { + HiiHandle = HiiHandles[Index]; + break; + } + } + + gBS->FreePool (HiiHandles); + return HiiHandle; +} + + +/** + Determines the handles that are currently active in the database. + It's the caller's responsibility to free handle buffer. + + @param HiiDatabase A pointer to the EFI_HII_DATABASE_PROTOCOL + instance. + @param HandleBufferLength On input, a pointer to the length of the handle + buffer. On output, the length of the handle buffer + that is required for the handles found. + @param HiiHandleBuffer Pointer to an array of Hii Handles returned. + + @retval EFI_SUCCESS Get an array of Hii Handles successfully. + @retval EFI_INVALID_PARAMETER Hii is NULL. + @retval EFI_NOT_FOUND Database not found. + +**/ +EFI_STATUS +GetHiiHandles ( + IN OUT UINTN *HandleBufferLength, + OUT EFI_HII_HANDLE **HiiHandleBuffer + ) +{ + UINTN BufferLength; + EFI_STATUS Status; + + BufferLength = 0; + + LocateHiiProtocols (); + + // + // Try to find the actual buffer size for HiiHandle Buffer. + // + Status = gIfrLibHiiDatabase->ListPackageLists ( + gIfrLibHiiDatabase, + EFI_HII_PACKAGE_TYPE_ALL, + NULL, + &BufferLength, + *HiiHandleBuffer + ); + + if (Status == EFI_BUFFER_TOO_SMALL) { + *HiiHandleBuffer = AllocateZeroPool (BufferLength); + Status = gIfrLibHiiDatabase->ListPackageLists ( + gIfrLibHiiDatabase, + EFI_HII_PACKAGE_TYPE_ALL, + NULL, + &BufferLength, + *HiiHandleBuffer + ); + // + // we should not fail here. + // + ASSERT_EFI_ERROR (Status); + } + + *HandleBufferLength = BufferLength; + + return Status; +} + + +/** + Extract Hii package list GUID for given HII handle. + + @param HiiHandle Hii handle + @param Guid Package list GUID + + @retval EFI_SUCCESS Successfully extract GUID from Hii database. + +**/ +EFI_STATUS +ExtractGuidFromHiiHandle ( + IN EFI_HII_HANDLE Handle, + OUT EFI_GUID *Guid + ) +{ + EFI_STATUS Status; + UINTN BufferSize; + EFI_HII_DATABASE_PROTOCOL *HiiDatabase; + EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList; + + // + // Locate HII Database protocol + // + Status = gBS->LocateProtocol ( + &gEfiHiiDatabaseProtocolGuid, + NULL, + (VOID **) &HiiDatabase + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get HII PackageList + // + BufferSize = 0; + HiiPackageList = NULL; + Status = HiiDatabase->ExportPackageLists (HiiDatabase, Handle, &BufferSize, HiiPackageList); + if (Status == EFI_BUFFER_TOO_SMALL) { + HiiPackageList = AllocatePool (BufferSize); + ASSERT (HiiPackageList != NULL); + + Status = HiiDatabase->ExportPackageLists (HiiDatabase, Handle, &BufferSize, HiiPackageList); + } + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Extract GUID + // + CopyMem (Guid, &HiiPackageList->PackageListGuid, sizeof (EFI_GUID)); + + gBS->FreePool (HiiPackageList); + + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Library/IfrSupportLib/UefiIfrForm.c b/MdeModulePkg/Library/IfrSupportLib/UefiIfrForm.c new file mode 100644 index 0000000000..362978a0a1 --- /dev/null +++ b/MdeModulePkg/Library/IfrSupportLib/UefiIfrForm.c @@ -0,0 +1,1121 @@ +/** @file + +Copyright (c) 2007, Intel Corporation +All rights reserved. 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. + +Module Name: + + UefiIfrForm.c + +Abstract: + + Common Library Routines to assist handle HII elements. + + +**/ + +#include "UefiIfrLibraryInternal.h" + +// +// Fake <ConfigHdr> +// +UINT16 mFakeConfigHdr[] = L"GUID=00000000000000000000000000000000&NAME=0000&PATH=0"; + +STATIC +EFI_STATUS +GetPackageDataFromPackageList ( + IN EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList, + IN UINT32 PackageIndex, + OUT UINT32 *BufferLen, + OUT EFI_HII_PACKAGE_HEADER **Buffer + ) +{ + UINT32 Index; + EFI_HII_PACKAGE_HEADER *Package; + UINT32 Offset; + UINT32 PackageListLength; + EFI_HII_PACKAGE_HEADER PackageHeader = {0, 0}; + + ASSERT(HiiPackageList != NULL); + + if ((BufferLen == NULL) || (Buffer == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Package = NULL; + Index = 0; + Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER); + CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32)); + while (Offset < PackageListLength) { + Package = (EFI_HII_PACKAGE_HEADER *) (((UINT8 *) HiiPackageList) + Offset); + CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER)); + if (Index == PackageIndex) { + break; + } + Offset += PackageHeader.Length; + Index++; + } + if (Offset >= PackageListLength) { + // + // no package found in this Package List + // + return EFI_NOT_FOUND; + } + + *BufferLen = PackageHeader.Length; + *Buffer = Package; + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +UpdateFormPackageData ( + IN EFI_GUID *FormSetGuid, + IN EFI_FORM_ID FormId, + IN EFI_HII_PACKAGE_HEADER *Package, + IN UINT32 PackageLength, + IN UINT16 Label, + IN BOOLEAN Insert, + IN EFI_HII_UPDATE_DATA *Data, + OUT UINT8 **TempBuffer, + OUT UINT32 *TempBufferSize + ) +{ + UINTN AddSize; + UINT8 *BufferPos; + EFI_HII_PACKAGE_HEADER PackageHeader; + UINTN Offset; + EFI_IFR_OP_HEADER *IfrOpHdr; + BOOLEAN GetFormSet; + BOOLEAN GetForm; + UINT8 ExtendOpCode; + UINT16 LabelNumber; + BOOLEAN Updated; + EFI_IFR_OP_HEADER *AddOpCode; + + if ((TempBuffer == NULL) || (TempBufferSize == NULL)) { + return EFI_INVALID_PARAMETER; + } + + *TempBufferSize = PackageLength; + if (Data != NULL) { + *TempBufferSize += Data->Offset; + } + *TempBuffer = AllocateZeroPool (*TempBufferSize); + if (*TempBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CopyMem (*TempBuffer, Package, sizeof (EFI_HII_PACKAGE_HEADER)); + *TempBufferSize = sizeof (EFI_HII_PACKAGE_HEADER); + BufferPos = *TempBuffer + sizeof (EFI_HII_PACKAGE_HEADER); + + CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER)); + IfrOpHdr = (EFI_IFR_OP_HEADER *)((UINT8 *) Package + sizeof (EFI_HII_PACKAGE_HEADER)); + Offset = sizeof (EFI_HII_PACKAGE_HEADER); + GetFormSet = (BOOLEAN) ((FormSetGuid == NULL) ? TRUE : FALSE); + GetForm = FALSE; + Updated = FALSE; + + while (Offset < PackageHeader.Length) { + CopyMem (BufferPos, IfrOpHdr, IfrOpHdr->Length); + BufferPos += IfrOpHdr->Length; + *TempBufferSize += IfrOpHdr->Length; + + switch (IfrOpHdr->OpCode) { + case EFI_IFR_FORM_SET_OP : + if (FormSetGuid != NULL) { + if (CompareMem (&((EFI_IFR_FORM_SET *) IfrOpHdr)->Guid, FormSetGuid, sizeof (EFI_GUID)) == 0) { + GetFormSet = TRUE; + } + } + break; + + case EFI_IFR_FORM_OP: + if (CompareMem (&((EFI_IFR_FORM *) IfrOpHdr)->FormId, &FormId, sizeof (EFI_FORM_ID)) == 0) { + GetForm = TRUE; + } + break; + + case EFI_IFR_GUID_OP : + if (!GetFormSet || !GetForm || Updated) { + // + // Go to the next Op-Code + // + Offset += IfrOpHdr->Length; + IfrOpHdr = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (IfrOpHdr) + IfrOpHdr->Length); + continue; + } + + ExtendOpCode = ((EFI_IFR_GUID_LABEL *) IfrOpHdr)->ExtendOpCode; + CopyMem (&LabelNumber, &((EFI_IFR_GUID_LABEL *)IfrOpHdr)->Number, sizeof (UINT16)); + if ((ExtendOpCode != EFI_IFR_EXTEND_OP_LABEL) || (LabelNumber != Label)) { + // + // Go to the next Op-Code + // + Offset += IfrOpHdr->Length; + IfrOpHdr = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (IfrOpHdr) + IfrOpHdr->Length); + continue; + } + + if (Insert && (Data != NULL)) { + // + // insert the DataCount amount of opcodes to TempBuffer if Data is NULL remove + // DataCount amount of opcodes unless runing into a label. + // + AddOpCode = (EFI_IFR_OP_HEADER *)Data->Data; + AddSize = 0; + while (AddSize < Data->Offset) { + CopyMem (BufferPos, AddOpCode, AddOpCode->Length); + BufferPos += AddOpCode->Length; + *TempBufferSize += AddOpCode->Length; + + AddSize += AddOpCode->Length; + AddOpCode = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (AddOpCode) + AddOpCode->Length); + } + } else { + // + // Search the next Label. + // + while (TRUE) { + Offset += IfrOpHdr->Length; + // + // Search the next label and Fail if not label found. + // + if (Offset >= PackageHeader.Length) { + goto Fail; + } + IfrOpHdr = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (IfrOpHdr) + IfrOpHdr->Length); + if (IfrOpHdr->OpCode == EFI_IFR_GUID_OP) { + ExtendOpCode = ((EFI_IFR_GUID_LABEL *) IfrOpHdr)->ExtendOpCode; + if (ExtendOpCode == EFI_IFR_EXTEND_OP_LABEL) { + break; + } + } + } + + if (Data != NULL) { + AddOpCode = (EFI_IFR_OP_HEADER *)Data->Data; + AddSize = 0; + while (AddSize < Data->Offset) { + CopyMem (BufferPos, AddOpCode, AddOpCode->Length); + BufferPos += AddOpCode->Length; + *TempBufferSize += AddOpCode->Length; + + AddSize += AddOpCode->Length; + AddOpCode = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (AddOpCode) + AddOpCode->Length); + } + } + + // + // copy the next label + // + CopyMem (BufferPos, IfrOpHdr, IfrOpHdr->Length); + BufferPos += IfrOpHdr->Length; + *TempBufferSize += IfrOpHdr->Length; + } + + Updated = TRUE; + break; + default : + break; + } + + // + // Go to the next Op-Code + // + Offset += IfrOpHdr->Length; + IfrOpHdr = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (IfrOpHdr) + IfrOpHdr->Length); + } + + // + // Update the package length. + // + PackageHeader.Length = *TempBufferSize; + CopyMem (*TempBuffer, &PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER)); + +Fail: + if (!Updated) { + gBS->FreePool (*TempBuffer); + *TempBufferSize = 0; + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + + +/** + This function allows the caller to update a form that has + previously been registered with the EFI HII database. + + @param Handle Hii Handle + @param FormSetGuid The formset should be updated. + @param FormId The form should be updated. + @param Label Update information starting immediately after this + label in the IFR + @param Insert If TRUE and Data is not NULL, insert data after + Label. If FALSE, replace opcodes between two + labels with Data + @param Data The adding data; If NULL, remove opcodes between + two Label. + + @retval EFI_SUCCESS Update success. + @retval Other Update fail. + +**/ +EFI_STATUS +IfrLibUpdateForm ( + IN EFI_HII_HANDLE Handle, + IN EFI_GUID *FormSetGuid, OPTIONAL + IN EFI_FORM_ID FormId, + IN UINT16 Label, + IN BOOLEAN Insert, + IN EFI_HII_UPDATE_DATA *Data + ) +{ + EFI_STATUS Status; + EFI_HII_DATABASE_PROTOCOL *HiiDatabase; + EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList; + UINT32 Index; + EFI_HII_PACKAGE_LIST_HEADER *UpdateBuffer; + UINTN BufferSize; + UINT8 *UpdateBufferPos; + EFI_HII_PACKAGE_HEADER PackageHeader; + EFI_HII_PACKAGE_HEADER *Package; + UINT32 PackageLength; + EFI_HII_PACKAGE_HEADER *TempBuffer; + UINT32 TempBufferSize; + BOOLEAN Updated; + + if (Data == NULL) { + return EFI_INVALID_PARAMETER; + } + + LocateHiiProtocols (); + HiiDatabase = gIfrLibHiiDatabase; + + // + // Get the orginal package list + // + BufferSize = 0; + HiiPackageList = NULL; + Status = HiiDatabase->ExportPackageLists (HiiDatabase, Handle, &BufferSize, HiiPackageList); + if (Status == EFI_BUFFER_TOO_SMALL) { + HiiPackageList = AllocatePool (BufferSize); + ASSERT (HiiPackageList != NULL); + + Status = HiiDatabase->ExportPackageLists (HiiDatabase, Handle, &BufferSize, HiiPackageList); + if (EFI_ERROR (Status)) { + gBS->FreePool (HiiPackageList); + return Status; + } + } + + // + // Calculate and allocate space for retrieval of IFR data + // + BufferSize += Data->Offset; + UpdateBuffer = AllocateZeroPool (BufferSize); + if (UpdateBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + UpdateBufferPos = (UINT8 *) UpdateBuffer; + + // + // copy the package list header + // + CopyMem (UpdateBufferPos, HiiPackageList, sizeof (EFI_HII_PACKAGE_LIST_HEADER)); + UpdateBufferPos += sizeof (EFI_HII_PACKAGE_LIST_HEADER); + + Updated = FALSE; + for (Index = 0; ; Index++) { + Status = GetPackageDataFromPackageList (HiiPackageList, Index, &PackageLength, &Package); + if (Status == EFI_SUCCESS) { + CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER)); + if ((PackageHeader.Type == EFI_HII_PACKAGE_FORM) && !Updated) { + Status = UpdateFormPackageData (FormSetGuid, FormId, Package, PackageLength, Label, Insert, Data, (UINT8 **)&TempBuffer, &TempBufferSize); + if (!EFI_ERROR(Status)) { + if (FormSetGuid == NULL) { + Updated = TRUE; + } + CopyMem (UpdateBufferPos, TempBuffer, TempBufferSize); + UpdateBufferPos += TempBufferSize; + gBS->FreePool (TempBuffer); + continue; + } + } + + CopyMem (UpdateBufferPos, Package, PackageLength); + UpdateBufferPos += PackageLength; + } else if (Status == EFI_NOT_FOUND) { + break; + } else { + gBS->FreePool (HiiPackageList); + return Status; + } + } + + // + // Update package list length + // + BufferSize = UpdateBufferPos - (UINT8 *) UpdateBuffer; + CopyMem (&UpdateBuffer->PackageLength, &BufferSize, sizeof (UINT32)); + + gBS->FreePool (HiiPackageList); + + return HiiDatabase->UpdatePackageList (HiiDatabase, Handle, UpdateBuffer); +} + + +/** + Draw a dialog and return the selected key. + + @param NumberOfLines The number of lines for the dialog box + @param KeyValue The EFI_KEY value returned if HotKey is TRUE.. + @param String Pointer to the first string in the list + @param ... A series of (quantity == NumberOfLines) text + strings which will be used to construct the dialog + box + + @retval EFI_SUCCESS Displayed dialog and received user interaction + @retval EFI_INVALID_PARAMETER One of the parameters was invalid. + +**/ +EFI_STATUS +IfrLibCreatePopUp ( + IN UINTN NumberOfLines, + OUT EFI_INPUT_KEY *KeyValue, + IN CHAR16 *String, + ... + ) +{ + UINTN Index; + UINTN Count; + UINTN Start; + UINTN Top; + CHAR16 *StringPtr; + UINTN LeftColumn; + UINTN RightColumn; + UINTN TopRow; + UINTN BottomRow; + UINTN DimensionsWidth; + UINTN DimensionsHeight; + VA_LIST Marker; + EFI_INPUT_KEY Key; + UINTN LargestString; + CHAR16 *StackString; + EFI_STATUS Status; + UINTN StringLen; + CHAR16 *LineBuffer; + CHAR16 **StringArray; + EFI_EVENT TimerEvent; + EFI_EVENT WaitList[2]; + UINTN CurrentAttribute; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut; + + if ((KeyValue == NULL) || (String == NULL)) { + return EFI_INVALID_PARAMETER; + } + + TopRow = 0; + BottomRow = 0; + LeftColumn = 0; + RightColumn = 0; + + ConOut = gST->ConOut; + ConOut->QueryMode (ConOut, ConOut->Mode->Mode, &RightColumn, &BottomRow); + + DimensionsWidth = RightColumn - LeftColumn; + DimensionsHeight = BottomRow - TopRow; + + CurrentAttribute = ConOut->Mode->Attribute; + + LineBuffer = AllocateZeroPool (DimensionsWidth * sizeof (CHAR16)); + ASSERT (LineBuffer != NULL); + + // + // Determine the largest string in the dialog box + // Notice we are starting with 1 since String is the first string + // + StringArray = AllocateZeroPool (NumberOfLines * sizeof (CHAR16 *)); + LargestString = StrLen (String); + StringArray[0] = String; + + VA_START (Marker, String); + for (Index = 1; Index < NumberOfLines; Index++) { + StackString = VA_ARG (Marker, CHAR16 *); + + if (StackString == NULL) { + return EFI_INVALID_PARAMETER; + } + + StringArray[Index] = StackString; + StringLen = StrLen (StackString); + if (StringLen > LargestString) { + LargestString = StringLen; + } + } + + if ((LargestString + 2) > DimensionsWidth) { + LargestString = DimensionsWidth - 2; + } + + // + // Subtract the PopUp width from total Columns, allow for one space extra on + // each end plus a border. + // + Start = (DimensionsWidth - LargestString - 2) / 2 + LeftColumn + 1; + + Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + TopRow - 1; + + // + // Disable cursor + // + ConOut->EnableCursor (ConOut, FALSE); + ConOut->SetAttribute (ConOut, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE); + + StringPtr = &LineBuffer[0]; + *StringPtr++ = BOXDRAW_DOWN_RIGHT; + for (Index = 0; Index < LargestString; Index++) { + *StringPtr++ = BOXDRAW_HORIZONTAL; + } + *StringPtr++ = BOXDRAW_DOWN_LEFT; + *StringPtr = L'\0'; + + ConOut->SetCursorPosition (ConOut, Start, Top); + ConOut->OutputString (ConOut, LineBuffer); + + for (Index = 0; Index < NumberOfLines; Index++) { + StringPtr = &LineBuffer[0]; + *StringPtr++ = BOXDRAW_VERTICAL; + + for (Count = 0; Count < LargestString; Count++) { + StringPtr[Count] = L' '; + } + + StringLen = StrLen (StringArray[Index]); + if (StringLen > LargestString) { + StringLen = LargestString; + } + CopyMem ( + StringPtr + ((LargestString - StringLen) / 2), + StringArray[Index], + StringLen * sizeof (CHAR16) + ); + StringPtr += LargestString; + + *StringPtr++ = BOXDRAW_VERTICAL; + *StringPtr = L'\0'; + + ConOut->SetCursorPosition (ConOut, Start, Top + 1 + Index); + ConOut->OutputString (ConOut, LineBuffer); + } + + StringPtr = &LineBuffer[0]; + *StringPtr++ = BOXDRAW_UP_RIGHT; + for (Index = 0; Index < LargestString; Index++) { + *StringPtr++ = BOXDRAW_HORIZONTAL; + } + *StringPtr++ = BOXDRAW_UP_LEFT; + *StringPtr = L'\0'; + + ConOut->SetCursorPosition (ConOut, Start, Top + NumberOfLines + 1); + ConOut->OutputString (ConOut, LineBuffer); + + do { + Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent); + + // + // Set a timer event of 1 second expiration + // + gBS->SetTimer ( + TimerEvent, + TimerRelative, + 10000000 + ); + + // + // Wait for the keystroke event or the timer + // + WaitList[0] = gST->ConIn->WaitForKey; + WaitList[1] = TimerEvent; + Status = gBS->WaitForEvent (2, WaitList, &Index); + + // + // Check for the timer expiration + // + if (!EFI_ERROR (Status) && Index == 1) { + Status = EFI_TIMEOUT; + } + + gBS->CloseEvent (TimerEvent); + } while (Status == EFI_TIMEOUT); + + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + CopyMem (KeyValue, &Key, sizeof (EFI_INPUT_KEY)); + + ConOut->SetAttribute (ConOut, CurrentAttribute); + ConOut->EnableCursor (ConOut, TRUE); + + return Status; +} + + +/** + Configure the buffer accrording to ConfigBody strings. + + @param DefaultId the ID of default. + @param Buffer the start address of buffer. + @param BufferSize the size of buffer. + @param Number the number of the strings. + + @retval EFI_BUFFER_TOO_SMALL the BufferSize is too small to operate. + @retval EFI_INVALID_PARAMETER Buffer is NULL or BufferSize is 0. + @retval EFI_SUCCESS Operation successful. + +**/ +EFI_STATUS +ExtractDefault( + IN VOID *Buffer, + IN UINTN *BufferSize, + UINTN Number, + ... + ) +{ + VA_LIST Args; + UINTN Index; + UINT32 TotalLen; + UINT8 *BufCfgArray; + UINT8 *BufferPos; + UINT16 Offset; + UINT16 Width; + UINT8 *Value; + + if ((Buffer == NULL) || (BufferSize == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Offset = 0; + Width = 0; + Value = NULL; + + VA_START (Args, Number); + for (Index = 0; Index < Number; Index++) { + BufCfgArray = (UINT8 *) VA_ARG (Args, VOID *); + CopyMem (&TotalLen, BufCfgArray, sizeof (UINT32)); + BufferPos = BufCfgArray + sizeof (UINT32); + + while ((UINT32)(BufferPos - BufCfgArray) < TotalLen) { + CopyMem (&Offset, BufferPos, sizeof (UINT16)); + BufferPos += sizeof (UINT16); + CopyMem (&Width, BufferPos, sizeof (UINT16)); + BufferPos += sizeof (UINT16); + Value = BufferPos; + BufferPos += Width; + + if ((UINTN)(Offset + Width) > *BufferSize) { + return EFI_BUFFER_TOO_SMALL; + } + + CopyMem ((UINT8 *)Buffer + Offset, Value, Width); + } + } + VA_END (Args); + + *BufferSize = (UINTN)Offset; + + return EFI_SUCCESS; +} + + +/** + Swap bytes in the buffer. + + @param Buffer Binary buffer. + @param BufferSize Size of the buffer in bytes. + + @return None. + +**/ +STATIC +VOID +SwapBuffer ( + IN OUT UINT8 *Buffer, + IN UINTN BufferSize + ) +{ + UINTN Index; + UINT8 Temp; + UINTN SwapCount; + + SwapCount = (BufferSize - 1) / 2; + for (Index = 0; Index < SwapCount; Index++) { + Temp = Buffer[Index]; + Buffer[Index] = Buffer[BufferSize - 1 - Index]; + Buffer[BufferSize - 1 - Index] = Temp; + } +} + + +/** + Converts binary buffer to Unicode string in reversed byte order from R8_BufToHexString(). + + @param Str String for output + @param Buffer Binary buffer. + @param BufferSize Size of the buffer in bytes. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +BufferToHexString ( + IN OUT CHAR16 *Str, + IN UINT8 *Buffer, + IN UINTN BufferSize + ) +{ + EFI_STATUS Status; + UINT8 *NewBuffer; + UINTN StrBufferLen; + + NewBuffer = AllocateCopyPool (BufferSize, Buffer); + SwapBuffer (NewBuffer, BufferSize); + + StrBufferLen = (BufferSize + 1) * sizeof (CHAR16); + Status = R8_BufToHexString (Str, &StrBufferLen, NewBuffer, BufferSize); + + gBS->FreePool (NewBuffer); + + return Status; +} + + +/** + Converts Hex String to binary buffer in reversed byte order from R8_HexStringToBuf(). + + @param Buffer Pointer to buffer that receives the data. + @param BufferSize Length in bytes of the buffer to hold converted + data. If routine return with EFI_SUCCESS, + containing length of converted data. If routine + return with EFI_BUFFER_TOO_SMALL, containg length + of buffer desired. + @param Str String to be converted from. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +HexStringToBuffer ( + IN OUT UINT8 *Buffer, + IN OUT UINTN *BufferSize, + IN CHAR16 *Str + ) +{ + EFI_STATUS Status; + UINTN ConvertedStrLen; + + ConvertedStrLen = 0; + Status = R8_HexStringToBuf (Buffer, BufferSize, Str, &ConvertedStrLen); + if (!EFI_ERROR (Status)) { + SwapBuffer (Buffer, ConvertedStrLen); + } + + return Status; +} + + +/** + Construct <ConfigHdr> using routing information GUID/NAME/PATH. + + @param ConfigHdr Pointer to the ConfigHdr string. + @param StrBufferLen On input: Length in bytes of buffer to hold the + ConfigHdr string. Includes tailing '\0' character. + On output: If return EFI_SUCCESS, containing + length of ConfigHdr string buffer. If return + EFI_BUFFER_TOO_SMALL, containg length of string + buffer desired. + @param Guid Routing information: GUID. + @param Name Routing information: NAME. + @param DriverHandle Driver handle which contains the routing + information: PATH. + + @retval EFI_SUCCESS Routine success. + @retval EFI_BUFFER_TOO_SMALL The ConfigHdr string buffer is too small. + +**/ +EFI_STATUS +ConstructConfigHdr ( + IN OUT CHAR16 *ConfigHdr, + IN OUT UINTN *StrBufferLen, + IN EFI_GUID *Guid, + IN CHAR16 *Name, OPTIONAL + IN EFI_HANDLE *DriverHandle + ) +{ + EFI_STATUS Status; + UINTN NameStrLen; + UINTN DevicePathSize; + UINTN BufferSize; + CHAR16 *StrPtr; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + if (Name == NULL) { + // + // There will be no "NAME" in <ConfigHdr> for Name/Value storage + // + NameStrLen = 0; + } else { + // + // For buffer storage + // + NameStrLen = StrLen (Name); + } + + // + // Retrieve DevicePath Protocol associated with this HiiPackageList + // + Status = gBS->HandleProtocol ( + DriverHandle, + &gEfiDevicePathProtocolGuid, + (VOID **) &DevicePath + ); + if (EFI_ERROR (Status)) { + return Status; + } + + DevicePathSize = GetDevicePathSize (DevicePath); + + // + // GUID=<HexCh>32&NAME=<Alpha>NameStrLen&PATH=<HexChar>DevicePathStrLen <NULL> + // | 5 | 32 | 6 | NameStrLen | 6 | DevicePathStrLen | + // + BufferSize = (5 + 32 + 6 + NameStrLen + 6 + DevicePathSize * 2 + 1) * sizeof (CHAR16); + if (*StrBufferLen < BufferSize) { + *StrBufferLen = BufferSize; + return EFI_BUFFER_TOO_SMALL; + } + + *StrBufferLen = BufferSize; + + StrPtr = ConfigHdr; + + StrCpy (StrPtr, L"GUID="); + StrPtr += 5; + BufferToHexString (StrPtr, (UINT8 *) Guid, sizeof (EFI_GUID)); + StrPtr += 32; + + StrCpy (StrPtr, L"&NAME="); + StrPtr += 6; + if (Name != NULL) { + StrCpy (StrPtr, Name); + StrPtr += NameStrLen; + } + + StrCpy (StrPtr, L"&PATH="); + StrPtr += 6; + BufferToHexString (StrPtr, (UINT8 *) DevicePath, DevicePathSize); + + return EFI_SUCCESS; +} + + +/** + Search BlockName "&OFFSET=Offset&WIDTH=Width" in a string. + + @param String The string to be searched in. + @param Offset Offset in BlockName. + @param Width Width in BlockName. + + @retval TRUE Block name found. + @retval FALSE Block name not found. + +**/ +BOOLEAN +FindBlockName ( + IN OUT CHAR16 *String, + UINTN Offset, + UINTN Width + ) +{ + EFI_STATUS Status; + UINTN Data; + UINTN BufferSize; + UINTN ConvertedStrLen; + + while ((String = StrStr (String, L"&OFFSET=")) != NULL) { + // + // Skip '&OFFSET=' + // + String = String + 8; + + Data = 0; + BufferSize = sizeof (UINTN); + Status = R8_HexStringToBuf ((UINT8 *) &Data, &BufferSize, String, &ConvertedStrLen); + if (EFI_ERROR (Status)) { + return FALSE; + } + String = String + ConvertedStrLen; + + if (Data != Offset) { + continue; + } + + if (StrnCmp (String, L"&WIDTH=", 7) != 0) { + return FALSE; + } + String = String + 7; + + Data = 0; + BufferSize = sizeof (UINTN); + Status = R8_HexStringToBuf ((UINT8 *) &Data, &BufferSize, String, &ConvertedStrLen); + if (EFI_ERROR (Status)) { + return FALSE; + } + if (Data == Width) { + return TRUE; + } + + String = String + ConvertedStrLen; + } + + return FALSE; +} + + +/** + This routine is invoked by ConfigAccess.Callback() to retrived uncommitted data from Form Browser. + + @param VariableGuid An optional field to indicate the target variable + GUID name to use. + @param VariableName An optional field to indicate the target + human-readable variable name. + @param BufferSize On input: Length in bytes of buffer to hold + retrived data. On output: If return + EFI_BUFFER_TOO_SMALL, containg length of buffer + desired. + @param Buffer Buffer to hold retrived data. + + @retval EFI_SUCCESS Routine success. + @retval EFI_BUFFER_TOO_SMALL The intput buffer is too small. + +**/ +EFI_STATUS +GetBrowserData ( + EFI_GUID *VariableGuid, OPTIONAL + CHAR16 *VariableName, OPTIONAL + UINTN *BufferSize, + UINT8 *Buffer + ) +{ + EFI_STATUS Status; + CHAR16 *ConfigHdr; + CHAR16 *ConfigResp; + CHAR16 *StringPtr; + UINTN HeaderLen; + UINTN BufferLen; + CHAR16 *Progress; + EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2; + EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting; + + // + // Locate protocols for use + // + Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Retrive formset storage data from Form Browser + // + ConfigHdr = mFakeConfigHdr; + HeaderLen = StrLen (ConfigHdr); + + BufferLen = 0x4000; + ConfigResp = AllocateZeroPool (BufferLen + HeaderLen); + + StringPtr = ConfigResp + HeaderLen; + *StringPtr = L'&'; + StringPtr++; + + Status = FormBrowser2->BrowserCallback ( + FormBrowser2, + &BufferLen, + StringPtr, + TRUE, + VariableGuid, + VariableName + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + gBS->FreePool (ConfigResp); + ConfigResp = AllocateZeroPool (BufferLen + HeaderLen); + + StringPtr = ConfigResp + HeaderLen; + *StringPtr = L'&'; + StringPtr++; + + Status = FormBrowser2->BrowserCallback ( + FormBrowser2, + &BufferLen, + StringPtr, + TRUE, + VariableGuid, + VariableName + ); + } + if (EFI_ERROR (Status)) { + gBS->FreePool (ConfigResp); + return Status; + } + CopyMem (ConfigResp, ConfigHdr, HeaderLen * sizeof (UINT16)); + + // + // Convert <ConfigResp> to buffer data + // + Status = HiiConfigRouting->ConfigToBlock ( + HiiConfigRouting, + ConfigResp, + Buffer, + BufferSize, + &Progress + ); + gBS->FreePool (ConfigResp); + + return Status; +} + + +/** + This routine is invoked by ConfigAccess.Callback() to update uncommitted data of Form Browser. + + @param VariableGuid An optional field to indicate the target variable + GUID name to use. + @param VariableName An optional field to indicate the target + human-readable variable name. + @param BufferSize Length in bytes of buffer to hold retrived data. + @param Buffer Buffer to hold retrived data. + @param RequestElement An optional field to specify which part of the + buffer data will be send back to Browser. If NULL, + the whole buffer of data will be committed to + Browser. <RequestElement> ::= + &OFFSET=<Number>&WIDTH=<Number>* + + @retval EFI_SUCCESS Routine success. + @retval Other Updating Browser uncommitted data failed. + +**/ +EFI_STATUS +SetBrowserData ( + EFI_GUID *VariableGuid, OPTIONAL + CHAR16 *VariableName, OPTIONAL + UINTN BufferSize, + UINT8 *Buffer, + CHAR16 *RequestElement OPTIONAL + ) +{ + EFI_STATUS Status; + CHAR16 *ConfigHdr; + CHAR16 *ConfigResp; + CHAR16 *StringPtr; + UINTN HeaderLen; + UINTN BufferLen; + CHAR16 *Progress; + EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2; + EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting; + CHAR16 BlockName[33]; + CHAR16 *ConfigRequest; + CHAR16 *Request; + + // + // Locate protocols for use + // + Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Prepare <ConfigRequest> + // + ConfigHdr = mFakeConfigHdr; + HeaderLen = StrLen (ConfigHdr); + + if (RequestElement == NULL) { + // + // RequestElement not specified, use "&OFFSET=0&WIDTH=<BufferSize>" as <BlockName> + // + BlockName[0] = L'\0'; + StrCpy (BlockName, L"&OFFSET=0&WIDTH="); + + // + // String lenghth of L"&OFFSET=0&WIDTH=" is 16 + // + StringPtr = BlockName + 16; + BufferLen = sizeof (BlockName) - (16 * sizeof (CHAR16)); + R8_BufToHexString (StringPtr, &BufferLen, (UINT8 *) &BufferSize, sizeof (UINTN)); + + Request = BlockName; + } else { + Request = RequestElement; + } + + BufferLen = HeaderLen * sizeof (CHAR16) + StrSize (Request); + ConfigRequest = AllocateZeroPool (BufferLen); + + CopyMem (ConfigRequest, ConfigHdr, HeaderLen * sizeof (CHAR16)); + StringPtr = ConfigRequest + HeaderLen; + StrCpy (StringPtr, Request); + + // + // Convert buffer to <ConfigResp> + // + Status = HiiConfigRouting->BlockToConfig ( + HiiConfigRouting, + ConfigRequest, + Buffer, + BufferSize, + &ConfigResp, + &Progress + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (ConfigResp); + return Status; + } + + // + // Skip <ConfigHdr> and '&' + // + StringPtr = ConfigResp + HeaderLen + 1; + + // + // Change uncommitted data in Browser + // + Status = FormBrowser2->BrowserCallback ( + FormBrowser2, + &BufferSize, + StringPtr, + FALSE, + NULL, + NULL + ); + gBS->FreePool (ConfigResp); + return Status; +} diff --git a/MdeModulePkg/Library/IfrSupportLib/UefiIfrLibraryInternal.h b/MdeModulePkg/Library/IfrSupportLib/UefiIfrLibraryInternal.h new file mode 100644 index 0000000000..1b5a79f696 --- /dev/null +++ b/MdeModulePkg/Library/IfrSupportLib/UefiIfrLibraryInternal.h @@ -0,0 +1,64 @@ +/** @file + +Copyright (c) 2007, Intel Corporation +All rights reserved. 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. + +Module Name: + + UefiIfrLibraryInternal + +Abstract: + + The file contain all library function for Ifr Operations. + + +**/ + +#ifndef _IFRLIBRARY_INTERNAL_H +#define _IFRLIBRARY_INTERNAL_H + + +#include <PiDxe.h> + +#include <Guid/GlobalVariable.h> +#include <Protocol/DevicePath.h> + +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/UefiRuntimeServicesTableLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/BaseLib.h> +#include <Library/DevicePathLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/IfrSupportLib.h> +#include <Library/PcdLib.h> + +#include <MdeModuleHii.h> + +#include "R8Lib.h" + +VOID +LocateHiiProtocols ( + VOID + ) +/*++ + +Routine Description: + This function locate Hii relative protocols for later usage. + +Arguments: + None. + +Returns: + None. + +--*/ +; + +#endif diff --git a/MdeModulePkg/Library/IfrSupportLib/UefiIfrOpCodeCreation.c b/MdeModulePkg/Library/IfrSupportLib/UefiIfrOpCodeCreation.c new file mode 100644 index 0000000000..240f0208a6 --- /dev/null +++ b/MdeModulePkg/Library/IfrSupportLib/UefiIfrOpCodeCreation.c @@ -0,0 +1,639 @@ +/** @file + +Copyright (c) 2007, Intel Corporation +All rights reserved. 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. + +Module Name: + + UefiIfrOpCodeCreation.c + +Abstract: + + Library Routines to create IFR independent of string data - assume tokens already exist + Primarily to be used for exporting op-codes at a label in pre-defined forms. + +Revision History: + + +**/ + +#include "UefiIfrLibraryInternal.h" + +STATIC EFI_GUID mIfrVendorGuid = EFI_IFR_TIANO_GUID; + +STATIC +BOOLEAN +IsValidQuestionFlags ( + IN UINT8 Flags + ) +{ + return (BOOLEAN) ((Flags & (~QUESTION_FLAGS)) ? FALSE : TRUE); +} + +STATIC +BOOLEAN +IsValidValueType ( + IN UINT8 Type + ) +{ + return (BOOLEAN) ((Type <= EFI_IFR_TYPE_OTHER) ? TRUE : FALSE); +} + +STATIC +BOOLEAN +IsValidNumricFlags ( + IN UINT8 Flags + ) +{ + if (Flags & ~(EFI_IFR_NUMERIC_SIZE | EFI_IFR_DISPLAY)) { + return FALSE; + } + + if ((Flags & EFI_IFR_DISPLAY) > EFI_IFR_DISPLAY_UINT_HEX) { + return FALSE; + } + + return TRUE; +} + +STATIC +BOOLEAN +IsValidCheckboxFlags ( + IN UINT8 Flags + ) +{ + return (BOOLEAN) ((Flags <= EFI_IFR_CHECKBOX_DEFAULT_MFG) ? TRUE : FALSE); +} + +EFI_STATUS +CreateEndOpCode ( + IN OUT EFI_HII_UPDATE_DATA *Data + ) +{ + EFI_IFR_END End; + UINT8 *LocalBuffer; + + ASSERT (Data != NULL && Data->Data != NULL); + + if (Data->Offset + sizeof (EFI_IFR_END) > Data->BufferSize) { + return EFI_BUFFER_TOO_SMALL; + } + + End.Header.Length = sizeof (EFI_IFR_END); + End.Header.OpCode = EFI_IFR_END_OP; + End.Header.Scope = 0; + + LocalBuffer = (UINT8 *) Data->Data + Data->Offset; + CopyMem (LocalBuffer, &End, sizeof (EFI_IFR_END)); + Data->Offset += sizeof (EFI_IFR_END); + + return EFI_SUCCESS; +} + +EFI_STATUS +CreateDefaultOpCode ( + IN EFI_IFR_TYPE_VALUE *Value, + IN UINT8 Type, + IN OUT EFI_HII_UPDATE_DATA *Data + ) +{ + EFI_IFR_DEFAULT Default; + UINT8 *LocalBuffer; + + ASSERT (Data != NULL && Data->Data != NULL); + + if ((Value == NULL) || !IsValidValueType (Type)) { + return EFI_INVALID_PARAMETER; + } + + if (Data->Offset + sizeof (EFI_IFR_DEFAULT) > Data->BufferSize) { + return EFI_BUFFER_TOO_SMALL; + } + + Default.Header.OpCode = EFI_IFR_DEFAULT_OP; + Default.Header.Length = sizeof (EFI_IFR_DEFAULT); + Default.Header.Scope = 0; + Default.Type = Type; + Default.DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD; + CopyMem (&Default.Value, Value, sizeof(EFI_IFR_TYPE_VALUE)); + + LocalBuffer = (UINT8 *) Data->Data + Data->Offset; + CopyMem (LocalBuffer, &Default, sizeof (EFI_IFR_DEFAULT)); + Data->Offset += sizeof (EFI_IFR_DEFAULT); + + return EFI_SUCCESS; +} + +EFI_STATUS +CreateActionOpCode ( + IN EFI_QUESTION_ID QuestionId, + IN EFI_STRING_ID Prompt, + IN EFI_STRING_ID Help, + IN UINT8 QuestionFlags, + IN EFI_STRING_ID QuestionConfig, + IN OUT EFI_HII_UPDATE_DATA *Data + ) +{ + EFI_IFR_ACTION Action; + UINT8 *LocalBuffer; + + ASSERT (Data != NULL && Data->Data != NULL); + + if (!IsValidQuestionFlags (QuestionFlags)) { + return EFI_INVALID_PARAMETER; + } + + if (Data->Offset + sizeof (EFI_IFR_ACTION) > Data->BufferSize) { + return EFI_BUFFER_TOO_SMALL; + } + + Action.Header.OpCode = EFI_IFR_ACTION_OP; + Action.Header.Length = sizeof (EFI_IFR_ACTION); + Action.Header.Scope = 0; + Action.Question.QuestionId = QuestionId; + Action.Question.Header.Prompt = Prompt; + Action.Question.Header.Help = Help; + Action.Question.VarStoreId = INVALID_VARSTORE_ID; + Action.Question.Flags = QuestionFlags; + Action.QuestionConfig = QuestionConfig; + + LocalBuffer = (UINT8 *) Data->Data + Data->Offset; + CopyMem (LocalBuffer, &Action, sizeof (EFI_IFR_ACTION)); + Data->Offset += sizeof (EFI_IFR_ACTION); + + return EFI_SUCCESS; +} + +EFI_STATUS +CreateSubTitleOpCode ( + IN EFI_STRING_ID Prompt, + IN EFI_STRING_ID Help, + IN UINT8 Flags, + IN UINT8 Scope, + IN OUT EFI_HII_UPDATE_DATA *Data + ) +{ + EFI_IFR_SUBTITLE Subtitle; + UINT8 *LocalBuffer; + + ASSERT (Data != NULL && Data->Data != NULL); + + if (Data->Offset + sizeof (EFI_IFR_SUBTITLE) > Data->BufferSize) { + return EFI_BUFFER_TOO_SMALL; + } + + Subtitle.Header.OpCode = EFI_IFR_SUBTITLE_OP; + Subtitle.Header.Length = sizeof (EFI_IFR_SUBTITLE); + Subtitle.Header.Scope = Scope; + Subtitle.Statement.Prompt = Prompt; + Subtitle.Statement.Help = Help; + Subtitle.Flags = Flags; + + LocalBuffer = (UINT8 *) Data->Data + Data->Offset; + CopyMem (LocalBuffer, &Subtitle, sizeof (EFI_IFR_SUBTITLE)); + Data->Offset += sizeof (EFI_IFR_SUBTITLE); + + return EFI_SUCCESS; +} + + +EFI_STATUS +CreateTextOpCode ( + IN EFI_STRING_ID Prompt, + IN EFI_STRING_ID Help, + IN EFI_STRING_ID TextTwo, + IN OUT EFI_HII_UPDATE_DATA *Data + ) +{ + EFI_IFR_TEXT Text; + UINT8 *LocalBuffer; + + ASSERT (Data != NULL && Data->Data != NULL); + + if (Data->Offset + sizeof (EFI_IFR_TEXT) > Data->BufferSize) { + return EFI_BUFFER_TOO_SMALL; + } + + Text.Header.OpCode = EFI_IFR_TEXT_OP; + Text.Header.Length = sizeof (EFI_IFR_TEXT); + Text.Header.Scope = 0; + Text.Statement.Prompt = Prompt; + Text.Statement.Help = Help; + Text.TextTwo = TextTwo; + + LocalBuffer = (UINT8 *) Data->Data + Data->Offset; + CopyMem (LocalBuffer, &Text, sizeof (EFI_IFR_TEXT)); + Data->Offset += sizeof (EFI_IFR_TEXT); + + return EFI_SUCCESS; +} + +EFI_STATUS +CreateGotoOpCode ( + IN EFI_FORM_ID FormId, + IN EFI_STRING_ID Prompt, + IN EFI_STRING_ID Help, + IN UINT8 QuestionFlags, + IN EFI_QUESTION_ID QuestionId, + IN OUT EFI_HII_UPDATE_DATA *Data + ) +{ + EFI_IFR_REF Goto; + UINT8 *LocalBuffer; + + ASSERT (Data != NULL && Data->Data != NULL); + + if (!IsValidQuestionFlags (QuestionFlags)) { + return EFI_INVALID_PARAMETER; + } + + if (Data->Offset + sizeof (EFI_IFR_REF) > Data->BufferSize) { + return EFI_BUFFER_TOO_SMALL; + } + + Goto.Header.OpCode = EFI_IFR_REF_OP; + Goto.Header.Length = sizeof (EFI_IFR_REF); + Goto.Header.Scope = 0; + Goto.Question.Header.Prompt = Prompt; + Goto.Question.Header.Help = Help; + Goto.Question.VarStoreId = INVALID_VARSTORE_ID; + Goto.Question.QuestionId = QuestionId; + Goto.Question.Flags = QuestionFlags; + Goto.FormId = FormId; + + LocalBuffer = (UINT8 *) Data->Data + Data->Offset; + CopyMem (LocalBuffer, &Goto, sizeof (EFI_IFR_REF)); + Data->Offset += sizeof (EFI_IFR_REF); + + return EFI_SUCCESS; +} + +EFI_STATUS +CreateOneOfOptionOpCode ( + IN UINTN OptionCount, + IN IFR_OPTION *OptionsList, + IN UINT8 Type, + IN OUT EFI_HII_UPDATE_DATA *Data + ) +{ + UINTN Index; + UINT8 *LocalBuffer; + EFI_IFR_ONE_OF_OPTION OneOfOption; + + ASSERT (Data != NULL && Data->Data != NULL); + + if ((OptionCount != 0) && (OptionsList == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (Data->Offset + OptionCount * sizeof (EFI_IFR_ONE_OF_OPTION) > Data->BufferSize) { + return EFI_BUFFER_TOO_SMALL; + } + + for (Index = 0; Index < OptionCount; Index++) { + OneOfOption.Header.OpCode = EFI_IFR_ONE_OF_OPTION_OP; + OneOfOption.Header.Length = sizeof (EFI_IFR_ONE_OF_OPTION); + OneOfOption.Header.Scope = 0; + + OneOfOption.Option = OptionsList[Index].StringToken; + OneOfOption.Value = OptionsList[Index].Value; + OneOfOption.Flags = (UINT8) (OptionsList[Index].Flags & (EFI_IFR_OPTION_DEFAULT | EFI_IFR_OPTION_DEFAULT_MFG)); + OneOfOption.Type = Type; + + LocalBuffer = (UINT8 *) Data->Data + Data->Offset; + CopyMem (LocalBuffer, &OneOfOption, sizeof (EFI_IFR_ONE_OF_OPTION)); + Data->Offset += sizeof (EFI_IFR_ONE_OF_OPTION); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +CreateOneOfOpCode ( + IN EFI_QUESTION_ID QuestionId, + IN EFI_VARSTORE_ID VarStoreId, + IN UINT16 VarOffset, + IN EFI_STRING_ID Prompt, + IN EFI_STRING_ID Help, + IN UINT8 QuestionFlags, + IN UINT8 OneOfFlags, + IN IFR_OPTION *OptionsList, + IN UINTN OptionCount, + IN OUT EFI_HII_UPDATE_DATA *Data + ) +{ + UINTN Length; + EFI_IFR_ONE_OF OneOf; + UINT8 *LocalBuffer; + + ASSERT (Data != NULL && Data->Data != NULL); + + if (!IsValidNumricFlags (OneOfFlags) || + !IsValidQuestionFlags (QuestionFlags) || + ((OptionCount != 0) && (OptionsList == NULL))) { + return EFI_INVALID_PARAMETER; + } + + Length = sizeof (EFI_IFR_ONE_OF) + OptionCount * sizeof (EFI_IFR_ONE_OF_OPTION) + sizeof (EFI_IFR_END); + if (Data->Offset + Length > Data->BufferSize) { + return EFI_BUFFER_TOO_SMALL; + } + + OneOf.Header.OpCode = EFI_IFR_ONE_OF_OP; + OneOf.Header.Length = sizeof (EFI_IFR_ONE_OF); + OneOf.Header.Scope = 1; + OneOf.Question.Header.Prompt = Prompt; + OneOf.Question.Header.Help = Help; + OneOf.Question.QuestionId = QuestionId; + OneOf.Question.VarStoreId = VarStoreId; + OneOf.Question.VarStoreInfo.VarOffset = VarOffset; + OneOf.Question.Flags = QuestionFlags; + OneOf.Flags = OneOfFlags; + ZeroMem ((VOID *) &OneOf.data, sizeof (MINMAXSTEP_DATA)); + + LocalBuffer = (UINT8 *) Data->Data + Data->Offset; + CopyMem (LocalBuffer, &OneOf, sizeof (EFI_IFR_ONE_OF)); + Data->Offset += sizeof (EFI_IFR_ONE_OF); + + CreateOneOfOptionOpCode (OptionCount, OptionsList, (UINT8) (OneOfFlags & EFI_IFR_NUMERIC_SIZE), Data); + + CreateEndOpCode (Data); + + return EFI_SUCCESS; +} + +EFI_STATUS +CreateOrderedListOpCode ( + IN EFI_QUESTION_ID QuestionId, + IN EFI_VARSTORE_ID VarStoreId, + IN UINT16 VarOffset, + IN EFI_STRING_ID Prompt, + IN EFI_STRING_ID Help, + IN UINT8 QuestionFlags, + IN UINT8 OrderedListFlags, + IN UINT8 DataType, + IN UINT8 MaxContainers, + IN IFR_OPTION *OptionsList, + IN UINTN OptionCount, + IN OUT EFI_HII_UPDATE_DATA *Data + ) +{ + UINTN Length; + EFI_IFR_ORDERED_LIST OrderedList; + UINT8 *LocalBuffer; + + ASSERT (Data != NULL && Data->Data != NULL); + + if (!IsValidQuestionFlags (QuestionFlags) || + ((OptionCount != 0) && (OptionsList == NULL))) { + return EFI_INVALID_PARAMETER; + } + + if ((OrderedListFlags != 0) && + (OrderedListFlags != EFI_IFR_UNIQUE_SET) && + (OrderedListFlags != EFI_IFR_NO_EMPTY_SET)) { + return EFI_INVALID_PARAMETER; + } + + Length = sizeof (EFI_IFR_ORDERED_LIST) + OptionCount * sizeof (EFI_IFR_ONE_OF_OPTION) + sizeof (EFI_IFR_END); + if (Data->Offset + Length > Data->BufferSize) { + return EFI_BUFFER_TOO_SMALL; + } + + OrderedList.Header.OpCode = EFI_IFR_ORDERED_LIST_OP; + OrderedList.Header.Length = sizeof (EFI_IFR_ORDERED_LIST); + OrderedList.Header.Scope = 1; + OrderedList.Question.Header.Prompt = Prompt; + OrderedList.Question.Header.Help = Help; + OrderedList.Question.QuestionId = QuestionId; + OrderedList.Question.VarStoreId = VarStoreId; + OrderedList.Question.VarStoreInfo.VarOffset = VarOffset; + OrderedList.Question.Flags = QuestionFlags; + OrderedList.MaxContainers = MaxContainers; + OrderedList.Flags = OrderedListFlags; + + LocalBuffer = (UINT8 *) Data->Data + Data->Offset; + CopyMem (LocalBuffer, &OrderedList, sizeof (EFI_IFR_ORDERED_LIST)); + Data->Offset += sizeof (EFI_IFR_ORDERED_LIST); + + CreateOneOfOptionOpCode (OptionCount, OptionsList, DataType, Data); + + CreateEndOpCode (Data); + + return EFI_SUCCESS; +} + +EFI_STATUS +CreateCheckBoxOpCode ( + IN EFI_QUESTION_ID QuestionId, + IN EFI_VARSTORE_ID VarStoreId, + IN UINT16 VarOffset, + IN EFI_STRING_ID Prompt, + IN EFI_STRING_ID Help, + IN UINT8 QuestionFlags, + IN UINT8 CheckBoxFlags, + IN OUT EFI_HII_UPDATE_DATA *Data + ) +{ + EFI_IFR_CHECKBOX CheckBox; + UINT8 *LocalBuffer; + + ASSERT (Data != NULL && Data->Data != NULL); + + if (!IsValidQuestionFlags (QuestionFlags) || !IsValidCheckboxFlags (CheckBoxFlags)) { + return EFI_INVALID_PARAMETER; + } + + if (Data->Offset + sizeof (EFI_IFR_CHECKBOX) > Data->BufferSize) { + return EFI_BUFFER_TOO_SMALL; + } + + CheckBox.Header.OpCode = EFI_IFR_CHECKBOX_OP; + CheckBox.Header.Length = sizeof (EFI_IFR_CHECKBOX); + CheckBox.Header.Scope = 0; + CheckBox.Question.QuestionId = QuestionId; + CheckBox.Question.VarStoreId = VarStoreId; + CheckBox.Question.VarStoreInfo.VarOffset = VarOffset; + CheckBox.Question.Header.Prompt = Prompt; + CheckBox.Question.Header.Help = Help; + CheckBox.Question.Flags = QuestionFlags; + CheckBox.Flags = CheckBoxFlags; + + LocalBuffer = (UINT8 *) Data->Data + Data->Offset; + CopyMem (LocalBuffer, &CheckBox, sizeof (EFI_IFR_CHECKBOX)); + Data->Offset += sizeof (EFI_IFR_CHECKBOX); + + return EFI_SUCCESS; +} + +EFI_STATUS +CreateNumericOpCode ( + IN EFI_QUESTION_ID QuestionId, + IN EFI_VARSTORE_ID VarStoreId, + IN UINT16 VarOffset, + IN EFI_STRING_ID Prompt, + IN EFI_STRING_ID Help, + IN UINT8 QuestionFlags, + IN UINT8 NumericFlags, + IN UINT64 Minimum, + IN UINT64 Maximum, + IN UINT64 Step, + IN UINT64 Default, + IN OUT EFI_HII_UPDATE_DATA *Data + ) +{ + EFI_STATUS Status; + EFI_IFR_NUMERIC Numeric; + MINMAXSTEP_DATA MinMaxStep; + EFI_IFR_TYPE_VALUE DefaultValue; + UINT8 *LocalBuffer; + + ASSERT (Data != NULL && Data->Data != NULL); + + if (!IsValidQuestionFlags (QuestionFlags) || !IsValidNumricFlags (NumericFlags)) { + return EFI_INVALID_PARAMETER; + } + + if (Data->Offset + sizeof (EFI_IFR_CHECKBOX) > Data->BufferSize) { + return EFI_BUFFER_TOO_SMALL; + } + + Numeric.Header.OpCode = EFI_IFR_NUMERIC_OP; + Numeric.Header.Length = sizeof (EFI_IFR_NUMERIC); + Numeric.Header.Scope = 1; + Numeric.Question.QuestionId = QuestionId; + Numeric.Question.VarStoreId = VarStoreId; + Numeric.Question.VarStoreInfo.VarOffset = VarOffset; + Numeric.Question.Header.Prompt = Prompt; + Numeric.Question.Header.Help = Help; + Numeric.Question.Flags = QuestionFlags; + Numeric.Flags = NumericFlags; + + switch (NumericFlags & EFI_IFR_NUMERIC_SIZE) { + case EFI_IFR_NUMERIC_SIZE_1: + MinMaxStep.u8.MinValue = (UINT8) Minimum; + MinMaxStep.u8.MaxValue = (UINT8) Maximum; + MinMaxStep.u8.Step = (UINT8) Step; + break; + + case EFI_IFR_NUMERIC_SIZE_2: + MinMaxStep.u16.MinValue = (UINT16) Minimum; + MinMaxStep.u16.MaxValue = (UINT16) Maximum; + MinMaxStep.u16.Step = (UINT16) Step; + break; + + case EFI_IFR_NUMERIC_SIZE_4: + MinMaxStep.u32.MinValue = (UINT32) Minimum; + MinMaxStep.u32.MaxValue = (UINT32) Maximum; + MinMaxStep.u32.Step = (UINT32) Step; + break; + + case EFI_IFR_NUMERIC_SIZE_8: + MinMaxStep.u64.MinValue = Minimum; + MinMaxStep.u64.MaxValue = Maximum; + MinMaxStep.u64.Step = Step; + break; + } + + CopyMem (&Numeric.data, &MinMaxStep, sizeof (MINMAXSTEP_DATA)); + + LocalBuffer = (UINT8 *) Data->Data + Data->Offset; + CopyMem (LocalBuffer, &Numeric, sizeof (EFI_IFR_NUMERIC)); + Data->Offset += sizeof (EFI_IFR_NUMERIC); + + DefaultValue.u64 = Default; + Status = CreateDefaultOpCode (&DefaultValue, (UINT8) (NumericFlags & EFI_IFR_NUMERIC_SIZE), Data); + if (EFI_ERROR(Status)) { + return Status; + } + + CreateEndOpCode (Data); + + return EFI_SUCCESS; +} + +EFI_STATUS +CreateStringOpCode ( + IN EFI_QUESTION_ID QuestionId, + IN EFI_VARSTORE_ID VarStoreId, + IN UINT16 VarOffset, + IN EFI_STRING_ID Prompt, + IN EFI_STRING_ID Help, + IN UINT8 QuestionFlags, + IN UINT8 StringFlags, + IN UINT8 MinSize, + IN UINT8 MaxSize, + IN OUT EFI_HII_UPDATE_DATA *Data + ) +{ + EFI_IFR_STRING String; + UINT8 *LocalBuffer; + + ASSERT (Data != NULL && Data->Data != NULL); + + if (!IsValidQuestionFlags (QuestionFlags) || (StringFlags & (~EFI_IFR_STRING_MULTI_LINE))) { + return EFI_INVALID_PARAMETER; + } + + if (Data->Offset + sizeof (EFI_IFR_STRING) > Data->BufferSize) { + return EFI_BUFFER_TOO_SMALL; + } + + String.Header.OpCode = EFI_IFR_STRING_OP; + String.Header.Length = sizeof (EFI_IFR_STRING); + String.Header.Scope = 0; + String.Question.Header.Prompt = Prompt; + String.Question.Header.Help = Help; + String.Question.QuestionId = QuestionId; + String.Question.VarStoreId = VarStoreId; + String.Question.VarStoreInfo.VarOffset = VarOffset; + String.Question.Flags = QuestionFlags; + String.MinSize = MinSize; + String.MaxSize = MaxSize; + String.Flags = StringFlags; + + LocalBuffer = (UINT8 *) Data->Data + Data->Offset; + CopyMem (LocalBuffer, &String, sizeof (EFI_IFR_STRING)); + Data->Offset += sizeof (EFI_IFR_STRING); + + return EFI_SUCCESS; +} + +EFI_STATUS +CreateBannerOpCode ( + IN EFI_STRING_ID Title, + IN UINT16 LineNumber, + IN UINT8 Alignment, + IN OUT EFI_HII_UPDATE_DATA *Data + ) +{ + EFI_IFR_GUID_BANNER Banner; + UINT8 *LocalBuffer; + + ASSERT (Data != NULL && Data->Data != NULL); + + if (Data->Offset + sizeof (EFI_IFR_GUID_BANNER) > Data->BufferSize) { + return EFI_BUFFER_TOO_SMALL; + } + + Banner.Header.OpCode = EFI_IFR_GUID_OP; + Banner.Header.Length = sizeof (EFI_IFR_GUID_BANNER); + Banner.Header.Scope = 0; + CopyMem (&Banner.Guid, &mIfrVendorGuid, sizeof (EFI_IFR_GUID)); + Banner.ExtendOpCode = EFI_IFR_EXTEND_OP_BANNER; + Banner.Title = Title; + Banner.LineNumber = LineNumber; + Banner.Alignment = Alignment; + + LocalBuffer = (UINT8 *) Data->Data + Data->Offset; + CopyMem (LocalBuffer, &Banner, sizeof (EFI_IFR_GUID_BANNER)); + Data->Offset += sizeof (EFI_IFR_GUID_BANNER); + + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Library/IfrSupportLib/UefiIfrString.c b/MdeModulePkg/Library/IfrSupportLib/UefiIfrString.c new file mode 100644 index 0000000000..253694032b --- /dev/null +++ b/MdeModulePkg/Library/IfrSupportLib/UefiIfrString.c @@ -0,0 +1,681 @@ +/** @file + +Copyright (c) 2007, Intel Corporation +All rights reserved. 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. + +Module Name: + + UefiIfrString.c + +Abstract: + + Common Library Routines to assist to handle String and Language. + + +**/ + +#include "UefiIfrLibraryInternal.h" + +// +// Lookup table of ISO639-2 3 character language codes to ISO 639-1 2 character language codes +// Each entry is 5 CHAR8 values long. The first 3 CHAR8 values are the ISO 639-2 code. +// The last 2 CHAR8 values are the ISO 639-1 code. +// +CHAR8 Iso639ToRfc3066ConversionTable[] = +"\ +aaraa\ +abkab\ +afraf\ +amham\ +araar\ +asmas\ +aymay\ +azeaz\ +bakba\ +belbe\ +benbn\ +bihbh\ +bisbi\ +bodbo\ +brebr\ +bulbg\ +catca\ +cescs\ +corkw\ +cosco\ +cymcy\ +danda\ +deude\ +dzodz\ +ellel\ +engen\ +epoeo\ +estet\ +euseu\ +faofo\ +fasfa\ +fijfj\ +finfi\ +frafr\ +fryfy\ +gaiga\ +gdhgd\ +glggl\ +grngn\ +gujgu\ +hauha\ +hebhe\ +hinhi\ +hrvhr\ +hunhu\ +hyehy\ +ikuiu\ +ileie\ +inaia\ +indid\ +ipkik\ +islis\ +itait\ +jawjw\ +jpnja\ +kalkl\ +kankn\ +kasks\ +katka\ +kazkk\ +khmkm\ +kinrw\ +kirky\ +korko\ +kurku\ +laolo\ +latla\ +lavlv\ +linln\ +litlt\ +ltzlb\ +malml\ +marmr\ +mkdmk\ +mlgmg\ +mltmt\ +molmo\ +monmn\ +mrimi\ +msams\ +myamy\ +nauna\ +nepne\ +nldnl\ +norno\ +ocioc\ +ormom\ +panpa\ +polpl\ +porpt\ +pusps\ +quequ\ +rohrm\ +ronro\ +runrn\ +rusru\ +sagsg\ +sansa\ +sinsi\ +slksk\ +slvsl\ +smise\ +smosm\ +snasn\ +sndsd\ +somso\ +sotst\ +spaes\ +sqisq\ +srpsr\ +sswss\ +sunsu\ +swasw\ +swesv\ +tamta\ +tattt\ +telte\ +tgktg\ +tgltl\ +thath\ +tsnts\ +tuktk\ +twitw\ +uigug\ +ukruk\ +urdur\ +uzbuz\ +vievi\ +volvo\ +wolwo\ +xhoxh\ +yidyi\ +zhaza\ +zhozh\ +zulzu\ +"; + + +/** + Convert language code from RFC3066 to ISO639-2. + + @param LanguageRfc3066 RFC3066 language code. + @param LanguageIso639 ISO639-2 language code. + + @retval EFI_SUCCESS Language code converted. + @retval EFI_NOT_FOUND Language code not found. + +**/ +EFI_STATUS +ConvertRfc3066LanguageToIso639Language ( + CHAR8 *LanguageRfc3066, + CHAR8 *LanguageIso639 + ) +{ + UINTN Index; + + if ((LanguageRfc3066[2] != '-') && (LanguageRfc3066[2] != 0)) { + CopyMem (LanguageIso639, LanguageRfc3066, 3); + return EFI_SUCCESS; + } + + for (Index = 0; Iso639ToRfc3066ConversionTable[Index] != 0; Index += 5) { + if (CompareMem (LanguageRfc3066, &Iso639ToRfc3066ConversionTable[Index + 3], 2) == 0) { + CopyMem (LanguageIso639, &Iso639ToRfc3066ConversionTable[Index], 3); + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + + +/** + Convert language code list from RFC3066 to ISO639-2, e.g. "en-US;fr-FR" will + be converted to "engfra". + + @param SupportedLanguages The RFC3066 language list. + + @return The ISO639-2 language list. + +**/ +CHAR8 * +Rfc3066ToIso639 ( + CHAR8 *SupportedLanguages + ) +{ + CHAR8 *Languages; + CHAR8 *ReturnValue; + CHAR8 *LangCodes; + CHAR8 LangRfc3066[RFC_3066_ENTRY_SIZE]; + CHAR8 LangIso639[ISO_639_2_ENTRY_SIZE]; + EFI_STATUS Status; + + ReturnValue = AllocateZeroPool (AsciiStrSize (SupportedLanguages)); + if (ReturnValue == NULL) { + return ReturnValue; + } + + Languages = ReturnValue; + LangCodes = SupportedLanguages; + while (*LangCodes != 0) { + GetNextLanguage (&LangCodes, LangRfc3066); + + Status = ConvertRfc3066LanguageToIso639Language (LangRfc3066, LangIso639); + if (!EFI_ERROR (Status)) { + CopyMem (Languages, LangIso639, 3); + Languages = Languages + 3; + } + } + + return ReturnValue; +} + + +/** + Determine what is the current language setting + + @param Lang Pointer of system language + + @return Status code + +**/ +EFI_STATUS +GetCurrentLanguage ( + OUT CHAR8 *Lang + ) +{ + EFI_STATUS Status; + UINTN Size; + + // + // Get current language setting + // + Size = RFC_3066_ENTRY_SIZE; + Status = gRT->GetVariable ( + L"PlatformLang", + &gEfiGlobalVariableGuid, + NULL, + &Size, + Lang + ); + + if (EFI_ERROR (Status)) { + AsciiStrCpy (Lang, (CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLang)); + } + + return Status; +} + + +/** + Get next language from language code list (with separator ';'). + + @param LangCode On input: point to first language in the list. On + output: point to next language in the list, or + NULL if no more language in the list. + @param Lang The first language in the list. + + @return None. + +**/ +VOID +GetNextLanguage ( + IN OUT CHAR8 **LangCode, + OUT CHAR8 *Lang + ) +{ + UINTN Index; + CHAR8 *StringPtr; + + if (LangCode == NULL || *LangCode == NULL) { + *Lang = 0; + return; + } + + Index = 0; + StringPtr = *LangCode; + while (StringPtr[Index] != 0 && StringPtr[Index] != ';') { + Index++; + } + + CopyMem (Lang, StringPtr, Index); + Lang[Index] = 0; + + if (StringPtr[Index] == ';') { + Index++; + } + *LangCode = StringPtr + Index; +} + + +/** + This function returns the list of supported languages, in the format specified + in UEFI specification Appendix M. + + @param HiiHandle The HII package list handle. + + @return The supported languages. + +**/ +CHAR8 * +GetSupportedLanguages ( + IN EFI_HII_HANDLE HiiHandle + ) +{ + EFI_STATUS Status; + UINTN BufferSize; + CHAR8 *LanguageString; + + LocateHiiProtocols (); + + // + // Collect current supported Languages for given HII handle + // + BufferSize = 0x1000; + LanguageString = AllocatePool (BufferSize); + Status = gIfrLibHiiString->GetLanguages (gIfrLibHiiString, HiiHandle, LanguageString, &BufferSize); + if (Status == EFI_BUFFER_TOO_SMALL) { + gBS->FreePool (LanguageString); + LanguageString = AllocatePool (BufferSize); + Status = gIfrLibHiiString->GetLanguages (gIfrLibHiiString, HiiHandle, LanguageString, &BufferSize); + } + + if (EFI_ERROR (Status)) { + LanguageString = NULL; + } + + return LanguageString; +} + + +/** + This function returns the number of supported languages + + @param HiiHandle The HII package list handle. + + @return The number of supported languages. + +**/ +UINT16 +GetSupportedLanguageNumber ( + IN EFI_HII_HANDLE HiiHandle + ) +{ + CHAR8 *Languages; + CHAR8 *LanguageString; + UINT16 LangNumber; + CHAR8 Lang[RFC_3066_ENTRY_SIZE]; + + Languages = GetSupportedLanguages (HiiHandle); + if (Languages == NULL) { + return 0; + } + + LangNumber = 0; + LanguageString = Languages; + while (*LanguageString != 0) { + GetNextLanguage (&LanguageString, Lang); + LangNumber++; + } + gBS->FreePool (Languages); + + return LangNumber; +} + + +/** + Get string specified by StringId form the HiiHandle. + + @param HiiHandle The HII handle of package list. + @param StringId The String ID. + @param String The output string. + + @retval EFI_NOT_FOUND String is not found. + @retval EFI_SUCCESS Operation is successful. + @retval EFI_OUT_OF_RESOURCES There is not enought memory in the system. + @retval EFI_INVALID_PARAMETER The String is NULL. + +**/ +EFI_STATUS +GetStringFromHandle ( + IN EFI_HII_HANDLE HiiHandle, + IN EFI_STRING_ID StringId, + OUT EFI_STRING *String + ) +{ + EFI_STATUS Status; + UINTN StringSize; + + if (String == NULL) { + return EFI_INVALID_PARAMETER; + } + + StringSize = IFR_LIB_DEFAULT_STRING_SIZE; + *String = AllocateZeroPool (StringSize); + if (*String == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = IfrLibGetString (HiiHandle, StringId, *String, &StringSize); + if (Status == EFI_BUFFER_TOO_SMALL) { + gBS->FreePool (*String); + *String = AllocateZeroPool (StringSize); + if (*String == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Status = IfrLibGetString (HiiHandle, StringId, *String, &StringSize); + } + + return Status; +} + + +/** + Get the string given the StringId and String package Producer's Guid. + + @param ProducerGuid The Guid of String package list. + @param StringId The String ID. + @param String The output string. + + @retval EFI_NOT_FOUND String is not found. + @retval EFI_SUCCESS Operation is successful. + @retval EFI_OUT_OF_RESOURCES There is not enought memory in the system. + +**/ +EFI_STATUS +GetStringFromToken ( + IN EFI_GUID *ProducerGuid, + IN EFI_STRING_ID StringId, + OUT EFI_STRING *String + ) +{ + EFI_STATUS Status; + UINTN Index; + UINTN HandleBufferLen; + EFI_HII_HANDLE *HiiHandleBuffer; + EFI_GUID Guid; + + Status = GetHiiHandles (&HandleBufferLen, &HiiHandleBuffer); + if (EFI_ERROR(Status)) { + return Status; + } + for (Index = 0; Index < (HandleBufferLen / sizeof (EFI_HII_HANDLE)); Index++) { + Status = ExtractGuidFromHiiHandle (HiiHandleBuffer[Index], &Guid); + if (EFI_ERROR(Status)) { + return Status; + } + if (CompareGuid (&Guid, ProducerGuid) == TRUE) { + break; + } + } + + if (Index >= (HandleBufferLen / sizeof (EFI_HII_HANDLE))) { + Status = EFI_NOT_FOUND; + goto Out; + } + + Status = GetStringFromHandle (HiiHandleBuffer[Index], StringId, String); + +Out: + if (HiiHandleBuffer != NULL) { + gBS->FreePool (HiiHandleBuffer); + } + return Status; +} + + +/** + This function adds the string into String Package of each language. + + @param PackageList Handle of the package list where this string will + be added. + @param StringId On return, contains the new strings id, which is + unique within PackageList. + @param String Points to the new null-terminated string. + + @retval EFI_SUCCESS The new string was added successfully. + @retval EFI_NOT_FOUND The specified PackageList could not be found in + database. + @retval EFI_OUT_OF_RESOURCES Could not add the string due to lack of resources. + @retval EFI_INVALID_PARAMETER String is NULL or StringId is NULL is NULL. + +**/ +EFI_STATUS +IfrLibNewString ( + IN EFI_HII_HANDLE PackageList, + OUT EFI_STRING_ID *StringId, + IN CONST EFI_STRING String + ) +{ + EFI_STATUS Status; + CHAR8 *Languages; + CHAR8 *LangStrings; + CHAR8 Lang[RFC_3066_ENTRY_SIZE]; + + Status = EFI_SUCCESS; + + LocateHiiProtocols (); + + Languages = GetSupportedLanguages (PackageList); + + LangStrings = Languages; + while (*LangStrings != 0) { + GetNextLanguage (&LangStrings, Lang); + + Status = gIfrLibHiiString->NewString ( + gIfrLibHiiString, + PackageList, + StringId, + Lang, + NULL, + String, + NULL + ); + if (EFI_ERROR (Status)) { + break; + } + } + + gBS->FreePool (Languages); + + return Status; +} + + +/** + This function try to retrieve string from String package of current language. + If fail, it try to retrieve string from String package of first language it support. + + @param PackageList The package list in the HII database to search for + the specified string. + @param StringId The string's id, which is unique within + PackageList. + @param String Points to the new null-terminated string. + @param StringSize On entry, points to the size of the buffer pointed + to by String, in bytes. On return, points to the + length of the string, in bytes. + + @retval EFI_SUCCESS The string was returned successfully. + @retval EFI_NOT_FOUND The string specified by StringId is not available. + @retval EFI_BUFFER_TOO_SMALL The buffer specified by StringLength is too small + to hold the string. + @retval EFI_INVALID_PARAMETER The String or StringSize was NULL. + +**/ +EFI_STATUS +IfrLibGetString ( + IN EFI_HII_HANDLE PackageList, + IN EFI_STRING_ID StringId, + OUT EFI_STRING String, + IN OUT UINTN *StringSize + ) +{ + EFI_STATUS Status; + CHAR8 *Languages; + CHAR8 *LangStrings; + CHAR8 Lang[RFC_3066_ENTRY_SIZE]; + CHAR8 CurrentLang[RFC_3066_ENTRY_SIZE]; + + LocateHiiProtocols (); + + GetCurrentLanguage (CurrentLang); + + Status = gIfrLibHiiString->GetString ( + gIfrLibHiiString, + CurrentLang, + PackageList, + StringId, + String, + StringSize, + NULL + ); + + if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) { + Languages = GetSupportedLanguages (PackageList); + LangStrings = Languages; + GetNextLanguage (&LangStrings, Lang); + gBS->FreePool (Languages); + + Status = gIfrLibHiiString->GetString ( + gIfrLibHiiString, + Lang, + PackageList, + StringId, + String, + StringSize, + NULL + ); + } + + return Status; +} + + +/** + This function updates the string in String package of each language. + + @param PackageList The package list containing the strings. + @param StringId The string's id, which is unique within + PackageList. + @param String Points to the new null-terminated string. + + @retval EFI_SUCCESS The string was updated successfully. + @retval EFI_NOT_FOUND The string specified by StringId is not in the + database. + @retval EFI_INVALID_PARAMETER The String was NULL. + @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the + task. + +**/ +EFI_STATUS +IfrLibSetString ( + IN EFI_HII_HANDLE PackageList, + IN EFI_STRING_ID StringId, + IN CONST EFI_STRING String + ) +{ + EFI_STATUS Status; + CHAR8 *Languages; + CHAR8 *LangStrings; + CHAR8 Lang[RFC_3066_ENTRY_SIZE]; + + Status = EFI_SUCCESS; + + LocateHiiProtocols (); + + Languages = GetSupportedLanguages (PackageList); + + LangStrings = Languages; + while (*LangStrings != 0) { + GetNextLanguage (&LangStrings, Lang); + + Status = gIfrLibHiiString->SetString ( + gIfrLibHiiString, + PackageList, + StringId, + Lang, + String, + NULL + ); + if (EFI_ERROR (Status)) { + break; + } + } + + gBS->FreePool (Languages); + + return Status; +} + diff --git a/MdeModulePkg/Library/PlatformBdsLibNull/BdsPlatform.c b/MdeModulePkg/Library/PlatformBdsLibNull/BdsPlatform.c new file mode 100644 index 0000000000..85633a9dc9 --- /dev/null +++ b/MdeModulePkg/Library/PlatformBdsLibNull/BdsPlatform.c @@ -0,0 +1,276 @@ +/*++
+
+Copyright (c) 2004 - 2006, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ BdsPlatform.c
+
+Abstract:
+
+ This file include all platform action which can be customized
+ by IBV/OEM.
+
+--*/
+
+#include "BdsPlatform.h"
+
+//
+// BDS Platform Functions
+//
+VOID
+PlatformBdsInit (
+ IN EFI_BDS_ARCH_PROTOCOL_INSTANCE *PrivateData
+ )
+/*++
+
+Routine Description:
+
+ Platform Bds init. Incude the platform firmware vendor, revision
+ and so crc check.
+
+Arguments:
+
+ PrivateData - The EFI_BDS_ARCH_PROTOCOL_INSTANCE instance
+
+Returns:
+
+ None.
+
+--*/
+{
+ return;
+}
+
+EFI_STATUS
+PlatformBdsConnectConsole (
+ IN BDS_CONSOLE_CONNECT_ENTRY *PlatformConsole
+ )
+/*++
+
+Routine Description:
+
+ Connect the predefined platform default console device. Always try to find
+ and enable the vga device if have.
+
+Arguments:
+
+ PlatformConsole - Predfined platform default console device array.
+
+Returns:
+
+ EFI_SUCCESS - Success connect at least one ConIn and ConOut
+ device, there must have one ConOut device is
+ active vga device.
+
+ EFI_STATUS - Return the status of
+ BdsLibConnectAllDefaultConsoles ()
+
+--*/
+{
+ return EFI_SUCCESS;
+}
+
+VOID
+PlatformBdsConnectSequence (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Connect with predeined platform connect sequence,
+ the OEM/IBV can customize with their own connect sequence.
+
+Arguments:
+
+ None.
+
+Returns:
+
+ None.
+
+--*/
+{
+ return;
+}
+
+VOID
+PlatformBdsGetDriverOption (
+ IN OUT LIST_ENTRY *BdsDriverLists
+ )
+/*++
+
+Routine Description:
+
+ Load the predefined driver option, OEM/IBV can customize this
+ to load their own drivers
+
+Arguments:
+
+ BdsDriverLists - The header of the driver option link list.
+
+Returns:
+
+ None.
+
+--*/
+{
+ return;
+}
+
+VOID
+PlatformBdsDiagnostics (
+ IN EXTENDMEM_COVERAGE_LEVEL MemoryTestLevel,
+ IN BOOLEAN QuietBoot
+ )
+/*++
+
+Routine Description:
+
+ Perform the platform diagnostic, such like test memory. OEM/IBV also
+ can customize this fuction to support specific platform diagnostic.
+
+Arguments:
+
+ MemoryTestLevel - The memory test intensive level
+
+ QuietBoot - Indicate if need to enable the quiet boot
+
+Returns:
+
+ None.
+
+--*/
+{
+ return;
+}
+
+VOID
+PlatformBdsPolicyBehavior (
+ IN EFI_BDS_ARCH_PROTOCOL_INSTANCE *PrivateData,
+ IN OUT LIST_ENTRY *DriverOptionList,
+ IN OUT LIST_ENTRY *BootOptionList
+ )
+/*++
+
+Routine Description:
+
+ The function will excute with as the platform policy, current policy
+ is driven by boot mode. IBV/OEM can customize this code for their specific
+ policy action.
+
+Arguments:
+
+ PrivateData - The EFI_BDS_ARCH_PROTOCOL_INSTANCE instance
+
+ DriverOptionList - The header of the driver option link list
+
+ BootOptionList - The header of the boot option link list
+
+Returns:
+
+ None.
+
+--*/
+{
+ return ;
+}
+
+VOID
+PlatformBdsBootSuccess (
+ IN BDS_COMMON_OPTION *Option
+ )
+/*++
+
+Routine Description:
+
+ Hook point after a boot attempt succeeds. We don't expect a boot option to
+ return, so the EFI 1.0 specification defines that you will default to an
+ interactive mode and stop processing the BootOrder list in this case. This
+ is alos a platform implementation and can be customized by IBV/OEM.
+
+Arguments:
+
+ Option - Pointer to Boot Option that succeeded to boot.
+
+Returns:
+
+ None.
+
+--*/
+{
+ return;
+}
+
+VOID
+PlatformBdsBootFail (
+ IN BDS_COMMON_OPTION *Option,
+ IN EFI_STATUS Status,
+ IN CHAR16 *ExitData,
+ IN UINTN ExitDataSize
+ )
+/*++
+
+Routine Description:
+
+ Hook point after a boot attempt fails.
+
+Arguments:
+
+ Option - Pointer to Boot Option that failed to boot.
+
+ Status - Status returned from failed boot.
+
+ ExitData - Exit data returned from failed boot.
+
+ ExitDataSize - Exit data size returned from failed boot.
+
+Returns:
+
+ None.
+
+--*/
+{
+ return;
+}
+
+EFI_STATUS
+PlatformBdsNoConsoleAction (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function is remained for IBV/OEM to do some platform action,
+ if there no console device can be connected.
+
+Arguments:
+
+ None.
+
+Returns:
+
+ EFI_SUCCESS - Direct return success now.
+
+--*/
+{
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+PlatformBdsLockNonUpdatableFlash (
+ VOID
+ )
+{
+ return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Library/PlatformBdsLibNull/BdsPlatform.h b/MdeModulePkg/Library/PlatformBdsLibNull/BdsPlatform.h new file mode 100644 index 0000000000..8332f6cc90 --- /dev/null +++ b/MdeModulePkg/Library/PlatformBdsLibNull/BdsPlatform.h @@ -0,0 +1,37 @@ +/*++
+
+Copyright (c) 2004 - 2006, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ BdsPlatform.h
+
+Abstract:
+
+ Head file for BDS Platform specific code
+
+--*/
+
+#ifndef _BDS_PLATFORM_H
+#define _BDS_PLATFORM_H
+
+#include <PiDxe.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/GenericBdsLib.h>
+#include <Library/PlatformBdsLib.h>
+#include <Library/GraphicsLib.h>
+
+#endif // _BDS_PLATFORM_H
diff --git a/MdeModulePkg/Library/PlatformBdsLibNull/PlatformBdsLibNull.inf b/MdeModulePkg/Library/PlatformBdsLibNull/PlatformBdsLibNull.inf new file mode 100644 index 0000000000..ce8535f26e --- /dev/null +++ b/MdeModulePkg/Library/PlatformBdsLibNull/PlatformBdsLibNull.inf @@ -0,0 +1,55 @@ +#/** @file
+# Component name for module GenericBdsLib
+#
+# FIX ME!
+# Copyright (c) 2007, Intel Corporation. All rights reserved.
+#
+# All rights reserved. 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 = 0x00010005
+ BASE_NAME = PlatformBdsLib
+ FILE_GUID = 143B5044-7C1B-4904-9778-EA16F1F3D554
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PlatformBdsLib|DXE_DRIVER
+ EDK_RELEASE_VERSION = 0x00020000
+ EFI_SPECIFICATION_VERSION = 0x0002000A
+
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+ BdsPlatform.c
+ PlatformData.c
+ BdsPlatform.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ PcdLib
+ GraphicsLib
+ GenericBdsLib
+
+[Guids]
+ gEfiDefaultBmpLogoGuid
diff --git a/MdeModulePkg/Library/PlatformBdsLibNull/PlatformData.c b/MdeModulePkg/Library/PlatformBdsLibNull/PlatformData.c new file mode 100644 index 0000000000..0b19277046 --- /dev/null +++ b/MdeModulePkg/Library/PlatformBdsLibNull/PlatformData.c @@ -0,0 +1,52 @@ +/*++
+
+Copyright (c) 2004 - 2006, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ PlatformData.c
+
+Abstract:
+
+ Defined the platform specific device path which will be used by
+ platform Bbd to perform the platform policy connect.
+
+--*/
+
+#include "BdsPlatform.h"
+
+//
+// Predefined platform default time out value
+//
+UINT16 gPlatformBootTimeOutDefault = 10;
+
+//
+// Platform specific keyboard device path
+//
+
+//
+// Predefined platform default console device path
+//
+BDS_CONSOLE_CONNECT_ENTRY gPlatformConsole[] = {
+ {
+ NULL,
+ 0
+ }
+};
+
+//
+// Predefined platform specific driver option
+//
+EFI_DEVICE_PATH_PROTOCOL *gPlatformDriverOption[] = { NULL };
+
+//
+// Predefined platform connect sequence
+//
+EFI_DEVICE_PATH_PROTOCOL *gPlatformConnectSequence[] = { NULL };
diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index f182323a45..907a06d3f4 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -33,6 +33,7 @@ UdpIoLib|Include/Library/UdpIoLib.h
S3Lib|Include/Library/S3Lib.h
RecoveryLib|Include/Library/RecoveryLib.h
+ GenericBdsLib.h|Include/Library/GenericBdsLib.h
PlatDriOverLib|Include/Library/PlatDriOverLib.h
[Guids.common]
@@ -123,6 +124,7 @@ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutGopSupport|TRUE|BOOLEAN|0x00010042
gEfiMdeModulePkgTokenSpaceGuid.PcdConOutUgaSupport|TRUE|BOOLEAN|0x00010043
gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreImageLoaderSearchTeSectionFirst|TRUE|BOOLEAN|0x00010044
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSupportHardwareErrorRecord|FALSE|BOOLEAN|0x00010044
[PcdsFixedAtBuild.common]
gEfiMdeModulePkgTokenSpaceGuid.PcdMaxPeiPcdCallBackNumberPerPcdEntry|0x08|UINT32|0x0001000f
@@ -141,6 +143,8 @@ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize|0x0|UINT32|0x30000014
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase|0x0|UINT32|0x30000010
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize|0x0|UINT32|0x30000011
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPlatformBootTimeOutDefault|10|UINT16|0x40000001
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHardwareErrorRecordLevel|1|UINT16|0x40000002
[PcdsDynamic.common]
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase|0x0|UINT32|0x30000001
@@ -149,6 +153,8 @@ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize|0x0|UINT32|0x30000014
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase|0x0|UINT32|0x30000010
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize|0x0|UINT32|0x30000011
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPlatformBootTimeOutDefault|10|UINT16|0x40000001
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHardwareErrorRecordLevel|1|UINT16|0x40000002
[PcdsPatchableInModule.common]
gEfiMdeModulePkgTokenSpaceGuid.PcdMaxPeiPerformanceLogEntries|40|UINT8|0x0001002f
@@ -158,7 +164,8 @@ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize|0x0|UINT32|0x30000014
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase|0x0|UINT32|0x30000010
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize|0x0|UINT32|0x30000011
-
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPlatformBootTimeOutDefault|10|UINT16|0x40000001
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHardwareErrorRecordLevel|1|UINT16|0x40000002
[PcdsFeatureFlag.IA32]
gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode|TRUE|BOOLEAN|0x0001003b
diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc index 637cdfbe80..34854f5e1a 100644 --- a/MdeModulePkg/MdeModulePkg.dsc +++ b/MdeModulePkg/MdeModulePkg.dsc @@ -35,8 +35,6 @@ PciExpressLib|MdePkg/Library/BasePciExpressLib/BasePciExpressLib.inf
PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf
PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf
- FrameworkIfrSupportLib|IntelFrameworkPkg/Library/FrameworkIfrSupportLib/IfrSupportLib.inf
-
PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf
PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf
PostCodeLib|MdePkg/Library/BasePostCodeLibDebug/BasePostCodeLibDebug.inf
@@ -64,14 +62,24 @@ UefiRuntimeLib|MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf
FvbServiceLib|MdeModulePkg/Library/EdkFvbServiceLib/EdkFvbServiceLib.inf
ScsiLib|MdePkg/Library/UefiScsiLib/UefiScsiLib.inf
- FrameworkHiiLib|IntelFrameworkPkg/Library/FrameworkHiiLib/HiiLib.inf
+ HiiLib|MdePkg/Library/HiiLib/HiiLib.inf
UsbLib|MdePkg/Library/UefiUsbLib/UefiUsbLib.inf
NetLib|MdeModulePkg/Library/DxeNetLib/DxeNetLib.inf
IpIoLib|MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.inf
UdpIoLib|MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf
DpcLib|MdeModulePkg/Library/DxeDpcLib/DxeDpcLib.inf
PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+ GraphicsLib|MdeModulepkg/Library/GraphicsLib/GraphicsLib.inf
+ IfrSupportLib|MdeModulePkg/Library/IfrSupportLib/IfrSupportLib.inf
CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf
+ DxePiLib|MdePkg/Library/DxePiLib/DxePiLib.inf
+ PlatformBdsLib|MdeModulePkg/Library/PlatformBdsLibNull/PlatformBdsLibNull.inf
+ GenericBdsLib|MdeModulePkg/Library/GenericBdsLib/GenericBdsLib.inf
+ GraphicsLib|MdeModulepkg/Library/GraphicsLib/GraphicsLib.inf
+ IfrSupportLib|MdeModulePkg/Library/IfrSupportLib/IfrSupportLib.inf
+ DxePiLib|MdePkg/Library/DxePiLib/DxePiLib.inf
+ PlatformBdsLib|MdeModulePkg/Library/PlatformBdsLibNull/PlatformBdsLibNull.inf
+ GenericBdsLib|MdeModulePkg/Library/GenericBdsLib/GenericBdsLib.inf
PlatDriOverLib|MdeModulePkg/Library/DxePlatDriOverLib/DxePlatDriOverLib.inf
[LibraryClasses.IA32]
@@ -261,9 +269,16 @@ MdeModulePkg/Library/PeiS3LibNull/PeiS3LibNull.inf
MdeModulePkg/Library/PeiRecoveryLibNull/PeiRecoveryLibNull.inf
+ MdeModulePkg/Library/IfrSupportLib/IfrSupportLib.inf
+ MdeModulePkg/Library/GenericBdsLib/GenericBdsLib.inf
+ MdeModulepkg/Library/GraphicsLib/GraphicsLib.inf
+
+ MdeModulePkg/Library/PlatformBdsLibNull/PlatformBdsLibNull.inf
+
MdeModulePkg/Universal/iScsi/IScsi.inf
MdeModulePkg/Universal/Network/ArpDxe/ArpDxe.inf
+ MdeModulePkg/Universal/BdsDxe/BdsDxe.inf
MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Dxe.inf
MdeModulePkg/Universal/Network/Ip4ConfigDxe/Ip4ConfigDxe.inf
MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Dxe.inf
@@ -317,6 +332,10 @@ MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
MdeModulePkg/Universal/Variable/Application/VariableInfo.inf
+ MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf
+ MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf
+ MdeModulePkg/Universal/DriverSampleDxe/DriverSampleDxe.inf
+
[Components.IA32]
MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
@@ -324,6 +343,7 @@ MdeModulePkg/Universal/DebugSupportDxe/DebugSupportDxe.inf
MdeModulePkg/Universal/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf
MdeModulePkg/Bus/Pci/UndiRuntimeDxe/UndiRuntimeDxe.inf
+ MdeModulepkg/Library/GraphicsLib/GraphicsLib.inf
[Components.X64]
MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
diff --git a/MdeModulePkg/Universal/BdsDxe/Bds.h b/MdeModulePkg/Universal/BdsDxe/Bds.h new file mode 100644 index 0000000000..fbfa9658da --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/Bds.h @@ -0,0 +1,117 @@ +/*++
+
+Copyright (c) 2004 - 2007, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ Bds.h
+
+Abstract:
+
+ Head file for BDS Architectural Protocol implementation
+
+Revision History
+
+--*/
+
+#ifndef _BDS_MODULE_H_
+#define _BDS_MODULE_H_
+
+#undef EFI_SPECIFICATION_VERSION
+#define EFI_SPECIFICATION_VERSION 0x0002000A
+#include <PiDxe.h>
+#include <MdeModuleHii.h>
+
+#include <Guid/FileSystemVolumeLabelInfo.h>
+#include <Protocol/DevicePath.h>
+#include <Guid/BootState.h>
+#include <Guid/DataHubRecords.h>
+#include <Protocol/LoadFile.h>
+#include <Protocol/CpuIo.h>
+#include <Guid/HobList.h>
+#include <Guid/FileInfo.h>
+#include <Protocol/HiiConfigRouting.h>
+#include <Protocol/Bds.h>
+#include <Protocol/DataHub.h>
+#include <Protocol/UgaDraw.h>
+#include <Protocol/BlockIo.h>
+#include <Guid/GlobalVariable.h>
+#include <Guid/GenericPlatformVariable.h>
+#include <Guid/CapsuleVendor.h>
+#include <Protocol/ConsoleControl.h>
+#include <Protocol/GenericMemoryTest.h>
+#include <Protocol/FormBrowser2.h>
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/HiiDatabase.h>
+#include <Protocol/HiiString.h>
+#include <Protocol/SerialIo.h>
+#include <Protocol/LegacyBios.h>
+#include <Protocol/SimpleTextInEx.h>
+#include <Protocol/Performance.h>
+
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/PrintLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/GraphicsLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/PerformanceLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/IfrSupportLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/HobLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PcdLib.h>
+#include <Library/CapsuleLib.h>
+#include <Library/HiiLib.h>
+
+#include <Library/GenericBdsLib.h>
+#include <Library/PlatformBdsLib.h>
+
+#define EFI_BDS_ARCH_PROTOCOL_INSTANCE_FROM_THIS(_this) \
+ CR (_this, \
+ EFI_BDS_ARCH_PROTOCOL_INSTANCE, \
+ Bds, \
+ EFI_BDS_ARCH_PROTOCOL_INSTANCE_SIGNATURE \
+ )
+
+EFI_STATUS
+PlatformBdsShowProgress (
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleForeground,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleBackground,
+ IN CHAR16 *Title,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL ProgressColor,
+ IN UINTN Progress,
+ IN UINTN PreviousValue
+ );
+
+//
+// Prototypes
+//
+EFI_STATUS
+EFIAPI
+BdsInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+VOID
+EFIAPI
+BdsEntry (
+ IN EFI_BDS_ARCH_PROTOCOL *This
+ );
+
+#endif
diff --git a/MdeModulePkg/Universal/BdsDxe/BdsDxe.inf b/MdeModulePkg/Universal/BdsDxe/BdsDxe.inf new file mode 100644 index 0000000000..c4c6b7fd8f --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/BdsDxe.inf @@ -0,0 +1,154 @@ +#/** @file
+# Component discription file for Bds module
+#
+# N/A
+# Copyright (c) 2008, Intel Corporation
+#
+# All rights reserved. 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 = 0x00010005
+ BASE_NAME = Bds
+ FILE_GUID = FC5C7020-1A48-4198-9BE2-EAD5ABC8CF2F
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ EDK_RELEASE_VERSION = 0x00020000
+ EFI_SPECIFICATION_VERSION = 0x00020000
+
+ ENTRY_POINT = BdsInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+ FrontPage.h
+ Language.h
+ Bds.h
+ Hotkey.h
+ BootMaint/BBSsupport.h
+ BootMngr/BootManager.h
+ BootMaint/BootMaint.h
+ String.h
+ BootMaint/FormGuid.h
+ HwErrRecSupport.c
+ HwErrRecSupport.h
+
+ DeviceMngr/DeviceManager.h
+ DeviceMngr/DeviceManagerVfr.Vfr
+ DeviceMngr/DeviceManagerStrings.uni
+ DeviceMngr/DeviceManager.c
+ BootMngr/BootManagerVfr.Vfr
+ BootMngr/BootManagerStrings.uni
+ BootMngr/BootManager.c
+ BootMaint/FE.vfr
+ BootMaint/FileExplorer.c
+ BootMaint/BootMaint.c
+ BootMaint/BBSsupport.c
+ BootMaint/UpdatePage.c
+ BootMaint/Variable.c
+ BootMaint/Data.c
+ BootMaint/ConsoleOption.c
+ BootMaint/BootOption.c
+ BootMaint/BmLib.c
+ BootMaint/Bm.vfr
+ BootMaint/Bmstring.uni
+ Hotkey.c
+ MemoryTest.c
+ Capsules.c
+ Strings.uni
+ String.c
+ Language.c
+ FrontPageVfr.Vfr
+ FrontPageStrings.uni
+ FrontPage.c
+ BdsEntry.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+
+
+[LibraryClasses]
+ DevicePathLib
+ BaseLib
+ HobLib
+ UefiRuntimeServicesTableLib
+ IfrSupportLib
+ GenericBdsLib
+ ReportStatusCodeLib
+ PerformanceLib
+ DxeServicesTableLib
+ MemoryAllocationLib
+ GraphicsLib
+ UefiLib
+ UefiBootServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ PrintLib
+ HiiLib
+ UefiDriverEntryPoint
+ PlatformBdsLib
+ CapsuleLib
+
+[Guids]
+ gEfiGlobalVariableGuid # ALWAYS_CONSUMED
+ gEfiHobListGuid # ALWAYS_CONSUMED
+ gEfiBootStateGuid # ALWAYS_CONSUMED
+ gEfiFileSystemVolumeLabelInfoIdGuid # ALWAYS_CONSUMED
+ gEfiFileInfoGuid # ALWAYS_CONSUMED
+ gEfiGenericPlatformVariableGuid
+ gEfiMiscSubClassGuid
+ gEfiMemorySubClassGuid
+ gEfiProcessorSubClassGuid
+ gEfiCapsuleVendorGuid
+
+[Protocols]
+ gEfiHiiStringProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiSimpleFileSystemProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiLoadFileProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiCpuIoProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiBdsArchProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiDataHubProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiGenericMemTestProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiLegacyBiosProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiConsoleControlProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiHiiDatabaseProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiUgaDrawProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiBlockIoProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiGraphicsOutputProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiSimpleTextInputExProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiHiiConfigRoutingProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiHiiConfigAccessProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiFormBrowser2ProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiSerialIoProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiAcpiS3SaveProtocolGuid
+
+[FeaturePcd.common]
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLangDepricate
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSupportHardwareErrorRecord
+
+[Pcd.common]
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLangCodes
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLang
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultPlatformLangCodes
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultPlatformLang
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHardwareErrorRecordLevel
+
+[Depex]
+ gEfiHiiDatabaseProtocolGuid
+
diff --git a/MdeModulePkg/Universal/BdsDxe/BdsDxe.msa b/MdeModulePkg/Universal/BdsDxe/BdsDxe.msa new file mode 100644 index 0000000000..25547558ae --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/BdsDxe.msa @@ -0,0 +1,238 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <MsaHeader>
+ <ModuleName>BdsDxe</ModuleName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <GuidValue>FC5C7020-1A48-4198-9BE2-EAD5ABC8CF2F</GuidValue>
+ <Version>1.0</Version>
+ <Abstract>Component discription file for Bds module</Abstract>
+ <Description>N/A</Description>
+ <Copyright>Copyright (c) 2008, Intel Corporation</Copyright>
+ <License>All rights reserved. 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.</License>
+ <Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
+ </MsaHeader>
+ <ModuleDefinitions>
+ <SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>
+ <BinaryModule>false</BinaryModule>
+ <OutputFileBasename>Bds</OutputFileBasename>
+ </ModuleDefinitions>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiDriverEntryPoint</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>PrintLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>DebugLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>BaseMemoryLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>EfiShellLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>EdkGenericPlatformBdsLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiBootServicesTableLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>EdkGraphicsLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>MemoryAllocationLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>DxeServicesTableLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>PerformanceLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>ReportStatusCodeLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>EdkGenericBdsLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>EdkIfrSupportLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiRuntimeServicesTableLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>HobLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>BaseLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>DevicePathLib</Keyword>
+ </LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>BdsEntry.c</Filename>
+ <Filename>FrontPage.c</Filename>
+ <Filename>FrontPageStrings.uni</Filename>
+ <Filename>FrontPageVfr.Vfr</Filename>
+ <Filename>Language.c</Filename>
+ <Filename>String.c</Filename>
+ <Filename>Strings.uni</Filename>
+ <Filename>Capsules.c</Filename>
+ <Filename>MemoryTest.c</Filename>
+ <Filename>Hotkey.c</Filename>
+ <Filename>BootMaint/Bmstring.uni</Filename>
+ <Filename>BootMaint/Bm.vfr</Filename>
+ <Filename>BootMaint/BmLib.c</Filename>
+ <Filename>BootMaint/BootOption.c</Filename>
+ <Filename>BootMaint/ConsoleOption.c</Filename>
+ <Filename>BootMaint/Data.c</Filename>
+ <Filename>BootMaint/Variable.c</Filename>
+ <Filename>BootMaint/UpdatePage.c</Filename>
+ <Filename>BootMaint/BBSsupport.c</Filename>
+ <Filename>BootMaint/BootMaint.c</Filename>
+ <Filename>BootMaint/FileExplorer.c</Filename>
+ <Filename>BootMaint/FE.vfr</Filename>
+ <Filename>BootMngr/BootManager.c</Filename>
+ <Filename>BootMngr/BootManagerStrings.uni</Filename>
+ <Filename>BootMngr/BootManagerVfr.Vfr</Filename>
+ <Filename>DeviceMngr/DeviceManager.c</Filename>
+ <Filename>DeviceMngr/DeviceManagerStrings.uni</Filename>
+ <Filename>DeviceMngr/DeviceManagerVfr.Vfr</Filename>
+ <Filename>Bds.dxs</Filename>
+ <Filename>DeviceMngr/DeviceManager.h</Filename>
+ <Filename>BootMaint/FormGuid.h</Filename>
+ <Filename>String.h</Filename>
+ <Filename>BootMaint/BootMaint.h</Filename>
+ <Filename>BootMngr/BootManager.h</Filename>
+ <Filename>BootMaint/BBSsupport.h</Filename>
+ <Filename>Hotkey.h</Filename>
+ <Filename>Bds.h</Filename>
+ <Filename>Language.h</Filename>
+ <Filename>FrontPage.h</Filename>
+ <Filename>EdkILib.c</Filename>
+ </SourceFiles>
+ <NonProcessedFiles>
+ <Filename>DeviceMngr/PlatOverMngr/PlatOverMngr.c</Filename>
+ <Filename>DeviceMngr/PlatOverMngr/PlatOverMngr.dxs</Filename>
+ <Filename>DeviceMngr/PlatOverMngr/PlatOverMngr.h</Filename>
+ <Filename>DeviceMngr/PlatOverMngr/Vfr.vfr</Filename>
+ <Filename>DeviceMngr/PlatOverMngr/VfrStrings.uni</Filename>
+ <Filename>DeviceMngr/SetOptions/GetInfo.c</Filename>
+ <Filename>DeviceMngr/SetOptions/GetInfo.h</Filename>
+ <Filename>DeviceMngr/SetOptions/SetOptions.c</Filename>
+ <Filename>DeviceMngr/SetOptions/SetOptions.h</Filename>
+ <Filename>DeviceMngr/SetOptions/Vfr.vfr</Filename>
+ <Filename>DeviceMngr/SetOptions/VfrStrings.uni</Filename>
+ <Filename>HwErrRecSupport.c</Filename>
+ <Filename>HwErrRecSupport.h</Filename>
+ </NonProcessedFiles>
+ <PackageDependencies>
+ <Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>
+ <Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>
+ <Package PackageGuid="3bd11b88-bf8b-4d90-9e04-77c97e58bbdd"/>
+ </PackageDependencies>
+ <Protocols>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiDevicePathProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiSerialIoProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiFormBrowser2ProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiHiiConfigAccessProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiHiiConfigRoutingProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiSimpleTextInputExProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiGraphicsOutputProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiBlockIoProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiUgaDrawProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiHiiDatabaseProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiConsoleControlProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiLegacyBiosProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiGenericMemTestProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiDataHubProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiBdsArchProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiCpuIoProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiLoadFileProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiSimpleFileSystemProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiHiiStringProtocolGuid</ProtocolCName>
+ </Protocol>
+ </Protocols>
+ <Guids>
+ <GuidCNames Usage="ALWAYS_CONSUMED">
+ <GuidCName>gEfiFlashMapHobGuid</GuidCName>
+ </GuidCNames>
+ <GuidCNames Usage="ALWAYS_CONSUMED">
+ <GuidCName>gTerminalDriverGuid</GuidCName>
+ </GuidCNames>
+ <GuidCNames Usage="ALWAYS_CONSUMED">
+ <GuidCName>gEfiFileInfoGuid</GuidCName>
+ </GuidCNames>
+ <GuidCNames Usage="ALWAYS_CONSUMED">
+ <GuidCName>gEfiFileSystemVolumeLabelInfoIdGuid</GuidCName>
+ </GuidCNames>
+ <GuidCNames Usage="ALWAYS_CONSUMED">
+ <GuidCName>gEfiBootStateGuid</GuidCName>
+ </GuidCNames>
+ <GuidCNames Usage="ALWAYS_CONSUMED">
+ <GuidCName>gEfiHobListGuid</GuidCName>
+ </GuidCNames>
+ <GuidCNames Usage="ALWAYS_CONSUMED">
+ <GuidCName>gEfiGenericVariableGuid</GuidCName>
+ </GuidCNames>
+ <GuidCNames Usage="ALWAYS_CONSUMED">
+ <GuidCName>gEfiGlobalVariableGuid</GuidCName>
+ </GuidCNames>
+ </Guids>
+ <Externs>
+ <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
+ <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
+ <Extern>
+ <ModuleEntryPoint>BdsInitialize</ModuleEntryPoint>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
diff --git a/MdeModulePkg/Universal/BdsDxe/BdsEntry.c b/MdeModulePkg/Universal/BdsDxe/BdsEntry.c new file mode 100644 index 0000000000..b40e0ee7fa --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/BdsEntry.c @@ -0,0 +1,375 @@ +/*++
+
+Copyright (c) 2004 - 2008, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ BdsEntry.c
+
+Abstract:
+
+ The entry of the bds
+
+--*/
+
+#include "Bds.h"
+#include "Language.h"
+#include "FrontPage.h"
+#include "Hotkey.h"
+#include "HwErrRecSupport.h"
+
+
+EFI_BDS_ARCH_PROTOCOL_INSTANCE gBdsInstanceTemplate = {
+ EFI_BDS_ARCH_PROTOCOL_INSTANCE_SIGNATURE,
+ NULL,
+ {BdsEntry},
+ 0xFFFF,
+ TRUE,
+ EXTENSIVE
+};
+
+UINT16 *mBootNext = NULL;
+
+EFI_HANDLE mBdsImageHandle;
+
+EFI_STATUS
+EFIAPI
+BdsInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+/*++
+
+Routine Description:
+
+ Install Boot Device Selection Protocol
+
+Arguments:
+
+ (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT)
+
+Returns:
+
+ EFI_SUCEESS - BDS has finished initializing.
+ Rerun the
+ dispatcher and recall BDS.Entry
+
+ Other - Return value from AllocatePool()
+ or gBS->InstallProtocolInterface
+
+--*/
+{
+ EFI_STATUS Status;
+
+ mBdsImageHandle = ImageHandle;
+
+ //
+ // Install protocol interface
+ //
+ Status = gBS->InstallProtocolInterface (
+ &gBdsInstanceTemplate.Handle,
+ &gEfiBdsArchProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &gBdsInstanceTemplate.Bds
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+VOID
+BdsBootDeviceSelect (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ In the loop of attempt to boot for the boot order
+
+Arguments:
+
+ None.
+
+Returns:
+
+ None.
+
+--*/
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ BDS_COMMON_OPTION *BootOption;
+ UINTN ExitDataSize;
+ CHAR16 *ExitData;
+ UINT16 Timeout;
+ LIST_ENTRY BootLists;
+ CHAR16 Buffer[20];
+ BOOLEAN BootNextExist;
+ LIST_ENTRY *LinkBootNext;
+
+ //
+ // Got the latest boot option
+ //
+ BootNextExist = FALSE;
+ LinkBootNext = NULL;
+ InitializeListHead (&BootLists);
+
+ //
+ // First check the boot next option
+ //
+ ZeroMem (Buffer, sizeof (Buffer));
+
+ if (mBootNext != NULL) {
+ //
+ // Indicate we have the boot next variable, so this time
+ // boot will always have this boot option
+ //
+ BootNextExist = TRUE;
+
+ //
+ // Clear the this variable so it's only exist in this time boot
+ //
+ gRT->SetVariable (
+ L"BootNext",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ 0,
+ mBootNext
+ );
+
+ //
+ // Add the boot next boot option
+ //
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *mBootNext);
+ BootOption = BdsLibVariableToOption (&BootLists, Buffer);
+ BootOption->BootCurrent = *mBootNext;
+ }
+ //
+ // Parse the boot order to get boot option
+ //
+ BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");
+ Link = BootLists.ForwardLink;
+
+ //
+ // Parameter check, make sure the loop will be valid
+ //
+ if (Link == NULL) {
+ return ;
+ }
+ //
+ // Here we make the boot in a loop, every boot success will
+ // return to the front page
+ //
+ for (;;) {
+ //
+ // Check the boot option list first
+ //
+ if (Link == &BootLists) {
+ //
+ // There are two ways to enter here:
+ // 1. There is no active boot option, give user chance to
+ // add new boot option
+ // 2. All the active boot option processed, and there is no
+ // one is success to boot, then we back here to allow user
+ // add new active boot option
+ //
+ Timeout = 0xffff;
+ PlatformBdsEnterFrontPage (Timeout, FALSE);
+ InitializeListHead (&BootLists);
+ BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");
+ Link = BootLists.ForwardLink;
+ continue;
+ }
+ //
+ // Get the boot option from the link list
+ //
+ BootOption = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);
+
+ //
+ // According to EFI Specification, 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 (BootOption->Attribute, LOAD_OPTION_ACTIVE)) {
+ //
+ // skip the header of the link list, becuase it has no boot option
+ //
+ Link = Link->ForwardLink;
+ continue;
+ }
+ //
+ // Make sure the boot option device path connected,
+ // but ignore the BBS device path
+ //
+ if (DevicePathType (BootOption->DevicePath) != BBS_DEVICE_PATH) {
+ //
+ // Notes: the internal shell can not been connected with device path
+ // so we do not check the status here
+ //
+ BdsLibConnectDevicePath (BootOption->DevicePath);
+ }
+ //
+ // All the driver options should have been processed since
+ // now boot will be performed.
+ //
+ Status = BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);
+ if (EFI_ERROR (Status)) {
+ //
+ // Call platform action to indicate the boot fail
+ //
+ BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_FAILED));
+ PlatformBdsBootFail (BootOption, Status, ExitData, ExitDataSize);
+
+ //
+ // Check the next boot option
+ //
+ Link = Link->ForwardLink;
+
+ } else {
+ //
+ // Call platform action to indicate the boot success
+ //
+ BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED));
+ PlatformBdsBootSuccess (BootOption);
+
+ //
+ // Boot success, then stop process the boot order, and
+ // present the boot manager menu, front page
+ //
+ Timeout = 0xffff;
+ PlatformBdsEnterFrontPage (Timeout, FALSE);
+
+ //
+ // Rescan the boot option list, avoid pertential risk of the boot
+ // option change in front page
+ //
+ if (BootNextExist) {
+ LinkBootNext = BootLists.ForwardLink;
+ }
+
+ InitializeListHead (&BootLists);
+ if (LinkBootNext != NULL) {
+ //
+ // Reserve the boot next option
+ //
+ InsertTailList (&BootLists, LinkBootNext);
+ }
+
+ BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");
+ Link = BootLists.ForwardLink;
+ }
+ }
+
+}
+
+VOID
+EFIAPI
+BdsEntry (
+ IN EFI_BDS_ARCH_PROTOCOL *This
+ )
+/*++
+
+Routine Description:
+
+ Service routine for BdsInstance->Entry(). Devices are connected, the
+ consoles are initialized, and the boot options are tried.
+
+Arguments:
+
+ This - Protocol Instance structure.
+
+Returns:
+
+ EFI_SUCEESS - BDS->Entry has finished executing.
+
+--*/
+{
+ EFI_BDS_ARCH_PROTOCOL_INSTANCE *PrivateData;
+ LIST_ENTRY DriverOptionList;
+ LIST_ENTRY BootOptionList;
+ UINTN BootNextSize;
+
+ //
+ // Insert the performance probe
+ //
+ PERF_END (0, DXE_TOK, NULL, 0);
+ PERF_START (0, BDS_TOK, NULL, 0);
+
+ //
+ // Initialize the global system boot option and driver option
+ //
+ InitializeListHead (&DriverOptionList);
+ InitializeListHead (&BootOptionList);
+
+ //
+ // Initialize hotkey service
+ //
+ InitializeHotkeyService ();
+
+ //
+ // Get the BDS private data
+ //
+ PrivateData = EFI_BDS_ARCH_PROTOCOL_INSTANCE_FROM_THIS (This);
+
+ //
+ // Do the platform init, can be customized by OEM/IBV
+ //
+ PERF_START (0, "PlatformBds", "BDS", 0);
+ PlatformBdsInit (PrivateData);
+
+ if (FeaturePcdGet (PcdSupportHardwareErrorRecord)) {
+ InitializeHwErrRecSupport (PcdGet16 (PcdHardwareErrorRecordLevel));
+ }
+ //
+ // bugbug: platform specific code
+ // Initialize the platform specific string and language
+ //
+ InitializeStringSupport ();
+ InitializeLanguage (TRUE);
+ InitializeFrontPage (FALSE);
+
+ //
+ // Set up the device list based on EFI 1.1 variables
+ // process Driver#### and Load the driver's in the
+ // driver option list
+ //
+ BdsLibBuildOptionFromVar (&DriverOptionList, L"DriverOrder");
+ if (!IsListEmpty (&DriverOptionList)) {
+ BdsLibLoadDrivers (&DriverOptionList);
+ }
+ //
+ // Check if we have the boot next option
+ //
+ mBootNext = BdsLibGetVariableAndSize (
+ L"BootNext",
+ &gEfiGlobalVariableGuid,
+ &BootNextSize
+ );
+
+ //
+ // Setup some platform policy here
+ //
+ PlatformBdsPolicyBehavior (PrivateData, &DriverOptionList, &BootOptionList);
+ PERF_END (0, "PlatformBds", "BDS", 0);
+
+ //
+ // BDS select the boot device to load OS
+ //
+ BdsBootDeviceSelect ();
+
+ //
+ // Only assert here since this is the right behavior, we should never
+ // return back to DxeCore.
+ //
+ ASSERT (FALSE);
+
+ return ;
+}
diff --git a/MdeModulePkg/Universal/BdsDxe/BootMaint/BBSsupport.c b/MdeModulePkg/Universal/BdsDxe/BootMaint/BBSsupport.c new file mode 100644 index 0000000000..2f0d5d9eb2 --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/BootMaint/BBSsupport.c @@ -0,0 +1,1664 @@ +/*++
+
+Copyright (c) 2004 - 2008, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ BBSsupport.c
+
+Abstract:
+
+ This function deal with the legacy boot option, it create, delete
+ and manage the legacy boot option, all legacy boot option is getting from
+ the legacy BBS table.
+
+--*/
+
+#include "BBSsupport.h"
+
+EFI_DEVICE_PATH_PROTOCOL EndDevicePath[] = {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ END_DEVICE_PATH_LENGTH,
+ 0
+};
+
+VOID
+AsciiToUnicodeSize (
+ IN UINT8 *a,
+ IN UINTN Size,
+ OUT UINT16 *u
+ )
+/*++
+
+ Routine Description:
+
+ 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.
+
+ Arguments:
+
+ a - Pointer to input Ascii string.
+ Size - The number of characters to translate.
+ u - Pointer to output Unicode string buffer.
+
+ Returns:
+
+ None
+
+--*/
+{
+ UINTN i;
+
+ i = 0;
+ while (a[i] != 0) {
+ u[i] = (CHAR16) a[i];
+ if (i == Size) {
+ break;
+ }
+
+ i++;
+ }
+ u[i] = 0;
+}
+
+UINTN
+UnicodeToAscii (
+ IN CHAR16 *UStr,
+ IN UINTN Length,
+ OUT CHAR8 *AStr
+ )
+/*++
+Routine Description:
+
+ change a Unicode string t ASCII string
+
+Arguments:
+
+ UStr - Unicode string
+ Lenght - most possible length of AStr
+ AStr - ASCII string to pass out
+
+Returns:
+
+ Actuall length
+
+--*/
+{
+ UINTN Index;
+
+ //
+ // just buffer copy, not character copy
+ //
+ for (Index = 0; Index < Length; Index++) {
+ *AStr++ = (CHAR8) *UStr++;
+ }
+
+ return Index;
+}
+
+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) {
+ Fmt = L"%s %d";
+ UnicodeSPrint (BootString, BufSize, Fmt, Type, Index - 5);
+ } else {
+ UnicodeSPrint (BootString, BufSize, Fmt, Type);
+ }
+}
+
+EFI_STATUS
+BdsCreateLegacyBootOption (
+ IN BBS_TABLE *CurrentBbsEntry,
+ IN EFI_DEVICE_PATH_PROTOCOL *CurrentBbsDevPath,
+ IN UINTN Index,
+ IN OUT UINT16 **BootOrderList,
+ IN OUT UINTN *BootOrderListSize
+ )
+/*++
+
+ Routine Description:
+
+ Create a legacy boot option for the specified entry of
+ BBS table, save it as variable, and append it to the boot
+ order list.
+
+ Arguments:
+
+ CurrentBbsEntry - Pointer to current BBS table.
+ CurrentBbsDevPath - Pointer to the Device Path Protocol instance of BBS
+ Index - Index of the specified entry in BBS table.
+ BootOrderList - On input, the original boot order list.
+ On output, the new boot order list attached with the
+ created node.
+ BootOrderListSize - On input, the original size of boot order list.
+ - On output, the size of new boot order list.
+
+ Returns:
+
+ EFI_SUCCESS - Boot Option successfully created.
+ EFI_OUT_OF_RESOURCES - Fail to allocate necessary memory.
+ Other - Error occurs while setting variable.
+
+--*/
+{
+ EFI_STATUS Status;
+ UINT16 CurrentBootOptionNo;
+ UINT16 BootString[10];
+ UINT16 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 (NULL == (*BootOrderList)) {
+ 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
+ //
+ UnicodeToAscii (BootDesc, StrSize (BootDesc), HelpString);
+ StringLen = AsciiStrLen (HelpString);
+ NewBbsDevPathNode = EfiAllocateZeroPool (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 (
+ EndDevicePath,
+ (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 = EfiAllocateZeroPool (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,
+ VAR_FLAG,
+ BufferSize,
+ Buffer
+ );
+
+ SafeFreePool (Buffer);
+ Buffer = NULL;
+
+ NewBootOrderList = EfiAllocateZeroPool (*BootOrderListSize + sizeof (UINT16));
+ if (NULL == NewBootOrderList) {
+ FreePool (NewBbsDevPathNode);
+ FreePool (CurrentBbsDevPath);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (NULL != *BootOrderList) {
+ CopyMem (NewBootOrderList, *BootOrderList, *BootOrderListSize);
+ }
+
+ SafeFreePool (*BootOrderList);
+
+ BootOrderLastIndex = (UINTN) (*BootOrderListSize / sizeof (UINT16));
+ NewBootOrderList[BootOrderLastIndex] = CurrentBootOptionNo;
+ *BootOrderListSize += sizeof (UINT16);
+ *BootOrderList = NewBootOrderList;
+
+ FreePool (NewBbsDevPathNode);
+ FreePool (CurrentBbsDevPath);
+ return Status;
+}
+
+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;
+}
+
+EFI_STATUS
+BdsDeleteBootOption (
+ IN UINTN OptionNumber,
+ IN OUT UINT16 *BootOrder,
+ IN OUT UINTN *BootOrderSize
+ )
+{
+ UINT16 BootOption[100];
+ UINTN Index;
+ EFI_STATUS Status;
+ UINTN Index2Del;
+
+ Status = EFI_SUCCESS;
+ Index2Del = 0;
+
+ UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", OptionNumber);
+ Status = EfiLibDeleteVariable (BootOption, &gEfiGlobalVariableGuid);
+ //
+ // adjust boot order array
+ //
+ for (Index = 0; Index < *BootOrderSize / sizeof (UINT16); Index++) {
+ if (BootOrder[Index] == OptionNumber) {
+ Index2Del = Index;
+ break;
+ }
+ }
+
+ if (Index != *BootOrderSize / sizeof (UINT16)) {
+ for (Index = 0; Index < *BootOrderSize / sizeof (UINT16) - 1; Index++) {
+ if (Index >= Index2Del) {
+ BootOrder[Index] = BootOrder[Index + 1];
+ }
+ }
+
+ *BootOrderSize -= sizeof (UINT16);
+ }
+
+ return Status;
+
+}
+
+EFI_STATUS
+BdsDeleteAllInvalidLegacyBootOptions (
+ VOID
+ )
+/*++
+
+ Routine Description:
+
+ Delete all the invalid legacy boot options.
+
+ Arguments:
+
+ None.
+
+ Returns:
+
+ EFI_SUCCESS - All invalide legacy boot options are deleted.
+ EFI_OUT_OF_RESOURCES - Fail to allocate necessary memory.
+ EFI_NOT_FOUND - Fail to retrive variable of boot order.
+ Other - Error occurs while setting variable or locating
+ protocol.
+
+--*/
+{
+ 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 = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ LegacyBios->GetBbsInfo (
+ LegacyBios,
+ &HddCount,
+ &LocalHddInfo,
+ &BbsCount,
+ &LocalBbsTable
+ );
+
+ 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) {
+ SafeFreePool (BootOrder);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, &BbsIndex)) {
+ SafeFreePool (BootOptionVar);
+ Index++;
+ continue;
+ }
+
+ //
+ // 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;
+ }
+
+ SafeFreePool (BootOptionVar);
+ //
+ // should delete
+ //
+ BdsDeleteBootOption (
+ BootOrder[Index],
+ BootOrder,
+ &BootOrderSize
+ );
+ }
+
+ if (BootOrderSize) {
+ Status = gRT->SetVariable (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ VAR_FLAG,
+ BootOrderSize,
+ BootOrder
+ );
+ } else {
+ EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid);
+ }
+
+ SafeFreePool (BootOrder);
+
+ return Status;
+}
+
+BOOLEAN
+BdsFindLegacyBootOptionByDevType (
+ IN UINT16 *BootOrder,
+ IN UINTN BootOptionNum,
+ IN UINT16 DevType,
+ OUT UINT32 *Attribute,
+ OUT UINT16 *BbsIndex,
+ OUT UINTN *OptionNumber
+ )
+{
+ UINTN Index;
+ UINTN BootOrderIndex;
+ UINT16 BootOption[100];
+ UINTN BootOptionSize;
+ UINT8 *BootOptionVar;
+ BBS_TABLE *BbsEntry;
+ BOOLEAN Found;
+
+ BbsEntry = NULL;
+ Found = FALSE;
+
+ if (NULL == BootOrder) {
+ return Found;
+ }
+
+ for (BootOrderIndex = 0; BootOrderIndex < BootOptionNum; BootOrderIndex++) {
+ Index = (UINTN) BootOrder[BootOrderIndex];
+ UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", Index);
+ BootOptionVar = BdsLibGetVariableAndSize (
+ BootOption,
+ &gEfiGlobalVariableGuid,
+ &BootOptionSize
+ );
+ if (NULL == BootOptionVar) {
+ continue;
+ }
+
+ if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, BbsIndex)) {
+ SafeFreePool (BootOptionVar);
+ continue;
+ }
+
+ if (BbsEntry->DeviceType != DevType) {
+ SafeFreePool (BootOptionVar);
+ continue;
+ }
+
+ *Attribute = *(UINT32 *) BootOptionVar;
+ *OptionNumber = Index;
+ Found = TRUE;
+ SafeFreePool (BootOptionVar);
+ break;
+ }
+
+ return Found;
+}
+
+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;
+
+ 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 (
+ EndDevicePath,
+ (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;
+}
+
+EFI_STATUS
+BdsAddNonExistingLegacyBootOptions (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Add the legacy boot options from BBS table if they do not exist.
+
+Arguments:
+
+ None.
+
+Returns:
+
+ EFI_SUCCESS - The boot options are added successfully or they are already in boot options.
+ others - An error occurred when creating legacy boot options.
+
+--*/
+{
+ UINT16 *BootOrder;
+ UINTN BootOrderSize;
+ EFI_STATUS Status;
+ UINT16 HddCount;
+ UINT16 BbsCount;
+ HDD_INFO *LocalHddInfo;
+ BBS_TABLE *LocalBbsTable;
+ UINT16 BbsIndex;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ UINTN Index;
+ UINT32 Attribute;
+ UINTN OptionNumber;
+ BOOLEAN Ret;
+
+ BootOrder = NULL;
+ HddCount = 0;
+ BbsCount = 0;
+ LocalHddInfo = NULL;
+ LocalBbsTable = NULL;
+
+ Status = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ LegacyBios->GetBbsInfo (
+ LegacyBios,
+ &HddCount,
+ &LocalHddInfo,
+ &BbsCount,
+ &LocalBbsTable
+ );
+
+ BootOrder = BdsLibGetVariableAndSize (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ &BootOrderSize
+ );
+ if (NULL == BootOrder) {
+ BootOrderSize = 0;
+ }
+
+ for (Index = 0; Index < BbsCount; Index++) {
+ if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||
+ (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)
+ ) {
+ continue;
+ }
+
+ Ret = BdsFindLegacyBootOptionByDevType (
+ BootOrder,
+ BootOrderSize / sizeof (UINT16),
+ LocalBbsTable[Index].DeviceType,
+ &Attribute,
+ &BbsIndex,
+ &OptionNumber
+ );
+ if (Ret) {
+ continue;
+ }
+
+ //
+ // 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)) {
+ break;
+ }
+ }
+
+ if (BootOrderSize > 0) {
+ Status = gRT->SetVariable (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ VAR_FLAG,
+ BootOrderSize,
+ BootOrder
+ );
+ } else {
+ EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid);
+ }
+
+ if (BootOrder != NULL) {
+ SafeFreePool (BootOrder);
+ }
+
+ return Status;
+}
+
+UINT16 *
+BdsFillDevOrderBuf (
+ IN BBS_TABLE *BbsTable,
+ IN BBS_TYPE BbsType,
+ IN UINTN BbsCount,
+ IN 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;
+}
+
+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;
+ UINT8 *DevOrder;
+ UINT8 *Ptr;
+ EFI_STATUS Status;
+
+ FDCount = 0;
+ HDCount = 0;
+ CDCount = 0;
+ NETCount = 0;
+ BEVCount = 0;
+ TotalSize = 0;
+ HeaderSize = sizeof (BBS_TYPE) + sizeof (UINT16);
+ DevOrder = NULL;
+ Ptr = NULL;
+ Status = EFI_SUCCESS;
+
+ 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);
+
+ DevOrder = EfiAllocateZeroPool (TotalSize);
+ if (NULL == DevOrder) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Ptr = DevOrder;
+
+ *((BBS_TYPE *) Ptr) = BBS_FLOPPY;
+ Ptr += sizeof (BBS_TYPE);
+ *((UINT16 *) Ptr) = (UINT16) (sizeof (UINT16) + FDCount * sizeof (UINT16));
+ Ptr += sizeof (UINT16);
+ if (FDCount) {
+ Ptr = (UINT8 *) BdsFillDevOrderBuf (BbsTable, BBS_FLOPPY, BbsCount, (UINT16 *) Ptr);
+ }
+
+ *((BBS_TYPE *) Ptr) = BBS_HARDDISK;
+ Ptr += sizeof (BBS_TYPE);
+ *((UINT16 *) Ptr) = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));
+ Ptr += sizeof (UINT16);
+ if (HDCount) {
+ Ptr = (UINT8 *) BdsFillDevOrderBuf (BbsTable, BBS_HARDDISK, BbsCount, (UINT16 *) Ptr);
+ }
+
+ *((BBS_TYPE *) Ptr) = BBS_CDROM;
+ Ptr += sizeof (BBS_TYPE);
+ *((UINT16 *) Ptr) = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));
+ Ptr += sizeof (UINT16);
+ if (CDCount) {
+ Ptr = (UINT8 *) BdsFillDevOrderBuf (BbsTable, BBS_CDROM, BbsCount, (UINT16 *) Ptr);
+ }
+
+ *((BBS_TYPE *) Ptr) = BBS_EMBED_NETWORK;
+ Ptr += sizeof (BBS_TYPE);
+ *((UINT16 *) Ptr) = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));
+ Ptr += sizeof (UINT16);
+ if (NETCount) {
+ Ptr = (UINT8 *) BdsFillDevOrderBuf (BbsTable, BBS_EMBED_NETWORK, BbsCount, (UINT16 *) Ptr);
+ }
+
+ *((BBS_TYPE *) Ptr) = BBS_BEV_DEVICE;
+ Ptr += sizeof (BBS_TYPE);
+ *((UINT16 *) Ptr) = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));
+ Ptr += sizeof (UINT16);
+ if (BEVCount) {
+ Ptr = (UINT8 *) BdsFillDevOrderBuf (BbsTable, BBS_BEV_DEVICE, BbsCount, (UINT16 *) Ptr);
+ }
+
+ Status = gRT->SetVariable (
+ VarLegacyDevOrder,
+ &EfiLegacyDevOrderGuid,
+ VAR_FLAG,
+ TotalSize,
+ DevOrder
+ );
+ SafeFreePool (DevOrder);
+
+ return Status;
+}
+
+EFI_STATUS
+BdsUpdateLegacyDevOrder (
+ VOID
+ )
+/*++
+Format of LegacyDevOrder variable:
+|-----------------------------------------------------------------------------------------------------------------
+| BBS_FLOPPY | Length | Index0 | Index1 | ... | BBS_HARDDISK | Length | Index0 | Index1 | ... | BBS_CDROM | Length | Index0 | ...
+|-----------------------------------------------------------------------------------------------------------------
+
+Length is a 16 bit integer, it indicates how many Indexes follows, including the size of itself.
+Index# is a 16 bit integer, the low byte of it stands for the index in BBS table
+ the high byte of it only have two value 0 and 0xFF, 0xFF means this device has been
+ disabled by user.
+--*/
+{
+ UINT8 *DevOrder;
+ UINT8 *NewDevOrder;
+ 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;
+ UINT8 *Ptr;
+ UINT8 *NewPtr;
+ UINT16 *NewFDPtr;
+ UINT16 *NewHDPtr;
+ UINT16 *NewCDPtr;
+ UINT16 *NewNETPtr;
+ UINT16 *NewBEVPtr;
+ UINT16 *NewDevPtr;
+ UINT16 Length;
+ UINT16 tmp;
+ UINTN FDIndex;
+ UINTN HDIndex;
+ UINTN CDIndex;
+ UINTN NETIndex;
+ UINTN BEVIndex;
+
+ LocalHddInfo = NULL;
+ LocalBbsTable = NULL;
+ 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 = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ LegacyBios->GetBbsInfo (
+ LegacyBios,
+ &HddCount,
+ &LocalHddInfo,
+ &BbsCount,
+ &LocalBbsTable
+ );
+
+ DevOrder = (UINT8 *) BdsLibGetVariableAndSize (
+ VarLegacyDevOrder,
+ &EfiLegacyDevOrderGuid,
+ &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 = EfiAllocateZeroPool (TotalSize);
+ if (NULL == NewDevOrder) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewFDPtr = (UINT16 *) (NewDevOrder + HeaderSize);
+ NewHDPtr = (UINT16 *) ((UINT8 *) NewFDPtr + FDCount * sizeof (UINT16) + HeaderSize);
+ NewCDPtr = (UINT16 *) ((UINT8 *) NewHDPtr + HDCount * sizeof (UINT16) + HeaderSize);
+ NewNETPtr = (UINT16 *) ((UINT8 *) NewCDPtr + CDCount * sizeof (UINT16) + HeaderSize);
+ NewBEVPtr = (UINT16 *) ((UINT8 *) NewNETPtr + NETCount * sizeof (UINT16) + HeaderSize);
+
+ //
+ // copy FD
+ //
+ Ptr = DevOrder;
+ NewPtr = NewDevOrder;
+ *((BBS_TYPE *) NewPtr) = *((BBS_TYPE *) Ptr);
+ Ptr += sizeof (BBS_TYPE);
+ NewPtr += sizeof (BBS_TYPE);
+ Length = *((UINT16 *) Ptr);
+ *((UINT16 *) NewPtr) = (UINT16) (sizeof (UINT16) + FDCount * sizeof (UINT16));
+ Ptr += sizeof (UINT16);
+
+ for (Index = 0; Index < Length / sizeof (UINT16) - 1; Index++) {
+ if (LocalBbsTable[*Ptr].BootPriority == BBS_IGNORE_ENTRY ||
+ LocalBbsTable[*Ptr].BootPriority == BBS_DO_NOT_BOOT_FROM ||
+ LocalBbsTable[*Ptr].DeviceType != BBS_FLOPPY
+ ) {
+ Ptr += sizeof (UINT16);
+ continue;
+ }
+
+ NewFDPtr[FDIndex] = *(UINT16 *) Ptr;
+ FDIndex++;
+ Ptr += sizeof (UINT16);
+ }
+ //
+ // copy HD
+ //
+ NewPtr = (UINT8 *) NewHDPtr - HeaderSize;
+ *((BBS_TYPE *) NewPtr) = *((BBS_TYPE *) Ptr);
+ Ptr += sizeof (BBS_TYPE);
+ NewPtr += sizeof (BBS_TYPE);
+ Length = *((UINT16 *) Ptr);
+ *((UINT16 *) NewPtr) = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));
+ Ptr += sizeof (UINT16);
+
+ for (Index = 0; Index < Length / sizeof (UINT16) - 1; Index++) {
+ if (LocalBbsTable[*Ptr].BootPriority == BBS_IGNORE_ENTRY ||
+ LocalBbsTable[*Ptr].BootPriority == BBS_DO_NOT_BOOT_FROM ||
+ LocalBbsTable[*Ptr].BootPriority == BBS_LOWEST_PRIORITY ||
+ LocalBbsTable[*Ptr].DeviceType != BBS_HARDDISK
+ ) {
+ Ptr += sizeof (UINT16);
+ continue;
+ }
+
+ NewHDPtr[HDIndex] = *(UINT16 *) Ptr;
+ HDIndex++;
+ Ptr += sizeof (UINT16);
+ }
+ //
+ // copy CD
+ //
+ NewPtr = (UINT8 *) NewCDPtr - HeaderSize;
+ *((BBS_TYPE *) NewPtr) = *((BBS_TYPE *) Ptr);
+ Ptr += sizeof (BBS_TYPE);
+ NewPtr += sizeof (BBS_TYPE);
+ Length = *((UINT16 *) Ptr);
+ *((UINT16 *) NewPtr) = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));
+ Ptr += sizeof (UINT16);
+
+ for (Index = 0; Index < Length / sizeof (UINT16) - 1; Index++) {
+ if (LocalBbsTable[*Ptr].BootPriority == BBS_IGNORE_ENTRY ||
+ LocalBbsTable[*Ptr].BootPriority == BBS_DO_NOT_BOOT_FROM ||
+ LocalBbsTable[*Ptr].BootPriority == BBS_LOWEST_PRIORITY ||
+ LocalBbsTable[*Ptr].DeviceType != BBS_CDROM
+ ) {
+ Ptr += sizeof (UINT16);
+ continue;
+ }
+
+ NewCDPtr[CDIndex] = *(UINT16 *) Ptr;
+ CDIndex++;
+ Ptr += sizeof (UINT16);
+ }
+ //
+ // copy NET
+ //
+ NewPtr = (UINT8 *) NewNETPtr - HeaderSize;
+ *((BBS_TYPE *) NewPtr) = *((BBS_TYPE *) Ptr);
+ Ptr += sizeof (BBS_TYPE);
+ NewPtr += sizeof (BBS_TYPE);
+ Length = *((UINT16 *) Ptr);
+ *((UINT16 *) NewPtr) = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));
+ Ptr += sizeof (UINT16);
+
+ for (Index = 0; Index < Length / sizeof (UINT16) - 1; Index++) {
+ if (LocalBbsTable[*Ptr].BootPriority == BBS_IGNORE_ENTRY ||
+ LocalBbsTable[*Ptr].BootPriority == BBS_DO_NOT_BOOT_FROM ||
+ LocalBbsTable[*Ptr].BootPriority == BBS_LOWEST_PRIORITY ||
+ LocalBbsTable[*Ptr].DeviceType != BBS_EMBED_NETWORK
+ ) {
+ Ptr += sizeof (UINT16);
+ continue;
+ }
+
+ NewNETPtr[NETIndex] = *(UINT16 *) Ptr;
+ NETIndex++;
+ Ptr += sizeof (UINT16);
+ }
+ //
+ // copy BEV
+ //
+ NewPtr = (UINT8 *) NewBEVPtr - HeaderSize;
+ *((BBS_TYPE *) NewPtr) = *((BBS_TYPE *) Ptr);
+ Ptr += sizeof (BBS_TYPE);
+ NewPtr += sizeof (BBS_TYPE);
+ Length = *((UINT16 *) Ptr);
+ *((UINT16 *) NewPtr) = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));
+ Ptr += sizeof (UINT16);
+
+ for (Index = 0; Index < Length / sizeof (UINT16) - 1; Index++) {
+ if (LocalBbsTable[*Ptr].BootPriority == BBS_IGNORE_ENTRY ||
+ LocalBbsTable[*Ptr].BootPriority == BBS_DO_NOT_BOOT_FROM ||
+ LocalBbsTable[*Ptr].BootPriority == BBS_LOWEST_PRIORITY ||
+ LocalBbsTable[*Ptr].DeviceType != BBS_BEV_DEVICE
+ ) {
+ Ptr += sizeof (UINT16);
+ continue;
+ }
+
+ NewBEVPtr[BEVIndex] = *(UINT16 *) Ptr;
+ BEVIndex++;
+ Ptr += sizeof (UINT16);
+ }
+
+ 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) {
+ 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
+ // save it.
+ //
+ NewDevPtr[*Idx] = (UINT16) (Index & 0xFF);
+ (*Idx)++;
+ }
+ }
+ }
+
+ if (FDCount) {
+ //
+ // Just to make sure that disabled indexes are all at the end of the array
+ //
+ for (Index = 0; Index < FDIndex - 1; Index++) {
+ if (0xFF00 != (NewFDPtr[Index] & 0xFF00)) {
+ continue;
+ }
+
+ for (Index2 = Index + 1; Index2 < FDIndex; Index2++) {
+ if (0 == (NewFDPtr[Index2] & 0xFF00)) {
+ tmp = NewFDPtr[Index];
+ NewFDPtr[Index] = NewFDPtr[Index2];
+ NewFDPtr[Index2] = tmp;
+ break;
+ }
+ }
+ }
+ }
+
+ if (HDCount) {
+ //
+ // Just to make sure that disabled indexes are all at the end of the array
+ //
+ for (Index = 0; Index < HDIndex - 1; Index++) {
+ if (0xFF00 != (NewHDPtr[Index] & 0xFF00)) {
+ continue;
+ }
+
+ for (Index2 = Index + 1; Index2 < HDIndex; Index2++) {
+ if (0 == (NewHDPtr[Index2] & 0xFF00)) {
+ tmp = NewHDPtr[Index];
+ NewHDPtr[Index] = NewHDPtr[Index2];
+ NewHDPtr[Index2] = tmp;
+ break;
+ }
+ }
+ }
+ }
+
+ if (CDCount) {
+ //
+ // Just to make sure that disabled indexes are all at the end of the array
+ //
+ for (Index = 0; Index < CDIndex - 1; Index++) {
+ if (0xFF00 != (NewCDPtr[Index] & 0xFF00)) {
+ continue;
+ }
+
+ for (Index2 = Index + 1; Index2 < CDIndex; Index2++) {
+ if (0 == (NewCDPtr[Index2] & 0xFF00)) {
+ tmp = NewCDPtr[Index];
+ NewCDPtr[Index] = NewCDPtr[Index2];
+ NewCDPtr[Index2] = tmp;
+ break;
+ }
+ }
+ }
+ }
+
+ if (NETCount) {
+ //
+ // Just to make sure that disabled indexes are all at the end of the array
+ //
+ for (Index = 0; Index < NETIndex - 1; Index++) {
+ if (0xFF00 != (NewNETPtr[Index] & 0xFF00)) {
+ continue;
+ }
+
+ for (Index2 = Index + 1; Index2 < NETIndex; Index2++) {
+ if (0 == (NewNETPtr[Index2] & 0xFF00)) {
+ tmp = NewNETPtr[Index];
+ NewNETPtr[Index] = NewNETPtr[Index2];
+ NewNETPtr[Index2] = tmp;
+ break;
+ }
+ }
+ }
+ }
+
+ if (BEVCount) {
+ //
+ // Just to make sure that disabled indexes are all at the end of the array
+ //
+ for (Index = 0; Index < BEVIndex - 1; Index++) {
+ if (0xFF00 != (NewBEVPtr[Index] & 0xFF00)) {
+ continue;
+ }
+
+ for (Index2 = Index + 1; Index2 < BEVIndex; Index2++) {
+ if (0 == (NewBEVPtr[Index2] & 0xFF00)) {
+ tmp = NewBEVPtr[Index];
+ NewBEVPtr[Index] = NewBEVPtr[Index2];
+ NewBEVPtr[Index2] = tmp;
+ break;
+ }
+ }
+ }
+ }
+
+ SafeFreePool (DevOrder);
+
+ Status = gRT->SetVariable (
+ VarLegacyDevOrder,
+ &EfiLegacyDevOrderGuid,
+ VAR_FLAG,
+ TotalSize,
+ NewDevOrder
+ );
+ SafeFreePool (NewDevOrder);
+
+ return Status;
+}
+
+EFI_STATUS
+BdsSetBootPriority4SameTypeDev (
+ IN UINT16 DeviceType,
+ IN OUT BBS_TABLE *LocalBbsTable,
+ IN OUT UINT16 *Priority
+ )
+/*++
+DeviceType - BBS_FLOPPY, BBS_HARDDISK, BBS_CDROM and so on
+LocalBbsTable - BBS table instance
+Priority - As input arg, it is the start point of boot priority, as output arg, it is the start point of boot
+ priority can be used next time.
+--*/
+{
+ UINT8 *DevOrder;
+
+ UINT8 *OrigBuffer;
+ UINT16 *DevIndex;
+ UINTN DevOrderSize;
+ UINTN DevCount;
+ UINTN Index;
+
+ DevOrder = BdsLibGetVariableAndSize (
+ VarLegacyDevOrder,
+ &EfiLegacyDevOrderGuid,
+ &DevOrderSize
+ );
+ if (NULL == DevOrder) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ OrigBuffer = DevOrder;
+ while (DevOrder < OrigBuffer + DevOrderSize) {
+ if (DeviceType == * (BBS_TYPE *) DevOrder) {
+ break;
+ }
+
+ DevOrder += sizeof (BBS_TYPE);
+ DevOrder += *(UINT16 *) DevOrder;
+ }
+
+ if (DevOrder >= OrigBuffer + DevOrderSize) {
+ SafeFreePool (OrigBuffer);
+ return EFI_NOT_FOUND;
+ }
+
+ DevOrder += sizeof (BBS_TYPE);
+ DevCount = (*((UINT16 *) DevOrder) - sizeof (UINT16)) / sizeof (UINT16);
+ DevIndex = (UINT16 *) (DevOrder + sizeof (UINT16));
+ //
+ // If the high byte of the DevIndex is 0xFF, it indicates that this device has been disabled.
+ //
+ for (Index = 0; Index < DevCount; Index++) {
+ if ((DevIndex[Index] & 0xFF00) == 0xFF00) {
+ //
+ // LocalBbsTable[DevIndex[Index] & 0xFF].BootPriority = BBS_DISABLED_ENTRY;
+ //
+ } else {
+ LocalBbsTable[DevIndex[Index] & 0xFF].BootPriority = *Priority;
+ (*Priority)++;
+ }
+ }
+
+ SafeFreePool (OrigBuffer);
+ return EFI_SUCCESS;
+}
+
+VOID
+PrintBbsTable (
+ IN BBS_TABLE *LocalBbsTable
+ )
+{
+ 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 < MAX_BBS_ENTRIES; 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/02%x %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"));
+}
+
+EFI_STATUS
+BdsRefreshBbsTableForBoot (
+ IN BDS_COMMON_OPTION *Entry
+ )
+{
+ EFI_STATUS Status;
+ 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;
+ UINT16 BootOption[100];
+ UINT8 *Ptr;
+ UINT16 DevPathLen;
+ EFI_DEVICE_PATH_PROTOCOL *DevPath;
+
+ HddCount = 0;
+ BbsCount = 0;
+ LocalHddInfo = NULL;
+ LocalBbsTable = NULL;
+ DevType = BBS_UNKNOWN;
+
+ Status = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (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;
+ Status = BdsSetBootPriority4SameTypeDev (
+ DevType,
+ LocalBbsTable,
+ &Priority
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ //
+ // we have to set the boot priority for other BBS entries with different device types
+ //
+ BootOrder = (UINT16 *) BdsLibGetVariableAndSize (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ &BootOrderSize
+ );
+ for (Index = 0; BootOrder && 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) {
+ SafeFreePool (BootOptionVar);
+ continue;
+ }
+
+ Ptr += DevPathLen;
+ if (DevType == ((BBS_TABLE *) Ptr)->DeviceType) {
+ //
+ // We don't want to process twice for a device type
+ //
+ SafeFreePool (BootOptionVar);
+ continue;
+ }
+
+ Status = BdsSetBootPriority4SameTypeDev (
+ ((BBS_TABLE *) Ptr)->DeviceType,
+ LocalBbsTable,
+ &Priority
+ );
+ SafeFreePool (BootOptionVar);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ if (BootOrder) {
+ SafeFreePool (BootOrder);
+ }
+ //
+ // For debug
+ //
+ PrintBbsTable (LocalBbsTable);
+
+ return Status;
+}
diff --git a/MdeModulePkg/Universal/BdsDxe/BootMaint/BBSsupport.h b/MdeModulePkg/Universal/BdsDxe/BootMaint/BBSsupport.h new file mode 100644 index 0000000000..532223fa80 --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/BootMaint/BBSsupport.h @@ -0,0 +1,78 @@ +/*++
+
+Copyright (c) 2004 - 2008, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ BBSsupport.h
+
+Abstract:
+
+ declares interface functions
+
+Revision History
+
+--*/
+
+#ifndef _EFI_BDS_BBS_SUPPORT_H
+#define _EFI_BDS_BBS_SUPPORT_H
+
+#include "BootMaint.h"
+//
+// Bugbug: Candidate for a PCD entries
+//
+#define MAX_BBS_ENTRIES 0x100
+
+VOID
+BdsBuildLegacyDevNameString (
+ IN BBS_TABLE *CurBBSEntry,
+ IN UINTN Index,
+ IN UINTN BufSize,
+ OUT CHAR16 *BootString
+ );
+
+EFI_STATUS
+BdsDeleteAllInvalidLegacyBootOptions (
+ VOID
+ );
+
+EFI_STATUS
+BdsAddNonExistingLegacyBootOptions (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Add the legacy boot options from BBS table if they do not exist.
+
+Arguments:
+
+ None.
+
+Returns:
+
+ EFI_SUCCESS - The boot options are added successfully or they are already in boot options.
+ others - An error occurred when creating legacy boot options.
+
+--*/
+;
+
+EFI_STATUS
+BdsUpdateLegacyDevOrder (
+ VOID
+ );
+
+EFI_STATUS
+BdsRefreshBbsTableForBoot (
+ IN BDS_COMMON_OPTION *Entry
+ );
+
+#endif
diff --git a/MdeModulePkg/Universal/BdsDxe/BootMaint/Bm.vfr b/MdeModulePkg/Universal/BdsDxe/BootMaint/Bm.vfr new file mode 100644 index 0000000000..93cbbeaf8f --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/BootMaint/Bm.vfr @@ -0,0 +1,391 @@ +// *++
+//
+// Copyright (c) 2004 - 2007, Intel Corporation
+// All rights reserved. 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.
+//
+// Module Name:
+//
+// bm.vfr
+//
+// Abstract:
+//
+// Boot Maintenance Utility Formset
+//
+// Revision History:
+//
+// --*/
+
+#include "FormGuid.h"
+
+#define LABEL_END 0xffff
+
+formset
+ guid = BOOT_MAINT_FORMSET_GUID,
+ title = STRING_TOKEN(STR_FORM_MAIN_TITLE),
+ help = STRING_TOKEN(STR_NULL_STRING),
+ class = 0,
+ subclass = 0,
+
+ varstore BMM_FAKE_NV_DATA,
+ varid = VARSTORE_ID_BOOT_MAINT,
+ name = BmmData,
+ guid = BOOT_MAINT_FORMSET_GUID;
+
+ form formid = FORM_MAIN_ID,
+ title = STRING_TOKEN(STR_FORM_MAIN_TITLE);
+
+ goto FORM_BOOT_SETUP_ID,
+ prompt = STRING_TOKEN(STR_FORM_BOOT_SETUP_TITLE),
+ help = STRING_TOKEN(STR_FORM_BOOT_SETUP_HELP),
+ flags = INTERACTIVE,
+ key = FORM_BOOT_SETUP_ID;
+
+ subtitle text = STRING_TOKEN(STR_NULL_STRING);
+
+ goto FORM_DRIVER_SETUP_ID,
+ prompt = STRING_TOKEN(STR_FORM_DRIVER_SETUP_TITLE),
+ help = STRING_TOKEN(STR_FORM_DRIVER_SETUP_HELP),
+ flags = INTERACTIVE,
+ key = FORM_DRIVER_SETUP_ID;
+
+ subtitle text = STRING_TOKEN(STR_NULL_STRING);
+
+ goto FORM_CON_MAIN_ID,
+ prompt = STRING_TOKEN(STR_FORM_CON_MAIN_TITLE),
+ help = STRING_TOKEN(STR_FORM_CON_MAIN_HELP),
+ flags = INTERACTIVE,
+ key = FORM_CON_MAIN_ID;
+
+ subtitle text = STRING_TOKEN(STR_NULL_STRING);
+
+ text
+ help = STRING_TOKEN(STR_BOOT_FROM_FILE_HELP),
+ text = STRING_TOKEN(STR_BOOT_FROM_FILE),
+ text = STRING_TOKEN(STR_NULL_STRING),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_BOOT_FROM_FILE;
+
+ subtitle text = STRING_TOKEN(STR_NULL_STRING);
+
+// label FORM_MAIN_ID;
+
+ goto FORM_BOOT_NEXT_ID,
+ prompt = STRING_TOKEN(STR_FORM_BOOT_NEXT_TITLE),
+ help = STRING_TOKEN(STR_FORM_BOOT_NEXT_HELP),
+ flags = INTERACTIVE,
+ key = FORM_BOOT_NEXT_ID;
+
+ goto FORM_TIME_OUT_ID,
+ prompt = STRING_TOKEN(STR_FORM_TIME_OUT_TITLE),
+ help = STRING_TOKEN(STR_FORM_TIME_OUT_HELP),
+ flags = INTERACTIVE,
+ key = FORM_TIME_OUT_ID;
+
+ subtitle text = STRING_TOKEN(STR_NULL_STRING);
+
+ goto FORM_MAIN_ID,
+ prompt = STRING_TOKEN(STR_RESET),
+ help = STRING_TOKEN(STR_RESET),
+ flags = INTERACTIVE,
+ key = FORM_RESET;
+
+ endform;
+
+ form formid = FORM_BOOT_SETUP_ID,
+ title = STRING_TOKEN(STR_FORM_BOOT_SETUP_TITLE);
+
+ goto FORM_MAIN_ID,
+ prompt = STRING_TOKEN(STR_FORM_GOTO_MAIN),
+ help = STRING_TOKEN(STR_FORM_GOTO_MAIN);
+ //flags = INTERACTIVE,
+ //key = FORM_MAIN_ID;
+
+ goto FORM_BOOT_ADD_ID,
+ prompt = STRING_TOKEN(STR_FORM_BOOT_ADD_TITLE),
+ help = STRING_TOKEN(STR_FORM_BOOT_ADD_HELP),
+ flags = INTERACTIVE,
+ key = FORM_BOOT_ADD_ID;
+
+ goto FORM_BOOT_DEL_ID,
+ prompt = STRING_TOKEN(STR_FORM_BOOT_DEL_TITLE),
+ help = STRING_TOKEN(STR_FORM_NEXT_BOOT_HELP),
+ flags = INTERACTIVE,
+ key = FORM_BOOT_DEL_ID;
+
+ goto FORM_BOOT_CHG_ID,
+ prompt = STRING_TOKEN(STR_FORM_BOOT_CHG_TITLE),
+ help = STRING_TOKEN(STR_FORM_NEXT_BOOT_HELP),
+ flags = INTERACTIVE,
+ key = FORM_BOOT_CHG_ID;
+
+ subtitle text = STRING_TOKEN(STR_NULL_STRING);
+ //
+ // We will add "Select Legacy Boot Floppy Drive" and "Select Legacy Boot Hard Drive"
+ // here dynamically
+ //
+ label FORM_BOOT_LEGACY_DEVICE_ID;
+ label LABEL_END;
+
+ endform;
+
+ form formid = FORM_DRIVER_SETUP_ID,
+ title = STRING_TOKEN(STR_FORM_DRIVER_SETUP_TITLE);
+
+ goto FORM_MAIN_ID,
+ prompt = STRING_TOKEN(STR_FORM_GOTO_MAIN),
+ help = STRING_TOKEN(STR_FORM_GOTO_MAIN);
+ //help = STRING_TOKEN(STR_FORM_GOTO_MAIN),
+ //flags = INTERACTIVE,
+ //key = FORM_MAIN_ID;
+
+ goto FORM_DRV_ADD_ID,
+ prompt = STRING_TOKEN(STR_FORM_DRV_ADD_TITLE),
+ help = STRING_TOKEN(STR_FORM_DRV_ADD_HELP),
+ flags = INTERACTIVE,
+ key = FORM_DRV_ADD_ID;
+
+ goto FORM_DRV_DEL_ID,
+ prompt = STRING_TOKEN(STR_FORM_DRV_DEL_TITLE),
+ help = STRING_TOKEN(STR_FORM_NEXT_BOOT_HELP),
+ flags = INTERACTIVE,
+ key = FORM_DRV_DEL_ID;
+
+ goto FORM_DRV_CHG_ID,
+ prompt = STRING_TOKEN(STR_FORM_DRV_CHG_TITLE),
+ help = STRING_TOKEN(STR_FORM_NEXT_BOOT_HELP),
+ flags = INTERACTIVE,
+ key = FORM_DRV_CHG_ID;
+ endform;
+
+ form formid = FORM_BOOT_ADD_ID,
+ title = STRING_TOKEN(STR_FORM_BOOT_ADD_TITLE);
+
+ label FORM_BOOT_ADD_ID;
+ label LABEL_END;
+ endform;
+
+ form formid = FORM_BOOT_DEL_ID,
+ title = STRING_TOKEN(STR_FORM_BOOT_DEL_TITLE);
+
+ label FORM_BOOT_DEL_ID;
+ label LABEL_END;
+ endform;
+
+ form formid = FORM_BOOT_CHG_ID,
+ title = STRING_TOKEN(STR_FORM_BOOT_CHG_TITLE);
+
+ label FORM_BOOT_CHG_ID;
+ label LABEL_END;
+
+ endform;
+
+ form formid = FORM_BOOT_NEXT_ID,
+ title = STRING_TOKEN(STR_FORM_BOOT_NEXT_TITLE);
+
+ label FORM_BOOT_NEXT_ID;
+ label LABEL_END;
+ endform;
+
+ form formid = FORM_TIME_OUT_ID,
+ title = STRING_TOKEN(STR_FORM_TIME_OUT_TITLE);
+
+ label FORM_TIME_OUT_ID;
+ label LABEL_END;
+ endform;
+
+ form formid = FORM_DRV_ADD_ID,
+ title = STRING_TOKEN(STR_FORM_DRV_ADD_TITLE);
+
+ goto FORM_MAIN_ID,
+ prompt = STRING_TOKEN(STR_FORM_GOTO_MAIN),
+ help = STRING_TOKEN(STR_FORM_GOTO_MAIN);
+ //flags = INTERACTIVE,
+ //key = FORM_MAIN_ID;
+
+ goto FORM_DRV_ADD_FILE_ID,
+ prompt = STRING_TOKEN(STR_FORM_DRV_ADD_FILE_TITLE),
+ help = STRING_TOKEN(STR_FORM_DRV_ADD_FILE_TITLE),
+ flags = INTERACTIVE,
+ key = FORM_DRV_ADD_FILE_ID;
+
+ endform;
+
+ form formid = FORM_DRV_DEL_ID,
+ title = STRING_TOKEN(STR_FORM_DRV_DEL_TITLE);
+
+ label FORM_DRV_DEL_ID;
+ label LABEL_END;
+
+ endform;
+
+ form formid = FORM_DRV_CHG_ID,
+ title = STRING_TOKEN(STR_FORM_DRV_CHG_TITLE);
+
+ label FORM_DRV_CHG_ID;
+ label LABEL_END;
+
+ endform;
+
+ form formid = FORM_CON_MAIN_ID,
+ title = STRING_TOKEN(STR_FORM_CON_MAIN_TITLE);
+
+ goto FORM_MAIN_ID,
+ prompt = STRING_TOKEN(STR_FORM_GOTO_MAIN),
+ help = STRING_TOKEN(STR_FORM_GOTO_MAIN);
+ //flags = INTERACTIVE,
+ //key = FORM_MAIN_ID;
+
+ goto FORM_CON_IN_ID,
+ prompt = STRING_TOKEN(STR_FORM_CON_IN_TITLE),
+ help = STRING_TOKEN(STR_FORM_CON_IN_HELP),
+ flags = INTERACTIVE,
+ key = FORM_CON_IN_ID;
+
+ goto FORM_CON_OUT_ID,
+ prompt = STRING_TOKEN(STR_FORM_CON_OUT_TITLE),
+ help = STRING_TOKEN(STR_FORM_CON_OUT_HELP),
+ flags = INTERACTIVE,
+ key = FORM_CON_OUT_ID;
+
+ goto FORM_CON_ERR_ID,
+ prompt = STRING_TOKEN(STR_FORM_STD_ERR_TITLE),
+ help = STRING_TOKEN(STR_FORM_STD_ERR_HELP),
+ flags = INTERACTIVE,
+ key = FORM_CON_ERR_ID;
+
+ goto FORM_CON_MODE_ID,
+ prompt = STRING_TOKEN(STR_FORM_MODE_TITLE),
+ help = STRING_TOKEN(STR_FORM_MODE_HELP),
+ flags = INTERACTIVE,
+ key = FORM_CON_MODE_ID;
+
+ goto FORM_CON_COM_ID,
+ prompt = STRING_TOKEN(STR_FORM_COM_TITLE),
+ help = STRING_TOKEN(STR_FORM_COM_HELP),
+ flags = INTERACTIVE,
+ key = FORM_CON_COM_ID;
+ endform;
+
+ form formid = FORM_CON_MODE_ID,
+ title = STRING_TOKEN(STR_FORM_MODE_TITLE);
+
+ label FORM_CON_MODE_ID;
+ label LABEL_END;
+ endform;
+
+ form formid = FORM_CON_COM_ID,
+ title = STRING_TOKEN(STR_FORM_COM_TITLE);
+
+ label FORM_CON_COM_ID;
+ label LABEL_END;
+ endform;
+
+ form formid = FORM_CON_COM_SETUP_ID,
+ title = STRING_TOKEN(STR_CON_COM_SETUP);
+
+ label FORM_CON_COM_SETUP_ID;
+ label LABEL_END;
+ endform;
+
+ form formid = FORM_FILE_SEEK_ID,
+ title = STRING_TOKEN(STR_FORM_BOOT_ADD_TITLE);
+
+ label FORM_FILE_SEEK_ID;
+ label LABEL_END;
+ endform;
+
+ form formid = FORM_FILE_NEW_SEEK_ID,
+ title = STRING_TOKEN(STR_FORM_BOOT_ADD_TITLE);
+
+ label FORM_FILE_NEW_SEEK_ID;
+ label LABEL_END;
+ endform;
+
+ form formid = FORM_DRV_ADD_FILE_ID,
+ title = STRING_TOKEN(STR_FORM_DRV_ADD_FILE_TITLE);
+
+ label FORM_DRV_ADD_FILE_ID;
+ label LABEL_END;
+ endform;
+
+ form formid = FORM_DRV_ADD_HANDLE_ID,
+ title = STRING_TOKEN(STR_FORM_DRV_ADD_HANDLE_TITLE);
+
+ label FORM_DRV_ADD_HANDLE_ID;
+ label LABEL_END;
+ endform;
+
+ form formid = FORM_DRV_ADD_HANDLE_DESC_ID,
+ title = STRING_TOKEN(STR_FORM_DRV_ADD_DESC_TITLE);
+
+ label FORM_DRV_ADD_HANDLE_DESC_ID;
+ label LABEL_END;
+
+ endform;
+
+ form formid = FORM_CON_IN_ID,
+ title = STRING_TOKEN(STR_FORM_CON_IN_TITLE);
+
+ label FORM_CON_IN_ID;
+ label LABEL_END;
+
+ endform;
+
+ form formid = FORM_CON_OUT_ID,
+ title = STRING_TOKEN(STR_FORM_CON_OUT_TITLE);
+
+ label FORM_CON_OUT_ID;
+ label LABEL_END;
+
+ endform;
+
+ form formid = FORM_CON_ERR_ID,
+ title = STRING_TOKEN(STR_FORM_STD_ERR_TITLE);
+
+ label FORM_CON_ERR_ID;
+ label LABEL_END;
+
+ endform;
+
+ form formid = FORM_SET_FD_ORDER_ID,
+ title = STRING_TOKEN(STR_FORM_SET_FD_ORDER_TITLE);
+
+ label FORM_SET_FD_ORDER_ID;
+ label LABEL_END;
+ endform;
+
+ form formid = FORM_SET_HD_ORDER_ID,
+ title = STRING_TOKEN(STR_FORM_SET_HD_ORDER_TITLE);
+
+ label FORM_SET_HD_ORDER_ID;
+ label LABEL_END;
+ endform;
+
+ form formid = FORM_SET_CD_ORDER_ID,
+ title = STRING_TOKEN(STR_FORM_SET_CD_ORDER_TITLE);
+
+ label FORM_SET_CD_ORDER_ID;
+ label LABEL_END;
+ endform;
+
+ form formid = FORM_SET_NET_ORDER_ID,
+ title = STRING_TOKEN(STR_FORM_SET_NET_ORDER_TITLE);
+
+ label FORM_SET_NET_ORDER_ID;
+ label LABEL_END;
+ endform;
+
+ form formid = FORM_SET_BEV_ORDER_ID,
+ title = STRING_TOKEN(STR_FORM_SET_BEV_ORDER_TITLE);
+
+ label FORM_SET_BEV_ORDER_ID;
+ label LABEL_END;
+ endform;
+
+endformset;
diff --git a/MdeModulePkg/Universal/BdsDxe/BootMaint/BmLib.c b/MdeModulePkg/Universal/BdsDxe/BootMaint/BmLib.c new file mode 100644 index 0000000000..e9a7409371 --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/BootMaint/BmLib.c @@ -0,0 +1,563 @@ +/*++
+
+Copyright (c) 2004 - 2008, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ bmlib.c
+
+AgBStract:
+
+ Boot Maintainence Helper functions
+
+--*/
+
+#include "BootMaint.h"
+
+VOID *
+EfiAllocateZeroPool (
+ IN UINTN Size
+ )
+/*++
+
+Routine Description:
+ Wrap original AllocatePool gBS call
+ and ZeroMem gBS call into a single
+ function in order to decrease code length
+
+Arguments:
+
+Returns:
+ Valid pointer to the allocated buffer
+ Null for failure
+
+--*/
+{
+ EFI_STATUS Status;
+ VOID *Ptr;
+ Status = gBS->AllocatePool (EfiBootServicesData, Size, &Ptr);
+ if (EFI_ERROR (Status)) {
+ Ptr = NULL;
+ return Ptr;
+ }
+
+ ZeroMem (Ptr, Size);
+ return Ptr;
+}
+
+EFI_STATUS
+EfiLibLocateProtocol (
+ IN EFI_GUID *ProtocolGuid,
+ OUT VOID **Interface
+ )
+/*++
+
+Routine Description:
+
+ Find the first instance of this Protocol
+ in the system and return it's interface
+
+Arguments:
+
+ ProtocolGuid - Provides the protocol to search for
+ Interface - On return, a pointer to the first interface
+ that matches ProtocolGuid
+
+Returns:
+
+ EFI_SUCCESS - A protocol instance matching ProtocolGuid was found
+
+ EFI_NOT_FOUND - No protocol instances were found that match ProtocolGuid
+
+--*/
+{
+ EFI_STATUS Status;
+
+ Status = gBS->LocateProtocol (
+ ProtocolGuid,
+ NULL,
+ (VOID **) Interface
+ );
+ return Status;
+}
+
+EFI_FILE_HANDLE
+EfiLibOpenRoot (
+ IN EFI_HANDLE DeviceHandle
+ )
+/*++
+
+Routine Description:
+
+ Function opens and returns a file handle to the root directory of a volume.
+
+Arguments:
+
+ DeviceHandle - A handle for a device
+
+Returns:
+
+ A valid file handle or NULL is returned
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
+ EFI_FILE_HANDLE File;
+
+ File = NULL;
+
+ //
+ // File the file system interface to the device
+ //
+ Status = gBS->HandleProtocol (
+ DeviceHandle,
+ &gEfiSimpleFileSystemProtocolGuid,
+ (VOID *) &Volume
+ );
+
+ //
+ // Open the root directory of the volume
+ //
+ if (!EFI_ERROR (Status)) {
+ Status = Volume->OpenVolume (
+ Volume,
+ &File
+ );
+ }
+ //
+ // Done
+ //
+ return EFI_ERROR (Status) ? NULL : File;
+}
+
+BOOLEAN
+EfiGrowBuffer (
+ IN OUT EFI_STATUS *Status,
+ IN OUT VOID **Buffer,
+ IN UINTN BufferSize
+ )
+/*++
+
+Routine Description:
+
+ Helper function called as part of the code needed
+ to allocate the proper sized buffer for various
+ EFI interfaces.
+
+Arguments:
+
+ Status - Current status
+
+ Buffer - Current allocated buffer, or NULL
+
+ BufferSize - Current buffer size needed
+
+Returns:
+
+ TRUE - if the buffer was reallocated and the caller
+ should try the API again.
+
+--*/
+{
+ BOOLEAN TryAgain;
+
+ //
+ // If this is an initial request, buffer will be null with a new buffer size
+ //
+ if (!*Buffer && BufferSize) {
+ *Status = EFI_BUFFER_TOO_SMALL;
+ }
+ //
+ // If the status code is "buffer too small", resize the buffer
+ //
+ TryAgain = FALSE;
+ if (*Status == EFI_BUFFER_TOO_SMALL) {
+
+ SafeFreePool (*Buffer);
+
+ *Buffer = EfiAllocateZeroPool (BufferSize);
+
+ if (*Buffer) {
+ TryAgain = TRUE;
+ } else {
+ *Status = EFI_OUT_OF_RESOURCES;
+ }
+ }
+ //
+ // If there's an error, free the buffer
+ //
+ if (!TryAgain && EFI_ERROR (*Status) && *Buffer) {
+ SafeFreePool (*Buffer);
+ *Buffer = NULL;
+ }
+
+ return TryAgain;
+}
+
+VOID *
+EfiLibGetVariable (
+ IN CHAR16 *Name,
+ IN EFI_GUID *VendorGuid
+ )
+/*++
+
+Routine Description:
+ Function returns the value of the specified variable.
+
+Arguments:
+ Name - A Null-terminated Unicode string that is
+ the name of the vendor's variable.
+
+ VendorGuid - A unique identifier for the vendor.
+
+Returns:
+
+ None
+
+--*/
+{
+ UINTN VarSize;
+
+ return BdsLibGetVariableAndSize (Name, VendorGuid, &VarSize);
+}
+
+EFI_STATUS
+EfiLibDeleteVariable (
+ IN CHAR16 *VarName,
+ IN EFI_GUID *VarGuid
+ )
+/*++
+
+Routine Description:
+ Function deletes the variable specified by VarName and VarGuid.
+
+Arguments:
+ VarName - A Null-terminated Unicode string that is
+ the name of the vendor's variable.
+
+ VendorGuid - A unique identifier for the vendor.
+
+Returns:
+
+ EFI_SUCCESS - The variable was found and removed
+
+ EFI_UNSUPPORTED - The variable store was inaccessible
+
+ EFI_OUT_OF_RESOURCES - The temporary buffer was not available
+
+ EFI_NOT_FOUND - The variable was not found
+
+--*/
+{
+ VOID *VarBuf;
+ EFI_STATUS Status;
+
+ VarBuf = EfiLibGetVariable (VarName, VarGuid);
+ Status = EFI_NOT_FOUND;
+
+ if (VarBuf) {
+ //
+ // Delete variable from Storage
+ //
+ Status = gRT->SetVariable (VarName, VarGuid, VAR_FLAG, 0, NULL);
+ ASSERT (!EFI_ERROR (Status));
+ SafeFreePool (VarBuf);
+ }
+
+ return Status;
+}
+
+EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *
+EfiLibFileSystemVolumeLabelInfo (
+ IN EFI_FILE_HANDLE FHand
+ )
+/*++
+
+Routine Description:
+
+ Function gets the file system information from an open file descriptor,
+ and stores it in a buffer allocated from pool.
+
+Arguments:
+
+ Fhand - A file handle
+
+Returns:
+
+ A pointer to a buffer with file information or NULL is returned
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *Buffer;
+ UINTN BufferSize;
+ //
+ // Initialize for GrowBuffer loop
+ //
+ Buffer = NULL;
+ BufferSize = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO + 200;
+
+ //
+ // Call the real function
+ //
+ while (EfiGrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {
+ Status = FHand->GetInfo (
+ FHand,
+ &gEfiFileSystemVolumeLabelInfoIdGuid,
+ &BufferSize,
+ Buffer
+ );
+ }
+
+ return Buffer;
+}
+
+CHAR16 *
+EfiStrDuplicate (
+ IN CHAR16 *Src
+ )
+{
+ CHAR16 *Dest;
+ UINTN Size;
+
+ Size = StrSize (Src);
+ Dest = EfiAllocateZeroPool (Size);
+ ASSERT (Dest != NULL);
+ if (Dest) {
+ CopyMem (Dest, Src, Size);
+ }
+
+ return Dest;
+}
+
+EFI_FILE_INFO *
+EfiLibFileInfo (
+ IN EFI_FILE_HANDLE FHand
+ )
+/*++
+
+Routine Description:
+
+ Function gets the file information from an open file descriptor, and stores it
+ in a buffer allocated from pool.
+
+Arguments:
+
+ Fhand - A file handle
+
+Returns:
+
+ A pointer to a buffer with file information or NULL is returned
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_FILE_INFO *Buffer;
+ UINTN BufferSize;
+
+ //
+ // Initialize for GrowBuffer loop
+ //
+ Buffer = NULL;
+ BufferSize = SIZE_OF_EFI_FILE_INFO + 200;
+
+ //
+ // Call the real function
+ //
+ while (EfiGrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {
+ Status = FHand->GetInfo (
+ FHand,
+ &gEfiFileInfoGuid,
+ &BufferSize,
+ Buffer
+ );
+ }
+
+ return Buffer;
+}
+
+UINTN
+EfiDevicePathInstanceCount (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+/*++
+
+Routine Description:
+ Function is used to determine the number of device path instances
+ that exist in a device path.
+
+Arguments:
+ DevicePath - A pointer to a device path data structure.
+
+Returns:
+
+ This function counts and returns the number of device path instances
+ in DevicePath.
+
+--*/
+{
+ UINTN Count;
+ UINTN Size;
+
+ Count = 0;
+ while (GetNextDevicePathInstance (&DevicePath, &Size)) {
+ Count += 1;
+ }
+
+ return Count;
+}
+
+VOID *
+EfiReallocatePool (
+ IN VOID *OldPool,
+ IN UINTN OldSize,
+ IN UINTN NewSize
+ )
+/*++
+
+Routine Description:
+ Adjusts the size of a previously allocated buffer.
+
+Arguments:
+ OldPool - A pointer to the buffer whose size is being adjusted.
+ OldSize - The size of the current buffer.
+ NewSize - The size of the new buffer.
+
+Returns:
+
+ EFI_SUCEESS - The requested number of bytes were allocated.
+
+ EFI_OUT_OF_RESOURCES - The pool requested could not be allocated.
+
+ EFI_INVALID_PARAMETER - The buffer was invalid.
+
+--*/
+{
+ VOID *NewPool;
+
+ NewPool = NULL;
+ if (NewSize) {
+ NewPool = EfiAllocateZeroPool (NewSize);
+ }
+
+ if (OldPool) {
+ if (NewPool) {
+ CopyMem (NewPool, OldPool, OldSize < NewSize ? OldSize : NewSize);
+ }
+
+ SafeFreePool (OldPool);
+ }
+
+ return NewPool;
+}
+
+BOOLEAN
+TimeCompare (
+ IN EFI_TIME *FirstTime,
+ IN EFI_TIME *SecondTime
+ )
+/*++
+
+Routine Description:
+ Compare two EFI_TIME data.
+
+Arguments:
+
+ FirstTime - A pointer to the first EFI_TIME data.
+ SecondTime - A pointer to the second EFI_TIME data.
+
+Returns:
+ TRUE The FirstTime is not later than the SecondTime.
+ FALSE The FirstTime is later than the SecondTime.
+
+--*/
+{
+ if (FirstTime->Year != SecondTime->Year) {
+ return (BOOLEAN) (FirstTime->Year < SecondTime->Year);
+ } else if (FirstTime->Month != SecondTime->Month) {
+ return (BOOLEAN) (FirstTime->Month < SecondTime->Month);
+ } else if (FirstTime->Day != SecondTime->Day) {
+ return (BOOLEAN) (FirstTime->Day < SecondTime->Day);
+ } else if (FirstTime->Hour != SecondTime->Hour) {
+ return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour);
+ } else if (FirstTime->Minute != SecondTime->Minute) {
+ return (BOOLEAN) (FirstTime->Minute < FirstTime->Minute);
+ } else if (FirstTime->Second != SecondTime->Second) {
+ return (BOOLEAN) (FirstTime->Second < SecondTime->Second);
+ }
+
+ return (BOOLEAN) (FirstTime->Nanosecond <= SecondTime->Nanosecond);
+}
+
+UINT16 *
+EfiLibStrFromDatahub (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevPath
+ )
+{
+ EFI_STATUS Status;
+ UINT16 *Desc;
+ EFI_DATA_HUB_PROTOCOL *Datahub;
+ UINT64 Count;
+ EFI_DATA_RECORD_HEADER *Record;
+ EFI_SUBCLASS_TYPE1_HEADER *DataHdr;
+ EFI_GUID MiscGuid = EFI_MISC_SUBCLASS_GUID;
+ EFI_MISC_ONBOARD_DEVICE_DATA *ob;
+ EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *Port;
+ EFI_TIME CurTime;
+
+ Status = gBS->LocateProtocol (
+ &gEfiDataHubProtocolGuid,
+ NULL,
+ (VOID **) &Datahub
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ Status = gRT->GetTime (&CurTime, NULL);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ Count = 0;
+ do {
+ Status = Datahub->GetNextRecord (Datahub, &Count, NULL, &Record);
+
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (Record->DataRecordClass == EFI_DATA_RECORD_CLASS_DATA && CompareGuid (&Record->DataRecordGuid, &MiscGuid)) {
+ //
+ // This record is what we need
+ //
+ DataHdr = (EFI_SUBCLASS_TYPE1_HEADER *) (Record + 1);
+ if (EFI_MISC_ONBOARD_DEVICE_RECORD_NUMBER == DataHdr->RecordType) {
+ ob = (EFI_MISC_ONBOARD_DEVICE_DATA *) (DataHdr + 1);
+ if (BdsLibMatchDevicePaths ((EFI_DEVICE_PATH_PROTOCOL *) &ob->OnBoardDevicePath, DevPath)) {
+ GetProducerString (&Record->ProducerName, ob->OnBoardDeviceDescription, &Desc);
+ return Desc;
+ }
+ }
+
+ if (EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_RECORD_NUMBER == DataHdr->RecordType) {
+ Port = (EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *) (DataHdr + 1);
+ if (BdsLibMatchDevicePaths ((EFI_DEVICE_PATH_PROTOCOL *) &Port->PortPath, DevPath)) {
+ GetProducerString (&Record->ProducerName, Port->PortExternalConnectorDesignator, &Desc);
+ return Desc;
+ }
+ }
+ }
+
+ } while (TimeCompare (&Record->LogTime, &CurTime) && Count != 0);
+
+ return NULL;
+}
diff --git a/MdeModulePkg/Universal/BdsDxe/BootMaint/Bmstring.uni b/MdeModulePkg/Universal/BdsDxe/BootMaint/Bmstring.uni Binary files differnew file mode 100644 index 0000000000..a332fb6ea3 --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/BootMaint/Bmstring.uni diff --git a/MdeModulePkg/Universal/BdsDxe/BootMaint/BootMaint.c b/MdeModulePkg/Universal/BdsDxe/BootMaint/BootMaint.c new file mode 100644 index 0000000000..9cf2a9d09a --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/BootMaint/BootMaint.c @@ -0,0 +1,1331 @@ +/*++
+
+Copyright (c) 2004 - 2008, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ BootMaint.c
+
+Abstract:
+
+ Boot Maintainence Main File
+
+--*/
+
+#include "BootMaint.h"
+#include "FormGuid.h"
+#include "Bds.h"
+#include "FrontPage.h"
+
+EFI_GUID EfiLegacyDevOrderGuid = EFI_LEGACY_DEV_ORDER_VARIABLE_GUID;
+EFI_GUID mBootMaintGuid = BOOT_MAINT_FORMSET_GUID;
+EFI_GUID mFileExplorerGuid = FILE_EXPLORE_FORMSET_GUID;
+
+CHAR16 mBootMaintStorageName[] = L"BmData";
+CHAR16 mFileExplorerStorageName[] = L"FeData";
+
+VOID
+InitAllMenu (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+VOID
+FreeAllMenu (
+ VOID
+ );
+
+EFI_STATUS
+CreateMenuStringToken (
+ IN BMM_CALLBACK_DATA *CallbackData,
+ IN EFI_HII_HANDLE HiiHandle,
+ IN BM_MENU_OPTION *MenuOption
+ )
+/*++
+
+Routine Description:
+ Create string tokens for a menu from its help strings and display strings
+
+Arguments:
+ HiiHandle - Hii Handle of the package to be updated.
+ MenuOption - The Menu whose string tokens need to be created
+
+Returns:
+ EFI_SUCCESS - string tokens created successfully
+ others - contain some errors
+
+--*/
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+ UINTN Index;
+
+ for (Index = 0; Index < MenuOption->MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (MenuOption, Index);
+
+ IfrLibNewString (
+ HiiHandle,
+ &NewMenuEntry->DisplayStringToken,
+ NewMenuEntry->DisplayString
+ );
+
+ if (NULL == NewMenuEntry->HelpString) {
+ NewMenuEntry->HelpStringToken = NewMenuEntry->DisplayStringToken;
+ } else {
+ IfrLibNewString (
+ HiiHandle,
+ &NewMenuEntry->HelpStringToken,
+ NewMenuEntry->HelpString
+ );
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+BootMaintExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ )
+/*++
+
+ Routine Description:
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+ Arguments:
+ This - Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ Request - A null-terminated Unicode string in <ConfigRequest> format.
+ Progress - On return, points to a character in the Request string.
+ Points to the string's null terminator if request was successful.
+ Points to the most recent '&' before the first failing name/value
+ pair (or the beginning of the string if the failure is in the
+ first name/value pair) if the request was not successful.
+ Results - A null-terminated Unicode string in <ConfigAltResp> format which
+ has all values filled in for the names in the Request string.
+ String to be allocated by the called function.
+
+ Returns:
+ EFI_SUCCESS - The Results is filled with the requested values.
+ EFI_OUT_OF_RESOURCES - Not enough memory to store the results.
+ EFI_INVALID_PARAMETER - Request is NULL, illegal syntax, or unknown name.
+ EFI_NOT_FOUND - Routing data doesn't match any storage in this driver.
+
+--*/
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ BMM_CALLBACK_DATA *Private;
+
+ Private = BMM_CALLBACK_DATA_FROM_THIS (This);
+
+ //
+ // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
+ //
+ BufferSize = sizeof (BMM_FAKE_NV_DATA);
+ Status = gHiiConfigRouting->BlockToConfig (
+ gHiiConfigRouting,
+ Request,
+ (UINT8 *) &Private->BmmFakeNvData,
+ BufferSize,
+ Results,
+ Progress
+ );
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+BootMaintCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+/*++
+
+ Routine Description:
+ This function processes the results of changes in configuration.
+
+ Arguments:
+ This - Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ Action - Specifies the type of action taken by the browser.
+ QuestionId - A unique value which is sent to the original exporting driver
+ so that it can identify the type of data to expect.
+ Type - The type of value for the question.
+ Value - A pointer to the data being sent to the original exporting driver.
+ ActionRequest - On return, points to the action requested by the callback function.
+
+ Returns:
+ EFI_SUCCESS - The callback successfully handled the action.
+ EFI_OUT_OF_RESOURCES - Not enough storage is available to hold the variable and its data.
+ EFI_DEVICE_ERROR - The variable could not be saved.
+ EFI_UNSUPPORTED - The specified Action is not supported by the callback.
+
+--*/
+{
+ BMM_CALLBACK_DATA *Private;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BMM_FAKE_NV_DATA *CurrentFakeNVMap;
+ EFI_STATUS Status;
+ UINTN OldValue;
+ UINTN NewValue;
+ UINTN Number;
+ UINTN Pos;
+ UINTN Bit;
+ UINT16 NewValuePos;
+ UINT16 Index2;
+ UINT16 Index;
+ UINT8 *OldLegacyDev;
+ UINT8 *NewLegacyDev;
+ UINT8 *DisMap;
+ EFI_FORM_ID FormId;
+ UINTN BufferSize;
+
+ if ((Value == NULL) || (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldValue = 0;
+ NewValue = 0;
+ Number = 0;
+ OldLegacyDev = NULL;
+ NewLegacyDev = NULL;
+ NewValuePos = 0;
+ DisMap = NULL;
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
+
+ Private = BMM_CALLBACK_DATA_FROM_THIS (This);
+ UpdatePageId (Private, QuestionId);
+
+ //
+ // Retrive uncommitted data from Form Browser
+ //
+ CurrentFakeNVMap = &Private->BmmFakeNvData;
+ BufferSize = sizeof (BMM_FAKE_NV_DATA);
+ Status = GetBrowserData (NULL, NULL, &BufferSize, (UINT8 *) CurrentFakeNVMap);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // need to be subtituded.
+ //
+ // Update Select FD/HD/CD/NET/BEV Order Form
+ //
+ if (FORM_SET_FD_ORDER_ID == Private->BmmPreviousPageId ||
+ FORM_SET_HD_ORDER_ID == Private->BmmPreviousPageId ||
+ FORM_SET_CD_ORDER_ID == Private->BmmPreviousPageId ||
+ FORM_SET_NET_ORDER_ID == Private->BmmPreviousPageId ||
+ FORM_SET_BEV_ORDER_ID == Private->BmmPreviousPageId ||
+ ((FORM_BOOT_SETUP_ID == Private->BmmPreviousPageId) &&
+ (QuestionId >= LEGACY_FD_QUESTION_ID) &&
+ (QuestionId < (LEGACY_BEV_QUESTION_ID + 100)) )
+ ) {
+
+ DisMap = Private->BmmOldFakeNVData.DisableMap;
+
+ FormId = Private->BmmPreviousPageId;
+ if (FormId == FORM_BOOT_SETUP_ID) {
+ FormId = Private->BmmCurrentPageId;
+ }
+
+ switch (FormId) {
+ case FORM_SET_FD_ORDER_ID:
+ Number = (UINT16) LegacyFDMenu.MenuNumber;
+ OldLegacyDev = Private->BmmOldFakeNVData.LegacyFD;
+ NewLegacyDev = CurrentFakeNVMap->LegacyFD;
+ break;
+
+ case FORM_SET_HD_ORDER_ID:
+ Number = (UINT16) LegacyHDMenu.MenuNumber;
+ OldLegacyDev = Private->BmmOldFakeNVData.LegacyHD;
+ NewLegacyDev = CurrentFakeNVMap->LegacyHD;
+ break;
+
+ case FORM_SET_CD_ORDER_ID:
+ Number = (UINT16) LegacyCDMenu.MenuNumber;
+ OldLegacyDev = Private->BmmOldFakeNVData.LegacyCD;
+ NewLegacyDev = CurrentFakeNVMap->LegacyCD;
+ break;
+
+ case FORM_SET_NET_ORDER_ID:
+ Number = (UINT16) LegacyNETMenu.MenuNumber;
+ OldLegacyDev = Private->BmmOldFakeNVData.LegacyNET;
+ NewLegacyDev = CurrentFakeNVMap->LegacyNET;
+ break;
+
+ case FORM_SET_BEV_ORDER_ID:
+ Number = (UINT16) LegacyBEVMenu.MenuNumber;
+ OldLegacyDev = Private->BmmOldFakeNVData.LegacyBEV;
+ NewLegacyDev = CurrentFakeNVMap->LegacyBEV;
+ break;
+
+ default:
+ break;
+ }
+ //
+ // First, find the different position
+ // if there is change, it should be only one
+ //
+ for (Index = 0; Index < Number; Index++) {
+ if (OldLegacyDev[Index] != NewLegacyDev[Index]) {
+ OldValue = OldLegacyDev[Index];
+ NewValue = NewLegacyDev[Index];
+ break;
+ }
+ }
+
+ if (Index != Number) {
+ //
+ // there is change, now process
+ //
+ if (0xFF == NewValue) {
+ //
+ // This item will be disable
+ // Just move the items behind this forward to overlap it
+ //
+ Pos = OldValue / 8;
+ Bit = 7 - (OldValue % 8);
+ DisMap[Pos] = (UINT8) (DisMap[Pos] | (UINT8) (1 << Bit));
+ for (Index2 = Index; Index2 < Number - 1; Index2++) {
+ NewLegacyDev[Index2] = NewLegacyDev[Index2 + 1];
+ }
+
+ NewLegacyDev[Index2] = 0xFF;
+ } else {
+ for (Index2 = 0; Index2 < Number; Index2++) {
+ if (Index2 == Index) {
+ continue;
+ }
+
+ if (OldLegacyDev[Index2] == NewValue) {
+ //
+ // If NewValue is in OldLegacyDev array
+ // remember its old position
+ //
+ NewValuePos = Index2;
+ break;
+ }
+ }
+
+ if (Index2 != Number) {
+ //
+ // We will change current item to an existing item
+ // (It's hard to describe here, please read code, it's like a cycle-moving)
+ //
+ for (Index2 = NewValuePos; Index2 != Index;) {
+ if (NewValuePos < Index) {
+ NewLegacyDev[Index2] = OldLegacyDev[Index2 + 1];
+ Index2++;
+ } else {
+ NewLegacyDev[Index2] = OldLegacyDev[Index2 - 1];
+ Index2--;
+ }
+ }
+ } else {
+ //
+ // If NewValue is not in OldlegacyDev array, we are changing to a disabled item
+ // so we should modify DisMap to reflect the change
+ //
+ Pos = NewValue / 8;
+ Bit = 7 - (NewValue % 8);
+ DisMap[Pos] = (UINT8) (DisMap[Pos] & (~ (UINT8) (1 << Bit)));
+ if (0xFF != OldValue) {
+ //
+ // Because NewValue is a item that was disabled before
+ // so after changing the OldValue should be disabled
+ // actually we are doing a swap of enable-disable states of two items
+ //
+ Pos = OldValue / 8;
+ Bit = 7 - (OldValue % 8);
+ DisMap[Pos] = (UINT8) (DisMap[Pos] | (UINT8) (1 << Bit));
+ }
+ }
+ }
+ //
+ // To prevent DISABLE appears in the middle of the list
+ // we should perform a re-ordering
+ //
+ Index = 0;
+ while (Index < Number) {
+ if (0xFF != NewLegacyDev[Index]) {
+ Index++;
+ continue;
+ }
+
+ Index2 = Index;
+ Index2++;
+ while (Index2 < Number) {
+ if (0xFF != NewLegacyDev[Index2]) {
+ break;
+ }
+
+ Index2++;
+ }
+
+ if (Index2 < Number) {
+ NewLegacyDev[Index] = NewLegacyDev[Index2];
+ NewLegacyDev[Index2] = 0xFF;
+ }
+
+ Index++;
+ }
+
+ CopyMem (
+ OldLegacyDev,
+ NewLegacyDev,
+ Number
+ );
+ }
+ }
+
+ if (QuestionId < FILE_OPTION_OFFSET) {
+ if (QuestionId < CONFIG_OPTION_OFFSET) {
+ switch (QuestionId) {
+ case KEY_VALUE_BOOT_FROM_FILE:
+ Private->FeCurrentState = BOOT_FROM_FILE_STATE;
+
+ //
+ // Exit Bmm main formset to send File Explorer formset.
+ //
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ break;
+
+ case FORM_BOOT_ADD_ID:
+ Private->FeCurrentState = ADD_BOOT_OPTION_STATE;
+
+ //
+ // Exit Bmm main formset to send File Explorer formset.
+ //
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ break;
+
+ case FORM_DRV_ADD_FILE_ID:
+ Private->FeCurrentState = ADD_DRIVER_OPTION_STATE;
+
+ //
+ // Exit Bmm main formset to send File Explorer formset.
+ //
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ break;
+
+ case FORM_DRV_ADD_HANDLE_ID:
+ CleanUpPage (FORM_DRV_ADD_HANDLE_ID, Private);
+ UpdateDrvAddHandlePage (Private);
+ break;
+
+ case FORM_BOOT_DEL_ID:
+ CleanUpPage (FORM_BOOT_DEL_ID, Private);
+ UpdateBootDelPage (Private);
+ break;
+
+ case FORM_BOOT_CHG_ID:
+ case FORM_DRV_CHG_ID:
+ UpdatePageBody (QuestionId, Private);
+ break;
+
+ case FORM_DRV_DEL_ID:
+ CleanUpPage (FORM_DRV_DEL_ID, Private);
+ UpdateDrvDelPage (Private);
+ break;
+
+ case FORM_BOOT_NEXT_ID:
+ CleanUpPage (FORM_BOOT_NEXT_ID, Private);
+ UpdateBootNextPage (Private);
+ break;
+
+ case FORM_TIME_OUT_ID:
+ CleanUpPage (FORM_TIME_OUT_ID, Private);
+ UpdateTimeOutPage (Private);
+ break;
+
+ case FORM_RESET:
+ gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
+ return EFI_UNSUPPORTED;
+
+ case FORM_CON_IN_ID:
+ case FORM_CON_OUT_ID:
+ case FORM_CON_ERR_ID:
+ UpdatePageBody (QuestionId, Private);
+ break;
+
+ case FORM_CON_MODE_ID:
+ CleanUpPage (FORM_CON_MODE_ID, Private);
+ UpdateConModePage (Private);
+ break;
+
+ case FORM_CON_COM_ID:
+ CleanUpPage (FORM_CON_COM_ID, Private);
+ UpdateConCOMPage (Private);
+ break;
+
+ case FORM_SET_FD_ORDER_ID:
+ case FORM_SET_HD_ORDER_ID:
+ case FORM_SET_CD_ORDER_ID:
+ case FORM_SET_NET_ORDER_ID:
+ case FORM_SET_BEV_ORDER_ID:
+ CleanUpPage (QuestionId, Private);
+ UpdateSetLegacyDeviceOrderPage (QuestionId, Private);
+ break;
+
+ case KEY_VALUE_SAVE_AND_EXIT:
+ case KEY_VALUE_NO_SAVE_AND_EXIT:
+
+ if (QuestionId == KEY_VALUE_SAVE_AND_EXIT) {
+ Status = ApplyChangeHandler (Private, CurrentFakeNVMap, Private->BmmPreviousPageId);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else if (QuestionId == KEY_VALUE_NO_SAVE_AND_EXIT) {
+ DiscardChangeHandler (Private, CurrentFakeNVMap);
+ }
+
+ //
+ // Tell browser not to ask for confirmation of changes,
+ // since we have already applied or discarded.
+ //
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;
+ break;
+
+ default:
+ break;
+ }
+ } else if ((QuestionId >= TERMINAL_OPTION_OFFSET) && (QuestionId < CONSOLE_OPTION_OFFSET)) {
+ Index2 = (UINT16) (QuestionId - TERMINAL_OPTION_OFFSET);
+ Private->CurrentTerminal = Index2;
+
+ CleanUpPage (FORM_CON_COM_SETUP_ID, Private);
+ UpdateTerminalPage (Private);
+
+ } else if (QuestionId >= HANDLE_OPTION_OFFSET) {
+ Index2 = (UINT16) (QuestionId - HANDLE_OPTION_OFFSET);
+
+ NewMenuEntry = BOpt_GetMenuEntry (&DriverMenu, Index2);
+ ASSERT (NewMenuEntry != NULL);
+ Private->HandleContext = (BM_HANDLE_CONTEXT *) NewMenuEntry->VariableContext;
+
+ CleanUpPage (FORM_DRV_ADD_HANDLE_DESC_ID, Private);
+
+ Private->MenuEntry = NewMenuEntry;
+ Private->LoadContext->FilePathList = Private->HandleContext->DevicePath;
+
+ UpdateDriverAddHandleDescPage (Private);
+ }
+ }
+
+ //
+ // Pass changed uncommitted data back to Form Browser
+ //
+ BufferSize = sizeof (BMM_FAKE_NV_DATA);
+ Status = SetBrowserData (NULL, NULL, BufferSize, (UINT8 *) CurrentFakeNVMap, NULL);
+
+ return Status;
+}
+
+EFI_STATUS
+ApplyChangeHandler (
+ IN BMM_CALLBACK_DATA *Private,
+ IN BMM_FAKE_NV_DATA *CurrentFakeNVMap,
+ IN EFI_FORM_ID FormId
+ )
+/*++
+
+Routine Description:
+ Function handling request to apply changes for BMM pages.
+
+Arguments:
+ Private - Pointer to callback data buffer.
+ CurrentFakeNVMap - Pointer to buffer holding data of various values used by BMM
+ FormId - ID of the form which has sent the request to apply change.
+
+Returns:
+ EFI_SUCCESS - Change successfully applied.
+ Other - Error occurs while trying to apply changes.
+
+--*/
+{
+ BM_CONSOLE_CONTEXT *NewConsoleContext;
+ BM_TERMINAL_CONTEXT *NewTerminalContext;
+ BM_LOAD_CONTEXT *NewLoadContext;
+ BM_MENU_ENTRY *NewMenuEntry;
+ EFI_STATUS Status;
+ UINT16 Index;
+
+ Status = EFI_SUCCESS;
+
+ switch (FormId) {
+ case FORM_SET_FD_ORDER_ID:
+ case FORM_SET_HD_ORDER_ID:
+ case FORM_SET_CD_ORDER_ID:
+ case FORM_SET_NET_ORDER_ID:
+ case FORM_SET_BEV_ORDER_ID:
+ Var_UpdateBBSOption (Private);
+ break;
+
+ case FORM_BOOT_DEL_ID:
+ for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index);
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+ NewLoadContext->Deleted = CurrentFakeNVMap->BootOptionDel[Index];
+ }
+
+ Var_DelBootOption ();
+ break;
+
+ case FORM_DRV_DEL_ID:
+ for (Index = 0; Index < DriverOptionMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index);
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+ NewLoadContext->Deleted = CurrentFakeNVMap->DriverOptionDel[Index];
+ }
+
+ Var_DelDriverOption ();
+ break;
+
+ case FORM_BOOT_CHG_ID:
+ Status = Var_UpdateBootOrder (Private);
+ break;
+
+ case FORM_DRV_CHG_ID:
+ Status = Var_UpdateDriverOrder (Private);
+ break;
+
+ case FORM_TIME_OUT_ID:
+ Status = gRT->SetVariable (
+ L"Timeout",
+ &gEfiGlobalVariableGuid,
+ VAR_FLAG,
+ sizeof (UINT16),
+ &(CurrentFakeNVMap->BootTimeOut)
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ Private->BmmOldFakeNVData.BootTimeOut = CurrentFakeNVMap->BootTimeOut;
+ break;
+
+ case FORM_BOOT_NEXT_ID:
+ Status = Var_UpdateBootNext (Private);
+ break;
+
+ case FORM_CON_MODE_ID:
+ Status = Var_UpdateConMode (Private);
+ break;
+
+ case FORM_CON_COM_SETUP_ID:
+ NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Private->CurrentTerminal);
+
+ ASSERT (NewMenuEntry != NULL);
+
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
+
+ NewTerminalContext->BaudRateIndex = CurrentFakeNVMap->COMBaudRate;
+ NewTerminalContext->BaudRate = BaudRateList[CurrentFakeNVMap->COMBaudRate].Value;
+ NewTerminalContext->DataBitsIndex = CurrentFakeNVMap->COMDataRate;
+ NewTerminalContext->DataBits = (UINT8) DataBitsList[CurrentFakeNVMap->COMDataRate].Value;
+ NewTerminalContext->StopBitsIndex = CurrentFakeNVMap->COMStopBits;
+ NewTerminalContext->StopBits = (UINT8) StopBitsList[CurrentFakeNVMap->COMStopBits].Value;
+ NewTerminalContext->ParityIndex = CurrentFakeNVMap->COMParity;
+ NewTerminalContext->Parity = (UINT8) ParityList[CurrentFakeNVMap->COMParity].Value;
+ NewTerminalContext->TerminalType = CurrentFakeNVMap->COMTerminalType;
+
+ ChangeTerminalDevicePath (
+ NewTerminalContext->DevicePath,
+ FALSE
+ );
+
+ Var_UpdateConsoleInpOption ();
+ Var_UpdateConsoleOutOption ();
+ Var_UpdateErrorOutOption ();
+ break;
+
+ case FORM_CON_IN_ID:
+ for (Index = 0; Index < ConsoleInpMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&ConsoleInpMenu, Index);
+ NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;
+ NewConsoleContext->IsActive = CurrentFakeNVMap->ConsoleCheck[Index];
+ }
+
+ for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
+ NewTerminalContext->IsConIn = CurrentFakeNVMap->ConsoleCheck[Index + ConsoleInpMenu.MenuNumber];
+ }
+
+ Var_UpdateConsoleInpOption ();
+ break;
+
+ case FORM_CON_OUT_ID:
+ for (Index = 0; Index < ConsoleOutMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&ConsoleOutMenu, Index);
+ NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;
+ NewConsoleContext->IsActive = CurrentFakeNVMap->ConsoleCheck[Index];
+ }
+
+ for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
+ NewTerminalContext->IsConOut = CurrentFakeNVMap->ConsoleCheck[Index + ConsoleOutMenu.MenuNumber];
+ }
+
+ Var_UpdateConsoleOutOption ();
+ break;
+
+ case FORM_CON_ERR_ID:
+ for (Index = 0; Index < ConsoleErrMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&ConsoleErrMenu, Index);
+ NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;
+ NewConsoleContext->IsActive = CurrentFakeNVMap->ConsoleCheck[Index];
+ }
+
+ for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
+ NewTerminalContext->IsStdErr = CurrentFakeNVMap->ConsoleCheck[Index + ConsoleErrMenu.MenuNumber];
+ }
+
+ Var_UpdateErrorOutOption ();
+ break;
+
+ case FORM_DRV_ADD_HANDLE_DESC_ID:
+ Status = Var_UpdateDriverOption (
+ Private,
+ Private->BmmHiiHandle,
+ CurrentFakeNVMap->DriverAddHandleDesc,
+ CurrentFakeNVMap->DriverAddHandleOptionalData,
+ CurrentFakeNVMap->DriverAddForceReconnect
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ BOpt_GetDriverOptions (Private);
+ CreateMenuStringToken (Private, Private->BmmHiiHandle, &DriverOptionMenu);
+ break;
+
+ default:
+ break;
+ }
+
+Error:
+ return Status;
+}
+
+VOID
+DiscardChangeHandler (
+ IN BMM_CALLBACK_DATA *Private,
+ IN BMM_FAKE_NV_DATA *CurrentFakeNVMap
+ )
+{
+ UINT16 Index;
+
+ switch (Private->BmmPreviousPageId) {
+ case FORM_BOOT_CHG_ID:
+ case FORM_DRV_CHG_ID:
+ CopyMem (CurrentFakeNVMap->OptionOrder, Private->BmmOldFakeNVData.OptionOrder, 100);
+ break;
+
+ case FORM_BOOT_DEL_ID:
+ for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
+ CurrentFakeNVMap->BootOptionDel[Index] = 0x00;
+ }
+ break;
+
+ case FORM_DRV_DEL_ID:
+ for (Index = 0; Index < DriverOptionMenu.MenuNumber; Index++) {
+ CurrentFakeNVMap->DriverOptionDel[Index] = 0x00;
+ }
+ break;
+
+ case FORM_BOOT_NEXT_ID:
+ CurrentFakeNVMap->BootNext = Private->BmmOldFakeNVData.BootNext;
+ break;
+
+ case FORM_TIME_OUT_ID:
+ CurrentFakeNVMap->BootTimeOut = Private->BmmOldFakeNVData.BootTimeOut;
+ break;
+
+ case FORM_DRV_ADD_HANDLE_DESC_ID:
+ case FORM_DRV_ADD_FILE_ID:
+ case FORM_DRV_ADD_HANDLE_ID:
+ CurrentFakeNVMap->DriverAddHandleDesc[0] = 0x0000;
+ CurrentFakeNVMap->DriverAddHandleOptionalData[0] = 0x0000;
+ break;
+
+ default:
+ break;
+ }
+}
+
+EFI_STATUS
+InitializeBM (
+ VOID
+ )
+/*++
+
+Routine Description:
+ Initialize the Boot Maintenance Utitliy
+
+Arguments:
+ ImageHandle - caller provided handle
+ SystemTable - caller provided system tables
+
+Returns:
+ EFI_SUCCESS - utility ended successfully
+ others - contain some errors
+
+--*/
+{
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ EFI_HII_PACKAGE_LIST_HEADER *PackageList;
+ BMM_CALLBACK_DATA *BmmCallbackInfo;
+ EFI_STATUS Status;
+ UINT8 *Ptr;
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Create CallbackData structures for Driver Callback
+ //
+ BmmCallbackInfo = EfiAllocateZeroPool (sizeof (BMM_CALLBACK_DATA));
+ if (BmmCallbackInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Create LoadOption in BmmCallbackInfo for Driver Callback
+ //
+ Ptr = EfiAllocateZeroPool (sizeof (BM_LOAD_CONTEXT) + sizeof (BM_FILE_CONTEXT) + sizeof (BM_HANDLE_CONTEXT) + sizeof (BM_MENU_ENTRY));
+ if (!Ptr) {
+ SafeFreePool (BmmCallbackInfo);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Initialize Bmm callback data.
+ //
+ BmmCallbackInfo->LoadContext = (BM_LOAD_CONTEXT *) Ptr;
+ Ptr += sizeof (BM_LOAD_CONTEXT);
+
+ BmmCallbackInfo->FileContext = (BM_FILE_CONTEXT *) Ptr;
+ Ptr += sizeof (BM_FILE_CONTEXT);
+
+ BmmCallbackInfo->HandleContext = (BM_HANDLE_CONTEXT *) Ptr;
+ Ptr += sizeof (BM_HANDLE_CONTEXT);
+
+ BmmCallbackInfo->MenuEntry = (BM_MENU_ENTRY *) Ptr;
+
+ BmmCallbackInfo->Signature = BMM_CALLBACK_DATA_SIGNATURE;
+ BmmCallbackInfo->BmmConfigAccess.ExtractConfig = BootMaintExtractConfig;
+ BmmCallbackInfo->BmmConfigAccess.RouteConfig = FakeRouteConfig;
+ BmmCallbackInfo->BmmConfigAccess.Callback = BootMaintCallback;
+ BmmCallbackInfo->BmmPreviousPageId = FORM_MAIN_ID;
+ BmmCallbackInfo->BmmCurrentPageId = FORM_MAIN_ID;
+ BmmCallbackInfo->FeConfigAccess.ExtractConfig = FakeExtractConfig;
+ BmmCallbackInfo->FeConfigAccess.RouteConfig = FakeRouteConfig;
+ BmmCallbackInfo->FeConfigAccess.Callback = FileExplorerCallback;
+ BmmCallbackInfo->FeCurrentState = INACTIVE_STATE;
+ BmmCallbackInfo->FeDisplayContext = UNKNOWN_CONTEXT;
+
+ //
+ // Create driver handle used by HII database
+ //
+ Status = HiiLibCreateHiiDriverHandle (&BmmCallbackInfo->BmmDriverHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Install Config Access protocol to driver handle
+ //
+ Status = gBS->InstallProtocolInterface (
+ &BmmCallbackInfo->BmmDriverHandle,
+ &gEfiHiiConfigAccessProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &BmmCallbackInfo->BmmConfigAccess
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Create driver handle used by HII database
+ //
+ Status = HiiLibCreateHiiDriverHandle (&BmmCallbackInfo->FeDriverHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Install Config Access protocol to driver handle
+ //
+ Status = gBS->InstallProtocolInterface (
+ &BmmCallbackInfo->FeDriverHandle,
+ &gEfiHiiConfigAccessProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &BmmCallbackInfo->FeConfigAccess
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Post our Boot Maint VFR binnary to the HII database.
+ //
+ PackageList = PreparePackageList (2, &mBootMaintGuid, BmBin, BdsStrings);
+ ASSERT (PackageList != NULL);
+
+ Status = gHiiDatabase->NewPackageList (
+ gHiiDatabase,
+ PackageList,
+ BmmCallbackInfo->BmmDriverHandle,
+ &BmmCallbackInfo->BmmHiiHandle
+ );
+ FreePool (PackageList);
+
+ //
+ // Post our File Explorer VFR binary to the HII database.
+ //
+ PackageList = PreparePackageList (2, &mFileExplorerGuid, FEBin, BdsStrings);
+ ASSERT (PackageList != NULL);
+
+ Status = gHiiDatabase->NewPackageList (
+ gHiiDatabase,
+ PackageList,
+ BmmCallbackInfo->FeDriverHandle,
+ &BmmCallbackInfo->FeHiiHandle
+ );
+ FreePool (PackageList);
+
+ //
+ // Allocate space for creation of Buffer
+ //
+ gUpdateData.BufferSize = UPDATE_DATA_SIZE;
+ gUpdateData.Data = EfiAllocateZeroPool (UPDATE_DATA_SIZE);
+ if (gUpdateData.Data == NULL) {
+ SafeFreePool (BmmCallbackInfo->LoadContext);
+ SafeFreePool (BmmCallbackInfo);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ InitializeStringDepository ();
+
+ InitAllMenu (BmmCallbackInfo);
+
+ CreateMenuStringToken (BmmCallbackInfo, BmmCallbackInfo->BmmHiiHandle, &ConsoleInpMenu);
+ CreateMenuStringToken (BmmCallbackInfo, BmmCallbackInfo->BmmHiiHandle, &ConsoleOutMenu);
+ CreateMenuStringToken (BmmCallbackInfo, BmmCallbackInfo->BmmHiiHandle, &ConsoleErrMenu);
+ CreateMenuStringToken (BmmCallbackInfo, BmmCallbackInfo->BmmHiiHandle, &BootOptionMenu);
+ CreateMenuStringToken (BmmCallbackInfo, BmmCallbackInfo->BmmHiiHandle, &DriverOptionMenu);
+ CreateMenuStringToken (BmmCallbackInfo, BmmCallbackInfo->BmmHiiHandle, &TerminalMenu);
+ CreateMenuStringToken (BmmCallbackInfo, BmmCallbackInfo->BmmHiiHandle, &DriverMenu);
+
+ UpdateBootDelPage (BmmCallbackInfo);
+ UpdateDrvDelPage (BmmCallbackInfo);
+
+ if (TerminalMenu.MenuNumber > 0) {
+ BmmCallbackInfo->CurrentTerminal = 0;
+ UpdateTerminalPage (BmmCallbackInfo);
+ }
+
+ Status = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios);
+ if (!EFI_ERROR (Status)) {
+ RefreshUpdateData ();
+
+ //
+ // If LegacyBios Protocol is installed, add 3 tags about legacy boot option
+ // in BootOption form: legacy FD/HD/CD/NET/BEV
+ //
+ CreateGotoOpCode (
+ FORM_SET_FD_ORDER_ID,
+ STRING_TOKEN (STR_FORM_SET_FD_ORDER_TITLE),
+ STRING_TOKEN (STR_FORM_SET_FD_ORDER_TITLE),
+ EFI_IFR_FLAG_CALLBACK,
+ FORM_SET_FD_ORDER_ID,
+ &gUpdateData
+ );
+
+ CreateGotoOpCode (
+ FORM_SET_HD_ORDER_ID,
+ STRING_TOKEN (STR_FORM_SET_HD_ORDER_TITLE),
+ STRING_TOKEN (STR_FORM_SET_HD_ORDER_TITLE),
+ EFI_IFR_FLAG_CALLBACK,
+ FORM_SET_HD_ORDER_ID,
+ &gUpdateData
+ );
+
+ CreateGotoOpCode (
+ FORM_SET_CD_ORDER_ID,
+ STRING_TOKEN (STR_FORM_SET_CD_ORDER_TITLE),
+ STRING_TOKEN (STR_FORM_SET_CD_ORDER_TITLE),
+ EFI_IFR_FLAG_CALLBACK,
+ FORM_SET_CD_ORDER_ID,
+ &gUpdateData
+ );
+
+ CreateGotoOpCode (
+ FORM_SET_NET_ORDER_ID,
+ STRING_TOKEN (STR_FORM_SET_NET_ORDER_TITLE),
+ STRING_TOKEN (STR_FORM_SET_NET_ORDER_TITLE),
+ EFI_IFR_FLAG_CALLBACK,
+ FORM_SET_NET_ORDER_ID,
+ &gUpdateData
+ );
+
+ CreateGotoOpCode (
+ FORM_SET_BEV_ORDER_ID,
+ STRING_TOKEN (STR_FORM_SET_BEV_ORDER_TITLE),
+ STRING_TOKEN (STR_FORM_SET_BEV_ORDER_TITLE),
+ EFI_IFR_FLAG_CALLBACK,
+ FORM_SET_BEV_ORDER_ID,
+ &gUpdateData
+ );
+
+ IfrLibUpdateForm (
+ BmmCallbackInfo->BmmHiiHandle,
+ &mBootMaintGuid,
+ FORM_MAIN_ID,
+ FORM_BOOT_LEGACY_DEVICE_ID,
+ FALSE,
+ &gUpdateData
+ );
+ }
+
+ //
+ // Dispatch BMM main formset and File Explorer formset.
+ //
+ FormSetDispatcher (BmmCallbackInfo);
+
+ //
+ // Remove our IFR data from HII database
+ //
+ gHiiDatabase->RemovePackageList (gHiiDatabase, BmmCallbackInfo->BmmHiiHandle);
+ gHiiDatabase->RemovePackageList (gHiiDatabase, BmmCallbackInfo->FeHiiHandle);
+
+ CleanUpStringDepository ();
+
+ FreeAllMenu ();
+
+ SafeFreePool (BmmCallbackInfo->LoadContext);
+ SafeFreePool (BmmCallbackInfo);
+ SafeFreePool (gUpdateData.Data);
+ gUpdateData.Data = NULL;
+
+ return Status;
+}
+
+VOID
+InitAllMenu (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ InitializeListHead (&BootOptionMenu.Head);
+ InitializeListHead (&DriverOptionMenu.Head);
+ BOpt_GetBootOptions (CallbackData);
+ BOpt_GetDriverOptions (CallbackData);
+ BOpt_GetLegacyOptions ();
+ InitializeListHead (&FsOptionMenu.Head);
+ BOpt_FindDrivers ();
+ InitializeListHead (&DirectoryMenu.Head);
+ InitializeListHead (&ConsoleInpMenu.Head);
+ InitializeListHead (&ConsoleOutMenu.Head);
+ InitializeListHead (&ConsoleErrMenu.Head);
+ InitializeListHead (&TerminalMenu.Head);
+ LocateSerialIo ();
+ GetAllConsoles ();
+}
+
+VOID
+FreeAllMenu (
+ VOID
+ )
+{
+ BOpt_FreeMenu (&DirectoryMenu);
+ BOpt_FreeMenu (&FsOptionMenu);
+ BOpt_FreeMenu (&BootOptionMenu);
+ BOpt_FreeMenu (&DriverOptionMenu);
+ BOpt_FreeMenu (&DriverMenu);
+ BOpt_FreeLegacyOptions ();
+ FreeAllConsoles ();
+}
+
+VOID
+InitializeStringDepository (
+ VOID
+ )
+/*++
+
+Routine Description:
+ Intialize all the string depositories.
+
+Arguments:
+ None.
+
+Returns:
+ None.
+
+--*/
+{
+ STRING_DEPOSITORY *StringDepository;
+ StringDepository = EfiAllocateZeroPool (sizeof (STRING_DEPOSITORY) * STRING_DEPOSITORY_NUMBER);
+ FileOptionStrDepository = StringDepository++;
+ ConsoleOptionStrDepository = StringDepository++;
+ BootOptionStrDepository = StringDepository++;
+ BootOptionHelpStrDepository = StringDepository++;
+ DriverOptionStrDepository = StringDepository++;
+ DriverOptionHelpStrDepository = StringDepository++;
+ TerminalStrDepository = StringDepository;
+}
+
+EFI_STRING_ID
+GetStringTokenFromDepository (
+ IN BMM_CALLBACK_DATA *CallbackData,
+ IN STRING_DEPOSITORY *StringDepository
+ )
+/*++
+
+Routine Description:
+ Fetch a usable string node from the string depository and return the string token.
+
+Arguments:
+ StringDepository - Pointer of the string depository.
+
+Returns:
+ EFI_STRING_ID - String token.
+
+--*/
+{
+ STRING_LIST_NODE *CurrentListNode;
+ STRING_LIST_NODE *NextListNode;
+
+ CurrentListNode = StringDepository->CurrentNode;
+
+ if ((NULL != CurrentListNode) && (NULL != CurrentListNode->Next)) {
+ //
+ // Fetch one reclaimed node from the list.
+ //
+ NextListNode = StringDepository->CurrentNode->Next;
+ } else {
+ //
+ // If there is no usable node in the list, update the list.
+ //
+ NextListNode = EfiAllocateZeroPool (sizeof (STRING_LIST_NODE));
+
+ IfrLibNewString (CallbackData->BmmHiiHandle, &(NextListNode->StringToken), L" ");
+ ASSERT (NextListNode->StringToken != 0);
+
+ StringDepository->TotalNodeNumber++;
+
+ if (NULL == CurrentListNode) {
+ StringDepository->ListHead = NextListNode;
+ } else {
+ CurrentListNode->Next = NextListNode;
+ }
+ }
+
+ StringDepository->CurrentNode = NextListNode;
+
+ return StringDepository->CurrentNode->StringToken;
+}
+
+VOID
+ReclaimStringDepository (
+ VOID
+ )
+/*++
+
+Routine Description:
+ Reclaim string depositories by moving the current node pointer to list head..
+
+Arguments:
+ None.
+
+Returns:
+ None.
+
+--*/
+{
+ UINTN DepositoryIndex;
+ STRING_DEPOSITORY *StringDepository;
+
+ StringDepository = FileOptionStrDepository;
+ for (DepositoryIndex = 0; DepositoryIndex < STRING_DEPOSITORY_NUMBER; DepositoryIndex++) {
+ StringDepository->CurrentNode = StringDepository->ListHead;
+ StringDepository++;
+ }
+}
+
+VOID
+CleanUpStringDepository (
+ VOID
+ )
+/*++
+
+Routine Description:
+ Release resource for all the string depositories.
+
+Arguments:
+ None.
+
+Returns:
+ None.
+
+--*/
+{
+ UINTN NodeIndex;
+ UINTN DepositoryIndex;
+ STRING_LIST_NODE *CurrentListNode;
+ STRING_LIST_NODE *NextListNode;
+ STRING_DEPOSITORY *StringDepository;
+
+ //
+ // Release string list nodes.
+ //
+ StringDepository = FileOptionStrDepository;
+ for (DepositoryIndex = 0; DepositoryIndex < STRING_DEPOSITORY_NUMBER; DepositoryIndex++) {
+ CurrentListNode = StringDepository->ListHead;
+ for (NodeIndex = 0; NodeIndex < StringDepository->TotalNodeNumber; NodeIndex++) {
+ NextListNode = CurrentListNode->Next;
+ SafeFreePool (CurrentListNode);
+ CurrentListNode = NextListNode;
+ }
+
+ StringDepository++;
+ }
+ //
+ // Release string depository.
+ //
+ SafeFreePool (FileOptionStrDepository);
+}
+
+EFI_STATUS
+BdsStartBootMaint (
+ VOID
+ )
+/*++
+
+Routine Description:
+ Start boot maintenance manager
+
+Arguments:
+
+Returns:
+
+--*/
+{
+ EFI_STATUS Status;
+ LIST_ENTRY BdsBootOptionList;
+
+ InitializeListHead (&BdsBootOptionList);
+
+ //
+ // Connect all prior to entering the platform setup menu.
+ //
+ if (!gConnectAllHappened) {
+ BdsLibConnectAllDriversToAllControllers ();
+ gConnectAllHappened = TRUE;
+ }
+ //
+ // Have chance to enumerate boot device
+ //
+ BdsLibEnumerateAllBootOption (&BdsBootOptionList);
+
+ //
+ // Drop the TPL level from TPL_APPLICATION to TPL_APPLICATION
+ //
+ gBS->RestoreTPL (TPL_APPLICATION);
+
+ //
+ // Init the BMM
+ //
+ Status = InitializeBM ();
+
+ //
+ // Raise the TPL level back to TPL_APPLICATION
+ //
+ gBS->RaiseTPL (TPL_APPLICATION);
+
+ return Status;
+}
+
+EFI_STATUS
+FormSetDispatcher (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+/*++
+
+Routine Description:
+ Dispatch BMM formset and FileExplorer formset.
+
+Arguments:
+
+Returns:
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_BROWSER_ACTION_REQUEST ActionRequest;
+
+ while (TRUE) {
+ UpdatePageId (CallbackData, FORM_MAIN_ID);
+
+ ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
+ Status = gFormBrowser2->SendForm (
+ gFormBrowser2,
+ &CallbackData->BmmHiiHandle,
+ 1,
+ NULL,
+ 0,
+ NULL,
+ &ActionRequest
+ );
+ if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
+ EnableResetRequired ();
+ }
+
+ ReclaimStringDepository ();
+
+ //
+ // When this Formset returns, check if we are going to explore files.
+ //
+ if (INACTIVE_STATE != CallbackData->FeCurrentState) {
+ UpdateFileExplorer (CallbackData, 0);
+
+ ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
+ Status = gFormBrowser2->SendForm (
+ gFormBrowser2,
+ &CallbackData->FeHiiHandle,
+ 1,
+ NULL,
+ 0,
+ NULL,
+ &ActionRequest
+ );
+ if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
+ EnableResetRequired ();
+ }
+
+ CallbackData->FeCurrentState = INACTIVE_STATE;
+ CallbackData->FeDisplayContext = UNKNOWN_CONTEXT;
+ ReclaimStringDepository ();
+ } else {
+ break;
+ }
+ }
+
+ return Status;
+}
+
diff --git a/MdeModulePkg/Universal/BdsDxe/BootMaint/BootMaint.h b/MdeModulePkg/Universal/BdsDxe/BootMaint/BootMaint.h new file mode 100644 index 0000000000..0de7b05dae --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/BootMaint/BootMaint.h @@ -0,0 +1,1087 @@ +/*++
+
+Copyright (c) 2004 - 2008, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ BootMaint.h
+
+Abstract:
+
+Revision History
+
+--*/
+
+#ifndef _BOOT_MAINT_H
+#define _BOOT_MAINT_H
+
+#include "Bds.h"
+#include "BBSsupport.h"
+#include "FormGuid.h"
+#include "FrontPage.h"
+
+//
+// Constants which are variable names used to access variables
+//
+#define VarLegacyDevOrder L"LegacyDevOrder"
+
+#define VarConOutMode L"ConOutMode"
+
+//
+// Guid of a NV Variable which store the information about the
+// FD/HD/CD/NET/BEV order
+//
+#define EFI_LEGACY_DEV_ORDER_VARIABLE_GUID \
+ { \
+ 0xa56074db, 0x65fe, 0x45f7, {0xbd, 0x21, 0x2d, 0x2b, 0xdd, 0x8e, 0x96, 0x52} \
+ }
+
+//
+// String Contant
+//
+#define StrFloppy L"Floppy Drive #%02x"
+#define StrHardDisk L"HardDisk Drive #%02x"
+#define StrCDROM L"ATAPI CDROM Drive #%02x"
+#define StrNET L"NET Drive #%02x"
+#define StrBEV L"BEV Drive #%02x"
+#define StrFloppyHelp L"Select Floppy Drive #%02x"
+#define StrHardDiskHelp L"Select HardDisk Drive #%02x"
+#define StrCDROMHelp L"Select ATAPI CDROM Drive #%02x"
+#define StrNETHelp L"NET Drive #%02x"
+#define StrBEVHelp L"BEV Drive #%02x"
+
+//
+// Variable created with this flag will be "Efi:...."
+//
+#define VAR_FLAG EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE
+
+//
+// Define Maxmim characters that will be accepted
+//
+#define MAX_CHAR 480
+#define MAX_CHAR_SIZE (MAX_CHAR * 2)
+
+//
+// Check to see if current build support option active feature of
+// some driver option
+//
+#ifndef LOAD_OPTION_ACTIVE
+#define LOAD_OPTION_ACTIVE 0x00000001
+#endif
+
+//
+// Check to see if current build support force reconnect feature of
+// some driver option
+//
+#ifndef LOAD_OPTION_FORCE_RECONNECT
+#define LOAD_OPTION_FORCE_RECONNECT 0x00000002
+#endif
+
+extern EFI_GUID mBootMaintGuid;
+extern EFI_GUID mFileExplorerGuid;
+
+//
+// These are the VFR compiler generated data representing our VFR data.
+//
+extern UINT8 BmBin[];
+extern UINT8 FEBin[];
+
+//
+// Below are the number of options in Baudrate, Databits,
+// Parity and Stopbits selection for serial ports.
+//
+#define BM_COM_ATTR_BUADRATE 19
+#define BM_COM_ATTR_DATABITS 4
+#define BM_COM_ATTR_PARITY 5
+#define BM_COM_ATTR_STOPBITS 3
+
+//
+// Callback function helper
+//
+#define BMM_CALLBACK_DATA_SIGNATURE EFI_SIGNATURE_32 ('C', 'b', 'c', 'k')
+#define BMM_CALLBACK_DATA_FROM_THIS(a) CR (a, BMM_CALLBACK_DATA, BmmConfigAccess, BMM_CALLBACK_DATA_SIGNATURE)
+
+#define FE_CALLBACK_DATA_FROM_THIS(a) CR (a, BMM_CALLBACK_DATA, FeConfigAccess, BMM_CALLBACK_DATA_SIGNATURE)
+
+//
+// Enumeration type definition
+//
+typedef UINT8 BBS_TYPE;
+
+typedef enum {
+ PC_ANSI = 0,
+ VT_100,
+ VT_100_PLUS,
+ VT_UTF8
+} TYPE_OF_TERMINAL;
+
+typedef enum {
+ COM1 = 0,
+ COM2,
+ UNKNOW_COM
+} TYPE_OF_COM;
+
+typedef enum {
+ CONIN = 0,
+ CONOUT,
+ CONERR,
+ UNKNOWN_CON
+} TYPE_OF_CON;
+
+typedef enum {
+ BAUDRATE = 0,
+ DATABITS,
+ PARITY,
+ STOPBITS,
+ UNKNOW_ATTR
+} TYPE_OF_ATTRIBUTE;
+
+typedef enum {
+ MANNER_GOTO = 0,
+ MANNER_CHECK,
+ MANNER_ONEOF,
+ MANNER_USER_DEFINE
+} TYPE_OF_UPATE_MANNER;
+
+typedef enum {
+ INACTIVE_STATE = 0,
+ BOOT_FROM_FILE_STATE,
+ ADD_BOOT_OPTION_STATE,
+ ADD_DRIVER_OPTION_STATE,
+ UNKNOWN_STATE
+} FILE_EXPLORER_STATE;
+
+typedef enum {
+ FILE_SYSTEM,
+ DIRECTORY,
+ UNKNOWN_CONTEXT
+} FILE_EXPLORER_DISPLAY_CONTEXT;
+
+//
+// All of the signatures that will be used in list structure
+//
+#define BM_MENU_OPTION_SIGNATURE 'menu'
+#define BM_LOAD_OPTION_SIGNATURE 'load'
+#define BM_CONSOLE_OPTION_SIGNATURE 'cnsl'
+#define BM_FILE_OPTION_SIGNATURE 'file'
+#define BM_HANDLE_OPTION_SIGNATURE 'hndl'
+#define BM_TERMINAL_OPTION_SIGNATURE 'trml'
+#define BM_MENU_ENTRY_SIGNATURE 'entr'
+
+#define BM_LOAD_CONTEXT_SELECT 0x0
+#define BM_CONSOLE_CONTEXT_SELECT 0x1
+#define BM_FILE_CONTEXT_SELECT 0x2
+#define BM_HANDLE_CONTEXT_SELECT 0x3
+#define BM_TERMINAL_CONTEXT_SELECT 0x5
+
+#define BM_CONSOLE_IN_CONTEXT_SELECT 0x6
+#define BM_CONSOLE_OUT_CONTEXT_SELECT 0x7
+#define BM_CONSOLE_ERR_CONTEXT_SELECT 0x8
+#define BM_LEGACY_DEV_CONTEXT_SELECT 0x9
+
+//
+// Buffer size for update data
+//
+#define UPDATE_DATA_SIZE 0x100000
+
+//
+// Namespace of callback keys used in display and file system navigation
+//
+#define MAX_BBS_OFFSET 0xE000
+#define NET_OPTION_OFFSET 0xD800
+#define BEV_OPTION_OFFSET 0xD000
+#define FD_OPTION_OFFSET 0xC000
+#define HD_OPTION_OFFSET 0xB000
+#define CD_OPTION_OFFSET 0xA000
+#define FILE_OPTION_OFFSET 0x8000
+#define FILE_OPTION_MASK 0x7FFF
+#define HANDLE_OPTION_OFFSET 0x7000
+#define CONSOLE_OPTION_OFFSET 0x6000
+#define TERMINAL_OPTION_OFFSET 0x5000
+#define CONFIG_OPTION_OFFSET 0x1200
+#define KEY_VALUE_OFFSET 0x1100
+#define FORM_ID_OFFSET 0x1000
+
+//
+// VarOffset that will be used to create question
+// all these values are computed from the structure
+// defined below
+//
+#define VAR_OFFSET(Field) ((UINT16) ((UINTN) &(((BMM_FAKE_NV_DATA *) 0)->Field)))
+
+//
+// Question Id of Zero is invalid, so add an offset to it
+//
+#define QUESTION_ID(Field) (VAR_OFFSET (Field) + CONFIG_OPTION_OFFSET)
+
+#define BOOT_TIME_OUT_VAR_OFFSET VAR_OFFSET (BootTimeOut)
+#define BOOT_NEXT_VAR_OFFSET VAR_OFFSET (BootNext)
+#define COM1_BAUD_RATE_VAR_OFFSET VAR_OFFSET (COM1BaudRate)
+#define COM1_DATA_RATE_VAR_OFFSET VAR_OFFSET (COM1DataRate)
+#define COM1_STOP_BITS_VAR_OFFSET VAR_OFFSET (COM1StopBits)
+#define COM1_PARITY_VAR_OFFSET VAR_OFFSET (COM1Parity)
+#define COM1_TERMINAL_VAR_OFFSET VAR_OFFSET (COM2TerminalType)
+#define COM2_BAUD_RATE_VAR_OFFSET VAR_OFFSET (COM2BaudRate)
+#define COM2_DATA_RATE_VAR_OFFSET VAR_OFFSET (COM2DataRate)
+#define COM2_STOP_BITS_VAR_OFFSET VAR_OFFSET (COM2StopBits)
+#define COM2_PARITY_VAR_OFFSET VAR_OFFSET (COM2Parity)
+#define COM2_TERMINAL_VAR_OFFSET VAR_OFFSET (COM2TerminalType)
+#define DRV_ADD_HANDLE_DESC_VAR_OFFSET VAR_OFFSET (DriverAddHandleDesc)
+#define DRV_ADD_ACTIVE_VAR_OFFSET VAR_OFFSET (DriverAddActive)
+#define DRV_ADD_RECON_VAR_OFFSET VAR_OFFSET (DriverAddForceReconnect)
+#define CON_IN_COM1_VAR_OFFSET VAR_OFFSET (ConsoleInputCOM1)
+#define CON_IN_COM2_VAR_OFFSET VAR_OFFSET (ConsoleInputCOM2)
+#define CON_OUT_COM1_VAR_OFFSET VAR_OFFSET (ConsoleOutputCOM1)
+#define CON_OUT_COM2_VAR_OFFSET VAR_OFFSET (ConsoleOutputCOM2)
+#define CON_ERR_COM1_VAR_OFFSET VAR_OFFSET (ConsoleErrorCOM1)
+#define CON_ERR_COM2_VAR_OFFSET VAR_OFFSET (ConsoleErrorCOM2)
+#define CON_MODE_VAR_OFFSET VAR_OFFSET (ConsoleOutMode)
+#define CON_DEVICE_VAR_OFFSET VAR_OFFSET (ConsoleCheck)
+#define OPTION_ORDER_VAR_OFFSET VAR_OFFSET (OptionOrder)
+#define DRIVER_OPTION_ORDER_VAR_OFFSET VAR_OFFSET (DriverOptionToBeDeleted)
+#define BOOT_OPTION_DEL_VAR_OFFSET VAR_OFFSET (BootOptionDel)
+#define DRIVER_OPTION_DEL_VAR_OFFSET VAR_OFFSET (DriverOptionDel)
+#define DRIVER_ADD_OPTION_VAR_OFFSET VAR_OFFSET (DriverAddHandleOptionalData)
+#define COM_BAUD_RATE_VAR_OFFSET VAR_OFFSET (COMBaudRate)
+#define COM_DATA_RATE_VAR_OFFSET VAR_OFFSET (COMDataRate)
+#define COM_STOP_BITS_VAR_OFFSET VAR_OFFSET (COMStopBits)
+#define COM_PARITY_VAR_OFFSET VAR_OFFSET (COMParity)
+#define COM_TERMINAL_VAR_OFFSET VAR_OFFSET (COMTerminalType)
+#define LEGACY_FD_VAR_OFFSET VAR_OFFSET (LegacyFD)
+#define LEGACY_HD_VAR_OFFSET VAR_OFFSET (LegacyHD)
+#define LEGACY_CD_VAR_OFFSET VAR_OFFSET (LegacyCD)
+#define LEGACY_NET_VAR_OFFSET VAR_OFFSET (LegacyNET)
+#define LEGACY_BEV_VAR_OFFSET VAR_OFFSET (LegacyBEV)
+
+#define BOOT_TIME_OUT_QUESTION_ID QUESTION_ID (BootTimeOut)
+#define BOOT_NEXT_QUESTION_ID QUESTION_ID (BootNext)
+#define COM1_BAUD_RATE_QUESTION_ID QUESTION_ID (COM1BaudRate)
+#define COM1_DATA_RATE_QUESTION_ID QUESTION_ID (COM1DataRate)
+#define COM1_STOP_BITS_QUESTION_ID QUESTION_ID (COM1StopBits)
+#define COM1_PARITY_QUESTION_ID QUESTION_ID (COM1Parity)
+#define COM1_TERMINAL_QUESTION_ID QUESTION_ID (COM2TerminalType)
+#define COM2_BAUD_RATE_QUESTION_ID QUESTION_ID (COM2BaudRate)
+#define COM2_DATA_RATE_QUESTION_ID QUESTION_ID (COM2DataRate)
+#define COM2_STOP_BITS_QUESTION_ID QUESTION_ID (COM2StopBits)
+#define COM2_PARITY_QUESTION_ID QUESTION_ID (COM2Parity)
+#define COM2_TERMINAL_QUESTION_ID QUESTION_ID (COM2TerminalType)
+#define DRV_ADD_HANDLE_DESC_QUESTION_ID QUESTION_ID (DriverAddHandleDesc)
+#define DRV_ADD_ACTIVE_QUESTION_ID QUESTION_ID (DriverAddActive)
+#define DRV_ADD_RECON_QUESTION_ID QUESTION_ID (DriverAddForceReconnect)
+#define CON_IN_COM1_QUESTION_ID QUESTION_ID (ConsoleInputCOM1)
+#define CON_IN_COM2_QUESTION_ID QUESTION_ID (ConsoleInputCOM2)
+#define CON_OUT_COM1_QUESTION_ID QUESTION_ID (ConsoleOutputCOM1)
+#define CON_OUT_COM2_QUESTION_ID QUESTION_ID (ConsoleOutputCOM2)
+#define CON_ERR_COM1_QUESTION_ID QUESTION_ID (ConsoleErrorCOM1)
+#define CON_ERR_COM2_QUESTION_ID QUESTION_ID (ConsoleErrorCOM2)
+#define CON_MODE_QUESTION_ID QUESTION_ID (ConsoleOutMode)
+#define CON_DEVICE_QUESTION_ID QUESTION_ID (ConsoleCheck)
+#define OPTION_ORDER_QUESTION_ID QUESTION_ID (OptionOrder)
+#define DRIVER_OPTION_ORDER_QUESTION_ID QUESTION_ID (DriverOptionToBeDeleted)
+#define BOOT_OPTION_DEL_QUESTION_ID QUESTION_ID (BootOptionDel)
+#define DRIVER_OPTION_DEL_QUESTION_ID QUESTION_ID (DriverOptionDel)
+#define DRIVER_ADD_OPTION_QUESTION_ID QUESTION_ID (DriverAddHandleOptionalData)
+#define COM_BAUD_RATE_QUESTION_ID QUESTION_ID (COMBaudRate)
+#define COM_DATA_RATE_QUESTION_ID QUESTION_ID (COMDataRate)
+#define COM_STOP_BITS_QUESTION_ID QUESTION_ID (COMStopBits)
+#define COM_PARITY_QUESTION_ID QUESTION_ID (COMParity)
+#define COM_TERMINAL_QUESTION_ID QUESTION_ID (COMTerminalType)
+#define LEGACY_FD_QUESTION_ID QUESTION_ID (LegacyFD)
+#define LEGACY_HD_QUESTION_ID QUESTION_ID (LegacyHD)
+#define LEGACY_CD_QUESTION_ID QUESTION_ID (LegacyCD)
+#define LEGACY_NET_QUESTION_ID QUESTION_ID (LegacyNET)
+#define LEGACY_BEV_QUESTION_ID QUESTION_ID (LegacyBEV)
+
+#define STRING_DEPOSITORY_NUMBER 8
+
+//
+// #pragma pack(1)
+//
+// Serial Ports attributes, first one is the value for
+// return from callback function, stringtoken is used to
+// display the value properly
+//
+typedef struct {
+ UINTN Value;
+ UINT16 StringToken;
+} COM_ATTR;
+
+typedef struct {
+ BBS_TYPE BbsType;
+ //
+ // Length = sizeof (UINT16) + SIZEOF (Data)
+ //
+ UINT16 Length;
+ UINT16 *Data;
+} BM_LEGACY_DEV_ORDER_CONTEXT;
+
+typedef struct {
+ UINT64 BaudRate;
+ UINT8 DataBits;
+ UINT8 Parity;
+ UINT8 StopBits;
+
+ UINT8 BaudRateIndex;
+ UINT8 DataBitsIndex;
+ UINT8 ParityIndex;
+ UINT8 StopBitsIndex;
+
+ UINT8 IsConIn;
+ UINT8 IsConOut;
+ UINT8 IsStdErr;
+ UINT8 TerminalType;
+
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+} BM_TERMINAL_CONTEXT;
+
+typedef struct {
+ BOOLEAN IsBootNext;
+ BOOLEAN LoadOptionModified;
+ BOOLEAN Deleted;
+
+ BOOLEAN IsLegacy;
+ BOOLEAN IsActive;
+ BOOLEAN ForceReconnect;
+ UINTN OptionalDataSize;
+
+ UINTN LoadOptionSize;
+ UINT8 *LoadOption;
+
+ UINT32 Attributes;
+ UINT16 FilePathListLength;
+ UINT16 *Description;
+ EFI_DEVICE_PATH_PROTOCOL *FilePathList;
+ UINT8 *OptionalData;
+
+ UINT16 BbsIndex;
+} BM_LOAD_CONTEXT;
+
+typedef struct {
+ BBS_TABLE *BbsTable;
+ UINTN Index;
+ UINTN BbsCount;
+ UINT16 *Description;
+} BM_LEGACY_DEVICE_CONTEXT;
+
+typedef struct {
+
+ BOOLEAN IsActive;
+
+ BOOLEAN IsTerminal;
+
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+} BM_CONSOLE_CONTEXT;
+
+typedef struct {
+ UINTN Column;
+ UINTN Row;
+} CONSOLE_OUT_MODE;
+
+typedef struct {
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_FILE_HANDLE FHandle;
+ UINT16 *FileName;
+ EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *Info;
+
+ BOOLEAN IsRoot;
+ BOOLEAN IsDir;
+ BOOLEAN IsRemovableMedia;
+ BOOLEAN IsLoadFile;
+ BOOLEAN IsBootLegacy;
+} BM_FILE_CONTEXT;
+
+typedef struct {
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+} BM_HANDLE_CONTEXT;
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Head;
+ UINTN MenuNumber;
+} BM_MENU_OPTION;
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ UINTN OptionNumber;
+ UINT16 *DisplayString;
+ UINT16 *HelpString;
+ EFI_STRING_ID DisplayStringToken;
+ EFI_STRING_ID HelpStringToken;
+ UINTN ContextSelection;
+ VOID *VariableContext;
+} BM_MENU_ENTRY;
+
+typedef struct {
+ //
+ // Shared callback data.
+ //
+ UINTN Signature;
+
+ BM_MENU_ENTRY *MenuEntry;
+ BM_HANDLE_CONTEXT *HandleContext;
+ BM_FILE_CONTEXT *FileContext;
+ BM_LOAD_CONTEXT *LoadContext;
+ BM_TERMINAL_CONTEXT *TerminalContext;
+ UINTN CurrentTerminal;
+ UINT8 BbsType;
+
+ //
+ // BMM main formset callback data.
+ //
+ EFI_HII_HANDLE BmmHiiHandle;
+ EFI_HANDLE BmmDriverHandle;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL BmmConfigAccess;
+ EFI_FORM_ID BmmCurrentPageId;
+ EFI_FORM_ID BmmPreviousPageId;
+ BOOLEAN BmmAskSaveOrNot;
+ BMM_FAKE_NV_DATA BmmFakeNvData;
+ BMM_FAKE_NV_DATA BmmOldFakeNVData;
+
+ //
+ // File explorer formset callback data.
+ //
+ EFI_HII_HANDLE FeHiiHandle;
+ EFI_HANDLE FeDriverHandle;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL FeConfigAccess;
+ FILE_EXPLORER_STATE FeCurrentState;
+ FILE_EXPLORER_DISPLAY_CONTEXT FeDisplayContext;
+ FILE_EXPLORER_NV_DATA FeFakeNvData;
+} BMM_CALLBACK_DATA;
+
+typedef struct _STRING_LIST_NODE {
+ EFI_STRING_ID StringToken;
+ struct _STRING_LIST_NODE *Next;
+} STRING_LIST_NODE;
+
+typedef struct _STRING_DEPOSITORY {
+ UINTN TotalNodeNumber;
+ STRING_LIST_NODE *CurrentNode;
+ STRING_LIST_NODE *ListHead;
+} STRING_DEPOSITORY;
+
+//
+// #pragma pack()
+//
+// For initializing File System menu
+//
+EFI_STATUS
+BOpt_FindFileSystem (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+;
+
+//
+// For cleaning up File System menu
+//
+VOID
+BOpt_FreeFileSystem (
+ VOID
+ )
+;
+
+//
+// For initializing File Navigation menu
+//
+EFI_STATUS
+BOpt_FindFiles (
+ IN BMM_CALLBACK_DATA *CallbackData,
+ IN BM_MENU_ENTRY *MenuEntry
+ )
+;
+
+//
+// For cleaning up File Navigation menu
+//
+VOID
+BOpt_FreeFiles (
+ VOID
+ )
+;
+
+//
+// For Initializing handle navigation menu
+//
+EFI_STATUS
+BOpt_FindDrivers (
+ VOID
+ )
+;
+
+//
+// For Cleaning up handle navigation menu
+//
+VOID
+BOpt_FreeDrivers(VOID);
+
+//
+// For initializing Boot Option menu
+//
+EFI_STATUS
+BOpt_GetBootOptions (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+//
+// For Initializing Driver option menu
+//
+EFI_STATUS
+BOpt_GetDriverOptions (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+//
+// For Cleaning up boot option menu
+//
+VOID
+BOpt_FreeBootOptions (VOID);
+
+//
+// For cleaning up driver option menu
+//
+VOID
+BOpt_FreeDriverOptions(VOID);
+
+//
+// For Initializing HD/FD/CD/NET/BEV option menu
+//
+EFI_STATUS
+BOpt_GetLegacyOptions(VOID);
+
+//
+// For cleaning up driver option menu
+//
+VOID
+BOpt_FreeLegacyOptions(VOID);
+
+//
+// this function is used to take place of all other free menu actions
+//
+VOID
+BOpt_FreeMenu (
+ BM_MENU_OPTION *FreeMenu
+ );
+
+
+//
+// Following are the helper functions used
+//
+CHAR16 *
+BOpt_AppendFileName (
+ IN CHAR16 *Str1,
+ IN CHAR16 *Str2
+ );
+
+BOOLEAN
+BOpt_IsEfiImageName (
+ IN UINT16 *FileName
+ );
+
+BOOLEAN
+BOpt_IsEfiApp (
+ IN EFI_FILE_HANDLE Dir,
+ IN UINT16 *FileName
+ );
+
+//
+// Get current unused boot option number
+//
+UINT16
+BOpt_GetBootOptionNumber (VOID);
+
+//
+// Get current unused driver option number
+//
+UINT16
+BOpt_GetDriverOptionNumber (VOID);
+
+BM_MENU_ENTRY *
+BOpt_CreateMenuEntry (
+ UINTN MenuType
+ );
+
+VOID
+BOpt_DestroyMenuEntry (
+ BM_MENU_ENTRY *MenuEntry
+ );
+
+BM_MENU_ENTRY *
+BOpt_GetMenuEntry (
+ BM_MENU_OPTION *MenuOption,
+ UINTN MenuNumber
+ );
+
+//
+// a helper function used to free pool type memory
+//
+VOID
+SafeFreePool (
+ IN VOID *Buffer
+ );
+
+//
+// Locate all serial io devices for console
+//
+EFI_STATUS
+LocateSerialIo (VOID);
+
+//
+// Initializing Console menu
+//
+EFI_STATUS
+GetAllConsoles(VOID);
+
+//
+// Get current mode information
+//
+VOID
+GetConsoleOutMode (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+//
+// Cleaning up console menu
+//
+EFI_STATUS
+FreeAllConsoles(VOID);
+
+VOID
+ChangeVariableDevicePath (
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath
+);
+
+EFI_STATUS
+ChangeTerminalDevicePath (
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ BOOLEAN ChangeTerminal
+);
+//
+// Variable operation by menu selection
+//
+EFI_STATUS
+Var_UpdateBootOption (
+ IN BMM_CALLBACK_DATA *CallbackData,
+ IN FILE_EXPLORER_NV_DATA *NvRamMap
+ );
+
+EFI_STATUS
+Var_DelBootOption (VOID);
+
+EFI_STATUS
+Var_ChangeBootOrder (VOID);
+
+EFI_STATUS
+Var_UpdateDriverOption (
+ IN BMM_CALLBACK_DATA *CallbackData,
+ IN EFI_HII_HANDLE HiiHandle,
+ IN UINT16 *DescriptionData,
+ IN UINT16 *OptionalData,
+ IN UINT8 ForceReconnect
+ );
+
+EFI_STATUS
+Var_DelDriverOption (VOID);
+
+EFI_STATUS
+Var_ChangeDriverOrder (VOID);
+
+EFI_STATUS
+Var_UpdateConsoleInpOption (VOID);
+
+EFI_STATUS
+Var_UpdateConsoleOutOption (VOID);
+
+EFI_STATUS
+Var_UpdateErrorOutOption (VOID);
+
+VOID
+Var_UpdateAllConsoleOption (VOID);
+
+EFI_STATUS
+Var_UpdateBootNext (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+EFI_STATUS
+Var_UpdateBootOrder (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+EFI_STATUS
+Var_UpdateDriverOrder (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+EFI_STATUS
+Var_UpdateBBSOption (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+EFI_STATUS
+Var_UpdateConMode (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+//
+// Following are page create and refresh functions
+//
+VOID
+RefreshUpdateData (
+ VOID
+ );
+
+VOID
+CleanUpPage (
+ IN UINT16 LabelId,
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+EFI_STATUS
+UpdatePage (
+ IN BMM_CALLBACK_DATA *CallbackData,
+ IN BM_MENU_OPTION *UpdatingMenu,
+ IN UINT16 UpdatingPage,
+ IN UINT16 UpdatingManner,
+ IN UINT16 QuestionIdStart,
+ IN UINT16 GotoForm,
+ IN UINT16 GotoAlternateForm,
+ IN EFI_STRING_ID DisplayTokenStart,
+ IN EFI_STRING_ID HelpTokenStart,
+ IN UINT16 KeyValueStart
+ );
+
+VOID
+UpdateBootAddPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+VOID
+UpdateBootDelPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+VOID
+UpdateDrvAddFilePage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+VOID
+UpdateDrvAddHandlePage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+VOID
+UpdateDrvDelPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+VOID
+UpdateDriverAddHandleDescPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+VOID
+UpdateBootTimeOut (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+VOID
+UpdateConInPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+VOID
+UpdateConOutPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+VOID
+UpdateStdErrPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+VOID
+UpdatePageBody (
+ IN UINT16 UpdatePageId,
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+VOID
+UpdateCOM1Page (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+VOID
+UpdateCOM2Page (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+VOID
+UpdateBootOrderPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+VOID
+UpdateDriverOrderPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+VOID
+UpdateBootNextPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+VOID
+UpdateTimeOutPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+VOID
+UpdateTerminalPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+VOID
+UpdateConModePage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+VOID
+UpdateConCOMPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+VOID
+UpdateSetLegacyDeviceOrderPage (
+ IN UINT16 UpdatePageId,
+ IN BMM_CALLBACK_DATA *CallbackData
+);
+
+EFI_STATUS
+BootLegacy (
+ IN UINT16 BbsType,
+ IN UINT16 BbsFlag
+);
+
+BM_MENU_ENTRY *
+GetCurrentTerminal (
+ UINTN TerminalNumber
+);
+
+EFI_FILE_HANDLE
+EfiLibOpenRoot (
+ IN EFI_HANDLE DeviceHandle
+ );
+
+EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *
+EfiLibFileSystemVolumeLabelInfo (
+ IN EFI_FILE_HANDLE FHand
+ );
+
+EFI_FILE_INFO *
+EfiLibFileInfo (
+ IN EFI_FILE_HANDLE FHand
+ );
+
+UINTN
+UnicodeToAscii (
+ IN CHAR16 *UStr,
+ IN UINTN Length,
+ OUT CHAR8 *AStr
+ );
+
+CHAR16 *
+DevicePathToStr (
+ EFI_DEVICE_PATH_PROTOCOL *DevPath
+ );
+
+VOID *
+EfiAllocateZeroPool (
+ IN UINTN Size
+ );
+
+EFI_STATUS
+EfiLibLocateProtocol (
+ IN EFI_GUID *ProtocolGuid,
+ OUT VOID **Interface
+ );
+
+VOID *
+EfiReallocatePool (
+ IN VOID *OldPool,
+ IN UINTN OldSize,
+ IN UINTN NewSize
+ );
+
+CHAR16 *
+DevicePathToStr (
+ EFI_DEVICE_PATH_PROTOCOL *DevPath
+ );
+
+VOID *
+BdsLibGetVariableAndSize (
+ IN CHAR16 *Name,
+ IN EFI_GUID *VendorGuid,
+ OUT UINTN *VarSize
+ );
+
+EFI_STATUS
+EfiLibDeleteVariable (
+ IN CHAR16 *VarName,
+ IN EFI_GUID *VarGuid
+ );
+
+CHAR16 *
+EfiStrDuplicate (
+ IN CHAR16 *Src
+ );
+
+BOOLEAN
+EfiLibMatchDevicePaths (
+ IN EFI_DEVICE_PATH_PROTOCOL *Multi,
+ IN EFI_DEVICE_PATH_PROTOCOL *Single
+ );
+
+UINTN
+EfiDevicePathInstanceCount (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+EFI_STATUS
+CreateMenuStringToken (
+ IN BMM_CALLBACK_DATA *CallbackData,
+ IN EFI_HII_HANDLE HiiHandle,
+ IN BM_MENU_OPTION *MenuOption
+ );
+
+UINT16 *
+EfiLibStrFromDatahub (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevPath
+ );
+
+VOID *
+GetLegacyBootOptionVar (
+ IN UINTN DeviceType,
+ OUT UINTN *OptionIndex,
+ OUT UINTN *OptionSize
+ );
+
+EFI_STATUS
+InitializeBM (
+ VOID
+ );
+
+EFI_STATUS
+BdsStartBootMaint (
+ VOID
+ );
+
+VOID
+InitializeStringDepository (VOID);
+
+EFI_STRING_ID
+GetStringTokenFromDepository (
+ IN BMM_CALLBACK_DATA *CallbackData,
+ IN STRING_DEPOSITORY *StringDepository
+ );
+
+VOID
+ReclaimStringDepository (
+ VOID
+ );
+
+VOID
+CleanUpStringDepository (
+ VOID
+ );
+
+EFI_STATUS
+ApplyChangeHandler (
+ IN BMM_CALLBACK_DATA *Private,
+ IN BMM_FAKE_NV_DATA *CurrentFakeNVMap,
+ IN EFI_FORM_ID FormId
+ );
+
+VOID
+DiscardChangeHandler (
+ IN BMM_CALLBACK_DATA *Private,
+ IN BMM_FAKE_NV_DATA *CurrentFakeNVMap
+ );
+
+VOID
+UpdatePageId (
+ BMM_CALLBACK_DATA *Private,
+ UINT16 NewPageId
+ );
+
+EFI_STATUS
+BootThisFile (
+ IN BM_FILE_CONTEXT *FileContext
+ );
+
+BOOLEAN
+UpdateFileExplorer (
+ IN BMM_CALLBACK_DATA *CallbackData,
+ IN UINT16 KeyValue
+ );
+
+EFI_STATUS
+EFIAPI
+FileExplorerCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ );
+
+EFI_STATUS
+FormSetDispatcher (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+//
+// Global variable in this program (defined in data.c)
+//
+extern BM_MENU_OPTION BootOptionMenu;
+extern BM_MENU_OPTION DriverOptionMenu;
+extern BM_MENU_OPTION FsOptionMenu;
+extern BM_MENU_OPTION ConsoleInpMenu;
+extern BM_MENU_OPTION ConsoleOutMenu;
+extern BM_MENU_OPTION ConsoleErrMenu;
+extern BM_MENU_OPTION DirectoryMenu;
+extern BM_MENU_OPTION DriverMenu;
+extern BM_MENU_OPTION TerminalMenu;
+extern BM_MENU_OPTION LegacyFDMenu;
+extern BM_MENU_OPTION LegacyHDMenu;
+extern BM_MENU_OPTION LegacyCDMenu;
+extern BM_MENU_OPTION LegacyNETMenu;
+extern BM_MENU_OPTION LegacyBEVMenu;
+extern UINT16 TerminalType[];
+extern COM_ATTR BaudRateList[19];
+extern COM_ATTR DataBitsList[4];
+extern COM_ATTR ParityList[5];
+extern COM_ATTR StopBitsList[3];
+extern EFI_GUID Guid[4];
+extern EFI_HII_UPDATE_DATA gUpdateData;
+extern STRING_DEPOSITORY *FileOptionStrDepository;
+extern STRING_DEPOSITORY *ConsoleOptionStrDepository;
+extern STRING_DEPOSITORY *BootOptionStrDepository;
+extern STRING_DEPOSITORY *BootOptionHelpStrDepository;
+extern STRING_DEPOSITORY *DriverOptionStrDepository;
+extern STRING_DEPOSITORY *DriverOptionHelpStrDepository;
+extern STRING_DEPOSITORY *TerminalStrDepository;
+extern EFI_DEVICE_PATH_PROTOCOL EndDevicePath[];
+extern EFI_GUID EfiLegacyDevOrderGuid;
+
+#endif
diff --git a/MdeModulePkg/Universal/BdsDxe/BootMaint/BootOption.c b/MdeModulePkg/Universal/BdsDxe/BootMaint/BootOption.c new file mode 100644 index 0000000000..9a2273cfc4 --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/BootMaint/BootOption.c @@ -0,0 +1,1697 @@ +/*++
+Copyright (c) 2004 - 2008, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ bootoption.c
+
+Abstract:
+
+ Provide boot option support for Application "BootMaint"
+
+ Include file system navigation, system handle selection
+
+ Boot option manipulation
+
+Revision History
+
+--*/
+
+#include "BootMaint.h"
+#include "BBSsupport.h"
+
+BM_MENU_ENTRY *
+BOpt_CreateMenuEntry (
+ UINTN MenuType
+ )
+/*++
+
+Routine Description
+ Create Menu Entry for future use, make all types together
+ in order to reduce code size
+
+Arguments:
+ MenuType Use this parameter to identify current
+ Menu type
+
+Returns:
+ NULL Cannot allocate memory for current menu
+ entry
+ Others A valid pointer pointing to the allocated
+ memory pool for current menu entry
+
+--*/
+{
+ BM_MENU_ENTRY *MenuEntry;
+ UINTN ContextSize;
+
+ switch (MenuType) {
+ case BM_LOAD_CONTEXT_SELECT:
+ ContextSize = sizeof (BM_LOAD_CONTEXT);
+ break;
+
+ case BM_FILE_CONTEXT_SELECT:
+ ContextSize = sizeof (BM_FILE_CONTEXT);
+ break;
+
+ case BM_CONSOLE_CONTEXT_SELECT:
+ ContextSize = sizeof (BM_CONSOLE_CONTEXT);
+ break;
+
+ case BM_TERMINAL_CONTEXT_SELECT:
+ ContextSize = sizeof (BM_TERMINAL_CONTEXT);
+ break;
+
+ case BM_HANDLE_CONTEXT_SELECT:
+ ContextSize = sizeof (BM_HANDLE_CONTEXT);
+ break;
+
+ case BM_LEGACY_DEV_CONTEXT_SELECT:
+ ContextSize = sizeof (BM_LEGACY_DEVICE_CONTEXT);
+ break;
+
+ default:
+ ContextSize = 0;
+ break;
+
+ }
+
+ if (0 == ContextSize) {
+ return NULL;
+ }
+
+ MenuEntry = EfiAllocateZeroPool (sizeof (BM_MENU_ENTRY));
+ if (NULL == MenuEntry) {
+ return MenuEntry;
+ }
+
+ MenuEntry->VariableContext = EfiAllocateZeroPool (ContextSize);
+ if (NULL == MenuEntry->VariableContext) {
+ SafeFreePool (MenuEntry);
+ MenuEntry = NULL;
+ return MenuEntry;
+ }
+
+ MenuEntry->Signature = BM_MENU_ENTRY_SIGNATURE;
+ MenuEntry->ContextSelection = MenuType;
+ return MenuEntry;
+}
+
+VOID
+BOpt_DestroyMenuEntry (
+ BM_MENU_ENTRY *MenuEntry
+ )
+/*++
+ Routine Description :
+ Destroy the menu entry passed in
+
+ Arguments :
+ The menu entry need to be destroyed
+
+ Returns :
+ None
+
+--*/
+{
+ BM_LOAD_CONTEXT *LoadContext;
+ BM_FILE_CONTEXT *FileContext;
+ BM_CONSOLE_CONTEXT *ConsoleContext;
+ BM_TERMINAL_CONTEXT *TerminalContext;
+ BM_HANDLE_CONTEXT *HandleContext;
+ BM_LEGACY_DEVICE_CONTEXT *LegacyDevContext;
+
+ //
+ // Select by the type in Menu entry for current context type
+ //
+ switch (MenuEntry->ContextSelection) {
+ case BM_LOAD_CONTEXT_SELECT:
+ LoadContext = (BM_LOAD_CONTEXT *) MenuEntry->VariableContext;
+ SafeFreePool (LoadContext->FilePathList);
+ SafeFreePool (LoadContext->LoadOption);
+ SafeFreePool (LoadContext->OptionalData);
+ SafeFreePool (LoadContext);
+ break;
+
+ case BM_FILE_CONTEXT_SELECT:
+ FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
+
+ if (!FileContext->IsRoot) {
+ SafeFreePool (FileContext->DevicePath);
+ } else {
+ if (FileContext->FHandle != NULL) {
+ FileContext->FHandle->Close (FileContext->FHandle);
+ }
+ }
+
+ SafeFreePool (FileContext->FileName);
+ SafeFreePool (FileContext->Info);
+ SafeFreePool (FileContext);
+ break;
+
+ case BM_CONSOLE_CONTEXT_SELECT:
+ ConsoleContext = (BM_CONSOLE_CONTEXT *) MenuEntry->VariableContext;
+ SafeFreePool (ConsoleContext->DevicePath);
+ SafeFreePool (ConsoleContext);
+ break;
+
+ case BM_TERMINAL_CONTEXT_SELECT:
+ TerminalContext = (BM_TERMINAL_CONTEXT *) MenuEntry->VariableContext;
+ SafeFreePool (TerminalContext->DevicePath);
+ SafeFreePool (TerminalContext);
+ break;
+
+ case BM_HANDLE_CONTEXT_SELECT:
+ HandleContext = (BM_HANDLE_CONTEXT *) MenuEntry->VariableContext;
+ SafeFreePool (HandleContext);
+ break;
+
+ case BM_LEGACY_DEV_CONTEXT_SELECT:
+ LegacyDevContext = (BM_LEGACY_DEVICE_CONTEXT *) MenuEntry->VariableContext;
+ SafeFreePool (LegacyDevContext);
+
+ default:
+ break;
+ }
+
+ SafeFreePool (MenuEntry->DisplayString);
+ if (NULL != MenuEntry->HelpString) {
+ SafeFreePool (MenuEntry->HelpString);
+ }
+
+ SafeFreePool (MenuEntry);
+}
+
+BM_MENU_ENTRY *
+BOpt_GetMenuEntry (
+ BM_MENU_OPTION *MenuOption,
+ UINTN MenuNumber
+ )
+/*++
+ Rountine Description :
+ Use this routine to get one particular menu entry in specified
+ menu
+
+ Arguments :
+ MenuOption The menu that we will search
+
+ MenuNumber The menunubmer that we want
+
+ Returns :
+ The desired menu entry
+
+--*/
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+ UINTN Index;
+ LIST_ENTRY *List;
+
+ if (MenuNumber >= MenuOption->MenuNumber) {
+ return NULL;
+ }
+
+ List = MenuOption->Head.ForwardLink;
+ for (Index = 0; Index < MenuNumber; Index++) {
+ List = List->ForwardLink;
+ }
+
+ NewMenuEntry = CR (List, BM_MENU_ENTRY, Link, BM_MENU_ENTRY_SIGNATURE);
+
+ return NewMenuEntry;
+}
+
+EFI_STATUS
+BOpt_FindFileSystem (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+/*++
+
+Routine Description
+ Find file systems for current Extensible Firmware
+ Including Handles that support Simple File System
+ protocol, Load File protocol.
+
+ Building up the FileSystem Menu for user selection
+ All file system will be stored in FsOptionMenu
+ for future use.
+
+Arguments:
+ CallbackData - BMM context data
+
+Returns:
+ EFI_SUCCESS - Success find the file system
+ EFI_OUT_OF_RESOURCES - Can not create menu entry
+
+--*/
+{
+ UINTN NoBlkIoHandles;
+ UINTN NoSimpleFsHandles;
+ UINTN NoLoadFileHandles;
+ EFI_HANDLE *BlkIoHandle;
+ EFI_HANDLE *SimpleFsHandle;
+ EFI_HANDLE *LoadFileHandle;
+ UINT16 *VolumeLabel;
+ EFI_BLOCK_IO_PROTOCOL *BlkIo;
+ UINTN Index;
+ EFI_STATUS Status;
+ BM_MENU_ENTRY *MenuEntry;
+ BM_FILE_CONTEXT *FileContext;
+ UINT16 *TempStr;
+ UINTN OptionNumber;
+ VOID *Buffer;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ UINT16 DeviceType;
+ BBS_BBS_DEVICE_PATH BbsDevicePathNode;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ BOOLEAN RemovableMedia;
+
+
+ NoSimpleFsHandles = 0;
+ NoLoadFileHandles = 0;
+ OptionNumber = 0;
+ InitializeListHead (&FsOptionMenu.Head);
+
+ //
+ // Locate Handles that support BlockIo protocol
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiBlockIoProtocolGuid,
+ NULL,
+ &NoBlkIoHandles,
+ &BlkIoHandle
+ );
+ if (!EFI_ERROR (Status)) {
+
+ for (Index = 0; Index < NoBlkIoHandles; Index++) {
+ Status = gBS->HandleProtocol (
+ BlkIoHandle[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlkIo
+ );
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Issue a dummy read to trigger reinstall of BlockIo protocol for removable media
+ //
+ if (BlkIo->Media->RemovableMedia) {
+ Buffer = EfiAllocateZeroPool (BlkIo->Media->BlockSize);
+ if (NULL == Buffer) {
+ SafeFreePool (BlkIoHandle);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ BlkIo->ReadBlocks (
+ BlkIo,
+ BlkIo->Media->MediaId,
+ 0,
+ BlkIo->Media->BlockSize,
+ Buffer
+ );
+ SafeFreePool (Buffer);
+ }
+ }
+ SafeFreePool (BlkIoHandle);
+ }
+
+ //
+ // Locate Handles that support Simple File System protocol
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleFileSystemProtocolGuid,
+ NULL,
+ &NoSimpleFsHandles,
+ &SimpleFsHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Find all the instances of the File System prototocol
+ //
+ for (Index = 0; Index < NoSimpleFsHandles; Index++) {
+ Status = gBS->HandleProtocol (
+ SimpleFsHandle[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlkIo
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // If no block IO exists assume it's NOT a removable media
+ //
+ RemovableMedia = FALSE;
+ } else {
+ //
+ // If block IO exists check to see if it's remobable media
+ //
+ RemovableMedia = BlkIo->Media->RemovableMedia;
+ }
+
+ //
+ // Allocate pool for this load option
+ //
+ MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);
+ if (NULL == MenuEntry) {
+ SafeFreePool (SimpleFsHandle);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
+
+ FileContext->Handle = SimpleFsHandle[Index];
+ MenuEntry->OptionNumber = Index;
+ FileContext->FHandle = EfiLibOpenRoot (FileContext->Handle);
+ if (!FileContext->FHandle) {
+ BOpt_DestroyMenuEntry (MenuEntry);
+ continue;
+ }
+
+ MenuEntry->HelpString = DevicePathToStr (DevicePathFromHandle (FileContext->Handle));
+ FileContext->Info = EfiLibFileSystemVolumeLabelInfo (FileContext->FHandle);
+ FileContext->FileName = EfiStrDuplicate (L"\\");
+ FileContext->DevicePath = FileDevicePath (
+ FileContext->Handle,
+ FileContext->FileName
+ );
+ FileContext->IsDir = TRUE;
+ FileContext->IsRoot = TRUE;
+ FileContext->IsRemovableMedia = RemovableMedia;
+ FileContext->IsLoadFile = FALSE;
+
+ //
+ // Get current file system's Volume Label
+ //
+ if (FileContext->Info == NULL) {
+ VolumeLabel = L"NO FILE SYSTEM INFO";
+ } else {
+ if (FileContext->Info->VolumeLabel == NULL) {
+ VolumeLabel = L"NULL VOLUME LABEL";
+ } else {
+ VolumeLabel = FileContext->Info->VolumeLabel;
+ if (*VolumeLabel == 0x0000) {
+ VolumeLabel = L"NO VOLUME LABEL";
+ }
+ }
+ }
+
+ TempStr = MenuEntry->HelpString;
+ MenuEntry->DisplayString = EfiAllocateZeroPool (MAX_CHAR);
+ ASSERT (MenuEntry->DisplayString != NULL);
+ UnicodeSPrint (
+ MenuEntry->DisplayString,
+ MAX_CHAR,
+ L"%s, [%s]",
+ VolumeLabel,
+ TempStr
+ );
+ OptionNumber++;
+ InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);
+ }
+ }
+
+ if (NoSimpleFsHandles != 0) {
+ SafeFreePool (SimpleFsHandle);
+ }
+ //
+ // Searching for handles that support Load File protocol
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiLoadFileProtocolGuid,
+ NULL,
+ &NoLoadFileHandles,
+ &LoadFileHandle
+ );
+
+ if (!EFI_ERROR (Status)) {
+ for (Index = 0; Index < NoLoadFileHandles; Index++) {
+ MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);
+ if (NULL == MenuEntry) {
+ SafeFreePool (LoadFileHandle);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
+ FileContext->IsRemovableMedia = FALSE;
+ FileContext->IsLoadFile = TRUE;
+ FileContext->Handle = LoadFileHandle[Index];
+ FileContext->IsRoot = TRUE;
+
+ FileContext->DevicePath = DevicePathFromHandle (FileContext->Handle);
+
+ MenuEntry->HelpString = DevicePathToStr (FileContext->DevicePath);
+
+ TempStr = MenuEntry->HelpString;
+ MenuEntry->DisplayString = EfiAllocateZeroPool (MAX_CHAR);
+ ASSERT (MenuEntry->DisplayString != NULL);
+ UnicodeSPrint (
+ MenuEntry->DisplayString,
+ MAX_CHAR,
+ L"Load File [%s]",
+ TempStr
+ );
+
+ MenuEntry->OptionNumber = OptionNumber;
+ OptionNumber++;
+ InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);
+ }
+ }
+
+ if (NoLoadFileHandles != 0) {
+ SafeFreePool (LoadFileHandle);
+ }
+
+ //
+ // Add Legacy Boot Option Support Here
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiLegacyBiosProtocolGuid,
+ NULL,
+ (VOID **) &LegacyBios
+ );
+ if (!EFI_ERROR (Status)) {
+
+ for (Index = BBS_TYPE_FLOPPY; Index <= BBS_TYPE_EMBEDDED_NETWORK; Index++) {
+ MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);
+ if (NULL == MenuEntry) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
+
+ FileContext->IsRemovableMedia = FALSE;
+ FileContext->IsLoadFile = TRUE;
+ FileContext->IsBootLegacy = TRUE;
+ DeviceType = (UINT16) Index;
+ BbsDevicePathNode.Header.Type = BBS_DEVICE_PATH;
+ BbsDevicePathNode.Header.SubType = BBS_BBS_DP;
+ SetDevicePathNodeLength (
+ &BbsDevicePathNode.Header,
+ sizeof (BBS_BBS_DEVICE_PATH)
+ );
+ BbsDevicePathNode.DeviceType = DeviceType;
+ BbsDevicePathNode.StatusFlag = 0;
+ BbsDevicePathNode.String[0] = 0;
+ DevicePath = AppendDevicePathNode (
+ EndDevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &BbsDevicePathNode
+ );
+
+ FileContext->DevicePath = DevicePath;
+ MenuEntry->HelpString = DevicePathToStr (FileContext->DevicePath);
+
+ TempStr = MenuEntry->HelpString;
+ MenuEntry->DisplayString = EfiAllocateZeroPool (MAX_CHAR);
+ ASSERT (MenuEntry->DisplayString != NULL);
+ UnicodeSPrint (
+ MenuEntry->DisplayString,
+ MAX_CHAR,
+ L"Boot Legacy [%s]",
+ TempStr
+ );
+ MenuEntry->OptionNumber = OptionNumber;
+ OptionNumber++;
+ InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);
+ }
+ }
+ //
+ // Remember how many file system options are here
+ //
+ FsOptionMenu.MenuNumber = OptionNumber;
+ return EFI_SUCCESS;
+}
+
+VOID
+BOpt_FreeMenu (
+ BM_MENU_OPTION *FreeMenu
+ )
+/*++
+
+Routine Description
+ Free resources allocated in Allocate Rountine
+
+Arguments:
+ FreeMenu Menu to be freed
+
+Returns:
+ VOID
+
+--*/
+{
+ BM_MENU_ENTRY *MenuEntry;
+ while (!IsListEmpty (&FreeMenu->Head)) {
+ MenuEntry = CR (
+ FreeMenu->Head.ForwardLink,
+ BM_MENU_ENTRY,
+ Link,
+ BM_MENU_ENTRY_SIGNATURE
+ );
+ RemoveEntryList (&MenuEntry->Link);
+ BOpt_DestroyMenuEntry (MenuEntry);
+ }
+}
+
+EFI_STATUS
+BOpt_FindFiles (
+ IN BMM_CALLBACK_DATA *CallbackData,
+ IN BM_MENU_ENTRY *MenuEntry
+ )
+/*++
+
+Routine Description
+ Find files under current directory
+ All files and sub-directories in current directory
+ will be stored in DirectoryMenu for future use.
+
+Arguments:
+ FileOption -- Pointer for Dir to explore
+
+Returns:
+ TRUE -- Get files from current dir successfully
+ FALSE -- Can't get files from current dir
+
+--*/
+{
+ EFI_FILE_HANDLE NewDir;
+ EFI_FILE_HANDLE Dir;
+ EFI_FILE_INFO *DirInfo;
+ UINTN BufferSize;
+ UINTN DirBufferSize;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_FILE_CONTEXT *FileContext;
+ BM_FILE_CONTEXT *NewFileContext;
+ UINTN Pass;
+ EFI_STATUS Status;
+ UINTN OptionNumber;
+
+ FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
+ Dir = FileContext->FHandle;
+ OptionNumber = 0;
+ //
+ // Open current directory to get files from it
+ //
+ Status = Dir->Open (
+ Dir,
+ &NewDir,
+ FileContext->FileName,
+ EFI_FILE_READ_ONLY,
+ 0
+ );
+ if (!FileContext->IsRoot) {
+ Dir->Close (Dir);
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DirInfo = EfiLibFileInfo (NewDir);
+ if (!DirInfo) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (!(DirInfo->Attribute & EFI_FILE_DIRECTORY)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FileContext->DevicePath = FileDevicePath (
+ FileContext->Handle,
+ FileContext->FileName
+ );
+
+ DirBufferSize = sizeof (EFI_FILE_INFO) + 1024;
+ DirInfo = EfiAllocateZeroPool (DirBufferSize);
+ if (!DirInfo) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Get all files in current directory
+ // Pass 1 to get Directories
+ // Pass 2 to get files that are EFI images
+ //
+ for (Pass = 1; Pass <= 2; Pass++) {
+ NewDir->SetPosition (NewDir, 0);
+ for (;;) {
+ BufferSize = DirBufferSize;
+ Status = NewDir->Read (NewDir, &BufferSize, DirInfo);
+ if (EFI_ERROR (Status) || BufferSize == 0) {
+ break;
+ }
+
+ if ((DirInfo->Attribute & EFI_FILE_DIRECTORY && Pass == 2) ||
+ (!(DirInfo->Attribute & EFI_FILE_DIRECTORY) && Pass == 1)
+ ) {
+ //
+ // Pass 1 is for Directories
+ // Pass 2 is for file names
+ //
+ continue;
+ }
+
+ if (!(BOpt_IsEfiImageName (DirInfo->FileName) || DirInfo->Attribute & EFI_FILE_DIRECTORY)) {
+ //
+ // Slip file unless it is a directory entry or a .EFI file
+ //
+ continue;
+ }
+
+ NewMenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);
+ if (NULL == NewMenuEntry) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewFileContext = (BM_FILE_CONTEXT *) NewMenuEntry->VariableContext;
+ NewFileContext->Handle = FileContext->Handle;
+ NewFileContext->FileName = BOpt_AppendFileName (
+ FileContext->FileName,
+ DirInfo->FileName
+ );
+ NewFileContext->FHandle = NewDir;
+ NewFileContext->DevicePath = FileDevicePath (
+ NewFileContext->Handle,
+ NewFileContext->FileName
+ );
+ NewMenuEntry->HelpString = NULL;
+
+ MenuEntry->DisplayStringToken = GetStringTokenFromDepository (
+ CallbackData,
+ FileOptionStrDepository
+ );
+
+ NewFileContext->IsDir = (BOOLEAN) ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY);
+
+ if (NewFileContext->IsDir) {
+ BufferSize = StrLen (DirInfo->FileName) * 2 + 6;
+ NewMenuEntry->DisplayString = EfiAllocateZeroPool (BufferSize);
+
+ UnicodeSPrint (
+ NewMenuEntry->DisplayString,
+ BufferSize,
+ L"<%s>",
+ DirInfo->FileName
+ );
+
+ } else {
+ NewMenuEntry->DisplayString = EfiStrDuplicate (DirInfo->FileName);
+ }
+
+ NewFileContext->IsRoot = FALSE;
+ NewFileContext->IsLoadFile = FALSE;
+ NewFileContext->IsRemovableMedia = FALSE;
+
+ NewMenuEntry->OptionNumber = OptionNumber;
+ OptionNumber++;
+ InsertTailList (&DirectoryMenu.Head, &NewMenuEntry->Link);
+ }
+ }
+
+ DirectoryMenu.MenuNumber = OptionNumber;
+ SafeFreePool (DirInfo);
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+BOpt_GetLegacyOptions (
+ VOID
+ )
+/*++
+Routine Description:
+
+ Build the LegacyFDMenu LegacyHDMenu LegacyCDMenu according to LegacyBios.GetBbsInfo().
+
+Arguments:
+ None
+
+Returns:
+ The device info of legacy device.
+
+--*/
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_LEGACY_DEVICE_CONTEXT *NewLegacyDevContext;
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ UINT16 HddCount;
+ HDD_INFO *HddInfo;
+ UINT16 BbsCount;
+ BBS_TABLE *BbsTable;
+ UINTN Index;
+ CHAR16 DescString[100];
+ UINTN FDNum;
+ UINTN HDNum;
+ UINTN CDNum;
+ UINTN NETNum;
+ UINTN BEVNum;
+
+ NewMenuEntry = NULL;
+ HddInfo = NULL;
+ BbsTable = NULL;
+ BbsCount = 0;
+
+ //
+ // Initialize Bbs Table Context from BBS info data
+ //
+ InitializeListHead (&LegacyFDMenu.Head);
+ InitializeListHead (&LegacyHDMenu.Head);
+ InitializeListHead (&LegacyCDMenu.Head);
+ InitializeListHead (&LegacyNETMenu.Head);
+ InitializeListHead (&LegacyBEVMenu.Head);
+
+ Status = gBS->LocateProtocol (
+ &gEfiLegacyBiosProtocolGuid,
+ NULL,
+ (VOID **) &LegacyBios
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = LegacyBios->GetBbsInfo (
+ LegacyBios,
+ &HddCount,
+ &HddInfo,
+ &BbsCount,
+ &BbsTable
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ FDNum = 0;
+ HDNum = 0;
+ CDNum = 0;
+ NETNum = 0;
+ BEVNum = 0;
+
+ for (Index = 0; Index < BbsCount; Index++) {
+ if ((BBS_IGNORE_ENTRY == BbsTable[Index].BootPriority) ||
+ (BBS_DO_NOT_BOOT_FROM == BbsTable[Index].BootPriority)
+ ) {
+ continue;
+ }
+
+ NewMenuEntry = BOpt_CreateMenuEntry (BM_LEGACY_DEV_CONTEXT_SELECT);
+ if (NULL == NewMenuEntry) {
+ break;
+ }
+
+ NewLegacyDevContext = (BM_LEGACY_DEVICE_CONTEXT *) NewMenuEntry->VariableContext;
+ NewLegacyDevContext->BbsTable = &BbsTable[Index];
+ NewLegacyDevContext->Index = Index;
+ NewLegacyDevContext->BbsCount = BbsCount;
+ BdsBuildLegacyDevNameString (
+ &BbsTable[Index],
+ Index,
+ sizeof (DescString),
+ DescString
+ );
+ NewLegacyDevContext->Description = EfiAllocateZeroPool (StrSize (DescString));
+ if (NULL == NewLegacyDevContext->Description) {
+ break;
+ }
+
+ CopyMem (NewLegacyDevContext->Description, DescString, StrSize (DescString));
+ NewMenuEntry->DisplayString = NewLegacyDevContext->Description;
+ NewMenuEntry->HelpString = NULL;
+
+ switch (BbsTable[Index].DeviceType) {
+ case BBS_FLOPPY:
+ InsertTailList (&LegacyFDMenu.Head, &NewMenuEntry->Link);
+ FDNum++;
+ break;
+
+ case BBS_HARDDISK:
+ InsertTailList (&LegacyHDMenu.Head, &NewMenuEntry->Link);
+ HDNum++;
+ break;
+
+ case BBS_CDROM:
+ InsertTailList (&LegacyCDMenu.Head, &NewMenuEntry->Link);
+ CDNum++;
+ break;
+
+ case BBS_EMBED_NETWORK:
+ InsertTailList (&LegacyNETMenu.Head, &NewMenuEntry->Link);
+ NETNum++;
+ break;
+
+ case BBS_BEV_DEVICE:
+ InsertTailList (&LegacyBEVMenu.Head, &NewMenuEntry->Link);
+ BEVNum++;
+ break;
+ }
+ }
+
+ if (Index != BbsCount) {
+ BOpt_FreeLegacyOptions ();
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ LegacyFDMenu.MenuNumber = FDNum;
+ LegacyHDMenu.MenuNumber = HDNum;
+ LegacyCDMenu.MenuNumber = CDNum;
+ LegacyNETMenu.MenuNumber = NETNum;
+ LegacyBEVMenu.MenuNumber = BEVNum;
+ return EFI_SUCCESS;
+}
+
+VOID
+BOpt_FreeLegacyOptions (
+ VOID
+ )
+{
+ BOpt_FreeMenu (&LegacyFDMenu);
+ BOpt_FreeMenu (&LegacyHDMenu);
+ BOpt_FreeMenu (&LegacyCDMenu);
+ BOpt_FreeMenu (&LegacyNETMenu);
+ BOpt_FreeMenu (&LegacyBEVMenu);
+}
+
+EFI_STATUS
+BOpt_GetBootOptions (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+/*++
+
+Routine Description:
+
+ Build the BootOptionMenu according to BootOrder Variable.
+ This Routine will access the Boot#### to get EFI_LOAD_OPTION
+
+Arguments:
+ None
+
+Returns:
+ The number of the Var Boot####
+
+--*/
+{
+ UINTN Index;
+ UINT16 BootString[10];
+ UINT8 *LoadOptionFromVar;
+ UINT8 *LoadOption;
+ UINTN BootOptionSize;
+ BOOLEAN BootNextFlag;
+ UINT16 *BootOrderList;
+ UINTN BootOrderListSize;
+ UINT16 *BootNext;
+ UINTN BootNextSize;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_LOAD_CONTEXT *NewLoadContext;
+ UINT8 *LoadOptionPtr;
+ UINTN StringSize;
+ UINTN OptionalDataSize;
+ UINT8 *LoadOptionEnd;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINTN MenuCount;
+ UINT8 *Ptr;
+
+ MenuCount = 0;
+ BootOrderListSize = 0;
+ BootNextSize = 0;
+ BootOrderList = NULL;
+ BootNext = NULL;
+ LoadOptionFromVar = NULL;
+ BOpt_FreeMenu (&BootOptionMenu);
+ InitializeListHead (&BootOptionMenu.Head);
+
+ //
+ // Get the BootOrder from the Var
+ //
+ BootOrderList = BdsLibGetVariableAndSize (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ &BootOrderListSize
+ );
+
+ //
+ // Get the BootNext from the Var
+ //
+ BootNext = BdsLibGetVariableAndSize (
+ L"BootNext",
+ &gEfiGlobalVariableGuid,
+ &BootNextSize
+ );
+
+ if (BootNext) {
+ if (BootNextSize != sizeof (UINT16)) {
+ SafeFreePool (BootNext);
+ BootNext = NULL;
+ }
+ }
+
+ for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {
+ UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", BootOrderList[Index]);
+ //
+ // Get all loadoptions from the VAR
+ //
+ LoadOptionFromVar = BdsLibGetVariableAndSize (
+ BootString,
+ &gEfiGlobalVariableGuid,
+ &BootOptionSize
+ );
+ if (!LoadOptionFromVar) {
+ continue;
+ }
+
+ LoadOption = EfiAllocateZeroPool (BootOptionSize);
+ if (!LoadOption) {
+ continue;
+ }
+
+ CopyMem (LoadOption, LoadOptionFromVar, BootOptionSize);
+ SafeFreePool (LoadOptionFromVar);
+
+ if (BootNext) {
+ BootNextFlag = (BOOLEAN) (*BootNext == BootOrderList[Index]);
+ } else {
+ BootNextFlag = FALSE;
+ }
+
+ if (0 == (*((UINT32 *) LoadOption) & LOAD_OPTION_ACTIVE)) {
+ SafeFreePool (LoadOption);
+ continue;
+ }
+ //
+ // BUGBUG: could not return EFI_OUT_OF_RESOURCES here directly.
+ // the buffer allocated already should be freed before returning.
+ //
+ NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
+ if (NULL == NewMenuEntry) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+
+ LoadOptionPtr = LoadOption;
+ LoadOptionEnd = LoadOption + BootOptionSize;
+
+ NewMenuEntry->OptionNumber = BootOrderList[Index];
+ NewLoadContext->LoadOptionModified = FALSE;
+ NewLoadContext->Deleted = FALSE;
+ NewLoadContext->IsBootNext = BootNextFlag;
+
+ //
+ // Is a Legacy Device?
+ //
+ Ptr = (UINT8 *) LoadOption;
+
+ //
+ // Attribute = *(UINT32 *)Ptr;
+ //
+ Ptr += sizeof (UINT32);
+
+ //
+ // FilePathSize = *(UINT16 *)Ptr;
+ //
+ Ptr += sizeof (UINT16);
+
+ //
+ // Description = (CHAR16 *)Ptr;
+ //
+ Ptr += StrSize ((CHAR16 *) Ptr);
+
+ //
+ // Now Ptr point to Device Path
+ //
+ DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
+ if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {
+ NewLoadContext->IsLegacy = TRUE;
+ } else {
+ NewLoadContext->IsLegacy = FALSE;
+ }
+ //
+ // LoadOption is a pointer type of UINT8
+ // for easy use with following LOAD_OPTION
+ // embedded in this struct
+ //
+ NewLoadContext->LoadOption = LoadOption;
+ NewLoadContext->LoadOptionSize = BootOptionSize;
+
+ NewLoadContext->Attributes = *(UINT32 *) LoadOptionPtr;
+ NewLoadContext->IsActive = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE);
+
+ NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);
+
+ LoadOptionPtr += sizeof (UINT32);
+
+ NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;
+ LoadOptionPtr += sizeof (UINT16);
+
+ StringSize = StrSize ((UINT16 *) LoadOptionPtr);
+ NewLoadContext->Description = EfiAllocateZeroPool (StringSize);
+ ASSERT (NewLoadContext->Description != NULL);
+ CopyMem (
+ NewLoadContext->Description,
+ (UINT16 *) LoadOptionPtr,
+ StringSize
+ );
+ NewMenuEntry->DisplayString = NewLoadContext->Description;
+
+ LoadOptionPtr += StringSize;
+
+ NewLoadContext->FilePathList = EfiAllocateZeroPool (NewLoadContext->FilePathListLength);
+ ASSERT (NewLoadContext->FilePathList != NULL);
+ CopyMem (
+ NewLoadContext->FilePathList,
+ (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,
+ NewLoadContext->FilePathListLength
+ );
+
+ NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList);
+ NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (
+ CallbackData,
+ BootOptionStrDepository
+ );
+ NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (
+ CallbackData,
+ BootOptionHelpStrDepository
+ );
+ LoadOptionPtr += NewLoadContext->FilePathListLength;
+
+ if (LoadOptionPtr < LoadOptionEnd) {
+ OptionalDataSize = BootOptionSize -
+ sizeof (UINT32) -
+ sizeof (UINT16) -
+ StringSize -
+ NewLoadContext->FilePathListLength;
+
+ NewLoadContext->OptionalData = EfiAllocateZeroPool (OptionalDataSize);
+ ASSERT (NewLoadContext->OptionalData != NULL);
+ CopyMem (
+ NewLoadContext->OptionalData,
+ LoadOptionPtr,
+ OptionalDataSize
+ );
+
+ NewLoadContext->OptionalDataSize = OptionalDataSize;
+ }
+
+ InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link);
+ MenuCount++;
+ }
+
+ SafeFreePool (BootNext);
+ SafeFreePool (BootOrderList);
+ BootOptionMenu.MenuNumber = MenuCount;
+ return MenuCount;
+}
+
+CHAR16 *
+BOpt_AppendFileName (
+ IN CHAR16 *Str1,
+ IN CHAR16 *Str2
+ )
+/*++
+
+Routine Description
+ Append file name to existing file name.
+
+Arguments:
+ Str1 - existing file name
+ Str2 - file name to be appended
+
+Returns:
+ Allocate a new string to hold the appended result.
+ Caller is responsible to free the returned string.
+
+--*/
+{
+ UINTN Size1;
+ UINTN Size2;
+ CHAR16 *Str;
+ CHAR16 *Ptr;
+ CHAR16 *LastSlash;
+
+ Size1 = StrSize (Str1);
+ Size2 = StrSize (Str2);
+ Str = EfiAllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));
+ ASSERT (Str != NULL);
+
+ StrCat (Str, Str1);
+ if (!((*Str == '\\') && (*(Str + 1) == 0))) {
+ StrCat (Str, L"\\");
+ }
+
+ StrCat (Str, Str2);
+
+ Ptr = Str;
+ LastSlash = Str;
+ while (*Ptr != 0) {
+ if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '.' && *(Ptr + 3) != 0) {
+ //
+ // Convert \Name\..\ to \
+ // DO NOT convert the .. if it is at the end of the string. This will
+ // break the .. behavior in changing directories.
+ //
+ StrCpy (LastSlash, Ptr + 3);
+ Ptr = LastSlash;
+ } else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') {
+ //
+ // Convert a \.\ to a \
+ //
+ StrCpy (Ptr, Ptr + 2);
+ Ptr = LastSlash;
+ } else if (*Ptr == '\\') {
+ LastSlash = Ptr;
+ }
+
+ Ptr++;
+ }
+
+ return Str;
+}
+
+BOOLEAN
+BOpt_IsEfiImageName (
+ IN UINT16 *FileName
+ )
+/*++
+
+Routine Description
+ Check whether current FileName point to a valid
+ Efi Image File.
+
+Arguments:
+ FileName - File need to be checked.
+
+Returns:
+ TRUE - Is Efi Image
+ FALSE - Not a valid Efi Image
+
+--*/
+{
+ //
+ // Search for ".efi" extension
+ //
+ while (*FileName) {
+ if (FileName[0] == '.') {
+ if (FileName[1] == 'e' || FileName[1] == 'E') {
+ if (FileName[2] == 'f' || FileName[2] == 'F') {
+ if (FileName[3] == 'i' || FileName[3] == 'I') {
+ return TRUE;
+ } else if (FileName[3] == 0x0000) {
+ return FALSE;
+ }
+ } else if (FileName[2] == 0x0000) {
+ return FALSE;
+ }
+ } else if (FileName[1] == 0x0000) {
+ return FALSE;
+ }
+ }
+
+ FileName += 1;
+ }
+
+ return FALSE;
+}
+
+BOOLEAN
+BOpt_IsEfiApp (
+ IN EFI_FILE_HANDLE Dir,
+ IN UINT16 *FileName
+ )
+/*++
+
+Routine Description:
+ Check whether current FileName point to a valid Efi Application
+
+Arguments:
+ Dir - Pointer to current Directory
+ FileName - Pointer to current File name.
+
+Returns:
+ TRUE - Is a valid Efi Application
+ FALSE - not a valid Efi Application
+
+--*/
+{
+ UINTN BufferSize;
+ EFI_IMAGE_DOS_HEADER DosHdr;
+ EFI_IMAGE_NT_HEADERS PeHdr;
+ EFI_IMAGE_OPTIONAL_HEADER32 *PeOpt32;
+ EFI_IMAGE_OPTIONAL_HEADER64 *PeOpt64;
+ UINT16 Subsystem;
+ EFI_FILE_HANDLE File;
+ EFI_STATUS Status;
+
+ Status = Dir->Open (Dir, &File, FileName, EFI_FILE_MODE_READ, 0);
+
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ BufferSize = sizeof (EFI_IMAGE_DOS_HEADER);
+ File->Read (File, &BufferSize, &DosHdr);
+ if (DosHdr.e_magic != EFI_IMAGE_DOS_SIGNATURE) {
+ File->Close (File);
+ return FALSE;
+ }
+
+ File->SetPosition (File, DosHdr.e_lfanew);
+ BufferSize = sizeof (EFI_IMAGE_NT_HEADERS);
+ File->Read (File, &BufferSize, &PeHdr);
+ if (PeHdr.Signature != EFI_IMAGE_NT_SIGNATURE) {
+ File->Close (File);
+ return FALSE;
+ }
+ //
+ // Determine PE type and read subsytem
+ // BugBug : We should be using EFI_IMAGE_MACHINE_TYPE_SUPPORTED (machine)
+ // macro to detect the machine type.
+ // We should not be using EFI_IMAGE_OPTIONAL_HEADER32 and
+ // EFI_IMAGE_OPTIONAL_HEADER64
+ //
+ if (PeHdr.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ PeOpt32 = (EFI_IMAGE_OPTIONAL_HEADER32 *) &(PeHdr.OptionalHeader);
+ Subsystem = PeOpt32->Subsystem;
+ } else if (PeHdr.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ PeOpt64 = (EFI_IMAGE_OPTIONAL_HEADER64 *) &(PeHdr.OptionalHeader);
+ Subsystem = PeOpt64->Subsystem;
+ } else {
+ return FALSE;
+ }
+
+ if (Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
+ File->Close (File);
+ return TRUE;
+ } else {
+ File->Close (File);
+ return FALSE;
+ }
+}
+
+EFI_STATUS
+BOpt_FindDrivers (
+ VOID
+ )
+/*++
+
+Routine Description
+ Find drivers that will be added as Driver#### variables from handles
+ in current system environment
+ All valid handles in the system except those consume SimpleFs, LoadFile
+ are stored in DriverMenu for future use.
+
+Arguments:
+ None
+
+Returns:
+ EFI_SUCCESS
+ Others
+
+--*/
+{
+ UINTN NoDevicePathHandles;
+ EFI_HANDLE *DevicePathHandle;
+ UINTN Index;
+ EFI_STATUS Status;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_HANDLE_CONTEXT *NewHandleContext;
+ EFI_HANDLE CurHandle;
+ UINTN OptionNumber;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs;
+ EFI_LOAD_FILE_PROTOCOL *LoadFile;
+
+ SimpleFs = NULL;
+ LoadFile = NULL;
+
+ InitializeListHead (&DriverMenu.Head);
+
+ //
+ // At first, get all handles that support Device Path
+ // protocol which is the basic requirement for
+ // Driver####
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiDevicePathProtocolGuid,
+ NULL,
+ &NoDevicePathHandles,
+ &DevicePathHandle
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ OptionNumber = 0;
+ for (Index = 0; Index < NoDevicePathHandles; Index++) {
+ CurHandle = DevicePathHandle[Index];
+
+ //
+ // Check whether this handle support
+ // driver binding
+ //
+ Status = gBS->HandleProtocol (
+ CurHandle,
+ &gEfiSimpleFileSystemProtocolGuid,
+ (VOID **) &SimpleFs
+ );
+ if (Status == EFI_SUCCESS) {
+ continue;
+ }
+
+ Status = gBS->HandleProtocol (
+ CurHandle,
+ &gEfiLoadFileProtocolGuid,
+ (VOID **) &LoadFile
+ );
+ if (Status == EFI_SUCCESS) {
+ continue;
+ }
+
+ NewMenuEntry = BOpt_CreateMenuEntry (BM_HANDLE_CONTEXT_SELECT);
+ if (NULL == NewMenuEntry) {
+ SafeFreePool (DevicePathHandle);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewHandleContext = (BM_HANDLE_CONTEXT *) NewMenuEntry->VariableContext;
+ NewHandleContext->Handle = CurHandle;
+ NewHandleContext->DevicePath = DevicePathFromHandle (CurHandle);
+ NewMenuEntry->DisplayString = DevicePathToStr (NewHandleContext->DevicePath);
+ NewMenuEntry->HelpString = NULL;
+ NewMenuEntry->OptionNumber = OptionNumber;
+ OptionNumber++;
+ InsertTailList (&DriverMenu.Head, &NewMenuEntry->Link);
+
+ }
+ SafeFreePool (DevicePathHandle);
+
+ DriverMenu.MenuNumber = OptionNumber;
+ return EFI_SUCCESS;
+}
+
+UINT16
+BOpt_GetBootOptionNumber (
+ VOID
+ )
+/*++
+
+Routine Description:
+ Get the Option Number that does not used
+
+Arguments:
+
+Returns:
+ The Option Number
+
+--*/
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+ UINT16 *BootOrderList;
+ UINTN BootOrderListSize;
+ UINT16 Number;
+ UINTN Index;
+ UINTN Index2;
+ BOOLEAN Found;
+ CHAR16 StrTemp[100];
+ UINT16 *OptionBuffer;
+ UINTN OptionSize;
+
+ BootOrderListSize = 0;
+ BootOrderList = NULL;
+
+ BootOrderList = BdsLibGetVariableAndSize (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ &BootOrderListSize
+ );
+ if (BootOrderList) {
+ //
+ // already have Boot####
+ //
+ // AlreadyBootNumbers = BootOrderListSize / sizeof(UINT16);
+ //
+ for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {
+ Found = TRUE;
+ for (Index2 = 0; Index2 < BootOptionMenu.MenuNumber; Index2++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index2);
+ if (Index == NewMenuEntry->OptionNumber) {
+ Found = FALSE;
+ break;
+ }
+ }
+
+ if (Found) {
+ UnicodeSPrint (StrTemp, 100, L"Boot%04x", Index);
+ DEBUG((DEBUG_ERROR,"INdex= %s\n", StrTemp));
+ OptionBuffer = BdsLibGetVariableAndSize (
+ StrTemp,
+ &gEfiGlobalVariableGuid,
+ &OptionSize
+ );
+ if (NULL == OptionBuffer)
+ break;
+ }
+ }
+ //
+ // end for Index
+ //
+ Number = (UINT16) Index;
+ } else {
+ //
+ // No Boot####
+ //
+ Number = 0;
+ }
+
+ return Number;
+}
+
+UINT16
+BOpt_GetDriverOptionNumber (
+ VOID
+ )
+/*++
+
+Routine Description:
+ Get the Option Number that does not used
+
+Arguments:
+
+Returns:
+ The Option Number
+
+--*/
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+ UINT16 *DriverOrderList;
+ UINTN DriverOrderListSize;
+ UINT16 Number;
+ UINTN Index;
+ UINTN Index2;
+ BOOLEAN Found;
+
+ DriverOrderListSize = 0;
+ DriverOrderList = NULL;
+
+ DriverOrderList = BdsLibGetVariableAndSize (
+ L"DriverOrder",
+ &gEfiGlobalVariableGuid,
+ &DriverOrderListSize
+ );
+ if (DriverOrderList) {
+ //
+ // already have Driver####
+ //
+ // AlreadyDriverNumbers = DriverOrderListSize / sizeof(UINT16);
+ //
+ for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) {
+ Found = TRUE;
+ for (Index2 = 0; Index2 < DriverOptionMenu.MenuNumber; Index2++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index2);
+ if (Index == NewMenuEntry->OptionNumber) {
+ Found = FALSE;
+ break;
+ }
+ }
+
+ if (Found) {
+ break;
+ }
+ }
+ //
+ // end for Index
+ //
+ Number = (UINT16) Index;
+ } else {
+ //
+ // No Driver####
+ //
+ Number = 0;
+ }
+
+ return Number;
+}
+
+EFI_STATUS
+BOpt_GetDriverOptions (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+/*++
+
+Routine Description:
+ Build up all DriverOptionMenu
+
+Arguments:
+
+Returns:
+ The Option Number
+
+--*/
+{
+ UINTN Index;
+ UINT16 DriverString[12];
+ UINT8 *LoadOptionFromVar;
+ UINT8 *LoadOption;
+ UINTN DriverOptionSize;
+
+ UINT16 *DriverOrderList;
+ UINTN DriverOrderListSize;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_LOAD_CONTEXT *NewLoadContext;
+ UINT8 *LoadOptionPtr;
+ UINTN StringSize;
+ UINTN OptionalDataSize;
+ UINT8 *LoadOptionEnd;
+
+ DriverOrderListSize = 0;
+ DriverOrderList = NULL;
+ DriverOptionSize = 0;
+ LoadOptionFromVar = NULL;
+ BOpt_FreeMenu (&DriverOptionMenu);
+ InitializeListHead (&DriverOptionMenu.Head);
+ //
+ // Get the DriverOrder from the Var
+ //
+ DriverOrderList = BdsLibGetVariableAndSize (
+ L"DriverOrder",
+ &gEfiGlobalVariableGuid,
+ &DriverOrderListSize
+ );
+
+ for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) {
+ UnicodeSPrint (
+ DriverString,
+ sizeof (DriverString),
+ L"Driver%04x",
+ DriverOrderList[Index]
+ );
+ //
+ // Get all loadoptions from the VAR
+ //
+ LoadOptionFromVar = BdsLibGetVariableAndSize (
+ DriverString,
+ &gEfiGlobalVariableGuid,
+ &DriverOptionSize
+ );
+ if (!LoadOptionFromVar) {
+ continue;
+ }
+
+ LoadOption = EfiAllocateZeroPool (DriverOptionSize);
+ if (!LoadOption) {
+ continue;
+ }
+
+ CopyMem (LoadOption, LoadOptionFromVar, DriverOptionSize);
+ SafeFreePool (LoadOptionFromVar);
+
+ NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
+ if (NULL == NewMenuEntry) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+ LoadOptionPtr = LoadOption;
+ LoadOptionEnd = LoadOption + DriverOptionSize;
+ NewMenuEntry->OptionNumber = DriverOrderList[Index];
+ NewLoadContext->LoadOptionModified = FALSE;
+ NewLoadContext->Deleted = FALSE;
+ NewLoadContext->IsLegacy = FALSE;
+
+ //
+ // LoadOption is a pointer type of UINT8
+ // for easy use with following LOAD_OPTION
+ // embedded in this struct
+ //
+ NewLoadContext->LoadOption = LoadOption;
+ NewLoadContext->LoadOptionSize = DriverOptionSize;
+
+ NewLoadContext->Attributes = *(UINT32 *) LoadOptionPtr;
+ NewLoadContext->IsActive = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE);
+
+ NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);
+
+ LoadOptionPtr += sizeof (UINT32);
+
+ NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;
+ LoadOptionPtr += sizeof (UINT16);
+
+ StringSize = StrSize ((UINT16 *) LoadOptionPtr);
+ NewLoadContext->Description = EfiAllocateZeroPool (StringSize);
+ ASSERT (NewLoadContext->Description != NULL);
+ CopyMem (
+ NewLoadContext->Description,
+ (UINT16 *) LoadOptionPtr,
+ StringSize
+ );
+ NewMenuEntry->DisplayString = NewLoadContext->Description;
+
+ LoadOptionPtr += StringSize;
+
+ NewLoadContext->FilePathList = EfiAllocateZeroPool (NewLoadContext->FilePathListLength);
+ ASSERT (NewLoadContext->FilePathList != NULL);
+ CopyMem (
+ NewLoadContext->FilePathList,
+ (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,
+ NewLoadContext->FilePathListLength
+ );
+
+ NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList);
+ NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (
+ CallbackData,
+ DriverOptionStrDepository
+ );
+ NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (
+ CallbackData,
+ DriverOptionHelpStrDepository
+ );
+ LoadOptionPtr += NewLoadContext->FilePathListLength;
+
+ if (LoadOptionPtr < LoadOptionEnd) {
+ OptionalDataSize = DriverOptionSize -
+ sizeof (UINT32) -
+ sizeof (UINT16) -
+ StringSize -
+ NewLoadContext->FilePathListLength;
+
+ NewLoadContext->OptionalData = EfiAllocateZeroPool (OptionalDataSize);
+ ASSERT (NewLoadContext->OptionalData != NULL);
+ CopyMem (
+ NewLoadContext->OptionalData,
+ LoadOptionPtr,
+ OptionalDataSize
+ );
+
+ NewLoadContext->OptionalDataSize = OptionalDataSize;
+ }
+
+ InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link);
+
+ }
+
+ SafeFreePool (DriverOrderList);
+ DriverOptionMenu.MenuNumber = Index;
+ return EFI_SUCCESS;
+
+}
+
diff --git a/MdeModulePkg/Universal/BdsDxe/BootMaint/ConsoleOption.c b/MdeModulePkg/Universal/BdsDxe/BootMaint/ConsoleOption.c new file mode 100644 index 0000000000..7239e6f679 --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/BootMaint/ConsoleOption.c @@ -0,0 +1,992 @@ +/*++
+Copyright (c) 2004 - 2008, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ consoleoption.c
+
+Abstract:
+
+ handles console redirection from boot manager
+
+
+Revision History
+
+--*/
+
+#include "BootMaint.h"
+
+EFI_DEVICE_PATH_PROTOCOL *
+DevicePathInstanceDup (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevPath
+ );
+
+EFI_STATUS
+UpdateComAttributeFromVariable (
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+EFI_STATUS
+ChangeTerminalDevicePath (
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ BOOLEAN ChangeTerminal
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+ EFI_DEVICE_PATH_PROTOCOL *Node1;
+ ACPI_HID_DEVICE_PATH *Acpi;
+ UART_DEVICE_PATH *Uart;
+ UART_DEVICE_PATH *Uart1;
+ UINTN Com;
+ UINT32 Match;
+ BM_TERMINAL_CONTEXT *NewTerminalContext;
+ BM_MENU_ENTRY *NewMenuEntry;
+
+ Match = EISA_PNP_ID (0x0501);
+ Node = DevicePath;
+ Node = NextDevicePathNode (Node);
+ Com = 0;
+ while (!IsDevicePathEnd (Node)) {
+ if ((DevicePathType (Node) == ACPI_DEVICE_PATH) && (DevicePathSubType (Node) == ACPI_DP)) {
+ Acpi = (ACPI_HID_DEVICE_PATH *) Node;
+ if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) {
+ CopyMem (&Com, &Acpi->UID, sizeof (UINT32));
+ }
+ }
+
+ NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Com);
+ if (NULL == NewMenuEntry) {
+ return EFI_NOT_FOUND;
+ }
+
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
+ if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) {
+ Uart = (UART_DEVICE_PATH *) Node;
+ CopyMem (
+ &Uart->BaudRate,
+ &NewTerminalContext->BaudRate,
+ sizeof (UINT64)
+ );
+
+ CopyMem (
+ &Uart->DataBits,
+ &NewTerminalContext->DataBits,
+ sizeof (UINT8)
+ );
+
+ CopyMem (
+ &Uart->Parity,
+ &NewTerminalContext->Parity,
+ sizeof (UINT8)
+ );
+
+ CopyMem (
+ &Uart->StopBits,
+ &NewTerminalContext->StopBits,
+ sizeof (UINT8)
+ );
+ //
+ // Change the device path in the ComPort
+ //
+ if (ChangeTerminal) {
+ Node1 = NewTerminalContext->DevicePath;
+ Node1 = NextDevicePathNode (Node1);
+ while (!IsDevicePathEnd (Node1)) {
+ if ((DevicePathType (Node1) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node1) == MSG_UART_DP)) {
+ Uart1 = (UART_DEVICE_PATH *) Node1;
+ CopyMem (
+ &Uart1->BaudRate,
+ &NewTerminalContext->BaudRate,
+ sizeof (UINT64)
+ );
+
+ CopyMem (
+ &Uart1->DataBits,
+ &NewTerminalContext->DataBits,
+ sizeof (UINT8)
+ );
+
+ CopyMem (
+ &Uart1->Parity,
+ &NewTerminalContext->Parity,
+ sizeof (UINT8)
+ );
+
+ CopyMem (
+ &Uart1->StopBits,
+ &NewTerminalContext->StopBits,
+ sizeof (UINT8)
+ );
+ break;
+ }
+ //
+ // end if
+ //
+ Node1 = NextDevicePathNode (Node1);
+ }
+ //
+ // end while
+ //
+ break;
+ }
+ }
+
+ Node = NextDevicePathNode (Node);
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+VOID
+ChangeVariableDevicePath (
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+ ACPI_HID_DEVICE_PATH *Acpi;
+ UART_DEVICE_PATH *Uart;
+ UINTN Com;
+ UINT32 Match;
+ BM_TERMINAL_CONTEXT *NewTerminalContext;
+ BM_MENU_ENTRY *NewMenuEntry;
+
+ Match = EISA_PNP_ID (0x0501);
+ Node = DevicePath;
+ Node = NextDevicePathNode (Node);
+ Com = 0;
+ while (!IsDevicePathEnd (Node)) {
+ if ((DevicePathType (Node) == ACPI_DEVICE_PATH) && (DevicePathSubType (Node) == ACPI_DP)) {
+ Acpi = (ACPI_HID_DEVICE_PATH *) Node;
+ if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) {
+ CopyMem (&Com, &Acpi->UID, sizeof (UINT32));
+ }
+ }
+
+ if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) {
+ NewMenuEntry = BOpt_GetMenuEntry (
+ &TerminalMenu,
+ Com
+ );
+ ASSERT (NewMenuEntry != NULL);
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
+ Uart = (UART_DEVICE_PATH *) Node;
+ CopyMem (
+ &Uart->BaudRate,
+ &NewTerminalContext->BaudRate,
+ sizeof (UINT64)
+ );
+
+ CopyMem (
+ &Uart->DataBits,
+ &NewTerminalContext->DataBits,
+ sizeof (UINT8)
+ );
+
+ CopyMem (
+ &Uart->Parity,
+ &NewTerminalContext->Parity,
+ sizeof (UINT8)
+ );
+
+ CopyMem (
+ &Uart->StopBits,
+ &NewTerminalContext->StopBits,
+ sizeof (UINT8)
+ );
+ }
+
+ Node = NextDevicePathNode (Node);
+ }
+
+ return ;
+}
+
+BOOLEAN
+RetrieveUartUid (
+ IN EFI_HANDLE Handle,
+ IN OUT UINT32 *AcpiUid
+ )
+/*++
+
+Routine Description:
+ Retrieve ACPI UID of UART from device path
+
+Arguments:
+ Handles - EFI_SERIAL_IO_PROTOCOL handle
+
+Returns:
+ TRUE - Find valid UID from device path
+ FALSE - Can't find
+
+--*/
+{
+ UINT32 Match;
+ UINT8 *Ptr;
+ ACPI_HID_DEVICE_PATH *Acpi;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ gBS->HandleProtocol (
+ Handle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath
+ );
+ Ptr = (UINT8 *) DevicePath;
+
+ while (*Ptr != END_DEVICE_PATH_TYPE) {
+ Ptr++;
+ }
+
+ Ptr = Ptr - sizeof (UART_DEVICE_PATH) - sizeof (ACPI_HID_DEVICE_PATH);
+ Acpi = (ACPI_HID_DEVICE_PATH *) Ptr;
+ Match = EISA_PNP_ID (0x0501);
+
+ if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) {
+ if (AcpiUid != NULL) {
+ *AcpiUid = Acpi->UID;
+ }
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+VOID
+SortedUartHandle (
+ IN EFI_HANDLE *Handles,
+ IN UINTN NoHandles
+ )
+/*++
+
+Routine Description:
+ Sort Uart handles array with Acpi->UID from low to high
+
+Arguments:
+ Handles - EFI_SERIAL_IO_PROTOCOL handle buffer
+ NoHandles - EFI_SERIAL_IO_PROTOCOL handle count
+
+Returns:
+ None
+
+--*/
+{
+ UINTN Index1;
+ UINTN Index2;
+ UINTN Position;
+ UINT32 AcpiUid1;
+ UINT32 AcpiUid2;
+ UINT32 TempAcpiUid;
+ EFI_HANDLE TempHandle;
+
+ for (Index1 = 0; Index1 < NoHandles-1; Index1++) {
+ if (!RetrieveUartUid (Handles[Index1], &AcpiUid1)) {
+ continue;
+ }
+ TempHandle = Handles[Index1];
+ Position = Index1;
+ TempAcpiUid = AcpiUid1;
+
+ for (Index2 = Index1+1; Index2 < NoHandles; Index2++) {
+ if (!RetrieveUartUid (Handles[Index2], &AcpiUid2)) {
+ continue;
+ }
+ if (AcpiUid2 < TempAcpiUid) {
+ TempAcpiUid = AcpiUid2;
+ TempHandle = Handles[Index2];
+ Position = Index2;
+ }
+ }
+ Handles[Position] = Handles[Index1];
+ Handles[Index1] = TempHandle;
+ }
+}
+
+BOOLEAN
+IsTerminalDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT TYPE_OF_TERMINAL *Termi,
+ OUT UINTN *Com
+ );
+
+EFI_STATUS
+LocateSerialIo (
+ VOID
+ )
+/*++
+
+Routine Description:
+ Build a list containing all serial devices
+
+Arguments:
+
+Returns:
+
+--*/
+{
+ UINT8 *Ptr;
+ UINTN Index;
+ UINTN Index2;
+ UINTN NoHandles;
+ EFI_HANDLE *Handles;
+ EFI_STATUS Status;
+ ACPI_HID_DEVICE_PATH *Acpi;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINT32 Match;
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;
+ EFI_DEVICE_PATH_PROTOCOL *OutDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *InpDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *ErrDevicePath;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_TERMINAL_CONTEXT *NewTerminalContext;
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
+ VENDOR_DEVICE_PATH Vendor;
+ //
+ // Get all handles that have SerialIo protocol installed
+ //
+ InitializeListHead (&TerminalMenu.Head);
+ TerminalMenu.MenuNumber = 0;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSerialIoProtocolGuid,
+ NULL,
+ &NoHandles,
+ &Handles
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // No serial ports present
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Sort Uart handles array with Acpi->UID from low to high
+ // then Terminal menu can be built from low Acpi->UID to high Acpi->UID
+ //
+ SortedUartHandle (Handles, NoHandles);
+
+ for (Index = 0; Index < NoHandles; Index++) {
+ //
+ // Check to see whether the handle has DevicePath Protocol installed
+ //
+ gBS->HandleProtocol (
+ Handles[Index],
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath
+ );
+ Ptr = (UINT8 *) DevicePath;
+ while (*Ptr != END_DEVICE_PATH_TYPE) {
+ Ptr++;
+ }
+
+ Ptr = Ptr - sizeof (UART_DEVICE_PATH) - sizeof (ACPI_HID_DEVICE_PATH);
+ Acpi = (ACPI_HID_DEVICE_PATH *) Ptr;
+ Match = EISA_PNP_ID (0x0501);
+
+ if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) {
+ NewMenuEntry = BOpt_CreateMenuEntry (BM_TERMINAL_CONTEXT_SELECT);
+ if (!NewMenuEntry) {
+ SafeFreePool (Handles);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
+ CopyMem (&NewMenuEntry->OptionNumber, &Acpi->UID, sizeof (UINT32));
+ NewTerminalContext->DevicePath = DevicePathInstanceDup (DevicePath);
+ //
+ // BugBug: I have no choice, calling EfiLibStrFromDatahub will hang the system!
+ // coz' the misc data for each platform is not correct, actually it's the device path stored in
+ // datahub which is not completed, so a searching for end of device path will enter a
+ // dead-loop.
+ //
+ NewMenuEntry->DisplayString = EfiLibStrFromDatahub (DevicePath);
+ if (NULL == NewMenuEntry->DisplayString) {
+ NewMenuEntry->DisplayString = DevicePathToStr (DevicePath);
+ }
+
+ NewMenuEntry->HelpString = NULL;
+
+ gBS->HandleProtocol (
+ Handles[Index],
+ &gEfiSerialIoProtocolGuid,
+ (VOID **) &SerialIo
+ );
+
+ CopyMem (
+ &NewTerminalContext->BaudRate,
+ &SerialIo->Mode->BaudRate,
+ sizeof (UINT64)
+ );
+
+ CopyMem (
+ &NewTerminalContext->DataBits,
+ &SerialIo->Mode->DataBits,
+ sizeof (UINT8)
+ );
+
+ CopyMem (
+ &NewTerminalContext->Parity,
+ &SerialIo->Mode->Parity,
+ sizeof (UINT8)
+ );
+
+ CopyMem (
+ &NewTerminalContext->StopBits,
+ &SerialIo->Mode->StopBits,
+ sizeof (UINT8)
+ );
+ InsertTailList (&TerminalMenu.Head, &NewMenuEntry->Link);
+ TerminalMenu.MenuNumber++;
+ }
+ }
+ SafeFreePool (Handles);
+
+ //
+ // Get L"ConOut", L"ConIn" and L"ErrOut" from the Var
+ //
+ OutDevicePath = EfiLibGetVariable (L"ConOut", &gEfiGlobalVariableGuid);
+ InpDevicePath = EfiLibGetVariable (L"ConIn", &gEfiGlobalVariableGuid);
+ ErrDevicePath = EfiLibGetVariable (L"ErrOut", &gEfiGlobalVariableGuid);
+ if (OutDevicePath) {
+ UpdateComAttributeFromVariable (OutDevicePath);
+ }
+
+ if (InpDevicePath) {
+ UpdateComAttributeFromVariable (InpDevicePath);
+ }
+
+ if (ErrDevicePath) {
+ UpdateComAttributeFromVariable (ErrDevicePath);
+ }
+
+ for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);
+ if (NULL == NewMenuEntry) {
+ return EFI_NOT_FOUND;
+ }
+
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
+
+ NewTerminalContext->TerminalType = 0;
+ NewTerminalContext->IsConIn = FALSE;
+ NewTerminalContext->IsConOut = FALSE;
+ NewTerminalContext->IsStdErr = FALSE;
+
+ Vendor.Header.Type = MESSAGING_DEVICE_PATH;
+ Vendor.Header.SubType = MSG_VENDOR_DP;
+
+ for (Index2 = 0; Index2 < 4; Index2++) {
+ CopyMem (&Vendor.Guid, &Guid[Index2], sizeof (EFI_GUID));
+ SetDevicePathNodeLength (&Vendor.Header, sizeof (VENDOR_DEVICE_PATH));
+ NewDevicePath = AppendDevicePathNode (
+ NewTerminalContext->DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &Vendor
+ );
+ SafeFreePool (NewMenuEntry->HelpString);
+ //
+ // NewMenuEntry->HelpString = DevicePathToStr (NewDevicePath);
+ // NewMenuEntry->DisplayString = NewMenuEntry->HelpString;
+ //
+ NewMenuEntry->HelpString = NULL;
+
+ if (BdsLibMatchDevicePaths (OutDevicePath, NewDevicePath)) {
+ NewTerminalContext->IsConOut = TRUE;
+ NewTerminalContext->TerminalType = (UINT8) Index2;
+ }
+
+ if (BdsLibMatchDevicePaths (InpDevicePath, NewDevicePath)) {
+ NewTerminalContext->IsConIn = TRUE;
+ NewTerminalContext->TerminalType = (UINT8) Index2;
+ }
+
+ if (BdsLibMatchDevicePaths (ErrDevicePath, NewDevicePath)) {
+ NewTerminalContext->IsStdErr = TRUE;
+ NewTerminalContext->TerminalType = (UINT8) Index2;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+UpdateComAttributeFromVariable (
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+/*++
+
+Routine Description:
+ Update Com Ports attributes from DevicePath
+
+Arguments:
+ DevicePath - DevicePath that contains Com ports
+
+Returns:
+
+--*/
+{
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+ EFI_DEVICE_PATH_PROTOCOL *SerialNode;
+ ACPI_HID_DEVICE_PATH *Acpi;
+ UART_DEVICE_PATH *Uart;
+ UART_DEVICE_PATH *Uart1;
+ UINT32 Match;
+ UINTN TerminalNumber;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_TERMINAL_CONTEXT *NewTerminalContext;
+ UINTN Index;
+
+ Match = EISA_PNP_ID (0x0501);
+ Node = DevicePath;
+ Node = NextDevicePathNode (Node);
+ TerminalNumber = 0;
+ for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
+ while (!IsDevicePathEnd (Node)) {
+ if ((DevicePathType (Node) == ACPI_DEVICE_PATH) && (DevicePathSubType (Node) == ACPI_DP)) {
+ Acpi = (ACPI_HID_DEVICE_PATH *) Node;
+ if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) {
+ CopyMem (&TerminalNumber, &Acpi->UID, sizeof (UINT32));
+ }
+ }
+
+ if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) {
+ Uart = (UART_DEVICE_PATH *) Node;
+ NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, TerminalNumber);
+ if (NULL == NewMenuEntry) {
+ return EFI_NOT_FOUND;
+ }
+
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
+ CopyMem (
+ &NewTerminalContext->BaudRate,
+ &Uart->BaudRate,
+ sizeof (UINT64)
+ );
+
+ CopyMem (
+ &NewTerminalContext->DataBits,
+ &Uart->DataBits,
+ sizeof (UINT8)
+ );
+
+ CopyMem (
+ &NewTerminalContext->Parity,
+ &Uart->Parity,
+ sizeof (UINT8)
+ );
+
+ CopyMem (
+ &NewTerminalContext->StopBits,
+ &Uart->StopBits,
+ sizeof (UINT8)
+ );
+
+ SerialNode = NewTerminalContext->DevicePath;
+ SerialNode = NextDevicePathNode (SerialNode);
+ while (!IsDevicePathEnd (SerialNode)) {
+ if ((DevicePathType (SerialNode) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (SerialNode) == MSG_UART_DP)) {
+ //
+ // Update following device paths according to
+ // previous acquired uart attributes
+ //
+ Uart1 = (UART_DEVICE_PATH *) SerialNode;
+ CopyMem (
+ &Uart1->BaudRate,
+ &NewTerminalContext->BaudRate,
+ sizeof (UINT64)
+ );
+
+ CopyMem (
+ &Uart1->DataBits,
+ &NewTerminalContext->DataBits,
+ sizeof (UINT8)
+ );
+ CopyMem (
+ &Uart1->Parity,
+ &NewTerminalContext->Parity,
+ sizeof (UINT8)
+ );
+ CopyMem (
+ &Uart1->StopBits,
+ &NewTerminalContext->StopBits,
+ sizeof (UINT8)
+ );
+
+ break;
+ }
+
+ SerialNode = NextDevicePathNode (SerialNode);
+ }
+ //
+ // end while
+ //
+ }
+
+ Node = NextDevicePathNode (Node);
+ }
+ //
+ // end while
+ //
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_DEVICE_PATH_PROTOCOL *
+DevicePathInstanceDup (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevPath
+ )
+/*++
+
+Routine Description:
+ Function creates a device path data structure that identically matches the
+ device path passed in.
+
+Arguments:
+ DevPath - A pointer to a device path data structure.
+
+Returns:
+
+ The new copy of DevPath is created to identically match the input.
+ Otherwise, NULL is returned.
+
+--*/
+{
+ EFI_DEVICE_PATH_PROTOCOL *NewDevPath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;
+ EFI_DEVICE_PATH_PROTOCOL *Temp;
+ UINT8 *Ptr;
+ UINTN Size;
+
+ //
+ // get the size of an instance from the input
+ //
+ Temp = DevPath;
+ DevicePathInst = GetNextDevicePathInstance (&Temp, &Size);
+
+ //
+ // Make a copy and set proper end type
+ //
+ NewDevPath = NULL;
+ if (Size) {
+ NewDevPath = EfiAllocateZeroPool (Size);
+ ASSERT (NewDevPath != NULL);
+ }
+
+ if (NewDevPath) {
+ CopyMem (NewDevPath, DevicePathInst, Size);
+ Ptr = (UINT8 *) NewDevPath;
+ Ptr += Size - sizeof (EFI_DEVICE_PATH_PROTOCOL);
+ Temp = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
+ SetDevicePathEndNode (Temp);
+ }
+
+ return NewDevPath;
+}
+
+EFI_STATUS
+GetConsoleMenu (
+ IN UINTN ConsoleMenuType
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *AllDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *MultiDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;
+ UINTN Size;
+ UINTN AllCount;
+ UINTN Index;
+ UINTN Index2;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_CONSOLE_CONTEXT *NewConsoleContext;
+ TYPE_OF_TERMINAL Terminal;
+ UINTN Com;
+ BM_MENU_OPTION *ConsoleMenu;
+
+ DevicePath = NULL;
+ AllDevicePath = NULL;
+ AllCount = 0;
+ switch (ConsoleMenuType) {
+ case BM_CONSOLE_IN_CONTEXT_SELECT:
+ ConsoleMenu = &ConsoleInpMenu;
+ DevicePath = EfiLibGetVariable (
+ L"ConIn",
+ &gEfiGlobalVariableGuid
+ );
+
+ AllDevicePath = EfiLibGetVariable (
+ L"ConInDev",
+ &gEfiGlobalVariableGuid
+ );
+ break;
+
+ case BM_CONSOLE_OUT_CONTEXT_SELECT:
+ ConsoleMenu = &ConsoleOutMenu;
+ DevicePath = EfiLibGetVariable (
+ L"ConOut",
+ &gEfiGlobalVariableGuid
+ );
+
+ AllDevicePath = EfiLibGetVariable (
+ L"ConOutDev",
+ &gEfiGlobalVariableGuid
+ );
+ break;
+
+ case BM_CONSOLE_ERR_CONTEXT_SELECT:
+ ConsoleMenu = &ConsoleErrMenu;
+ DevicePath = EfiLibGetVariable (
+ L"ErrOut",
+ &gEfiGlobalVariableGuid
+ );
+
+ AllDevicePath = EfiLibGetVariable (
+ L"ErrOutDev",
+ &gEfiGlobalVariableGuid
+ );
+ break;
+
+ default:
+ return EFI_UNSUPPORTED;
+ }
+
+ if (NULL == AllDevicePath) {
+ return EFI_NOT_FOUND;
+ }
+
+ InitializeListHead (&ConsoleMenu->Head);
+
+ AllCount = EfiDevicePathInstanceCount (AllDevicePath);
+ ConsoleMenu->MenuNumber = 0;
+ //
+ // Following is menu building up for Console Out Devices
+ //
+ MultiDevicePath = AllDevicePath;
+ Index2 = 0;
+ for (Index = 0; Index < AllCount; Index++) {
+ DevicePathInst = GetNextDevicePathInstance (&MultiDevicePath, &Size);
+
+ NewMenuEntry = BOpt_CreateMenuEntry (BM_CONSOLE_CONTEXT_SELECT);
+ if (NULL == NewMenuEntry) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;
+ NewMenuEntry->OptionNumber = Index2;
+
+ NewConsoleContext->DevicePath = DevicePathInstanceDup (DevicePathInst);
+ NewMenuEntry->DisplayString = EfiLibStrFromDatahub (NewConsoleContext->DevicePath);
+ if (NULL == NewMenuEntry->DisplayString) {
+ NewMenuEntry->DisplayString = DevicePathToStr (NewConsoleContext->DevicePath);
+ }
+
+ NewConsoleContext->IsTerminal = IsTerminalDevicePath (
+ NewConsoleContext->DevicePath,
+ &Terminal,
+ &Com
+ );
+
+ NewConsoleContext->IsActive = BdsLibMatchDevicePaths (
+ DevicePath,
+ NewConsoleContext->DevicePath
+ );
+
+ if (NewConsoleContext->IsTerminal) {
+ BOpt_DestroyMenuEntry (NewMenuEntry);
+ } else {
+ Index2++;
+ ConsoleMenu->MenuNumber++;
+ InsertTailList (&ConsoleMenu->Head, &NewMenuEntry->Link);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+GetAllConsoles (
+ VOID
+ )
+/*++
+
+Routine Description:
+ Build up ConsoleOutMenu, ConsoleInpMenu and ConsoleErrMenu
+
+Arguments:
+
+Returns:
+ EFI_SUCCESS
+ Others
+
+--*/
+{
+ GetConsoleMenu (BM_CONSOLE_IN_CONTEXT_SELECT);
+ GetConsoleMenu (BM_CONSOLE_OUT_CONTEXT_SELECT);
+ GetConsoleMenu (BM_CONSOLE_ERR_CONTEXT_SELECT);
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+FreeAllConsoles (
+ VOID
+ )
+/*++
+
+Routine Description:
+ Free ConsoleOutMenu, ConsoleInpMenu and ConsoleErrMenu
+
+Arguments:
+
+Returns:
+ EFI_SUCCESS
+ Others
+
+--*/
+{
+ BOpt_FreeMenu (&ConsoleOutMenu);
+ BOpt_FreeMenu (&ConsoleInpMenu);
+ BOpt_FreeMenu (&ConsoleErrMenu);
+ BOpt_FreeMenu (&TerminalMenu);
+ return EFI_SUCCESS;
+}
+
+BOOLEAN
+IsTerminalDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT TYPE_OF_TERMINAL *Termi,
+ OUT UINTN *Com
+ )
+/*++
+
+Routine Description:
+ Test whether DevicePath is a valid Terminal
+
+Arguments:
+ DevicePath - DevicePath to be checked
+ Termi - If is terminal, give its type
+ Com - If is Com Port, give its type
+
+Returns:
+ TRUE - If DevicePath point to a Terminal
+ FALSE
+
+--*/
+{
+ UINT8 *Ptr;
+ BOOLEAN IsTerminal;
+ VENDOR_DEVICE_PATH *Vendor;
+ ACPI_HID_DEVICE_PATH *Acpi;
+ UINT32 Match;
+ EFI_GUID TempGuid;
+
+ IsTerminal = FALSE;
+
+ //
+ // Parse the Device Path, should be change later!!!
+ //
+ Ptr = (UINT8 *) DevicePath;
+ while (*Ptr != END_DEVICE_PATH_TYPE) {
+ Ptr++;
+ }
+
+ Ptr = Ptr - sizeof (VENDOR_DEVICE_PATH);
+ Vendor = (VENDOR_DEVICE_PATH *) Ptr;
+
+ //
+ // There are four kinds of Terminal types
+ // check to see whether this devicepath
+ // is one of that type
+ //
+ CopyMem (&TempGuid, &Vendor->Guid, sizeof (EFI_GUID));
+
+ if (CompareGuid (&TempGuid, &Guid[0])) {
+ *Termi = PC_ANSI;
+ IsTerminal = TRUE;
+ } else {
+ if (CompareGuid (&TempGuid, &Guid[1])) {
+ *Termi = VT_100;
+ IsTerminal = TRUE;
+ } else {
+ if (CompareGuid (&TempGuid, &Guid[2])) {
+ *Termi = VT_100_PLUS;
+ IsTerminal = TRUE;
+ } else {
+ if (CompareGuid (&TempGuid, &Guid[3])) {
+ *Termi = VT_UTF8;
+ IsTerminal = TRUE;
+ } else {
+ IsTerminal = FALSE;
+ }
+ }
+ }
+ }
+
+ if (!IsTerminal) {
+ return FALSE;
+ }
+
+ Ptr = Ptr - sizeof (UART_DEVICE_PATH) - sizeof (ACPI_HID_DEVICE_PATH);
+ Acpi = (ACPI_HID_DEVICE_PATH *) Ptr;
+ Match = EISA_PNP_ID (0x0501);
+ if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) {
+ CopyMem (Com, &Acpi->UID, sizeof (UINT32));
+ } else {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+VOID
+GetConsoleOutMode (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+/*++
+
+Routine Description:
+ Get mode number according to column and row
+
+Arguments:
+ CallbackData - BMM_CALLBACK_DATA
+
+Returns:
+ None.
+
+--*/
+{
+ UINTN Col;
+ UINTN Row;
+ UINTN CurrentCol;
+ UINTN CurrentRow;
+ UINTN Mode;
+ UINTN MaxMode;
+ EFI_STATUS Status;
+ CONSOLE_OUT_MODE *ModeInfo;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
+
+ ConOut = gST->ConOut;
+ MaxMode = (UINTN) (ConOut->Mode->MaxMode);
+ ModeInfo = EfiLibGetVariable (VarConOutMode, &gEfiGenericPlatformVariableGuid);
+
+ if (ModeInfo != NULL) {
+ CurrentCol = ModeInfo->Column;
+ CurrentRow = ModeInfo->Row;
+ for (Mode = 0; Mode < MaxMode; Mode++) {
+ Status = ConOut->QueryMode (ConOut, Mode, &Col, &Row);
+ if (!EFI_ERROR(Status)) {
+ if (CurrentCol == Col && CurrentRow == Row) {
+ CallbackData->BmmFakeNvData.ConsoleOutMode = (UINT16) Mode;
+ break;
+ }
+ }
+ }
+ }
+ SafeFreePool (ModeInfo);
+}
diff --git a/MdeModulePkg/Universal/BdsDxe/BootMaint/Data.c b/MdeModulePkg/Universal/BdsDxe/BootMaint/Data.c new file mode 100644 index 0000000000..598d3c1075 --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/BootMaint/Data.c @@ -0,0 +1,324 @@ +/*++
+
+Copyright (c) 2004 - 2007, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ Data.c
+
+Abstract:
+
+ Define some data used for Boot Maint
+
+Revision History
+
+--*/
+
+#include "BootMaint.h"
+
+EFI_HII_UPDATE_DATA gUpdateData;
+STRING_DEPOSITORY *FileOptionStrDepository;
+STRING_DEPOSITORY *ConsoleOptionStrDepository;
+STRING_DEPOSITORY *BootOptionStrDepository;
+STRING_DEPOSITORY *BootOptionHelpStrDepository;
+STRING_DEPOSITORY *DriverOptionStrDepository;
+STRING_DEPOSITORY *DriverOptionHelpStrDepository;
+STRING_DEPOSITORY *TerminalStrDepository;
+
+//
+// Terminal type string token storage
+//
+UINT16 TerminalType[] = {
+ STRING_TOKEN(STR_COM_TYPE_0),
+ STRING_TOKEN(STR_COM_TYPE_1),
+ STRING_TOKEN(STR_COM_TYPE_2),
+ STRING_TOKEN(STR_COM_TYPE_3),
+};
+
+//
+// File system selection menu
+//
+BM_MENU_OPTION FsOptionMenu = {
+ BM_MENU_OPTION_SIGNATURE,
+ NULL,
+ 0
+};
+
+//
+// Console Input Device Selection Menu
+//
+BM_MENU_OPTION ConsoleInpMenu = {
+ BM_MENU_OPTION_SIGNATURE,
+ NULL,
+ 0
+};
+
+//
+// Console Output Device Selection Menu
+//
+BM_MENU_OPTION ConsoleOutMenu = {
+ BM_MENU_OPTION_SIGNATURE,
+ NULL,
+ 0
+};
+
+//
+// Error Output Device Selection Menu
+//
+BM_MENU_OPTION ConsoleErrMenu = {
+ BM_MENU_OPTION_SIGNATURE,
+ NULL,
+ 0
+};
+
+//
+// Boot Option from variable Menu
+//
+BM_MENU_OPTION BootOptionMenu = {
+ BM_MENU_OPTION_SIGNATURE,
+ NULL,
+ 0
+};
+
+//
+// Driver Option from variable menu
+//
+BM_MENU_OPTION DriverOptionMenu = {
+ BM_MENU_OPTION_SIGNATURE,
+ NULL,
+ 0
+};
+
+//
+// Legacy FD Info from LegacyBios.GetBbsInfo()
+//
+BM_MENU_OPTION LegacyFDMenu = {
+ BM_MENU_OPTION_SIGNATURE,
+ NULL,
+ 0
+};
+
+//
+// Legacy HD Info from LegacyBios.GetBbsInfo()
+//
+BM_MENU_OPTION LegacyHDMenu = {
+ BM_MENU_OPTION_SIGNATURE,
+ NULL,
+ 0
+};
+
+//
+// Legacy CD Info from LegacyBios.GetBbsInfo()
+//
+BM_MENU_OPTION LegacyCDMenu = {
+ BM_MENU_OPTION_SIGNATURE,
+ NULL,
+ 0
+};
+
+//
+// Legacy NET Info from LegacyBios.GetBbsInfo()
+//
+BM_MENU_OPTION LegacyNETMenu = {
+ BM_MENU_OPTION_SIGNATURE,
+ NULL,
+ 0
+};
+
+//
+// Legacy NET Info from LegacyBios.GetBbsInfo()
+//
+BM_MENU_OPTION LegacyBEVMenu = {
+ BM_MENU_OPTION_SIGNATURE,
+ NULL,
+ 0
+};
+
+//
+// Files and sub-directories in current directory menu
+//
+BM_MENU_OPTION DirectoryMenu = {
+ BM_MENU_OPTION_SIGNATURE,
+ NULL,
+ 0
+};
+
+//
+// Handles in current system selection menu
+//
+BM_MENU_OPTION DriverMenu = {
+ BM_MENU_OPTION_SIGNATURE,
+ NULL,
+ 0
+};
+
+BM_MENU_OPTION TerminalMenu = {
+ BM_MENU_OPTION_SIGNATURE,
+ NULL,
+ 0
+};
+
+//
+// Value and string token correspondency for BaudRate
+//
+COM_ATTR BaudRateList[19] = {
+ {
+ 115200,
+ STRING_TOKEN(STR_COM_BAUD_RATE_0)
+ },
+ {
+ 57600,
+ STRING_TOKEN(STR_COM_BAUD_RATE_1)
+ },
+ {
+ 38400,
+ STRING_TOKEN(STR_COM_BAUD_RATE_2)
+ },
+ {
+ 19200,
+ STRING_TOKEN(STR_COM_BAUD_RATE_3)
+ },
+ {
+ 9600,
+ STRING_TOKEN(STR_COM_BAUD_RATE_4)
+ },
+ {
+ 7200,
+ STRING_TOKEN(STR_COM_BAUD_RATE_5)
+ },
+ {
+ 4800,
+ STRING_TOKEN(STR_COM_BAUD_RATE_6)
+ },
+ {
+ 3600,
+ STRING_TOKEN(STR_COM_BAUD_RATE_7)
+ },
+ {
+ 2400,
+ STRING_TOKEN(STR_COM_BAUD_RATE_8)
+ },
+ {
+ 2000,
+ STRING_TOKEN(STR_COM_BAUD_RATE_9)
+ },
+ {
+ 1800,
+ STRING_TOKEN(STR_COM_BAUD_RATE_10)
+ },
+ {
+ 1200,
+ STRING_TOKEN(STR_COM_BAUD_RATE_11)
+ },
+ {
+ 600,
+ STRING_TOKEN(STR_COM_BAUD_RATE_12)
+ },
+ {
+ 300,
+ STRING_TOKEN(STR_COM_BAUD_RATE_13)
+ },
+ {
+ 150,
+ STRING_TOKEN(STR_COM_BAUD_RATE_14)
+ },
+ {
+ 134,
+ STRING_TOKEN(STR_COM_BAUD_RATE_15)
+ },
+ {
+ 110,
+ STRING_TOKEN(STR_COM_BAUD_RATE_16)
+ },
+ {
+ 75,
+ STRING_TOKEN(STR_COM_BAUD_RATE_17)
+ },
+ {
+ 50,
+ STRING_TOKEN(STR_COM_BAUD_RATE_18)
+ }
+};
+
+//
+// Value and string token correspondency for DataBits
+//
+COM_ATTR DataBitsList[4] = {
+ {
+ 5,
+ STRING_TOKEN(STR_COM_DATA_BITS_0)
+ },
+ {
+ 6,
+ STRING_TOKEN(STR_COM_DATA_BITS_1)
+ },
+ {
+ 7,
+ STRING_TOKEN(STR_COM_DATA_BITS_2)
+ },
+ {
+ 8,
+ STRING_TOKEN(STR_COM_DATA_BITS_3)
+ }
+};
+
+//
+// Value and string token correspondency for Parity
+//
+COM_ATTR ParityList[5] = {
+ {
+ NoParity,
+ STRING_TOKEN(STR_COM_PAR_0)
+ },
+ {
+ EvenParity,
+ STRING_TOKEN(STR_COM_PAR_1)
+ },
+ {
+ OddParity,
+ STRING_TOKEN(STR_COM_PAR_2)
+ },
+ {
+ MarkParity,
+ STRING_TOKEN(STR_COM_PAR_3)
+ },
+ {
+ SpaceParity,
+ STRING_TOKEN(STR_COM_PAR_4)
+ }
+};
+
+//
+// Value and string token correspondency for Baudreate
+//
+COM_ATTR StopBitsList[3] = {
+ {
+ OneStopBit,
+ STRING_TOKEN(STR_COM_STOP_BITS_0)
+ },
+ {
+ OneFiveStopBits,
+ STRING_TOKEN(STR_COM_STOP_BITS_1)
+ },
+ {
+ TwoStopBits,
+ STRING_TOKEN(STR_COM_STOP_BITS_2)
+ }
+};
+
+//
+// Guid for messaging path, used in Serial port setting.
+//
+EFI_GUID Guid[4] = {
+ DEVICE_PATH_MESSAGING_PC_ANSI,
+ DEVICE_PATH_MESSAGING_VT_100,
+ DEVICE_PATH_MESSAGING_VT_100_PLUS,
+ DEVICE_PATH_MESSAGING_VT_UTF8
+};
diff --git a/MdeModulePkg/Universal/BdsDxe/BootMaint/FE.vfr b/MdeModulePkg/Universal/BdsDxe/BootMaint/FE.vfr new file mode 100644 index 0000000000..97d432185c --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/BootMaint/FE.vfr @@ -0,0 +1,134 @@ +// *++
+//
+// Copyright (c) 2004 - 2007, Intel Corporation
+// All rights reserved. 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.
+//
+// Module Name:
+//
+// FE.vfr
+//
+// Abstract:
+//
+// File Explorer Formset
+//
+// Revision History:
+//
+// --*/
+
+#include "FormGuid.h"
+
+#define LABEL_END 0xffff
+
+formset
+ guid = FILE_EXPLORE_FORMSET_GUID,
+ title = STRING_TOKEN(STR_FILE_EXPLORER_TITLE),
+ help = STRING_TOKEN(STR_NULL_STRING),
+ class = 0,
+ subclass = 0,
+
+ varstore FILE_EXPLORER_NV_DATA,
+ varid = VARSTORE_ID_BOOT_MAINT,
+ name = FeData,
+ guid = FILE_EXPLORE_FORMSET_GUID;
+
+ form formid = FORM_FILE_EXPLORER_ID,
+ title = STRING_TOKEN(STR_FILE_EXPLORER_TITLE);
+
+ label FORM_FILE_EXPLORER_ID;
+ label LABEL_END;
+ endform;
+
+ form formid = FORM_BOOT_ADD_DESCRIPTION_ID,
+ title = STRING_TOKEN(STR_FORM_BOOT_ADD_DESC_TITLE);
+
+ label FORM_BOOT_ADD_DESCRIPTION_ID;
+ label LABEL_END;
+
+ subtitle text = STRING_TOKEN(STR_NULL_STRING);
+
+ string varid = FeData.DescriptionData,
+ prompt = STRING_TOKEN(STR_LOAD_OPTION_DESC),
+ help = STRING_TOKEN(STR_NULL_STRING),
+ minsize = 6,
+ maxsize = 75,
+ endstring;
+
+ string varid = FeData.OptionalData,
+ prompt = STRING_TOKEN(STR_OPTIONAL_DATA),
+ help = STRING_TOKEN(STR_NULL_STRING),
+ minsize = 0,
+ maxsize = 120,
+ endstring;
+
+ subtitle text = STRING_TOKEN(STR_NULL_STRING);
+
+ text
+ help = STRING_TOKEN(STR_SAVE_AND_EXIT),
+ text = STRING_TOKEN(STR_SAVE_AND_EXIT),
+ text = STRING_TOKEN(STR_NULL_STRING),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_SAVE_AND_EXIT_BOOT;
+
+ text
+ help = STRING_TOKEN(STR_NO_SAVE_AND_EXIT),
+ text = STRING_TOKEN(STR_NO_SAVE_AND_EXIT),
+ text = STRING_TOKEN(STR_NULL_STRING),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_NO_SAVE_AND_EXIT_BOOT;
+
+ endform;
+
+ form formid = FORM_DRIVER_ADD_FILE_DESCRIPTION_ID,
+ title = STRING_TOKEN(STR_FORM_DRV_ADD_DESC_TITLE);
+
+ label FORM_DRIVER_ADD_FILE_DESCRIPTION_ID;
+ label LABEL_END;
+
+ subtitle text = STRING_TOKEN(STR_NULL_STRING);
+
+ string varid = FeData.DescriptionData,
+ prompt = STRING_TOKEN(STR_LOAD_OPTION_DESC),
+ help = STRING_TOKEN(STR_NULL_STRING),
+ minsize = 6,
+ maxsize = 75,
+ endstring;
+
+ string varid = FeData.OptionalData,
+ prompt = STRING_TOKEN(STR_OPTIONAL_DATA),
+ help = STRING_TOKEN(STR_NULL_STRING),
+ minsize = 0,
+ maxsize = 120,
+ endstring;
+
+ checkbox varid = FeData.ForceReconnect,
+ prompt = STRING_TOKEN(STR_LOAD_OPTION_FORCE_RECON),
+ help = STRING_TOKEN(STR_LOAD_OPTION_FORCE_RECON),
+ flags = CHECKBOX_DEFAULT,
+ key = 0,
+ endcheckbox;
+
+ subtitle text = STRING_TOKEN(STR_NULL_STRING);
+
+ text
+ help = STRING_TOKEN(STR_SAVE_AND_EXIT),
+ text = STRING_TOKEN(STR_SAVE_AND_EXIT),
+ text = STRING_TOKEN(STR_NULL_STRING),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_SAVE_AND_EXIT_DRIVER; //BUGBUB: allow duplicate key in one formset???
+
+ text
+ help = STRING_TOKEN(STR_NO_SAVE_AND_EXIT),
+ text = STRING_TOKEN(STR_NO_SAVE_AND_EXIT),
+ text = STRING_TOKEN(STR_NULL_STRING),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_NO_SAVE_AND_EXIT_DRIVER;
+
+ endform;
+
+endformset;
\ No newline at end of file diff --git a/MdeModulePkg/Universal/BdsDxe/BootMaint/FileExplorer.c b/MdeModulePkg/Universal/BdsDxe/BootMaint/FileExplorer.c new file mode 100644 index 0000000000..811702f1d3 --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/BootMaint/FileExplorer.c @@ -0,0 +1,327 @@ +/*++
+
+Copyright (c) 2004 - 2008, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ FileExplorer.c
+
+Abstract:
+
+ File explorer related functions.
+
+--*/
+
+#include "BootMaint.h"
+
+VOID
+UpdateFileExplorePage (
+ IN BMM_CALLBACK_DATA *CallbackData,
+ BM_MENU_OPTION *MenuOption
+ )
+/*++
+Routine Description:
+ Update the File Explore page.
+
+Arguments:
+ MenuOption - Pointer to menu options to display.
+
+Returns:
+ None.
+
+--*/
+{
+ UINTN Index;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_FILE_CONTEXT *NewFileContext;
+ EFI_FORM_ID FormId;
+
+ NewMenuEntry = NULL;
+ NewFileContext = NULL;
+ FormId = 0;
+
+ RefreshUpdateData ();
+
+ for (Index = 0; Index < MenuOption->MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (MenuOption, Index);
+ NewFileContext = (BM_FILE_CONTEXT *) NewMenuEntry->VariableContext;
+
+ if (NewFileContext->IsBootLegacy) {
+ continue;
+ }
+
+ if ((NewFileContext->IsDir) || (BOOT_FROM_FILE_STATE == CallbackData->FeCurrentState)) {
+ //
+ // Create Text opcode for directory, also create Text opcode for file in BOOT_FROM_FILE_STATE.
+ //
+ CreateActionOpCode (
+ (UINT16) (FILE_OPTION_OFFSET + Index),
+ NewMenuEntry->DisplayStringToken,
+ STRING_TOKEN (STR_NULL_STRING),
+ EFI_IFR_FLAG_CALLBACK,
+ 0,
+ &gUpdateData
+ );
+ } else {
+ //
+ // Create Goto opcode for file in ADD_BOOT_OPTION_STATE or ADD_DRIVER_OPTION_STATE.
+ //
+ if (ADD_BOOT_OPTION_STATE == CallbackData->FeCurrentState) {
+ FormId = FORM_BOOT_ADD_DESCRIPTION_ID;
+ } else if (ADD_DRIVER_OPTION_STATE == CallbackData->FeCurrentState) {
+ FormId = FORM_DRIVER_ADD_FILE_DESCRIPTION_ID;
+ }
+
+ CreateGotoOpCode (
+ FormId,
+ NewMenuEntry->DisplayStringToken,
+ STRING_TOKEN (STR_NULL_STRING),
+ EFI_IFR_FLAG_CALLBACK,
+ (UINT16) (FILE_OPTION_OFFSET + Index),
+ &gUpdateData
+ );
+ }
+ }
+
+ IfrLibUpdateForm (
+ CallbackData->FeHiiHandle,
+ &mFileExplorerGuid,
+ FORM_FILE_EXPLORER_ID,
+ FORM_FILE_EXPLORER_ID,
+ FALSE,
+ &gUpdateData
+ );
+}
+
+BOOLEAN
+UpdateFileExplorer (
+ IN BMM_CALLBACK_DATA *CallbackData,
+ IN UINT16 KeyValue
+ )
+/*++
+
+Routine Description:
+ Update the file explower page with the refershed file system.
+
+Arguments:
+ CallbackData - BMM context data
+ KeyValue - Key value to identify the type of data to expect.
+
+Returns:
+ TRUE - Inform the caller to create a callback packet to exit file explorer.
+ FALSE - Indicate that there is no need to exit file explorer.
+
+--*/
+{
+ UINT16 FileOptionMask;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_FILE_CONTEXT *NewFileContext;
+ EFI_FORM_ID FormId;
+ BOOLEAN ExitFileExplorer;
+ EFI_STATUS Status;
+
+ NewMenuEntry = NULL;
+ NewFileContext = NULL;
+ ExitFileExplorer = FALSE;
+
+ FileOptionMask = (UINT16) (FILE_OPTION_MASK & KeyValue);
+
+ if (UNKNOWN_CONTEXT == CallbackData->FeDisplayContext) {
+ //
+ // First in, display file system.
+ //
+ BOpt_FreeMenu (&FsOptionMenu);
+ BOpt_FindFileSystem (CallbackData);
+ CreateMenuStringToken (CallbackData, CallbackData->FeHiiHandle, &FsOptionMenu);
+
+ UpdateFileExplorePage (CallbackData, &FsOptionMenu);
+
+ CallbackData->FeDisplayContext = FILE_SYSTEM;
+ } else {
+ if (FILE_SYSTEM == CallbackData->FeDisplayContext) {
+ NewMenuEntry = BOpt_GetMenuEntry (&FsOptionMenu, FileOptionMask);
+ } else if (DIRECTORY == CallbackData->FeDisplayContext) {
+ NewMenuEntry = BOpt_GetMenuEntry (&DirectoryMenu, FileOptionMask);
+ }
+
+ CallbackData->FeDisplayContext = DIRECTORY;
+
+ NewFileContext = (BM_FILE_CONTEXT *) NewMenuEntry->VariableContext;
+
+ if (NewFileContext->IsDir ) {
+ RemoveEntryList (&NewMenuEntry->Link);
+ BOpt_FreeMenu (&DirectoryMenu);
+ Status = BOpt_FindFiles (CallbackData, NewMenuEntry);
+ if (EFI_ERROR (Status)) {
+ ExitFileExplorer = TRUE;
+ goto exit;
+ }
+ CreateMenuStringToken (CallbackData, CallbackData->FeHiiHandle, &DirectoryMenu);
+ BOpt_DestroyMenuEntry (NewMenuEntry);
+
+ UpdateFileExplorePage (CallbackData, &DirectoryMenu);
+
+ } else {
+ switch (CallbackData->FeCurrentState) {
+ case BOOT_FROM_FILE_STATE:
+ //
+ // Here boot from file
+ //
+ BootThisFile (NewFileContext);
+ ExitFileExplorer = TRUE;
+ break;
+
+ case ADD_BOOT_OPTION_STATE:
+ case ADD_DRIVER_OPTION_STATE:
+ if (ADD_BOOT_OPTION_STATE == CallbackData->FeCurrentState) {
+ FormId = FORM_BOOT_ADD_DESCRIPTION_ID;
+ } else {
+ FormId = FORM_DRIVER_ADD_FILE_DESCRIPTION_ID;
+ }
+
+ CallbackData->MenuEntry = NewMenuEntry;
+ CallbackData->LoadContext->FilePathList = ((BM_FILE_CONTEXT *) (CallbackData->MenuEntry->VariableContext))->DevicePath;
+
+ //
+ // Create Subtitle op-code for the display string of the option.
+ //
+ RefreshUpdateData ();
+
+ CreateSubTitleOpCode (
+ NewMenuEntry->DisplayStringToken,
+ 0,
+ 0,
+ 0,
+ &gUpdateData
+ );
+
+ IfrLibUpdateForm (
+ CallbackData->FeHiiHandle,
+ &mFileExplorerGuid,
+ FormId,
+ FormId,
+ FALSE,
+ &gUpdateData
+ );
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ exit:
+ return ExitFileExplorer;
+}
+
+EFI_STATUS
+EFIAPI
+FileExplorerCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+/*++
+
+ Routine Description:
+ This function processes the results of changes in configuration.
+
+ Arguments:
+ This - Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ Action - Specifies the type of action taken by the browser.
+ QuestionId - A unique value which is sent to the original exporting driver
+ so that it can identify the type of data to expect.
+ Type - The type of value for the question.
+ Value - A pointer to the data being sent to the original exporting driver.
+ ActionRequest - On return, points to the action requested by the callback function.
+
+ Returns:
+ EFI_SUCCESS - The callback successfully handled the action.
+ EFI_OUT_OF_RESOURCES - Not enough storage is available to hold the variable and its data.
+ EFI_DEVICE_ERROR - The variable could not be saved.
+ EFI_UNSUPPORTED - The specified Action is not supported by the callback.
+
+--*/
+{
+ BMM_CALLBACK_DATA *Private;
+ FILE_EXPLORER_NV_DATA *NvRamMap;
+ EFI_STATUS Status;
+ UINTN BufferSize;
+
+ if ((Value == NULL) || (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ Private = FE_CALLBACK_DATA_FROM_THIS (This);
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
+
+ //
+ // Retrive uncommitted data from Form Browser
+ //
+ NvRamMap = &Private->FeFakeNvData;
+ BufferSize = sizeof (FILE_EXPLORER_NV_DATA);
+ Status = GetBrowserData (NULL, NULL, &BufferSize, (UINT8 *) NvRamMap);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (QuestionId == KEY_VALUE_SAVE_AND_EXIT_BOOT || QuestionId == KEY_VALUE_SAVE_AND_EXIT_DRIVER) {
+ //
+ // Apply changes and exit formset
+ //
+ if (ADD_BOOT_OPTION_STATE == Private->FeCurrentState) {
+ Status = Var_UpdateBootOption (Private, NvRamMap);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BOpt_GetBootOptions (Private);
+ CreateMenuStringToken (Private, Private->FeHiiHandle, &BootOptionMenu);
+ } else if (ADD_DRIVER_OPTION_STATE == Private->FeCurrentState) {
+ Status = Var_UpdateDriverOption (
+ Private,
+ Private->FeHiiHandle,
+ NvRamMap->DescriptionData,
+ NvRamMap->OptionalData,
+ NvRamMap->ForceReconnect
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BOpt_GetDriverOptions (Private);
+ CreateMenuStringToken (Private, Private->FeHiiHandle, &DriverOptionMenu);
+ }
+
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ } else if (QuestionId == KEY_VALUE_NO_SAVE_AND_EXIT_BOOT || QuestionId == KEY_VALUE_NO_SAVE_AND_EXIT_DRIVER) {
+ //
+ // Discard changes and exit formset
+ //
+ NvRamMap->OptionalData[0] = 0x0000;
+ NvRamMap->DescriptionData[0] = 0x0000;
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ } else if (QuestionId < FILE_OPTION_OFFSET) {
+ //
+ // Exit File Explorer formset
+ //
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ } else {
+ if (UpdateFileExplorer (Private, QuestionId)) {
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ }
+ }
+
+ return Status;
+}
diff --git a/MdeModulePkg/Universal/BdsDxe/BootMaint/FormGuid.h b/MdeModulePkg/Universal/BdsDxe/BootMaint/FormGuid.h new file mode 100644 index 0000000000..9c0adf2bba --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/BootMaint/FormGuid.h @@ -0,0 +1,216 @@ +/*++
+
+Copyright (c) 2004 - 2007, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ FormGuid.h
+
+Abstract:
+
+ Formset guids, form id and VarStore data structure for Boot Maintenance Manager.
+
+--*/
+#ifndef _FORM_GUID_H
+#define _FORM_GUID_H
+
+#define BOOT_MAINT_FORMSET_GUID \
+ { \
+ 0x642237c7, 0x35d4, 0x472d, {0x83, 0x65, 0x12, 0xe0, 0xcc, 0xf2, 0x7a, 0x22} \
+ }
+
+#define FILE_EXPLORE_FORMSET_GUID \
+ { \
+ 0x1f2d63e1, 0xfebd, 0x4dc7, {0x9c, 0xc5, 0xba, 0x2b, 0x1c, 0xef, 0x9c, 0x5b} \
+ }
+
+#define FORM_MAIN_ID 0x1001
+#define FORM_BOOT_ADD_ID 0x1002
+#define FORM_BOOT_DEL_ID 0x1003
+#define FORM_BOOT_CHG_ID 0x1004
+#define FORM_DRV_ADD_ID 0x1005
+#define FORM_DRV_DEL_ID 0x1006
+#define FORM_DRV_CHG_ID 0x1007
+#define FORM_CON_MAIN_ID 0x1008
+#define FORM_CON_IN_ID 0x1009
+#define FORM_CON_OUT_ID 0x100A
+#define FORM_CON_ERR_ID 0x100B
+#define FORM_FILE_SEEK_ID 0x100C
+#define FORM_FILE_NEW_SEEK_ID 0x100D
+#define FORM_DRV_ADD_FILE_ID 0x100E
+#define FORM_DRV_ADD_HANDLE_ID 0x100F
+#define FORM_DRV_ADD_HANDLE_DESC_ID 0x1010
+#define FORM_BOOT_NEXT_ID 0x1011
+#define FORM_TIME_OUT_ID 0x1012
+#define FORM_RESET 0x1013
+#define FORM_BOOT_SETUP_ID 0x1014
+#define FORM_DRIVER_SETUP_ID 0x1015
+#define FORM_BOOT_LEGACY_DEVICE_ID 0x1016
+#define FORM_CON_COM_ID 0x1017
+#define FORM_CON_COM_SETUP_ID 0x1018
+#define FORM_SET_FD_ORDER_ID 0x1019
+#define FORM_SET_HD_ORDER_ID 0x101A
+#define FORM_SET_CD_ORDER_ID 0x101B
+#define FORM_SET_NET_ORDER_ID 0x101C
+#define FORM_SET_BEV_ORDER_ID 0x101D
+#define FORM_FILE_EXPLORER_ID 0x101E
+#define FORM_BOOT_ADD_DESCRIPTION_ID 0x101F
+#define FORM_DRIVER_ADD_FILE_DESCRIPTION_ID 0x1020
+#define FORM_CON_MODE_ID 0x1021
+
+#define MAXIMUM_FORM_ID 0x10FF
+
+#define KEY_VALUE_COM_SET_BAUD_RATE 0x1101
+#define KEY_VALUE_COM_SET_DATA_BITS 0x1102
+#define KEY_VALUE_COM_SET_STOP_BITS 0x1103
+#define KEY_VALUE_COM_SET_PARITY 0x1104
+#define KEY_VALUE_COM_SET_TERMI_TYPE 0x1105
+#define KEY_VALUE_MAIN_BOOT_NEXT 0x1106
+#define KEY_VALUE_BOOT_ADD_DESC_DATA 0x1107
+#define KEY_VALUE_BOOT_ADD_OPT_DATA 0x1108
+#define KEY_VALUE_DRIVER_ADD_DESC_DATA 0x1109
+#define KEY_VALUE_DRIVER_ADD_OPT_DATA 0x110A
+#define KEY_VALUE_SAVE_AND_EXIT 0x110B
+#define KEY_VALUE_NO_SAVE_AND_EXIT 0x110C
+#define KEY_VALUE_BOOT_FROM_FILE 0x110D
+
+#define MAXIMUM_NORMAL_KEY_VALUE 0x11FF
+
+//
+// Varstore ID defined for Buffer Stoarge
+//
+#define VARSTORE_ID_BOOT_MAINT 0x1000
+#define VARSTORE_ID_FILE_EXPLORER 0x1001
+
+//
+// This is the structure that will be used to store the
+// question's current value. Use it at initialize time to
+// set default value for each question. When using at run
+// time, this map is returned by the callback function,
+// so dynamically changing the question's value will be
+// possible through this mechanism
+//
+typedef struct {
+ //
+ // Three questions displayed at the main page
+ // for Timeout, BootNext Variables respectively
+ //
+ UINT16 BootTimeOut;
+ UINT16 BootNext;
+
+ //
+ // This is the COM1 Attributes value storage
+ //
+ UINT8 COM1BaudRate;
+ UINT8 COM1DataRate;
+ UINT8 COM1StopBits;
+ UINT8 COM1Parity;
+ UINT8 COM1TerminalType;
+
+ //
+ // This is the COM2 Attributes value storage
+ //
+ UINT8 COM2BaudRate;
+ UINT8 COM2DataRate;
+ UINT8 COM2StopBits;
+ UINT8 COM2Parity;
+ UINT8 COM2TerminalType;
+
+ //
+ // Driver Option Add Handle page storage
+ //
+ UINT16 DriverAddHandleDesc[100];
+ UINT16 DriverAddHandleOptionalData[100];
+ UINT8 DriverAddActive;
+ UINT8 DriverAddForceReconnect;
+
+ //
+ // Console Input/Output/Errorout using COM port check storage
+ //
+ UINT8 ConsoleInputCOM1;
+ UINT8 ConsoleInputCOM2;
+ UINT8 ConsoleOutputCOM1;
+ UINT8 ConsoleOutputCOM2;
+ UINT8 ConsoleErrorCOM1;
+ UINT8 ConsoleErrorCOM2;
+
+ //
+ // At most 100 input/output/errorout device for console storage
+ //
+ UINT8 ConsoleCheck[100];
+
+ //
+ // Boot or Driver Option Order storage
+ //
+ UINT8 OptionOrder[100];
+ UINT8 DriverOptionToBeDeleted[100];
+
+ //
+ // Boot Option Delete storage
+ //
+ UINT8 BootOptionDel[100];
+ UINT8 DriverOptionDel[100];
+
+ //
+ // This is the Terminal Attributes value storage
+ //
+ UINT8 COMBaudRate;
+ UINT8 COMDataRate;
+ UINT8 COMStopBits;
+ UINT8 COMParity;
+ UINT8 COMTerminalType;
+
+ //
+ // Legacy Device Order Selection Storage
+ //
+ UINT8 LegacyFD[100];
+ UINT8 LegacyHD[100];
+ UINT8 LegacyCD[100];
+ UINT8 LegacyNET[100];
+ UINT8 LegacyBEV[100];
+
+ //
+ // We use DisableMap array to record the enable/disable state of each boot device
+ // It should be taken as a bit array, from left to right there are totally 256 bits
+ // the most left one stands for BBS table item 0, and the most right one stands for item 256
+ // If the bit is 1, it means the boot device has been disabled.
+ //
+ UINT8 DisableMap[32];
+
+ //
+ // Console Output Text Mode
+ //
+ UINT16 ConsoleOutMode;
+
+ //
+ // UINT16 PadArea[10];
+ //
+} BMM_FAKE_NV_DATA;
+
+//
+// Key used by File Explorer forms
+//
+#define KEY_VALUE_SAVE_AND_EXIT_BOOT 0x1000
+#define KEY_VALUE_NO_SAVE_AND_EXIT_BOOT 0x1001
+#define KEY_VALUE_SAVE_AND_EXIT_DRIVER 0x1002
+#define KEY_VALUE_NO_SAVE_AND_EXIT_DRIVER 0x1003
+
+//
+// This is the data structure used by File Explorer formset
+//
+typedef struct {
+ UINT16 DescriptionData[75];
+ UINT16 OptionalData[127];
+ UINT8 Active;
+ UINT8 ForceReconnect;
+} FILE_EXPLORER_NV_DATA;
+
+#endif
+
diff --git a/MdeModulePkg/Universal/BdsDxe/BootMaint/UpdatePage.c b/MdeModulePkg/Universal/BdsDxe/BootMaint/UpdatePage.c new file mode 100644 index 0000000000..d1608bf528 --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/BootMaint/UpdatePage.c @@ -0,0 +1,1211 @@ +/*++
+
+Copyright (c) 2004 - 2008, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ UpdatePage.c
+
+Abstract:
+
+ Dynamically Update the pages
+
+--*/
+
+#include "BootMaint.h"
+
+EFI_GUID gTerminalDriverGuid = {
+ 0x10634d8e, 0x1c05, 0x46cb, {0xbb, 0xc, 0x5a, 0xfd, 0xc8, 0x29, 0xa8, 0xc8}
+};
+
+VOID
+RefreshUpdateData (
+ VOID
+ )
+/*++
+
+Routine Description:
+ Refresh the global UpdateData structure.
+
+Arguments:
+ None.
+
+Returns:
+ None.
+
+--*/
+{
+ gUpdateData.Offset = 0;
+}
+
+VOID
+UpdatePageStart (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ RefreshUpdateData ();
+
+ if (!(CallbackData->BmmAskSaveOrNot)) {
+ //
+ // Add a "Go back to main page" tag in front of the form when there are no
+ // "Apply changes" and "Discard changes" tags in the end of the form.
+ //
+ CreateGotoOpCode (
+ FORM_MAIN_ID,
+ STRING_TOKEN (STR_FORM_GOTO_MAIN),
+ STRING_TOKEN (STR_FORM_GOTO_MAIN),
+ 0,
+ FORM_MAIN_ID,
+ &gUpdateData
+ );
+ }
+
+}
+
+VOID
+UpdatePageEnd (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ //
+ // Create the "Apply changes" and "Discard changes" tags.
+ //
+ if (CallbackData->BmmAskSaveOrNot) {
+ CreateSubTitleOpCode (
+ STRING_TOKEN (STR_NULL_STRING),
+ 0,
+ 0,
+ 0,
+ &gUpdateData
+ );
+
+ CreateGotoOpCode (
+ FORM_MAIN_ID,
+ STRING_TOKEN (STR_SAVE_AND_EXIT),
+ STRING_TOKEN (STR_NULL_STRING),
+ EFI_IFR_FLAG_CALLBACK,
+ KEY_VALUE_SAVE_AND_EXIT,
+ &gUpdateData
+ );
+ }
+
+ //
+ // Ensure user can return to the main page.
+ //
+ CreateGotoOpCode (
+ FORM_MAIN_ID,
+ STRING_TOKEN (STR_NO_SAVE_AND_EXIT),
+ STRING_TOKEN (STR_NULL_STRING),
+ EFI_IFR_FLAG_CALLBACK,
+ KEY_VALUE_NO_SAVE_AND_EXIT,
+ &gUpdateData
+ );
+
+ IfrLibUpdateForm (
+ CallbackData->BmmHiiHandle,
+ &mBootMaintGuid,
+ CallbackData->BmmCurrentPageId,
+ CallbackData->BmmCurrentPageId,
+ FALSE,
+ &gUpdateData
+ );
+}
+
+VOID
+CleanUpPage (
+ IN UINT16 LabelId,
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ RefreshUpdateData ();
+
+ //
+ // Remove all op-codes from dynamic page
+ //
+ IfrLibUpdateForm (
+ CallbackData->BmmHiiHandle,
+ &mBootMaintGuid,
+ LabelId,
+ LabelId,
+ FALSE,
+ &gUpdateData
+ );
+}
+
+EFI_STATUS
+BootThisFile (
+ IN BM_FILE_CONTEXT *FileContext
+ )
+{
+ EFI_STATUS Status;
+ UINTN ExitDataSize;
+ CHAR16 *ExitData;
+ BDS_COMMON_OPTION *Option;
+
+ Status = gBS->AllocatePool (EfiBootServicesData, sizeof (BDS_COMMON_OPTION), (VOID **) &Option);
+ Option->Description = FileContext->FileName;
+ Option->DevicePath = FileContext->DevicePath;
+ Option->LoadOptionsSize = 0;
+ Option->LoadOptions = NULL;
+
+ //
+ // Since current no boot from removable media directly is allowed */
+ //
+ gST->ConOut->ClearScreen (gST->ConOut);
+
+ gBS->RaiseTPL (TPL_APPLICATION);
+
+ ExitDataSize = 0;
+
+ Status = BdsLibBootViaBootOption (Option, Option->DevicePath, &ExitDataSize, &ExitData);
+
+ gBS->RestoreTPL (TPL_APPLICATION);
+
+ return Status;
+
+}
+
+VOID
+UpdateConCOMPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+ UINT16 Index;
+ EFI_STATUS Status;
+ VOID *Interface;
+
+ CallbackData->BmmAskSaveOrNot = FALSE;
+
+ UpdatePageStart (CallbackData);
+
+ Status = EfiLibLocateProtocol (&gTerminalDriverGuid, (VOID **) &Interface);
+ if (!EFI_ERROR (Status)) {
+ for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);
+
+ CreateGotoOpCode (
+ FORM_CON_COM_SETUP_ID,
+ NewMenuEntry->DisplayStringToken,
+ STRING_TOKEN (STR_NULL_STRING),
+ EFI_IFR_FLAG_CALLBACK,
+ (UINT16) (TERMINAL_OPTION_OFFSET + Index),
+ &gUpdateData
+ );
+ }
+ }
+
+ UpdatePageEnd (CallbackData);
+}
+
+VOID
+UpdateBootDelPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_LOAD_CONTEXT *NewLoadContext;
+ UINT16 Index;
+
+ CallbackData->BmmAskSaveOrNot = TRUE;
+
+ UpdatePageStart (CallbackData);
+ CreateMenuStringToken (CallbackData, CallbackData->BmmHiiHandle, &BootOptionMenu);
+
+ for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index);
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+ if (NewLoadContext->IsLegacy) {
+ continue;
+ }
+
+ NewLoadContext->Deleted = FALSE;
+ CallbackData->BmmFakeNvData.BootOptionDel[Index] = 0x00;
+
+ CreateCheckBoxOpCode (
+ (EFI_QUESTION_ID) (BOOT_OPTION_DEL_QUESTION_ID + Index),
+ VARSTORE_ID_BOOT_MAINT,
+ (UINT16) (BOOT_OPTION_DEL_VAR_OFFSET + Index),
+ NewMenuEntry->DisplayStringToken,
+ NewMenuEntry->HelpStringToken,
+ 0,
+ 0,
+ &gUpdateData
+ );
+ }
+
+ UpdatePageEnd (CallbackData);
+}
+
+VOID
+UpdateDrvAddHandlePage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+ UINT16 Index;
+
+ CallbackData->BmmAskSaveOrNot = FALSE;
+
+ UpdatePageStart (CallbackData);
+
+ for (Index = 0; Index < DriverMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&DriverMenu, Index);
+
+ CreateGotoOpCode (
+ FORM_DRV_ADD_HANDLE_DESC_ID,
+ NewMenuEntry->DisplayStringToken,
+ STRING_TOKEN (STR_NULL_STRING),
+ EFI_IFR_FLAG_CALLBACK,
+ (UINT16) (HANDLE_OPTION_OFFSET + Index),
+ &gUpdateData
+ );
+ }
+
+ UpdatePageEnd (CallbackData);
+}
+
+VOID
+UpdateDrvDelPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_LOAD_CONTEXT *NewLoadContext;
+ UINT16 Index;
+
+ CallbackData->BmmAskSaveOrNot = TRUE;
+
+ UpdatePageStart (CallbackData);
+
+ CreateMenuStringToken (CallbackData, CallbackData->BmmHiiHandle, &DriverOptionMenu);
+
+ for (Index = 0; Index < DriverOptionMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index);
+
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+ NewLoadContext->Deleted = FALSE;
+ CallbackData->BmmFakeNvData.DriverOptionDel[Index] = 0x00;
+
+ CreateCheckBoxOpCode (
+ (EFI_QUESTION_ID) (DRIVER_OPTION_DEL_QUESTION_ID + Index),
+ VARSTORE_ID_BOOT_MAINT,
+ (UINT16) (DRIVER_OPTION_DEL_VAR_OFFSET + Index),
+ NewMenuEntry->DisplayStringToken,
+ NewMenuEntry->HelpStringToken,
+ 0,
+ 0,
+ &gUpdateData
+ );
+ }
+
+ UpdatePageEnd (CallbackData);
+}
+
+VOID
+UpdateDriverAddHandleDescPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+
+ CallbackData->BmmFakeNvData.DriverAddActive = 0x01;
+ CallbackData->BmmFakeNvData.DriverAddForceReconnect = 0x00;
+ CallbackData->BmmAskSaveOrNot = TRUE;
+ NewMenuEntry = CallbackData->MenuEntry;
+
+ UpdatePageStart (CallbackData);
+
+ CreateSubTitleOpCode (
+ NewMenuEntry->DisplayStringToken,
+ 0,
+ 0,
+ 0,
+ &gUpdateData
+ );
+
+ CreateStringOpCode (
+ (EFI_QUESTION_ID) DRV_ADD_HANDLE_DESC_QUESTION_ID,
+ VARSTORE_ID_BOOT_MAINT,
+ DRV_ADD_HANDLE_DESC_VAR_OFFSET,
+ STRING_TOKEN (STR_LOAD_OPTION_DESC),
+ STRING_TOKEN (STR_NULL_STRING),
+ 0,
+ 0,
+ 6,
+ 75,
+ &gUpdateData
+ );
+
+ CreateCheckBoxOpCode (
+ (EFI_QUESTION_ID) DRV_ADD_RECON_QUESTION_ID,
+ VARSTORE_ID_BOOT_MAINT,
+ DRV_ADD_RECON_VAR_OFFSET,
+ STRING_TOKEN (STR_LOAD_OPTION_FORCE_RECON),
+ STRING_TOKEN (STR_LOAD_OPTION_FORCE_RECON),
+ 0,
+ 0,
+ &gUpdateData
+ );
+
+ CreateStringOpCode (
+ (EFI_QUESTION_ID) DRIVER_ADD_OPTION_QUESTION_ID,
+ VARSTORE_ID_BOOT_MAINT,
+ DRIVER_ADD_OPTION_VAR_OFFSET,
+ STRING_TOKEN (STR_OPTIONAL_DATA),
+ STRING_TOKEN (STR_NULL_STRING),
+ 0,
+ 0,
+ 6,
+ 75,
+ &gUpdateData
+ );
+
+ UpdatePageEnd (CallbackData);
+}
+
+VOID
+UpdateConsolePage (
+ IN UINT16 UpdatePageId,
+ IN BM_MENU_OPTION *ConsoleMenu,
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_CONSOLE_CONTEXT *NewConsoleContext;
+ BM_TERMINAL_CONTEXT *NewTerminalContext;
+ UINT16 Index;
+ UINT16 Index2;
+ UINT8 CheckFlags;
+ EFI_STATUS Status;
+ VOID *Interface;
+
+ CallbackData->BmmAskSaveOrNot = TRUE;
+
+ UpdatePageStart (CallbackData);
+
+ for (Index = 0; Index < ConsoleMenu->MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (ConsoleMenu, Index);
+ NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;
+ CheckFlags = 0;
+ if (NewConsoleContext->IsActive) {
+ CheckFlags |= EFI_IFR_CHECKBOX_DEFAULT;
+ CallbackData->BmmFakeNvData.ConsoleCheck[Index] = TRUE;
+ } else {
+ CallbackData->BmmFakeNvData.ConsoleCheck[Index] = FALSE;
+ }
+
+ CreateCheckBoxOpCode (
+ (EFI_QUESTION_ID) (CON_DEVICE_QUESTION_ID + Index),
+ VARSTORE_ID_BOOT_MAINT,
+ (UINT16) (CON_DEVICE_VAR_OFFSET + Index),
+ NewMenuEntry->DisplayStringToken,
+ NewMenuEntry->HelpStringToken,
+ 0,
+ CheckFlags,
+ &gUpdateData
+ );
+ }
+
+ Status = EfiLibLocateProtocol (&gTerminalDriverGuid, (VOID **) &Interface);
+ if (!EFI_ERROR (Status)) {
+ for (Index2 = 0; Index2 < TerminalMenu.MenuNumber; Index2++) {
+ CheckFlags = 0;
+ NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index2);
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
+
+ if ((NewTerminalContext->IsConIn && (UpdatePageId == FORM_CON_IN_ID)) ||
+ (NewTerminalContext->IsConOut && (UpdatePageId == FORM_CON_OUT_ID)) ||
+ (NewTerminalContext->IsStdErr && (UpdatePageId == FORM_CON_ERR_ID))
+ ) {
+ CheckFlags |= EFI_IFR_CHECKBOX_DEFAULT;
+ CallbackData->BmmFakeNvData.ConsoleCheck[Index] = TRUE;
+ } else {
+ CallbackData->BmmFakeNvData.ConsoleCheck[Index] = FALSE;
+ }
+
+ CreateCheckBoxOpCode (
+ (EFI_QUESTION_ID) (CON_DEVICE_QUESTION_ID + Index),
+ VARSTORE_ID_BOOT_MAINT,
+ (UINT16) (CON_DEVICE_VAR_OFFSET + Index),
+ NewMenuEntry->DisplayStringToken,
+ NewMenuEntry->HelpStringToken,
+ 0,
+ CheckFlags,
+ &gUpdateData
+ );
+
+ Index++;
+ }
+ }
+
+ UpdatePageEnd (CallbackData);
+}
+
+VOID
+UpdateOrderPage (
+ IN UINT16 UpdatePageId,
+ IN BM_MENU_OPTION *OptionMenu,
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+ UINT16 Index;
+ IFR_OPTION *IfrOptionList;
+
+ CallbackData->BmmAskSaveOrNot = TRUE;
+
+ UpdatePageStart (CallbackData);
+
+ CreateMenuStringToken (CallbackData, CallbackData->BmmHiiHandle, OptionMenu);
+
+ ZeroMem (CallbackData->BmmFakeNvData.OptionOrder, 100);
+
+ IfrOptionList = EfiAllocateZeroPool (sizeof (IFR_OPTION) * OptionMenu->MenuNumber);
+ if (NULL == IfrOptionList) {
+ return ;
+ }
+
+ for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (OptionMenu, Index);
+ IfrOptionList[Index].StringToken = NewMenuEntry->DisplayStringToken;
+ IfrOptionList[Index].Value.u8 = (UINT8) (NewMenuEntry->OptionNumber + 1);
+ IfrOptionList[Index].Flags = 0;
+ CallbackData->BmmFakeNvData.OptionOrder[Index] = IfrOptionList[Index].Value.u8;
+ }
+
+ if (OptionMenu->MenuNumber > 0) {
+ CreateOrderedListOpCode (
+ (EFI_QUESTION_ID) OPTION_ORDER_QUESTION_ID,
+ VARSTORE_ID_BOOT_MAINT,
+ OPTION_ORDER_VAR_OFFSET,
+ STRING_TOKEN (STR_CHANGE_ORDER),
+ STRING_TOKEN (STR_CHANGE_ORDER),
+ 0,
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ 100,
+ IfrOptionList,
+ OptionMenu->MenuNumber,
+ &gUpdateData
+ );
+ }
+
+ SafeFreePool (IfrOptionList);
+
+ UpdatePageEnd (CallbackData);
+
+ CopyMem (
+ CallbackData->BmmOldFakeNVData.OptionOrder,
+ CallbackData->BmmFakeNvData.OptionOrder,
+ 100
+ );
+}
+
+VOID
+UpdateBootNextPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_LOAD_CONTEXT *NewLoadContext;
+ IFR_OPTION *IfrOptionList;
+ UINTN NumberOfOptions;
+ UINT16 Index;
+
+ IfrOptionList = NULL;
+ NumberOfOptions = BootOptionMenu.MenuNumber;
+ CallbackData->BmmAskSaveOrNot = TRUE;
+
+ UpdatePageStart (CallbackData);
+ CreateMenuStringToken (CallbackData, CallbackData->BmmHiiHandle, &BootOptionMenu);
+
+ if (NumberOfOptions > 0) {
+ IfrOptionList = EfiAllocateZeroPool ((NumberOfOptions + 1) * sizeof (IFR_OPTION));
+
+ ASSERT (IfrOptionList);
+
+ CallbackData->BmmFakeNvData.BootNext = (UINT16) (BootOptionMenu.MenuNumber);
+
+ for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index);
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+ if (NewLoadContext->IsBootNext) {
+ IfrOptionList[Index].Flags = EFI_IFR_OPTION_DEFAULT;
+ CallbackData->BmmFakeNvData.BootNext = Index;
+ } else {
+ IfrOptionList[Index].Flags = 0;
+ }
+
+ IfrOptionList[Index].Value.u16 = Index;
+ IfrOptionList[Index].StringToken = NewMenuEntry->DisplayStringToken;
+ }
+
+ IfrOptionList[Index].Value.u16 = Index;
+ IfrOptionList[Index].StringToken = STRING_TOKEN (STR_NONE);
+ IfrOptionList[Index].Flags = 0;
+ if (CallbackData->BmmFakeNvData.BootNext == Index) {
+ IfrOptionList[Index].Flags |= EFI_IFR_OPTION_DEFAULT;
+ }
+
+ CreateOneOfOpCode (
+ (EFI_QUESTION_ID) BOOT_NEXT_QUESTION_ID,
+ VARSTORE_ID_BOOT_MAINT,
+ BOOT_NEXT_VAR_OFFSET,
+ STRING_TOKEN (STR_BOOT_NEXT),
+ STRING_TOKEN (STR_BOOT_NEXT_HELP),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_2,
+ IfrOptionList,
+ (UINTN) (NumberOfOptions + 1),
+ &gUpdateData
+ );
+
+ SafeFreePool (IfrOptionList);
+ }
+
+ UpdatePageEnd (CallbackData);
+}
+
+VOID
+UpdateTimeOutPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ UINT16 BootTimeOut;
+
+ CallbackData->BmmAskSaveOrNot = TRUE;
+
+ UpdatePageStart (CallbackData);
+
+ BootTimeOut = BdsLibGetTimeout ();
+
+ CreateNumericOpCode (
+ (EFI_QUESTION_ID) BOOT_TIME_OUT_QUESTION_ID,
+ VARSTORE_ID_BOOT_MAINT,
+ BOOT_TIME_OUT_VAR_OFFSET,
+ STRING_TOKEN (STR_NUM_AUTO_BOOT),
+ STRING_TOKEN (STR_HLP_AUTO_BOOT),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_2 | EFI_IFR_DISPLAY_UINT_DEC,
+ 0,
+ 65535,
+ 0,
+ BootTimeOut,
+ &gUpdateData
+ );
+
+ CallbackData->BmmFakeNvData.BootTimeOut = BootTimeOut;
+
+ UpdatePageEnd (CallbackData);
+}
+
+VOID
+UpdateConModePage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+/*++
+
+Routine Description:
+ Refresh the text mode page
+
+Arguments:
+ CallbackData - BMM_CALLBACK_DATA
+
+Returns:
+ None.
+
+--*/
+{
+ UINTN Mode;
+ UINTN Index;
+ UINTN Col;
+ UINTN Row;
+ CHAR16 RowString[50];
+ CHAR16 ModeString[50];
+ UINTN MaxMode;
+ UINTN ValidMode;
+ EFI_STRING_ID *ModeToken;
+ IFR_OPTION *IfrOptionList;
+ EFI_STATUS Status;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
+
+ ConOut = gST->ConOut;
+ Index = 0;
+ ValidMode = 0;
+ MaxMode = (UINTN) (ConOut->Mode->MaxMode);
+
+ CallbackData->BmmAskSaveOrNot = TRUE;
+
+ UpdatePageStart (CallbackData);
+
+ //
+ // Check valid mode
+ //
+ for (Mode = 0; Mode < MaxMode; Mode++) {
+ Status = ConOut->QueryMode (ConOut, Mode, &Col, &Row);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ ValidMode++;
+ }
+
+ if (ValidMode == 0) {
+ return;
+ }
+
+ IfrOptionList = EfiAllocateZeroPool (sizeof (IFR_OPTION) * ValidMode);
+ ASSERT(IfrOptionList != NULL);
+
+ ModeToken = EfiAllocateZeroPool (sizeof (EFI_STRING_ID) * ValidMode);
+ ASSERT(ModeToken != NULL);
+
+ //
+ // Determin which mode should be the first entry in menu
+ //
+ GetConsoleOutMode (CallbackData);
+
+ //
+ // Build text mode options
+ //
+ for (Mode = 0; Mode < MaxMode; Mode++) {
+ Status = ConOut->QueryMode (ConOut, Mode, &Col, &Row);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ //
+ // Build mode string Column x Row
+ //
+ UnicodeValueToString (ModeString, 0, Col, 0);
+ StrCat (ModeString, L" x ");
+ UnicodeValueToString (RowString, 0, Row, 0);
+ StrCat (ModeString, RowString);
+
+ IfrLibNewString (CallbackData->BmmHiiHandle, &ModeToken[Index], ModeString);
+
+ IfrOptionList[Index].StringToken = ModeToken[Index];
+ IfrOptionList[Index].Value.u16 = (UINT16) Mode;
+ if (Mode == CallbackData->BmmFakeNvData.ConsoleOutMode) {
+ IfrOptionList[Index].Flags = EFI_IFR_OPTION_DEFAULT;
+ } else {
+ IfrOptionList[Index].Flags = 0;
+ }
+ Index++;
+ }
+
+ CreateOneOfOpCode (
+ (EFI_QUESTION_ID) CON_MODE_QUESTION_ID,
+ VARSTORE_ID_BOOT_MAINT,
+ CON_MODE_VAR_OFFSET,
+ STRING_TOKEN (STR_CON_MODE_SETUP),
+ STRING_TOKEN (STR_CON_MODE_SETUP),
+ EFI_IFR_FLAG_RESET_REQUIRED,
+ EFI_IFR_NUMERIC_SIZE_2,
+ IfrOptionList,
+ ValidMode,
+ &gUpdateData
+ );
+ SafeFreePool (IfrOptionList);
+ SafeFreePool (ModeToken);
+
+ UpdatePageEnd (CallbackData);
+}
+
+VOID
+UpdateTerminalPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ UINT8 Index;
+ UINT8 CheckFlags;
+ IFR_OPTION *IfrOptionList;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_TERMINAL_CONTEXT *NewTerminalContext;
+
+ CallbackData->BmmAskSaveOrNot = TRUE;
+
+ UpdatePageStart (CallbackData);
+
+ NewMenuEntry = BOpt_GetMenuEntry (
+ &TerminalMenu,
+ CallbackData->CurrentTerminal
+ );
+
+ if (NewMenuEntry == NULL) {
+ return ;
+ }
+
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
+
+ IfrOptionList = EfiAllocateZeroPool (sizeof (IFR_OPTION) * 19);
+ if (IfrOptionList == NULL) {
+ return ;
+ }
+
+ for (Index = 0; Index < 19; Index++) {
+ CheckFlags = 0;
+ if (NewTerminalContext->BaudRate == (UINT64) (BaudRateList[Index].Value)) {
+ CheckFlags |= EFI_IFR_OPTION_DEFAULT;
+ NewTerminalContext->BaudRateIndex = Index;
+ CallbackData->BmmFakeNvData.COMBaudRate = NewTerminalContext->BaudRateIndex;
+ }
+
+ IfrOptionList[Index].Flags = CheckFlags;
+ IfrOptionList[Index].StringToken = BaudRateList[Index].StringToken;
+ IfrOptionList[Index].Value.u8 = Index;
+ }
+
+ CreateOneOfOpCode (
+ (EFI_QUESTION_ID) COM_BAUD_RATE_QUESTION_ID,
+ VARSTORE_ID_BOOT_MAINT,
+ COM_BAUD_RATE_VAR_OFFSET,
+ STRING_TOKEN (STR_COM_BAUD_RATE),
+ STRING_TOKEN (STR_COM_BAUD_RATE),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ IfrOptionList,
+ 19,
+ &gUpdateData
+ );
+
+ for (Index = 0; Index < 4; Index++) {
+ CheckFlags = 0;
+
+ if (NewTerminalContext->DataBits == DataBitsList[Index].Value) {
+ NewTerminalContext->DataBitsIndex = Index;
+ CallbackData->BmmFakeNvData.COMDataRate = NewTerminalContext->DataBitsIndex;
+ CheckFlags |= EFI_IFR_OPTION_DEFAULT;
+ }
+
+ IfrOptionList[Index].Flags = CheckFlags;
+ IfrOptionList[Index].StringToken = DataBitsList[Index].StringToken;
+ IfrOptionList[Index].Value.u8 = Index;
+ }
+
+ CreateOneOfOpCode (
+ (EFI_QUESTION_ID) COM_DATA_RATE_QUESTION_ID,
+ VARSTORE_ID_BOOT_MAINT,
+ COM_DATA_RATE_VAR_OFFSET,
+ STRING_TOKEN (STR_COM_DATA_BITS),
+ STRING_TOKEN (STR_COM_DATA_BITS),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ IfrOptionList,
+ 4,
+ &gUpdateData
+ );
+
+ for (Index = 0; Index < 5; Index++) {
+ CheckFlags = 0;
+ if (NewTerminalContext->Parity == ParityList[Index].Value) {
+ CheckFlags |= EFI_IFR_OPTION_DEFAULT;
+ NewTerminalContext->ParityIndex = (UINT8) Index;
+ CallbackData->BmmFakeNvData.COMParity = NewTerminalContext->ParityIndex;
+ }
+
+ IfrOptionList[Index].Flags = CheckFlags;
+ IfrOptionList[Index].StringToken = ParityList[Index].StringToken;
+ IfrOptionList[Index].Value.u8 = Index;
+ }
+
+ CreateOneOfOpCode (
+ (EFI_QUESTION_ID) COM_PARITY_QUESTION_ID,
+ VARSTORE_ID_BOOT_MAINT,
+ COM_PARITY_VAR_OFFSET,
+ STRING_TOKEN (STR_COM_PARITY),
+ STRING_TOKEN (STR_COM_PARITY),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ IfrOptionList,
+ 5,
+ &gUpdateData
+ );
+
+ for (Index = 0; Index < 3; Index++) {
+ CheckFlags = 0;
+ if (NewTerminalContext->StopBits == StopBitsList[Index].Value) {
+ CheckFlags |= EFI_IFR_OPTION_DEFAULT;
+ NewTerminalContext->StopBitsIndex = (UINT8) Index;
+ CallbackData->BmmFakeNvData.COMStopBits = NewTerminalContext->StopBitsIndex;
+ }
+
+ IfrOptionList[Index].Flags = CheckFlags;
+ IfrOptionList[Index].StringToken = StopBitsList[Index].StringToken;
+ IfrOptionList[Index].Value.u8 = Index;
+ }
+
+ CreateOneOfOpCode (
+ (EFI_QUESTION_ID) COM_STOP_BITS_QUESTION_ID,
+ VARSTORE_ID_BOOT_MAINT,
+ COM_STOP_BITS_VAR_OFFSET,
+ STRING_TOKEN (STR_COM_STOP_BITS),
+ STRING_TOKEN (STR_COM_STOP_BITS),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ IfrOptionList,
+ 3,
+ &gUpdateData
+ );
+
+ for (Index = 0; Index < 4; Index++) {
+ CheckFlags = 0;
+ if (NewTerminalContext->TerminalType == Index) {
+ CheckFlags |= EFI_IFR_OPTION_DEFAULT;
+ CallbackData->BmmFakeNvData.COMTerminalType = NewTerminalContext->TerminalType;
+ }
+
+ IfrOptionList[Index].Flags = CheckFlags;
+ IfrOptionList[Index].StringToken = (EFI_STRING_ID) TerminalType[Index];
+ IfrOptionList[Index].Value.u8 = Index;
+ }
+
+ CreateOneOfOpCode (
+ (EFI_QUESTION_ID) COM_TERMINAL_QUESTION_ID,
+ VARSTORE_ID_BOOT_MAINT,
+ COM_TERMINAL_VAR_OFFSET,
+ STRING_TOKEN (STR_COM_TERMI_TYPE),
+ STRING_TOKEN (STR_COM_TERMI_TYPE),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ IfrOptionList,
+ 4,
+ &gUpdateData
+ );
+
+ SafeFreePool (IfrOptionList);
+
+ UpdatePageEnd (CallbackData);
+}
+
+VOID
+UpdatePageBody (
+ IN UINT16 UpdatePageId,
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ CleanUpPage (UpdatePageId, CallbackData);
+ switch (UpdatePageId) {
+ case FORM_CON_IN_ID:
+ UpdateConsolePage (UpdatePageId, &ConsoleInpMenu, CallbackData);
+ break;
+
+ case FORM_CON_OUT_ID:
+ UpdateConsolePage (UpdatePageId, &ConsoleOutMenu, CallbackData);
+ break;
+
+ case FORM_CON_ERR_ID:
+ UpdateConsolePage (UpdatePageId, &ConsoleErrMenu, CallbackData);
+ break;
+
+ case FORM_BOOT_CHG_ID:
+ UpdateOrderPage (UpdatePageId, &BootOptionMenu, CallbackData);
+ break;
+
+ case FORM_DRV_CHG_ID:
+ UpdateOrderPage (UpdatePageId, &DriverOptionMenu, CallbackData);
+ break;
+
+ default:
+ break;
+ }
+}
+
+VOID *
+GetLegacyBootOptionVar (
+ IN UINTN DeviceType,
+ OUT UINTN *OptionIndex,
+ OUT UINTN *OptionSize
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ VOID *OptionBuffer;
+ UINTN OrderSize;
+ UINTN Index;
+ UINT16 *OrderBuffer;
+ CHAR16 StrTemp[100];
+ UINT16 FilePathSize;
+ UINT8 *Ptr;
+ UINT8 *OptionalData;
+
+ //
+ // Get Boot Option number from the size of BootOrder
+ //
+ OrderBuffer = BdsLibGetVariableAndSize (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ &OrderSize
+ );
+
+ for (Index = 0; Index < OrderSize / sizeof (UINT16); Index++) {
+ UnicodeSPrint (StrTemp, 100, L"Boot%04x", OrderBuffer[Index]);
+ OptionBuffer = BdsLibGetVariableAndSize (
+ StrTemp,
+ &gEfiGlobalVariableGuid,
+ OptionSize
+ );
+ if (NULL == OptionBuffer) {
+ continue;
+ }
+
+ Ptr = (UINT8 *) OptionBuffer;
+ Ptr += sizeof (UINT32);
+
+ FilePathSize = *(UINT16 *) Ptr;
+ Ptr += sizeof (UINT16);
+
+ Ptr += StrSize ((CHAR16 *) Ptr);
+
+ //
+ // Now Ptr point to Device Path
+ //
+ DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
+ Ptr += FilePathSize;
+
+ //
+ // Now Ptr point to Optional Data
+ //
+ OptionalData = Ptr;
+
+ if ((DeviceType == ((BBS_TABLE *) OptionalData)->DeviceType) &&
+ (BBS_DEVICE_PATH == DevicePath->Type) &&
+ (BBS_BBS_DP == DevicePath->SubType)
+ ) {
+ *OptionIndex = OrderBuffer[Index];
+ SafeFreePool (OrderBuffer);
+ return OptionBuffer;
+ } else {
+ SafeFreePool (OptionBuffer);
+ }
+ }
+
+ SafeFreePool (OrderBuffer);
+ return NULL;
+}
+
+VOID
+UpdateSetLegacyDeviceOrderPage (
+ IN UINT16 UpdatePageId,
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ BM_LEGACY_DEV_ORDER_CONTEXT *DevOrder;
+ BM_MENU_OPTION *OptionMenu;
+ BM_MENU_ENTRY *NewMenuEntry;
+ IFR_OPTION *IfrOptionList;
+ EFI_STRING_ID StrRef;
+ EFI_STRING_ID StrRefHelp;
+ BBS_TYPE BbsType;
+ UINTN VarSize;
+ UINTN Pos;
+ UINTN Bit;
+ UINT16 Index;
+ UINT16 Key;
+ CHAR16 String[100];
+ CHAR16 *TypeStr;
+ CHAR16 *TypeStrHelp;
+ UINT16 VarDevOrder;
+ UINT8 *VarData;
+ UINT8 *LegacyOrder;
+ UINT8 *OldData;
+ UINT8 *DisMap;
+
+ OptionMenu = NULL;
+ Key = 0;
+ StrRef = 0;
+ StrRefHelp = 0;
+ TypeStr = NULL;
+ TypeStrHelp = NULL;
+ BbsType = BBS_FLOPPY;
+ LegacyOrder = NULL;
+ OldData = NULL;
+ DisMap = NULL;
+
+ CallbackData->BmmAskSaveOrNot = TRUE;
+ UpdatePageStart (CallbackData);
+
+ DisMap = CallbackData->BmmOldFakeNVData.DisableMap;
+
+ SetMem (DisMap, 32, 0);
+ //
+ // Create oneof option list
+ //
+ switch (UpdatePageId) {
+ case FORM_SET_FD_ORDER_ID:
+ OptionMenu = (BM_MENU_OPTION *) &LegacyFDMenu;
+ Key = (UINT16) LEGACY_FD_QUESTION_ID;
+ TypeStr = StrFloppy;
+ TypeStrHelp = StrFloppyHelp;
+ BbsType = BBS_FLOPPY;
+ LegacyOrder = CallbackData->BmmFakeNvData.LegacyFD;
+ OldData = CallbackData->BmmOldFakeNVData.LegacyFD;
+ break;
+
+ case FORM_SET_HD_ORDER_ID:
+ OptionMenu = (BM_MENU_OPTION *) &LegacyHDMenu;
+ Key = (UINT16) LEGACY_HD_QUESTION_ID;
+ TypeStr = StrHardDisk;
+ TypeStrHelp = StrHardDiskHelp;
+ BbsType = BBS_HARDDISK;
+ LegacyOrder = CallbackData->BmmFakeNvData.LegacyHD;
+ OldData = CallbackData->BmmOldFakeNVData.LegacyHD;
+ break;
+
+ case FORM_SET_CD_ORDER_ID:
+ OptionMenu = (BM_MENU_OPTION *) &LegacyCDMenu;
+ Key = (UINT16) LEGACY_CD_QUESTION_ID;
+ TypeStr = StrCDROM;
+ TypeStrHelp = StrCDROMHelp;
+ BbsType = BBS_CDROM;
+ LegacyOrder = CallbackData->BmmFakeNvData.LegacyCD;
+ OldData = CallbackData->BmmOldFakeNVData.LegacyCD;
+ break;
+
+ case FORM_SET_NET_ORDER_ID:
+ OptionMenu = (BM_MENU_OPTION *) &LegacyNETMenu;
+ Key = (UINT16) LEGACY_NET_QUESTION_ID;
+ TypeStr = StrNET;
+ TypeStrHelp = StrNETHelp;
+ BbsType = BBS_EMBED_NETWORK;
+ LegacyOrder = CallbackData->BmmFakeNvData.LegacyNET;
+ OldData = CallbackData->BmmOldFakeNVData.LegacyNET;
+ break;
+
+ case FORM_SET_BEV_ORDER_ID:
+ OptionMenu = (BM_MENU_OPTION *) &LegacyBEVMenu;
+ Key = (UINT16) LEGACY_BEV_QUESTION_ID;
+ TypeStr = StrBEV;
+ TypeStrHelp = StrBEVHelp;
+ BbsType = BBS_BEV_DEVICE;
+ LegacyOrder = CallbackData->BmmFakeNvData.LegacyBEV;
+ OldData = CallbackData->BmmOldFakeNVData.LegacyBEV;
+ break;
+
+ }
+
+ CreateMenuStringToken (CallbackData, CallbackData->BmmHiiHandle, OptionMenu);
+
+ IfrOptionList = EfiAllocateZeroPool (sizeof (IFR_OPTION) * (OptionMenu->MenuNumber + 1));
+ if (NULL == IfrOptionList) {
+ return ;
+ }
+
+ for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (OptionMenu, Index);
+ IfrOptionList[Index].Flags = 0;
+ if (0 == Index) {
+ IfrOptionList[Index].Flags |= EFI_IFR_OPTION_DEFAULT;
+ }
+
+ IfrOptionList[Index].StringToken = NewMenuEntry->DisplayStringToken;
+ IfrOptionList[Index].Value.u8 = (UINT8) ((BM_LEGACY_DEVICE_CONTEXT *) NewMenuEntry->VariableContext)->Index;
+ }
+ //
+ // for item "Disabled"
+ //
+ IfrOptionList[Index].Flags = 0;
+ IfrOptionList[Index].StringToken = STRING_TOKEN (STR_DISABLE_LEGACY_DEVICE);
+ IfrOptionList[Index].Value.u8 = 0xFF;
+
+ //
+ // Get Device Order from variable
+ //
+ VarData = BdsLibGetVariableAndSize (
+ VarLegacyDevOrder,
+ &EfiLegacyDevOrderGuid,
+ &VarSize
+ );
+
+ if (NULL != VarData) {
+ DevOrder = (BM_LEGACY_DEV_ORDER_CONTEXT *) VarData;
+ while (VarData < VarData + VarSize) {
+ if (DevOrder->BbsType == BbsType) {
+ break;
+ }
+
+ VarData += sizeof (BBS_TYPE);
+ VarData += *(UINT16 *) VarData;
+ DevOrder = (BM_LEGACY_DEV_ORDER_CONTEXT *) VarData;
+ }
+ //
+ // Create oneof tag here for FD/HD/CD #1 #2
+ //
+ for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
+ //
+ // Create the string for oneof tag
+ //
+ UnicodeSPrint (String, sizeof (String), TypeStr, Index);
+ StrRef = 0;
+ IfrLibNewString (CallbackData->BmmHiiHandle, &StrRef, String);
+
+ UnicodeSPrint (String, sizeof (String), TypeStrHelp, Index);
+ StrRefHelp = 0;
+ IfrLibNewString (CallbackData->BmmHiiHandle, &StrRefHelp, String);
+
+ CreateOneOfOpCode (
+ (EFI_QUESTION_ID) (Key + Index),
+ VARSTORE_ID_BOOT_MAINT,
+ (UINT16) (Key + Index - CONFIG_OPTION_OFFSET),
+ StrRef,
+ StrRefHelp,
+ EFI_IFR_FLAG_CALLBACK,
+ EFI_IFR_NUMERIC_SIZE_1,
+ IfrOptionList,
+ OptionMenu->MenuNumber + 1,
+ &gUpdateData
+ );
+
+ VarDevOrder = *(UINT16 *) ((UINT8 *) DevOrder + sizeof (BBS_TYPE) + sizeof (UINT16) + Index * sizeof (UINT16));
+
+ if (0xFF00 == (VarDevOrder & 0xFF00)) {
+ LegacyOrder[Index] = 0xFF;
+ Pos = (VarDevOrder & 0xFF) / 8;
+ Bit = 7 - ((VarDevOrder & 0xFF) % 8);
+ DisMap[Pos] = (UINT8) (DisMap[Pos] | (UINT8) (1 << Bit));
+ } else {
+ LegacyOrder[Index] = (UINT8) (VarDevOrder & 0xFF);
+ }
+ }
+ }
+
+ CopyMem (OldData, LegacyOrder, 100);
+
+ if (IfrOptionList != NULL) {
+ SafeFreePool (IfrOptionList);
+ IfrOptionList = NULL;
+ }
+
+ UpdatePageEnd (CallbackData);
+}
+
+VOID
+UpdatePageId (
+ BMM_CALLBACK_DATA *Private,
+ UINT16 NewPageId
+ )
+{
+ if ((NewPageId < FILE_OPTION_OFFSET) && (NewPageId >= HANDLE_OPTION_OFFSET)) {
+ //
+ // If we select a handle to add driver option, advance to the add handle description page.
+ //
+ NewPageId = FORM_DRV_ADD_HANDLE_DESC_ID;
+ } else if ((NewPageId == KEY_VALUE_SAVE_AND_EXIT) || (NewPageId == KEY_VALUE_NO_SAVE_AND_EXIT)) {
+ //
+ // Return to main page after "Save Changes" or "Discard Changes".
+ //
+ NewPageId = FORM_MAIN_ID;
+ } else if ((NewPageId >= TERMINAL_OPTION_OFFSET) && (NewPageId < CONSOLE_OPTION_OFFSET)) {
+ NewPageId = FORM_CON_COM_SETUP_ID;
+ }
+
+ if ((NewPageId > 0) && (NewPageId < MAXIMUM_FORM_ID)) {
+ Private->BmmPreviousPageId = Private->BmmCurrentPageId;
+ Private->BmmCurrentPageId = NewPageId;
+ }
+}
diff --git a/MdeModulePkg/Universal/BdsDxe/BootMaint/Variable.c b/MdeModulePkg/Universal/BdsDxe/BootMaint/Variable.c new file mode 100644 index 0000000000..f5a1038b46 --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/BootMaint/Variable.c @@ -0,0 +1,1314 @@ +/*++
+
+Copyright (c) 2004 - 2008, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ Variable.c
+
+Abstract:
+
+ Variable operation that will be used by bootmaint
+
+--*/
+
+#include "BootMaint.h"
+
+EFI_STATUS
+Var_DelBootOption (
+ VOID
+ )
+/*++
+
+Routine Description:
+ Delete Boot Option that represent a Deleted state in BootOptionMenu.
+ After deleting this boot option, call Var_ChangeBootOrder to
+ make sure BootOrder is in valid state.
+
+Arguments:
+ LoadOption -- Pointer to the boot option that to be deleted
+
+Returns:
+ EFI_SUCCESS
+ Others
+
+--*/
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_LOAD_CONTEXT *NewLoadContext;
+ UINT16 BootString[10];
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN Index2;
+
+ Status = EFI_SUCCESS;
+ Index2 = 0;
+ for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, (Index - Index2));
+ if (NULL == NewMenuEntry) {
+ return EFI_NOT_FOUND;
+ }
+
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+ if (!NewLoadContext->Deleted) {
+ continue;
+ }
+
+ UnicodeSPrint (
+ BootString,
+ sizeof (BootString),
+ L"Boot%04x",
+ NewMenuEntry->OptionNumber
+ );
+
+ EfiLibDeleteVariable (BootString, &gEfiGlobalVariableGuid);
+ Index2++;
+ //
+ // If current Load Option is the same as BootNext,
+ // must delete BootNext in order to make sure
+ // there will be no panic on next boot
+ //
+ if (NewLoadContext->IsBootNext) {
+ EfiLibDeleteVariable (L"BootNext", &gEfiGlobalVariableGuid);
+ }
+
+ RemoveEntryList (&NewMenuEntry->Link);
+ BOpt_DestroyMenuEntry (NewMenuEntry);
+ NewMenuEntry = NULL;
+ }
+
+ BootOptionMenu.MenuNumber -= Index2;
+
+ Status = Var_ChangeBootOrder ();
+ return Status;
+}
+
+EFI_STATUS
+Var_ChangeBootOrder (
+ VOID
+ )
+/*++
+
+Routine Description:
+ After any operation on Boot####, there will be a discrepancy in BootOrder.
+ Since some are missing but in BootOrder, while some are present but are
+ not reflected by BootOrder. Then a function rebuild BootOrder from
+ scratch by content from BootOptionMenu is needed.
+
+Arguments:
+
+Returns:
+ EFI_SUCCESS
+ Others
+
+--*/
+{
+
+ EFI_STATUS Status;
+ BM_MENU_ENTRY *NewMenuEntry;
+ UINT16 *BootOrderList;
+ UINT16 *BootOrderListPtr;
+ UINTN BootOrderListSize;
+ UINTN Index;
+
+ BootOrderList = NULL;
+ BootOrderListSize = 0;
+
+ //
+ // First check whether BootOrder is present in current configuration
+ //
+ BootOrderList = BdsLibGetVariableAndSize (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ &BootOrderListSize
+ );
+
+ //
+ // If exists, delete it to hold new BootOrder
+ //
+ if (BootOrderList) {
+ EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid);
+ SafeFreePool (BootOrderList);
+ BootOrderList = NULL;
+ }
+ //
+ // Maybe here should be some check method to ensure that
+ // no new added boot options will be added
+ // but the setup engine now will give only one callback
+ // that is to say, user are granted only one chance to
+ // decide whether the boot option will be added or not
+ // there should be no indictor to show whether this
+ // is a "new" boot option
+ //
+ BootOrderListSize = BootOptionMenu.MenuNumber;
+
+ if (BootOrderListSize > 0) {
+ BootOrderList = EfiAllocateZeroPool (BootOrderListSize * sizeof (UINT16));
+ ASSERT (BootOrderList != NULL);
+ BootOrderListPtr = BootOrderList;
+
+ //
+ // Get all current used Boot#### from BootOptionMenu.
+ // OptionNumber in each BM_LOAD_OPTION is really its
+ // #### value.
+ //
+ for (Index = 0; Index < BootOrderListSize; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index);
+ *BootOrderList = (UINT16) NewMenuEntry->OptionNumber;
+ BootOrderList++;
+ }
+
+ BootOrderList = BootOrderListPtr;
+
+ //
+ // After building the BootOrderList, write it back
+ //
+ Status = gRT->SetVariable (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ VAR_FLAG,
+ BootOrderListSize * sizeof (UINT16),
+ BootOrderList
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+Var_DelDriverOption (
+ VOID
+ )
+/*++
+
+Routine Description:
+ Delete Load Option that represent a Deleted state in BootOptionMenu.
+ After deleting this Driver option, call Var_ChangeDriverOrder to
+ make sure DriverOrder is in valid state.
+
+Arguments:
+ LoadOption -- Pointer to the Driver option that to be deleted
+
+Returns:
+ EFI_SUCCESS
+ Others
+
+--*/
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_LOAD_CONTEXT *NewLoadContext;
+ UINT16 DriverString[12];
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN Index2;
+
+ Status = EFI_SUCCESS;
+ Index2 = 0;
+ for (Index = 0; Index < DriverOptionMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, (Index - Index2));
+ if (NULL == NewMenuEntry) {
+ return EFI_NOT_FOUND;
+ }
+
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+ if (!NewLoadContext->Deleted) {
+ continue;
+ }
+
+ UnicodeSPrint (
+ DriverString,
+ sizeof (DriverString),
+ L"Driver%04x",
+ NewMenuEntry->OptionNumber
+ );
+
+ EfiLibDeleteVariable (DriverString, &gEfiGlobalVariableGuid);
+ Index2++;
+
+ RemoveEntryList (&NewMenuEntry->Link);
+ BOpt_DestroyMenuEntry (NewMenuEntry);
+ NewMenuEntry = NULL;
+ }
+
+ DriverOptionMenu.MenuNumber -= Index2;
+
+ Status = Var_ChangeDriverOrder ();
+ return Status;
+}
+
+EFI_STATUS
+Var_ChangeDriverOrder (
+ VOID
+ )
+/*++
+
+Routine Description:
+ After any operation on Driver####, there will be a discrepancy in
+ DriverOrder. Since some are missing but in DriverOrder, while some
+ are present but are not reflected by DriverOrder. Then a function
+ rebuild DriverOrder from scratch by content from DriverOptionMenu is
+ needed.
+
+Arguments:
+
+Returns:
+ EFI_SUCCESS
+ Others
+
+--*/
+{
+ EFI_STATUS Status;
+ BM_MENU_ENTRY *NewMenuEntry;
+ UINT16 *DriverOrderList;
+ UINT16 *DriverOrderListPtr;
+ UINTN DriverOrderListSize;
+ UINTN Index;
+
+ DriverOrderList = NULL;
+ DriverOrderListSize = 0;
+
+ //
+ // First check whether DriverOrder is present in current configuration
+ //
+ DriverOrderList = BdsLibGetVariableAndSize (
+ L"DriverOrder",
+ &gEfiGlobalVariableGuid,
+ &DriverOrderListSize
+ );
+
+ //
+ // If exists, delete it to hold new DriverOrder
+ //
+ if (DriverOrderList) {
+ EfiLibDeleteVariable (L"DriverOrder", &gEfiGlobalVariableGuid);
+ SafeFreePool (DriverOrderList);
+ DriverOrderList = NULL;
+ }
+
+ DriverOrderListSize = DriverOptionMenu.MenuNumber;
+
+ if (DriverOrderListSize > 0) {
+ DriverOrderList = EfiAllocateZeroPool (DriverOrderListSize * sizeof (UINT16));
+ ASSERT (DriverOrderList != NULL);
+ DriverOrderListPtr = DriverOrderList;
+
+ //
+ // Get all current used Driver#### from DriverOptionMenu.
+ // OptionNumber in each BM_LOAD_OPTION is really its
+ // #### value.
+ //
+ for (Index = 0; Index < DriverOrderListSize; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index);
+ *DriverOrderList = (UINT16) NewMenuEntry->OptionNumber;
+ DriverOrderList++;
+ }
+
+ DriverOrderList = DriverOrderListPtr;
+
+ //
+ // After building the DriverOrderList, write it back
+ //
+ Status = gRT->SetVariable (
+ L"DriverOrder",
+ &gEfiGlobalVariableGuid,
+ VAR_FLAG,
+ DriverOrderListSize * sizeof (UINT16),
+ DriverOrderList
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+VOID
+Var_UpdateAllConsoleOption (
+ VOID
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *OutDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *InpDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *ErrDevicePath;
+ EFI_STATUS Status;
+
+ OutDevicePath = EfiLibGetVariable (L"ConOut", &gEfiGlobalVariableGuid);
+ InpDevicePath = EfiLibGetVariable (L"ConIn", &gEfiGlobalVariableGuid);
+ ErrDevicePath = EfiLibGetVariable (L"ErrOut", &gEfiGlobalVariableGuid);
+ if (OutDevicePath) {
+ ChangeVariableDevicePath (OutDevicePath);
+ Status = gRT->SetVariable (
+ L"ConOut",
+ &gEfiGlobalVariableGuid,
+ VAR_FLAG,
+ GetDevicePathSize (OutDevicePath),
+ OutDevicePath
+ );
+ ASSERT (!EFI_ERROR (Status));
+ }
+
+ if (InpDevicePath) {
+ ChangeVariableDevicePath (InpDevicePath);
+ Status = gRT->SetVariable (
+ L"ConIn",
+ &gEfiGlobalVariableGuid,
+ VAR_FLAG,
+ GetDevicePathSize (InpDevicePath),
+ InpDevicePath
+ );
+ ASSERT (!EFI_ERROR (Status));
+ }
+
+ if (ErrDevicePath) {
+ ChangeVariableDevicePath (ErrDevicePath);
+ Status = gRT->SetVariable (
+ L"ErrOut",
+ &gEfiGlobalVariableGuid,
+ VAR_FLAG,
+ GetDevicePathSize (ErrDevicePath),
+ ErrDevicePath
+ );
+ ASSERT (!EFI_ERROR (Status));
+ }
+}
+
+EFI_STATUS
+Var_UpdateConsoleOption (
+ IN UINT16 *ConsoleName,
+ IN BM_MENU_OPTION *ConsoleMenu,
+ IN UINT16 UpdatePageId
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *ConDevicePath;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_CONSOLE_CONTEXT *NewConsoleContext;
+ BM_TERMINAL_CONTEXT *NewTerminalContext;
+ EFI_STATUS Status;
+ VENDOR_DEVICE_PATH Vendor;
+ EFI_DEVICE_PATH_PROTOCOL *TerminalDevicePath;
+ UINTN Index;
+
+ ConDevicePath = EfiLibGetVariable (ConsoleName, &gEfiGlobalVariableGuid);
+ if (ConDevicePath != NULL) {
+ EfiLibDeleteVariable (ConsoleName, &gEfiGlobalVariableGuid);
+ SafeFreePool (ConDevicePath);
+ ConDevicePath = NULL;
+ };
+
+ //
+ // First add all console input device to it from console input menu
+ //
+ for (Index = 0; Index < ConsoleMenu->MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (ConsoleMenu, Index);
+ if (NULL == NewMenuEntry) {
+ return EFI_NOT_FOUND;
+ }
+
+ NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;
+ if (NewConsoleContext->IsActive) {
+ ConDevicePath = AppendDevicePathInstance (
+ ConDevicePath,
+ NewConsoleContext->DevicePath
+ );
+ }
+ }
+
+ for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);
+ if (NULL == NewMenuEntry) {
+ return EFI_NOT_FOUND;
+ }
+
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
+ if ((NewTerminalContext->IsConIn && (UpdatePageId == FORM_CON_IN_ID)) ||
+ (NewTerminalContext->IsConOut && (UpdatePageId == FORM_CON_OUT_ID)) ||
+ (NewTerminalContext->IsStdErr && (UpdatePageId == FORM_CON_ERR_ID))
+ ) {
+ Vendor.Header.Type = MESSAGING_DEVICE_PATH;
+ Vendor.Header.SubType = MSG_VENDOR_DP;
+ CopyMem (
+ &Vendor.Guid,
+ &Guid[NewTerminalContext->TerminalType],
+ sizeof (EFI_GUID)
+ );
+ SetDevicePathNodeLength (&Vendor.Header, sizeof (VENDOR_DEVICE_PATH));
+ TerminalDevicePath = AppendDevicePathNode (
+ NewTerminalContext->DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &Vendor
+ );
+ ASSERT (TerminalDevicePath != NULL);
+ ChangeTerminalDevicePath (TerminalDevicePath, TRUE);
+ ConDevicePath = AppendDevicePathInstance (
+ ConDevicePath,
+ TerminalDevicePath
+ );
+ }
+ }
+
+ if (ConDevicePath) {
+ Status = gRT->SetVariable (
+ ConsoleName,
+ &gEfiGlobalVariableGuid,
+ VAR_FLAG,
+ GetDevicePathSize (ConDevicePath),
+ ConDevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+EFI_STATUS
+Var_UpdateConsoleInpOption (
+ VOID
+ )
+{
+ return Var_UpdateConsoleOption (L"ConIn", &ConsoleInpMenu, FORM_CON_IN_ID);
+}
+
+EFI_STATUS
+Var_UpdateConsoleOutOption (
+ VOID
+ )
+{
+ return Var_UpdateConsoleOption (L"ConOut", &ConsoleOutMenu, FORM_CON_OUT_ID);
+}
+
+EFI_STATUS
+Var_UpdateErrorOutOption (
+ VOID
+ )
+{
+ return Var_UpdateConsoleOption (L"ErrOut", &ConsoleErrMenu, FORM_CON_ERR_ID);
+}
+
+EFI_STATUS
+Var_UpdateDriverOption (
+ IN BMM_CALLBACK_DATA *CallbackData,
+ IN EFI_HII_HANDLE HiiHandle,
+ IN UINT16 *DescriptionData,
+ IN UINT16 *OptionalData,
+ IN UINT8 ForceReconnect
+ )
+{
+ UINT16 Index;
+ UINT16 *DriverOrderList;
+ UINT16 *NewDriverOrderList;
+ UINT16 DriverString[12];
+ UINTN DriverOrderListSize;
+ VOID *Buffer;
+ UINTN BufferSize;
+ UINT8 *Ptr;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_LOAD_CONTEXT *NewLoadContext;
+ BOOLEAN OptionalDataExist;
+ EFI_STATUS Status;
+
+ OptionalDataExist = FALSE;
+
+ Index = BOpt_GetDriverOptionNumber ();
+ UnicodeSPrint (
+ DriverString,
+ sizeof (DriverString),
+ L"Driver%04x",
+ Index
+ );
+
+ if (*DescriptionData == 0x0000) {
+ StrCpy (DescriptionData, DriverString);
+ }
+
+ BufferSize = sizeof (UINT32) + sizeof (UINT16) + StrSize (DescriptionData);
+ BufferSize += GetDevicePathSize (CallbackData->LoadContext->FilePathList);
+
+ if (*OptionalData != 0x0000) {
+ OptionalDataExist = TRUE;
+ BufferSize += StrSize (OptionalData);
+ }
+
+ Buffer = EfiAllocateZeroPool (BufferSize);
+ if (NULL == Buffer) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
+ if (NULL == NewMenuEntry) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+ NewLoadContext->Deleted = FALSE;
+ NewLoadContext->LoadOptionSize = BufferSize;
+ Ptr = (UINT8 *) Buffer;
+ NewLoadContext->LoadOption = Ptr;
+ *((UINT32 *) Ptr) = LOAD_OPTION_ACTIVE | (ForceReconnect << 1);
+ NewLoadContext->Attributes = *((UINT32 *) Ptr);
+ NewLoadContext->IsActive = TRUE;
+ NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);
+
+ Ptr += sizeof (UINT32);
+ *((UINT16 *) Ptr) = (UINT16) GetDevicePathSize (CallbackData->LoadContext->FilePathList);
+ NewLoadContext->FilePathListLength = *((UINT16 *) Ptr);
+
+ Ptr += sizeof (UINT16);
+ CopyMem (
+ Ptr,
+ DescriptionData,
+ StrSize (DescriptionData)
+ );
+
+ NewLoadContext->Description = EfiAllocateZeroPool (StrSize (DescriptionData));
+ ASSERT (NewLoadContext->Description != NULL);
+ NewMenuEntry->DisplayString = NewLoadContext->Description;
+ CopyMem (
+ NewLoadContext->Description,
+ (VOID *) Ptr,
+ StrSize (DescriptionData)
+ );
+
+ Ptr += StrSize (DescriptionData);
+ CopyMem (
+ Ptr,
+ CallbackData->LoadContext->FilePathList,
+ GetDevicePathSize (CallbackData->LoadContext->FilePathList)
+ );
+
+ NewLoadContext->FilePathList = EfiAllocateZeroPool (GetDevicePathSize (CallbackData->LoadContext->FilePathList));
+ ASSERT (NewLoadContext->FilePathList != NULL);
+
+ CopyMem (
+ NewLoadContext->FilePathList,
+ (VOID *) Ptr,
+ GetDevicePathSize (CallbackData->LoadContext->FilePathList)
+ );
+
+ NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList);
+ NewMenuEntry->OptionNumber = Index;
+ NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (
+ CallbackData,
+ DriverOptionStrDepository
+ );
+ IfrLibNewString (HiiHandle, &NewMenuEntry->DisplayStringToken, NewMenuEntry->DisplayString);
+
+ NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (
+ CallbackData,
+ DriverOptionHelpStrDepository
+ );
+ IfrLibNewString (HiiHandle, &NewMenuEntry->HelpStringToken, NewMenuEntry->HelpString);
+
+ if (OptionalDataExist) {
+ Ptr += (UINT8) GetDevicePathSize (CallbackData->LoadContext->FilePathList);
+
+ CopyMem (
+ Ptr,
+ OptionalData,
+ StrSize (OptionalData)
+ );
+ }
+
+ Status = gRT->SetVariable (
+ DriverString,
+ &gEfiGlobalVariableGuid,
+ VAR_FLAG,
+ BufferSize,
+ Buffer
+ );
+ ASSERT_EFI_ERROR (Status);
+ DriverOrderList = BdsLibGetVariableAndSize (
+ L"DriverOrder",
+ &gEfiGlobalVariableGuid,
+ &DriverOrderListSize
+ );
+ NewDriverOrderList = EfiAllocateZeroPool (DriverOrderListSize + sizeof (UINT16));
+ ASSERT (NewDriverOrderList != NULL);
+ CopyMem (NewDriverOrderList, DriverOrderList, DriverOrderListSize);
+ NewDriverOrderList[DriverOrderListSize / sizeof (UINT16)] = Index;
+ if (DriverOrderList != NULL) {
+ EfiLibDeleteVariable (L"DriverOrder", &gEfiGlobalVariableGuid);
+ }
+
+ Status = gRT->SetVariable (
+ L"DriverOrder",
+ &gEfiGlobalVariableGuid,
+ VAR_FLAG,
+ DriverOrderListSize + sizeof (UINT16),
+ NewDriverOrderList
+ );
+ ASSERT_EFI_ERROR (Status);
+ SafeFreePool (DriverOrderList);
+ DriverOrderList = NULL;
+ SafeFreePool (NewDriverOrderList);
+ NewDriverOrderList = NULL;
+ InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link);
+ DriverOptionMenu.MenuNumber++;
+
+ *DescriptionData = 0x0000;
+ *OptionalData = 0x0000;
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+Var_UpdateBootOption (
+ IN BMM_CALLBACK_DATA *CallbackData,
+ IN FILE_EXPLORER_NV_DATA *NvRamMap
+ )
+{
+ UINT16 *BootOrderList;
+ UINT16 *NewBootOrderList;
+ UINTN BootOrderListSize;
+ UINT16 BootString[10];
+ VOID *Buffer;
+ UINTN BufferSize;
+ UINT8 *Ptr;
+ UINT16 Index;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_LOAD_CONTEXT *NewLoadContext;
+ BOOLEAN OptionalDataExist;
+ EFI_STATUS Status;
+
+ OptionalDataExist = FALSE;
+
+ Index = BOpt_GetBootOptionNumber () ;
+ UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", Index);
+
+ if (NvRamMap->DescriptionData[0] == 0x0000) {
+ StrCpy (NvRamMap->DescriptionData, BootString);
+ }
+
+ BufferSize = sizeof (UINT32) + sizeof (UINT16) + StrSize (NvRamMap->DescriptionData);
+ BufferSize += GetDevicePathSize (CallbackData->LoadContext->FilePathList);
+
+ if (NvRamMap->OptionalData[0] != 0x0000) {
+ OptionalDataExist = TRUE;
+ BufferSize += StrSize (NvRamMap->OptionalData);
+ }
+
+ Buffer = EfiAllocateZeroPool (BufferSize);
+ if (NULL == Buffer) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
+ if (NULL == NewMenuEntry) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+ NewLoadContext->Deleted = FALSE;
+ NewLoadContext->LoadOptionSize = BufferSize;
+ Ptr = (UINT8 *) Buffer;
+ NewLoadContext->LoadOption = Ptr;
+ *((UINT32 *) Ptr) = LOAD_OPTION_ACTIVE;
+ NewLoadContext->Attributes = *((UINT32 *) Ptr);
+ NewLoadContext->IsActive = TRUE;
+ NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);
+
+ Ptr += sizeof (UINT32);
+ *((UINT16 *) Ptr) = (UINT16) GetDevicePathSize (CallbackData->LoadContext->FilePathList);
+ NewLoadContext->FilePathListLength = *((UINT16 *) Ptr);
+ Ptr += sizeof (UINT16);
+
+ CopyMem (
+ Ptr,
+ NvRamMap->DescriptionData,
+ StrSize (NvRamMap->DescriptionData)
+ );
+
+ NewLoadContext->Description = EfiAllocateZeroPool (StrSize (NvRamMap->DescriptionData));
+ ASSERT (NewLoadContext->Description != NULL);
+
+ NewMenuEntry->DisplayString = NewLoadContext->Description;
+ CopyMem (
+ NewLoadContext->Description,
+ (VOID *) Ptr,
+ StrSize (NvRamMap->DescriptionData)
+ );
+
+ Ptr += StrSize (NvRamMap->DescriptionData);
+ CopyMem (
+ Ptr,
+ CallbackData->LoadContext->FilePathList,
+ GetDevicePathSize (CallbackData->LoadContext->FilePathList)
+ );
+
+ NewLoadContext->FilePathList = EfiAllocateZeroPool (GetDevicePathSize (CallbackData->LoadContext->FilePathList));
+ ASSERT (NewLoadContext->FilePathList != NULL);
+
+ CopyMem (
+ NewLoadContext->FilePathList,
+ (VOID *) Ptr,
+ GetDevicePathSize (CallbackData->LoadContext->FilePathList)
+ );
+
+ NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList);
+ NewMenuEntry->OptionNumber = Index;
+ NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (
+ CallbackData,
+ BootOptionStrDepository
+ );
+ IfrLibNewString (CallbackData->FeHiiHandle, &NewMenuEntry->DisplayStringToken, NewMenuEntry->DisplayString);
+
+ NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (
+ CallbackData,
+ BootOptionHelpStrDepository
+ );
+ IfrLibNewString (CallbackData->FeHiiHandle, &NewMenuEntry->HelpStringToken, NewMenuEntry->HelpString);
+
+ if (OptionalDataExist) {
+ Ptr += (UINT8) GetDevicePathSize (CallbackData->LoadContext->FilePathList);
+
+ CopyMem (Ptr, NvRamMap->OptionalData, StrSize (NvRamMap->OptionalData));
+ }
+
+ Status = gRT->SetVariable (
+ BootString,
+ &gEfiGlobalVariableGuid,
+ VAR_FLAG,
+ BufferSize,
+ Buffer
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ BootOrderList = BdsLibGetVariableAndSize (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ &BootOrderListSize
+ );
+
+ NewBootOrderList = EfiAllocateZeroPool (BootOrderListSize + sizeof (UINT16));
+ ASSERT (NewBootOrderList != NULL);
+ CopyMem (NewBootOrderList, BootOrderList, BootOrderListSize);
+ NewBootOrderList[BootOrderListSize / sizeof (UINT16)] = Index;
+
+ if (BootOrderList != NULL) {
+ EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid);
+ }
+
+ Status = gRT->SetVariable (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ VAR_FLAG,
+ BootOrderListSize + sizeof (UINT16),
+ NewBootOrderList
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ SafeFreePool (BootOrderList);
+ BootOrderList = NULL;
+ SafeFreePool (NewBootOrderList);
+ NewBootOrderList = NULL;
+ InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link);
+ BootOptionMenu.MenuNumber++;
+
+ NvRamMap->DescriptionData[0] = 0x0000;
+ NvRamMap->OptionalData[0] = 0x0000;
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+Var_UpdateBootNext (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_LOAD_CONTEXT *NewLoadContext;
+ BMM_FAKE_NV_DATA *CurrentFakeNVMap;
+ UINT16 Index;
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+ CurrentFakeNVMap = &CallbackData->BmmFakeNvData;
+ for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index);
+ if (NULL == NewMenuEntry) {
+ return EFI_NOT_FOUND;
+ }
+
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+ NewLoadContext->IsBootNext = FALSE;
+ }
+
+ if (CurrentFakeNVMap->BootNext == BootOptionMenu.MenuNumber) {
+ EfiLibDeleteVariable (L"BootNext", &gEfiGlobalVariableGuid);
+ return EFI_SUCCESS;
+ }
+
+ NewMenuEntry = BOpt_GetMenuEntry (
+ &BootOptionMenu,
+ CurrentFakeNVMap->BootNext
+ );
+ if (NULL == NewMenuEntry) {
+ return EFI_NOT_FOUND;
+ }
+
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+ Status = gRT->SetVariable (
+ L"BootNext",
+ &gEfiGlobalVariableGuid,
+ VAR_FLAG,
+ sizeof (UINT16),
+ &NewMenuEntry->OptionNumber
+ );
+ NewLoadContext->IsBootNext = TRUE;
+ CallbackData->BmmOldFakeNVData.BootNext = CurrentFakeNVMap->BootNext;
+ return Status;
+}
+
+EFI_STATUS
+Var_UpdateBootOrder (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ EFI_STATUS Status;
+ UINT16 Index;
+ UINT16 *BootOrderList;
+ UINT16 *NewBootOrderList;
+ UINTN BootOrderListSize;
+ UINT8 *Map;
+
+ BootOrderList = NULL;
+ BootOrderListSize = 0;
+
+ //
+ // First check whether BootOrder is present in current configuration
+ //
+ BootOrderList = BdsLibGetVariableAndSize (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ &BootOrderListSize
+ );
+
+ NewBootOrderList = EfiAllocateZeroPool (BootOrderListSize);
+ if (!NewBootOrderList) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Map = EfiAllocateZeroPool (BootOrderListSize / sizeof (UINT16));
+ if (!Map) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // If exists, delete it to hold new BootOrder
+ //
+ if (BootOrderList) {
+ EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid);
+ }
+
+ for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
+ NewBootOrderList[Index] = (UINT16) (CallbackData->BmmFakeNvData.OptionOrder[Index] - 1);
+ }
+
+ Status = gRT->SetVariable (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ VAR_FLAG,
+ BootOrderListSize,
+ NewBootOrderList
+ );
+ SafeFreePool (BootOrderList);
+ SafeFreePool (NewBootOrderList);
+ SafeFreePool (Map);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BOpt_FreeMenu (&BootOptionMenu);
+ BOpt_GetBootOptions (CallbackData);
+
+ return EFI_SUCCESS;
+
+}
+
+EFI_STATUS
+Var_UpdateDriverOrder (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ EFI_STATUS Status;
+ UINT16 Index;
+ UINT16 *DriverOrderList;
+ UINT16 *NewDriverOrderList;
+ UINTN DriverOrderListSize;
+
+ DriverOrderList = NULL;
+ DriverOrderListSize = 0;
+
+ //
+ // First check whether DriverOrder is present in current configuration
+ //
+ DriverOrderList = BdsLibGetVariableAndSize (
+ L"DriverOrder",
+ &gEfiGlobalVariableGuid,
+ &DriverOrderListSize
+ );
+
+ NewDriverOrderList = EfiAllocateZeroPool (DriverOrderListSize);
+
+ if (!NewDriverOrderList) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // If exists, delete it to hold new DriverOrder
+ //
+ if (DriverOrderList) {
+ EfiLibDeleteVariable (L"DriverOrder", &gEfiGlobalVariableGuid);
+ }
+
+ for (Index = 0; Index < DriverOrderListSize; Index++) {
+ NewDriverOrderList[Index] = (UINT16) (CallbackData->BmmFakeNvData.OptionOrder[Index] - 1);
+ }
+
+ Status = gRT->SetVariable (
+ L"DriverOrder",
+ &gEfiGlobalVariableGuid,
+ VAR_FLAG,
+ DriverOrderListSize,
+ NewDriverOrderList
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ SafeFreePool (DriverOrderList);
+
+ BOpt_FreeMenu (&DriverOptionMenu);
+ BOpt_GetDriverOptions (CallbackData);
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+Var_UpdateBBSOption (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ UINTN Index;
+ UINTN Index2;
+ VOID *BootOptionVar;
+ CHAR16 VarName[100];
+ UINTN OptionSize;
+ UINT8 *Ptr;
+ EFI_STATUS Status;
+ CHAR16 DescString[100];
+ CHAR8 DescAsciiString[100];
+ UINTN NewOptionSize;
+ UINT8 *NewOptionPtr;
+ UINT8 *TempPtr;
+ UINT32 *Attribute;
+ BM_MENU_OPTION *OptionMenu;
+ BM_LEGACY_DEVICE_CONTEXT *LegacyDeviceContext;
+ UINT8 *LegacyDev;
+ UINT8 *VarData;
+ UINTN VarSize;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_LEGACY_DEV_ORDER_CONTEXT *DevOrder;
+ UINT8 *OriginalPtr;
+ UINT8 *DisMap;
+ UINTN Pos;
+ UINTN Bit;
+ UINT16 *NewOrder;
+ UINT16 Tmp;
+
+ LegacyDeviceContext = NULL;
+ DisMap = NULL;
+ NewOrder = NULL;
+
+ if (FORM_SET_FD_ORDER_ID == CallbackData->BmmPreviousPageId) {
+ OptionMenu = (BM_MENU_OPTION *) &LegacyFDMenu;
+ LegacyDev = CallbackData->BmmFakeNvData.LegacyFD;
+ CallbackData->BbsType = BBS_FLOPPY;
+ } else {
+ if (FORM_SET_HD_ORDER_ID == CallbackData->BmmPreviousPageId) {
+ OptionMenu = (BM_MENU_OPTION *) &LegacyHDMenu;
+ LegacyDev = CallbackData->BmmFakeNvData.LegacyHD;
+ CallbackData->BbsType = BBS_HARDDISK;
+ } else {
+ if (FORM_SET_CD_ORDER_ID == CallbackData->BmmPreviousPageId) {
+ OptionMenu = (BM_MENU_OPTION *) &LegacyCDMenu;
+ LegacyDev = CallbackData->BmmFakeNvData.LegacyCD;
+ CallbackData->BbsType = BBS_CDROM;
+ } else {
+ if (FORM_SET_NET_ORDER_ID == CallbackData->BmmPreviousPageId) {
+ OptionMenu = (BM_MENU_OPTION *) &LegacyNETMenu;
+ LegacyDev = CallbackData->BmmFakeNvData.LegacyNET;
+ CallbackData->BbsType = BBS_EMBED_NETWORK;
+ } else {
+ OptionMenu = (BM_MENU_OPTION *) &LegacyBEVMenu;
+ LegacyDev = CallbackData->BmmFakeNvData.LegacyBEV;
+ CallbackData->BbsType = BBS_BEV_DEVICE;
+ }
+ }
+ }
+ }
+
+ DisMap = CallbackData->BmmOldFakeNVData.DisableMap;
+ Status = EFI_SUCCESS;
+
+ //
+ // Find the first device's context
+ // If all devices are disabled( 0xFF == LegacyDev[0]), LegacyDeviceContext can be set to any VariableContext
+ // because we just use it to fill the desc string, and user can not see the string in UI
+ //
+ for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (OptionMenu, Index);
+ LegacyDeviceContext = (BM_LEGACY_DEVICE_CONTEXT *) NewMenuEntry->VariableContext;
+ if (0xFF != LegacyDev[0] && LegacyDev[0] == LegacyDeviceContext->Index) {
+ DEBUG ((DEBUG_ERROR, "DescStr: %s\n", LegacyDeviceContext->Description));
+ break;
+ }
+ }
+ //
+ // Update the Variable "LegacyDevOrder"
+ //
+ VarData = (UINT8 *) BdsLibGetVariableAndSize (
+ VarLegacyDevOrder,
+ &EfiLegacyDevOrderGuid,
+ &VarSize
+ );
+
+ if (NULL == VarData) {
+ return EFI_NOT_FOUND;
+ }
+
+ OriginalPtr = VarData;
+ DevOrder = (BM_LEGACY_DEV_ORDER_CONTEXT *) VarData;
+
+ while (VarData < VarData + VarSize) {
+ if (DevOrder->BbsType == CallbackData->BbsType) {
+ break;
+ }
+
+ VarData += sizeof (BBS_TYPE);
+ VarData += *(UINT16 *) VarData;
+ DevOrder = (BM_LEGACY_DEV_ORDER_CONTEXT *) VarData;
+ }
+
+ if (VarData >= VarData + VarSize) {
+ SafeFreePool (OriginalPtr);
+ return EFI_NOT_FOUND;
+ }
+
+ NewOrder = (UINT16 *) EfiAllocateZeroPool (DevOrder->Length - sizeof (UINT16));
+ if (NULL == NewOrder) {
+ SafeFreePool (VarData);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
+ if (0xFF == LegacyDev[Index]) {
+ break;
+ }
+
+ NewOrder[Index] = LegacyDev[Index];
+ }
+ //
+ // Only the enable/disable state of each boot device with same device type can be changed,
+ // so we can count on the index information in DevOrder.
+ // DisMap bit array is the only reliable source to check a device's en/dis state,
+ // so we use DisMap to set en/dis state of each item in NewOrder array
+ //
+ for (Index2 = 0; Index2 < OptionMenu->MenuNumber; Index2++) {
+ Tmp = *(UINT16 *) ((UINT8 *) DevOrder + sizeof (BBS_TYPE) + sizeof (UINT16) + Index2 * sizeof (UINT16));
+ Tmp &= 0xFF;
+ Pos = Tmp / 8;
+ Bit = 7 - (Tmp % 8);
+ if (DisMap[Pos] & (1 << Bit)) {
+ NewOrder[Index] = (UINT16) (0xFF00 | Tmp);
+ Index++;
+ }
+ }
+
+ CopyMem (
+ (UINT8 *) DevOrder + sizeof (BBS_TYPE) + sizeof (UINT16),
+ NewOrder,
+ DevOrder->Length - sizeof (UINT16)
+ );
+ SafeFreePool (NewOrder);
+
+ Status = gRT->SetVariable (
+ VarLegacyDevOrder,
+ &EfiLegacyDevOrderGuid,
+ VAR_FLAG,
+ VarSize,
+ OriginalPtr
+ );
+
+ SafeFreePool (OriginalPtr);
+
+ //
+ // Update Optional Data of Boot####
+ //
+ BootOptionVar = GetLegacyBootOptionVar (CallbackData->BbsType, &Index, &OptionSize);
+
+ if (NULL != BootOptionVar) {
+ CopyMem (
+ DescString,
+ LegacyDeviceContext->Description,
+ StrSize (LegacyDeviceContext->Description)
+ );
+
+ UnicodeToAscii (DescString, StrSize (DescString), DescAsciiString);
+
+ NewOptionSize = sizeof (UINT32) + sizeof (UINT16) + StrSize (DescString) +
+ sizeof (BBS_BBS_DEVICE_PATH);
+ NewOptionSize += AsciiStrLen (DescAsciiString) +
+ EFI_END_DEVICE_PATH_LENGTH + sizeof (BBS_TABLE) + sizeof (UINT16);
+
+ UnicodeSPrint (VarName, 100, L"Boot%04x", Index);
+
+ Ptr = BootOptionVar;
+
+ Attribute = (UINT32 *) Ptr;
+ *Attribute |= LOAD_OPTION_ACTIVE;
+ if (0xFF == LegacyDev[0]) {
+ //
+ // Disable this legacy boot option
+ //
+ *Attribute &= ~LOAD_OPTION_ACTIVE;
+ }
+
+ Ptr += sizeof (UINT32);
+
+ Ptr += sizeof (UINT16);
+ Ptr += StrSize ((CHAR16 *) Ptr);
+
+ NewOptionPtr = EfiAllocateZeroPool (NewOptionSize);
+ if (NULL == NewOptionPtr) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ TempPtr = NewOptionPtr;
+
+ //
+ // Attribute
+ //
+ CopyMem (
+ TempPtr,
+ BootOptionVar,
+ sizeof (UINT32)
+ );
+
+ TempPtr += sizeof (UINT32);
+
+ //
+ // BBS device path Length
+ //
+ *((UINT16 *) TempPtr) = (UINT16) (sizeof (BBS_BBS_DEVICE_PATH) +
+ AsciiStrLen (DescAsciiString) +
+ EFI_END_DEVICE_PATH_LENGTH);
+
+ TempPtr += sizeof (UINT16);
+
+ //
+ // Description string
+ //
+ CopyMem (
+ TempPtr,
+ DescString,
+ StrSize (DescString)
+ );
+
+ TempPtr += StrSize (DescString);
+
+ //
+ // BBS device path
+ //
+ CopyMem (
+ TempPtr,
+ Ptr,
+ sizeof (BBS_BBS_DEVICE_PATH)
+ );
+
+ CopyMem (
+ ((BBS_BBS_DEVICE_PATH*) TempPtr)->String,
+ DescAsciiString,
+ AsciiStrSize (DescAsciiString)
+ );
+
+ SetDevicePathNodeLength (
+ (EFI_DEVICE_PATH_PROTOCOL *) TempPtr,
+ sizeof (BBS_BBS_DEVICE_PATH) + AsciiStrLen (DescAsciiString)
+ );
+
+ TempPtr += sizeof (BBS_BBS_DEVICE_PATH) + AsciiStrLen (DescAsciiString);
+
+ //
+ // End node
+ //
+ CopyMem (
+ TempPtr,
+ EndDevicePath,
+ EFI_END_DEVICE_PATH_LENGTH
+ );
+ TempPtr += EFI_END_DEVICE_PATH_LENGTH;
+
+ //
+ // Now TempPtr point to optional data, i.e. Bbs Table
+ //
+ CopyMem (
+ TempPtr,
+ LegacyDeviceContext->BbsTable,
+ sizeof (BBS_TABLE)
+ );
+
+ //
+ // Now TempPtr point to BBS index
+ //
+ TempPtr += sizeof (BBS_TABLE);
+ *((UINT16 *) TempPtr) = (UINT16) LegacyDeviceContext->Index;
+
+ Status = gRT->SetVariable (
+ VarName,
+ &gEfiGlobalVariableGuid,
+ VAR_FLAG,
+ NewOptionSize,
+ NewOptionPtr
+ );
+
+ SafeFreePool (NewOptionPtr);
+ SafeFreePool (BootOptionVar);
+ }
+
+ BOpt_GetBootOptions (CallbackData);
+ return Status;
+}
+
+EFI_STATUS
+Var_UpdateConMode (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ EFI_STATUS Status;
+ UINTN Mode;
+ CONSOLE_OUT_MODE ModeInfo;
+
+ Mode = CallbackData->BmmFakeNvData.ConsoleOutMode;
+
+ Status = gST->ConOut->QueryMode (gST->ConOut, Mode, &(ModeInfo.Column), &(ModeInfo.Row));
+ if (EFI_ERROR(Status)) {
+ ModeInfo.Column = 80;
+ ModeInfo.Row = 25;
+ }
+
+ Status = gRT->SetVariable (
+ VarConOutMode,
+ &gEfiGenericPlatformVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ sizeof (CONSOLE_OUT_MODE),
+ &ModeInfo
+ );
+
+ return Status;
+}
diff --git a/MdeModulePkg/Universal/BdsDxe/BootMngr/BootManager.c b/MdeModulePkg/Universal/BdsDxe/BootMngr/BootManager.c new file mode 100644 index 0000000000..fdf39cac98 --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/BootMngr/BootManager.c @@ -0,0 +1,335 @@ +/*++
+
+Copyright (c) 2004 - 2008, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ BootManager.c
+
+Abstract:
+
+ The platform boot manager reference implement
+
+--*/
+
+#include "BootManager.h"
+
+UINT16 mKeyInput;
+EFI_GUID mBootManagerGuid = BOOT_MANAGER_FORMSET_GUID;
+LIST_ENTRY *mBootOptionsList;
+BDS_COMMON_OPTION *gOption;
+
+BOOT_MANAGER_CALLBACK_DATA gBootManagerPrivate = {
+ BOOT_MANAGER_CALLBACK_DATA_SIGNATURE,
+ NULL,
+ NULL,
+ {
+ FakeExtractConfig,
+ FakeRouteConfig,
+ BootManagerCallback
+ }
+};
+
+EFI_STATUS
+EFIAPI
+BootManagerCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+/*++
+
+ Routine Description:
+ This function processes the results of changes in configuration.
+
+ Arguments:
+ This - Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ Action - Specifies the type of action taken by the browser.
+ QuestionId - A unique value which is sent to the original exporting driver
+ so that it can identify the type of data to expect.
+ Type - The type of value for the question.
+ Value - A pointer to the data being sent to the original exporting driver.
+ ActionRequest - On return, points to the action requested by the callback function.
+
+ Returns:
+ EFI_SUCCESS - The callback successfully handled the action.
+ EFI_OUT_OF_RESOURCES - Not enough storage is available to hold the variable and its data.
+ EFI_DEVICE_ERROR - The variable could not be saved.
+ EFI_UNSUPPORTED - The specified Action is not supported by the callback.
+
+--*/
+{
+ BDS_COMMON_OPTION *Option;
+ LIST_ENTRY *Link;
+ UINT16 KeyCount;
+
+ if ((Value == NULL) || (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Initialize the key count
+ //
+ KeyCount = 0;
+
+ for (Link = mBootOptionsList->ForwardLink; Link != mBootOptionsList; Link = Link->ForwardLink) {
+ Option = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);
+
+ KeyCount++;
+
+ gOption = Option;
+
+ //
+ // Is this device the one chosen?
+ //
+ if (KeyCount == QuestionId) {
+ //
+ // Assigning the returned Key to a global allows the original routine to know what was chosen
+ //
+ mKeyInput = QuestionId;
+
+ //
+ // Request to exit SendForm(), so that we could boot the selected option
+ //
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ break;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+InitializeBootManager (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Initialize HII information for the FrontPage
+
+Arguments:
+ None
+
+Returns:
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_HII_PACKAGE_LIST_HEADER *PackageList;
+
+ //
+ // Create driver handle used by HII database
+ //
+ Status = HiiLibCreateHiiDriverHandle (&gBootManagerPrivate.DriverHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Install Config Access protocol to driver handle
+ //
+ Status = gBS->InstallProtocolInterface (
+ &gBootManagerPrivate.DriverHandle,
+ &gEfiHiiConfigAccessProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &gBootManagerPrivate.ConfigAccess
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Publish our HII data
+ //
+ PackageList = PreparePackageList (2, &mBootManagerGuid, BootManagerVfrBin, BdsStrings);
+ ASSERT (PackageList != NULL);
+
+ Status = gHiiDatabase->NewPackageList (
+ gHiiDatabase,
+ PackageList,
+ gBootManagerPrivate.DriverHandle,
+ &gBootManagerPrivate.HiiHandle
+ );
+ FreePool (PackageList);
+
+ return Status;
+}
+
+VOID
+CallBootManager (
+ VOID
+ )
+/*++
+
+Routine Description:
+ Hook to enable UI timeout override behavior.
+
+Arguments:
+ BdsDeviceList - Device List that BDS needs to connect.
+
+ Entry - Pointer to current Boot Entry.
+
+Returns:
+ NONE
+
+--*/
+{
+ EFI_STATUS Status;
+ BDS_COMMON_OPTION *Option;
+ LIST_ENTRY *Link;
+ EFI_HII_UPDATE_DATA UpdateData;
+ CHAR16 *ExitData;
+ UINTN ExitDataSize;
+ EFI_STRING_ID Token;
+ EFI_INPUT_KEY Key;
+ LIST_ENTRY BdsBootOptionList;
+ CHAR16 *HelpString;
+ EFI_STRING_ID HelpToken;
+ UINT16 *TempStr;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_BROWSER_ACTION_REQUEST ActionRequest;
+ UINTN TempSize;
+
+ gOption = NULL;
+ InitializeListHead (&BdsBootOptionList);
+
+ //
+ // Connect all prior to entering the platform setup menu.
+ //
+ if (!gConnectAllHappened) {
+ BdsLibConnectAllDriversToAllControllers ();
+ gConnectAllHappened = TRUE;
+ }
+ //
+ // BugBug: Here we can not remove the legacy refresh macro, so we need
+ // get the boot order every time from "BootOrder" variable.
+ // Recreate the boot option list base on the BootOrder variable
+ //
+ BdsLibEnumerateAllBootOption (&BdsBootOptionList);
+
+ mBootOptionsList = &BdsBootOptionList;
+
+ HiiHandle = gBootManagerPrivate.HiiHandle;
+
+ //
+ // Allocate space for creation of UpdateData Buffer
+ //
+ UpdateData.BufferSize = 0x1000;
+ UpdateData.Offset = 0;
+ UpdateData.Data = AllocateZeroPool (0x1000);
+ ASSERT (UpdateData.Data != NULL);
+
+ mKeyInput = 0;
+
+ for (Link = BdsBootOptionList.ForwardLink; Link != &BdsBootOptionList; Link = Link->ForwardLink) {
+ Option = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);
+
+ //
+ // At this stage we are creating a menu entry, thus the Keys are reproduceable
+ //
+ mKeyInput++;
+
+ //
+ // Don't display the boot option marked as LOAD_OPTION_HIDDEN
+ //
+ if (Option->Attribute & LOAD_OPTION_HIDDEN) {
+ continue;
+ }
+
+ IfrLibNewString (HiiHandle, &Token, Option->Description);
+
+ TempStr = DevicePathToStr (Option->DevicePath);
+ TempSize = StrSize (TempStr);
+ HelpString = AllocateZeroPool (TempSize + StrSize (L"Device Path : "));
+ StrCat (HelpString, L"Device Path : ");
+ StrCat (HelpString, TempStr);
+
+ IfrLibNewString (HiiHandle, &HelpToken, HelpString);
+
+ CreateActionOpCode (
+ mKeyInput,
+ Token,
+ HelpToken,
+ EFI_IFR_FLAG_CALLBACK,
+ 0,
+ &UpdateData
+ );
+ }
+
+ IfrLibUpdateForm (
+ HiiHandle,
+ &mBootManagerGuid,
+ BOOT_MANAGER_FORM_ID,
+ LABEL_BOOT_OPTION,
+ FALSE,
+ &UpdateData
+ );
+ FreePool (UpdateData.Data);
+
+ //
+ // Drop the TPL level from TPL_APPLICATION to TPL_APPLICATION
+ //
+ gBS->RestoreTPL (TPL_APPLICATION);
+
+ ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
+ Status = gFormBrowser2->SendForm (
+ gFormBrowser2,
+ &HiiHandle,
+ 1,
+ NULL,
+ 0,
+ NULL,
+ &ActionRequest
+ );
+ if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
+ EnableResetRequired ();
+ }
+
+ if (gOption == NULL) {
+ gBS->RaiseTPL (TPL_APPLICATION);
+ return ;
+ }
+
+ //
+ //Will leave browser, check any reset required change is applied? if yes, reset system
+ //
+ SetupResetReminder ();
+
+ //
+ // Raise the TPL level back to TPL_APPLICATION
+ //
+ gBS->RaiseTPL (TPL_APPLICATION);
+
+ //
+ // parse the selected option
+ //
+ Status = BdsLibBootViaBootOption (gOption, gOption->DevicePath, &ExitDataSize, &ExitData);
+
+ if (!EFI_ERROR (Status)) {
+ gOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED));
+ PlatformBdsBootSuccess (gOption);
+ } else {
+ gOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_FAILED));
+ PlatformBdsBootFail (gOption, Status, ExitData, ExitDataSize);
+ gST->ConOut->OutputString (
+ gST->ConOut,
+ GetStringById (STRING_TOKEN (STR_ANY_KEY_CONTINUE))
+ );
+ gBS->RestoreTPL (TPL_APPLICATION);
+ //
+ // BdsLibUiWaitForSingleEvent (gST->ConIn->WaitForKey, 0);
+ //
+ gBS->RaiseTPL (TPL_APPLICATION);
+ gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+ }
+}
diff --git a/MdeModulePkg/Universal/BdsDxe/BootMngr/BootManager.h b/MdeModulePkg/Universal/BdsDxe/BootMngr/BootManager.h new file mode 100644 index 0000000000..fab04d22a3 --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/BootMngr/BootManager.h @@ -0,0 +1,88 @@ +/*++
+
+Copyright (c) 2004 - 2008, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ BootManager.h
+
+Abstract:
+
+ The platform boot manager reference implement
+
+Revision History
+
+--*/
+
+#ifndef _EFI_BOOT_MANAGER_H
+#define _EFI_BOOT_MANAGER_H
+
+#include "Bds.h"
+#include "FrontPage.h"
+
+//
+// These are defined as the same with vfr file
+//
+#define BOOT_MANAGER_FORMSET_GUID \
+ { \
+ 0x847bc3fe, 0xb974, 0x446d, {0x94, 0x49, 0x5a, 0xd5, 0x41, 0x2e, 0x99, 0x3b} \
+ }
+
+#define BOOT_MANAGER_FORM_ID 0x1000
+
+#define LABEL_BOOT_OPTION 0x00
+
+//
+// These are the VFR compiler generated data representing our VFR data.
+//
+extern UINT8 BootManagerVfrBin[];
+
+#define BOOT_MANAGER_CALLBACK_DATA_SIGNATURE EFI_SIGNATURE_32 ('B', 'M', 'C', 'B')
+
+typedef struct {
+ UINTN Signature;
+
+ //
+ // HII relative handles
+ //
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HANDLE DriverHandle;
+
+ //
+ // Produced protocols
+ //
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+} BOOT_MANAGER_CALLBACK_DATA;
+
+EFI_STATUS
+EFIAPI
+BootManagerCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+;
+
+EFI_STATUS
+InitializeBootManager (
+ VOID
+ )
+;
+
+VOID
+CallBootManager (
+ VOID
+ )
+;
+
+#endif
diff --git a/MdeModulePkg/Universal/BdsDxe/BootMngr/BootManagerStrings.uni b/MdeModulePkg/Universal/BdsDxe/BootMngr/BootManagerStrings.uni Binary files differnew file mode 100644 index 0000000000..99b0cdf551 --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/BootMngr/BootManagerStrings.uni diff --git a/MdeModulePkg/Universal/BdsDxe/BootMngr/BootManagerVfr.Vfr b/MdeModulePkg/Universal/BdsDxe/BootMngr/BootManagerVfr.Vfr new file mode 100644 index 0000000000..e31d2292d4 --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/BootMngr/BootManagerVfr.Vfr @@ -0,0 +1,59 @@ +// *++
+//
+// Copyright (c) 2004 - 2007, Intel Corporation
+// All rights reserved. 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.
+//
+// Module Name:
+//
+// BootManager.vfr
+//
+// Abstract:
+//
+// Browser formset.
+//
+// Revision History:
+//
+// --*/
+
+#define FORMSET_GUID { 0x847bc3fe, 0xb974, 0x446d, 0x94, 0x49, 0x5a, 0xd5, 0x41, 0x2e, 0x99, 0x3b }
+
+#define BOOT_MANAGER_FORM_ID 0x1000
+
+#define LABEL_BOOT_OPTION 0x00
+#define LABEL_BOOT_OPTION_END 0x01
+
+#define BOOT_MANAGER_CLASS 0x00
+#define BOOT_MANAGER_SUBCLASS 0x00
+
+formset
+ guid = FORMSET_GUID,
+ title = STRING_TOKEN(STR_BM_BANNER),
+ help = STRING_TOKEN(STR_LAST_STRING),
+ class = BOOT_MANAGER_CLASS,
+ subclass = BOOT_MANAGER_SUBCLASS,
+
+ form formid = BOOT_MANAGER_FORM_ID,
+ title = STRING_TOKEN(STR_BM_BANNER);
+
+ subtitle text = STRING_TOKEN(STR_LAST_STRING);
+ subtitle text = STRING_TOKEN(STR_BOOT_OPTION_BANNER);
+ subtitle text = STRING_TOKEN(STR_LAST_STRING);
+
+ //
+ // This is where we will dynamically add choices for the Boot Manager
+ //
+ label LABEL_BOOT_OPTION;
+ label LABEL_BOOT_OPTION_END;
+
+ subtitle text = STRING_TOKEN(STR_LAST_STRING);
+ subtitle text = STRING_TOKEN(STR_HELP_FOOTER);
+
+ endform;
+
+endformset;
diff --git a/MdeModulePkg/Universal/BdsDxe/Capsules.c b/MdeModulePkg/Universal/BdsDxe/Capsules.c new file mode 100644 index 0000000000..9969f486da --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/Capsules.c @@ -0,0 +1,264 @@ +/*++
+
+Copyright (c) 2004 - 2008, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ Capsules.c
+
+Abstract:
+
+ BDS routines to handle capsules.
+
+--*/
+#include "Bds.h"
+
+VOID
+BdsLockFv (
+ IN EFI_CPU_IO_PROTOCOL *CpuIo,
+ IN EFI_PHYSICAL_ADDRESS Base
+ )
+{
+ EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINT8 Data;
+ UINT32 BlockLength;
+ UINTN Index;
+
+ BaseAddress = Base - 0x400000 + 2;
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) (Base));
+ BlockMap = &(FvHeader->BlockMap[0]);
+
+ while ((BlockMap->NumBlocks != 0) && (BlockMap->Length != 0)) {
+ BlockLength = BlockMap->Length;
+ for (Index = 0; Index < BlockMap->NumBlocks; Index++) {
+ CpuIo->Mem.Read (
+ CpuIo,
+ EfiCpuIoWidthUint8,
+ BaseAddress,
+ 1,
+ &Data
+ );
+ Data = (UINT8) (Data | 0x3);
+ CpuIo->Mem.Write (
+ CpuIo,
+ EfiCpuIoWidthUint8,
+ BaseAddress,
+ 1,
+ &Data
+ );
+ BaseAddress += BlockLength;
+ }
+
+ BlockMap++;
+ }
+}
+
+EFI_STATUS
+ProcessCapsules (
+ EFI_BOOT_MODE BootMode
+ )
+/*++
+
+Routine Description:
+
+ This routine is called to see if there are any capsules we need to process.
+ If the boot mode is not UPDATE, then we do nothing. Otherwise find the
+ capsule HOBS and produce firmware volumes for them via the DXE service.
+ Then call the dispatcher to dispatch drivers from them. Finally, check
+ the status of the updates.
+
+Arguments:
+
+ BootMode - the current boot mode
+
+Returns:
+
+ EFI_INVALID_PARAMETER - boot mode is not correct for an update
+
+Note:
+
+ This function should be called by BDS in case we need to do some
+ sort of processing even if there is no capsule to process. We
+ need to do this if an earlier update went awry and we need to
+ clear the capsule variable so on the next reset PEI does not see it and
+ think there is a capsule available.
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_PEI_HOB_POINTERS HobPointer;
+ EFI_CAPSULE_HEADER *CapsuleHeader;
+ UINT32 Size;
+ UINT32 CapsuleNumber;
+ UINT32 CapsuleTotalNumber;
+ EFI_CAPSULE_TABLE *CapsuleTable;
+ UINT32 Index;
+ UINT32 CacheIndex;
+ UINT32 CacheNumber;
+ VOID **CapsulePtr;
+ VOID **CapsulePtrCache;
+ EFI_GUID *CapsuleGuidCache;
+ CAPSULE_HOB_INFO *CapsuleHobInfo;
+
+ CapsuleNumber = 0;
+ CapsuleTotalNumber = 0;
+ CacheIndex = 0;
+ CacheNumber = 0;
+ CapsulePtr = NULL;
+ CapsulePtrCache = NULL;
+ CapsuleGuidCache = NULL;
+
+ //
+ // We don't do anything else if the boot mode is not flash-update
+ //
+ if (BootMode != BOOT_ON_FLASH_UPDATE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ //
+ // Find all capsule images from hob
+ //
+ HobPointer.Raw = GetHobList ();
+ while ((HobPointer.Raw = GetNextGuidHob (&gEfiCapsuleVendorGuid, HobPointer.Raw)) != NULL) {
+ CapsuleTotalNumber ++;
+
+ HobPointer.Raw = GET_NEXT_HOB (HobPointer);
+ }
+
+ if (CapsuleTotalNumber == 0) {
+ //
+ // We didn't find a hob, so had no errors.
+ //
+ PlatformBdsLockNonUpdatableFlash ();
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Init temp Capsule Data table.
+ //
+ CapsulePtr = (VOID **) AllocateZeroPool (sizeof (VOID *) * CapsuleTotalNumber);
+ ASSERT (CapsulePtr != NULL);
+ CapsulePtrCache = (VOID **) AllocateZeroPool (sizeof (VOID *) * CapsuleTotalNumber);
+ ASSERT (CapsulePtrCache != NULL);
+ CapsuleGuidCache = (EFI_GUID *) AllocateZeroPool (sizeof (EFI_GUID) * CapsuleTotalNumber);
+ ASSERT (CapsuleGuidCache != NULL);
+
+ //
+ // Find all capsule images from hob
+ //
+ HobPointer.Raw = GetHobList ();
+ while ((HobPointer.Raw = GetNextGuidHob (&gEfiCapsuleVendorGuid, HobPointer.Raw)) != NULL) {
+ CapsuleHobInfo = GET_GUID_HOB_DATA (HobPointer.Guid);
+ CapsulePtr [CapsuleNumber++] = (VOID *)(UINTN)(CapsuleHobInfo->BaseAddress);
+
+ HobPointer.Raw = GET_NEXT_HOB (HobPointer);
+ }
+
+ //
+ //Check the capsule flags,if contains CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE, install
+ //capsuleTable to configure table with EFI_CAPSULE_GUID
+ //
+
+ //
+ // Capsules who have CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE always are used for operating
+ // System to have information persist across a system reset. EFI System Table must
+ // point to an array of capsules that contains the same CapsuleGuid value. And agents
+ // searching for this type capsule will look in EFI System Table and search for the
+ // capsule's Guid and associated pointer to retrieve the data. Two steps below describes
+ // how to sorting the capsules by the unique guid and install the array to EFI System Table.
+ // Firstly, Loop for all coalesced capsules, record unique CapsuleGuids and cache them in an
+ // array for later sorting capsules by CapsuleGuid.
+ //
+ for (Index = 0; Index < CapsuleTotalNumber; Index++) {
+ CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index];
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0) {
+ //
+ // For each capsule, we compare it with known CapsuleGuid in the CacheArray.
+ // If already has the Guid, skip it. Whereas, record it in the CacheArray as
+ // an additional one.
+ //
+ CacheIndex = 0;
+ while (CacheIndex < CacheNumber) {
+ if (CompareGuid(&CapsuleGuidCache[CacheIndex],&CapsuleHeader->CapsuleGuid)) {
+ break;
+ }
+ CacheIndex++;
+ }
+ if (CacheIndex == CacheNumber) {
+ CopyMem(&CapsuleGuidCache[CacheNumber++],&CapsuleHeader->CapsuleGuid,sizeof(EFI_GUID));
+ }
+ }
+ }
+
+ //
+ // Secondly, for each unique CapsuleGuid in CacheArray, gather all coalesced capsules
+ // whose guid is the same as it, and malloc memory for an array which preceding
+ // with UINT32. The array fills with entry point of capsules that have the same
+ // CapsuleGuid, and UINT32 represents the size of the array of capsules. Then install
+ // this array into EFI System Table, so that agents searching for this type capsule
+ // will look in EFI System Table and search for the capsule's Guid and associated
+ // pointer to retrieve the data.
+ //
+ CacheIndex = 0;
+ while (CacheIndex < CacheNumber) {
+ CapsuleNumber = 0;
+ for (Index = 0; Index < CapsuleTotalNumber; Index++) {
+ CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index];
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0) {
+ if (CompareGuid (&CapsuleGuidCache[CacheIndex], &CapsuleHeader->CapsuleGuid)) {
+ //
+ // Cache Caspuleheader to the array, this array is uniqued with certain CapsuleGuid.
+ //
+ CapsulePtrCache[CapsuleNumber++] = (VOID*)CapsuleHeader;
+ }
+ }
+ }
+ if (CapsuleNumber != 0) {
+ Size = sizeof(EFI_CAPSULE_TABLE) + (CapsuleNumber - 1) * sizeof(VOID*);
+ CapsuleTable = AllocateRuntimePool (Size);
+ ASSERT (CapsuleTable != NULL);
+ CapsuleTable->CapsuleArrayNumber = CapsuleNumber;
+ CopyMem(&CapsuleTable->CapsulePtr[0], CapsulePtrCache, CapsuleNumber * sizeof(VOID*));
+ Status = gBS->InstallConfigurationTable (&CapsuleGuidCache[CacheIndex], (VOID*)CapsuleTable);
+ ASSERT_EFI_ERROR (Status);
+ }
+ CacheIndex++;
+ }
+
+ //
+ // Besides ones with CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flag, all capsules left are
+ // recognized by platform with CapsuleGuid. For general platform driver, UpdateFlash
+ // type is commonly supported, so here only deal with encapsuled FVs capsule. Additional
+ // type capsule transaction could be extended. It depends on platform policy.
+ //
+ for (Index = 0; Index < CapsuleTotalNumber; Index++) {
+ CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index];
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) {
+ //
+ // Call capsule library to process capsule image.
+ //
+ ProcessCapsuleImage (CapsuleHeader);
+ }
+ }
+
+ PlatformBdsLockNonUpdatableFlash ();
+
+ //
+ // Free the allocated temp memory space.
+ //
+ FreePool (CapsuleGuidCache);
+ FreePool (CapsulePtrCache);
+ FreePool (CapsulePtr);
+
+ return Status;
+}
diff --git a/MdeModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManager.c b/MdeModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManager.c new file mode 100644 index 0000000000..0ec274d8ce --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManager.c @@ -0,0 +1,434 @@ +/*++
+
+Copyright (c) 2004 - 2008, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ DeviceManager.c
+
+Abstract:
+
+ The platform device manager reference implement
+
+--*/
+
+#include "DeviceManager.h"
+
+DEVICE_MANAGER_CALLBACK_DATA gDeviceManagerPrivate = {
+ DEVICE_MANAGER_CALLBACK_DATA_SIGNATURE,
+ NULL,
+ NULL,
+ {
+ FakeExtractConfig,
+ FakeRouteConfig,
+ DeviceManagerCallback
+ }
+};
+
+EFI_GUID mDeviceManagerGuid = DEVICE_MANAGER_FORMSET_GUID;
+
+DEVICE_MANAGER_MENU_ITEM mDeviceManagerMenuItemTable[] = {
+ { STRING_TOKEN (STR_DISK_DEVICE), EFI_DISK_DEVICE_CLASS },
+ { STRING_TOKEN (STR_VIDEO_DEVICE), EFI_VIDEO_DEVICE_CLASS },
+ { STRING_TOKEN (STR_NETWORK_DEVICE), EFI_NETWORK_DEVICE_CLASS },
+ { STRING_TOKEN (STR_INPUT_DEVICE), EFI_INPUT_DEVICE_CLASS },
+ { STRING_TOKEN (STR_ON_BOARD_DEVICE), EFI_ON_BOARD_DEVICE_CLASS },
+ { STRING_TOKEN (STR_OTHER_DEVICE), EFI_OTHER_DEVICE_CLASS }
+};
+
+#define MENU_ITEM_NUM \
+ (sizeof (mDeviceManagerMenuItemTable) / sizeof (DEVICE_MANAGER_MENU_ITEM))
+
+EFI_STATUS
+EFIAPI
+DeviceManagerCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+/*++
+
+ Routine Description:
+ This function processes the results of changes in configuration.
+
+ Arguments:
+ This - Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ Action - Specifies the type of action taken by the browser.
+ QuestionId - A unique value which is sent to the original exporting driver
+ so that it can identify the type of data to expect.
+ Type - The type of value for the question.
+ Value - A pointer to the data being sent to the original exporting driver.
+ ActionRequest - On return, points to the action requested by the callback function.
+
+ Returns:
+ EFI_SUCCESS - The callback successfully handled the action.
+ EFI_OUT_OF_RESOURCES - Not enough storage is available to hold the variable and its data.
+ EFI_DEVICE_ERROR - The variable could not be saved.
+ EFI_UNSUPPORTED - The specified Action is not supported by the callback.
+
+--*/
+{
+ DEVICE_MANAGER_CALLBACK_DATA *PrivateData;
+
+ if ((Value == NULL) || (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivateData = DEVICE_MANAGER_CALLBACK_DATA_FROM_THIS (This);
+
+ switch (QuestionId) {
+ case DEVICE_MANAGER_KEY_VBIOS:
+ PrivateData->VideoBios = Value->u8;
+ gRT->SetVariable (
+ L"VBIOS",
+ &gEfiGenericPlatformVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ sizeof (UINT8),
+ &PrivateData->VideoBios
+ );
+
+ //
+ // Tell browser not to ask for confirmation of changes,
+ // since we have already applied.
+ //
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;
+ break;
+
+ default:
+ //
+ // The key corresponds the Handle Index which was requested to be displayed
+ //
+ gCallbackKey = QuestionId;
+
+ //
+ // Request to exit SendForm(), so as to switch to selected form
+ //
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ break;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+InitializeDeviceManager (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Initialize HII information for the FrontPage
+
+Arguments:
+ None
+
+Returns:
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_HII_PACKAGE_LIST_HEADER *PackageList;
+
+ //
+ // Create driver handle used by HII database
+ //
+ Status = HiiLibCreateHiiDriverHandle (&gDeviceManagerPrivate.DriverHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Install Config Access protocol to driver handle
+ //
+ Status = gBS->InstallProtocolInterface (
+ &gDeviceManagerPrivate.DriverHandle,
+ &gEfiHiiConfigAccessProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &gDeviceManagerPrivate.ConfigAccess
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Publish our HII data
+ //
+ PackageList = PreparePackageList (2, &mDeviceManagerGuid, DeviceManagerVfrBin, BdsStrings);
+ ASSERT (PackageList != NULL);
+
+ Status = gHiiDatabase->NewPackageList (
+ gHiiDatabase,
+ PackageList,
+ gDeviceManagerPrivate.DriverHandle,
+ &gDeviceManagerPrivate.HiiHandle
+ );
+ FreePool (PackageList);
+
+ return Status;
+}
+
+EFI_STATUS
+CallDeviceManager (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Call the browser and display the device manager
+
+Arguments:
+
+ None
+
+Returns:
+ EFI_SUCCESS - Operation is successful.
+ EFI_INVALID_PARAMETER - If the inputs to SendForm function is not valid.
+
+--*/
+{
+ EFI_STATUS Status;
+ UINTN Count;
+ UINTN Index;
+ CHAR16 *String;
+ UINTN StringLength;
+ EFI_HII_UPDATE_DATA UpdateData[MENU_ITEM_NUM];
+ EFI_STRING_ID Token;
+ EFI_STRING_ID TokenHelp;
+ IFR_OPTION *IfrOptionList;
+ UINT8 *VideoOption;
+ UINTN VideoOptionSize;
+ EFI_HII_HANDLE *HiiHandles;
+ UINTN HandleBufferLength;
+ UINTN NumberOfHiiHandles;
+ EFI_HII_HANDLE HiiHandle;
+ UINT16 FormSetClass;
+ EFI_STRING_ID FormSetTitle;
+ EFI_STRING_ID FormSetHelp;
+ EFI_BROWSER_ACTION_REQUEST ActionRequest;
+ EFI_HII_PACKAGE_LIST_HEADER *PackageList;
+
+ IfrOptionList = NULL;
+ VideoOption = NULL;
+ HiiHandles = NULL;
+ HandleBufferLength = 0;
+
+ Status = EFI_SUCCESS;
+ gCallbackKey = 0;
+
+ //
+ // Connect all prior to entering the platform setup menu.
+ //
+ if (!gConnectAllHappened) {
+ BdsLibConnectAllDriversToAllControllers ();
+ gConnectAllHappened = TRUE;
+ }
+
+ //
+ // Create Subtitle OpCodes
+ //
+ for (Index = 0; Index < MENU_ITEM_NUM; Index++) {
+ //
+ // Allocate space for creation of UpdateData Buffer
+ //
+ UpdateData[Index].BufferSize = 0x1000;
+ UpdateData[Index].Offset = 0;
+ UpdateData[Index].Data = AllocatePool (0x1000);
+ ASSERT (UpdateData[Index].Data != NULL);
+
+ CreateSubTitleOpCode (mDeviceManagerMenuItemTable[Index].StringId, 0, 0, 1, &UpdateData[Index]);
+ }
+
+ //
+ // Get all the Hii handles
+ //
+ Status = GetHiiHandles (&HandleBufferLength, &HiiHandles);
+ ASSERT_EFI_ERROR (Status);
+
+ HiiHandle = gDeviceManagerPrivate.HiiHandle;
+
+ StringLength = 0x1000;
+ String = AllocateZeroPool (StringLength);
+ ASSERT (String != NULL);
+
+ //
+ // Search for formset of each class type
+ //
+ NumberOfHiiHandles = HandleBufferLength / sizeof (EFI_HII_HANDLE);
+ for (Index = 0; Index < NumberOfHiiHandles; Index++) {
+ HiiLibExtractClassFromHiiHandle (HiiHandles[Index], &FormSetClass, &FormSetTitle, &FormSetHelp);
+
+ if (FormSetClass == EFI_NON_DEVICE_CLASS) {
+ continue;
+ }
+
+ Token = 0;
+ *String = 0;
+ StringLength = 0x1000;
+ IfrLibGetString (HiiHandles[Index], FormSetTitle, String, &StringLength);
+ IfrLibNewString (HiiHandle, &Token, String);
+
+ TokenHelp = 0;
+ *String = 0;
+ StringLength = 0x1000;
+ IfrLibGetString (HiiHandles[Index], FormSetHelp, String, &StringLength);
+ IfrLibNewString (HiiHandle, &TokenHelp, String);
+
+ for (Count = 0; Count < MENU_ITEM_NUM; Count++) {
+ if (FormSetClass & mDeviceManagerMenuItemTable[Count].Class) {
+ CreateActionOpCode (
+ (EFI_QUESTION_ID) (Index + DEVICE_KEY_OFFSET),
+ Token,
+ TokenHelp,
+ EFI_IFR_FLAG_CALLBACK,
+ 0,
+ &UpdateData[Count]
+ );
+ }
+ }
+ }
+ FreePool (String);
+
+ for (Index = 0; Index < MENU_ITEM_NUM; Index++) {
+ //
+ // Add End Opcode for Subtitle
+ //
+ CreateEndOpCode (&UpdateData[Index]);
+
+ IfrLibUpdateForm (
+ HiiHandle,
+ &mDeviceManagerGuid,
+ DEVICE_MANAGER_FORM_ID,
+ mDeviceManagerMenuItemTable[Index].Class,
+ FALSE,
+ &UpdateData[Index]
+ );
+ }
+
+ //
+ // Add oneof for video BIOS selection
+ //
+ VideoOption = BdsLibGetVariableAndSize (
+ L"VBIOS",
+ &gEfiGenericPlatformVariableGuid,
+ &VideoOptionSize
+ );
+ if (NULL == VideoOption) {
+ gDeviceManagerPrivate.VideoBios = 0;
+ } else {
+ gDeviceManagerPrivate.VideoBios = VideoOption[0];
+ FreePool (VideoOption);
+ }
+
+ ASSERT (gDeviceManagerPrivate.VideoBios <= 1);
+
+ IfrOptionList = AllocatePool (2 * sizeof (IFR_OPTION));
+ ASSERT (IfrOptionList != NULL);
+ IfrOptionList[0].Flags = 0;
+ IfrOptionList[0].StringToken = STRING_TOKEN (STR_ONE_OF_PCI);
+ IfrOptionList[0].Value.u8 = 0;
+ IfrOptionList[1].Flags = 0;
+ IfrOptionList[1].StringToken = STRING_TOKEN (STR_ONE_OF_AGP);
+ IfrOptionList[1].Value.u8 = 1;
+ IfrOptionList[gDeviceManagerPrivate.VideoBios].Flags |= EFI_IFR_OPTION_DEFAULT;
+
+ UpdateData[0].Offset = 0;
+ CreateOneOfOpCode (
+ DEVICE_MANAGER_KEY_VBIOS,
+ 0,
+ 0,
+ STRING_TOKEN (STR_ONE_OF_VBIOS),
+ STRING_TOKEN (STR_ONE_OF_VBIOS_HELP),
+ EFI_IFR_FLAG_CALLBACK,
+ EFI_IFR_NUMERIC_SIZE_1,
+ IfrOptionList,
+ 2,
+ &UpdateData[0]
+ );
+
+ IfrLibUpdateForm (
+ HiiHandle,
+ &mDeviceManagerGuid,
+ DEVICE_MANAGER_FORM_ID,
+ LABEL_VBIOS,
+ FALSE,
+ &UpdateData[0]
+ );
+
+ //
+ // Drop the TPL level from TPL_APPLICATION to TPL_APPLICATION
+ //
+ gBS->RestoreTPL (TPL_APPLICATION);
+
+ ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
+ Status = gFormBrowser2->SendForm (
+ gFormBrowser2,
+ &HiiHandle,
+ 1,
+ NULL,
+ 0,
+ NULL,
+ &ActionRequest
+ );
+ if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
+ EnableResetRequired ();
+ }
+
+ //
+ // We will have returned from processing a callback - user either hit ESC to exit, or selected
+ // a target to display
+ //
+ if (gCallbackKey != 0) {
+ ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
+ Status = gFormBrowser2->SendForm (
+ gFormBrowser2,
+ &HiiHandles[gCallbackKey - DEVICE_KEY_OFFSET],
+ 1,
+ NULL,
+ 0,
+ NULL,
+ &ActionRequest
+ );
+
+ if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
+ EnableResetRequired ();
+ }
+
+ //
+ // Force return to Device Manager
+ //
+ gCallbackKey = FRONT_PAGE_KEY_DEVICE_MANAGER;
+ }
+
+ //
+ // Cleanup dynamic created strings in HII database by reinstall the packagelist
+ //
+ gHiiDatabase->RemovePackageList (gHiiDatabase, HiiHandle);
+ PackageList = PreparePackageList (2, &mDeviceManagerGuid, DeviceManagerVfrBin, BdsStrings);
+ ASSERT (PackageList != NULL);
+ Status = gHiiDatabase->NewPackageList (
+ gHiiDatabase,
+ PackageList,
+ gDeviceManagerPrivate.DriverHandle,
+ &gDeviceManagerPrivate.HiiHandle
+ );
+ FreePool (PackageList);
+
+ for (Index = 0; Index < MENU_ITEM_NUM; Index++) {
+ FreePool (UpdateData[Index].Data);
+ }
+ FreePool (HiiHandles);
+
+ gBS->RaiseTPL (TPL_APPLICATION);
+
+ return Status;
+}
diff --git a/MdeModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManager.h b/MdeModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManager.h new file mode 100644 index 0000000000..046945612e --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManager.h @@ -0,0 +1,108 @@ +/*++
+
+Copyright (c) 2004 - 2008, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ DeviceManager.c
+
+Abstract:
+
+ The platform device manager reference implement
+
+Revision History
+
+--*/
+
+#ifndef _DEVICE_MANAGER_H
+#define _DEVICE_MANAGER_H
+
+#include "Bds.h"
+#include "FrontPage.h"
+
+//
+// These are defined as the same with vfr file
+//
+#define DEVICE_MANAGER_FORMSET_GUID \
+ { \
+ 0x3ebfa8e6, 0x511d, 0x4b5b, {0xa9, 0x5f, 0xfb, 0x38, 0x26, 0xf, 0x1c, 0x27} \
+ }
+
+#define LABEL_VBIOS 0x0040
+
+#define DEVICE_MANAGER_FORM_ID 0x1000
+
+#define DEVICE_KEY_OFFSET 0x1000
+#define DEVICE_MANAGER_KEY_VBIOS 0x2000
+
+//
+// These are the VFR compiler generated data representing our VFR data.
+//
+extern UINT8 DeviceManagerVfrBin[];
+
+#define DEVICE_MANAGER_CALLBACK_DATA_SIGNATURE EFI_SIGNATURE_32 ('D', 'M', 'C', 'B')
+
+typedef struct {
+ UINTN Signature;
+
+ //
+ // HII relative handles
+ //
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HANDLE DriverHandle;
+
+ //
+ // Produced protocols
+ //
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+
+ //
+ // Configuration data
+ //
+ UINT8 VideoBios;
+} DEVICE_MANAGER_CALLBACK_DATA;
+
+#define DEVICE_MANAGER_CALLBACK_DATA_FROM_THIS(a) \
+ CR (a, \
+ DEVICE_MANAGER_CALLBACK_DATA, \
+ ConfigAccess, \
+ DEVICE_MANAGER_CALLBACK_DATA_SIGNATURE \
+ )
+
+typedef struct {
+ EFI_STRING_ID StringId;
+ UINT16 Class;
+} DEVICE_MANAGER_MENU_ITEM;
+
+EFI_STATUS
+EFIAPI
+DeviceManagerCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+;
+
+EFI_STATUS
+InitializeDeviceManager (
+ VOID
+ )
+;
+
+EFI_STATUS
+CallDeviceManager (
+ VOID
+ )
+;
+
+#endif
diff --git a/MdeModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManagerStrings.uni b/MdeModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManagerStrings.uni Binary files differnew file mode 100644 index 0000000000..99beee4c65 --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManagerStrings.uni diff --git a/MdeModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManagerVfr.Vfr b/MdeModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManagerVfr.Vfr new file mode 100644 index 0000000000..78fff23f5d --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManagerVfr.Vfr @@ -0,0 +1,82 @@ +// *++
+//
+// Copyright (c) 2004 - 2007, Intel Corporation
+// All rights reserved. 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.
+//
+// Module Name:
+//
+// DeviceManagerVfr.vfr
+//
+// Abstract:
+//
+// Device Manager formset.
+//
+// Revision History:
+//
+// --*/
+
+#define FORMSET_GUID { 0x3ebfa8e6, 0x511d, 0x4b5b, 0xa9, 0x5f, 0xfb, 0x38, 0x26, 0xf, 0x1c, 0x27 }
+
+#define EFI_DISK_DEVICE_CLASS 0x0001
+#define EFI_VIDEO_DEVICE_CLASS 0x0002
+#define EFI_NETWORK_DEVICE_CLASS 0x0004
+#define EFI_INPUT_DEVICE_CLASS 0x0008
+#define EFI_ON_BOARD_DEVICE_CLASS 0x0010
+#define EFI_OTHER_DEVICE_CLASS 0x0020
+#define LABEL_VBIOS 0x0040
+
+#define LABEL_END 0xffff
+
+#define DEVICE_MANAGER_CLASS 0x0000
+#define FRONT_PAGE_SUBCLASS 0x0003
+
+#define DEVICE_MANAGER_FORM_ID 0x1000
+
+formset
+ guid = FORMSET_GUID,
+ title = STRING_TOKEN(STR_DEVICE_MANAGER_TITLE),
+ help = STRING_TOKEN(STR_EMPTY_STRING),
+ class = DEVICE_MANAGER_CLASS,
+ subclass = FRONT_PAGE_SUBCLASS,
+
+ form formid = DEVICE_MANAGER_FORM_ID,
+ title = STRING_TOKEN(STR_DEVICE_MANAGER_TITLE);
+
+ //
+ // This is where devices get added to the device manager hierarchy
+ //
+ label EFI_DISK_DEVICE_CLASS;
+// label LABEL_END; // Since next opcode is a label, so this one could be omitted to save code size
+
+ label EFI_VIDEO_DEVICE_CLASS;
+// label LABEL_END;
+
+ label EFI_NETWORK_DEVICE_CLASS;
+// label LABEL_END;
+
+ label EFI_INPUT_DEVICE_CLASS;
+// label LABEL_END;
+
+ label EFI_ON_BOARD_DEVICE_CLASS;
+// label LABEL_END;
+
+ label EFI_OTHER_DEVICE_CLASS;
+ label LABEL_END;
+
+ subtitle text = STRING_TOKEN(STR_EMPTY_STRING);
+
+ label LABEL_VBIOS;
+ label LABEL_END;
+
+ subtitle text = STRING_TOKEN(STR_EMPTY_STRING);
+ subtitle text = STRING_TOKEN(STR_EXIT_STRING);
+
+ endform;
+endformset;
+
diff --git a/MdeModulePkg/Universal/BdsDxe/FrontPage.c b/MdeModulePkg/Universal/BdsDxe/FrontPage.c new file mode 100644 index 0000000000..b82b40fbb7 --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/FrontPage.c @@ -0,0 +1,1035 @@ +/*++
+
+Copyright (c) 2004 - 2008, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ FrontPage.c
+
+Abstract:
+
+ FrontPage routines to handle the callbacks and browser calls
+
+--*/
+
+#include "Bds.h"
+#include "FrontPage.h"
+
+EFI_GUID mFrontPageGuid = FRONT_PAGE_FORMSET_GUID;
+
+BOOLEAN gConnectAllHappened = FALSE;
+UINTN gCallbackKey;
+
+EFI_HII_DATABASE_PROTOCOL *gHiiDatabase;
+EFI_HII_STRING_PROTOCOL *gHiiString;
+EFI_FORM_BROWSER2_PROTOCOL *gFormBrowser2;
+EFI_HII_CONFIG_ROUTING_PROTOCOL *gHiiConfigRouting;
+
+FRONT_PAGE_CALLBACK_DATA gFrontPagePrivate = {
+ FRONT_PAGE_CALLBACK_DATA_SIGNATURE,
+ NULL,
+ NULL,
+ NULL,
+ {
+ FakeExtractConfig,
+ FakeRouteConfig,
+ FrontPageCallback
+ }
+};
+
+EFI_STATUS
+EFIAPI
+FakeExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ )
+/*++
+
+ Routine Description:
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+ Arguments:
+ This - Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ Request - A null-terminated Unicode string in <ConfigRequest> format.
+ Progress - On return, points to a character in the Request string.
+ Points to the string's null terminator if request was successful.
+ Points to the most recent '&' before the first failing name/value
+ pair (or the beginning of the string if the failure is in the
+ first name/value pair) if the request was not successful.
+ Results - A null-terminated Unicode string in <ConfigAltResp> format which
+ has all values filled in for the names in the Request string.
+ String to be allocated by the called function.
+
+ Returns:
+ EFI_SUCCESS - The Results is filled with the requested values.
+ EFI_OUT_OF_RESOURCES - Not enough memory to store the results.
+ EFI_INVALID_PARAMETER - Request is NULL, illegal syntax, or unknown name.
+ EFI_NOT_FOUND - Routing data doesn't match any storage in this driver.
+
+--*/
+{
+ return EFI_NOT_FOUND;
+}
+
+EFI_STATUS
+EFIAPI
+FakeRouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ )
+/*++
+
+ Routine Description:
+ This function processes the results of changes in configuration.
+
+ Arguments:
+ This - Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ Configuration - A null-terminated Unicode string in <ConfigResp> format.
+ Progress - A pointer to a string filled in with the offset of the most
+ recent '&' before the first failing name/value pair (or the
+ beginning of the string if the failure is in the first
+ name/value pair) or the terminating NULL if all was successful.
+
+ Returns:
+ EFI_SUCCESS - The Results is processed successfully.
+ EFI_INVALID_PARAMETER - Configuration is NULL.
+ EFI_NOT_FOUND - Routing data doesn't match any storage in this driver.
+
+--*/
+{
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+FrontPageCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+/*++
+
+ Routine Description:
+ This function processes the results of changes in configuration.
+
+ Arguments:
+ This - Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ Action - Specifies the type of action taken by the browser.
+ QuestionId - A unique value which is sent to the original exporting driver
+ so that it can identify the type of data to expect.
+ Type - The type of value for the question.
+ Value - A pointer to the data being sent to the original exporting driver.
+ ActionRequest - On return, points to the action requested by the callback function.
+
+ Returns:
+ EFI_SUCCESS - The callback successfully handled the action.
+ EFI_OUT_OF_RESOURCES - Not enough storage is available to hold the variable and its data.
+ EFI_DEVICE_ERROR - The variable could not be saved.
+ EFI_UNSUPPORTED - The specified Action is not supported by the callback.
+
+--*/
+{
+ CHAR8 *LanguageString;
+ CHAR8 *LangCode;
+ CHAR8 Lang[RFC_3066_ENTRY_SIZE];
+#ifdef LANG_SUPPORT
+ CHAR8 OldLang[ISO_639_2_ENTRY_SIZE];
+#endif
+ UINTN Index;
+ EFI_STATUS Status;
+
+ if ((Value == NULL) || (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ gCallbackKey = QuestionId;
+
+ //
+ // The first 4 entries in the Front Page are to be GUARANTEED to remain constant so IHV's can
+ // describe to their customers in documentation how to find their setup information (namely
+ // under the device manager and specific buckets)
+ //
+ switch (QuestionId) {
+ case FRONT_PAGE_KEY_CONTINUE:
+ //
+ // This is the continue - clear the screen and return an error to get out of FrontPage loop
+ //
+ break;
+
+ case FRONT_PAGE_KEY_LANGUAGE:
+ //
+ // Collect the languages from what our current Language support is based on our VFR
+ //
+ LanguageString = GetSupportedLanguages (gFrontPagePrivate.HiiHandle);
+ ASSERT (LanguageString != NULL);
+
+ Index = 0;
+ LangCode = LanguageString;
+ while (*LangCode != 0) {
+ GetNextLanguage (&LangCode, Lang);
+
+ if (Index == Value->u8) {
+ break;
+ }
+
+ Index++;
+ }
+
+ Status = gRT->SetVariable (
+ L"PlatformLang",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ AsciiStrSize (Lang),
+ Lang
+ );
+
+#ifdef LANG_SUPPORT
+ //
+ // Set UEFI deprecated variable "Lang" for backwards compatibility
+ //
+ Status = ConvertRfc3066LanguageToIso639Language (Lang, OldLang);
+ if (!EFI_ERROR (Status)) {
+ Status = gRT->SetVariable (
+ L"Lang",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ ISO_639_2_ENTRY_SIZE,
+ OldLang
+ );
+ }
+#endif
+
+ FreePool (LanguageString);
+ break;
+
+ case FRONT_PAGE_KEY_BOOT_MANAGER:
+ //
+ // Boot Manager
+ //
+ break;
+
+ case FRONT_PAGE_KEY_DEVICE_MANAGER:
+ //
+ // Device Manager
+ //
+ break;
+
+ case FRONT_PAGE_KEY_BOOT_MAINTAIN:
+ //
+ // Boot Maintenance Manager
+ //
+ break;
+
+ default:
+ gCallbackKey = 0;
+ break;
+ }
+
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+InitializeFrontPage (
+ BOOLEAN ReInitializeStrings
+ )
+/*++
+
+Routine Description:
+ Initialize HII information for the FrontPage
+
+Arguments:
+ None
+
+Returns:
+ EFI_SUCCESS - The operation is successful.
+ EFI_DEVICE_ERROR - If the dynamic opcode creation failed.
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_HII_PACKAGE_LIST_HEADER *PackageList;
+ EFI_HII_UPDATE_DATA UpdateData;
+ IFR_OPTION *OptionList;
+ CHAR8 *LanguageString;
+ CHAR8 *LangCode;
+ CHAR8 Lang[RFC_3066_ENTRY_SIZE];
+ CHAR8 CurrentLang[RFC_3066_ENTRY_SIZE];
+ UINTN OptionCount;
+ EFI_STRING_ID Token;
+ CHAR16 *StringBuffer;
+ UINTN BufferSize;
+ UINTN Index;
+ EFI_HII_HANDLE HiiHandle;
+
+ if (!ReInitializeStrings) {
+ //
+ // Initialize the Device Manager
+ //
+ InitializeDeviceManager ();
+
+ //
+ // Initialize the Device Manager
+ //
+ InitializeBootManager ();
+
+ gCallbackKey = 0;
+
+ //
+ // Locate Hii relative protocols
+ //
+ Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **) &gHiiDatabase);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->LocateProtocol (&gEfiHiiStringProtocolGuid, NULL, (VOID **) &gHiiString);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &gFormBrowser2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &gHiiConfigRouting);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Create driver handle used by HII database
+ //
+ Status = HiiLibCreateHiiDriverHandle (&gFrontPagePrivate.DriverHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Install Config Access protocol to driver handle
+ //
+ Status = gBS->InstallProtocolInterface (
+ &gFrontPagePrivate.DriverHandle,
+ &gEfiHiiConfigAccessProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &gFrontPagePrivate.ConfigAccess
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Publish our HII data
+ //
+ PackageList = PreparePackageList (2, &mFrontPageGuid, FrontPageVfrBin, BdsStrings);
+ ASSERT (PackageList != NULL);
+
+ Status = gHiiDatabase->NewPackageList (
+ gHiiDatabase,
+ PackageList,
+ gFrontPagePrivate.DriverHandle,
+ &gFrontPagePrivate.HiiHandle
+ );
+ FreePool (PackageList);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Get current language setting
+ //
+ GetCurrentLanguage (CurrentLang);
+
+ //
+ // Allocate space for creation of UpdateData Buffer
+ //
+ UpdateData.BufferSize = 0x1000;
+ UpdateData.Data = AllocateZeroPool (0x1000);
+ ASSERT (UpdateData.Data != NULL);
+
+ OptionList = AllocateZeroPool (0x1000);
+ ASSERT (OptionList != NULL);
+
+ //
+ // Collect the languages from what our current Language support is based on our VFR
+ //
+ HiiHandle = gFrontPagePrivate.HiiHandle;
+ LanguageString = GetSupportedLanguages (HiiHandle);
+ ASSERT (LanguageString != NULL);
+
+ OptionCount = 0;
+ LangCode = LanguageString;
+ while (*LangCode != 0) {
+ GetNextLanguage (&LangCode, Lang);
+
+ if (gFrontPagePrivate.LanguageToken == NULL) {
+ //
+ // Get Language Name from String Package. The StringId of Printable Language
+ // Name is always 1 which is generated by StringGather Tool.
+ //
+ BufferSize = 0x100;
+ StringBuffer = AllocatePool (BufferSize);
+ Status = gHiiString->GetString (
+ gHiiString,
+ Lang,
+ HiiHandle,
+ PRINTABLE_LANGUAGE_NAME_STRING_ID,
+ StringBuffer,
+ &BufferSize,
+ NULL
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ FreePool (StringBuffer);
+ StringBuffer = AllocatePool (BufferSize);
+ Status = gHiiString->GetString (
+ gHiiString,
+ Lang,
+ HiiHandle,
+ PRINTABLE_LANGUAGE_NAME_STRING_ID,
+ StringBuffer,
+ &BufferSize,
+ NULL
+ );
+ }
+ ASSERT_EFI_ERROR (Status);
+
+ Token = 0;
+ Status = IfrLibNewString (HiiHandle, &Token, StringBuffer);
+ FreePool (StringBuffer);
+ } else {
+ Token = gFrontPagePrivate.LanguageToken[OptionCount];
+ }
+
+ if (AsciiStrCmp (Lang, CurrentLang) == 0) {
+ OptionList[OptionCount].Flags = EFI_IFR_OPTION_DEFAULT;
+ } else {
+ OptionList[OptionCount].Flags = 0;
+ }
+ OptionList[OptionCount].StringToken = Token;
+ OptionList[OptionCount].Value.u8 = (UINT8) OptionCount;
+
+ OptionCount++;
+ }
+
+ FreePool (LanguageString);
+
+ UpdateData.Offset = 0;
+ CreateOneOfOpCode (
+ FRONT_PAGE_KEY_LANGUAGE,
+ 0,
+ 0,
+ STRING_TOKEN (STR_LANGUAGE_SELECT),
+ STRING_TOKEN (STR_LANGUAGE_SELECT_HELP),
+ EFI_IFR_FLAG_CALLBACK,
+ EFI_IFR_NUMERIC_SIZE_1,
+ OptionList,
+ OptionCount,
+ &UpdateData
+ );
+
+ Status = IfrLibUpdateForm (
+ HiiHandle,
+ &mFrontPageGuid,
+ FRONT_PAGE_FORM_ID,
+ LABEL_SELECT_LANGUAGE,
+ FALSE,
+ &UpdateData
+ );
+
+ //
+ // Save the string Id for each language
+ //
+ gFrontPagePrivate.LanguageToken = AllocatePool (OptionCount * sizeof (EFI_STRING_ID));
+ ASSERT (gFrontPagePrivate.LanguageToken != NULL);
+ for (Index = 0; Index < OptionCount; Index++) {
+ gFrontPagePrivate.LanguageToken[Index] = OptionList[Index].StringToken;
+ }
+
+ FreePool (UpdateData.Data);
+ FreePool (OptionList);
+ return Status;
+}
+
+EFI_STATUS
+CallFrontPage (
+ VOID
+ )
+/*++
+
+Routine Description:
+ Call the browser and display the front page
+
+Arguments:
+ None
+
+Returns:
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_BROWSER_ACTION_REQUEST ActionRequest;
+
+ //
+ // Begin waiting for USER INPUT
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_PC_INPUT_WAIT)
+ );
+
+
+ //
+ // Drop the TPL level from TPL_APPLICATION to TPL_APPLICATION
+ //
+ gBS->RestoreTPL (TPL_APPLICATION);
+
+ ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
+ Status = gFormBrowser2->SendForm (
+ gFormBrowser2,
+ &gFrontPagePrivate.HiiHandle,
+ 1,
+ NULL,
+ 0,
+ NULL,
+ &ActionRequest
+ );
+ //
+ // Check whether user change any option setting which needs a reset to be effective
+ //
+ if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
+ EnableResetRequired ();
+ }
+
+ gBS->RaiseTPL (TPL_APPLICATION);
+ return Status;
+}
+
+EFI_STATUS
+GetProducerString (
+ IN EFI_GUID *ProducerGuid,
+ IN EFI_STRING_ID Token,
+ OUT CHAR16 **String
+ )
+/*++
+
+Routine Description:
+ Acquire the string associated with the ProducerGuid and return it.
+
+Arguments:
+ ProducerGuid - The Guid to search the HII database for
+ Token - The token value of the string to extract
+ String - The string that is extracted
+
+Returns:
+ EFI_SUCCESS - The function returns EFI_SUCCESS always.
+
+--*/
+{
+ EFI_STATUS Status;
+
+ Status = GetStringFromToken (ProducerGuid, Token, String);
+ if (EFI_ERROR (Status)) {
+ *String = GetStringById (STRING_TOKEN (STR_MISSING_STRING));
+ }
+
+ return EFI_SUCCESS;
+}
+
+VOID
+ConvertProcessorToString (
+ IN EFI_PROCESSOR_CORE_FREQUENCY_DATA *ProcessorFrequency,
+ OUT CHAR16 **String
+ )
+/*++
+
+Routine Description:
+ Convert Processor Frequency Data to a string
+
+Arguments:
+ ProcessorFrequency - The frequency data to process
+ String - The string that is created
+
+Returns:
+
+--*/
+{
+ CHAR16 *StringBuffer;
+ UINTN Index;
+ UINT32 FreqMhz;
+
+ if (ProcessorFrequency->Exponent >= 6) {
+ FreqMhz = ProcessorFrequency->Value;
+ for (Index = 0; Index < (UINTN) (ProcessorFrequency->Exponent - 6); Index++) {
+ FreqMhz *= 10;
+ }
+ } else {
+ FreqMhz = 0;
+ }
+
+ StringBuffer = AllocateZeroPool (0x20);
+ ASSERT (StringBuffer != NULL);
+ Index = UnicodeValueToString (StringBuffer, LEFT_JUSTIFY, FreqMhz / 1000, 3);
+ StrCat (StringBuffer, L".");
+ UnicodeValueToString (StringBuffer + Index + 1, PREFIX_ZERO, (FreqMhz % 1000) / 10, 2);
+ StrCat (StringBuffer, L" GHz");
+
+ *String = (CHAR16 *) StringBuffer;
+
+ return ;
+}
+
+VOID
+ConvertMemorySizeToString (
+ IN UINT32 MemorySize,
+ OUT CHAR16 **String
+ )
+/*++
+
+Routine Description:
+ Convert Memory Size to a string
+
+Arguments:
+ MemorySize - The size of the memory to process
+ String - The string that is created
+
+Returns:
+
+--*/
+{
+ CHAR16 *StringBuffer;
+
+ StringBuffer = AllocateZeroPool (0x20);
+ ASSERT (StringBuffer != NULL);
+ UnicodeValueToString (StringBuffer, LEFT_JUSTIFY, MemorySize, 6);
+ StrCat (StringBuffer, L" MB RAM");
+
+ *String = (CHAR16 *) StringBuffer;
+
+ return ;
+}
+
+VOID
+UpdateFrontPageStrings (
+ VOID
+ )
+/*++
+
+Routine Description:
+ Update the banner information for the Front Page based on DataHub information
+
+Arguments:
+ None
+
+Returns:
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_STRING_ID TokenToUpdate;
+ CHAR16 *NewString;
+ UINT64 MonotonicCount;
+ EFI_DATA_HUB_PROTOCOL *DataHub;
+ EFI_DATA_RECORD_HEADER *Record;
+ EFI_SUBCLASS_TYPE1_HEADER *DataHeader;
+ EFI_MISC_BIOS_VENDOR_DATA *BiosVendor;
+ EFI_MISC_SYSTEM_MANUFACTURER_DATA *SystemManufacturer;
+ EFI_PROCESSOR_VERSION_DATA *ProcessorVersion;
+ EFI_PROCESSOR_CORE_FREQUENCY_DATA *ProcessorFrequency;
+ EFI_MEMORY_ARRAY_START_ADDRESS_DATA *MemoryArray;
+ BOOLEAN Find[5];
+
+ ZeroMem (Find, sizeof (Find));
+
+ //
+ // Update Front Page strings
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiDataHubProtocolGuid,
+ NULL,
+ (VOID **) &DataHub
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ MonotonicCount = 0;
+ Record = NULL;
+ do {
+ Status = DataHub->GetNextRecord (DataHub, &MonotonicCount, NULL, &Record);
+ if (Record->DataRecordClass == EFI_DATA_RECORD_CLASS_DATA) {
+ DataHeader = (EFI_SUBCLASS_TYPE1_HEADER *) (Record + 1);
+ if (CompareGuid (&Record->DataRecordGuid, &gEfiMiscSubClassGuid) &&
+ (DataHeader->RecordType == EFI_MISC_BIOS_VENDOR_RECORD_NUMBER)
+ ) {
+ BiosVendor = (EFI_MISC_BIOS_VENDOR_DATA *) (DataHeader + 1);
+ GetProducerString (&Record->ProducerName, BiosVendor->BiosVersion, &NewString);
+ TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_BIOS_VERSION);
+ IfrLibSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString);
+ FreePool (NewString);
+ Find[0] = TRUE;
+ }
+
+ if (CompareGuid (&Record->DataRecordGuid, &gEfiMiscSubClassGuid) &&
+ (DataHeader->RecordType == EFI_MISC_SYSTEM_MANUFACTURER_RECORD_NUMBER)
+ ) {
+ SystemManufacturer = (EFI_MISC_SYSTEM_MANUFACTURER_DATA *) (DataHeader + 1);
+ GetProducerString (&Record->ProducerName, SystemManufacturer->SystemProductName, &NewString);
+ TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_COMPUTER_MODEL);
+ IfrLibSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString);
+ FreePool (NewString);
+ Find[1] = TRUE;
+ }
+
+ if (CompareGuid (&Record->DataRecordGuid, &gEfiProcessorSubClassGuid) &&
+ (DataHeader->RecordType == ProcessorVersionRecordType)
+ ) {
+ ProcessorVersion = (EFI_PROCESSOR_VERSION_DATA *) (DataHeader + 1);
+ GetProducerString (&Record->ProducerName, *ProcessorVersion, &NewString);
+ TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_CPU_MODEL);
+ IfrLibSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString);
+ FreePool (NewString);
+ Find[2] = TRUE;
+ }
+
+ if (CompareGuid (&Record->DataRecordGuid, &gEfiProcessorSubClassGuid) &&
+ (DataHeader->RecordType == ProcessorCoreFrequencyRecordType)
+ ) {
+ ProcessorFrequency = (EFI_PROCESSOR_CORE_FREQUENCY_DATA *) (DataHeader + 1);
+ ConvertProcessorToString (ProcessorFrequency, &NewString);
+ TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_CPU_SPEED);
+ IfrLibSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString);
+ FreePool (NewString);
+ Find[3] = TRUE;
+ }
+
+ if (CompareGuid (&Record->DataRecordGuid, &gEfiMemorySubClassGuid) &&
+ (DataHeader->RecordType == EFI_MEMORY_ARRAY_START_ADDRESS_RECORD_NUMBER)
+ ) {
+ MemoryArray = (EFI_MEMORY_ARRAY_START_ADDRESS_DATA *) (DataHeader + 1);
+ ConvertMemorySizeToString (
+ (UINT32)(RShiftU64((MemoryArray->MemoryArrayEndAddress - MemoryArray->MemoryArrayStartAddress + 1), 20)),
+ &NewString
+ );
+ TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_MEMORY_SIZE);
+ IfrLibSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString);
+ FreePool (NewString);
+ Find[4] = TRUE;
+ }
+ }
+ } while (!EFI_ERROR (Status) && (MonotonicCount != 0) && !(Find[0] && Find[1] && Find[2] && Find[3] && Find[4]));
+
+ return ;
+}
+
+EFI_STATUS
+WaitForSingleEvent (
+ IN EFI_EVENT Event,
+ IN UINT64 Timeout OPTIONAL
+ )
+/*++
+
+Routine Description:
+ Function waits for a given event to fire, or for an optional timeout to expire.
+
+Arguments:
+ Event - The event to wait for
+ Timeout - An optional timeout value in 100 ns units.
+
+Returns:
+ EFI_SUCCESS - Event fired before Timeout expired.
+ EFI_TIME_OUT - Timout expired before Event fired..
+
+--*/
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_EVENT TimerEvent;
+ EFI_EVENT WaitList[2];
+
+ if (Timeout) {
+ //
+ // Create a timer event
+ //
+ Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Set the timer event
+ //
+ gBS->SetTimer (
+ TimerEvent,
+ TimerRelative,
+ Timeout
+ );
+
+ //
+ // Wait for the original event or the timer
+ //
+ WaitList[0] = Event;
+ WaitList[1] = TimerEvent;
+ Status = gBS->WaitForEvent (2, WaitList, &Index);
+ gBS->CloseEvent (TimerEvent);
+
+ //
+ // If the timer expired, change the return to timed out
+ //
+ if (!EFI_ERROR (Status) && Index == 1) {
+ Status = EFI_TIMEOUT;
+ }
+ }
+ } else {
+ //
+ // No timeout... just wait on the event
+ //
+ Status = gBS->WaitForEvent (1, &Event, &Index);
+ ASSERT (!EFI_ERROR (Status));
+ ASSERT (Index == 0);
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+ShowProgress (
+ IN UINT16 TimeoutDefault
+ )
+/*++
+
+Routine Description:
+ Function show progress bar to wait for user input.
+
+Arguments:
+ TimeoutDefault - The fault time out value before the system
+ continue to boot.
+
+Returns:
+ EFI_SUCCESS - User pressed some key except "Enter"
+ EFI_TIME_OUT - Timout expired or user press "Enter"
+
+--*/
+{
+ EFI_STATUS Status;
+ CHAR16 *TmpStr;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color;
+ EFI_INPUT_KEY Key;
+ UINT16 TimeoutRemain;
+
+ if (TimeoutDefault == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ SetMem (&Foreground, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff);
+ SetMem (&Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0);
+ SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff);
+
+ //
+ // Clear the progress status bar first
+ //
+ TmpStr = GetStringById (STRING_TOKEN (STR_START_BOOT_OPTION));
+ if (TmpStr != NULL) {
+ PlatformBdsShowProgress (Foreground, Background, TmpStr, Color, 0, 0);
+ }
+
+ TimeoutRemain = TimeoutDefault;
+ while (TimeoutRemain != 0) {
+ Status = WaitForSingleEvent (gST->ConIn->WaitForKey, ONE_SECOND);
+ if (Status != EFI_TIMEOUT) {
+ break;
+ }
+ TimeoutRemain--;
+
+ //
+ // Show progress
+ //
+ if (TmpStr != NULL) {
+ PlatformBdsShowProgress (
+ Foreground,
+ Background,
+ TmpStr,
+ Color,
+ ((TimeoutDefault - TimeoutRemain) * 100 / TimeoutDefault),
+ 0
+ );
+ }
+ }
+ gBS->FreePool (TmpStr);
+
+ //
+ // Timeout expired
+ //
+ if (TimeoutRemain == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ //
+ // User pressed some key
+ //
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
+ //
+ // User pressed enter, equivalent to select "continue"
+ //
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+VOID
+PlatformBdsEnterFrontPage (
+ IN UINT16 TimeoutDefault,
+ IN BOOLEAN ConnectAllHappened
+ )
+/*++
+
+Routine Description:
+ This function is the main entry of the platform setup entry.
+ The function will present the main menu of the system setup,
+ this is the platform reference part and can be customize.
+
+Arguments:
+ TimeoutDefault - The fault time out value before the system
+ continue to boot.
+ ConnectAllHappened - The indicater to check if the connect all have
+ already happended.
+
+Returns:
+ None
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl;
+
+ //
+ // Indicate if we need connect all in the platform setup
+ //
+ if (ConnectAllHappened) {
+ gConnectAllHappened = TRUE;
+ }
+
+ if (TimeoutDefault != 0xffff) {
+ gBS->RestoreTPL (TPL_APPLICATION);
+ Status = ShowProgress (TimeoutDefault);
+ gBS->RaiseTPL (TPL_APPLICATION);
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Timeout or user press enter to continue
+ //
+ goto Exit;
+ }
+ }
+
+ do {
+
+ InitializeFrontPage (TRUE);
+
+ //
+ // Update Front Page strings
+ //
+ UpdateFrontPageStrings ();
+
+ gCallbackKey = 0;
+ PERF_START (0, "BdsTimeOut", "BDS", 0);
+ Status = CallFrontPage ();
+ PERF_END (0, "BdsTimeOut", "BDS", 0);
+
+ //
+ // If gCallbackKey is greater than 1 and less or equal to 5,
+ // it will lauch configuration utilities.
+ // 2 = set language
+ // 3 = boot manager
+ // 4 = device manager
+ // 5 = boot maintainenance manager
+ //
+ if (gCallbackKey != 0) {
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_PC_USER_SETUP)
+ );
+ }
+ //
+ // Based on the key that was set, we can determine what to do
+ //
+ switch (gCallbackKey) {
+ //
+ // The first 4 entries in the Front Page are to be GUARANTEED to remain constant so IHV's can
+ // describe to their customers in documentation how to find their setup information (namely
+ // under the device manager and specific buckets)
+ //
+ // These entries consist of the Continue, Select language, Boot Manager, and Device Manager
+ //
+ case FRONT_PAGE_KEY_CONTINUE:
+ //
+ // User hit continue
+ //
+ break;
+
+ case FRONT_PAGE_KEY_LANGUAGE:
+ //
+ // User made a language setting change - display front page again
+ //
+ break;
+
+ case FRONT_PAGE_KEY_BOOT_MANAGER:
+ //
+ // User chose to run the Boot Manager
+ //
+ CallBootManager ();
+ break;
+
+ case FRONT_PAGE_KEY_DEVICE_MANAGER:
+ //
+ // Display the Device Manager
+ //
+ do {
+ CallDeviceManager();
+ } while (gCallbackKey == FRONT_PAGE_KEY_DEVICE_MANAGER);
+ break;
+
+ case FRONT_PAGE_KEY_BOOT_MAINTAIN:
+ //
+ // Display the Boot Maintenance Manager
+ //
+ BdsStartBootMaint ();
+ break;
+ }
+
+ } while ((Status == EFI_SUCCESS) && (gCallbackKey != FRONT_PAGE_KEY_CONTINUE));
+
+ //
+ //Will leave browser, check any reset required change is applied? if yes, reset system
+ //
+ gBS->RestoreTPL (TPL_APPLICATION);
+ SetupResetReminder ();
+ gBS->RaiseTPL (TPL_APPLICATION);
+
+Exit:
+ //
+ // Automatically load current entry
+ // Note: The following lines of code only execute when Auto boot
+ // takes affect
+ //
+ Status = gBS->LocateProtocol (&gEfiConsoleControlProtocolGuid, NULL, (VOID **) &ConsoleControl);
+ ConsoleControl->SetMode (ConsoleControl, EfiConsoleControlScreenText);
+
+}
diff --git a/MdeModulePkg/Universal/BdsDxe/FrontPage.h b/MdeModulePkg/Universal/BdsDxe/FrontPage.h new file mode 100644 index 0000000000..fc01d16d54 --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/FrontPage.h @@ -0,0 +1,149 @@ +/*++
+
+Copyright (c) 2004 - 2008, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ FrontPage.h
+
+Abstract:
+
+ FrontPage routines to handle the callbacks and browser calls
+
+Revision History
+
+--*/
+
+#ifndef _FRONT_PAGE_H
+#define _FRONT_PAGE_H
+
+#include "DeviceMngr/DeviceManager.h"
+#include "BootMaint/BootMaint.h"
+#include "BootMngr/BootManager.h"
+#include "String.h"
+
+#define ONE_SECOND 10000000
+
+//
+// This is the VFR compiler generated header file which defines the
+// string identifiers.
+//
+#define PRINTABLE_LANGUAGE_NAME_STRING_ID 0x0001
+
+//
+// These are defined as the same with vfr file
+//
+#define FRONT_PAGE_FORM_ID 0x1000
+
+#define FRONT_PAGE_KEY_CONTINUE 0x1000
+#define FRONT_PAGE_KEY_LANGUAGE 0x1234
+#define FRONT_PAGE_KEY_BOOT_MANAGER 0x1064
+#define FRONT_PAGE_KEY_DEVICE_MANAGER 0x8567
+#define FRONT_PAGE_KEY_BOOT_MAINTAIN 0x9876
+
+#define LABEL_SELECT_LANGUAGE 0x1000
+
+#define FRONT_PAGE_FORMSET_GUID \
+ { \
+ 0x9e0c30bc, 0x3f06, 0x4ba6, 0x82, 0x88, 0x9, 0x17, 0x9b, 0x85, 0x5d, 0xbe \
+ }
+
+#define FRONT_PAGE_CALLBACK_DATA_SIGNATURE EFI_SIGNATURE_32 ('F', 'P', 'C', 'B')
+
+typedef struct {
+ UINTN Signature;
+
+ //
+ // HII relative handles
+ //
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HANDLE DriverHandle;
+ EFI_STRING_ID *LanguageToken;
+
+ //
+ // Produced protocols
+ //
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+} FRONT_PAGE_CALLBACK_DATA;
+
+#define EFI_FP_CALLBACK_DATA_FROM_THIS(a) \
+ CR (a, \
+ FRONT_PAGE_CALLBACK_DATA, \
+ ConfigAccess, \
+ FRONT_PAGE_CALLBACK_DATA_SIGNATURE \
+ )
+
+//
+// These are the VFR compiler generated data representing our VFR data.
+//
+extern UINT8 FrontPageVfrBin[];
+
+extern EFI_HII_DATABASE_PROTOCOL *gHiiDatabase;
+extern EFI_HII_STRING_PROTOCOL *gHiiString;
+extern EFI_FORM_BROWSER2_PROTOCOL *gFormBrowser2;
+extern EFI_HII_CONFIG_ROUTING_PROTOCOL *gHiiConfigRouting;
+
+extern UINTN gCallbackKey;
+extern BOOLEAN gConnectAllHappened;
+
+EFI_STATUS
+EFIAPI
+FakeExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ );
+
+EFI_STATUS
+EFIAPI
+FakeRouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ );
+
+EFI_STATUS
+EFIAPI
+FrontPageCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ );
+
+EFI_STATUS
+InitializeFrontPage (
+ IN BOOLEAN ReInitializeStrings
+ );
+
+EFI_STATUS
+GetProducerString (
+ IN EFI_GUID *ProducerGuid,
+ IN EFI_STRING_ID Token,
+ OUT CHAR16 **String
+ );
+
+BOOLEAN
+TimeCompare (
+ IN EFI_TIME *FirstTime,
+ IN EFI_TIME *SecondTime
+ );
+
+VOID
+PlatformBdsEnterFrontPage (
+ IN UINT16 TimeoutDefault,
+ IN BOOLEAN ConnectAllHappened
+ );
+
+#endif // _FRONT_PAGE_H_
+
diff --git a/MdeModulePkg/Universal/BdsDxe/FrontPageStrings.uni b/MdeModulePkg/Universal/BdsDxe/FrontPageStrings.uni Binary files differnew file mode 100644 index 0000000000..b22fa5aa2a --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/FrontPageStrings.uni diff --git a/MdeModulePkg/Universal/BdsDxe/FrontPageVfr.Vfr b/MdeModulePkg/Universal/BdsDxe/FrontPageVfr.Vfr new file mode 100644 index 0000000000..e7332aadbf --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/FrontPageVfr.Vfr @@ -0,0 +1,145 @@ +// *++
+//
+// Copyright (c) 2007, Intel Corporation
+// All rights reserved. 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.
+//
+// Module Name:
+//
+// FrontPageVfr.vfr
+//
+// Abstract:
+//
+// Browser formset.
+//
+// Revision History:
+//
+// --*/
+
+#define FORMSET_GUID { 0x9e0c30bc, 0x3f06, 0x4ba6, 0x82, 0x88, 0x9, 0x17, 0x9b, 0x85, 0x5d, 0xbe }
+
+#define FRONT_PAGE_CLASS 0x0000
+#define FRONT_PAGE_SUBCLASS 0x0002
+
+#define FRONT_PAGE_FORM_ID 0x1000
+
+#define FRONT_PAGE_ITEM_ONE 0x0001
+#define FRONT_PAGE_ITEM_TWO 0x0002
+#define FRONT_PAGE_ITEM_THREE 0x0003
+#define FRONT_PAGE_ITEM_FOUR 0x0004
+#define FRONT_PAGE_ITEM_FIVE 0x0005
+
+#define FRONT_PAGE_KEY_CONTINUE 0x1000
+#define FRONT_PAGE_KEY_LANGUAGE 0x1234
+#define FRONT_PAGE_KEY_BOOT_MANAGER 0x1064
+#define FRONT_PAGE_KEY_DEVICE_MANAGER 0x8567
+#define FRONT_PAGE_KEY_BOOT_MAINTAIN 0x9876
+
+#define LABEL_SELECT_LANGUAGE 0x1000
+#define LABEL_TIMEOUT 0x2000
+#define LABEL_END 0xffff
+
+formset
+ guid = FORMSET_GUID,
+ title = STRING_TOKEN(STR_FRONT_PAGE_TITLE),
+ help = STRING_TOKEN(STR_NULL_STRING),
+ class = FRONT_PAGE_CLASS,
+ subclass = FRONT_PAGE_SUBCLASS,
+
+ form formid = FRONT_PAGE_FORM_ID,
+ title = STRING_TOKEN(STR_FRONT_PAGE_TITLE);
+
+ banner
+ title = STRING_TOKEN(STR_FRONT_PAGE_COMPUTER_MODEL),
+ line 0,
+ align left;
+
+ banner
+ title = STRING_TOKEN(STR_FRONT_PAGE_CPU_MODEL),
+ line 1,
+ align left;
+
+ banner
+ title = STRING_TOKEN(STR_FRONT_PAGE_CPU_SPEED),
+ line 1,
+ align right;
+
+ banner
+ title = STRING_TOKEN(STR_FRONT_PAGE_BIOS_VERSION),
+ line 2,
+ align left;
+
+ banner
+ title = STRING_TOKEN(STR_FRONT_PAGE_MEMORY_SIZE),
+ line 2,
+ align right;
+
+// banner
+// title = STRING_TOKEN(STR_FRONT_PAGE_BANNER_0_LEFT),
+// line 0,
+// align left;
+
+// banner
+// title = STRING_TOKEN(STR_FRONT_PAGE_BANNER_0_RIGHT),
+// line 0,
+// align right;
+
+// banner
+// title = STRING_TOKEN(STR_FRONT_PAGE_BANNER_1_LEFT),
+// line 1,
+// align left;
+
+// banner
+// title = STRING_TOKEN(STR_FRONT_PAGE_BANNER_1_RIGHT),
+// line 1,
+// align right;
+
+// banner
+// title = STRING_TOKEN(STR_FRONT_PAGE_BANNER_2_LEFT),
+// line 2,
+// align left;
+
+// banner
+// title = STRING_TOKEN(STR_FRONT_PAGE_BANNER_3_LEFT),
+// line 3,
+// align left;
+
+ goto FRONT_PAGE_ITEM_ONE,
+ prompt = STRING_TOKEN(STR_CONTINUE_PROMPT),
+ help = STRING_TOKEN(STR_CONTINUE_HELP),
+ flags = INTERACTIVE,
+ key = FRONT_PAGE_KEY_CONTINUE;
+
+ label LABEL_SELECT_LANGUAGE;
+ //
+ // This is where we will dynamically add a OneOf type op-code to select
+ // Languages from the currently available choices
+ //
+ label LABEL_END;
+
+ goto FRONT_PAGE_ITEM_THREE,
+ prompt = STRING_TOKEN(STR_BOOT_MANAGER),
+ help = STRING_TOKEN(STR_BOOT_MANAGER_HELP),
+ flags = INTERACTIVE,
+ key = FRONT_PAGE_KEY_BOOT_MANAGER;
+
+ goto FRONT_PAGE_ITEM_FOUR,
+ prompt = STRING_TOKEN(STR_DEVICE_MANAGER),
+ help = STRING_TOKEN(STR_DEVICE_MANAGER_HELP),
+ flags = INTERACTIVE,
+ key = FRONT_PAGE_KEY_DEVICE_MANAGER;
+
+ goto FRONT_PAGE_ITEM_FIVE,
+ prompt = STRING_TOKEN(STR_BOOT_MAINT_MANAGER),
+ help = STRING_TOKEN(STR_BOOT_MAINT_MANAGER_HELP),
+ flags = INTERACTIVE,
+ key = FRONT_PAGE_KEY_BOOT_MAINTAIN;
+
+ endform;
+
+endformset;
diff --git a/MdeModulePkg/Universal/BdsDxe/Hotkey.c b/MdeModulePkg/Universal/BdsDxe/Hotkey.c new file mode 100644 index 0000000000..ea4bbf5578 --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/Hotkey.c @@ -0,0 +1,769 @@ +/*++
+
+Copyright (c) 2007 - 2008, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ Hotkey.h
+
+Abstract:
+
+ Provides a way for 3rd party applications to register themselves for launch by the
+ Boot Manager based on hot key
+
+Revision History
+
+--*/
+
+#include "Hotkey.h"
+
+
+LIST_ENTRY mHotkeyList = INITIALIZE_LIST_HEAD_VARIABLE (mHotkeyList);
+BOOLEAN mHotkeyCallbackPending = FALSE;
+EFI_EVENT mHotkeyEvent;
+VOID *mHotkeyRegistration;
+
+
+BOOLEAN
+IsKeyOptionValid (
+ IN EFI_KEY_OPTION *KeyOption
+)
+/*++
+
+Routine Description:
+
+ Check if the Key Option is valid or not.
+
+Arguments:
+
+ KeyOption - The Hot Key Option to be checked.
+
+Returns:
+
+ TRUE - The Hot Key Option is valid.
+ FALSE - The Hot Key Option is invalid.
+
+--*/
+{
+ UINT16 BootOptionName[10];
+ UINT8 *BootOptionVar;
+ UINTN BootOptionSize;
+ UINT32 Crc;
+
+ //
+ // Check whether corresponding Boot Option exist
+ //
+ UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", KeyOption->BootOption);
+ BootOptionVar = BdsLibGetVariableAndSize (
+ BootOptionName,
+ &gEfiGlobalVariableGuid,
+ &BootOptionSize
+ );
+
+ if (BootOptionVar == NULL || BootOptionSize == 0) {
+ return FALSE;
+ }
+
+ //
+ // Check CRC for Boot Option
+ //
+ gBS->CalculateCrc32 (BootOptionVar, BootOptionSize, &Crc);
+ FreePool (BootOptionVar);
+
+ return (BOOLEAN) ((KeyOption->BootOptionCrc == Crc) ? TRUE : FALSE);
+}
+
+EFI_STATUS
+RegisterHotkey (
+ IN EFI_KEY_OPTION *KeyOption,
+ OUT UINT16 *KeyOptionNumber
+)
+/*++
+
+Routine Description:
+
+ Create Key#### for the given hotkey.
+
+Arguments:
+
+ KeyOption - The Hot Key Option to be added.
+ KeyOptionNumber - The key option number for Key#### (optional).
+
+Returns:
+
+ EFI_SUCCESS - Register hotkey successfully.
+ EFI_INVALID_PARAMETER - The hotkey option is invalid.
+
+--*/
+{
+ UINT16 KeyOptionName[10];
+ UINT16 *KeyOrder;
+ UINTN KeyOrderSize;
+ UINT16 *NewKeyOrder;
+ UINTN Index;
+ UINT16 MaxOptionNumber;
+ UINT16 RegisterOptionNumber;
+ EFI_KEY_OPTION *TempOption;
+ UINTN TempOptionSize;
+ EFI_STATUS Status;
+ UINTN KeyOptionSize;
+ BOOLEAN UpdateBootOption;
+
+ //
+ // Validate the given key option
+ //
+ if (!IsKeyOptionValid (KeyOption)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ KeyOptionSize = sizeof (EFI_KEY_OPTION) + GET_KEY_CODE_COUNT (KeyOption->KeyOptions.PackedValue) * sizeof (EFI_INPUT_KEY);
+ UpdateBootOption = FALSE;
+
+ //
+ // check whether HotKey conflict with keys used by Setup Browser
+ //
+
+ KeyOrder = BdsLibGetVariableAndSize (
+ VarKeyOrder,
+ &gEfiGlobalVariableGuid,
+ &KeyOrderSize
+ );
+ if (KeyOrder == NULL) {
+ KeyOrderSize = 0;
+ }
+
+ //
+ // Find free key option number
+ //
+ MaxOptionNumber = 0;
+ TempOption = NULL;
+ for (Index = 0; Index < KeyOrderSize / sizeof (UINT16); Index++) {
+ if (MaxOptionNumber < KeyOrder[Index]) {
+ MaxOptionNumber = KeyOrder[Index];
+ }
+
+ UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOrder[Index]);
+ TempOption = BdsLibGetVariableAndSize (
+ KeyOptionName,
+ &gEfiGlobalVariableGuid,
+ &TempOptionSize
+ );
+
+ if (CompareMem (TempOption, KeyOption, TempOptionSize) == 0) {
+ //
+ // Got the option, so just return
+ //
+ FreePool (TempOption);
+ FreePool (KeyOrder);
+ return EFI_SUCCESS;
+ }
+
+ if (KeyOption->KeyOptions.PackedValue == TempOption->KeyOptions.PackedValue) {
+ if (GET_KEY_CODE_COUNT (KeyOption->KeyOptions.PackedValue) == 0 ||
+ CompareMem (
+ ((UINT8 *) TempOption) + sizeof (EFI_KEY_OPTION),
+ ((UINT8 *) KeyOption) + sizeof (EFI_KEY_OPTION),
+ KeyOptionSize - sizeof (EFI_KEY_OPTION)
+ ) == 0) {
+ //
+ // Hotkey is the same but BootOption changed, need update
+ //
+ UpdateBootOption = TRUE;
+ break;
+ }
+ }
+
+ FreePool (TempOption);
+ }
+
+ if (UpdateBootOption) {
+ RegisterOptionNumber = KeyOrder[Index];
+ FreePool (TempOption);
+ } else {
+ RegisterOptionNumber = (UINT16) (MaxOptionNumber + 1);
+ }
+
+ if (KeyOptionNumber != NULL) {
+ *KeyOptionNumber = RegisterOptionNumber;
+ }
+
+ //
+ // Create variable Key####
+ //
+ UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", RegisterOptionNumber);
+ Status = gRT->SetVariable (
+ KeyOptionName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ KeyOptionSize,
+ KeyOption
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (KeyOrder);
+ return Status;
+ }
+
+ //
+ // Update the key order variable - "KeyOrder"
+ //
+ if (!UpdateBootOption) {
+ Index = KeyOrderSize / sizeof (UINT16);
+ KeyOrderSize += sizeof (UINT16);
+ }
+
+ NewKeyOrder = AllocatePool (KeyOrderSize);
+ if (NewKeyOrder == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (KeyOrder != NULL) {
+ CopyMem (NewKeyOrder, KeyOrder, KeyOrderSize);
+ }
+
+ NewKeyOrder[Index] = RegisterOptionNumber;
+
+ Status = gRT->SetVariable (
+ VarKeyOrder,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ KeyOrderSize,
+ NewKeyOrder
+ );
+
+ FreePool (KeyOrder);
+ FreePool (NewKeyOrder);
+
+ return Status;
+}
+
+EFI_STATUS
+UnregisterHotkey (
+ IN UINT16 KeyOptionNumber
+)
+/*++
+
+Routine Description:
+
+ Delete Key#### for the given Key Option number.
+
+Arguments:
+
+ KeyOptionNumber - Key option number for Key####
+
+Returns:
+
+ EFI_SUCCESS - Unregister hotkey successfully.
+ EFI_NOT_FOUND - No Key#### is found for the given Key Option number.
+
+--*/
+{
+ UINT16 KeyOption[10];
+ UINTN Index;
+ EFI_STATUS Status;
+ UINTN Index2Del;
+ UINT16 *KeyOrder;
+ UINTN KeyOrderSize;
+
+ //
+ // Delete variable Key####
+ //
+ UnicodeSPrint (KeyOption, sizeof (KeyOption), L"Key%04x", KeyOptionNumber);
+ gRT->SetVariable (
+ KeyOption,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ 0,
+ NULL
+ );
+
+ //
+ // Adjust key order array
+ //
+ KeyOrder = BdsLibGetVariableAndSize (
+ VarKeyOrder,
+ &gEfiGlobalVariableGuid,
+ &KeyOrderSize
+ );
+ if (KeyOrder == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ Index2Del = 0;
+ for (Index = 0; Index < KeyOrderSize / sizeof (UINT16); Index++) {
+ if (KeyOrder[Index] == KeyOptionNumber) {
+ Index2Del = Index;
+ break;
+ }
+ }
+
+ if (Index != KeyOrderSize / sizeof (UINT16)) {
+ //
+ // KeyOptionNumber found in "KeyOrder", delete it
+ //
+ for (Index = Index2Del; Index < KeyOrderSize / sizeof (UINT16) - 1; Index++) {
+ KeyOrder[Index] = KeyOrder[Index + 1];
+ }
+
+ KeyOrderSize -= sizeof (UINT16);
+ }
+
+ Status = gRT->SetVariable (
+ VarKeyOrder,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ KeyOrderSize,
+ KeyOrder
+ );
+
+ FreePool (KeyOrder);
+
+ return Status;
+}
+
+EFI_STATUS
+HotkeyCallback (
+ IN EFI_KEY_DATA *KeyData
+)
+/*++
+
+Routine Description:
+
+ This is the common notification function for HotKeys, it will be registered
+ with SimpleTextInEx protocol interface - RegisterKeyNotify() of ConIn handle.
+
+Arguments:
+
+ KeyData - A pointer to a buffer that is filled in with the keystroke
+ information for the key that was pressed.
+
+Returns:
+
+ EFI_SUCCESS - KeyData is successfully processed.
+
+--*/
+{
+ BOOLEAN HotkeyCatched;
+ LIST_ENTRY BootLists;
+ LIST_ENTRY *Link;
+ BDS_HOTKEY_OPTION *Hotkey;
+ UINT16 Buffer[10];
+ BDS_COMMON_OPTION *BootOption;
+ UINTN ExitDataSize;
+ CHAR16 *ExitData;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ EFI_KEY_DATA *HotkeyData;
+
+ if (mHotkeyCallbackPending) {
+ //
+ // When responsing to a Hotkey, ignore sequential hotkey stroke until
+ // the current Boot#### load option returned
+ //
+ return EFI_SUCCESS;
+ }
+
+ Status = EFI_SUCCESS;
+ Link = GetFirstNode (&mHotkeyList);
+
+ while (!IsNull (&mHotkeyList, Link)) {
+ HotkeyCatched = FALSE;
+ Hotkey = BDS_HOTKEY_OPTION_FROM_LINK (Link);
+
+ //
+ // Is this Key Stroke we are waiting for?
+ //
+ HotkeyData = &Hotkey->KeyData[Hotkey->WaitingKey];
+ if ((KeyData->Key.ScanCode == HotkeyData->Key.ScanCode) &&
+ (KeyData->Key.UnicodeChar == HotkeyData->Key.UnicodeChar) &&
+ ((HotkeyData->KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) ? (KeyData->KeyState.KeyShiftState == HotkeyData->KeyState.KeyShiftState) : 1)) {
+ //
+ // Receive an expecting key stroke
+ //
+ if (Hotkey->CodeCount > 1) {
+ //
+ // For hotkey of key combination, transit to next waiting state
+ //
+ Hotkey->WaitingKey++;
+
+ if (Hotkey->WaitingKey == Hotkey->CodeCount) {
+ //
+ // Received the whole key stroke sequence
+ //
+ HotkeyCatched = TRUE;
+ }
+ } else {
+ //
+ // For hotkey of single key stroke
+ //
+ HotkeyCatched = TRUE;
+ }
+ } else {
+ //
+ // Receive an unexpected key stroke, reset to initial waiting state
+ //
+ Hotkey->WaitingKey = 0;
+ }
+
+ if (HotkeyCatched) {
+ //
+ // Reset to initial waiting state
+ //
+ Hotkey->WaitingKey = 0;
+
+ //
+ // Launch its BootOption
+ //
+ InitializeListHead (&BootLists);
+
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", Hotkey->BootOptionNumber);
+ BootOption = BdsLibVariableToOption (&BootLists, Buffer);
+ BootOption->BootCurrent = Hotkey->BootOptionNumber;
+ BdsLibConnectDevicePath (BootOption->DevicePath);
+
+ //
+ // Clear the screen before launch this BootOption
+ //
+ gST->ConOut->Reset (gST->ConOut, FALSE);
+
+ //
+ // BdsLibBootViaBootOption() is expected to be invoked at TPL level TPL_APPLICATION,
+ // so raise the TPL to TPL_APPLICATION first, then restore it
+ //
+ OldTpl = gBS->RaiseTPL (TPL_APPLICATION);
+
+ mHotkeyCallbackPending = TRUE;
+ Status = BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);
+ mHotkeyCallbackPending = FALSE;
+
+ gBS->RestoreTPL (OldTpl);
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Call platform action to indicate the boot fail
+ //
+ BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_FAILED));
+ PlatformBdsBootFail (BootOption, Status, ExitData, ExitDataSize);
+ } else {
+ //
+ // Call platform action to indicate the boot success
+ //
+ BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED));
+ PlatformBdsBootSuccess (BootOption);
+ }
+ }
+
+ Link = GetNextNode (&mHotkeyList, Link);
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+HotkeyRegisterNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleTextInEx
+)
+/*++
+
+Routine Description:
+
+ Register the common HotKey notify function to given SimpleTextInEx protocol instance.
+
+Arguments:
+
+ SimpleTextInEx - Simple Text Input Ex protocol instance
+
+Returns:
+
+ EFI_SUCCESS - Register hotkey notification function successfully.
+ EFI_OUT_OF_RESOURCES - Unable to allocate necessary data structures.
+
+--*/
+{
+ UINTN Index;
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ BDS_HOTKEY_OPTION *Hotkey;
+
+ //
+ // Register notification function for each hotkey
+ //
+ Link = GetFirstNode (&mHotkeyList);
+
+ while (!IsNull (&mHotkeyList, Link)) {
+ Hotkey = BDS_HOTKEY_OPTION_FROM_LINK (Link);
+
+ Index = 0;
+ do {
+ Status = SimpleTextInEx->RegisterKeyNotify (
+ SimpleTextInEx,
+ &Hotkey->KeyData[Index],
+ HotkeyCallback,
+ &Hotkey->NotifyHandle
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // some of the hotkey registry failed
+ //
+ return Status;
+ }
+ Index ++;
+ } while (Index < Hotkey->CodeCount);
+
+ Link = GetNextNode (&mHotkeyList, Link);
+ }
+
+ return EFI_SUCCESS;
+}
+
+VOID
+EFIAPI
+HotkeyEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+/*++
+
+Routine Description:
+ Callback function for SimpleTextInEx protocol install events
+
+Arguments:
+
+ Standard event notification function arguments:
+ Event - the event that is signaled.
+ Context - not used here.
+
+Returns:
+
+--*/
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ EFI_HANDLE Handle;
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleTextInEx;
+
+ while (TRUE) {
+ BufferSize = sizeof (EFI_HANDLE);
+ Status = gBS->LocateHandle (
+ ByRegisterNotify,
+ NULL,
+ mHotkeyRegistration,
+ &BufferSize,
+ &Handle
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // If no more notification events exist
+ //
+ return ;
+ }
+
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiSimpleTextInputExProtocolGuid,
+ (VOID **) &SimpleTextInEx
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ HotkeyRegisterNotify (SimpleTextInEx);
+ }
+}
+
+EFI_STATUS
+HotkeyInsertList (
+ IN EFI_KEY_OPTION *KeyOption
+)
+/*++
+
+Routine Description:
+
+ Insert Key Option to hotkey list.
+
+Arguments:
+
+ KeyOption - The Hot Key Option to be added to hotkey list.
+
+Returns:
+
+ EFI_SUCCESS - Add to hotkey list success.
+
+--*/
+{
+ BDS_HOTKEY_OPTION *HotkeyLeft;
+ BDS_HOTKEY_OPTION *HotkeyRight;
+ UINTN Index;
+ UINT32 KeyOptions;
+ UINT32 KeyShiftStateLeft;
+ UINT32 KeyShiftStateRight;
+ EFI_INPUT_KEY *InputKey;
+ EFI_KEY_DATA *KeyData;
+
+ HotkeyLeft = AllocateZeroPool (sizeof (BDS_HOTKEY_OPTION));
+ if (HotkeyLeft == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ HotkeyLeft->Signature = BDS_HOTKEY_OPTION_SIGNATURE;
+ HotkeyLeft->BootOptionNumber = KeyOption->BootOption;
+
+ KeyOptions = KeyOption->KeyOptions.PackedValue;
+
+ HotkeyLeft->CodeCount = (UINT8) GET_KEY_CODE_COUNT (KeyOptions);
+
+ //
+ // Map key shift state from KeyOptions to EFI_KEY_DATA.KeyState
+ //
+ KeyShiftStateRight = (KeyOptions & EFI_KEY_OPTION_SHIFT) |
+ ((KeyOptions & EFI_KEY_OPTION_CONTROL) << 1) |
+ ((KeyOptions & EFI_KEY_OPTION_ALT) << 2) |
+ ((KeyOptions & EFI_KEY_OPTION_LOGO) << 3) |
+ ((KeyOptions & (EFI_KEY_OPTION_MENU | EFI_KEY_OPTION_SYSREQ)) << 4) |
+ EFI_SHIFT_STATE_VALID;
+
+ KeyShiftStateLeft = (KeyShiftStateRight & 0xffffff00) | ((KeyShiftStateRight & 0xff) << 1);
+
+ InputKey = (EFI_INPUT_KEY *) (((UINT8 *) KeyOption) + sizeof (EFI_KEY_OPTION));
+
+ Index = 0;
+ KeyData = &HotkeyLeft->KeyData[0];
+ do {
+ //
+ // If Key CodeCount is 0, then only KeyData[0] is used;
+ // if Key CodeCount is n, then KeyData[0]~KeyData[n-1] are used
+ //
+ KeyData->Key.ScanCode = InputKey[Index].ScanCode;
+ KeyData->Key.UnicodeChar = InputKey[Index].UnicodeChar;
+ KeyData->KeyState.KeyShiftState = KeyShiftStateLeft;
+
+ Index++;
+ KeyData++;
+ } while (Index < HotkeyLeft->CodeCount);
+ InsertTailList (&mHotkeyList, &HotkeyLeft->Link);
+
+ if (KeyShiftStateLeft != KeyShiftStateRight) {
+ //
+ // Need an extra hotkey for shift key on right
+ //
+ HotkeyRight = AllocateCopyPool (sizeof (BDS_HOTKEY_OPTION), HotkeyLeft);
+ if (HotkeyRight == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Index = 0;
+ KeyData = &HotkeyRight->KeyData[0];
+ do {
+ //
+ // Key.ScanCode and Key.UnicodeChar have already been initialized,
+ // only need to update KeyState.KeyShiftState
+ //
+ KeyData->KeyState.KeyShiftState = KeyShiftStateRight;
+
+ Index++;
+ KeyData++;
+ } while (Index < HotkeyRight->CodeCount);
+ InsertTailList (&mHotkeyList, &HotkeyRight->Link);
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+InitializeHotkeyService (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Process all the "Key####" variables, associate Hotkeys with corresponding Boot Options.
+
+Arguments:
+
+ None
+
+Returns:
+
+ EFI_SUCCESS - Hotkey services successfully initialized.
+
+--*/
+{
+ EFI_STATUS Status;
+ UINT32 BootOptionSupport;
+ UINT16 *KeyOrder;
+ UINTN KeyOrderSize;
+ UINTN Index;
+ UINT16 KeyOptionName[8];
+ UINTN KeyOptionSize;
+ EFI_KEY_OPTION *KeyOption;
+
+ //
+ // Export our capability - EFI_BOOT_OPTION_SUPPORT_KEY and EFI_BOOT_OPTION_SUPPORT_APP
+ //
+ BootOptionSupport = EFI_BOOT_OPTION_SUPPORT_KEY | EFI_BOOT_OPTION_SUPPORT_APP;
+ Status = gRT->SetVariable (
+ L"BootOptionSupport",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ sizeof (UINT32),
+ &BootOptionSupport
+ );
+
+ //
+ // Get valid Key Option List from private EFI variable "KeyOrder"
+ //
+ KeyOrder = BdsLibGetVariableAndSize (
+ VarKeyOrder,
+ &gEfiGlobalVariableGuid,
+ &KeyOrderSize
+ );
+
+ if (KeyOrder == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ for (Index = 0; Index < KeyOrderSize / sizeof (UINT16); Index ++) {
+ UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOrder[Index]);
+ KeyOption = BdsLibGetVariableAndSize (
+ KeyOptionName,
+ &gEfiGlobalVariableGuid,
+ &KeyOptionSize
+ );
+
+ if (KeyOption == NULL || !IsKeyOptionValid (KeyOption)) {
+ UnregisterHotkey (KeyOrder[Index]);
+ } else {
+ HotkeyInsertList (KeyOption);
+ }
+ }
+
+ //
+ // Register Protocol notify for Hotkey service
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ HotkeyEvent,
+ NULL,
+ &mHotkeyEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register for protocol notifications on this event
+ //
+ Status = gBS->RegisterProtocolNotify (
+ &gEfiSimpleTextInputExProtocolGuid,
+ mHotkeyEvent,
+ &mHotkeyRegistration
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
diff --git a/MdeModulePkg/Universal/BdsDxe/Hotkey.h b/MdeModulePkg/Universal/BdsDxe/Hotkey.h new file mode 100644 index 0000000000..87059e12e0 --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/Hotkey.h @@ -0,0 +1,117 @@ +/*++
+
+Copyright (c) 2007 - 2008, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ Hotkey.h
+
+Abstract:
+
+ Provides a way for 3rd party applications to register themselves for launch by the
+ Boot Manager based on hot key
+
+Revision History
+
+--*/
+
+#ifndef _HOTKEY_H
+#define _HOTKEY_H
+
+#include "Bds.h"
+#include "String.h"
+
+#define GET_KEY_CODE_COUNT(KeyOptions) (((KeyOptions) & EFI_KEY_CODE_COUNT) >> 8)
+
+#define BDS_HOTKEY_OPTION_SIGNATURE EFI_SIGNATURE_32 ('B', 'd', 'K', 'O')
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ EFI_HANDLE NotifyHandle;
+ UINT16 BootOptionNumber;
+ UINT8 CodeCount;
+ UINT8 WaitingKey;
+ EFI_KEY_DATA KeyData[3];
+} BDS_HOTKEY_OPTION;
+
+#define BDS_HOTKEY_OPTION_FROM_LINK(a) CR (a, BDS_HOTKEY_OPTION, Link, BDS_HOTKEY_OPTION_SIGNATURE)
+
+#define VarKeyOrder L"KeyOrder"
+
+EFI_STATUS
+RegisterHotkey (
+ IN EFI_KEY_OPTION *KeyOption,
+ OUT UINT16 *KeyOptionNumber
+)
+/*++
+
+Routine Description:
+
+ Create Key#### for the given hotkey.
+
+Arguments:
+
+ KeyOption - The Hot Key Option to be added.
+ KeyOptionNumber - The key option number for Key#### (optional).
+
+Returns:
+
+ EFI_SUCCESS - Register hotkey successfully.
+ EFI_INVALID_PARAMETER - The hotkey option is invalid.
+
+--*/
+;
+
+EFI_STATUS
+UnregisterHotkey (
+ IN UINT16 KeyOptionNumber
+)
+/*++
+
+Routine Description:
+
+ Delete Key#### for the given Key Option number.
+
+Arguments:
+
+ KeyOptionNumber - Key option number for Key####
+
+Returns:
+
+ EFI_SUCCESS - Unregister hotkey successfully.
+ EFI_NOT_FOUND - No Key#### is found for the given Key Option number.
+
+--*/
+;
+
+
+EFI_STATUS
+InitializeHotkeyService (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Process all the "Key####" variables, associate Hotkeys with corresponding Boot Options.
+
+Arguments:
+
+ None
+
+Returns:
+
+ EFI_SUCCESS - Hotkey services successfully initialized.
+
+--*/
+;
+
+#endif
diff --git a/MdeModulePkg/Universal/BdsDxe/HwErrRecSupport.c b/MdeModulePkg/Universal/BdsDxe/HwErrRecSupport.c new file mode 100644 index 0000000000..339361e195 --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/HwErrRecSupport.c @@ -0,0 +1,62 @@ +/*++
+
+Copyright (c) 2007, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ HwErrRecSupport.c
+
+Abstract:
+
+ Set the level of support for Hardware Error Record Persistence that is
+ implemented by the platform.
+
+Revision History
+
+--*/
+
+#include "HwErrRecSupport.h"
+
+VOID
+InitializeHwErrRecSupport (
+ IN UINT16 HwErrRecSupportLevel
+ )
+/*++
+
+ Routine Description:
+ Set the HwErrRecSupport variable contains a binary UINT16 that supplies the
+ level of support for Hardware Error Record Persistence that is implemented
+ by the platform.
+
+ Arguments:
+ HwErrRecSupportLevel
+ zero value - Indicates that the platform implements no support for
+ Hardware Error Record Persistence.
+ non-zero value - Indicates that the platform implements Hardware Error
+ Record Persistence.
+
+ Returns:
+
+--*/
+{
+ EFI_STATUS Status;
+
+ Status = gRT->SetVariable (
+ L"HwErrRecSupport",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof (UINT16),
+ &HwErrRecSupportLevel
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "HwErrRecSupport: Can not set the variable\n"));
+ }
+
+}
diff --git a/MdeModulePkg/Universal/BdsDxe/HwErrRecSupport.h b/MdeModulePkg/Universal/BdsDxe/HwErrRecSupport.h new file mode 100644 index 0000000000..fdd62bad0b --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/HwErrRecSupport.h @@ -0,0 +1,53 @@ +/*++
+
+Copyright (c) 2007, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ HwErrRecSupport.h
+
+Abstract:
+
+ Set the level of support for Hardware Error Record Persistence that is
+ implemented by the platform.
+
+Revision History
+
+--*/
+
+#ifndef _HW_ERR_REC_SUPPORT_H
+#define _HW_ERR_REC_SUPPORT_H
+
+#include "Bds.h"
+
+VOID
+InitializeHwErrRecSupport (
+ IN UINT16 HwErrRecSupportLevel
+ )
+/*++
+
+ Routine Description:
+ Set the HwErrRecSupport variable contains a binary UINT16 that supplies the
+ level of support for Hardware Error Record Persistence that is implemented
+ by the platform.
+
+ Arguments:
+ HwErrRecSupportLevel
+ zero value - Indicates that the platform implements no support for
+ Hardware Error Record Persistence.
+ non-zero value - Indicates that the platform implements Hardware Error
+ Record Persistence.
+
+ Returns:
+
+--*/
+;
+
+#endif
diff --git a/MdeModulePkg/Universal/BdsDxe/Language.c b/MdeModulePkg/Universal/BdsDxe/Language.c new file mode 100644 index 0000000000..8a99e9bf82 --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/Language.c @@ -0,0 +1,420 @@ +/*++
+
+Copyright (c) 2004 - 2008, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ Language.c
+
+Abstract:
+
+ Language settings
+
+Revision History
+
+--*/
+
+#include "Language.h"
+#include "FrontPage.h"
+
+#define NARROW_GLYPH_NUMBER 8
+#define WIDE_GLYPH_NUMBER 75
+
+EFI_GUID mFontPackageGuid = {
+ 0x78941450, 0x90ab, 0x4fb1, {0xb7, 0x5f, 0x58, 0x92, 0x14, 0xe2, 0x4a, 0xc}
+};
+
+typedef struct {
+ //
+ // This 4-bytes total array length is required by PreparePackageList()
+ //
+ UINT32 Length;
+
+ //
+ // This is the Font package definition
+ //
+ EFI_HII_PACKAGE_HEADER Header;
+ UINT16 NumberOfNarrowGlyphs;
+ UINT16 NumberOfWideGlyphs;
+ EFI_NARROW_GLYPH NarrowArray[NARROW_GLYPH_NUMBER];
+ EFI_WIDE_GLYPH WideArray[WIDE_GLYPH_NUMBER];
+} FONT_PACK_BIN;
+
+FONT_PACK_BIN mFontBin = {
+ sizeof (FONT_PACK_BIN),
+ {
+ sizeof (FONT_PACK_BIN) - sizeof (UINT32),
+ EFI_HII_PACKAGE_SIMPLE_FONTS,
+ },
+ NARROW_GLYPH_NUMBER,
+ 0,
+ { // Narrow Glyphs
+ {
+ 0x05d0,
+ 0x00,
+ {
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x4E,
+ 0x6E,
+ 0x62,
+ 0x32,
+ 0x32,
+ 0x3C,
+ 0x68,
+ 0x4C,
+ 0x4C,
+ 0x46,
+ 0x76,
+ 0x72,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ }
+ },
+ {
+ 0x05d1,
+ 0x00,
+ {
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x78,
+ 0x7C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x7E,
+ 0x7E,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ }
+ },
+ {
+ 0x05d2,
+ 0x00,
+ {
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x78,
+ 0x7C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x1C,
+ 0x3E,
+ 0x66,
+ 0x66,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ }
+ },
+ {
+ 0x05d3,
+ 0x00,
+ {
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x7E,
+ 0x7E,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ }
+ },
+ {
+ 0x05d4,
+ 0x00,
+ {
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x7C,
+ 0x7E,
+ 0x06,
+ 0x06,
+ 0x06,
+ 0x06,
+ 0x66,
+ 0x66,
+ 0x66,
+ 0x66,
+ 0x66,
+ 0x66,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ }
+ },
+ {
+ 0x05d5,
+ 0x00,
+ {
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x3C,
+ 0x3C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ }
+ },
+ {
+ 0x05d6,
+ 0x00,
+ {
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x38,
+ 0x38,
+ 0x1E,
+ 0x1E,
+ 0x18,
+ 0x18,
+ 0x18,
+ 0x18,
+ 0x18,
+ 0x18,
+ 0x18,
+ 0x18,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ }
+ },
+ {
+ 0x0000,
+ 0x00,
+ {
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ }
+ }
+ }
+};
+
+VOID
+ExportFonts (
+ VOID
+ )
+/*++
+
+Routine Description:
+ Routine to export glyphs to the HII database. This is in addition to whatever is defined in the Graphics Console driver.
+
+Arguments:
+ None
+
+Returns:
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_HANDLE DriverHandle;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HII_PACKAGE_LIST_HEADER *PackageList;
+
+ //
+ // Create driver handle used by HII database
+ //
+ Status = HiiLibCreateHiiDriverHandle (&DriverHandle);
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ PackageList = PreparePackageList (1, &mFontPackageGuid, &mFontBin);
+ ASSERT (PackageList != NULL);
+
+ gHiiDatabase->NewPackageList (gHiiDatabase, PackageList, DriverHandle, &HiiHandle);
+ FreePool (PackageList);
+}
+
+VOID
+InitializeLanguage (
+ BOOLEAN LangCodesSettingRequired
+ )
+/*++
+
+Routine Description:
+ Determine the current language that will be used
+ based on language related EFI Variables
+
+Arguments:
+ LangCodesSettingRequired - If required to set LangCode variable
+
+Returns:
+
+--*/
+{
+ EFI_STATUS Status;
+ UINTN Size;
+ CHAR8 *Lang;
+ CHAR8 LangCode[ISO_639_2_ENTRY_SIZE];
+ CHAR8 *LangCodes;
+ CHAR8 *PlatformLang;
+ CHAR8 *PlatformLangCodes;
+ UINTN Index;
+ BOOLEAN Invalid;
+
+ ExportFonts ();
+
+ LangCodes = (CHAR8 *)PcdGetPtr (PcdUefiVariableDefaultLangCodes);
+ if (LangCodesSettingRequired) {
+ if (!FeaturePcdGet (PcdUefiVariableDefaultLangDepricate)) {
+ //
+ // UEFI 2.1 depricated this variable so we support turning it off
+ //
+ Status = gRT->SetVariable (
+ L"LangCodes",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ AsciiStrLen (LangCodes),
+ LangCodes
+ );
+ }
+
+
+ PlatformLangCodes = (CHAR8 *)PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes);
+ Status = gRT->SetVariable (
+ L"PlatformLangCodes",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ AsciiStrSize (PlatformLangCodes),
+ PlatformLangCodes
+ );
+ }
+
+ if (!FeaturePcdGet (PcdUefiVariableDefaultLangDepricate)) {
+ //
+ // UEFI 2.1 depricated this variable so we support turning it off
+ //
+
+ //
+ // Find current LangCode from Lang NV Variable
+ //
+ Size = ISO_639_2_ENTRY_SIZE;
+ Status = gRT->GetVariable (
+ L"Lang",
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &Size,
+ &LangCode
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = EFI_NOT_FOUND;
+ for (Index = 0; LangCodes[Index] != 0; Index += ISO_639_2_ENTRY_SIZE) {
+ if (CompareMem (&LangCodes[Index], LangCode, ISO_639_2_ENTRY_SIZE) == 0) {
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+ }
+
+ //
+ // If we cannot get language code from Lang variable,
+ // or LangCode cannot be found from language table,
+ // set the mDefaultLangCode to Lang variable.
+ //
+ if (EFI_ERROR (Status)) {
+ Lang = (CHAR8 *)PcdGetPtr (PcdUefiVariableDefaultLang);
+ Status = gRT->SetVariable (
+ L"Lang",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ ISO_639_2_ENTRY_SIZE,
+ Lang
+ );
+ }
+ }
+
+ Invalid = FALSE;
+ PlatformLang = BdsLibGetVariableAndSize (L"PlatformLang", &gEfiGlobalVariableGuid, &Size);
+ if (PlatformLang != NULL) {
+ //
+ // Check Current PlatformLang value against PlatformLangCode. Need a library that is TBD
+ // Set Invalid based on state of PlatformLang.
+ //
+
+ FreePool (PlatformLang);
+ } else {
+ // No valid variable is set
+ Invalid = TRUE;
+ }
+
+ if (Invalid) {
+ PlatformLang = (CHAR8 *)PcdGetPtr (PcdUefiVariableDefaultPlatformLang);
+ Status = gRT->SetVariable (
+ L"PlatformLang",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ AsciiStrSize (PlatformLang),
+ PlatformLang
+ );
+ }
+}
diff --git a/MdeModulePkg/Universal/BdsDxe/Language.h b/MdeModulePkg/Universal/BdsDxe/Language.h new file mode 100644 index 0000000000..586a59a555 --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/Language.h @@ -0,0 +1,47 @@ +/*++
+
+Copyright (c) 2004 - 2008, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ Language.h
+
+Abstract:
+
+ Language setting
+
+Revision History
+
+--*/
+
+#ifndef _LANGUAGE_H
+#define _LANGUAGE_H
+
+#include "String.h"
+
+VOID
+InitializeLanguage (
+ BOOLEAN LangCodesSettingRequired
+ )
+/*++
+
+Routine Description:
+ Determine the current language that will be used
+ based on language related EFI Variables
+
+Arguments:
+ LangCodesSettingRequired - If required to set LangCode variable
+
+Returns:
+
+--*/
+;
+
+#endif // _LANGUAGE_H_
diff --git a/MdeModulePkg/Universal/BdsDxe/MemoryTest.c b/MdeModulePkg/Universal/BdsDxe/MemoryTest.c new file mode 100644 index 0000000000..b9f24e6d4b --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/MemoryTest.c @@ -0,0 +1,431 @@ +/*++
+
+Copyright (c) 2004 - 2008, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ MemoryTest.c
+
+Abstract:
+
+ Perform the platform memory test
+
+--*/
+
+#include "Bds.h"
+#include "String.h"
+
+//
+// BDS Platform Functions
+//
+EFI_STATUS
+PlatformBdsShowProgress (
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleForeground,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleBackground,
+ IN CHAR16 *Title,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL ProgressColor,
+ IN UINTN Progress,
+ IN UINTN PreviousValue
+ )
+/*++
+
+Routine Description:
+
+ Show progress bar with title above it. It only works in Graphics mode.
+
+Arguments:
+
+ TitleForeground - Foreground color for Title.
+ TitleBackground - Background color for Title.
+ Title - Title above progress bar.
+ ProgressColor - Progress bar color.
+ Progress - Progress (0-100)
+
+Returns:
+
+ EFI_STATUS - Success update the progress bar
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_UGA_DRAW_PROTOCOL *UgaDraw;
+ UINT32 SizeOfX;
+ UINT32 SizeOfY;
+ UINT32 ColorDepth;
+ UINT32 RefreshRate;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color;
+ UINTN BlockHeight;
+ UINTN BlockWidth;
+ UINTN BlockNum;
+ UINTN PosX;
+ UINTN PosY;
+ UINTN Index;
+
+ if (Progress > 100) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UgaDraw = NULL;
+ Status = gBS->HandleProtocol (
+ gST->ConsoleOutHandle,
+ &gEfiGraphicsOutputProtocolGuid,
+ (VOID **) &GraphicsOutput
+ );
+ if (EFI_ERROR (Status)) {
+ GraphicsOutput = NULL;
+
+ Status = gBS->HandleProtocol (
+ gST->ConsoleOutHandle,
+ &gEfiUgaDrawProtocolGuid,
+ (VOID **) &UgaDraw
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ if (GraphicsOutput != NULL) {
+ SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;
+ SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;
+ } else {
+ Status = UgaDraw->GetMode (
+ UgaDraw,
+ &SizeOfX,
+ &SizeOfY,
+ &ColorDepth,
+ &RefreshRate
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ BlockWidth = SizeOfX / 100;
+ BlockHeight = SizeOfY / 50;
+
+ BlockNum = Progress;
+
+ PosX = 0;
+ PosY = SizeOfY * 48 / 50;
+
+ if (BlockNum == 0) {
+ //
+ // Clear progress area
+ //
+ SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0);
+
+ if (GraphicsOutput != NULL) {
+ Status = GraphicsOutput->Blt (
+ GraphicsOutput,
+ &Color,
+ EfiBltVideoFill,
+ 0,
+ 0,
+ 0,
+ PosY - GLYPH_HEIGHT - 1,
+ SizeOfX,
+ SizeOfY - (PosY - GLYPH_HEIGHT - 1),
+ SizeOfX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+ );
+ } else {
+ Status = UgaDraw->Blt (
+ UgaDraw,
+ (EFI_UGA_PIXEL *) &Color,
+ EfiUgaVideoFill,
+ 0,
+ 0,
+ 0,
+ PosY - GLYPH_HEIGHT - 1,
+ SizeOfX,
+ SizeOfY - (PosY - GLYPH_HEIGHT - 1),
+ SizeOfX * sizeof (EFI_UGA_PIXEL)
+ );
+ }
+ }
+ //
+ // Show progress by drawing blocks
+ //
+ for (Index = PreviousValue; Index < BlockNum; Index++) {
+ PosX = Index * BlockWidth;
+ if (GraphicsOutput != NULL) {
+ Status = GraphicsOutput->Blt (
+ GraphicsOutput,
+ &ProgressColor,
+ EfiBltVideoFill,
+ 0,
+ 0,
+ PosX,
+ PosY,
+ BlockWidth - 1,
+ BlockHeight,
+ (BlockWidth) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+ );
+ } else {
+ Status = UgaDraw->Blt (
+ UgaDraw,
+ (EFI_UGA_PIXEL *) &ProgressColor,
+ EfiUgaVideoFill,
+ 0,
+ 0,
+ PosX,
+ PosY,
+ BlockWidth - 1,
+ BlockHeight,
+ (BlockWidth) * sizeof (EFI_UGA_PIXEL)
+ );
+ }
+ }
+
+ PrintXY (
+ (SizeOfX - StrLen (Title) * GLYPH_WIDTH) / 2,
+ PosY - GLYPH_HEIGHT - 1,
+ &TitleForeground,
+ &TitleBackground,
+ Title
+ );
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+BdsMemoryTest (
+ IN EXTENDMEM_COVERAGE_LEVEL Level
+ )
+/*++
+
+Routine Description:
+
+ Perform the memory test base on the memory test intensive level,
+ and update the memory resource.
+
+Arguments:
+
+ Level - The memory test intensive level.
+
+Returns:
+
+ EFI_STATUS - Success test all the system memory and update
+ the memory resource
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_STATUS InitStatus;
+ EFI_STATUS ReturnStatus;
+ BOOLEAN RequireSoftECCInit;
+ EFI_GENERIC_MEMORY_TEST_PROTOCOL *GenMemoryTest;
+ UINT64 TestedMemorySize;
+ UINT64 TotalMemorySize;
+ UINTN TestPercent;
+ UINT64 PreviousValue;
+ BOOLEAN ErrorOut;
+ BOOLEAN TestAbort;
+ EFI_INPUT_KEY Key;
+ CHAR16 StrPercent[16];
+ CHAR16 *StrTotalMemory;
+ CHAR16 *Pos;
+ CHAR16 *TmpStr;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color;
+ UINT8 Value;
+ UINTN DataSize;
+ UINT32 Attributes;
+ UINT32 TempData;
+
+ ReturnStatus = EFI_SUCCESS;
+ ZeroMem (&Key, sizeof (EFI_INPUT_KEY));
+
+ Pos = AllocatePool (128);
+
+ if (Pos == NULL) {
+ return ReturnStatus;
+ }
+
+ StrTotalMemory = Pos;
+
+ TestedMemorySize = 0;
+ TotalMemorySize = 0;
+ PreviousValue = 0;
+ ErrorOut = FALSE;
+ TestAbort = FALSE;
+
+ SetMem (&Foreground, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff);
+ SetMem (&Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0);
+ SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff);
+
+ RequireSoftECCInit = FALSE;
+
+ gST->ConOut->ClearScreen (gST->ConOut);
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_YELLOW | EFI_BRIGHT);
+ gST->ConOut->EnableCursor (gST->ConOut, FALSE);
+
+ Status = gBS->LocateProtocol (
+ &gEfiGenericMemTestProtocolGuid,
+ NULL,
+ (VOID **) &GenMemoryTest
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (Pos);
+ return EFI_SUCCESS;
+ }
+
+ InitStatus = GenMemoryTest->MemoryTestInit (
+ GenMemoryTest,
+ Level,
+ &RequireSoftECCInit
+ );
+ if (InitStatus == EFI_NO_MEDIA) {
+ //
+ // The PEI codes also have the relevant memory test code to check the memory,
+ // it can select to test some range of the memory or all of them. If PEI code
+ // checks all the memory, this BDS memory test will has no not-test memory to
+ // do the test, and then the status of EFI_NO_MEDIA will be returned by
+ // "MemoryTestInit". So it does not need to test memory again, just return.
+ //
+ FreePool (Pos);
+ return EFI_SUCCESS;
+ }
+
+ gST->ConOut->SetCursorPosition (gST->ConOut, 0, 2);
+ TmpStr = GetStringById (STRING_TOKEN (STR_ESC_TO_SKIP_MEM_TEST));
+
+ if (TmpStr != NULL) {
+ gST->ConOut->OutputString (gST->ConOut, TmpStr);
+ FreePool (TmpStr);
+ }
+
+ do {
+ Status = GenMemoryTest->PerformMemoryTest (
+ GenMemoryTest,
+ &TestedMemorySize,
+ &TotalMemorySize,
+ &ErrorOut,
+ TestAbort
+ );
+ if (ErrorOut && (Status == EFI_DEVICE_ERROR)) {
+ TmpStr = GetStringById (STRING_TOKEN (STR_SYSTEM_MEM_ERROR));
+ if (TmpStr != NULL) {
+ PrintXY (10, 10, NULL, NULL, TmpStr);
+ gST->ConOut->SetCursorPosition (gST->ConOut, 0, 4);
+ gST->ConOut->OutputString (gST->ConOut, TmpStr);
+ FreePool (TmpStr);
+ }
+
+ ASSERT (0);
+ }
+
+ TempData = (UINT32) DivU64x32 (TotalMemorySize, 16);
+ TestPercent = (UINTN) DivU64x32 (
+ DivU64x32 (MultU64x32 (TestedMemorySize, 100), 16),
+ TempData
+ );
+ if (TestPercent != PreviousValue) {
+ UnicodeValueToString (StrPercent, 0, TestPercent, 0);
+ gST->ConOut->SetCursorPosition (gST->ConOut, 0, 0);
+ TmpStr = GetStringById (STRING_TOKEN (STR_MEMORY_TEST_PERCENT));
+ if (TmpStr != NULL) {
+ BdsLibOutputStrings (gST->ConOut, StrPercent, TmpStr, NULL);
+ FreePool (TmpStr);
+ }
+
+ TmpStr = GetStringById (STRING_TOKEN (STR_PERFORM_MEM_TEST));
+ if (TmpStr != NULL) {
+ PlatformBdsShowProgress (
+ Foreground,
+ Background,
+ TmpStr,
+ Color,
+ TestPercent,
+ (UINTN) PreviousValue
+ );
+ FreePool (TmpStr);
+ }
+ }
+
+ PreviousValue = TestPercent;
+
+ if (Key.ScanCode == SCAN_ESC) {
+ if (!RequireSoftECCInit) {
+ TmpStr = GetStringById (STRING_TOKEN (STR_PERFORM_MEM_TEST));
+ if (TmpStr != NULL) {
+ PlatformBdsShowProgress (
+ Foreground,
+ Background,
+ TmpStr,
+ Color,
+ 100,
+ (UINTN) PreviousValue
+ );
+ FreePool (TmpStr);
+ }
+
+ gST->ConOut->SetCursorPosition (gST->ConOut, 0, 0);
+ gST->ConOut->OutputString (gST->ConOut, L"100");
+ Status = GenMemoryTest->Finished (GenMemoryTest);
+ goto Done;
+ }
+
+ TestAbort = TRUE;
+ }
+ } while (Status != EFI_NOT_FOUND);
+
+ Status = GenMemoryTest->Finished (GenMemoryTest);
+
+Done:
+ UnicodeValueToString (StrTotalMemory, COMMA_TYPE, TotalMemorySize, 0);
+ if (StrTotalMemory[0] == L',') {
+ StrTotalMemory++;
+ }
+
+ TmpStr = GetStringById (STRING_TOKEN (STR_MEM_TEST_COMPLETED));
+ if (TmpStr != NULL) {
+ StrCat (StrTotalMemory, TmpStr);
+ FreePool (TmpStr);
+ }
+
+ gST->ConOut->ClearScreen (gST->ConOut);
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_YELLOW | EFI_BRIGHT);
+ gST->ConOut->EnableCursor (gST->ConOut, FALSE);
+ gST->ConOut->OutputString (gST->ConOut, StrTotalMemory);
+ PlatformBdsShowProgress (
+ Foreground,
+ Background,
+ StrTotalMemory,
+ Color,
+ 100,
+ (UINTN) PreviousValue
+ );
+
+ FreePool (Pos);
+
+ DataSize = sizeof (Value);
+ Status = gRT->GetVariable (
+ L"BootState",
+ &gEfiBootStateGuid,
+ &Attributes,
+ &DataSize,
+ &Value
+ );
+
+ if (EFI_ERROR (Status)) {
+ Value = 1;
+ gRT->SetVariable (
+ L"BootState",
+ &gEfiBootStateGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (Value),
+ &Value
+ );
+ }
+
+ return ReturnStatus;
+}
diff --git a/MdeModulePkg/Universal/BdsDxe/String.c b/MdeModulePkg/Universal/BdsDxe/String.c new file mode 100644 index 0000000000..84f9f96edf --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/String.c @@ -0,0 +1,104 @@ +/*++
+
+Copyright (c) 2004 - 2008, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ String.c
+
+Abstract:
+
+ String support
+
+--*/
+
+#include "Bds.h"
+#include "Language.h"
+#include "FrontPage.h"
+
+EFI_HII_HANDLE gStringPackHandle;
+
+EFI_GUID mBdsStringPackGuid = {
+ 0x7bac95d3, 0xddf, 0x42f3, 0x9e, 0x24, 0x7c, 0x64, 0x49, 0x40, 0x37, 0x9a
+};
+
+EFI_STATUS
+InitializeStringSupport (
+ VOID
+ )
+/*++
+
+Routine Description:
+ Initialize HII global accessor for string support
+
+Arguments:
+ None
+
+Returns:
+ EFI_SUCCESS - String support initialize success.
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_HANDLE DriverHandle;
+ EFI_HII_PACKAGE_LIST_HEADER *PackageList;
+
+ Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **) &gHiiDatabase);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Create driver handle used by HII database
+ //
+ Status = HiiLibCreateHiiDriverHandle (&DriverHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PackageList = PreparePackageList (1, &mBdsStringPackGuid, &BdsStrings);
+ ASSERT (PackageList != NULL);
+
+ Status = gHiiDatabase->NewPackageList (
+ gHiiDatabase,
+ PackageList,
+ DriverHandle,
+ &gStringPackHandle
+ );
+
+ FreePool (PackageList);
+ return Status;
+}
+
+CHAR16 *
+GetStringById (
+ IN EFI_STRING_ID Id
+ )
+/*++
+
+Routine Description:
+ Get string by string id from HII Interface
+
+Arguments:
+ Id - String ID.
+
+Returns:
+ CHAR16 * - String from ID.
+ NULL - If error occurs.
+
+--*/
+{
+ CHAR16 *String;
+
+ String = NULL;
+ GetStringFromHandle (gStringPackHandle, Id, &String);
+
+ return String;
+}
diff --git a/MdeModulePkg/Universal/BdsDxe/String.h b/MdeModulePkg/Universal/BdsDxe/String.h new file mode 100644 index 0000000000..14c42a95d0 --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/String.h @@ -0,0 +1,61 @@ +/*++
+
+Copyright (c) 2004 - 2008, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ String.h
+
+Abstract:
+
+ String support
+
+Revision History
+
+--*/
+
+#ifndef _STRING_H_
+#define _STRING_H_
+
+#include "Bds.h"
+
+extern EFI_HII_HANDLE gStringPackHandle;
+
+//
+// This is the VFR compiler generated header file which defines the
+// string identifiers.
+//
+
+extern UINT8 BdsStrings[];
+
+//
+// String Definition Guid for BDS Platform
+//
+#define EFI_BDS_PLATFORM_GUID \
+ { \
+ 0x7777E939, 0xD57E, 0x4DCB, 0xA0, 0x8E, 0x64, 0xD7, 0x98, 0x57, 0x1E, 0x0F \
+ }
+
+CHAR16 *
+GetStringById (
+ IN EFI_STRING_ID Id
+ );
+
+EFI_STATUS
+InitializeStringSupport (
+ VOID
+ );
+
+EFI_STATUS
+CallFrontPage (
+ VOID
+ );
+
+#endif // _STRING_H_
diff --git a/MdeModulePkg/Universal/BdsDxe/Strings.uni b/MdeModulePkg/Universal/BdsDxe/Strings.uni Binary files differnew file mode 100644 index 0000000000..c83bb8a991 --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/Strings.uni diff --git a/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsole.c b/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsole.c index 37e816af01..77a209e1e4 100644 --- a/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsole.c +++ b/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsole.c @@ -83,10 +83,19 @@ GRAPHICS_CONSOLE_DEV mGraphicsConsoleDevTemplate = { { 0, 0, 0, 0, 0, 0 } // Mode 3
},
(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) NULL,
- (EFI_HII_HANDLE) 0
+ (EFI_HII_HANDLE ) 0
};
+#if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
+EFI_HII_DATABASE_PROTOCOL *mHiiDatabase;
+EFI_HII_FONT_PROTOCOL *mHiiFont;
+BOOLEAN mFirstAccessFlag = TRUE;
+
+STATIC EFI_GUID mFontPackageListGuid = {0xf5f219d3, 0x7006, 0x4648, 0xac, 0x8d, 0xd6, 0x1d, 0xfb, 0x7b, 0xc6, 0xad};
+
+#else
EFI_HII_PROTOCOL *mHii;
+#endif
static CHAR16 mCrLfString[3] = { CHAR_CARRIAGE_RETURN, CHAR_LINEFEED, CHAR_NULL };
@@ -194,6 +203,7 @@ GraphicsConsoleControllerDriverSupported ( } else {
goto Error;
}
+
//
// Does Hii Exist? If not, we aren't ready to run
//
@@ -249,8 +259,6 @@ GraphicsConsoleControllerDriverStart ( {
EFI_STATUS Status;
GRAPHICS_CONSOLE_DEV *Private;
- EFI_HII_PACKAGES *Package;
- EFI_HII_FONT_PACK *FontPack;
UINTN NarrowFontSize;
UINT32 HorizontalResolution;
UINT32 VerticalResolution;
@@ -259,9 +267,8 @@ GraphicsConsoleControllerDriverStart ( UINTN MaxMode;
UINTN Columns;
UINTN Rows;
- UINT8 *Location;
UINT32 ModeNumber;
-
+
ModeNumber = 0;
//
@@ -301,17 +308,14 @@ GraphicsConsoleControllerDriverStart ( }
}
- //
- // Get the HII protocol. If Supported() succeeds, do we really
- // need to get HII protocol again?
- //
- Status = EfiLocateHiiProtocol ();
- if (EFI_ERROR (Status)) {
- goto Error;
- }
-
NarrowFontSize = ReturnNarrowFontSize ();
+#if 1
+ if (mFirstAccessFlag) {
+ HiiLibAddFontPackageToHiiDatabase (NarrowFontSize, (UINT8 *) UsStdNarrowGlyphData, &mFontPackageListGuid, &(Private->HiiHandle));
+ mFirstAccessFlag = FALSE;
+ }
+#else
FontPack = AllocateZeroPool (sizeof (EFI_HII_FONT_PACK) + NarrowFontSize);
ASSERT (FontPack);
@@ -333,7 +337,7 @@ GraphicsConsoleControllerDriverStart ( // Free the font database
//
FreePool (FontPack);
-
+#endif
//
// If the current mode information can not be retrieved, then attemp to set the default mode
// of 800x600, 32 bit colot, 60 Hz refresh.
@@ -614,7 +618,14 @@ GraphicsConsoleControllerDriverStop ( //
// Remove the font pack
//
+#if 1
+ Status = HiiLibRemovePackagesFromHiiDatabase (Private->HiiHandle);
+ if (!EFI_ERROR (Status)) {
+ mFirstAccessFlag = TRUE;
+ }
+#else
mHii->RemovePack (mHii, Private->HiiHandle);
+#endif
//
// Free our instance data
@@ -678,7 +689,7 @@ EfiLocateHiiProtocol ( /*++
Routine Description:
- Find if the HII protocol is available. If yes, locate the HII protocol
+ Locate HII protocols for future usage.
Arguments:
@@ -690,6 +701,43 @@ EfiLocateHiiProtocol ( UINTN Size;
EFI_STATUS Status;
+#if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
+
+ //
+ // There should only be one - so buffer size is this
+ //
+ Size = sizeof (EFI_HANDLE);
+
+ Status = gBS->LocateHandle (
+ ByProtocol,
+ &gEfiHiiDatabaseProtocolGuid,
+ NULL,
+ &Size,
+ (VOID **) &Handle
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiHiiDatabaseProtocolGuid,
+ (VOID **) &mHiiDatabase
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiHiiFontProtocolGuid,
+ (VOID **) &mHiiFont
+ );
+ return Status;
+#else
+
//
// There should only be one - so buffer size is this
//
@@ -710,11 +758,13 @@ EfiLocateHiiProtocol ( Status = gBS->HandleProtocol (
Handle,
&gEfiHiiProtocolGuid,
- (VOID **)&mHii
+ &mHii
);
return Status;
+#endif
}
+
//
// Body of the STO functions
//
@@ -1090,15 +1140,31 @@ GraphicsConsoleConOutTestString ( --*/
{
EFI_STATUS Status;
- UINT16 GlyphWidth;
- UINT32 GlyphStatus;
UINT16 Count;
- GLYPH_UNION *Glyph;
-
- GlyphStatus = 0;
- Count = 0;
- while (WString[Count]) {
+#if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
+ EFI_IMAGE_OUTPUT *Blt = NULL;
+#else
+ UINT16 GlyphWidth;
+ UINT32 GlyphStatus = 0;
+ GLYPH_UNION *Glyph;
+#endif
+
+ Count = 0;
+
+ while (WString[Count] != 0) {
+#if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
+ Status = mHiiFont->GetGlyph (
+ mHiiFont,
+ WString[Count],
+ NULL,
+ &Blt,
+ NULL
+ );
+ SafeFreePool (Blt);
+ Blt = NULL;
+ Count++;
+#else
Status = mHii->GetGlyph (
mHii,
WString,
@@ -1107,7 +1173,7 @@ GraphicsConsoleConOutTestString ( &GlyphWidth,
&GlyphStatus
);
-
+#endif
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
@@ -1654,6 +1720,69 @@ GetTextColors ( return EFI_SUCCESS;
}
+#if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
+EFI_STATUS
+DrawUnicodeWeightAtCursorN (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *UnicodeWeight,
+ IN UINTN Count
+ )
+{
+ EFI_STATUS Status;
+ GRAPHICS_CONSOLE_DEV *Private;
+ EFI_IMAGE_OUTPUT *Blt;
+ EFI_STRING String;
+ EFI_FONT_DISPLAY_INFO *FontInfo;
+
+ Private = GRAPHICS_CONSOLE_CON_OUT_DEV_FROM_THIS (This);
+ //
+ // GOP protocol is required in UEFI mode.
+ //
+ ASSERT (Private->GraphicsOutput != NULL);
+
+ Blt = (EFI_IMAGE_OUTPUT *) AllocateZeroPool (sizeof (EFI_IMAGE_OUTPUT));
+ if (Blt == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Blt->Width = (UINT16) (Private->ModeData[This->Mode->Mode].GopWidth);
+ Blt->Height = (UINT16) (Private->ModeData[This->Mode->Mode].GopHeight);
+ Blt->Image.Screen = Private->GraphicsOutput;
+
+ String = AllocateCopyPool ((Count + 1) * sizeof (CHAR16), UnicodeWeight);
+ if (String == NULL) {
+ SafeFreePool (Blt);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ *(String + Count) = 0;
+
+ FontInfo = (EFI_FONT_DISPLAY_INFO *) AllocateZeroPool (sizeof (EFI_FONT_DISPLAY_INFO));
+ if (FontInfo == NULL) {
+ SafeFreePool (Blt);
+ SafeFreePool (String);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ GetTextColors (This, &FontInfo->ForegroundColor, &FontInfo->BackgroundColor);
+
+ Status = mHiiFont->StringToImage (
+ mHiiFont,
+ EFI_HII_IGNORE_IF_NO_GLYPH | EFI_HII_DIRECT_TO_SCREEN,
+ String,
+ FontInfo,
+ &Blt,
+ This->Mode->CursorColumn * GLYPH_WIDTH + Private->ModeData[This->Mode->Mode].DeltaX,
+ This->Mode->CursorRow * GLYPH_HEIGHT + Private->ModeData[This->Mode->Mode].DeltaY,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ SafeFreePool (Blt);
+ SafeFreePool (String);
+ SafeFreePool (FontInfo);
+ return Status;
+}
+#else
STATIC
EFI_STATUS
DrawUnicodeWeightAtCursorN (
@@ -1794,6 +1923,7 @@ DrawUnicodeWeightAtCursorN ( return ReturnStatus;
}
+#endif
STATIC
EFI_STATUS
diff --git a/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsole.h b/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsole.h index f78c22c564..1c182f3b90 100644 --- a/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsole.h +++ b/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsole.h @@ -24,7 +24,7 @@ Revision History #define _GRAPHICS_CONSOLE_H
#include <PiDxe.h>
-#include <Protocol/FrameworkHii.h>
+//#include <Protocol/FrameworkHii.h>
#include <Protocol/SimpleTextOut.h>
#include <Protocol/GraphicsOutput.h>
#include <Protocol/UgaDraw.h>
@@ -32,10 +32,17 @@ Revision History #include <Library/DebugLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/UefiLib.h>
-#include <Library/FrameworkHiiLib.h>
+//#include <Library/FrameworkHiiLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiBootServicesTableLib.h>
+#include <Library/HiiLib.h>
+#include <Library/BaseLib.h>
+
+#include <MdeModuleHii.h>
+
+#include <Protocol/HiiFont.h>
+#include <Protocol/HiiDatabase.h>
extern EFI_COMPONENT_NAME_PROTOCOL gGraphicsConsoleComponentName;
@@ -174,8 +181,8 @@ GraphicsConsoleComponentNameGetControllerName ( //
// Glyph database
//
-#define GLYPH_WIDTH 8
-#define GLYPH_HEIGHT 19
+//#define GLYPH_WIDTH 8
+//#define GLYPH_HEIGHT 19
//
// User can define valid graphic resolution here
@@ -307,11 +314,6 @@ GraphicsConsoleConOutEnableCursor ( );
EFI_STATUS
-EfiLocateHiiProtocol (
- VOID
- );
-
-EFI_STATUS
EFIAPI
GraphicsConsoleControllerDriverSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
@@ -336,4 +338,11 @@ GraphicsConsoleControllerDriverStop ( IN EFI_HANDLE *ChildHandleBuffer
);
+EFI_STATUS
+EfiLocateHiiProtocol (
+ VOID
+ )
+;
+
+
#endif
diff --git a/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf b/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf index 013bc18389..4ccfe2177c 100644 --- a/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf +++ b/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf @@ -21,7 +21,7 @@ MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
EDK_RELEASE_VERSION = 0x00020000
- EFI_SPECIFICATION_VERSION = 0x00020000
+ EFI_SPECIFICATION_VERSION = 0x0002000A
ENTRY_POINT = InitializeGraphicsConsole
@@ -43,6 +43,7 @@ [Packages]
MdePkg/MdePkg.dec
# currently use Hii for glyph lookup, need to change to UEFI scheme
+ MdeModulePkg/MdeModulePkg.dec
IntelFrameworkPkg/IntelFrameworkPkg.dec
[LibraryClasses]
@@ -52,12 +53,13 @@ UefiLib
UefiDriverEntryPoint
DebugLib
- FrameworkHiiLib
+ HiiLib
[Protocols]
gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiSimpleTextOutProtocolGuid # PROTOCOL BY_START
- gEfiHiiProtocolGuid # PROTOCOL TO_START
gEfiGraphicsOutputProtocolGuid # PROTOCOL TO_START
gEfiUgaDrawProtocolGuid # PROTOCOL TO_START
+ gEfiHiiFontProtocolGuid
+ gEfiHiiDatabaseProtocolGuid
diff --git a/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.msa b/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.msa index 187cc9b4ec..4276a2d042 100644 --- a/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.msa +++ b/MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.msa @@ -65,9 +65,6 @@ <Protocol Usage="TO_START">
<ProtocolCName>gEfiGraphicsOutputProtocolGuid</ProtocolCName>
</Protocol>
- <Protocol Usage="TO_START">
- <ProtocolCName>gEfiHiiProtocolGuid</ProtocolCName>
- </Protocol>
<Protocol Usage="BY_START">
<ProtocolCName>gEfiSimpleTextOutProtocolGuid</ProtocolCName>
</Protocol>
diff --git a/MdeModulePkg/Universal/DevicePathDxe/DevicePathFromText.c b/MdeModulePkg/Universal/DevicePathDxe/DevicePathFromText.c index db93c6daa1..7055c74571 100644 --- a/MdeModulePkg/Universal/DevicePathDxe/DevicePathFromText.c +++ b/MdeModulePkg/Universal/DevicePathDxe/DevicePathFromText.c @@ -2359,14 +2359,14 @@ DevPathFromTextSata ( MSG_SATA_DP,
sizeof (SATA_DEVICE_PATH)
);
- Sata->HbaPortNumber = (UINT16) Xtoi (Param1);
+ Sata->HBAPortNumber = (UINT16) Xtoi (Param1);
if (Param3 != NULL) {
- Sata->PortMultiplierPort = (UINT16) Xtoi (Param2);
+ Sata->PortMultiplierPortNumber = (UINT16) Xtoi (Param2);
Param2 = Param3;
} else {
- Sata->PortMultiplierPort = 0;
+ Sata->PortMultiplierPortNumber = 0;
}
- Sata->LogicalUnitNumber = (UINT16) Xtoi (Param2);
+ Sata->Lun = (UINT16) Xtoi (Param2);
return (EFI_DEVICE_PATH_PROTOCOL *) Sata;
}
diff --git a/MdeModulePkg/Universal/DevicePathDxe/DevicePathToText.c b/MdeModulePkg/Universal/DevicePathDxe/DevicePathToText.c index 546c4a40e3..78c95737a4 100644 --- a/MdeModulePkg/Universal/DevicePathDxe/DevicePathToText.c +++ b/MdeModulePkg/Universal/DevicePathDxe/DevicePathToText.c @@ -830,9 +830,9 @@ DevPathToTextSata ( CatPrint (
Str,
L"Sata(0x%x,0x%x,0x%x)",
- (UINTN) Sata->HbaPortNumber,
- (UINTN) Sata->PortMultiplierPort,
- (UINTN) Sata->LogicalUnitNumber
+ (UINTN) Sata->HBAPortNumber,
+ (UINTN) Sata->PortMultiplierPortNumber,
+ (UINTN) Sata->Lun
);
}
diff --git a/MdeModulePkg/Universal/DriverSampleDxe/DriverSample.c b/MdeModulePkg/Universal/DriverSampleDxe/DriverSample.c new file mode 100644 index 0000000000..f18e31163f --- /dev/null +++ b/MdeModulePkg/Universal/DriverSampleDxe/DriverSample.c @@ -0,0 +1,788 @@ +/** @file
+Copyright (c) 2004 - 2007, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+ DriverSample.c
+
+Abstract:
+
+ This is an example of how a driver might export data to the HII protocol to be
+ later utilized by the Setup Protocol
+
+
+**/
+
+
+#include "DriverSample.h"
+
+#define DISPLAY_ONLY_MY_ITEM 0x0002
+
+EFI_GUID mFormSetGuid = FORMSET_GUID;
+EFI_GUID mInventoryGuid = INVENTORY_GUID;
+
+CHAR16 VariableName[] = L"MyIfrNVData";
+
+VOID
+EncodePassword (
+ IN CHAR16 *Password,
+ IN UINT8 MaxSize
+ )
+{
+ UINTN Index;
+ UINTN Loop;
+ CHAR16 *Buffer;
+ CHAR16 *Key;
+
+ Key = L"MAR10648567";
+ Buffer = AllocateZeroPool (MaxSize);
+ ASSERT (Buffer != NULL);
+
+ for (Index = 0; Key[Index] != 0; Index++) {
+ for (Loop = 0; Loop < (UINT8) (MaxSize / 2); Loop++) {
+ Buffer[Loop] = (CHAR16) (Password[Loop] ^ Key[Index]);
+ }
+ }
+
+ CopyMem (Password, Buffer, MaxSize);
+
+ gBS->FreePool (Buffer);
+ return ;
+}
+
+EFI_STATUS
+ValidatePassword (
+ DRIVER_SAMPLE_PRIVATE_DATA *PrivateData,
+ EFI_STRING_ID StringId
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN BufferSize;
+ CHAR16 *Password;
+ CHAR16 *EncodedPassword;
+ BOOLEAN OldPassword;
+
+ //
+ // Get encoded password first
+ //
+ BufferSize = sizeof (DRIVER_SAMPLE_CONFIGURATION);
+ Status = gRT->GetVariable (
+ VariableName,
+ &mFormSetGuid,
+ NULL,
+ &BufferSize,
+ &PrivateData->Configuration
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Old password not exist, prompt for new password
+ //
+ return EFI_SUCCESS;
+ }
+
+ OldPassword = FALSE;
+ //
+ // Check whether we have any old password set
+ //
+ for (Index = 0; Index < 20; Index++) {
+ if (PrivateData->Configuration.WhatIsThePassword2[Index] != 0) {
+ OldPassword = TRUE;
+ break;
+ }
+ }
+ if (!OldPassword) {
+ //
+ // Old password not exist, return EFI_SUCCESS to prompt for new password
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Get user input password
+ //
+ BufferSize = 21 * sizeof (CHAR16);
+ Password = AllocateZeroPool (BufferSize);
+ ASSERT (Password != NULL);
+
+ Status = IfrLibGetString (PrivateData->HiiHandle[0], StringId, Password, &BufferSize);
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (Password);
+ return Status;
+ }
+
+ //
+ // Validate old password
+ //
+ EncodedPassword = AllocateCopyPool (21 * sizeof (CHAR16), Password);
+ ASSERT (EncodedPassword != NULL);
+ EncodePassword (EncodedPassword, 20 * sizeof (CHAR16));
+ if (CompareMem (EncodedPassword, PrivateData->Configuration.WhatIsThePassword2, 20 * sizeof (CHAR16)) != 0) {
+ //
+ // Old password mismatch, return EFI_NOT_READY to prompt for error message
+ //
+ Status = EFI_NOT_READY;
+ } else {
+ Status = EFI_SUCCESS;
+ }
+
+ gBS->FreePool (Password);
+ gBS->FreePool (EncodedPassword);
+
+ return Status;
+}
+
+EFI_STATUS
+SetPassword (
+ DRIVER_SAMPLE_PRIVATE_DATA *PrivateData,
+ EFI_STRING_ID StringId
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ CHAR16 *Password;
+ DRIVER_SAMPLE_CONFIGURATION *Configuration;
+
+ //
+ // Get Buffer Storage data from EFI variable
+ //
+ BufferSize = sizeof (DRIVER_SAMPLE_CONFIGURATION);
+ Status = gRT->GetVariable (
+ VariableName,
+ &mFormSetGuid,
+ NULL,
+ &BufferSize,
+ &PrivateData->Configuration
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get user input password
+ //
+ Password = &PrivateData->Configuration.WhatIsThePassword2[0];
+ ZeroMem (Password, 20 * sizeof (CHAR16));
+ Status = IfrLibGetString (PrivateData->HiiHandle[0], StringId, Password, &BufferSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Retrive uncommitted data from Browser
+ //
+ BufferSize = sizeof (DRIVER_SAMPLE_CONFIGURATION);
+ Configuration = AllocateZeroPool (sizeof (DRIVER_SAMPLE_PRIVATE_DATA));
+ ASSERT (Configuration != NULL);
+ Status = GetBrowserData (&mFormSetGuid, VariableName, &BufferSize, (UINT8 *) Configuration);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Update password's clear text in the screen
+ //
+ CopyMem (Configuration->PasswordClearText, Password, 20 * sizeof (CHAR16));
+
+ //
+ // Update uncommitted data of Browser
+ //
+ BufferSize = sizeof (DRIVER_SAMPLE_CONFIGURATION);
+ Status = SetBrowserData (
+ &mFormSetGuid,
+ VariableName,
+ BufferSize,
+ (UINT8 *) Configuration,
+ NULL
+ );
+ }
+ gBS->FreePool (Configuration);
+
+ //
+ // Set password
+ //
+ EncodePassword (Password, 20 * sizeof (CHAR16));
+ Status = gRT->SetVariable(
+ VariableName,
+ &mFormSetGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (DRIVER_SAMPLE_CONFIGURATION),
+ &PrivateData->Configuration
+ );
+ return Status;
+}
+
+
+/**
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Request A null-terminated Unicode string in
+ <ConfigRequest> format.
+ @param Progress On return, points to a character in the Request
+ string. Points to the string's null terminator if
+ request was successful. Points to the most recent
+ '&' before the first failing name/value pair (or
+ the beginning of the string if the failure is in
+ the first name/value pair) if the request was not
+ successful.
+ @param Results A null-terminated Unicode string in
+ <ConfigAltResp> format which has all values filled
+ in for the names in the Request string. String to
+ be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is NULL, illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+ExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ DRIVER_SAMPLE_PRIVATE_DATA *PrivateData;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+
+ PrivateData = DRIVER_SAMPLE_PRIVATE_FROM_THIS (This);
+ HiiConfigRouting = PrivateData->HiiConfigRouting;
+
+ //
+ // Get Buffer Storage data from EFI variable
+ //
+ BufferSize = sizeof (DRIVER_SAMPLE_CONFIGURATION);
+ Status = gRT->GetVariable (
+ VariableName,
+ &mFormSetGuid,
+ NULL,
+ &BufferSize,
+ &PrivateData->Configuration
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
+ //
+ Status = HiiConfigRouting->BlockToConfig (
+ HiiConfigRouting,
+ Request,
+ (UINT8 *) &PrivateData->Configuration,
+ BufferSize,
+ Results,
+ Progress
+ );
+ return Status;
+}
+
+
+/**
+ This function processes the results of changes in configuration.
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Configuration A null-terminated Unicode string in <ConfigResp>
+ format.
+ @param Progress A pointer to a string filled in with the offset of
+ the most recent '&' before the first failing
+ name/value pair (or the beginning of the string if
+ the failure is in the first name/value pair) or
+ the terminating NULL if all was successful.
+
+ @retval EFI_SUCCESS The Results is processed successfully.
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+RouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ DRIVER_SAMPLE_PRIVATE_DATA *PrivateData;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+
+ PrivateData = DRIVER_SAMPLE_PRIVATE_FROM_THIS (This);
+ HiiConfigRouting = PrivateData->HiiConfigRouting;
+
+ //
+ // Get Buffer Storage data from EFI variable
+ //
+ BufferSize = sizeof (DRIVER_SAMPLE_CONFIGURATION);
+ Status = gRT->GetVariable (
+ VariableName,
+ &mFormSetGuid,
+ NULL,
+ &BufferSize,
+ &PrivateData->Configuration
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Convert <ConfigResp> to buffer data by helper function ConfigToBlock()
+ //
+ BufferSize = sizeof (DRIVER_SAMPLE_CONFIGURATION);
+ Status = HiiConfigRouting->ConfigToBlock (
+ HiiConfigRouting,
+ Configuration,
+ (UINT8 *) &PrivateData->Configuration,
+ &BufferSize,
+ Progress
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Store Buffer Storage back to EFI variable
+ //
+ Status = gRT->SetVariable(
+ VariableName,
+ &mFormSetGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (DRIVER_SAMPLE_CONFIGURATION),
+ &PrivateData->Configuration
+ );
+
+ return Status;
+}
+
+
+/**
+ This function processes the results of changes in configuration.
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Action Specifies the type of action taken by the browser.
+ @param QuestionId A unique value which is sent to the original
+ exporting driver so that it can identify the type
+ of data to expect.
+ @param Type The type of value for the question.
+ @param Value A pointer to the data being sent to the original
+ exporting driver.
+ @param ActionRequest On return, points to the action requested by the
+ callback function.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @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 saved.
+ @retval EFI_UNSUPPORTED The specified Action is not supported by the
+ callback.
+
+**/
+EFI_STATUS
+EFIAPI
+DriverCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+{
+ DRIVER_SAMPLE_PRIVATE_DATA *PrivateData;
+ EFI_STATUS Status;
+ EFI_HII_UPDATE_DATA UpdateData;
+ IFR_OPTION *IfrOptionList;
+
+ if ((Value == NULL) || (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ PrivateData = DRIVER_SAMPLE_PRIVATE_FROM_THIS (This);
+
+ switch (QuestionId) {
+ case 0x1234:
+ //
+ // Create dynamic page for this interactive goto
+ //
+ UpdateData.BufferSize = 0x1000;
+ UpdateData.Offset = 0;
+ UpdateData.Data = AllocatePool (0x1000);
+ ASSERT (UpdateData.Data != NULL);
+
+ IfrOptionList = AllocatePool (2 * sizeof (IFR_OPTION));
+ ASSERT (IfrOptionList != NULL);
+
+ IfrOptionList[0].Flags = 0;
+ IfrOptionList[0].StringToken = STRING_TOKEN (STR_BOOT_OPTION1);
+ IfrOptionList[0].Value.u8 = 1;
+ IfrOptionList[1].Flags = EFI_IFR_OPTION_DEFAULT;
+ IfrOptionList[1].StringToken = STRING_TOKEN (STR_BOOT_OPTION2);
+ IfrOptionList[1].Value.u8 = 2;
+
+ CreateActionOpCode (
+ 0x1237,
+ STRING_TOKEN(STR_EXIT_TEXT),
+ STRING_TOKEN(STR_EXIT_TEXT),
+ EFI_IFR_FLAG_CALLBACK,
+ 0,
+ &UpdateData
+ );
+
+ CreateOneOfOpCode (
+ 0x8001,
+ 0,
+ 0,
+ STRING_TOKEN (STR_ONE_OF_PROMPT),
+ STRING_TOKEN (STR_ONE_OF_HELP),
+ EFI_IFR_FLAG_CALLBACK,
+ EFI_IFR_NUMERIC_SIZE_1,
+ IfrOptionList,
+ 2,
+ &UpdateData
+ );
+
+ CreateOrderedListOpCode (
+ 0x8002,
+ 0,
+ 0,
+ STRING_TOKEN (STR_BOOT_OPTIONS),
+ STRING_TOKEN (STR_BOOT_OPTIONS),
+ EFI_IFR_FLAG_RESET_REQUIRED,
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ 10,
+ IfrOptionList,
+ 2,
+ &UpdateData
+ );
+
+ CreateGotoOpCode (
+ 1,
+ STRING_TOKEN (STR_GOTO_FORM1),
+ STRING_TOKEN (STR_GOTO_HELP),
+ 0,
+ 0x8003,
+ &UpdateData
+ );
+
+ Status = IfrLibUpdateForm (
+ PrivateData->HiiHandle[0],
+ &mFormSetGuid,
+ 0x1234,
+ 0x1234,
+ TRUE,
+ &UpdateData
+ );
+ gBS->FreePool (IfrOptionList);
+ gBS->FreePool (UpdateData.Data);
+ break;
+
+ case 0x1237:
+ //
+ // User press "Exit now", request Browser to exit
+ //
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ break;
+
+ case 0x1238:
+ //
+ // User press "Save now", request Browser to save the uncommitted data.
+ //
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;
+ break;
+
+ case 0x2000:
+ //
+ // When try to set a new password, user will be chanlleged with old password.
+ // The Callback is responsible for validating old password input by user,
+ // If Callback return EFI_SUCCESS, it indicates validation pass.
+ //
+ switch (PrivateData->PasswordState) {
+ case BROWSER_STATE_VALIDATE_PASSWORD:
+ Status = ValidatePassword (PrivateData, Value->string);
+ if (Status == EFI_SUCCESS) {
+ PrivateData->PasswordState = BROWSER_STATE_SET_PASSWORD;
+ }
+ break;
+
+ case BROWSER_STATE_SET_PASSWORD:
+ Status = SetPassword (PrivateData, Value->string);
+ PrivateData->PasswordState = BROWSER_STATE_VALIDATE_PASSWORD;
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+DriverSampleInit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS SavedStatus;
+ EFI_HII_PACKAGE_LIST_HEADER *PackageList;
+ EFI_HII_HANDLE HiiHandle[2];
+ EFI_HANDLE DriverHandle[2];
+ DRIVER_SAMPLE_PRIVATE_DATA *PrivateData;
+ EFI_SCREEN_DESCRIPTOR Screen;
+ EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
+ EFI_HII_STRING_PROTOCOL *HiiString;
+ EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+ CHAR16 *NewString;
+ UINTN BufferSize;
+ DRIVER_SAMPLE_CONFIGURATION *Configuration;
+ BOOLEAN ExtractIfrDefault;
+
+ //
+ // Initialize the library and our protocol.
+ //
+ //@MT: EfiInitializeDriverLib (ImageHandle, SystemTable);
+
+ //
+ // Initialize screen dimensions for SendForm().
+ // Remove 3 characters from top and bottom
+ //
+ ZeroMem (&Screen, sizeof (EFI_SCREEN_DESCRIPTOR));
+ gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &Screen.RightColumn, &Screen.BottomRow);
+
+ Screen.TopRow = 3;
+ Screen.BottomRow = Screen.BottomRow - 3;
+
+ //
+ // Initialize driver private data
+ //
+ PrivateData = AllocatePool (sizeof (DRIVER_SAMPLE_PRIVATE_DATA));
+ if (PrivateData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PrivateData->Signature = DRIVER_SAMPLE_PRIVATE_SIGNATURE;
+
+ PrivateData->ConfigAccess.ExtractConfig = ExtractConfig;
+ PrivateData->ConfigAccess.RouteConfig = RouteConfig;
+ PrivateData->ConfigAccess.Callback = DriverCallback;
+ PrivateData->PasswordState = BROWSER_STATE_VALIDATE_PASSWORD;
+
+ //
+ // Locate Hii Database protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **) &HiiDatabase);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ PrivateData->HiiDatabase = HiiDatabase;
+
+ //
+ // Locate HiiString protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiHiiStringProtocolGuid, NULL, (VOID **) &HiiString);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ PrivateData->HiiString = HiiString;
+
+ //
+ // Locate Formbrowser2 protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ PrivateData->FormBrowser2 = FormBrowser2;
+
+ //
+ // Locate ConfigRouting protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ PrivateData->HiiConfigRouting = HiiConfigRouting;
+
+ //
+ // Install Config Access protocol
+ //
+ Status = HiiLibCreateHiiDriverHandle (&DriverHandle[0]);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ PrivateData->DriverHandle[0] = DriverHandle[0];
+
+ Status = gBS->InstallProtocolInterface (
+ &DriverHandle[0],
+ &gEfiHiiConfigAccessProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &PrivateData->ConfigAccess
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Publish our HII data
+ //
+ PackageList = PreparePackageList (
+ 2,
+ &mFormSetGuid,
+ DriverSampleStrings,
+ VfrBin
+ );
+ if (PackageList == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = HiiDatabase->NewPackageList (
+ HiiDatabase,
+ PackageList,
+ DriverHandle[0],
+ &HiiHandle[0]
+ );
+ gBS->FreePool (PackageList);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ PrivateData->HiiHandle[0] = HiiHandle[0];
+
+ //
+ // Publish another Fromset
+ //
+ Status = HiiLibCreateHiiDriverHandle (&DriverHandle[1]);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ PrivateData->DriverHandle[1] = DriverHandle[1];
+
+ PackageList = PreparePackageList (
+ 2,
+ &mInventoryGuid,
+ DriverSampleStrings,
+ InventoryBin
+ );
+ if (PackageList == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = HiiDatabase->NewPackageList (
+ HiiDatabase,
+ PackageList,
+ DriverHandle[1],
+ &HiiHandle[1]
+ );
+ gBS->FreePool (PackageList);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ PrivateData->HiiHandle[1] = HiiHandle[1];
+
+ //
+ // Very simple example of how one would update a string that is already
+ // in the HII database
+ //
+ NewString = L"700 Mhz";
+
+ Status = IfrLibSetString (HiiHandle[0], STRING_TOKEN (STR_CPU_STRING2), NewString);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Initialize configuration data
+ //
+ Configuration = &PrivateData->Configuration;
+ ZeroMem (Configuration, sizeof (DRIVER_SAMPLE_CONFIGURATION));
+
+ //
+ // Try to read NV config EFI variable first
+ //
+ ExtractIfrDefault = TRUE;
+ BufferSize = sizeof (DRIVER_SAMPLE_CONFIGURATION);
+ Status = gRT->GetVariable (VariableName, &mFormSetGuid, NULL, &BufferSize, Configuration);
+ if (!EFI_ERROR (Status) && (BufferSize == sizeof (DRIVER_SAMPLE_CONFIGURATION))) {
+ ExtractIfrDefault = FALSE;
+ }
+
+ if (ExtractIfrDefault) {
+ //
+ // EFI variable for NV config doesn't exit, we should build this variable
+ // based on default values stored in IFR
+ //
+ BufferSize = sizeof (DRIVER_SAMPLE_CONFIGURATION);
+ Status = ExtractDefault (Configuration, &BufferSize, 1, VfrMyIfrNVDataDefault0000);
+
+ if (!EFI_ERROR (Status)) {
+ gRT->SetVariable(
+ VariableName,
+ &mFormSetGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (DRIVER_SAMPLE_CONFIGURATION),
+ Configuration
+ );
+ }
+ }
+
+ //
+ // Example of how to display only the item we sent to HII
+ //
+ if (DISPLAY_ONLY_MY_ITEM == 0x0001) {
+ //
+ // Have the browser pull out our copy of the data, and only display our data
+ //
+ // Status = FormConfig->SendForm (FormConfig, TRUE, HiiHandle, NULL, NULL, NULL, &Screen, NULL);
+ //
+ Status = FormBrowser2->SendForm (
+ FormBrowser2,
+ HiiHandle,
+ 1,
+ NULL,
+ 0,
+ NULL,
+ NULL
+ );
+ SavedStatus = Status;
+
+ Status = HiiDatabase->RemovePackageList (HiiDatabase, HiiHandle[0]);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = HiiDatabase->RemovePackageList (HiiDatabase, HiiHandle[1]);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return SavedStatus;
+ } else {
+ //
+ // Have the browser pull out all the data in the HII Database and display it.
+ //
+ // Status = FormConfig->SendForm (FormConfig, TRUE, 0, NULL, NULL, NULL, NULL, NULL);
+ //
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Universal/DriverSampleDxe/DriverSample.h b/MdeModulePkg/Universal/DriverSampleDxe/DriverSample.h new file mode 100644 index 0000000000..9f19258a22 --- /dev/null +++ b/MdeModulePkg/Universal/DriverSampleDxe/DriverSample.h @@ -0,0 +1,97 @@ +/** @file + +Copyright (c) 2007, Intel Corporation +All rights reserved. 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. + +Module Name: + + DriverSample.h + +Abstract: + + +Revision History + + +**/ + +#ifndef _DRIVER_SAMPLE_H +#define _DRIVER_SAMPLE_H + +#include <PiDxe.h> + +#include <Protocol/HiiConfigRouting.h> +#include <Protocol/FormBrowser2.h> +#include <Protocol/HiiConfigAccess.h> +#include <Protocol/HiiDatabase.h> +#include <Protocol/HiiString.h> + +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/UefiRuntimeServicesTableLib.h> +#include <Library/UefiDriverEntryPoint.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/IfrSupportLib.h> +#include <Library/HiiLib.h> + +#include <MdeModuleHii.h> + + +#include "NVDataStruc.h" + +// +// This is the generated <AltResp> for defaults defined in VFR +// +extern UINT8 VfrMyIfrNVDataDefault0000[]; + +// +// This is the generated IFR binary data for each formset defined in VFR. +// This data array is ready to be used as input of PreparePackageList() to +// create a packagelist (which contains Form packages, String packages, etc). +// +extern UINT8 VfrBin[]; +extern UINT8 InventoryBin[]; + +// +// This is the generated String package data for all .UNI files. +// This data array is ready to be used as input of PreparePackageList() to +// create a packagelist (which contains Form packages, String packages, etc). +// +extern UINT8 DriverSampleStrings[]; + +#define SAMPLE_STRING L"This is an error!" + +#define DRIVER_SAMPLE_PRIVATE_SIGNATURE EFI_SIGNATURE_32 ('D', 'S', 'p', 's') + +typedef struct { + UINTN Signature; + + EFI_HANDLE DriverHandle[2]; + EFI_HII_HANDLE HiiHandle[2]; + DRIVER_SAMPLE_CONFIGURATION Configuration; + UINT8 PasswordState; + + // + // Consumed protocol + // + EFI_HII_DATABASE_PROTOCOL *HiiDatabase; + EFI_HII_STRING_PROTOCOL *HiiString; + EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting; + EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2; + + // + // Produced protocol + // + EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess; +} DRIVER_SAMPLE_PRIVATE_DATA; + +#define DRIVER_SAMPLE_PRIVATE_FROM_THIS(a) CR (a, DRIVER_SAMPLE_PRIVATE_DATA, ConfigAccess, DRIVER_SAMPLE_PRIVATE_SIGNATURE) + +#endif diff --git a/MdeModulePkg/Universal/DriverSampleDxe/DriverSampleDxe.inf b/MdeModulePkg/Universal/DriverSampleDxe/DriverSampleDxe.inf new file mode 100644 index 0000000000..42a331779e --- /dev/null +++ b/MdeModulePkg/Universal/DriverSampleDxe/DriverSampleDxe.inf @@ -0,0 +1,72 @@ +#/** @file
+# Component name for module DriverSample
+#
+# FIX ME!
+# Copyright (c) 2007, Intel Corporation. All rights reserved.
+#
+# All rights reserved. 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 = 0x00010005
+ BASE_NAME = DriverSample
+ FILE_GUID = FE3542FE-C1D3-4EF8-657C-8048606FF671
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ EDK_RELEASE_VERSION = 0x00020000
+ EFI_SPECIFICATION_VERSION = 0x0002000A
+
+ ENTRY_POINT = DriverSampleInit
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+ DriverSample.c
+ inventorystrings.uni
+ NVDataStruc.h
+ VfrStrings.uni
+ DriverSample.h
+ Inventory.vfr
+ Vfr.vfr
+ VfrStrings.uni
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiRuntimeServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ HiiLib
+ IfrSupportLib
+ BaseLib
+
+
+[Protocols]
+ gEfiHiiStringProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiHiiConfigRoutingProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiHiiConfigAccessProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiFormBrowser2ProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiHiiDatabaseProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+
+
+[Depex]
+ gEfiSimpleTextOutProtocolGuid AND gEfiHiiDatabaseProtocolGuid
+
diff --git a/MdeModulePkg/Universal/DriverSampleDxe/DriverSampleDxe.msa b/MdeModulePkg/Universal/DriverSampleDxe/DriverSampleDxe.msa new file mode 100644 index 0000000000..87bd7d8d71 --- /dev/null +++ b/MdeModulePkg/Universal/DriverSampleDxe/DriverSampleDxe.msa @@ -0,0 +1,80 @@ +<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <MsaHeader>
+ <ModuleName>DriverSample</ModuleName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <GuidValue>FE3542FE-C1D3-4EF8-657C-8048606FF671</GuidValue>
+ <Version>1.0</Version>
+ <Abstract>Component name for module DriverSample</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2007, Intel Corporation. All rights reserved.</Copyright>
+ <License>All rights reserved. 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.</License>
+ <Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
+ </MsaHeader>
+ <ModuleDefinitions>
+ <SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>
+ <BinaryModule>false</BinaryModule>
+ <OutputFileBasename>DriverSample</OutputFileBasename>
+ </ModuleDefinitions>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>DebugLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>BaseMemoryLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiRuntimeServicesTableLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiDriverEntryPoint</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiBootServicesTableLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>MemoryAllocationLib</Keyword>
+ </LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>DriverSample.h</Filename>
+ <Filename>VfrStrings.uni</Filename>
+ <Filename>NVDataStruc.h</Filename>
+ <Filename>inventorystrings.uni</Filename>
+ <Filename>DriverSample.c</Filename>
+ <Filename>DriverSample.dxs</Filename>
+ </SourceFiles>
+ <PackageDependencies>
+ <Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>
+ <Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>
+ </PackageDependencies>
+ <Protocols>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiHiiDatabaseProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiFormBrowser2ProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiHiiConfigAccessProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiHiiConfigRoutingProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiHiiStringProtocolGuid</ProtocolCName>
+ </Protocol>
+ </Protocols>
+ <Externs>
+ <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
+ <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
+ <Extern>
+ <ModuleEntryPoint>DriverSampleInit</ModuleEntryPoint>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
\ No newline at end of file diff --git a/MdeModulePkg/Universal/DriverSampleDxe/NVDataStruc.h b/MdeModulePkg/Universal/DriverSampleDxe/NVDataStruc.h new file mode 100644 index 0000000000..0ed3c8da71 --- /dev/null +++ b/MdeModulePkg/Universal/DriverSampleDxe/NVDataStruc.h @@ -0,0 +1,64 @@ +/** @file + +Copyright (c) 2007, Intel Corporation +All rights reserved. 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. + +Module Name: + + NVDataStruc.h + +Abstract: + + NVData structure used by the sample driver + +Revision History: + + +**/ + +#ifndef _NVDATASTRUC_H +#define _NVDATASTRUC_H + +#define FORMSET_GUID \ + { \ + 0xA04A27f4, 0xDF00, 0x4D42, 0xB5, 0x52, 0x39, 0x51, 0x13, 0x02, 0x11, 0x3D \ + } + +#define INVENTORY_GUID \ + { \ + 0xb3f56470, 0x6141, 0x4621, 0x8f, 0x19, 0x70, 0x4e, 0x57, 0x7a, 0xa9, 0xe8 \ + } + +#define VAR_EQ_TEST_NAME 0x100 + +#pragma pack(1) +typedef struct { + UINT16 WhatIsThePassword[20]; + UINT16 WhatIsThePassword2[20]; + UINT16 MyStringData[20]; + UINT16 PasswordClearText[20]; + UINT16 SomethingHiddenForHtml; + UINT8 HowOldAreYouInYearsManual; + UINT16 HowTallAreYouManual; + UINT8 HowOldAreYouInYears; + UINT16 HowTallAreYou; + UINT8 MyFavoriteNumber; + UINT8 TestLateCheck; + UINT8 TestLateCheck2; + UINT8 QuestionAboutTreeHugging; + UINT8 ChooseToActivateNuclearWeaponry; + UINT8 SuppressGrayOutSomething; + UINT8 OrderedList[8]; + UINT8 BootOrder[8]; + UINT8 BootOrderLarge; + UINT8 DynamicCheck; +} DRIVER_SAMPLE_CONFIGURATION; +#pragma pack() + +#endif diff --git a/MdeModulePkg/Universal/DriverSampleDxe/Vfr.vfr b/MdeModulePkg/Universal/DriverSampleDxe/Vfr.vfr new file mode 100644 index 0000000000..e88d708b2a --- /dev/null +++ b/MdeModulePkg/Universal/DriverSampleDxe/Vfr.vfr @@ -0,0 +1,504 @@ +// *++
+//
+// Copyright (c) 2007, Intel Corporation
+// All rights reserved. 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.
+//
+// Module Name:
+//
+// Vfr.vfr
+//
+// Abstract:
+//
+// Sample Setup formset
+//
+// Revision History:
+//
+// --*/
+
+
+#include "NVDataStruc.h"
+
+//
+// Formset class used by Device Manager
+//
+#define EFI_NON_DEVICE_CLASS 0x00
+#define EFI_DISK_DEVICE_CLASS 0x01
+#define EFI_VIDEO_DEVICE_CLASS 0x02
+#define EFI_NETWORK_DEVICE_CLASS 0x04
+#define EFI_INPUT_DEVICE_CLASS 0x08
+#define EFI_ON_BOARD_DEVICE_CLASS 0x10
+#define EFI_OTHER_DEVICE_CLASS 0x20
+
+//
+// Formset subclass
+//
+#define EFI_SETUP_APPLICATION_SUBCLASS 0x00
+#define EFI_GENERAL_APPLICATION_SUBCLASS 0x01
+#define EFI_FRONT_PAGE_SUBCLASS 0x02
+#define EFI_SINGLE_USE_SUBCLASS 0x03
+
+//
+// EFI Variable attributes
+//
+#define EFI_VARIABLE_NON_VOLATILE 0x00000001
+#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002
+#define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004
+#define EFI_VARIABLE_READ_ONLY 0x00000008
+
+//
+// NV data structure definition
+//
+typedef struct {
+ UINT8 Field8;
+ UINT16 Field16;
+ UINT8 OrderedList[3];
+} MY_DATA2;
+
+//
+// Labels definition
+//
+#define LABEL_1_VALUE 0x01
+#define LABEL_2_VALUE 0x1000
+#define LABEL_UPDATE_BBS 0x2222
+#define LABEL_END 0x2223
+
+formset
+ guid = FORMSET_GUID,
+ title = STRING_TOKEN(STR_FORM_SET_TITLE),
+ help = STRING_TOKEN(STR_FORM_SET_TITLE_HELP),
+ class = EFI_ON_BOARD_DEVICE_CLASS,
+ subclass = EFI_SETUP_APPLICATION_SUBCLASS,
+
+ //
+ // Define a Buffer Storage (EFI_IFR_VARSTORE)
+ //
+ varstore DRIVER_SAMPLE_CONFIGURATION, // This is the data structure type
+ varid = 0x1234, // Optional VarStore ID
+ name = MyIfrNVData, // Define referenced name in vfr
+ guid = FORMSET_GUID; // GUID of this buffer storage
+
+ //
+ // Define another Buffer Storage
+ //
+ varstore MY_DATA2,
+ name = MyIfrNVData2,
+ guid = FORMSET_GUID;
+
+ //
+ // Define a EFI variable Storage (EFI_IFR_VARSTORE_EFI)
+ //
+ efivarstore MyEfiVar, // Define referenced name in vfr
+ attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS, // EFI variable attribures
+ name = STRING_TOKEN(STR_VAR_NAME), // EFI variable name
+ varsize = 1, // Size of the EFI variable
+ guid = FORMSET_GUID; // EFI variable GUID
+
+ //
+ // Define a Form (EFI_IFR_FORM)
+ //
+ form formid = 1, // Form ID
+ title = STRING_TOKEN(STR_FORM1_TITLE); // Form title
+
+ subtitle text = STRING_TOKEN(STR_SUBTITLE_TEXT);
+
+ subtitle text = STRING_TOKEN(STR_SUBTITLE_TEXT2);
+
+ //
+ // Define a display only text (EFI_IFR_TEXT)
+ //
+ text
+ help = STRING_TOKEN(STR_TEXT_HELP), // Help string
+ text = STRING_TOKEN(STR_CPU_STRING), // Prompt string
+ text = STRING_TOKEN(STR_CPU_STRING2); // TextTwo
+
+ text
+ help = STRING_TOKEN(STR_EXIT_TEXT),
+ text = STRING_TOKEN(STR_EXIT_TEXT),
+ text = STRING_TOKEN(STR_EXIT_TEXT),
+ flags = INTERACTIVE,
+ key = 0x1237;
+
+ text
+ help = STRING_TOKEN(STR_SAVE_TEXT),
+ text = STRING_TOKEN(STR_SAVE_TEXT),
+ text = STRING_TOKEN(STR_SAVE_TEXT),
+ flags = INTERACTIVE,
+ key = 0x1238;
+
+ //
+ // Define oneof (EFI_IFR_ONE_OF)
+ //
+ oneof varid = MyIfrNVData.SuppressGrayOutSomething, // Use "DataStructure.Member" to reference Buffer Storage
+ prompt = STRING_TOKEN(STR_ONE_OF_PROMPT),
+ help = STRING_TOKEN(STR_ONE_OF_HELP),
+ //
+ // Define an option (EFI_IFR_ONE_OF_OPTION)
+ //
+ option text = STRING_TOKEN(STR_ONE_OF_TEXT4), value = 0x0, flags = 0;
+ option text = STRING_TOKEN(STR_ONE_OF_TEXT5), value = 0x1, flags = 0;
+ //
+ // DEFAULT indicate this option will be marked with EFI_IFR_OPTION_DEFAULT
+ //
+ option text = STRING_TOKEN(STR_ONE_OF_TEXT6), value = 0x2, flags = DEFAULT;
+ endoneof;
+
+ oneof varid = MyIfrNVData.BootOrderLarge,
+ prompt = STRING_TOKEN(STR_ONE_OF_PROMPT),
+ help = STRING_TOKEN(STR_ONE_OF_HELP),
+ option text = STRING_TOKEN(STR_BOOT_ORDER1), value = 0x0, flags = 0;
+ option text = STRING_TOKEN(STR_BOOT_ORDER2), value = 0x1, flags = DEFAULT;
+ endoneof;
+
+ grayoutif ideqval MyIfrNVData.SuppressGrayOutSomething == 0x1;
+ suppressif ideqval MyIfrNVData.SuppressGrayOutSomething == 0x0;
+
+ checkbox varid = MyIfrNVData.ChooseToActivateNuclearWeaponry,
+ prompt = STRING_TOKEN(STR_CHECK_BOX_PROMPT),
+ help = STRING_TOKEN(STR_CHECK_BOX_HELP),
+ //
+ // CHECKBOX_DEFAULT indicate this checkbox is marked with EFI_IFR_CHECKBOX_DEFAULT
+ //
+ flags = CHECKBOX_DEFAULT,
+ key = 0,
+
+ endcheckbox;
+ endif;
+ endif;
+
+ //
+ // Ordered list:
+ // sizeof(MyIfrNVData) storage must be UINT8 array, and
+ // size written for the variable must be size of the entire
+ // variable.
+ //
+ //
+ suppressif ideqval MyIfrNVData.SuppressGrayOutSomething == 0x0;
+
+ //
+ // label is defined as an anchor where you want to insert some dynamic
+ // opcodes created on-the-fly
+ //
+ label LABEL_UPDATE_BBS;
+
+ orderedlist
+ varid = MyIfrNVData.BootOrder,
+ prompt = STRING_TOKEN(STR_BOOT_OPTIONS),
+ help = STRING_TOKEN(STR_NULL_STRING),
+ option text = STRING_TOKEN(STR_BOOT_OPTION2), value = 2, flags = RESET_REQUIRED;
+ option text = STRING_TOKEN(STR_BOOT_OPTION1), value = 1, flags = RESET_REQUIRED;
+ option text = STRING_TOKEN(STR_BOOT_OPTION3), value = 3, flags = RESET_REQUIRED;
+ suppressif ideqval MyIfrNVData.BootOrderLarge == 0;
+ option text = STRING_TOKEN(STR_BOOT_OPTION4), value = 4, flags = 0;
+ endif
+ endlist;
+
+ //
+ // label should be paired with each other
+ //
+ label LABEL_END;
+
+ endif; // end suppressif
+
+ suppressif ideqval MyIfrNVData.SuppressGrayOutSomething == 0x2;
+ orderedlist
+ varid = MyIfrNVData.OrderedList,
+ prompt = STRING_TOKEN(STR_TEST_OPCODE),
+ help = STRING_TOKEN(STR_TEXT_HELP),
+ option text = STRING_TOKEN(STR_ONE_OF_TEXT1), value = 3, flags = RESET_REQUIRED;
+ option text = STRING_TOKEN(STR_ONE_OF_TEXT2), value = 2, flags = RESET_REQUIRED;
+ option text = STRING_TOKEN(STR_ONE_OF_TEXT3), value = 1, flags = RESET_REQUIRED;
+ endlist;
+ endif;
+
+ label 100;
+
+ //
+ // Define a hyperlink (EFI_IFR_REF)
+ //
+ goto 0x1234, // Destination Form ID
+ prompt = STRING_TOKEN(STR_GOTO_DYNAMIC), // Prompt string
+ help = STRING_TOKEN(STR_GOTO_HELP), // Help string
+ flags = INTERACTIVE, // INTERACTIVE indicate it's marked with EFI_IFR_FLAG_CALLBACK
+ key = 0x1234; // Question ID which will be passed-in in COnfigAccess.Callback()
+
+ goto 0x1234,
+ prompt = STRING_TOKEN(STR_GOTO_DYNAMIC2),
+ help = STRING_TOKEN(STR_GOTO_HELP),
+ flags = INTERACTIVE,
+ key = 0x1235;
+
+ oneof varid = MyIfrNVData.TestLateCheck,
+ prompt = STRING_TOKEN(STR_TEST_OPCODE),
+ help = STRING_TOKEN(STR_ONE_OF_HELP),
+ option text = STRING_TOKEN(STR_ONE_OF_TEXT1), value = 0, flags = RESET_REQUIRED;
+ option text = STRING_TOKEN(STR_ONE_OF_TEXT2), value = 1, flags = DEFAULT | RESET_REQUIRED;
+
+ endoneof;
+
+ oneof varid = MyIfrNVData.TestLateCheck2,
+ prompt = STRING_TOKEN(STR_TEST_OPCODE2),
+ help = STRING_TOKEN(STR_ONE_OF_HELP),
+ option text = STRING_TOKEN(STR_ONE_OF_TEXT1), value = 0, flags = DEFAULT | RESET_REQUIRED;
+ option text = STRING_TOKEN(STR_ONE_OF_TEXT2), value = 1, flags = RESET_REQUIRED;
+
+ inconsistentif prompt = STRING_TOKEN(STR_ERROR_POPUP),
+ ideqid MyIfrNVData.TestLateCheck == MyIfrNVData.TestLateCheck2
+ endif
+
+ endoneof;
+
+ oneof varid = MyIfrNVData.QuestionAboutTreeHugging,
+ prompt = STRING_TOKEN(STR_ONE_OF_PROMPT),
+ help = STRING_TOKEN(STR_ONE_OF_HELP),
+ option text = STRING_TOKEN(STR_ONE_OF_TEXT1), value = 0, flags = RESET_REQUIRED;
+ option text = STRING_TOKEN(STR_ONE_OF_TEXT2), value = 1, flags = DEFAULT | RESET_REQUIRED;
+ option text = STRING_TOKEN(STR_ONE_OF_TEXT3), value = 0x03, flags = RESET_REQUIRED;
+
+ endoneof;
+
+ //
+ // Define a string (EFI_IFR_STRING)
+ //
+ string varid = MyIfrNVData.MyStringData,
+ prompt = STRING_TOKEN(STR_MY_STRING_PROMPT2),
+ help = STRING_TOKEN(STR_MY_STRING_HELP2),
+ flags = INTERACTIVE,
+ key = 0x1236,
+ minsize = 6,
+ maxsize = 20,
+ endstring;
+
+ //
+ // Define a numeric (EFI_IFR_NUMERIC)
+ //
+ numeric varid = MyIfrNVData.HowOldAreYouInYearsManual,
+ prompt = STRING_TOKEN(STR_NUMERIC_READONLY_PROMPT),
+ help = STRING_TOKEN(STR_NUMERIC_HELP0),
+ flags = READ_ONLY, // READ_ONLY indicate it's marked with EFI_IFR_FLAG_READ_ONLY
+ minimum = 0,
+ maximum = 0xf0,
+ step = 0, // Stepping of 0 equates to a manual entering
+ // of a value, otherwise it will be adjusted by "+"/"-"
+ default = 20,
+
+ endnumeric;
+
+ numeric varid = MyIfrNVData.HowOldAreYouInYearsManual,
+ prompt = STRING_TOKEN(STR_NUMERIC_MANUAL_PROMPT),
+ help = STRING_TOKEN(STR_NUMERIC_HELP0),
+ minimum = 0,
+ maximum = 0xf0,
+ step = 0,
+ default = 21,
+
+ inconsistentif prompt = STRING_TOKEN(STR_ERROR_POPUP),
+ ideqval MyIfrNVData.HowOldAreYouInYearsManual == 99
+ OR
+ ideqid MyIfrNVData.HowOldAreYouInYearsManual == MyEfiVar
+ OR
+ ideqvallist MyIfrNVData.HowOldAreYouInYearsManual == 1 3 5 7
+ endif
+
+ endnumeric;
+
+ numeric varid = MyEfiVar, // Reference of EFI variable storage
+ prompt = STRING_TOKEN(STR_TALL_HEX_PROMPT),
+ help = STRING_TOKEN(STR_NUMERIC_HELP1),
+ flags = DISPLAY_UINT_HEX, // Display in HEX format (if not specified, default is in decimal format)
+ minimum = 0,
+ maximum = 250,
+ default = 175,
+
+ endnumeric;
+
+ label LABEL_1_VALUE;
+ label LABEL_2_VALUE;
+
+ grayoutif ideqval MyIfrNVData.HowOldAreYouInYearsManual == 23 AND ideqval MyIfrNVData.SuppressGrayOutSomething == 0x1;
+ numeric varid = MyIfrNVData.HowOldAreYouInYears,
+ prompt = STRING_TOKEN(STR_NUMERIC_STEP_PROMPT),
+ help = STRING_TOKEN(STR_NUMERIC_HELP2),
+ minimum = 0,
+ maximum = 243,
+ step = 1,
+ default = 18,
+
+ endnumeric;
+ endif;
+
+ //
+ // Non-interactive password, validate by Setup Browser
+ //
+ password varid = MyIfrNVData.WhatIsThePassword,
+ prompt = STRING_TOKEN(STR_PASSWORD_PROMPT),
+ help = STRING_TOKEN(STR_PASSWORD_HELP),
+ minsize = 6,
+ maxsize = 20, // new opcode
+ endpassword;
+
+ string varid = MyIfrNVData.PasswordClearText,
+ prompt = STRING_TOKEN(STR_MY_STRING_PROMPT),
+ help = STRING_TOKEN(STR_MY_STRING_HELP),
+ minsize = 6,
+ maxsize = 0x14,
+ endstring;
+
+ //
+ // Interactive password, validate via ConfigAccess.Callback()
+ //
+ password varid = MyIfrNVData.WhatIsThePassword2,
+ prompt = STRING_TOKEN(STR_PASSWORD_CALLBACK_PROMPT),
+ help = STRING_TOKEN(STR_PASSWORD_HELP),
+ flags = INTERACTIVE,
+ key = 0x2000,
+ minsize = 6,
+ maxsize = 20, // new opcode
+ endpassword;
+
+ goto 2,
+ prompt = STRING_TOKEN(STR_GOTO_FORM2), //SecondSetupPage // this too has no end-op and basically it's a jump to a form ONLY
+ help = STRING_TOKEN(STR_GOTO_HELP);
+
+ goto 3,
+ prompt = STRING_TOKEN(STR_GOTO_FORM3), //ThirdSetupPage // this too has no end-op and basically it's a jump to a form ONLY
+ help = STRING_TOKEN(STR_GOTO_HELP);
+
+ endform;
+
+ form formid = 2, // SecondSetupPage,
+ title = STRING_TOKEN(STR_FORM2_TITLE); // note formid is a variable (for readability) (UINT16) - also added Form to the line to signify the Op-Code
+
+
+ date year varid = Date.Year, // Note that it is a member of NULL, so the RTC will be the system resource to retrieve and save from
+ prompt = STRING_TOKEN(STR_DATE_PROMPT),
+ help = STRING_TOKEN(STR_DATE_YEAR_HELP),
+ minimum = 1998,
+ maximum = 2099,
+ step = 1,
+ default = 2004,
+
+ month varid = Date.Month, // Note that it is a member of NULL, so the RTC will be the system resource to retrieve and save from
+ prompt = STRING_TOKEN(STR_DATE_PROMPT),
+ help = STRING_TOKEN(STR_DATE_MONTH_HELP),
+ minimum = 1,
+ maximum = 12,
+ step = 1,
+ default = 1,
+
+ day varid = Date.Day, // Note that it is a member of NULL, so the RTC will be the system resource to retrieve and save from
+ prompt = STRING_TOKEN(STR_DATE_PROMPT),
+ help = STRING_TOKEN(STR_DATE_DAY_HELP),
+ minimum = 1,
+ maximum = 31,
+ step = 0x1,
+ default = 1,
+
+ inconsistentif prompt = STRING_TOKEN(STR_ERROR_POPUP),
+ ideqval Date.Day == 31
+ AND
+ ideqvallist Date.Month == 2 4 6 9 11
+ endif
+
+ //
+ // If the day is 30 AND month is 2
+ //
+ inconsistentif prompt = STRING_TOKEN(STR_ERROR_POPUP),
+ ideqval Date.Day == 30
+ AND
+ ideqval Date.Month == 2
+ endif
+
+ //
+ // If the day is 29 AND month is 2 AND it year is NOT a leapyear
+ //
+ inconsistentif prompt = STRING_TOKEN(STR_ERROR_POPUP),
+ ideqval Date.Day == 0x1D
+ AND
+ ideqval Date.Month == 2
+ AND
+ NOT
+ ideqvallist Date.Year == 2004 2008 20012 20016 2020 2024 2028 2032 2036
+ endif
+
+ enddate;
+
+ time hour varid = Time.Hours, // Note that it is a member of NULL, so the RTC will be the system resource to retrieve and save from
+ prompt = STRING_TOKEN(STR_TIME_PROMPT),
+ help = STRING_TOKEN(STR_TIME_HOUR_HELP),
+ minimum = 0,
+ maximum = 23,
+ step = 1,
+ default = 0,
+
+ minute varid = Time.Minutes, // Note that it is a member of NULL, so the RTC will be the system resource to retrieve and save from
+ prompt = STRING_TOKEN(STR_TIME_PROMPT),
+ help = STRING_TOKEN(STR_TIME_MINUTE_HELP),
+ minimum = 0,
+ maximum = 59,
+ step = 1,
+ default = 0,
+
+ second varid = Time.Seconds, // Note that it is a member of NULL, so the RTC will be the system resource to retrieve and save from
+ prompt = STRING_TOKEN(STR_TIME_PROMPT),
+ help = STRING_TOKEN(STR_TIME_SECOND_HELP),
+ minimum = 0,
+ maximum = 59,
+ step = 1,
+ default = 0,
+
+ endtime;
+
+ checkbox varid = MyIfrNVData.ChooseToActivateNuclearWeaponry,
+ prompt = STRING_TOKEN(STR_CHECK_BOX_PROMPT),
+ help = STRING_TOKEN(STR_CHECK_BOX_HELP),
+ flags = CHECKBOX_DEFAULT,
+ key = 0,
+ endcheckbox;
+
+ text
+ help = STRING_TOKEN(STR_TEXT_HELP),
+ text = STRING_TOKEN(STR_TEXT_TEXT_1);
+
+ text
+ help = STRING_TOKEN(STR_TEXT_HELP),
+ text = STRING_TOKEN(STR_TEXT_TEXT_1),
+ text = STRING_TOKEN(STR_TEXT_TEXT_2);
+
+ goto 1,
+ prompt = STRING_TOKEN(STR_GOTO_FORM1), //MainSetupPage // this too has no end-op and basically it's a jump to a form ONLY
+ help = STRING_TOKEN(STR_GOTO_HELP);
+
+ endform;
+
+ form formid = 3, title = STRING_TOKEN(STR_FORM3_TITLE); // note formid is a variable (for readability) (UINT16) - also added Form to the line to signify the Op-Code
+
+ grayoutif ideqval MyIfrNVData.SuppressGrayOutSomething == 0x1;
+ text
+ help = STRING_TOKEN(STR_TEXT_HELP),
+ text = STRING_TOKEN(STR_TEXT_TEXT_1);
+ endif;
+
+ endform;
+
+ form formid = 4, title = STRING_TOKEN(STR_FORM3_TITLE);
+
+ endform;
+
+ form formid = 0x1234, // Dynamically created page,
+ title = STRING_TOKEN(STR_DYNAMIC_TITLE); // note formid is a variable (for readability) (UINT16) - also added Form to the line to signify the Op-Code
+
+ label 0x1234;
+ //
+ // This is where we will insert dynamic created opcodes
+ //
+ label LABEL_END;
+
+ endform;
+
+endformset;
diff --git a/MdeModulePkg/Universal/DriverSampleDxe/VfrStrings.uni b/MdeModulePkg/Universal/DriverSampleDxe/VfrStrings.uni Binary files differnew file mode 100644 index 0000000000..fb72d1a2bc --- /dev/null +++ b/MdeModulePkg/Universal/DriverSampleDxe/VfrStrings.uni diff --git a/MdeModulePkg/Universal/DriverSampleDxe/inventory.vfr b/MdeModulePkg/Universal/DriverSampleDxe/inventory.vfr new file mode 100644 index 0000000000..79dcf18cbb --- /dev/null +++ b/MdeModulePkg/Universal/DriverSampleDxe/inventory.vfr @@ -0,0 +1,121 @@ +// *++
+//
+// Copyright (c) 2007, Intel Corporation
+// All rights reserved. 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.
+//
+// Module Name:
+//
+// Inventory.vfr
+//
+// Abstract:
+//
+// Sample Inventory Data.
+//
+// Revision History:
+//
+// --*/
+
+#define INVENTORY_GUID { 0xb3f56470, 0x6141, 0x4621, 0x8f, 0x19, 0x70, 0x4e, 0x57, 0x7a, 0xa9, 0xe8 }
+
+formset
+ guid = INVENTORY_GUID,
+ title = STRING_TOKEN(STR_INV_FORM_SET_TITLE),
+ help = STRING_TOKEN(STR_INV_FORM_SET_HELP),
+ class = 0x04,
+ subclass = 0x03,
+
+ form formid = 1,
+ title = STRING_TOKEN(STR_INV_FORM1_TITLE); // note formid is a variable (for readability) (UINT16) - also added Form to the line to signify the Op-Code
+
+ text
+ help = STRING_TOKEN(STR_INV_VERSION_HELP),
+ text = STRING_TOKEN(STR_INV_VERSION_TEXT),
+ text = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ flags = 0,
+ key = 0;
+
+ text
+ help = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ text = STRING_TOKEN(STR_INV_VERSION_TEXT2),
+ text = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ flags = 0,
+ key = 0;
+
+ text
+ help = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ text = STRING_TOKEN(STR_INV_VERSION_TEXT3),
+ text = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ flags = 0,
+ key = 0;
+
+ text
+ help = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ text = STRING_TOKEN(STR_INV_VERSION_TEXT4),
+ text = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ flags = 0,
+ key = 0;
+
+ subtitle text = STRING_TOKEN(STR_INV_EMPTY_STRING);
+
+ text
+ help = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ text = STRING_TOKEN(STR_INV_VERSION_TEXT5),
+ text = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ flags = 0,
+ key = 0;
+
+ text
+ help = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ text = STRING_TOKEN(STR_INV_VERSION_TEXT6),
+ text = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ flags = 0,
+ key = 0;
+
+ text
+ help = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ text = STRING_TOKEN(STR_INV_VERSION_TEXT7),
+ text = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ flags = 0,
+ key = 0;
+
+ text
+ help = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ text = STRING_TOKEN(STR_INV_VERSION_TEXT8),
+ text = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ flags = 0,
+ key = 0;
+
+ text
+ help = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ text = STRING_TOKEN(STR_INV_VERSION_TEXT9),
+ text = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ flags = 0,
+ key = 0;
+
+ text
+ help = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ text = STRING_TOKEN(STR_INV_VERSION_TEXT10),
+ text = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ flags = 0,
+ key = 0;
+
+ text
+ help = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ text = STRING_TOKEN(STR_INV_VERSION_TEXT11),
+ text = STRING_TOKEN(STR_INV_EMPTY_STRING),
+ flags = 0,
+ key = 0;
+
+ subtitle text = STRING_TOKEN(STR_INV_EMPTY_STRING);
+
+ subtitle text = STRING_TOKEN(STR_INV_VERSION_TEXT12);
+
+ endform;
+
+endformset;
diff --git a/MdeModulePkg/Universal/DriverSampleDxe/inventorystrings.uni b/MdeModulePkg/Universal/DriverSampleDxe/inventorystrings.uni Binary files differnew file mode 100644 index 0000000000..8d944564d7 --- /dev/null +++ b/MdeModulePkg/Universal/DriverSampleDxe/inventorystrings.uni diff --git a/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c b/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c new file mode 100644 index 0000000000..15a55d794a --- /dev/null +++ b/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c @@ -0,0 +1,2116 @@ +/** @file
+
+Copyright (c) 2007, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ ConfigRouting.c
+
+Abstract:
+
+ Implementation for EFI_HII_CONFIG_ROUTING_PROTOCOL.
+
+Revision History
+
+
+**/
+
+
+#include "HiiDatabase.h"
+
+#ifndef DISABLE_UNUSED_HII_PROTOCOLS
+
+STATIC
+CHAR16
+NibbleToHexCharPrivate (
+ IN UINT8 Nibble
+ )
+/*++
+
+ Routine Description:
+ Converts the low nibble of a byte to hex unicode character.
+
+ Arguments:
+ Nibble - lower nibble of a byte.
+
+ Returns:
+ Hex unicode character between L'0' to L'f'.
+
+--*/
+{
+ Nibble &= 0x0F;
+
+ if (Nibble <= 0x9) {
+ return (CHAR16)(Nibble + L'0');
+ }
+
+ return (CHAR16)(Nibble - 0xA + L'a');
+}
+
+
+/**
+ Converts Unicode string to binary buffer.
+ The conversion may be partial.
+ The first character in the string that is not hex digit stops the conversion.
+ At a minimum, any blob of data could be represented as a hex string.
+
+ @param Buf Pointer to buffer that receives the data.
+ @param Len Length in bytes of the buffer to hold converted
+ data. If routine return with EFI_SUCCESS,
+ containing length of converted data. If routine
+ return with EFI_BUFFER_TOO_SMALL, containg length
+ of buffer desired.
+ @param Str String to be converted from.
+ @param ConvertedStrLen Length of the Hex String consumed.
+
+ @retval EFI_SUCCESS Routine Success.
+ @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold converted data.
+
+**/
+STATIC
+EFI_STATUS
+HexStringToBufPrivate (
+ IN OUT UINT8 *Buf,
+ IN OUT UINTN *Len,
+ IN CHAR16 *Str,
+ OUT UINTN *ConvertedStrLen OPTIONAL
+ )
+{
+ UINTN HexCnt;
+ UINTN Idx;
+ UINTN BufferLength;
+ UINT8 Digit;
+ UINT8 Byte;
+
+ //
+ // Find out how many hex characters the string has.
+ //
+ for (Idx = 0, HexCnt = 0; R8_IsHexDigit (&Digit, Str[Idx]); Idx++, HexCnt++);
+
+ if (HexCnt == 0) {
+ *Len = 0;
+ return EFI_SUCCESS;
+ }
+ //
+ // Two Unicode characters make up 1 buffer byte. Round up.
+ //
+ BufferLength = (HexCnt + 1) / 2;
+
+ //
+ // Test if buffer is passed enough.
+ //
+ if (BufferLength > (*Len)) {
+ *Len = BufferLength;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *Len = BufferLength;
+
+ for (Idx = 0; Idx < HexCnt; Idx++) {
+
+ R8_IsHexDigit (&Digit, Str[Idx]);
+
+ //
+ // For odd charaters, write the lower nibble for each buffer byte,
+ // and for even characters, the upper nibble.
+ //
+ if ((Idx & 1) == 0) {
+ Byte = (UINT8) (Digit << 4);
+ } else {
+ Byte = Buf[Idx / 2];
+ Byte &= 0xF0;
+ Byte = (UINT8) (Byte | Digit);
+ }
+
+ Buf[Idx / 2] = Byte;
+ }
+
+ if (ConvertedStrLen != NULL) {
+ *ConvertedStrLen = HexCnt;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Converts binary buffer to Unicode string.
+ At a minimum, any blob of data could be represented as a hex string.
+
+ @param Str Pointer to the string.
+ @param HexStringBufferLength Length in bytes of buffer to hold the hex string.
+ Includes tailing '\0' character. If routine return
+ with EFI_SUCCESS, containing length of hex string
+ buffer. If routine return with
+ EFI_BUFFER_TOO_SMALL, containg length of hex
+ string buffer desired.
+ @param Buf Buffer to be converted from.
+ @param Len Length in bytes of the buffer to be converted.
+ @param Flag If TRUE, encode the data in the same order as the
+ it resides in the Buf. Else encode it in the
+ reverse direction.
+
+ @retval EFI_SUCCESS Routine success.
+ @retval EFI_BUFFER_TOO_SMALL The hex string buffer is too small.
+
+**/
+STATIC
+EFI_STATUS
+BufToHexStringPrivate (
+ IN OUT CHAR16 *Str,
+ IN OUT UINTN *HexStringBufferLength,
+ IN UINT8 *Buf,
+ IN UINTN Len,
+ IN BOOLEAN Flag
+ )
+{
+ UINTN Idx;
+ UINT8 Byte;
+ UINTN StrLen;
+
+ //
+ // Make sure string is either passed or allocate enough.
+ // It takes 2 Unicode characters (4 bytes) to represent 1 byte of the binary buffer.
+ // Plus the Unicode termination character.
+ //
+ StrLen = Len * 2;
+ if ((*HexStringBufferLength) < (StrLen + 1) * sizeof (CHAR16)) {
+ *HexStringBufferLength = (StrLen + 1) * sizeof (CHAR16);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *HexStringBufferLength = (StrLen + 1) * sizeof (CHAR16);
+
+ //
+ // Ends the string.
+ //
+ Str[StrLen] = 0;
+
+ for (Idx = 0; Idx < Len; Idx++) {
+
+ Byte = Buf[Idx];
+ if (Flag) {
+ Str[Idx * 2] = NibbleToHexCharPrivate ((UINT8)(Byte >> 4));
+ Str[Idx * 2 + 1] = NibbleToHexCharPrivate (Byte);
+ } else {
+ Str[StrLen - 1 - Idx * 2] = NibbleToHexCharPrivate (Byte);
+ Str[StrLen - 2 - Idx * 2] = NibbleToHexCharPrivate ((UINT8)(Byte >> 4));
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ Calculate the number of Unicode characters of the incoming Configuration string,
+ not including NULL terminator.
+
+ @param String String in <MultiConfigRequest> or
+ <MultiConfigResp> format.
+
+ @return The number of Unicode characters.
+
+**/
+STATIC
+UINTN
+CalculateConfigStringLen (
+ IN EFI_STRING String
+ )
+{
+ UINTN Length;
+
+ //
+ // "GUID=" should be the first element of incoming string.
+ //
+ ASSERT (String != NULL);
+ ASSERT (StrnCmp (String, L"GUID=", StrLen (L"GUID=")) == 0);
+
+ Length = StrLen (L"GUID=");
+ String += Length;
+
+ //
+ // The beginning of next <ConfigRequest>/<ConfigResp> should be "&GUID=".
+ // Will meet '\0' if there is only one <ConfigRequest>/<ConfigResp>.
+ //
+ while (*String != 0 && StrnCmp (String, L"&GUID=", StrLen (L"&GUID=")) != 0) {
+ Length++;
+ String++;
+ }
+
+ return Length;
+}
+
+
+/**
+ Convert the hex UNICODE %02x encoding of a UEFI device path to binary
+ from <PathHdr> of <ConfigHdr>.
+
+ @param String UEFI configuration string
+ @param DevicePath binary of a UEFI device path.
+
+ @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
+ @retval EFI_OUT_OF_RESOURCES Lake of resources to store neccesary structures.
+ @retval EFI_SUCCESS The device path is retrieved and translated to
+ binary format.
+
+**/
+STATIC
+EFI_STATUS
+GetDevicePath (
+ IN EFI_STRING String,
+ OUT UINT8 **DevicePath
+ )
+{
+ UINTN Length;
+ EFI_STRING PathHdr;
+ EFI_STRING DevicePathString;
+
+ if (String == NULL || DevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Find the 'PATH=' of <PathHdr> and skip it.
+ //
+ for (; (*String != 0 && StrnCmp (String, L"PATH=", StrLen (L"PATH=")) != 0); String++);
+ if (*String == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ String += StrLen (L"PATH=");
+ PathHdr = String;
+
+ //
+ // The content between 'PATH=' of <ConfigHdr> and '&' of next element
+ // or '\0' (end of configuration string) is the UNICODE %02x bytes encoding
+ // of UEFI device path.
+ //
+ for (Length = 0; *String != 0 && *String != L'&'; String++, Length++);
+ DevicePathString = (EFI_STRING) AllocateZeroPool ((Length + 1) * sizeof (CHAR16));
+ if (DevicePathString == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ StrnCpy (DevicePathString, PathHdr, Length);
+ *(DevicePathString + Length) = 0;
+
+ //
+ // The data in <PathHdr> is encoded as hex UNICODE %02x bytes in the same order
+ // as the device path resides in RAM memory.
+ // Translate the data into binary.
+ // Two Unicode characters make up 1 buffer byte.
+ //
+ Length /= 2;
+ *DevicePath = (UINT8 *) AllocateZeroPool (Length);
+ if (*DevicePath == NULL) {
+ SafeFreePool (DevicePathString);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ HexStringToBufPrivate (*DevicePath, &Length, DevicePathString, NULL);
+
+ SafeFreePool (DevicePathString);
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+ Extract Storage from all Form Packages in current hii database.
+
+ @param HiiDatabase EFI_HII_DATABASE_PROTOCOL instance.
+ @param StorageListHead Storage link List head.
+
+ @retval EFI_NOT_FOUND There is no form package in current hii database.
+ @retval EFI_INVALID_PARAMETER Any parameter is invalid.
+ @retval EFI_SUCCESS All existing storage is exported.
+
+**/
+STATIC
+EFI_STATUS
+ExportAllStorage (
+ IN EFI_HII_DATABASE_PROTOCOL *HiiDatabase,
+ IN OUT LIST_ENTRY *StorageListHead
+)
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ UINTN HandleCount;
+ EFI_HII_HANDLE *HandleBuffer;
+ UINTN Index;
+ UINTN Index2;
+ EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
+ EFI_HII_PACKAGE_HEADER *Package;
+ UINT8 *OpCodeData;
+ UINT8 Operand;
+ UINT32 Offset;
+ HII_FORMSET_STORAGE *Storage;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HANDLE DriverHandle;
+ CHAR8 *AsciiString;
+ UINT32 PackageListLength;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+
+ //
+ // Find the package list which contains Form package.
+ //
+ BufferSize = 0;
+ HandleBuffer = NULL;
+ Status = HiiListPackageLists (
+ HiiDatabase,
+ EFI_HII_PACKAGE_FORM,
+ NULL,
+ &BufferSize,
+ HandleBuffer
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ HandleBuffer = AllocateZeroPool (BufferSize);
+ ASSERT (HandleBuffer != NULL);
+
+ Status = HiiListPackageLists (
+ HiiDatabase,
+ EFI_HII_PACKAGE_FORM,
+ NULL,
+ &BufferSize,
+ HandleBuffer
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ SafeFreePool (HandleBuffer);
+ return Status;
+ }
+
+ HandleCount = BufferSize / sizeof (EFI_HII_HANDLE);
+ for (Index = 0; Index < HandleCount; Index++) {
+ HiiHandle = HandleBuffer[Index];
+
+ BufferSize = 0;
+ HiiPackageList = NULL;
+ Status = HiiExportPackageLists (HiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ HiiPackageList = AllocateZeroPool (BufferSize);
+ ASSERT (HiiPackageList != NULL);
+ Status = HiiExportPackageLists (HiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
+ }
+ if (EFI_ERROR (Status)) {
+ SafeFreePool (HandleBuffer);
+ SafeFreePool (HiiPackageList);
+ return Status;
+ }
+
+ //
+ // Get Form package from this HII package List
+ //
+ Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
+ CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
+ Package = NULL;
+ ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
+
+ while (Offset < PackageListLength) {
+ Package = (EFI_HII_PACKAGE_HEADER *) (((UINT8 *) HiiPackageList) + Offset);
+ CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
+ if (PackageHeader.Type == EFI_HII_PACKAGE_FORM) {
+ break;
+ }
+ Offset += PackageHeader.Length;
+ }
+ if (Offset >= PackageListLength) {
+ //
+ // Error here: No Form package found in this Package List
+ //
+ ASSERT (FALSE);
+ }
+
+ //
+ // Search Storage definition in this Form package
+ //
+ Offset = sizeof (EFI_HII_PACKAGE_HEADER);
+ while (Offset < PackageHeader.Length) {
+ OpCodeData = ((UINT8 *) Package) + Offset;
+ Offset += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
+
+ Operand = ((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode;
+
+ if ((Operand == EFI_IFR_VARSTORE_OP) ||
+ (Operand == EFI_IFR_VARSTORE_NAME_VALUE_OP) ||
+ (Operand == EFI_IFR_VARSTORE_EFI_OP)) {
+
+ Storage = AllocateZeroPool (sizeof (HII_FORMSET_STORAGE));
+ ASSERT (Storage != NULL);
+ InsertTailList (StorageListHead, &Storage->Entry);
+
+ Storage->Signature = HII_FORMSET_STORAGE_SIGNATURE;
+ Storage->HiiHandle = HiiHandle;
+
+ Status = HiiGetPackageListHandle (HiiDatabase, HiiHandle, &DriverHandle);
+ if (EFI_ERROR (Status)) {
+ SafeFreePool (HandleBuffer);
+ SafeFreePool (HiiPackageList);
+ SafeFreePool (Storage);
+ return Status;
+ }
+ Storage->DriverHandle = DriverHandle;
+
+ if (Operand == EFI_IFR_VARSTORE_OP) {
+ Storage->Type = EFI_HII_VARSTORE_BUFFER;
+
+ CopyMem (&Storage->Guid, &((EFI_IFR_VARSTORE *) OpCodeData)->Guid, sizeof (EFI_GUID));
+ CopyMem (&Storage->Size, &((EFI_IFR_VARSTORE *) OpCodeData)->Size, sizeof (UINT16));
+
+ AsciiString = (CHAR8 *) ((EFI_IFR_VARSTORE *) OpCodeData)->Name;
+ Storage->Name = AllocateZeroPool (AsciiStrSize (AsciiString) * 2);
+ ASSERT (Storage->Name != NULL);
+ for (Index2 = 0; AsciiString[Index2] != 0; Index2++) {
+ Storage->Name[Index2] = (CHAR16) AsciiString[Index2];
+ }
+ //
+ // Append '\0' to the end of the unicode string.
+ //
+ Storage->Name[Index2] = 0;
+ } else if (Operand == EFI_IFR_VARSTORE_NAME_VALUE_OP) {
+ Storage->Type = EFI_HII_VARSTORE_NAME_VALUE;
+
+ CopyMem (&Storage->Guid, &((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->Guid, sizeof (EFI_GUID));
+ } else if (Operand == EFI_IFR_VARSTORE_EFI_OP) {
+ Storage->Type = EFI_HII_VARSTORE_EFI_VARIABLE;
+
+ CopyMem (&Storage->Guid, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Guid, sizeof (EFI_GUID));
+ }
+ }
+ }
+
+ SafeFreePool (HiiPackageList);
+ }
+
+ SafeFreePool (HandleBuffer);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Generate a sub string then output it.
+
+ @param String A constant string which is the prefix of the to be
+ generated string, e.g. GUID=
+ @param BufferLen The length of the Buffer in bytes.
+ @param Buffer Points to a buffer which will be converted to hex
+ string and to be the content of the generated
+ string.
+ @param Flag If TRUE, convert the buffer data in the same order
+ as the it resides in the Buffer. Else convert it
+ in the reverse direction.
+ @param SubStr Points to the output string. It's caller's
+ responsibility to free this buffer.
+
+
+**/
+STATIC
+VOID
+GenerateSubStr (
+ IN CONST EFI_STRING String,
+ IN UINTN BufferLen,
+ IN UINT8 *Buffer,
+ IN BOOLEAN Flag,
+ OUT EFI_STRING *SubStr
+ )
+{
+ UINTN Length;
+ EFI_STRING Str;
+ EFI_STATUS Status;
+
+ ASSERT (String != NULL && SubStr != NULL);
+
+ if (Buffer == NULL) {
+ *SubStr = AllocateCopyPool (StrSize (String), String);
+ ASSERT (*SubStr != NULL);
+ return ;
+ }
+
+ Length = BufferLen * 2 + 1 + StrLen (String) + 1;
+ Str = AllocateZeroPool (Length * sizeof (CHAR16));
+ ASSERT (Str != NULL);
+
+ StrCpy (Str, String);
+ Length = (BufferLen * 2 + 1) * sizeof (CHAR16);
+
+ Status = BufToHexStringPrivate (
+ Str + StrLen (String),
+ &Length,
+ Buffer,
+ BufferLen,
+ Flag
+ );
+
+ ASSERT_EFI_ERROR (Status);
+ StrCat (Str, L"&");
+
+ *SubStr = Str;
+}
+
+
+/**
+ Retrieve the <ConfigBody> from String then output it.
+
+ @param String A sub string of a configuration string in
+ <MultiConfigAltResp> format.
+ @param ConfigBody Points to the output string. It's caller's
+ responsibility to free this buffer.
+
+ @retval EFI_INVALID_PARAMETER There is no form package in current hii database.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to finish this operation.
+ @retval EFI_SUCCESS All existing storage is exported.
+
+**/
+STATIC
+EFI_STATUS
+OutputConfigBody (
+ IN EFI_STRING String,
+ OUT EFI_STRING *ConfigBody
+ )
+{
+ EFI_STRING TmpPtr;
+ EFI_STRING Result;
+ UINTN Length;
+
+ if (String == NULL || ConfigBody == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TmpPtr = StrStr (String, L"GUID=");
+ if (TmpPtr == NULL) {
+ //
+ // It is the last <ConfigResp> of the incoming configuration string.
+ //
+ Result = AllocateCopyPool (StrSize (String), String);
+ if (Result == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ } else {
+ *ConfigBody = Result;
+ return EFI_SUCCESS;
+ }
+ }
+
+ Length = TmpPtr - String;
+ Result = AllocateCopyPool (Length * sizeof (CHAR16), String);
+ if (Result == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *(Result + Length - 1) = 0;
+ *ConfigBody = Result;
+ return EFI_SUCCESS;
+
+}
+
+
+#endif
+
+VOID *
+ReallocatePool (
+ IN VOID *OldPool,
+ IN UINTN OldSize,
+ IN UINTN NewSize
+ )
+/*++
+
+Routine Description:
+ Adjusts the size of a previously allocated buffer.
+
+Arguments:
+ OldPool - A pointer to the buffer whose size is being adjusted.
+ OldSize - The size of the current buffer.
+ NewSize - The size of the new buffer.
+
+Returns:
+ Points to the new buffer
+
+--*/
+{
+ VOID *NewPool;
+
+ NewPool = NULL;
+ if (NewSize) {
+ NewPool = AllocateZeroPool (NewSize);
+ }
+
+ if (OldPool) {
+ if (NewPool) {
+ CopyMem (NewPool, OldPool, OldSize < NewSize ? OldSize : NewSize);
+ }
+
+ gBS->FreePool (OldPool);
+ }
+
+ return NewPool;
+}
+
+
+/**
+ Append a string to a multi-string format.
+
+ @param MultiString String in <MultiConfigRequest>,
+ <MultiConfigAltResp>, or <MultiConfigResp>. On
+ input, the buffer length of this string is
+ MAX_STRING_LENGTH. On output, the buffer length
+ might be updated.
+ @param AppendString NULL-terminated Unicode string.
+
+ @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
+ @retval EFI_SUCCESS AppendString is append to the end of MultiString
+
+**/
+STATIC
+EFI_STATUS
+AppendToMultiString (
+ IN OUT EFI_STRING *MultiString,
+ IN EFI_STRING AppendString
+ )
+{
+ UINTN AppendStringSize;
+ UINTN MultiStringSize;
+
+ if (MultiString == NULL || *MultiString == NULL || AppendString == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AppendStringSize = StrSize (AppendString);
+ MultiStringSize = StrSize (*MultiString);
+
+ //
+ // Enlarge the buffer each time when length exceeds MAX_STRING_LENGTH.
+ //
+ if (MultiStringSize + AppendStringSize > MAX_STRING_LENGTH ||
+ MultiStringSize > MAX_STRING_LENGTH) {
+ *MultiString = (EFI_STRING) ReallocatePool (
+ (VOID *) (*MultiString),
+ MultiStringSize,
+ MultiStringSize + AppendStringSize
+ );
+ }
+
+ //
+ // Append the incoming string
+ //
+ StrCat (*MultiString, AppendString);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Get the value of <Number> in <BlockConfig> format, i.e. the value of OFFSET
+ or WIDTH or VALUE.
+ <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
+
+ @param StringPtr String in <BlockConfig> format and points to the
+ first character of <Number>.
+ @param Number The output value. Caller takes the responsibility
+ to free memory.
+ @param Len Length of the <Number>, in characters.
+
+ @retval EFI_OUT_OF_RESOURCES Insufficient resources to store neccessary
+ structures.
+ @retval EFI_SUCCESS Value of <Number> is outputted in Number
+ successfully.
+
+**/
+STATIC
+EFI_STATUS
+GetValueOfNumber (
+ IN EFI_STRING StringPtr,
+ OUT UINT8 **Number,
+ OUT UINTN *Len
+ )
+{
+ EFI_STRING TmpPtr;
+ UINTN Length;
+ EFI_STRING Str;
+ UINT8 *Buf;
+ EFI_STATUS Status;
+
+ ASSERT (StringPtr != NULL && Number != NULL && Len != NULL);
+ ASSERT (*StringPtr != 0);
+
+ Buf = NULL;
+
+ TmpPtr = StringPtr;
+ while (*StringPtr != 0 && *StringPtr != L'&') {
+ StringPtr++;
+ }
+ *Len = StringPtr - TmpPtr;
+ Length = *Len + 1;
+
+ Str = (EFI_STRING) AllocateZeroPool (Length * sizeof (EFI_STRING));
+ if (Str == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ CopyMem (Str, TmpPtr, *Len * sizeof (CHAR16));
+ *(Str + *Len) = 0;
+
+ Length = (Length + 1) / 2;
+ Buf = (UINT8 *) AllocateZeroPool (Length);
+ if (Buf == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ Status = R8_HexStringToBuf (Buf, &Length, Str, NULL);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ *Number = Buf;
+ Status = EFI_SUCCESS;
+
+Exit:
+ SafeFreePool (Str);
+ return Status;
+}
+
+
+/**
+ This function allows a caller to extract the current configuration
+ for one or more named elements from one or more drivers.
+
+ @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
+ instance.
+ @param Request A null-terminated Unicode string in
+ <MultiConfigRequest> format.
+ @param Progress On return, points to a character in the Request
+ string. Points to the string's null terminator if
+ request was successful. Points to the most recent
+ & before the first failing name / value pair (or
+ the beginning of the string if the failure is in
+ the first name / value pair) if the request was
+ not successful.
+ @param Results Null-terminated Unicode string in
+ <MultiConfigAltResp> format which has all values
+ filled in for the names in the Request string.
+ String to be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results string is filled with the values
+ corresponding to all requested names.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
+ results that must be stored awaiting possible
+ future protocols.
+ @retval EFI_NOT_FOUND Routing data doesn't match any known driver.
+ Progress set to the "G" in "GUID" of the routing
+ header that doesn't match. Note: There is no
+ requirement that all routing data be validated
+ before any configuration extraction.
+ @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Request
+ parameter would result in this type of error. The
+ Progress parameter is set to NULL.
+ @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set to most recent &
+ before the error or the beginning of the string.
+ @retval EFI_INVALID_PARAMETER Unknown name. Progress points to the & before the
+ name in question.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiConfigRoutingExtractConfig (
+ IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ )
+{
+#ifndef DISABLE_UNUSED_HII_PROTOCOLS
+
+ HII_DATABASE_PRIVATE_DATA *Private;
+ EFI_STRING StringPtr;
+ EFI_STRING ConfigRequest;
+ UINTN Length;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ HII_DATABASE_RECORD *Database;
+ UINT8 *CurrentDevicePath;
+ EFI_HANDLE DriverHandle;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
+ EFI_STRING AccessProgress;
+ EFI_STRING AccessResults;
+ UINTN RemainSize;
+ EFI_STRING TmpPtr;
+
+ if (This == NULL || Progress == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Request == NULL) {
+ *Progress = NULL;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ StringPtr = Request;
+ *Progress = StringPtr;
+
+ //
+ // The first element of <MultiConfigRequest> should be
+ // <GuidHdr>, which is in 'GUID='<Guid> syntax.
+ //
+ if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Allocate a fix length of memory to store Results. Reallocate memory for
+ // Results if this fix length is insufficient.
+ //
+ *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
+ if (*Results == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {
+ //
+ // If parsing error, set Progress to the beginning of the <MultiConfigRequest>
+ // or most recent & before the error.
+ //
+ if (StringPtr == Request) {
+ *Progress = StringPtr;
+ } else {
+ *Progress = StringPtr - 1;
+ }
+
+ //
+ // Process each <ConfigRequest> of <MultiConfigRequest>
+ //
+ Length = CalculateConfigStringLen (StringPtr);
+ ConfigRequest = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);
+ if (ConfigRequest == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ *(ConfigRequest + Length) = 0;
+
+ //
+ // Get the UEFI device path
+ //
+ Status = GetDevicePath (ConfigRequest, (UINT8 **) &DevicePath);
+ if (EFI_ERROR (Status)) {
+ SafeFreePool (ConfigRequest);
+ return Status;
+ }
+
+ //
+ // Find driver which matches the routing data.
+ //
+ DriverHandle = NULL;
+ for (Link = Private->DatabaseList.ForwardLink;
+ Link != &Private->DatabaseList;
+ Link = Link->ForwardLink
+ ) {
+ Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ CurrentDevicePath = Database->PackageList->DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
+ if (CurrentDevicePath != NULL) {
+ if (CompareMem (
+ DevicePath,
+ CurrentDevicePath,
+ GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)
+ ) == 0) {
+ DriverHandle = Database->DriverHandle;
+ break;
+ }
+ }
+ }
+
+ SafeFreePool (DevicePath);
+
+ if (DriverHandle == NULL) {
+ //
+ // Routing data does not match any known driver.
+ // Set Progress to the 'G' in "GUID" of the routing header.
+ //
+ *Progress = StringPtr;
+ SafeFreePool (ConfigRequest);
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Call corresponding ConfigAccess protocol to extract settings
+ //
+ Status = gBS->HandleProtocol (
+ DriverHandle,
+ &gEfiHiiConfigAccessProtocolGuid,
+ (VOID **) &ConfigAccess
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = ConfigAccess->ExtractConfig (
+ ConfigAccess,
+ ConfigRequest,
+ &AccessProgress,
+ &AccessResults
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // AccessProgress indicates the parsing progress on <ConfigRequest>.
+ // Map it to the progress on <MultiConfigRequest> then return it.
+ //
+ RemainSize = StrSize (AccessProgress);
+ for (TmpPtr = StringPtr; CompareMem (TmpPtr, AccessProgress, RemainSize) != 0; TmpPtr++);
+ *Progress = TmpPtr;
+
+ SafeFreePool (ConfigRequest);
+ return Status;
+ }
+
+ //
+ // Attach this <ConfigAltResp> to a <MultiConfigAltResp>
+ //
+ ASSERT (*AccessProgress == 0);
+ Status = AppendToMultiString (Results, AccessResults);
+ ASSERT_EFI_ERROR (Status);
+ SafeFreePool (AccessResults);
+ AccessResults = NULL;
+ SafeFreePool (ConfigRequest);
+ ConfigRequest = NULL;
+
+ //
+ // Go to next <ConfigRequest> (skip '&').
+ //
+ StringPtr += Length;
+ if (*StringPtr == 0) {
+ *Progress = StringPtr;
+ break;
+ }
+
+ StringPtr++;
+
+ }
+
+ return EFI_SUCCESS;
+#else
+ return EFI_UNSUPPORTED;
+#endif
+
+}
+
+
+/**
+ This function allows the caller to request the current configuration for the
+ entirety of the current HII database and returns the data in a
+ null-terminated Unicode string.
+
+ @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
+ instance.
+ @param Results Null-terminated Unicode string in
+ <MultiConfigAltResp> format which has all values
+ filled in for the names in the Request string.
+ String to be allocated by the called function.
+ De-allocation is up to the caller.
+
+ @retval EFI_SUCCESS The Results string is filled with the values
+ corresponding to all requested names.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
+ results that must be stored awaiting possible
+ future protocols.
+ @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Results
+ parameter would result in this type of error.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiConfigRoutingExportConfig (
+ IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
+ OUT EFI_STRING *Results
+ )
+{
+#ifndef DISABLE_UNUSED_HII_PROTOCOLS
+
+ EFI_STATUS Status;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ LIST_ENTRY StorageListHdr;
+ HII_FORMSET_STORAGE *Storage;
+ LIST_ENTRY *Link;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINTN Length;
+ EFI_STRING PathHdr;
+ UINTN PathHdrSize;
+ EFI_STRING ConfigRequest;
+ UINTN RequestSize;
+ EFI_STRING StringPtr;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
+ EFI_STRING AccessProgress;
+ EFI_STRING AccessResults;
+ UINTN TmpSize;
+
+ if (This == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+
+ InitializeListHead (&StorageListHdr);
+
+ Status = ExportAllStorage (&Private->HiiDatabase, &StorageListHdr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Allocate a fix length of memory to store Results. Reallocate memory for
+ // Results if this fix length is insufficient.
+ //
+ *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
+ if (*Results == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Parsing all formset storages.
+ //
+ for (Link = StorageListHdr.ForwardLink; Link != &StorageListHdr; Link = Link->ForwardLink) {
+ Storage = CR (Link, HII_FORMSET_STORAGE, Entry, HII_FORMSET_STORAGE_SIGNATURE);
+ //
+ // Find the corresponding device path instance
+ //
+ Status = gBS->HandleProtocol (
+ Storage->DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Convert the device path binary to hex UNICODE %02x bytes in the same order
+ // as the device path resides in RAM memory.
+ //
+ Length = GetDevicePathSize (DevicePath);
+ PathHdrSize = (Length * 2 + 1) * sizeof (CHAR16);
+ PathHdr = (EFI_STRING) AllocateZeroPool (PathHdrSize);
+ if (PathHdr == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = BufToHexStringPrivate (PathHdr, &PathHdrSize, (UINT8 *) DevicePath, Length, TRUE);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Generate a <ConfigRequest> with one <ConfigHdr> and zero <RequestElement>.
+ // It means extract all possible configurations from this specific driver.
+ //
+ TmpSize = StrLen (L"GUID=&NAME=&PATH=");
+ RequestSize = (TmpSize + sizeof (EFI_GUID) * 2 + StrLen (Storage->Name))
+ * sizeof (CHAR16) + PathHdrSize;
+ ConfigRequest = (EFI_STRING) AllocateZeroPool (RequestSize);
+ if (ConfigRequest == NULL) {
+ SafeFreePool (PathHdr);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Add <GuidHdr>
+ // <GuidHdr> ::= 'GUID='<Guid>
+ //
+ StringPtr = ConfigRequest;
+ StrnCpy (StringPtr, L"GUID=", StrLen (L"GUID="));
+ StringPtr += StrLen (L"GUID=");
+
+ Status = BufToHexStringPrivate (
+ StringPtr,
+ &RequestSize,
+ (UINT8 *) (&Storage->Guid),
+ sizeof (EFI_GUID),
+ FALSE
+ );
+ ASSERT_EFI_ERROR (Status);
+ StringPtr += RequestSize / 2 - 1;
+ ASSERT (*StringPtr == 0);
+ *StringPtr = L'&';
+ StringPtr++;
+
+ //
+ // Add <NameHdr>
+ // <NameHdr> ::= 'NAME='<String>
+ //
+ StrnCpy (StringPtr, L"NAME=", StrLen (L"NAME="));
+ StringPtr += StrLen (L"NAME=");
+ StrnCpy (StringPtr, Storage->Name, StrLen (Storage->Name));
+ StringPtr += StrLen (Storage->Name);
+ *StringPtr = L'&';
+ StringPtr++;
+
+ //
+ // Add <PathHdr>
+ // <PathHdr> ::= '<PATH=>'<UEFI binary represented as hex UNICODE %02x>
+ //
+ StrnCpy (StringPtr, L"PATH=", StrLen (L"PATH="));
+ StringPtr += StrLen (L"PATH=");
+ StrCpy (StringPtr, PathHdr);
+
+ SafeFreePool (PathHdr);
+ PathHdr = NULL;
+
+ //
+ // BUGBUG: The "Implementation note" of ExportConfig() in UEFI spec makes the
+ // code somewhat complex. Let's TBD here whether a <ConfigRequest> or a <ConfigHdr>
+ // is required to call ConfigAccess.ExtractConfig().
+ //
+ // Here we use <ConfigHdr> to call ConfigAccess instance. It requires ConfigAccess
+ // to handle such kind of "ConfigRequest". It is not supported till now.
+ //
+ // Either the ExportConfig will be updated or the ConfigAccess.ExtractConfig()
+ // will be updated as soon as the decision is made.
+
+ //
+ // Route the request to corresponding ConfigAccess protocol to extract settings.
+ //
+ Status = gBS->HandleProtocol (
+ Storage->DriverHandle,
+ &gEfiHiiConfigAccessProtocolGuid,
+ (VOID **) &ConfigAccess
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = ConfigAccess->ExtractConfig (
+ ConfigAccess,
+ ConfigRequest,
+ &AccessProgress,
+ &AccessResults
+ );
+ if (EFI_ERROR (Status)) {
+ SafeFreePool (ConfigRequest);
+ SafeFreePool (AccessResults);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Attach this <ConfigAltResp> to a <MultiConfigAltResp>
+ //
+ ASSERT (*AccessProgress == 0);
+ Status = AppendToMultiString (Results, AccessResults);
+ ASSERT_EFI_ERROR (Status);
+ SafeFreePool (AccessResults);
+ AccessResults = NULL;
+ SafeFreePool (ConfigRequest);
+ ConfigRequest = NULL;
+
+ }
+
+ //
+ // Free the exported storage resource
+ //
+ while (!IsListEmpty (&StorageListHdr)) {
+ Storage = CR (
+ StorageListHdr.ForwardLink,
+ HII_FORMSET_STORAGE,
+ Entry,
+ HII_FORMSET_STORAGE_SIGNATURE
+ );
+ RemoveEntryList (&Storage->Entry);
+ SafeFreePool (Storage->Name);
+ SafeFreePool (Storage);
+ }
+
+ return EFI_SUCCESS;
+#else
+ return EFI_UNSUPPORTED;
+#endif
+}
+
+
+/**
+ This function processes the results of processing forms and routes it to the
+ appropriate handlers or storage.
+
+ @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
+ instance.
+ @param Configuration A null-terminated Unicode string in
+ <MulltiConfigResp> format.
+ @param Progress A pointer to a string filled in with the offset of
+ the most recent & before the first failing name /
+ value pair (or the beginning of the string if the
+ failure is in the first name / value pair) or the
+ terminating NULL if all was successful.
+
+ @retval EFI_SUCCESS The results have been distributed or are awaiting
+ distribution.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
+ results that must be stored awaiting possible
+ future protocols.
+ @retval EFI_INVALID_PARAMETER Passing in a NULL for the Configuration parameter
+ would result in this type of error.
+ @retval EFI_NOT_FOUND Target for the specified routing data was not
+ found.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiConfigRoutingRoutConfig (
+ IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ )
+{
+#ifndef DISABLE_UNUSED_HII_PROTOCOLS
+
+ HII_DATABASE_PRIVATE_DATA *Private;
+ EFI_STRING StringPtr;
+ EFI_STRING ConfigResp;
+ UINTN Length;
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ LIST_ENTRY *Link;
+ HII_DATABASE_RECORD *Database;
+ UINT8 *CurrentDevicePath;
+ EFI_HANDLE DriverHandle;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
+ EFI_STRING AccessProgress;
+ UINTN RemainSize;
+ EFI_STRING TmpPtr;
+
+ if (This == NULL || Progress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Configuration == NULL) {
+ *Progress = NULL;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ StringPtr = Configuration;
+ *Progress = StringPtr;
+
+ //
+ // The first element of <MultiConfigResp> should be
+ // <GuidHdr>, which is in 'GUID='<Guid> syntax.
+ //
+ if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {
+ //
+ // If parsing error, set Progress to the beginning of the <MultiConfigResp>
+ // or most recent & before the error.
+ //
+ if (StringPtr == Configuration) {
+ *Progress = StringPtr;
+ } else {
+ *Progress = StringPtr - 1;
+ }
+
+ //
+ // Process each <ConfigResp> of <MultiConfigResp>
+ //
+ Length = CalculateConfigStringLen (StringPtr);
+ ConfigResp = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);
+ if (ConfigResp == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Append '\0' to the end of ConfigRequest
+ //
+ *(ConfigResp + Length) = 0;
+
+ //
+ // Get the UEFI device path
+ //
+ Status = GetDevicePath (ConfigResp, (UINT8 **) &DevicePath);
+ if (EFI_ERROR (Status)) {
+ SafeFreePool (ConfigResp);
+ return Status;
+ }
+
+ //
+ // Find driver which matches the routing data.
+ //
+ DriverHandle = NULL;
+ for (Link = Private->DatabaseList.ForwardLink;
+ Link != &Private->DatabaseList;
+ Link = Link->ForwardLink
+ ) {
+ Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ CurrentDevicePath = Database->PackageList->DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
+ if (CurrentDevicePath != NULL) {
+ if (CompareMem (
+ DevicePath,
+ CurrentDevicePath,
+ GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)
+ ) == 0) {
+ DriverHandle = Database->DriverHandle;
+ break;
+ }
+ }
+ }
+
+ SafeFreePool (DevicePath);
+
+ if (DriverHandle == NULL) {
+ //
+ // Routing data does not match any known driver.
+ // Set Progress to the 'G' in "GUID" of the routing header.
+ //
+ *Progress = StringPtr;
+ SafeFreePool (ConfigResp);
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Call corresponding ConfigAccess protocol to route settings
+ //
+ Status = gBS->HandleProtocol (
+ DriverHandle,
+ &gEfiHiiConfigAccessProtocolGuid,
+ (VOID **) &ConfigAccess
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = ConfigAccess->RouteConfig (
+ ConfigAccess,
+ ConfigResp,
+ &AccessProgress
+ );
+
+ if (EFI_ERROR (Status)) {
+ //
+ // AccessProgress indicates the parsing progress on <ConfigResp>.
+ // Map it to the progress on <MultiConfigResp> then return it.
+ //
+ RemainSize = StrSize (AccessProgress);
+ for (TmpPtr = StringPtr; CompareMem (TmpPtr, AccessProgress, RemainSize) != 0; TmpPtr++);
+ *Progress = TmpPtr;
+
+ SafeFreePool (ConfigResp);
+ return Status;
+ }
+
+ SafeFreePool (ConfigResp);
+ ConfigResp = NULL;
+
+ //
+ // Go to next <ConfigResp> (skip '&').
+ //
+ StringPtr += Length;
+ if (*StringPtr == 0) {
+ *Progress = StringPtr;
+ break;
+ }
+
+ StringPtr++;
+
+ }
+
+ return EFI_SUCCESS;
+#else
+ return EFI_UNSUPPORTED;
+#endif
+}
+
+
+/**
+ This helper function is to be called by drivers to map configuration data
+ stored in byte array ("block") formats such as UEFI Variables into current
+ configuration strings.
+
+ @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
+ instance.
+ @param ConfigRequest A null-terminated Unicode string in
+ <ConfigRequest> format.
+ @param Block Array of bytes defining the block's configuration.
+ @param BlockSize Length in bytes of Block.
+ @param Config Filled-in configuration string. String allocated
+ by the function. Returned only if call is
+ successful.
+ @param Progress A pointer to a string filled in with the offset of
+ the most recent & before the first failing
+ name/value pair (or the beginning of the string if
+ the failure is in the first name / value pair) or
+ the terminating NULL if all was successful.
+
+ @retval EFI_SUCCESS The request succeeded. Progress points to the null
+ terminator at the end of the ConfigRequest
+ string.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
+ points to the first character of ConfigRequest.
+ @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigRequest or
+ Block parameter would result in this type of
+ error. Progress points to the first character of
+ ConfigRequest.
+ @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined.
+ @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted string.
+ Block is left updated and Progress points at
+ the "&" preceding the first non-<BlockName>.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiBlockToConfig (
+ IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
+ IN CONST EFI_STRING ConfigRequest,
+ IN CONST UINT8 *Block,
+ IN CONST UINTN BlockSize,
+ OUT EFI_STRING *Config,
+ OUT EFI_STRING *Progress
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+ EFI_STRING StringPtr;
+ UINTN Length;
+ EFI_STATUS Status;
+ EFI_STRING TmpPtr;
+ UINT8 *TmpBuffer;
+ UINTN Offset;
+ UINTN Width;
+ UINT8 *Value;
+ EFI_STRING ValueStr;
+ EFI_STRING ConfigElement;
+
+ if (This == NULL || Progress == NULL || Config == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Block == NULL || ConfigRequest == NULL) {
+ *Progress = ConfigRequest;
+ return EFI_INVALID_PARAMETER;
+ }
+
+
+ Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ ASSERT (Private != NULL);
+
+ StringPtr = ConfigRequest;
+ ValueStr = NULL;
+ Value = NULL;
+ ConfigElement = NULL;
+
+ //
+ // Allocate a fix length of memory to store Results. Reallocate memory for
+ // Results if this fix length is insufficient.
+ //
+ *Config = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
+ if (*Config == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Jump <ConfigHdr>
+ //
+ if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
+ *Progress = StringPtr;
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+ while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
+ StringPtr++;
+ }
+ if (*StringPtr == 0) {
+ *Progress = StringPtr;
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+ while (*StringPtr++ != L'&');
+
+ //
+ // Copy <ConfigHdr> and an additional '&' to <ConfigResp>
+ //
+ Length = StringPtr - ConfigRequest;
+ CopyMem (*Config, ConfigRequest, Length * sizeof (CHAR16));
+
+ //
+ // Parse each <RequestElement> if exists
+ // Only <BlockName> format is supported by this help function.
+ // <BlockName> ::= 'OFFSET='<Number>&'WIDTH='<Number>
+ //
+ while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {
+ //
+ // Back up the header of one <BlockName>
+ //
+ TmpPtr = StringPtr;
+
+ StringPtr += StrLen (L"OFFSET=");
+ //
+ // Get Offset
+ //
+ Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
+ if (Status == EFI_OUT_OF_RESOURCES) {
+ *Progress = ConfigRequest;
+ goto Exit;
+ }
+ Offset = 0;
+ CopyMem (
+ &Offset,
+ TmpBuffer,
+ (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
+ );
+ SafeFreePool (TmpBuffer);
+
+ StringPtr += Length;
+ if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
+ *Progress = StringPtr - Length - StrLen (L"OFFSET=") - 1;
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+ StringPtr += StrLen (L"&WIDTH=");
+
+ //
+ // Get Width
+ //
+ Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
+ if (Status == EFI_OUT_OF_RESOURCES) {
+ *Progress = ConfigRequest;
+ goto Exit;
+ }
+ Width = 0;
+ CopyMem (
+ &Width,
+ TmpBuffer,
+ (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
+ );
+ SafeFreePool (TmpBuffer);
+
+ StringPtr += Length;
+ if (*StringPtr != 0 && *StringPtr != L'&') {
+ *Progress = StringPtr - Length - StrLen (L"&WIDTH=");
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ //
+ // Calculate Value and convert it to hex string.
+ //
+ if (Offset + Width > BlockSize) {
+ *Progress = StringPtr;
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Value = (UINT8 *) AllocateZeroPool (Width);
+ if (Value == NULL) {
+ *Progress = ConfigRequest;
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ CopyMem (Value, (UINT8 *) Block + Offset, Width);
+
+ Length = Width * 2 + 1;
+ ValueStr = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
+ if (ValueStr == NULL) {
+ *Progress = ConfigRequest;
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ Status = R8_BufToHexString (ValueStr, &Length, Value, Width);
+ ASSERT_EFI_ERROR (Status);
+ SafeFreePool (Value);
+ Value = NULL;
+
+ //
+ // Build a ConfigElement
+ //
+ Length += StringPtr - TmpPtr + 1 + StrLen (L"VALUE=");
+ ConfigElement = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
+ if (ConfigElement == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ CopyMem (ConfigElement, TmpPtr, (StringPtr - TmpPtr + 1) * sizeof (CHAR16));
+ if (*StringPtr == 0) {
+ *(ConfigElement + (StringPtr - TmpPtr)) = L'&';
+ }
+ *(ConfigElement + (StringPtr - TmpPtr) + 1) = 0;
+ StrCat (ConfigElement, L"VALUE=");
+ StrCat (ConfigElement, ValueStr);
+
+ AppendToMultiString (Config, ConfigElement);
+
+ SafeFreePool (ConfigElement);
+ SafeFreePool (ValueStr);
+ ConfigElement = NULL;
+ ValueStr = NULL;
+
+ //
+ // If '\0', parsing is finished. Otherwise skip '&' to continue
+ //
+ if (*StringPtr == 0) {
+ break;
+ }
+ AppendToMultiString (Config, L"&");
+ StringPtr++;
+
+ }
+
+ if (*StringPtr != 0) {
+ *Progress = StringPtr - 1;
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ *Progress = StringPtr;
+ return EFI_SUCCESS;
+
+Exit:
+
+ SafeFreePool (*Config);
+ SafeFreePool (ValueStr);
+ SafeFreePool (Value);
+ SafeFreePool (ConfigElement);
+
+ return Status;
+
+}
+
+
+/**
+ This helper function is to be called by drivers to map configuration strings
+ to configurations stored in byte array ("block") formats such as UEFI Variables.
+
+ @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
+ instance.
+ @param ConfigResp A null-terminated Unicode string in <ConfigResp>
+ format.
+ @param Block A possibly null array of bytes representing the
+ current block. Only bytes referenced in the
+ ConfigResp string in the block are modified. If
+ this parameter is null or if the *BlockSize
+ parameter is (on input) shorter than required by
+ the Configuration string, only the BlockSize
+ parameter is updated and an appropriate status
+ (see below) is returned.
+ @param BlockSize The length of the Block in units of UINT8. On
+ input, this is the size of the Block. On output,
+ if successful, contains the index of the last
+ modified byte in the Block.
+ @param Progress On return, points to an element of the ConfigResp
+ string filled in with the offset of the most
+ recent '&' before the first failing name / value
+ pair (or the beginning of the string if the
+ failure is in the first name / value pair) or the
+ terminating NULL if all was successful.
+
+ @retval EFI_SUCCESS The request succeeded. Progress points to the null
+ terminator at the end of the ConfigResp string.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
+ points to the first character of ConfigResp.
+ @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigResp or
+ Block parameter would result in this type of
+ error. Progress points to the first character of
+ ConfigResp.
+ @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted name /
+ value pair. Block is left updated and
+ Progress points at the '&' preceding the first
+ non-<BlockName>.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiConfigToBlock (
+ IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
+ IN CONST EFI_STRING ConfigResp,
+ IN OUT UINT8 *Block,
+ IN OUT UINTN *BlockSize,
+ OUT EFI_STRING *Progress
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+ EFI_STRING StringPtr;
+ UINTN Length;
+ EFI_STATUS Status;
+ UINT8 *TmpBuffer;
+ UINTN Offset;
+ UINTN Width;
+ UINT8 *Value;
+ UINTN BufferSize;
+
+ if (This == NULL || BlockSize == NULL || Progress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ConfigResp == NULL || Block == NULL) {
+ *Progress = ConfigResp;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ ASSERT (Private != NULL);
+
+ StringPtr = ConfigResp;
+ BufferSize = *BlockSize;
+ Value = NULL;
+
+ //
+ // Jump <ConfigHdr>
+ //
+ if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
+ *Progress = StringPtr;
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+ while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
+ StringPtr++;
+ }
+ if (*StringPtr == 0) {
+ *Progress = StringPtr;
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+ while (*StringPtr++ != L'&');
+
+ //
+ // Parse each <ConfigElement> if exists
+ // Only <BlockConfig> format is supported by this help function.
+ // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE='<Number>
+ //
+ while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {
+ StringPtr += StrLen (L"OFFSET=");
+ //
+ // Get Offset
+ //
+ Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
+ if (Status == EFI_OUT_OF_RESOURCES) {
+ *Progress = ConfigResp;
+ goto Exit;
+ }
+ Offset = 0;
+ CopyMem (
+ &Offset,
+ TmpBuffer,
+ (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
+ );
+ SafeFreePool (TmpBuffer);
+
+ StringPtr += Length;
+ if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
+ *Progress = StringPtr - Length - StrLen (L"OFFSET=") - 1;
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+ StringPtr += StrLen (L"&WIDTH=");
+
+ //
+ // Get Width
+ //
+ Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
+ if (Status == EFI_OUT_OF_RESOURCES) {
+ *Progress = ConfigResp;
+ goto Exit;
+ }
+ Width = 0;
+ CopyMem (
+ &Width,
+ TmpBuffer,
+ (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
+ );
+ SafeFreePool (TmpBuffer);
+
+ StringPtr += Length;
+ if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) != 0) {
+ *Progress = StringPtr - Length - StrLen (L"&WIDTH=");
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+ StringPtr += StrLen (L"&VALUE=");
+
+ //
+ // Get Value
+ //
+ Status = GetValueOfNumber (StringPtr, &Value, &Length);
+ if (Status == EFI_OUT_OF_RESOURCES) {
+ *Progress = ConfigResp;
+ goto Exit;
+ }
+
+ StringPtr += Length;
+ if (*StringPtr != 0 && *StringPtr != L'&') {
+ *Progress = StringPtr - Length - 7;
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ //
+ // Update the Block with configuration info
+ //
+
+ if (Offset + Width > BufferSize) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ CopyMem (Block + Offset, Value, Width);
+ *BlockSize = Offset + Width - 1;
+
+ SafeFreePool (Value);
+ Value = NULL;
+
+ //
+ // If '\0', parsing is finished. Otherwise skip '&' to continue
+ //
+ if (*StringPtr == 0) {
+ break;
+ }
+
+ StringPtr++;
+ }
+
+ if (*StringPtr != 0) {
+ *Progress = StringPtr - 1;
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ *Progress = StringPtr;
+ return EFI_SUCCESS;
+
+Exit:
+
+ SafeFreePool (Value);
+ return Status;
+}
+
+
+/**
+ This helper function is to be called by drivers to extract portions of
+ a larger configuration string.
+
+ @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
+ instance.
+ @param Configuration A null-terminated Unicode string in
+ <MultiConfigAltResp> format.
+ @param Guid A pointer to the GUID value to search for in the
+ routing portion of the ConfigResp string when
+ retrieving the requested data. If Guid is NULL,
+ then all GUID values will be searched for.
+ @param Name A pointer to the NAME value to search for in the
+ routing portion of the ConfigResp string when
+ retrieving the requested data. If Name is NULL,
+ then all Name values will be searched for.
+ @param DevicePath A pointer to the PATH value to search for in the
+ routing portion of the ConfigResp string when
+ retrieving the requested data. If DevicePath is
+ NULL, then all DevicePath values will be searched
+ for.
+ @param AltCfgId A pointer to the ALTCFG value to search for in the
+ routing portion of the ConfigResp string when
+ retrieving the requested data. If this parameter
+ is NULL, then the current setting will be
+ retrieved.
+ @param AltCfgResp A pointer to a buffer which will be allocated by
+ the function which contains the retrieved string
+ as requested. This buffer is only allocated if
+ the call was successful.
+
+ @retval EFI_SUCCESS The request succeeded. The requested data was
+ extracted and placed in the newly allocated
+ AltCfgResp buffer.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate AltCfgResp.
+ @retval EFI_INVALID_PARAMETER Any parameter is invalid.
+ @retval EFI_NOT_FOUND Target for the specified routing data was not
+ found.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetAltCfg (
+ IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ IN CONST EFI_GUID *Guid,
+ IN CONST EFI_STRING Name,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN CONST UINT16 *AltCfgId,
+ OUT EFI_STRING *AltCfgResp
+ )
+{
+#ifndef DISABLE_UNUSED_HII_PROTOCOLS
+
+ EFI_STATUS Status;
+ EFI_STRING StringPtr;
+ EFI_STRING HdrStart = NULL;
+ EFI_STRING HdrEnd = NULL;
+ EFI_STRING TmpPtr;
+ UINTN Length;
+ EFI_STRING GuidStr = NULL;
+ EFI_STRING NameStr = NULL;
+ EFI_STRING PathStr = NULL;
+ EFI_STRING AltIdStr = NULL;
+ EFI_STRING Result = NULL;
+ BOOLEAN GuidFlag = FALSE;
+ BOOLEAN NameFlag = FALSE;
+ BOOLEAN PathFlag = FALSE;
+
+ if (This == NULL || Configuration == NULL || AltCfgResp == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ StringPtr = Configuration;
+ if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Generate the sub string for later matching.
+ //
+ GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (UINT8 *) Guid, FALSE, &GuidStr);
+ GenerateSubStr (
+ L"PATH=",
+ GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath),
+ (UINT8 *) DevicePath,
+ TRUE,
+ &PathStr
+ );
+ if (AltCfgId != NULL) {
+ GenerateSubStr (L"ALTCFG=", sizeof (UINT16), (UINT8 *) AltCfgId, FALSE, &AltIdStr);
+ }
+ if (Name != NULL) {
+ Length = StrLen (Name);
+ Length += StrLen (L"NAME=&") + 1;
+ NameStr = AllocateZeroPool (Length * sizeof (CHAR16));
+ if (NameStr == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ StrCpy (NameStr, L"NAME=");
+ StrCat (NameStr, Name);
+ StrCat (NameStr, L"&");
+ } else {
+ GenerateSubStr (L"NAME=", 0, NULL, FALSE, &NameStr);
+ }
+
+ while (*StringPtr != 0) {
+ //
+ // Try to match the GUID
+ //
+ if (!GuidFlag) {
+ TmpPtr = StrStr (StringPtr, GuidStr);
+ if (TmpPtr == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Exit;
+ }
+ HdrStart = TmpPtr;
+
+ //
+ // Jump to <NameHdr>
+ //
+ if (Guid != NULL) {
+ StringPtr = TmpPtr + StrLen (GuidStr);
+ } else {
+ StringPtr = StrStr (TmpPtr, L"NAME=");
+ if (StringPtr == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Exit;
+ }
+ }
+ GuidFlag = TRUE;
+ }
+
+ //
+ // Try to match the NAME
+ //
+ if (GuidFlag && !NameFlag) {
+ if (StrnCmp (StringPtr, NameStr, StrLen (NameStr)) != 0) {
+ GuidFlag = FALSE;
+ } else {
+ //
+ // Jump to <PathHdr>
+ //
+ if (Name != NULL) {
+ StringPtr += StrLen (NameStr);
+ } else {
+ StringPtr = StrStr (StringPtr, L"PATH=");
+ if (StringPtr == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Exit;
+ }
+ }
+ NameFlag = TRUE;
+ }
+ }
+
+ //
+ // Try to match the DevicePath
+ //
+ if (GuidFlag && NameFlag && !PathFlag) {
+ if (StrnCmp (StringPtr, PathStr, StrLen (PathStr)) != 0) {
+ GuidFlag = FALSE;
+ NameFlag = FALSE;
+ } else {
+ //
+ // Jump to '&' before <DescHdr> or <ConfigBody>
+ //
+ if (DevicePath != NULL) {
+ StringPtr += StrLen (PathStr);
+ } else {
+ StringPtr = StrStr (StringPtr, L"&");
+ if (StringPtr == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Exit;
+ }
+ }
+ PathFlag = TRUE;
+ HdrEnd = ++StringPtr;
+ }
+ }
+
+ //
+ // Try to match the AltCfgId
+ //
+ if (GuidFlag && NameFlag && PathFlag) {
+ if (AltCfgId == NULL) {
+ //
+ // Return Current Setting when AltCfgId is NULL.
+ //
+ Status = OutputConfigBody (StringPtr, &Result);
+ goto Exit;
+ }
+ //
+ // Search the <ConfigAltResp> to get the <AltResp> with AltCfgId.
+ //
+ if (StrnCmp (StringPtr, AltIdStr, StrLen (AltIdStr)) != 0) {
+ GuidFlag = FALSE;
+ NameFlag = FALSE;
+ PathFlag = FALSE;
+ } else {
+ Status = OutputConfigBody (StringPtr, &Result);
+ goto Exit;
+ }
+ }
+ }
+
+ Status = EFI_NOT_FOUND;
+
+Exit:
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Copy the <ConfigHdr> and <ConfigBody>
+ //
+ Length = HdrEnd - HdrStart + StrLen (Result);
+ *AltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16));
+ if (*AltCfgResp == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ } else {
+ StrnCpy (*AltCfgResp, HdrStart, HdrEnd - HdrStart);
+ StrCat (*AltCfgResp, Result);
+ Status = EFI_SUCCESS;
+ }
+ }
+
+ SafeFreePool (GuidStr);
+ SafeFreePool (NameStr);
+ SafeFreePool (PathStr);
+ SafeFreePool (AltIdStr);
+ SafeFreePool (Result);
+
+ return Status;
+
+#else
+ return EFI_UNSUPPORTED;
+#endif
+
+}
+
diff --git a/MdeModulePkg/Universal/HiiDatabaseDxe/Database.c b/MdeModulePkg/Universal/HiiDatabaseDxe/Database.c new file mode 100644 index 0000000000..a24c59bdce --- /dev/null +++ b/MdeModulePkg/Universal/HiiDatabaseDxe/Database.c @@ -0,0 +1,3727 @@ +/** @file
+
+Copyright (c) 2007, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ Database.c
+
+Abstract:
+
+ Implementation for EFI_HII_DATABASE_PROTOCOL.
+
+Revision History
+
+
+**/
+
+
+#include "HiiDatabase.h"
+
+//
+// Global variables
+//
+STATIC EFI_GUID mHiiDatabaseNotifyGuid = HII_DATABASE_NOTIFY_GUID;
+
+
+/**
+ This function generates a HII_DATABASE_RECORD node and adds into hii database.
+
+ @param Private hii database private structure
+ @param DatabaseRecord HII_DATABASE_RECORD node which is used to store a
+ package list
+
+ @retval EFI_SUCCESS A database record is generated successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new
+ database contents.
+ @retval EFI_INVALID_PARAMETER Private is NULL or DatabaseRecord is NULL.
+
+**/
+STATIC
+EFI_STATUS
+GenerateHiiDatabaseRecord (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ OUT HII_DATABASE_RECORD **DatabaseNode
+ )
+{
+ HII_DATABASE_RECORD *DatabaseRecord;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList;
+ HII_HANDLE *HiiHandle;
+
+ if (Private == NULL || DatabaseNode == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DatabaseRecord = (HII_DATABASE_RECORD *) AllocateZeroPool (sizeof (HII_DATABASE_RECORD));
+ if (DatabaseRecord == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ DatabaseRecord->Signature = HII_DATABASE_RECORD_SIGNATURE;
+
+ DatabaseRecord->PackageList = AllocateZeroPool (sizeof (HII_DATABASE_PACKAGE_LIST_INSTANCE));
+ if (DatabaseRecord->PackageList == NULL) {
+ SafeFreePool (DatabaseRecord);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PackageList = DatabaseRecord->PackageList;
+
+ InitializeListHead (&PackageList->GuidPkgHdr);
+ InitializeListHead (&PackageList->FormPkgHdr);
+ InitializeListHead (&PackageList->KeyboardLayoutHdr);
+ InitializeListHead (&PackageList->StringPkgHdr);
+ InitializeListHead (&PackageList->FontPkgHdr);
+ InitializeListHead (&PackageList->SimpleFontPkgHdr);
+ PackageList->ImagePkg = NULL;
+ PackageList->DevicePathPkg = NULL;
+
+ //
+ // Create a new hii handle
+ //
+ HiiHandle = (HII_HANDLE *) AllocateZeroPool (sizeof (HII_HANDLE));
+ if (HiiHandle == NULL) {
+ SafeFreePool (DatabaseRecord->PackageList);
+ SafeFreePool (DatabaseRecord);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ HiiHandle->Signature = HII_HANDLE_SIGNATURE;
+ //
+ // Backup the number of Hii handles
+ //
+ Private->HiiHandleCount++;
+ HiiHandle->Key = Private->HiiHandleCount;
+ //
+ // Insert the handle to hii handle list of the whole database.
+ //
+ InsertTailList (&Private->HiiHandleList, &HiiHandle->Handle);
+
+ DatabaseRecord->Handle = (EFI_HII_HANDLE) HiiHandle;
+
+ //
+ // Insert the Package List node to Package List link of the whole database.
+ //
+ InsertTailList (&Private->DatabaseList, &DatabaseRecord->DatabaseEntry);
+
+ *DatabaseNode = DatabaseRecord;
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+ This function checks whether a handle is a valid EFI_HII_HANDLE
+
+ @param Handle Pointer to a EFI_HII_HANDLE
+
+ @retval TRUE Valid
+ @retval FALSE Invalid
+
+**/
+BOOLEAN
+IsHiiHandleValid (
+ EFI_HII_HANDLE Handle
+ )
+{
+ HII_HANDLE *HiiHandle;
+
+ HiiHandle = (HII_HANDLE *) Handle;
+
+ if (HiiHandle == NULL) {
+ return FALSE;
+ }
+
+ if (HiiHandle->Signature != HII_HANDLE_SIGNATURE) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/**
+ This function invokes the matching registered function.
+
+ @param Private HII Database driver private structure.
+ @param NotifyType The type of change concerning the database.
+ @param PackageInstance Points to the package referred to by the
+ notification.
+ @param PackageType Package type
+ @param Handle The handle of the package list which contains the
+ specified package.
+
+ @retval EFI_SUCCESS Already checked all registered function and
+ invoked if matched.
+ @retval EFI_INVALID_PARAMETER Any input parameter is not valid.
+
+**/
+STATIC
+EFI_STATUS
+InvokeRegisteredFunction (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType,
+ IN VOID *PackageInstance,
+ IN UINT8 PackageType,
+ IN EFI_HII_HANDLE Handle
+ )
+{
+ HII_DATABASE_NOTIFY *Notify;
+ LIST_ENTRY *Link;
+ EFI_HII_PACKAGE_HEADER *Package;
+ UINT8 *Buffer;
+ UINT32 BufferSize;
+ UINT32 HeaderSize;
+ UINT32 ImageBlockSize;
+ UINT32 PaletteInfoSize;
+
+ if (Private == NULL || (NotifyType & 0xF) == 0 || PackageInstance == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Private->Signature != HII_DATABASE_PRIVATE_DATA_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (!IsHiiHandleValid (Handle)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Buffer = NULL;
+ Package = NULL;
+
+ //
+ // Convert the incoming package from hii database storage format to UEFI
+ // storage format. e.g. HII_GUID_PACKAGE_INSTANCE to EFI_HII_GUID_PACKAGE_HDR.
+ //
+ switch (PackageType) {
+ case EFI_HII_PACKAGE_TYPE_GUID:
+ Package = (EFI_HII_PACKAGE_HEADER *) (((HII_GUID_PACKAGE_INSTANCE *) PackageInstance)->GuidPkg);
+ break;
+
+ case EFI_HII_PACKAGE_FORM:
+ BufferSize = ((HII_IFR_PACKAGE_INSTANCE *) PackageInstance)->FormPkgHdr.Length;
+ Buffer = (UINT8 *) AllocateZeroPool (BufferSize);
+ ASSERT (Buffer != NULL);
+ CopyMem (
+ Buffer,
+ &((HII_IFR_PACKAGE_INSTANCE *) PackageInstance)->FormPkgHdr,
+ sizeof (EFI_HII_PACKAGE_HEADER)
+ );
+ CopyMem (
+ Buffer + sizeof (EFI_HII_PACKAGE_HEADER),
+ ((HII_IFR_PACKAGE_INSTANCE *) PackageInstance)->IfrData,
+ BufferSize - sizeof (EFI_HII_PACKAGE_HEADER)
+ );
+ Package = (EFI_HII_PACKAGE_HEADER *) Buffer;
+ break;
+
+ case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
+ Package = (EFI_HII_PACKAGE_HEADER *) (((HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE *) PackageInstance)->KeyboardPkg);
+ break;
+
+ case EFI_HII_PACKAGE_STRINGS:
+ BufferSize = ((HII_STRING_PACKAGE_INSTANCE *) PackageInstance)->StringPkgHdr->Header.Length;
+ HeaderSize = ((HII_STRING_PACKAGE_INSTANCE *) PackageInstance)->StringPkgHdr->HdrSize;
+ Buffer = (UINT8 *) AllocateZeroPool (BufferSize);
+ ASSERT (Buffer != NULL);
+ CopyMem (
+ Buffer,
+ ((HII_STRING_PACKAGE_INSTANCE *) PackageInstance)->StringPkgHdr,
+ HeaderSize
+ );
+ CopyMem (
+ Buffer + HeaderSize,
+ ((HII_STRING_PACKAGE_INSTANCE *) PackageInstance)->StringBlock,
+ BufferSize - HeaderSize
+ );
+ Package = (EFI_HII_PACKAGE_HEADER *) Buffer;
+ break;
+
+ case EFI_HII_PACKAGE_FONTS:
+ BufferSize = ((HII_FONT_PACKAGE_INSTANCE *) PackageInstance)->FontPkgHdr->Header.Length;
+ HeaderSize = ((HII_FONT_PACKAGE_INSTANCE *) PackageInstance)->FontPkgHdr->HdrSize;
+ Buffer = (UINT8 *) AllocateZeroPool (BufferSize);
+ ASSERT (Buffer != NULL);
+ CopyMem (
+ Buffer,
+ ((HII_FONT_PACKAGE_INSTANCE *) PackageInstance)->FontPkgHdr,
+ HeaderSize
+ );
+ CopyMem (
+ Buffer + HeaderSize,
+ ((HII_FONT_PACKAGE_INSTANCE *) PackageInstance)->GlyphBlock,
+ BufferSize - HeaderSize
+ );
+ Package = (EFI_HII_PACKAGE_HEADER *) Buffer;
+ break;
+
+ case EFI_HII_PACKAGE_IMAGES:
+ BufferSize = ((HII_IMAGE_PACKAGE_INSTANCE *) PackageInstance)->ImagePkgHdr.Header.Length;
+ HeaderSize = sizeof (EFI_HII_IMAGE_PACKAGE_HDR);
+ Buffer = (UINT8 *) AllocateZeroPool (BufferSize);
+ ASSERT (Buffer != NULL);
+
+ CopyMem (
+ Buffer,
+ &((HII_IMAGE_PACKAGE_INSTANCE *) PackageInstance)->ImagePkgHdr,
+ HeaderSize
+ );
+ CopyMem (
+ Buffer + sizeof (EFI_HII_PACKAGE_HEADER),
+ &HeaderSize,
+ sizeof (UINT32)
+ );
+
+ ImageBlockSize = ((HII_IMAGE_PACKAGE_INSTANCE *) PackageInstance)->ImageBlockSize;
+ if (ImageBlockSize != 0) {
+ CopyMem (
+ Buffer + HeaderSize,
+ ((HII_IMAGE_PACKAGE_INSTANCE *) PackageInstance)->ImageBlock,
+ ImageBlockSize
+ );
+ }
+
+ PaletteInfoSize = ((HII_IMAGE_PACKAGE_INSTANCE *) PackageInstance)->PaletteInfoSize;
+ if (PaletteInfoSize != 0) {
+ CopyMem (
+ Buffer + HeaderSize + ImageBlockSize,
+ ((HII_IMAGE_PACKAGE_INSTANCE *) PackageInstance)->PaletteBlock,
+ PaletteInfoSize
+ );
+ HeaderSize += ImageBlockSize;
+ CopyMem (
+ Buffer + sizeof (EFI_HII_PACKAGE_HEADER) + sizeof (UINT32),
+ &HeaderSize,
+ sizeof (UINT32)
+ );
+ }
+ Package = (EFI_HII_PACKAGE_HEADER *) Buffer;
+ break;
+
+ case EFI_HII_PACKAGE_SIMPLE_FONTS:
+ BufferSize = ((HII_SIMPLE_FONT_PACKAGE_INSTANCE *) PackageInstance)->SimpleFontPkgHdr->Header.Length;
+ Buffer = (UINT8 *) AllocateZeroPool (BufferSize);
+ ASSERT (Buffer != NULL);
+ CopyMem (
+ Buffer,
+ ((HII_SIMPLE_FONT_PACKAGE_INSTANCE *) PackageInstance)->SimpleFontPkgHdr,
+ BufferSize
+ );
+ Package = (EFI_HII_PACKAGE_HEADER *) Buffer;
+ break;
+
+ case EFI_HII_PACKAGE_DEVICE_PATH:
+ Package = (EFI_HII_PACKAGE_HEADER *) PackageInstance;
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (Link = Private->DatabaseNotifyList.ForwardLink;
+ Link != &Private->DatabaseNotifyList;
+ Link = Link->ForwardLink
+ ) {
+ Notify = CR (Link, HII_DATABASE_NOTIFY, DatabaseNotifyEntry, HII_DATABASE_NOTIFY_SIGNATURE);
+ if (Notify->NotifyType == NotifyType && Notify->PackageType == PackageType) {
+ //
+ // Check in case PackageGuid is not NULL when Package is GUID package
+ //
+ if (PackageType != EFI_HII_PACKAGE_TYPE_GUID) {
+ Notify->PackageGuid = NULL;
+ }
+ //
+ // Status of Registered Function is unknown so did not check it
+ //
+ Notify->PackageNotifyFn (
+ Notify->PackageType,
+ Notify->PackageGuid,
+ Package,
+ Handle,
+ NotifyType
+ );
+ }
+ }
+
+ SafeFreePool (Buffer);
+ Buffer = NULL;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function insert a GUID package to a package list node.
+
+ @param PackageHdr Pointer to a buffer stored with GUID package
+ information.
+ @param NotifyType The type of change concerning the database.
+ @param PackageList Pointer to a package list which will be inserted
+ to.
+ @param Package Created GUID pacakge
+
+ @retval EFI_SUCCESS Guid Package is inserted successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new
+ Guid package.
+ @retval EFI_INVALID_PARAMETER PackageHdr is NULL or PackageList is NULL.
+
+**/
+STATIC
+EFI_STATUS
+InsertGuidPackage (
+ IN VOID *PackageHdr,
+ IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ OUT HII_GUID_PACKAGE_INSTANCE **Package
+ )
+{
+ HII_GUID_PACKAGE_INSTANCE *GuidPackage;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+
+ if (PackageHdr == NULL || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CopyMem (&PackageHeader, PackageHdr, sizeof (EFI_HII_PACKAGE_HEADER));
+
+ //
+ // Create a GUID package node
+ //
+ GuidPackage = (HII_GUID_PACKAGE_INSTANCE *) AllocateZeroPool (sizeof (HII_GUID_PACKAGE_INSTANCE));
+ if (GuidPackage == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ GuidPackage->GuidPkg = (UINT8 *) AllocateZeroPool (PackageHeader.Length);
+ if (GuidPackage->GuidPkg == NULL) {
+ SafeFreePool (GuidPackage);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ GuidPackage->Signature = HII_GUID_PACKAGE_SIGNATURE;
+ CopyMem (GuidPackage->GuidPkg, PackageHdr, PackageHeader.Length);
+ InsertTailList (&PackageList->GuidPkgHdr, &GuidPackage->GuidEntry);
+ *Package = GuidPackage;
+
+ if (NotifyType == EFI_HII_DATABASE_NOTIFY_ADD_PACK) {
+ PackageList->PackageListHdr.PackageLength += PackageHeader.Length;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function exports GUID packages to a buffer.
+
+ @param Private Hii database private structure.
+ @param Handle Identification of a package list.
+ @param PackageList Pointer to a package list which will be exported.
+ @param UsedSize The length of buffer be used.
+ @param BufferSize Length of the Buffer.
+ @param Buffer Allocated space for storing exported data.
+ @param ResultSize The size of the already exported content of this
+ package list.
+
+ @retval EFI_SUCCESS Guid Packages are exported successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+
+**/
+STATIC
+EFI_STATUS
+ExportGuidPackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ IN UINTN UsedSize,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer,
+ IN OUT UINTN *ResultSize
+ )
+{
+ HII_GUID_PACKAGE_INSTANCE *GuidPackage;
+ LIST_ENTRY *Link;
+ UINTN PackageLength;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+ EFI_STATUS Status;
+
+ if (PackageList == NULL || ResultSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize > 0 && Buffer == NULL ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PackageLength = 0;
+ Status = EFI_SUCCESS;
+
+ for (Link = PackageList->GuidPkgHdr.ForwardLink; Link != &PackageList->GuidPkgHdr; Link = Link->ForwardLink) {
+ GuidPackage = CR (Link, HII_GUID_PACKAGE_INSTANCE, GuidEntry, HII_GUID_PACKAGE_SIGNATURE);
+ CopyMem (&PackageHeader, GuidPackage->GuidPkg, sizeof (EFI_HII_PACKAGE_HEADER));
+ PackageLength += PackageHeader.Length;
+ if (PackageLength + *ResultSize + UsedSize <= BufferSize) {
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_EXPORT_PACK,
+ (VOID *) GuidPackage,
+ EFI_HII_PACKAGE_TYPE_GUID,
+ Handle
+ );
+ ASSERT_EFI_ERROR (Status);
+ CopyMem (Buffer, GuidPackage->GuidPkg, PackageHeader.Length);
+ Buffer = (UINT8 *) Buffer + PackageHeader.Length;
+ }
+ }
+
+ *ResultSize += PackageLength;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function deletes all GUID packages from a package list node.
+
+ @param Private Hii database private data.
+ @param Handle Handle of the package list which contains the to
+ be removed GUID packages.
+ @param PackageList Pointer to a package list that contains removing
+ packages.
+
+ @retval EFI_SUCCESS GUID Package(s) is deleted successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is not valid.
+
+**/
+STATIC
+EFI_STATUS
+RemoveGuidPackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList
+ )
+{
+ LIST_ENTRY *ListHead;
+ HII_GUID_PACKAGE_INSTANCE *Package;
+ EFI_STATUS Status;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+
+ ListHead = &PackageList->GuidPkgHdr;
+
+ while (!IsListEmpty (ListHead)) {
+ Package = CR (
+ ListHead->ForwardLink,
+ HII_GUID_PACKAGE_INSTANCE,
+ GuidEntry,
+ HII_GUID_PACKAGE_SIGNATURE
+ );
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,
+ (VOID *) Package,
+ EFI_HII_PACKAGE_TYPE_GUID,
+ Handle
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ RemoveEntryList (&Package->GuidEntry);
+ CopyMem (&PackageHeader, Package->GuidPkg, sizeof (EFI_HII_PACKAGE_HEADER));
+ PackageList->PackageListHdr.PackageLength -= PackageHeader.Length;
+ SafeFreePool (Package->GuidPkg);
+ SafeFreePool (Package);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function insert a Form package to a package list node.
+
+ @param PackageHdr Pointer to a buffer stored with Form package
+ information.
+ @param NotifyType The type of change concerning the database.
+ @param PackageList Pointer to a package list which will be inserted
+ to.
+ @param Package Created Form package
+
+ @retval EFI_SUCCESS Form Package is inserted successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new
+ Form package.
+ @retval EFI_INVALID_PARAMETER PackageHdr is NULL or PackageList is NULL.
+
+**/
+STATIC
+EFI_STATUS
+InsertFormPackage (
+ IN VOID *PackageHdr,
+ IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ OUT HII_IFR_PACKAGE_INSTANCE **Package
+ )
+{
+ HII_IFR_PACKAGE_INSTANCE *FormPackage;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+
+ if (PackageHdr == NULL || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get the length of the package, including package header itself
+ //
+ CopyMem (&PackageHeader, PackageHdr, sizeof (EFI_HII_PACKAGE_HEADER));
+
+ //
+ // Create a Form package node
+ //
+ FormPackage = (HII_IFR_PACKAGE_INSTANCE *) AllocateZeroPool (sizeof (HII_IFR_PACKAGE_INSTANCE));
+ if (FormPackage == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FormPackage->IfrData = (UINT8 *) AllocateZeroPool (PackageHeader.Length - sizeof (EFI_HII_PACKAGE_HEADER));
+ if (FormPackage->IfrData == NULL) {
+ SafeFreePool (FormPackage);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FormPackage->Signature = HII_IFR_PACKAGE_SIGNATURE;
+ //
+ // Copy Package Header
+ //
+ CopyMem (&FormPackage->FormPkgHdr, &PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
+
+ //
+ // Copy Ifr contents
+ //
+ CopyMem (
+ FormPackage->IfrData,
+ (UINT8 *) PackageHdr + sizeof (EFI_HII_PACKAGE_HEADER),
+ PackageHeader.Length - sizeof (EFI_HII_PACKAGE_HEADER)
+ );
+
+ InsertTailList (&PackageList->FormPkgHdr, &FormPackage->IfrEntry);
+ *Package = FormPackage;
+
+ if (NotifyType == EFI_HII_DATABASE_NOTIFY_ADD_PACK) {
+ PackageList->PackageListHdr.PackageLength += FormPackage->FormPkgHdr.Length;
+ }
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function exports Form packages to a buffer.
+
+ @param Private Hii database private structure.
+ @param Handle Identification of a package list.
+ @param PackageList Pointer to a package list which will be exported.
+ @param UsedSize The length of buffer be used.
+ @param BufferSize Length of the Buffer.
+ @param Buffer Allocated space for storing exported data.
+ @param ResultSize The size of the already exported content of this
+ package list.
+
+ @retval EFI_SUCCESS Form Packages are exported successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+
+**/
+STATIC
+EFI_STATUS
+ExportFormPackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ IN UINTN UsedSize,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer,
+ IN OUT UINTN *ResultSize
+ )
+{
+ HII_IFR_PACKAGE_INSTANCE *FormPackage;
+ UINTN PackageLength;
+ LIST_ENTRY *Link;
+ EFI_STATUS Status;
+
+ if (Private == NULL || PackageList == NULL || ResultSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize > 0 && Buffer == NULL ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PackageLength = 0;
+ Status = EFI_SUCCESS;
+
+ //
+ // Export Form packages.
+ //
+ for (Link = PackageList->FormPkgHdr.ForwardLink; Link != &PackageList->FormPkgHdr; Link = Link->ForwardLink) {
+ FormPackage = CR (Link, HII_IFR_PACKAGE_INSTANCE, IfrEntry, HII_IFR_PACKAGE_SIGNATURE);
+ PackageLength += FormPackage->FormPkgHdr.Length;
+ if (PackageLength + *ResultSize + UsedSize <= BufferSize) {
+ //
+ // Invoke registered notification if exists
+ //
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_EXPORT_PACK,
+ (VOID *) FormPackage,
+ EFI_HII_PACKAGE_FORM,
+ Handle
+ );
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Copy the Form package content.
+ //
+ CopyMem (Buffer, (VOID *) (&FormPackage->FormPkgHdr), sizeof (EFI_HII_PACKAGE_HEADER));
+ Buffer = (UINT8 *) Buffer + sizeof (EFI_HII_PACKAGE_HEADER);
+ CopyMem (
+ Buffer,
+ (VOID *) FormPackage->IfrData,
+ FormPackage->FormPkgHdr.Length - sizeof (EFI_HII_PACKAGE_HEADER)
+ );
+ Buffer = (UINT8 *) Buffer + FormPackage->FormPkgHdr.Length - sizeof (EFI_HII_PACKAGE_HEADER);
+ }
+ }
+
+ *ResultSize += PackageLength;
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+ This function deletes all Form packages from a package list node.
+
+ @param Private Hii database private data.
+ @param Handle Handle of the package list which contains the to
+ be removed Form packages.
+ @param PackageList Pointer to a package list that contains removing
+ packages.
+
+ @retval EFI_SUCCESS Form Package(s) is deleted successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is not valid.
+
+**/
+STATIC
+EFI_STATUS
+RemoveFormPackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList
+ )
+{
+ LIST_ENTRY *ListHead;
+ HII_IFR_PACKAGE_INSTANCE *Package;
+ EFI_STATUS Status;
+
+ ListHead = &PackageList->FormPkgHdr;
+
+ while (!IsListEmpty (ListHead)) {
+ Package = CR (
+ ListHead->ForwardLink,
+ HII_IFR_PACKAGE_INSTANCE,
+ IfrEntry,
+ HII_IFR_PACKAGE_SIGNATURE
+ );
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,
+ (VOID *) Package,
+ EFI_HII_PACKAGE_FORM,
+ Handle
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ RemoveEntryList (&Package->IfrEntry);
+ PackageList->PackageListHdr.PackageLength -= Package->FormPkgHdr.Length;
+ SafeFreePool (Package->IfrData);
+ SafeFreePool (Package);
+
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ This function insert a String package to a package list node.
+
+ @param Private Hii database private structure.
+ @param PackageHdr Pointer to a buffer stored with String package
+ information.
+ @param NotifyType The type of change concerning the database.
+ @param PackageList Pointer to a package list which will be inserted
+ to.
+ @param Package Created String package
+
+ @retval EFI_SUCCESS String Package is inserted successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new
+ String package.
+ @retval EFI_INVALID_PARAMETER PackageHdr is NULL or PackageList is NULL.
+ @retval EFI_UNSUPPORTED A string package with the same language already
+ exists in current package list.
+
+**/
+STATIC
+EFI_STATUS
+InsertStringPackage (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN VOID *PackageHdr,
+ IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ OUT HII_STRING_PACKAGE_INSTANCE **Package
+
+ )
+{
+ HII_STRING_PACKAGE_INSTANCE *StringPackage;
+ UINT32 HeaderSize;
+ EFI_STATUS Status;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+ CHAR8 *Language;
+ UINT32 LanguageSize;
+ LIST_ENTRY *Link;
+
+ if (Private == NULL || PackageHdr == NULL || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Private->Signature != HII_DATABASE_PRIVATE_DATA_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CopyMem (&PackageHeader, PackageHdr, sizeof (EFI_HII_PACKAGE_HEADER));
+ CopyMem (&HeaderSize, (UINT8 *) PackageHdr + sizeof (EFI_HII_PACKAGE_HEADER), sizeof (UINT32));
+
+ //
+ // It is illegal to have two string packages with same language within one packagelist
+ // since the stringid will be duplicate if so. Check it to avoid this potential issue.
+ //
+ LanguageSize = HeaderSize - sizeof (EFI_HII_STRING_PACKAGE_HDR) + sizeof (CHAR8);
+ Language = (CHAR8 *) AllocateZeroPool (LanguageSize);
+ if (Language == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ AsciiStrCpy (Language, (CHAR8 *) PackageHdr + HeaderSize - LanguageSize);
+ for (Link = PackageList->StringPkgHdr.ForwardLink; Link != &PackageList->StringPkgHdr; Link = Link->ForwardLink) {
+ StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
+ if (R8_EfiLibCompareLanguage (Language, StringPackage->StringPkgHdr->Language)) {
+ SafeFreePool (Language);
+ return EFI_UNSUPPORTED;
+ }
+ }
+ SafeFreePool (Language);
+
+ //
+ // Create a String package node
+ //
+ StringPackage = (HII_STRING_PACKAGE_INSTANCE *) AllocateZeroPool (sizeof (HII_STRING_PACKAGE_INSTANCE));
+ if (StringPackage == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ StringPackage->StringPkgHdr = (EFI_HII_STRING_PACKAGE_HDR *) AllocateZeroPool (HeaderSize);
+ if (StringPackage->StringPkgHdr == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ StringPackage->StringBlock = (UINT8 *) AllocateZeroPool (PackageHeader.Length - HeaderSize);
+ if (StringPackage->StringBlock == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ StringPackage->Signature = HII_STRING_PACKAGE_SIGNATURE;
+ StringPackage->FontId = 0;
+ InitializeListHead (&StringPackage->FontInfoList);
+
+ //
+ // Copy the String package header.
+ //
+ CopyMem (StringPackage->StringPkgHdr, PackageHdr, HeaderSize);
+
+ //
+ // Copy the String blocks
+ //
+ CopyMem (
+ StringPackage->StringBlock,
+ (UINT8 *) PackageHdr + HeaderSize,
+ PackageHeader.Length - HeaderSize
+ );
+
+ //
+ // Collect all font block info
+ //
+ Status = FindStringBlock (Private, StringPackage, (EFI_STRING_ID) (-1), NULL, NULL, NULL, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Insert to String package array
+ //
+ InsertTailList (&PackageList->StringPkgHdr, &StringPackage->StringEntry);
+ *Package = StringPackage;
+
+ if (NotifyType == EFI_HII_DATABASE_NOTIFY_ADD_PACK) {
+ PackageList->PackageListHdr.PackageLength += StringPackage->StringPkgHdr->Header.Length;
+ }
+
+ return EFI_SUCCESS;
+
+Error:
+
+ SafeFreePool (StringPackage->StringBlock);
+ SafeFreePool (StringPackage->StringPkgHdr);
+ SafeFreePool (StringPackage);
+ return Status;
+
+}
+
+
+/**
+ This function exports String packages to a buffer.
+
+ @param Private Hii database private structure.
+ @param Handle Identification of a package list.
+ @param PackageList Pointer to a package list which will be exported.
+ @param UsedSize The length of buffer be used.
+ @param BufferSize Length of the Buffer.
+ @param Buffer Allocated space for storing exported data.
+ @param ResultSize The size of the already exported content of this
+ package list.
+
+ @retval EFI_SUCCESS String Packages are exported successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+
+**/
+STATIC
+EFI_STATUS
+ExportStringPackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ IN UINTN UsedSize,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer,
+ IN OUT UINTN *ResultSize
+ )
+{
+ LIST_ENTRY *Link;
+ UINTN PackageLength;
+ EFI_STATUS Status;
+ HII_STRING_PACKAGE_INSTANCE *StringPackage;
+
+ if (Private == NULL || PackageList == NULL || ResultSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize > 0 && Buffer == NULL ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PackageLength = 0;
+ Status = EFI_SUCCESS;
+
+ for (Link = PackageList->StringPkgHdr.ForwardLink; Link != &PackageList->StringPkgHdr; Link = Link->ForwardLink) {
+ StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
+ PackageLength += StringPackage->StringPkgHdr->Header.Length;
+ if (PackageLength + *ResultSize + UsedSize <= BufferSize) {
+ //
+ // Invoke registered notification function with EXPORT_PACK notify type
+ //
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_EXPORT_PACK,
+ (VOID *) StringPackage,
+ EFI_HII_PACKAGE_STRINGS,
+ Handle
+ );
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Copy String package header
+ //
+ CopyMem (Buffer, StringPackage->StringPkgHdr, StringPackage->StringPkgHdr->HdrSize);
+ Buffer = (UINT8 *) Buffer + StringPackage->StringPkgHdr->HdrSize;
+
+ //
+ // Copy String blocks information
+ //
+ CopyMem (
+ Buffer,
+ StringPackage->StringBlock,
+ StringPackage->StringPkgHdr->Header.Length - StringPackage->StringPkgHdr->HdrSize
+ );
+ Buffer = (UINT8 *) Buffer + StringPackage->StringPkgHdr->Header.Length - StringPackage->StringPkgHdr->HdrSize;
+ }
+ }
+
+ *ResultSize += PackageLength;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function deletes all String packages from a package list node.
+
+ @param Private Hii database private data.
+ @param Handle Handle of the package list which contains the to
+ be removed String packages.
+ @param PackageList Pointer to a package list that contains removing
+ packages.
+
+ @retval EFI_SUCCESS String Package(s) is deleted successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is not valid.
+
+**/
+STATIC
+EFI_STATUS
+RemoveStringPackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList
+ )
+{
+ LIST_ENTRY *ListHead;
+ HII_STRING_PACKAGE_INSTANCE *Package;
+ HII_FONT_INFO *FontInfo;
+ EFI_STATUS Status;
+
+ ListHead = &PackageList->StringPkgHdr;
+
+ while (!IsListEmpty (ListHead)) {
+ Package = CR (
+ ListHead->ForwardLink,
+ HII_STRING_PACKAGE_INSTANCE,
+ StringEntry,
+ HII_STRING_PACKAGE_SIGNATURE
+ );
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,
+ (VOID *) Package,
+ EFI_HII_PACKAGE_STRINGS,
+ Handle
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ RemoveEntryList (&Package->StringEntry);
+ PackageList->PackageListHdr.PackageLength -= Package->StringPkgHdr->Header.Length;
+ SafeFreePool (Package->StringBlock);
+ SafeFreePool (Package->StringPkgHdr);
+ //
+ // Delete font information
+ //
+ while (!IsListEmpty (&Package->FontInfoList)) {
+ FontInfo = CR (
+ Package->FontInfoList.ForwardLink,
+ HII_FONT_INFO,
+ Entry,
+ HII_FONT_INFO_SIGNATURE
+ );
+ RemoveEntryList (&FontInfo->Entry);
+ SafeFreePool (FontInfo);
+ }
+
+ SafeFreePool (Package);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function insert a Font package to a package list node.
+
+ @param Private Hii database private structure.
+ @param PackageHdr Pointer to a buffer stored with Font package
+ information.
+ @param NotifyType The type of change concerning the database.
+ @param PackageList Pointer to a package list which will be inserted
+ to.
+ @param Package Created Font package
+
+ @retval EFI_SUCCESS Font Package is inserted successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new
+ Font package.
+ @retval EFI_INVALID_PARAMETER PackageHdr is NULL or PackageList is NULL.
+ @retval EFI_UNSUPPORTED A font package with same EFI_FONT_INFO already
+ exists in current hii database.
+
+**/
+STATIC
+EFI_STATUS
+InsertFontPackage (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN VOID *PackageHdr,
+ IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ OUT HII_FONT_PACKAGE_INSTANCE **Package
+ )
+{
+ HII_FONT_PACKAGE_INSTANCE *FontPackage;
+ EFI_HII_FONT_PACKAGE_HDR *FontPkgHdr;
+ UINT32 HeaderSize;
+ EFI_STATUS Status;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+ EFI_FONT_INFO *FontInfo;
+ UINT32 FontInfoSize;
+ HII_GLOBAL_FONT_INFO *GlobalFont;
+
+ if (Private == NULL || PackageHdr == NULL || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CopyMem (&PackageHeader, PackageHdr, sizeof (EFI_HII_PACKAGE_HEADER));
+ CopyMem (&HeaderSize, (UINT8 *) PackageHdr + sizeof (EFI_HII_PACKAGE_HEADER), sizeof (UINT32));
+
+ FontInfo = NULL;
+ FontPackage = NULL;
+ GlobalFont = NULL;
+
+ //
+ // It is illegal to have two font packages with same EFI_FONT_INFO within hii
+ // database. EFI_FONT_INFO (FontName, FontSize, FontStyle) describes font's
+ // attributes and identify a font uniquely.
+ //
+ FontPkgHdr = (EFI_HII_FONT_PACKAGE_HDR *) AllocateZeroPool (HeaderSize);
+ if (FontPkgHdr == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+ CopyMem (FontPkgHdr, PackageHdr, HeaderSize);
+
+ FontInfoSize = sizeof (EFI_FONT_INFO) + HeaderSize - sizeof (EFI_HII_FONT_PACKAGE_HDR);
+ FontInfo = (EFI_FONT_INFO *) AllocateZeroPool (FontInfoSize);
+ if (FontInfo == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+ FontInfo->FontStyle = FontPkgHdr->FontStyle;
+ FontInfo->FontSize = FontPkgHdr->Cell.Height;
+ StrCpy (FontInfo->FontName, FontPkgHdr->FontFamily);
+
+ if (IsFontInfoExisted (Private, FontInfo, NULL, NULL, NULL)) {
+ Status = EFI_UNSUPPORTED;
+ goto Error;
+ }
+
+ //
+ // Create a Font package node
+ //
+ FontPackage = (HII_FONT_PACKAGE_INSTANCE *) AllocateZeroPool (sizeof (HII_FONT_PACKAGE_INSTANCE));
+ if (FontPackage == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+ FontPackage->Signature = HII_FONT_PACKAGE_SIGNATURE;
+ FontPackage->FontPkgHdr = FontPkgHdr;
+ InitializeListHead (&FontPackage->GlyphInfoList);
+
+ FontPackage->GlyphBlock = (UINT8 *) AllocateZeroPool (PackageHeader.Length - HeaderSize);
+ if (FontPackage->GlyphBlock == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+ CopyMem (FontPackage->GlyphBlock, (UINT8 *) PackageHdr + HeaderSize, PackageHeader.Length - HeaderSize);
+
+ //
+ // Collect all default character cell information and backup in GlyphInfoList.
+ //
+ Status = FindGlyphBlock (FontPackage, (CHAR16) (-1), NULL, NULL, NULL);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ //
+ // This font package describes an unique EFI_FONT_INFO. Backup it in global
+ // font info list.
+ //
+ GlobalFont = (HII_GLOBAL_FONT_INFO *) AllocateZeroPool (sizeof (HII_GLOBAL_FONT_INFO));
+ if (GlobalFont == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+ GlobalFont->Signature = HII_GLOBAL_FONT_INFO_SIGNATURE;
+ GlobalFont->FontPackage = FontPackage;
+ GlobalFont->FontInfoSize = FontInfoSize;
+ GlobalFont->FontInfo = FontInfo;
+ InsertTailList (&Private->FontInfoList, &GlobalFont->Entry);
+
+ //
+ // Insert this font package to Font package array
+ //
+ InsertTailList (&PackageList->FontPkgHdr, &FontPackage->FontEntry);
+ *Package = FontPackage;
+
+ if (NotifyType == EFI_HII_DATABASE_NOTIFY_ADD_PACK) {
+ PackageList->PackageListHdr.PackageLength += FontPackage->FontPkgHdr->Header.Length;
+ }
+
+ return EFI_SUCCESS;
+
+Error:
+
+ SafeFreePool (FontPkgHdr);
+ SafeFreePool (FontInfo);
+ SafeFreePool (FontPackage->GlyphBlock);
+ SafeFreePool (FontPackage);
+ SafeFreePool (GlobalFont);
+
+ return Status;
+
+}
+
+
+/**
+ This function exports Font packages to a buffer.
+
+ @param Private Hii database private structure.
+ @param Handle Identification of a package list.
+ @param PackageList Pointer to a package list which will be exported.
+ @param UsedSize The length of buffer be used.
+ @param BufferSize Length of the Buffer.
+ @param Buffer Allocated space for storing exported data.
+ @param ResultSize The size of the already exported content of this
+ package list.
+
+ @retval EFI_SUCCESS Font Packages are exported successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+
+**/
+STATIC
+EFI_STATUS
+ExportFontPackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ IN UINTN UsedSize,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer,
+ IN OUT UINTN *ResultSize
+ )
+{
+ LIST_ENTRY *Link;
+ UINTN PackageLength;
+ EFI_STATUS Status;
+ HII_FONT_PACKAGE_INSTANCE *Package;
+
+
+ if (Private == NULL || PackageList == NULL || ResultSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize > 0 && Buffer == NULL ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PackageLength = 0;
+ Status = EFI_SUCCESS;
+
+ for (Link = PackageList->FontPkgHdr.ForwardLink; Link != &PackageList->FontPkgHdr; Link = Link->ForwardLink) {
+ Package = CR (Link, HII_FONT_PACKAGE_INSTANCE, FontEntry, HII_FONT_PACKAGE_SIGNATURE);
+ PackageLength += Package->FontPkgHdr->Header.Length;
+ if (PackageLength + *ResultSize + UsedSize <= BufferSize) {
+ //
+ // Invoke registered notification function with EXPORT_PACK notify type
+ //
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_EXPORT_PACK,
+ (VOID *) Package,
+ EFI_HII_PACKAGE_FONTS,
+ Handle
+ );
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Copy Font package header
+ //
+ CopyMem (Buffer, Package->FontPkgHdr, Package->FontPkgHdr->HdrSize);
+ Buffer = (UINT8 *) Buffer + Package->FontPkgHdr->HdrSize;
+
+ //
+ // Copy Glyph blocks information
+ //
+ CopyMem (
+ Buffer,
+ Package->GlyphBlock,
+ Package->FontPkgHdr->Header.Length - Package->FontPkgHdr->HdrSize
+ );
+ Buffer = (UINT8 *) Buffer + Package->FontPkgHdr->Header.Length - Package->FontPkgHdr->HdrSize;
+ }
+ }
+
+ *ResultSize += PackageLength;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function deletes all Font packages from a package list node.
+
+ @param Private Hii database private data.
+ @param Handle Handle of the package list which contains the to
+ be removed Font packages.
+ @param PackageList Pointer to a package list that contains removing
+ packages.
+
+ @retval EFI_SUCCESS Font Package(s) is deleted successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is not valid.
+
+**/
+STATIC
+EFI_STATUS
+RemoveFontPackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList
+ )
+{
+ LIST_ENTRY *ListHead;
+ HII_FONT_PACKAGE_INSTANCE *Package;
+ EFI_STATUS Status;
+ HII_GLYPH_INFO *GlyphInfo;
+ LIST_ENTRY *Link;
+ HII_GLOBAL_FONT_INFO *GlobalFont;
+
+ ListHead = &PackageList->FontPkgHdr;
+
+ while (!IsListEmpty (ListHead)) {
+ Package = CR (
+ ListHead->ForwardLink,
+ HII_FONT_PACKAGE_INSTANCE,
+ FontEntry,
+ HII_FONT_PACKAGE_SIGNATURE
+ );
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,
+ (VOID *) Package,
+ EFI_HII_PACKAGE_FONTS,
+ Handle
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ RemoveEntryList (&Package->FontEntry);
+ PackageList->PackageListHdr.PackageLength -= Package->FontPkgHdr->Header.Length;
+ SafeFreePool (Package->GlyphBlock);
+ SafeFreePool (Package->FontPkgHdr);
+ //
+ // Delete default character cell information
+ //
+ while (!IsListEmpty (&Package->GlyphInfoList)) {
+ GlyphInfo = CR (
+ Package->GlyphInfoList.ForwardLink,
+ HII_GLYPH_INFO,
+ Entry,
+ HII_GLYPH_INFO_SIGNATURE
+ );
+ RemoveEntryList (&GlyphInfo->Entry);
+ SafeFreePool (GlyphInfo);
+ }
+
+ //
+ // Remove corresponding global font info
+ //
+ for (Link = Private->FontInfoList.ForwardLink; Link != &Private->FontInfoList; Link = Link->ForwardLink) {
+ GlobalFont = CR (Link, HII_GLOBAL_FONT_INFO, Entry, HII_GLOBAL_FONT_INFO_SIGNATURE);
+ if (GlobalFont->FontPackage == Package) {
+ RemoveEntryList (&GlobalFont->Entry);
+ SafeFreePool (GlobalFont->FontInfo);
+ SafeFreePool (GlobalFont);
+ break;
+ }
+ }
+
+ SafeFreePool (Package);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function insert a Image package to a package list node.
+
+ @param PackageHdr Pointer to a buffer stored with Image package
+ information.
+ @param NotifyType The type of change concerning the database.
+ @param PackageList Pointer to a package list which will be inserted
+ to.
+ @param Package Created Image package
+
+ @retval EFI_SUCCESS Image Package is inserted successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new
+ Image package.
+ @retval EFI_INVALID_PARAMETER PackageHdr is NULL or PackageList is NULL.
+
+**/
+STATIC
+EFI_STATUS
+InsertImagePackage (
+ IN VOID *PackageHdr,
+ IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ OUT HII_IMAGE_PACKAGE_INSTANCE **Package
+ )
+{
+ HII_IMAGE_PACKAGE_INSTANCE *ImagePackage;
+ UINT32 PaletteSize;
+ UINT32 ImageSize;
+ UINT16 Index;
+ EFI_HII_IMAGE_PALETTE_INFO_HEADER *PaletteHdr;
+ EFI_HII_IMAGE_PALETTE_INFO *PaletteInfo;
+ UINT32 PaletteInfoOffset;
+ UINT32 ImageInfoOffset;
+ UINT16 CurrentSize;
+
+ if (PackageHdr == NULL || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Less than one image package is allowed in one package list.
+ //
+ if (PackageList->ImagePkg != NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Create a Image package node
+ //
+ ImagePackage = (HII_IMAGE_PACKAGE_INSTANCE *) AllocateZeroPool (sizeof (HII_IMAGE_PACKAGE_INSTANCE));
+ if (ImagePackage == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Copy the Image package header.
+ //
+ CopyMem (&ImagePackage->ImagePkgHdr, PackageHdr, sizeof (EFI_HII_IMAGE_PACKAGE_HDR));
+
+ PaletteInfoOffset = ImagePackage->ImagePkgHdr.PaletteInfoOffset;
+ ImageInfoOffset = ImagePackage->ImagePkgHdr.ImageInfoOffset;
+
+ //
+ // If PaletteInfoOffset is zero, there are no palettes in this image package.
+ //
+ PaletteSize = 0;
+ ImagePackage->PaletteBlock = NULL;
+ if (PaletteInfoOffset != 0) {
+ PaletteHdr = (EFI_HII_IMAGE_PALETTE_INFO_HEADER *) ((UINT8 *) PackageHdr + PaletteInfoOffset);
+ PaletteSize = sizeof (EFI_HII_IMAGE_PALETTE_INFO_HEADER);
+ PaletteInfo = (EFI_HII_IMAGE_PALETTE_INFO *) ((UINT8 *) PaletteHdr + PaletteSize);
+
+ for (Index = 0; Index < PaletteHdr->PaletteCount; Index++) {
+ CopyMem (&CurrentSize, PaletteInfo, sizeof (UINT16));
+ CurrentSize += sizeof (UINT16);
+ PaletteSize += (UINT32) CurrentSize;
+ PaletteInfo = (EFI_HII_IMAGE_PALETTE_INFO *) ((UINT8 *) PaletteInfo + CurrentSize);
+ }
+
+ ImagePackage->PaletteBlock = (UINT8 *) AllocateZeroPool (PaletteSize);
+ if (ImagePackage->PaletteBlock == NULL) {
+ SafeFreePool (ImagePackage);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (
+ ImagePackage->PaletteBlock,
+ (UINT8 *) PackageHdr + PaletteInfoOffset,
+ PaletteSize
+ );
+ }
+
+ //
+ // If ImageInfoOffset is zero, there are no images in this package.
+ //
+ ImageSize = 0;
+ ImagePackage->ImageBlock = NULL;
+ if (ImageInfoOffset != 0) {
+ ImageSize = ImagePackage->ImagePkgHdr.Header.Length -
+ sizeof (EFI_HII_IMAGE_PACKAGE_HDR) - PaletteSize;
+ ImagePackage->ImageBlock = (UINT8 *) AllocateZeroPool (ImageSize);
+ if (ImagePackage->ImageBlock == NULL) {
+ SafeFreePool (ImagePackage->PaletteBlock);
+ SafeFreePool (ImagePackage);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (
+ ImagePackage->ImageBlock,
+ (UINT8 *) PackageHdr + ImageInfoOffset,
+ ImageSize
+ );
+ }
+
+ ImagePackage->ImageBlockSize = ImageSize;
+ ImagePackage->PaletteInfoSize = PaletteSize;
+ PackageList->ImagePkg = ImagePackage;
+ *Package = ImagePackage;
+
+ if (NotifyType == EFI_HII_DATABASE_NOTIFY_ADD_PACK) {
+ PackageList->PackageListHdr.PackageLength += ImagePackage->ImagePkgHdr.Header.Length;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function exports Image packages to a buffer.
+
+ @param Private Hii database private structure.
+ @param Handle Identification of a package list.
+ @param PackageList Pointer to a package list which will be exported.
+ @param UsedSize The length of buffer be used.
+ @param BufferSize Length of the Buffer.
+ @param Buffer Allocated space for storing exported data.
+ @param ResultSize The size of the already exported content of this
+ package list.
+
+ @retval EFI_SUCCESS Image Packages are exported successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+
+**/
+STATIC
+EFI_STATUS
+ExportImagePackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ IN UINTN UsedSize,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer,
+ IN OUT UINTN *ResultSize
+ )
+{
+ UINTN PackageLength;
+ EFI_STATUS Status;
+ HII_IMAGE_PACKAGE_INSTANCE *Package;
+
+
+ if (Private == NULL || PackageList == NULL || ResultSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize > 0 && Buffer == NULL ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Package = PackageList->ImagePkg;
+
+ if (Package == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ PackageLength = Package->ImagePkgHdr.Header.Length;
+
+ if (PackageLength + *ResultSize + UsedSize <= BufferSize) {
+ //
+ // Invoke registered notification function with EXPORT_PACK notify type
+ //
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_EXPORT_PACK,
+ (VOID *) Package,
+ EFI_HII_PACKAGE_IMAGES,
+ Handle
+ );
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (Package->ImagePkgHdr.Header.Length ==
+ sizeof (EFI_HII_IMAGE_PACKAGE_HDR) + Package->ImageBlockSize + Package->PaletteInfoSize);
+ //
+ // Copy Image package header,
+ // then justify the offset for image info and palette info in the header.
+ //
+ CopyMem (Buffer, &Package->ImagePkgHdr, sizeof (EFI_HII_IMAGE_PACKAGE_HDR));
+ Buffer = (UINT8 *) Buffer + sizeof (EFI_HII_IMAGE_PACKAGE_HDR);
+
+ //
+ // Copy Image blocks information
+ //
+ if (Package->ImageBlockSize != 0) {
+ CopyMem (Buffer, Package->ImageBlock, Package->ImageBlockSize);
+ Buffer = (UINT8 *) Buffer + Package->ImageBlockSize;
+ }
+ //
+ // Copy Palette information
+ //
+ if (Package->PaletteInfoSize != 0) {
+ CopyMem (Buffer, Package->PaletteBlock, Package->PaletteInfoSize);
+ Buffer = (UINT8 *) Buffer + Package->PaletteInfoSize;
+ }
+ }
+
+ *ResultSize += PackageLength;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function deletes Image package from a package list node.
+
+ @param Private Hii database private data.
+ @param Handle Handle of the package list which contains the to
+ be removed Image packages.
+ @param PackageList Package List which contains the to be removed
+ Image package.
+
+ @retval EFI_SUCCESS Image Package(s) is deleted successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is not valid.
+
+**/
+STATIC
+EFI_STATUS
+RemoveImagePackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList
+ )
+{
+ HII_IMAGE_PACKAGE_INSTANCE *Package;
+ EFI_STATUS Status;
+
+ Package = PackageList->ImagePkg;
+
+ //
+ // Image package does not exist, return directly.
+ //
+ if (Package == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,
+ (VOID *) Package,
+ EFI_HII_PACKAGE_IMAGES,
+ Handle
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PackageList->PackageListHdr.PackageLength -= Package->ImagePkgHdr.Header.Length;
+
+ SafeFreePool (Package->ImageBlock);
+ SafeFreePool (Package->PaletteBlock);
+ SafeFreePool (Package);
+
+ PackageList->ImagePkg = NULL;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function insert a Simple Font package to a package list node.
+
+ @param PackageHdr Pointer to a buffer stored with Simple Font
+ package information.
+ @param NotifyType The type of change concerning the database.
+ @param PackageList Pointer to a package list which will be inserted
+ to.
+ @param Package Created Simple Font package
+
+ @retval EFI_SUCCESS Simple Font Package is inserted successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new
+ Simple Font package.
+ @retval EFI_INVALID_PARAMETER PackageHdr is NULL or PackageList is NULL.
+
+**/
+STATIC
+EFI_STATUS
+InsertSimpleFontPackage (
+ IN VOID *PackageHdr,
+ IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ OUT HII_SIMPLE_FONT_PACKAGE_INSTANCE **Package
+ )
+{
+ HII_SIMPLE_FONT_PACKAGE_INSTANCE *SimpleFontPackage;
+ EFI_STATUS Status;
+ EFI_HII_PACKAGE_HEADER Header;
+
+ if (PackageHdr == NULL || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Create a Simple Font package node
+ //
+ SimpleFontPackage = AllocateZeroPool (sizeof (HII_SIMPLE_FONT_PACKAGE_INSTANCE));
+ if (SimpleFontPackage == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+ SimpleFontPackage->Signature = HII_S_FONT_PACKAGE_SIGNATURE;
+
+ //
+ // Copy the Simple Font package.
+ //
+ CopyMem (&Header, PackageHdr, sizeof (EFI_HII_PACKAGE_HEADER));
+
+ SimpleFontPackage->SimpleFontPkgHdr = AllocateZeroPool (Header.Length);
+ if (SimpleFontPackage->SimpleFontPkgHdr == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ CopyMem (SimpleFontPackage->SimpleFontPkgHdr, PackageHdr, Header.Length);
+
+ //
+ // Insert to Simple Font package array
+ //
+ InsertTailList (&PackageList->SimpleFontPkgHdr, &SimpleFontPackage->SimpleFontEntry);
+ *Package = SimpleFontPackage;
+
+ if (NotifyType == EFI_HII_DATABASE_NOTIFY_ADD_PACK) {
+ PackageList->PackageListHdr.PackageLength += Header.Length;
+ }
+
+ return EFI_SUCCESS;
+
+Error:
+
+ SafeFreePool (SimpleFontPackage->SimpleFontPkgHdr);
+ SafeFreePool (SimpleFontPackage);
+ return Status;
+}
+
+
+/**
+ This function exports SimpleFont packages to a buffer.
+
+ @param Private Hii database private structure.
+ @param Handle Identification of a package list.
+ @param PackageList Pointer to a package list which will be exported.
+ @param UsedSize The length of buffer be used.
+ @param BufferSize Length of the Buffer.
+ @param Buffer Allocated space for storing exported data.
+ @param ResultSize The size of the already exported content of this
+ package list.
+
+ @retval EFI_SUCCESS SimpleFont Packages are exported successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+
+**/
+STATIC
+EFI_STATUS
+ExportSimpleFontPackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ IN UINTN UsedSize,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer,
+ IN OUT UINTN *ResultSize
+ )
+{
+ LIST_ENTRY *Link;
+ UINTN PackageLength;
+ EFI_STATUS Status;
+ HII_SIMPLE_FONT_PACKAGE_INSTANCE *Package;
+
+ if (Private == NULL || PackageList == NULL || ResultSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize > 0 && Buffer == NULL ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PackageLength = 0;
+ Status = EFI_SUCCESS;
+
+ for (Link = PackageList->SimpleFontPkgHdr.ForwardLink; Link != &PackageList->SimpleFontPkgHdr; Link = Link->ForwardLink) {
+ Package = CR (Link, HII_SIMPLE_FONT_PACKAGE_INSTANCE, SimpleFontEntry, HII_S_FONT_PACKAGE_SIGNATURE);
+ PackageLength += Package->SimpleFontPkgHdr->Header.Length;
+ if (PackageLength + *ResultSize + UsedSize <= BufferSize) {
+ //
+ // Invoke registered notification function with EXPORT_PACK notify type
+ //
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_EXPORT_PACK,
+ (VOID *) Package,
+ EFI_HII_PACKAGE_SIMPLE_FONTS,
+ Handle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Copy SimpleFont package
+ //
+ CopyMem (Buffer, Package->SimpleFontPkgHdr, Package->SimpleFontPkgHdr->Header.Length);
+ Buffer = (UINT8 *) Buffer + Package->SimpleFontPkgHdr->Header.Length;
+ }
+ }
+
+ *ResultSize += PackageLength;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function deletes all Simple Font packages from a package list node.
+
+ @param Private Hii database private data.
+ @param Handle Handle of the package list which contains the to
+ be removed Simple Font packages.
+ @param PackageList Pointer to a package list that contains removing
+ packages.
+
+ @retval EFI_SUCCESS Simple Font Package(s) is deleted successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is not valid.
+
+**/
+STATIC
+EFI_STATUS
+RemoveSimpleFontPackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList
+ )
+{
+ LIST_ENTRY *ListHead;
+ HII_SIMPLE_FONT_PACKAGE_INSTANCE *Package;
+ EFI_STATUS Status;
+
+ ListHead = &PackageList->SimpleFontPkgHdr;
+
+ while (!IsListEmpty (ListHead)) {
+ Package = CR (
+ ListHead->ForwardLink,
+ HII_SIMPLE_FONT_PACKAGE_INSTANCE,
+ SimpleFontEntry,
+ HII_S_FONT_PACKAGE_SIGNATURE
+ );
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,
+ (VOID *) Package,
+ EFI_HII_PACKAGE_SIMPLE_FONTS,
+ Handle
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ RemoveEntryList (&Package->SimpleFontEntry);
+ PackageList->PackageListHdr.PackageLength -= Package->SimpleFontPkgHdr->Header.Length;
+ SafeFreePool (Package->SimpleFontPkgHdr);
+ SafeFreePool (Package);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function insert a Device path package to a package list node.
+
+ @param DevicePath Pointer to a EFI_DEVICE_PATH_PROTOCOL protocol
+ instance
+ @param NotifyType The type of change concerning the database.
+ @param PackageList Pointer to a package list which will be inserted
+ to.
+
+ @retval EFI_SUCCESS Device path Package is inserted successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new
+ Device path package.
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL or PackageList is NULL.
+
+**/
+STATIC
+EFI_STATUS
+InsertDevicePathPackage (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList
+ )
+{
+ UINT32 PackageLength;
+ EFI_HII_PACKAGE_HEADER Header;
+
+ if (DevicePath == NULL || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Less than one device path package is allowed in one package list.
+ //
+ if (PackageList->DevicePathPkg != NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PackageLength = (UINT32) GetDevicePathSize (DevicePath) + sizeof (EFI_HII_PACKAGE_HEADER);
+ PackageList->DevicePathPkg = (UINT8 *) AllocateZeroPool (PackageLength);
+ if (PackageList->DevicePathPkg == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Header.Length = PackageLength;
+ Header.Type = EFI_HII_PACKAGE_DEVICE_PATH;
+ CopyMem (PackageList->DevicePathPkg, &Header, sizeof (EFI_HII_PACKAGE_HEADER));
+ CopyMem (
+ PackageList->DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER),
+ DevicePath,
+ PackageLength - sizeof (EFI_HII_PACKAGE_HEADER)
+ );
+
+ //
+ // Since Device Path package is created by NewPackageList, either NEW_PACK
+ // or ADD_PACK should increase the length of package list.
+ //
+ PackageList->PackageListHdr.PackageLength += PackageLength;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function exports device path package to a buffer.
+
+ @param Private Hii database private structure.
+ @param Handle Identification of a package list.
+ @param PackageList Pointer to a package list which will be exported.
+ @param UsedSize The length of buffer be used.
+ @param BufferSize Length of the Buffer.
+ @param Buffer Allocated space for storing exported data.
+ @param ResultSize The size of the already exported content of this
+ package list.
+
+ @retval EFI_SUCCESS Device path Package is exported successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+
+**/
+STATIC
+EFI_STATUS
+ExportDevicePathPackage (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ IN UINTN UsedSize,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer,
+ IN OUT UINTN *ResultSize
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Package;
+ EFI_HII_PACKAGE_HEADER Header;
+
+ if (Private == NULL || PackageList == NULL || ResultSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (BufferSize > 0 && Buffer == NULL ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Package = PackageList->DevicePathPkg;
+
+ if (Package == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ CopyMem (&Header, Package, sizeof (EFI_HII_PACKAGE_HEADER));
+
+ if (Header.Length + *ResultSize + UsedSize <= BufferSize) {
+ //
+ // Invoke registered notification function with EXPORT_PACK notify type
+ //
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_EXPORT_PACK,
+ (VOID *) Package,
+ EFI_HII_PACKAGE_DEVICE_PATH,
+ Handle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Copy Device path package
+ //
+ CopyMem (Buffer, Package, Header.Length);
+ }
+
+ *ResultSize += Header.Length;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function deletes Device Path package from a package list node.
+
+ @param Private Hii database private data.
+ @param Handle Handle of the package list.
+ @param PackageList Package List which contains the to be removed
+ Device Path package.
+
+ @retval EFI_SUCCESS Device Path Package is deleted successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is not valid.
+
+**/
+STATIC
+EFI_STATUS
+RemoveDevicePathPackage (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Package;
+ EFI_HII_PACKAGE_HEADER Header;
+
+ Package = PackageList->DevicePathPkg;
+
+ //
+ // No device path, return directly.
+ //
+ if (Package == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,
+ (VOID *) Package,
+ EFI_HII_PACKAGE_DEVICE_PATH,
+ Handle
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CopyMem (&Header, Package, sizeof (EFI_HII_PACKAGE_HEADER));
+ PackageList->PackageListHdr.PackageLength -= Header.Length;
+
+ SafeFreePool (Package);
+
+ PackageList->DevicePathPkg = NULL;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function will insert a device path package to package list firstly then
+ invoke notification functions if any.
+
+ @param Private Hii database private structure.
+ @param NotifyType The type of change concerning the database.
+ @param DevicePath Pointer to a EFI_DEVICE_PATH_PROTOCOL protocol
+ instance
+ @param DatabaseRecord Pointer to a database record contains a package
+ list which will be inserted to.
+
+ @retval EFI_SUCCESS Device path Package is inserted successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new
+ Device path package.
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL or PackageList is NULL.
+
+**/
+STATIC
+EFI_STATUS
+AddDevicePathPackage (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN OUT HII_DATABASE_RECORD *DatabaseRecord
+ )
+{
+ EFI_STATUS Status;
+
+ if (DevicePath == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ ASSERT (Private != NULL);
+ ASSERT (DatabaseRecord != NULL);
+
+ //
+ // Create a device path package and insert to packagelist
+ //
+ Status = InsertDevicePathPackage (
+ DevicePath,
+ NotifyType,
+ DatabaseRecord->PackageList
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return InvokeRegisteredFunction (
+ Private,
+ NotifyType,
+ (VOID *) DatabaseRecord->PackageList->DevicePathPkg,
+ EFI_HII_PACKAGE_DEVICE_PATH,
+ DatabaseRecord->Handle
+ );
+}
+
+
+/**
+ This function insert a Keyboard Layout package to a package list node.
+
+ @param PackageHdr Pointer to a buffer stored with Keyboard Layout
+ package information.
+ @param NotifyType The type of change concerning the database.
+ @param PackageList Pointer to a package list which will be inserted
+ to.
+ @param Package Created Keyboard Layout package
+
+ @retval EFI_SUCCESS Keyboard Layout Package is inserted successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new
+ Keyboard Layout package.
+ @retval EFI_INVALID_PARAMETER PackageHdr is NULL or PackageList is NULL.
+
+**/
+STATIC
+EFI_STATUS
+InsertKeyboardLayoutPackage (
+ IN VOID *PackageHdr,
+ IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ OUT HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE **Package
+ )
+{
+ HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE *KeyboardLayoutPackage;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+ EFI_STATUS Status;
+
+ if (PackageHdr == NULL || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CopyMem (&PackageHeader, PackageHdr, sizeof (EFI_HII_PACKAGE_HEADER));
+
+ //
+ // Create a Keyboard Layout package node
+ //
+ KeyboardLayoutPackage = AllocateZeroPool (sizeof (HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE));
+ if (KeyboardLayoutPackage == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+ KeyboardLayoutPackage->Signature = HII_KB_LAYOUT_PACKAGE_SIGNATURE;
+
+ KeyboardLayoutPackage->KeyboardPkg = (UINT8 *) AllocateZeroPool (PackageHeader.Length);
+ if (KeyboardLayoutPackage->KeyboardPkg == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ CopyMem (KeyboardLayoutPackage->KeyboardPkg, PackageHdr, PackageHeader.Length);
+ InsertTailList (&PackageList->KeyboardLayoutHdr, &KeyboardLayoutPackage->KeyboardEntry);
+
+ *Package = KeyboardLayoutPackage;
+
+ if (NotifyType == EFI_HII_DATABASE_NOTIFY_ADD_PACK) {
+ PackageList->PackageListHdr.PackageLength += PackageHeader.Length;
+ }
+
+ return EFI_SUCCESS;
+
+Error:
+
+ SafeFreePool (KeyboardLayoutPackage->KeyboardPkg);
+ SafeFreePool (KeyboardLayoutPackage);
+
+ return Status;
+}
+
+
+/**
+ This function exports Keyboard Layout packages to a buffer.
+
+ @param Private Hii database private structure.
+ @param Handle Identification of a package list.
+ @param PackageList Pointer to a package list which will be exported.
+ @param UsedSize The length of buffer be used.
+ @param BufferSize Length of the Buffer.
+ @param Buffer Allocated space for storing exported data.
+ @param ResultSize The size of the already exported content of this
+ package list.
+
+ @retval EFI_SUCCESS Keyboard Layout Packages are exported
+ successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+
+**/
+STATIC
+EFI_STATUS
+ExportKeyboardLayoutPackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ IN UINTN UsedSize,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer,
+ IN OUT UINTN *ResultSize
+ )
+{
+ LIST_ENTRY *Link;
+ UINTN PackageLength;
+ EFI_STATUS Status;
+ HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE *Package;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+
+ if (Private == NULL || PackageList == NULL || ResultSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize > 0 && Buffer == NULL ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PackageLength = 0;
+ Status = EFI_SUCCESS;
+
+ for (Link = PackageList->KeyboardLayoutHdr.ForwardLink; Link != &PackageList->KeyboardLayoutHdr; Link = Link->ForwardLink) {
+ Package = CR (Link, HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE, KeyboardEntry, HII_KB_LAYOUT_PACKAGE_SIGNATURE);
+ CopyMem (&PackageHeader, Package->KeyboardPkg, sizeof (EFI_HII_PACKAGE_HEADER));
+ PackageLength += PackageHeader.Length;
+ if (PackageLength + *ResultSize + UsedSize <= BufferSize) {
+ //
+ // Invoke registered notification function with EXPORT_PACK notify type
+ //
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_EXPORT_PACK,
+ (EFI_HII_PACKAGE_HEADER *) Package,
+ EFI_HII_PACKAGE_KEYBOARD_LAYOUT,
+ Handle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Copy Keyboard Layout package
+ //
+ CopyMem (Buffer, Package->KeyboardPkg, PackageHeader.Length);
+ Buffer = (UINT8 *) Buffer + PackageHeader.Length;
+ }
+ }
+
+ *ResultSize += PackageLength;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function deletes all Keyboard Layout packages from a package list node.
+
+ @param Private Hii database private data.
+ @param Handle Handle of the package list which contains the to
+ be removed Keyboard Layout packages.
+ @param PackageList Pointer to a package list that contains removing
+ packages.
+
+ @retval EFI_SUCCESS Keyboard Layout Package(s) is deleted
+ successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is not valid.
+
+**/
+STATIC
+EFI_STATUS
+RemoveKeyboardLayoutPackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList
+ )
+{
+ LIST_ENTRY *ListHead;
+ HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE *Package;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+ EFI_STATUS Status;
+
+ ListHead = &PackageList->KeyboardLayoutHdr;
+
+ while (!IsListEmpty (ListHead)) {
+ Package = CR (
+ ListHead->ForwardLink,
+ HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE,
+ KeyboardEntry,
+ HII_KB_LAYOUT_PACKAGE_SIGNATURE
+ );
+ Status = InvokeRegisteredFunction (
+ Private,
+ EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,
+ (VOID *) Package,
+ EFI_HII_PACKAGE_KEYBOARD_LAYOUT,
+ Handle
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ RemoveEntryList (&Package->KeyboardEntry);
+ CopyMem (&PackageHeader, Package->KeyboardPkg, sizeof (EFI_HII_PACKAGE_HEADER));
+ PackageList->PackageListHdr.PackageLength -= PackageHeader.Length;
+ SafeFreePool (Package->KeyboardPkg);
+ SafeFreePool (Package);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function will insert a package list to hii database firstly then
+ invoke notification functions if any. It is the worker function of
+ HiiNewPackageList and HiiUpdatePackageList.
+
+ @param Private Hii database private structure.
+ @param NotifyType The type of change concerning the database.
+ @param PackageList Pointer to a package list.
+ @param DatabaseRecord Pointer to a database record contains a package
+ list instance which will be inserted to.
+
+ @retval EFI_SUCCESS All incoming packages are inserted to current
+ database.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new
+ Device path package.
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+
+**/
+STATIC
+EFI_STATUS
+AddPackages (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType,
+ IN CONST EFI_HII_PACKAGE_LIST_HEADER *PackageList,
+ IN OUT HII_DATABASE_RECORD *DatabaseRecord
+ )
+{
+ EFI_STATUS Status;
+ HII_GUID_PACKAGE_INSTANCE *GuidPackage;
+ HII_IFR_PACKAGE_INSTANCE *FormPackage;
+ HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE *KeyboardLayoutPackage;
+ HII_STRING_PACKAGE_INSTANCE *StringPackage;
+ HII_FONT_PACKAGE_INSTANCE *FontPackage;
+ HII_SIMPLE_FONT_PACKAGE_INSTANCE *SimpleFontPackage;
+ HII_IMAGE_PACKAGE_INSTANCE *ImagePackage;
+ EFI_HII_PACKAGE_HEADER *PackageHdrPtr;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+ UINT32 OldPackageListLen;
+
+ //
+ // Process the package list header
+ //
+ OldPackageListLen = DatabaseRecord->PackageList->PackageListHdr.PackageLength;
+ CopyMem (
+ &DatabaseRecord->PackageList->PackageListHdr,
+ (VOID *) PackageList,
+ sizeof (EFI_HII_PACKAGE_LIST_HEADER)
+ );
+ if (NotifyType == EFI_HII_DATABASE_NOTIFY_ADD_PACK) {
+ DatabaseRecord->PackageList->PackageListHdr.PackageLength = OldPackageListLen;
+ }
+
+ PackageHdrPtr = (EFI_HII_PACKAGE_HEADER *) ((UINT8 *) PackageList + sizeof (EFI_HII_PACKAGE_LIST_HEADER));
+ CopyMem (&PackageHeader, PackageHdrPtr, sizeof (EFI_HII_PACKAGE_HEADER));
+
+ Status = EFI_SUCCESS;
+
+ while (PackageHeader.Type != EFI_HII_PACKAGE_END) {
+ switch (PackageHeader.Type) {
+ case EFI_HII_PACKAGE_TYPE_GUID:
+ Status = InsertGuidPackage (
+ PackageHdrPtr,
+ NotifyType,
+ DatabaseRecord->PackageList,
+ &GuidPackage
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = InvokeRegisteredFunction (
+ Private,
+ NotifyType,
+ (VOID *) GuidPackage,
+ (UINT8) (PackageHeader.Type),
+ DatabaseRecord->Handle
+ );
+ break;
+ case EFI_HII_PACKAGE_FORM:
+ Status = InsertFormPackage (
+ PackageHdrPtr,
+ NotifyType,
+ DatabaseRecord->PackageList,
+ &FormPackage
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = InvokeRegisteredFunction (
+ Private,
+ NotifyType,
+ (VOID *) FormPackage,
+ (UINT8) (PackageHeader.Type),
+ DatabaseRecord->Handle
+ );
+ break;
+ case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
+ Status = InsertKeyboardLayoutPackage (
+ PackageHdrPtr,
+ NotifyType,
+ DatabaseRecord->PackageList,
+ &KeyboardLayoutPackage
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = InvokeRegisteredFunction (
+ Private,
+ NotifyType,
+ (VOID *) KeyboardLayoutPackage,
+ (UINT8) (PackageHeader.Type),
+ DatabaseRecord->Handle
+ );
+ break;
+ case EFI_HII_PACKAGE_STRINGS:
+ Status = InsertStringPackage (
+ Private,
+ PackageHdrPtr,
+ NotifyType,
+ DatabaseRecord->PackageList,
+ &StringPackage
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = InvokeRegisteredFunction (
+ Private,
+ NotifyType,
+ (VOID *) StringPackage,
+ (UINT8) (PackageHeader.Type),
+ DatabaseRecord->Handle
+ );
+ break;
+ case EFI_HII_PACKAGE_FONTS:
+ Status = InsertFontPackage (
+ Private,
+ PackageHdrPtr,
+ NotifyType,
+ DatabaseRecord->PackageList,
+ &FontPackage
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = InvokeRegisteredFunction (
+ Private,
+ NotifyType,
+ (VOID *) FontPackage,
+ (UINT8) (PackageHeader.Type),
+ DatabaseRecord->Handle
+ );
+ break;
+ case EFI_HII_PACKAGE_IMAGES:
+ Status = InsertImagePackage (
+ PackageHdrPtr,
+ NotifyType,
+ DatabaseRecord->PackageList,
+ &ImagePackage
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = InvokeRegisteredFunction (
+ Private,
+ NotifyType,
+ (VOID *) ImagePackage,
+ (UINT8) (PackageHeader.Type),
+ DatabaseRecord->Handle
+ );
+ break;
+ case EFI_HII_PACKAGE_SIMPLE_FONTS:
+ Status = InsertSimpleFontPackage (
+ PackageHdrPtr,
+ NotifyType,
+ DatabaseRecord->PackageList,
+ &SimpleFontPackage
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = InvokeRegisteredFunction (
+ Private,
+ NotifyType,
+ (VOID *) SimpleFontPackage,
+ (UINT8) (PackageHeader.Type),
+ DatabaseRecord->Handle
+ );
+ break;
+ case EFI_HII_PACKAGE_DEVICE_PATH:
+ Status = AddDevicePathPackage (
+ Private,
+ NotifyType,
+ (EFI_DEVICE_PATH_PROTOCOL *) ((UINT8 *) PackageHdrPtr + sizeof (EFI_HII_PACKAGE_HEADER)),
+ DatabaseRecord
+ );
+ break;
+ default:
+ break;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // goto header of next package
+ //
+ PackageHdrPtr = (EFI_HII_PACKAGE_HEADER *) ((UINT8 *) PackageHdrPtr + PackageHeader.Length);
+ CopyMem (&PackageHeader, PackageHdrPtr, sizeof (EFI_HII_PACKAGE_HEADER));
+ }
+
+ return Status;
+}
+
+
+/**
+ This function exports a package list to a buffer. It is the worker function
+ of HiiExportPackageList.
+
+ @param Private Hii database private structure.
+ @param Handle Identification of a package list.
+ @param PackageList Pointer to a package list which will be exported.
+ @param UsedSize The length of buffer has been used by exporting
+ package lists when Handle is NULL.
+ @param BufferSize Length of the Buffer.
+ @param Buffer Allocated space for storing exported data.
+
+ @retval EFI_SUCCESS Keyboard Layout Packages are exported
+ successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+
+**/
+STATIC
+EFI_STATUS
+ExportPackageList (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_HII_HANDLE Handle,
+ IN HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList,
+ IN OUT UINTN *UsedSize,
+ IN UINTN BufferSize,
+ OUT EFI_HII_PACKAGE_LIST_HEADER *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN ResultSize;
+ EFI_HII_PACKAGE_HEADER EndofPackageList;
+
+ ASSERT (Private != NULL || PackageList != NULL || UsedSize != NULL);
+ ASSERT (Private->Signature == HII_DATABASE_PRIVATE_DATA_SIGNATURE);
+ ASSERT (IsHiiHandleValid (Handle));
+
+ if (BufferSize > 0 && Buffer == NULL ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Copy the package list header
+ // ResultSize indicates the length of the exported bytes of this package list
+ //
+ ResultSize = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
+ if (ResultSize + *UsedSize <= BufferSize) {
+ CopyMem ((VOID *) Buffer, PackageList, ResultSize);
+ }
+ //
+ // Copy the packages and invoke EXPORT_PACK notify functions if exists.
+ //
+ Status = ExportGuidPackages (
+ Private,
+ Handle,
+ PackageList,
+ *UsedSize,
+ BufferSize,
+ (VOID *) ((UINT8 *) Buffer + ResultSize),
+ &ResultSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = ExportFormPackages (
+ Private,
+ Handle,
+ PackageList,
+ *UsedSize,
+ BufferSize,
+ (VOID *) ((UINT8 *) Buffer + ResultSize),
+ &ResultSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = ExportKeyboardLayoutPackages (
+ Private,
+ Handle,
+ PackageList,
+ *UsedSize,
+ BufferSize,
+ (VOID *) ((UINT8 *) Buffer + ResultSize),
+ &ResultSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = ExportStringPackages (
+ Private,
+ Handle,
+ PackageList,
+ *UsedSize,
+ BufferSize,
+ (VOID *) ((UINT8 *) Buffer + ResultSize),
+ &ResultSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = ExportFontPackages (
+ Private,
+ Handle,
+ PackageList,
+ *UsedSize,
+ BufferSize,
+ (VOID *) ((UINT8 *) Buffer + ResultSize),
+ &ResultSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = ExportImagePackages (
+ Private,
+ Handle,
+ PackageList,
+ *UsedSize,
+ BufferSize,
+ (VOID *) ((UINT8 *) Buffer + ResultSize),
+ &ResultSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = ExportSimpleFontPackages (
+ Private,
+ Handle,
+ PackageList,
+ *UsedSize,
+ BufferSize,
+ (VOID *) ((UINT8 *) Buffer + ResultSize),
+ &ResultSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = ExportDevicePathPackage (
+ Private,
+ Handle,
+ PackageList,
+ *UsedSize,
+ BufferSize,
+ (VOID *) ((UINT8 *) Buffer + ResultSize),
+ &ResultSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Append the package list end.
+ //
+ EndofPackageList.Length = sizeof (EFI_HII_PACKAGE_HEADER);
+ EndofPackageList.Type = EFI_HII_PACKAGE_END;
+ if (ResultSize + *UsedSize + sizeof (EFI_HII_PACKAGE_HEADER) <= BufferSize) {
+ CopyMem (
+ (VOID *) ((UINT8 *) Buffer + ResultSize),
+ (VOID *) &EndofPackageList,
+ sizeof (EFI_HII_PACKAGE_HEADER)
+ );
+ }
+
+ *UsedSize += ResultSize + sizeof (EFI_HII_PACKAGE_HEADER);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function adds the packages in the package list to the database and returns a handle. If there is a
+ EFI_DEVICE_PATH_PROTOCOL associated with the DriverHandle, then this function will
+ create a package of type EFI_PACKAGE_TYPE_DEVICE_PATH and add it to the package list.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param PackageList A pointer to an EFI_HII_PACKAGE_LIST_HEADER
+ structure.
+ @param DriverHandle Associate the package list with this EFI handle.
+ @param Handle A pointer to the EFI_HII_HANDLE instance.
+
+ @retval EFI_SUCCESS The package list associated with the Handle was
+ added to the HII database.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new
+ database contents.
+ @retval EFI_INVALID_PARAMETER PackageList is NULL or Handle is NULL.
+ @retval EFI_INVALID_PARAMETER PackageListGuid already exists in database.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiNewPackageList (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN CONST EFI_HII_PACKAGE_LIST_HEADER *PackageList,
+ IN CONST EFI_HANDLE DriverHandle,
+ OUT EFI_HII_HANDLE *Handle
+ )
+{
+ EFI_STATUS Status;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ HII_DATABASE_RECORD *DatabaseRecord;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ LIST_ENTRY *Link;
+ EFI_GUID PackageListGuid;
+
+ if (This == NULL || PackageList == NULL || Handle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ CopyMem (&PackageListGuid, (VOID *) PackageList, sizeof (EFI_GUID));
+
+ //
+ // Check the Package list GUID to guarantee this GUID is unique in database.
+ //
+ for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
+ DatabaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ if (CompareGuid (
+ &(DatabaseRecord->PackageList->PackageListHdr.PackageListGuid),
+ &PackageListGuid
+ )
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // Build a PackageList node
+ //
+ Status = GenerateHiiDatabaseRecord (Private, &DatabaseRecord);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Fill in information of the created Package List node
+ // according to incoming package list.
+ //
+ Status = AddPackages (Private, EFI_HII_DATABASE_NOTIFY_NEW_PACK, PackageList, DatabaseRecord);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DatabaseRecord->DriverHandle = DriverHandle;
+
+ //
+ // Create a Device path package and add into the package list if exists.
+ //
+ Status = gBS->HandleProtocol (
+ DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = AddDevicePathPackage (Private, EFI_HII_DATABASE_NOTIFY_NEW_PACK, DevicePath, DatabaseRecord);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ *Handle = DatabaseRecord->Handle;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function removes the package list that is associated with a handle Handle
+ from the HII database. Before removing the package, any registered functions
+ with the notification type REMOVE_PACK and the same package type will be called.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param Handle The handle that was registered to the data that is
+ requested for removal.
+
+ @retval EFI_SUCCESS The data associated with the Handle was removed
+ from the HII database.
+ @retval EFI_NOT_FOUND The specified PackageList could not be found in
+ database.
+ @retval EFI_INVALID_PARAMETER The Handle was not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiRemovePackageList (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN EFI_HII_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ LIST_ENTRY *Link;
+ HII_DATABASE_RECORD *Node;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList;
+ HII_HANDLE *HiiHandle;
+
+ if (This == NULL || !IsHiiHandleValid (Handle)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // Get the packagelist to be removed.
+ //
+ for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
+ Node = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ if (Node->Handle == Handle) {
+ PackageList = (HII_DATABASE_PACKAGE_LIST_INSTANCE *) (Node->PackageList);
+ ASSERT (PackageList != NULL);
+
+ //
+ // Call registered functions with REMOVE_PACK before removing packages
+ // then remove them.
+ //
+ Status = RemoveGuidPackages (Private, Handle, PackageList);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = RemoveFormPackages (Private, Handle, PackageList);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = RemoveKeyboardLayoutPackages (Private, Handle, PackageList);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = RemoveStringPackages (Private, Handle, PackageList);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = RemoveFontPackages (Private, Handle, PackageList);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = RemoveImagePackages (Private, Handle, PackageList);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = RemoveSimpleFontPackages (Private, Handle, PackageList);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = RemoveDevicePathPackage (Private, Handle, PackageList);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Free resources of the package list
+ //
+ RemoveEntryList (&Node->DatabaseEntry);
+
+ HiiHandle = (HII_HANDLE *) Handle;
+ RemoveEntryList (&HiiHandle->Handle);
+ Private->HiiHandleCount--;
+ ASSERT (Private->HiiHandleCount >= 0);
+
+ HiiHandle->Signature = 0;
+ SafeFreePool (HiiHandle);
+ SafeFreePool (Node->PackageList);
+ SafeFreePool (Node);
+
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ This function updates the existing package list (which has the specified Handle)
+ in the HII databases, using the new package list specified by PackageList.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param Handle The handle that was registered to the data that is
+ requested to be updated.
+ @param PackageList A pointer to an EFI_HII_PACKAGE_LIST_HEADER
+ package.
+
+ @retval EFI_SUCCESS The HII database was successfully updated.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate enough memory for the updated
+ database.
+ @retval EFI_INVALID_PARAMETER Handle or PackageList was NULL.
+ @retval EFI_NOT_FOUND The Handle was not valid or could not be found in
+ database.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiUpdatePackageList (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN EFI_HII_HANDLE Handle,
+ IN CONST EFI_HII_PACKAGE_LIST_HEADER *PackageList
+ )
+{
+ EFI_STATUS Status;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ LIST_ENTRY *Link;
+ HII_DATABASE_RECORD *Node;
+ EFI_HII_PACKAGE_HEADER *PackageHdrPtr;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *OldPackageList;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+
+ if (This == NULL || PackageList == NULL || Handle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!IsHiiHandleValid (Handle)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+
+ PackageHdrPtr = (EFI_HII_PACKAGE_HEADER *) ((UINT8 *) PackageList + sizeof (EFI_HII_PACKAGE_LIST_HEADER));
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Get original packagelist to be updated
+ //
+ for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
+ Node = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ if (Node->Handle == Handle) {
+ OldPackageList = Node->PackageList;
+ //
+ // Remove the package if its type matches one of the package types which is
+ // contained in the new package list.
+ //
+ CopyMem (&PackageHeader, PackageHdrPtr, sizeof (EFI_HII_PACKAGE_HEADER));
+ while (PackageHeader.Type != EFI_HII_PACKAGE_END) {
+ switch (PackageHeader.Type) {
+ case EFI_HII_PACKAGE_TYPE_GUID:
+ Status = RemoveGuidPackages (Private, Handle, OldPackageList);
+ break;
+ case EFI_HII_PACKAGE_FORM:
+ Status = RemoveFormPackages (Private, Handle, OldPackageList);
+ break;
+ case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
+ Status = RemoveKeyboardLayoutPackages (Private, Handle, OldPackageList);
+ break;
+ case EFI_HII_PACKAGE_STRINGS:
+ Status = RemoveStringPackages (Private, Handle, OldPackageList);
+ break;
+ case EFI_HII_PACKAGE_FONTS:
+ Status = RemoveFontPackages (Private, Handle, OldPackageList);
+ break;
+ case EFI_HII_PACKAGE_IMAGES:
+ Status = RemoveImagePackages (Private, Handle, OldPackageList);
+ break;
+ case EFI_HII_PACKAGE_SIMPLE_FONTS:
+ Status = RemoveSimpleFontPackages (Private, Handle, OldPackageList);
+ break;
+ case EFI_HII_PACKAGE_DEVICE_PATH:
+ Status = RemoveDevicePathPackage (Private, Handle, OldPackageList);
+ break;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PackageHdrPtr = (EFI_HII_PACKAGE_HEADER *) ((UINT8 *) PackageHdrPtr + PackageHeader.Length);
+ CopyMem (&PackageHeader, PackageHdrPtr, sizeof (EFI_HII_PACKAGE_HEADER));
+ }
+
+ //
+ // Add all of the packages within the new package list
+ //
+ return AddPackages (Private, EFI_HII_DATABASE_NOTIFY_ADD_PACK, PackageList, Node);
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ This function returns a list of the package handles of the specified type
+ that are currently active in the database. The pseudo-type
+ EFI_HII_PACKAGE_TYPE_ALL will cause all package handles to be listed.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param PackageType Specifies the package type of the packages to list
+ or EFI_HII_PACKAGE_TYPE_ALL for all packages to be
+ listed.
+ @param PackageGuid If PackageType is EFI_HII_PACKAGE_TYPE_GUID, then
+ this is the pointer to the GUID which must match
+ the Guid field of EFI_HII_GUID_PACKAGE_GUID_HDR.
+ Otherwise, it must be NULL.
+ @param HandleBufferLength On input, a pointer to the length of the handle
+ buffer. On output, the length of the handle
+ buffer that is required for the handles found.
+ @param Handle An array of EFI_HII_HANDLE instances returned.
+
+ @retval EFI_SUCCESS The matching handles are outputed successfully.
+ @retval EFI_BUFFER_TO_SMALL The HandleBufferLength parameter indicates that
+ Handle is too small to support the number of
+ handles. HandleBufferLength is updated with a
+ value that will enable the data to fit.
+ @retval EFI_NOT_FOUND No matching handle could not be found in database.
+ @retval EFI_INVALID_PARAMETER Handle or HandleBufferLength was NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiListPackageLists (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN UINT8 PackageType,
+ IN CONST EFI_GUID *PackageGuid,
+ IN OUT UINTN *HandleBufferLength,
+ OUT EFI_HII_HANDLE *Handle
+ )
+{
+ HII_GUID_PACKAGE_INSTANCE *GuidPackage;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ HII_DATABASE_RECORD *Node;
+ LIST_ENTRY *Link;
+ BOOLEAN Matched;
+ HII_HANDLE **Result;
+ UINTN ResultSize;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList;
+ LIST_ENTRY *Link1;
+
+ //
+ // Check input parameters
+ //
+ if (This == NULL || HandleBufferLength == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (*HandleBufferLength > 0 && Handle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((PackageType == EFI_HII_PACKAGE_TYPE_GUID && PackageGuid == NULL) ||
+ (PackageType != EFI_HII_PACKAGE_TYPE_GUID && PackageGuid != NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ Matched = FALSE;
+ Result = (HII_HANDLE **) Handle;
+ ResultSize = 0;
+
+ for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
+ Node = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ PackageList = (HII_DATABASE_PACKAGE_LIST_INSTANCE *) (Node->PackageList);
+ switch (PackageType) {
+ case EFI_HII_PACKAGE_TYPE_GUID:
+ for (Link1 = PackageList->GuidPkgHdr.ForwardLink; Link1 != &PackageList->GuidPkgHdr; Link1 = Link1->ForwardLink) {
+ GuidPackage = CR (Link1, HII_GUID_PACKAGE_INSTANCE, GuidEntry, HII_GUID_PACKAGE_SIGNATURE);
+ if (CompareGuid (
+ (EFI_GUID *) PackageGuid,
+ (EFI_GUID *) (GuidPackage->GuidPkg + sizeof (EFI_HII_PACKAGE_HEADER))
+ )) {
+ Matched = TRUE;
+ break;
+ }
+ }
+ break;
+ case EFI_HII_PACKAGE_FORM:
+ if (!IsListEmpty (&PackageList->FormPkgHdr)) {
+ Matched = TRUE;
+ }
+ break;
+ case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:
+ if (!IsListEmpty (&PackageList->KeyboardLayoutHdr)) {
+ Matched = TRUE;
+ }
+ break;
+ case EFI_HII_PACKAGE_STRINGS:
+ if (!IsListEmpty (&PackageList->StringPkgHdr)) {
+ Matched = TRUE;
+ }
+ break;
+ case EFI_HII_PACKAGE_FONTS:
+ if (!IsListEmpty (&PackageList->FontPkgHdr)) {
+ Matched = TRUE;
+ }
+ break;
+ case EFI_HII_PACKAGE_IMAGES:
+ if (PackageList->ImagePkg != NULL) {
+ Matched = TRUE;
+ }
+ break;
+ case EFI_HII_PACKAGE_SIMPLE_FONTS:
+ if (!IsListEmpty (&PackageList->SimpleFontPkgHdr)) {
+ Matched = TRUE;
+ }
+ break;
+ case EFI_HII_PACKAGE_DEVICE_PATH:
+ if (PackageList->DevicePathPkg != NULL) {
+ Matched = TRUE;
+ }
+ break;
+ //
+ // Pesudo-type EFI_HII_PACKAGE_TYPE_ALL will cause all package handles
+ // to be listed.
+ //
+ case EFI_HII_PACKAGE_TYPE_ALL:
+ Matched = TRUE;
+ break;
+ default:
+ break;
+ }
+
+ //
+ // This active package list has the specified package type, list it.
+ //
+ if (Matched) {
+ ResultSize += sizeof (EFI_HII_HANDLE);
+ if (ResultSize <= *HandleBufferLength) {
+ *Result++ = Node->Handle;
+ }
+ }
+ Matched = FALSE;
+ }
+
+ if (ResultSize == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (*HandleBufferLength < ResultSize) {
+ *HandleBufferLength = ResultSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *HandleBufferLength = ResultSize;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function will export one or all package lists in the database to a buffer.
+ For each package list exported, this function will call functions registered
+ with EXPORT_PACK and then copy the package list to the buffer.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param Handle An EFI_HII_HANDLE that corresponds to the desired
+ package list in the HII database to export or NULL
+ to indicate all package lists should be exported.
+ @param BufferSize On input, a pointer to the length of the buffer.
+ On output, the length of the buffer that is
+ required for the exported data.
+ @param Buffer A pointer to a buffer that will contain the
+ results of the export function.
+
+ @retval EFI_SUCCESS Package exported.
+ @retval EFI_BUFFER_TO_SMALL The HandleBufferLength parameter indicates that
+ Handle is too small to support the number of
+ handles. HandleBufferLength is updated with a
+ value that will enable the data to fit.
+ @retval EFI_NOT_FOUND The specifiecd Handle could not be found in the
+ current database.
+ @retval EFI_INVALID_PARAMETER Handle or Buffer or BufferSize was NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiExportPackageLists (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN EFI_HII_HANDLE Handle,
+ IN OUT UINTN *BufferSize,
+ OUT EFI_HII_PACKAGE_LIST_HEADER *Buffer
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_STATUS Status;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ HII_DATABASE_RECORD *Node;
+ UINTN UsedSize;
+
+ if (This == NULL || BufferSize == NULL || Handle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (*BufferSize > 0 && Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (!IsHiiHandleValid (Handle)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ UsedSize = 0;
+
+ for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
+ Node = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ if (Handle == NULL) {
+ //
+ // Export all package lists in current hii database.
+ //
+ Status = ExportPackageList (
+ Private,
+ Node->Handle,
+ (HII_DATABASE_PACKAGE_LIST_INSTANCE *) (Node->PackageList),
+ &UsedSize,
+ *BufferSize,
+ (EFI_HII_PACKAGE_LIST_HEADER *)((UINT8 *) Buffer + UsedSize)
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ else if (Handle != NULL && Node->Handle == Handle) {
+ Status = ExportPackageList (
+ Private,
+ Handle,
+ (HII_DATABASE_PACKAGE_LIST_INSTANCE *) (Node->PackageList),
+ &UsedSize,
+ *BufferSize,
+ Buffer
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (*BufferSize < UsedSize) {
+ *BufferSize = UsedSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ return EFI_SUCCESS;
+ }
+ }
+
+ if (Handle == NULL && UsedSize != 0) {
+ if (*BufferSize < UsedSize) {
+ *BufferSize = UsedSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ This function registers a function which will be called when specified actions related to packages of
+ the specified type occur in the HII database. By registering a function, other HII-related drivers are
+ notified when specific package types are added, removed or updated in the HII database.
+ Each driver or application which registers a notification should use
+ EFI_HII_DATABASE_PROTOCOL.UnregisterPackageNotify() before exiting.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param PackageType Specifies the package type of the packages to list
+ or EFI_HII_PACKAGE_TYPE_ALL for all packages to be
+ listed.
+ @param PackageGuid If PackageType is EFI_HII_PACKAGE_TYPE_GUID, then
+ this is the pointer to the GUID which must match
+ the Guid field of
+ EFI_HII_GUID_PACKAGE_GUID_HDR. Otherwise, it must
+ be NULL.
+ @param PackageNotifyFn Points to the function to be called when the event
+ specified by
+ NotificationType occurs.
+ @param NotifyType Describes the types of notification which this
+ function will be receiving.
+ @param NotifyHandle Points to the unique handle assigned to the
+ registered notification. Can be used in
+ EFI_HII_DATABASE_PROTOCOL.UnregisterPackageNotify()
+ to stop notifications.
+
+ @retval EFI_SUCCESS Notification registered successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary data structures
+ @retval EFI_INVALID_PARAMETER NotifyHandle is NULL.
+ @retval EFI_INVALID_PARAMETER PackageGuid is not NULL when PackageType is not
+ EFI_HII_PACKAGE_TYPE_GUID.
+ @retval EFI_INVALID_PARAMETER PackageGuid is NULL when PackageType is
+ EFI_HII_PACKAGE_TYPE_GUID.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiRegisterPackageNotify (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN UINT8 PackageType,
+ IN CONST EFI_GUID *PackageGuid,
+ IN CONST EFI_HII_DATABASE_NOTIFY PackageNotifyFn,
+ IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType,
+ OUT EFI_HANDLE *NotifyHandle
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+ HII_DATABASE_NOTIFY *Notify;
+ EFI_STATUS Status;
+
+ if (This == NULL || NotifyHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((PackageType == EFI_HII_PACKAGE_TYPE_GUID && PackageGuid == NULL) ||
+ (PackageType != EFI_HII_PACKAGE_TYPE_GUID && PackageGuid != NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // Allocate a notification node
+ //
+ Notify = (HII_DATABASE_NOTIFY *) AllocateZeroPool (sizeof (HII_DATABASE_NOTIFY));
+ if (Notify == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Generate a notify handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Notify->NotifyHandle,
+ &mHiiDatabaseNotifyGuid,
+ NULL,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Fill in the information to the notification node
+ //
+ Notify->Signature = HII_DATABASE_NOTIFY_SIGNATURE;
+ Notify->PackageType = PackageType;
+ Notify->PackageGuid = (EFI_GUID *) PackageGuid;
+ Notify->PackageNotifyFn = (EFI_HII_DATABASE_NOTIFY) PackageNotifyFn;
+ Notify->NotifyType = NotifyType;
+
+ InsertTailList (&Private->DatabaseNotifyList, &Notify->DatabaseNotifyEntry);
+ *NotifyHandle = Notify->NotifyHandle;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Removes the specified HII database package-related notification.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param NotifyHandle The handle of the notification function being
+ unregistered.
+
+ @retval EFI_SUCCESS Notification is unregistered successfully.
+ @retval EFI_INVALID_PARAMETER The Handle is invalid.
+ @retval EFI_NOT_FOUND The incoming notification handle does not exist
+ in current hii database.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiUnregisterPackageNotify (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN EFI_HANDLE NotificationHandle
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+ HII_DATABASE_NOTIFY *Notify;
+ LIST_ENTRY *Link;
+ EFI_STATUS Status;
+
+ if (This == NULL || NotificationHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = gBS->OpenProtocol (
+ NotificationHandle,
+ &mHiiDatabaseNotifyGuid,
+ NULL,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+
+ for (Link = Private->DatabaseNotifyList.ForwardLink; Link != &Private->DatabaseNotifyList; Link = Link->ForwardLink) {
+ Notify = CR (Link, HII_DATABASE_NOTIFY, DatabaseNotifyEntry, HII_DATABASE_NOTIFY_SIGNATURE);
+ if (Notify->NotifyHandle == NotificationHandle) {
+ //
+ // Remove the matching notification node
+ //
+ RemoveEntryList (&Notify->DatabaseNotifyEntry);
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Notify->NotifyHandle,
+ &mHiiDatabaseNotifyGuid,
+ NULL,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ SafeFreePool (Notify);
+ Notify = NULL;
+
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ This routine retrieves an array of GUID values for each keyboard layout that
+ was previously registered in the system.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param KeyGuidBufferLength On input, a pointer to the length of the keyboard
+ GUID buffer. On output, the length of the handle
+ buffer that is required for the handles found.
+ @param KeyGuidBuffer An array of keyboard layout GUID instances
+ returned.
+
+ @retval EFI_SUCCESS KeyGuidBuffer was updated successfully.
+ @retval EFI_BUFFER_TOO_SMALL The KeyGuidBufferLength parameter indicates
+ that KeyGuidBuffer is too small to support the
+ number of GUIDs. KeyGuidBufferLength is
+ updated with a value that will enable the data to
+ fit.
+ @retval EFI_INVALID_PARAMETER The KeyGuidBuffer or KeyGuidBufferLength was NULL.
+ @retval EFI_NOT_FOUND There was no keyboard layout.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiFindKeyboardLayouts (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN OUT UINT16 *KeyGuidBufferLength,
+ OUT EFI_GUID *KeyGuidBuffer
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+ HII_DATABASE_RECORD *Node;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *Link1;
+ UINT16 ResultSize;
+ UINTN Index;
+ UINT16 LayoutCount;
+ UINT16 LayoutLength;
+ UINT8 *Layout;
+ HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE *Package;
+
+ if (This == NULL || KeyGuidBufferLength == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (*KeyGuidBufferLength > 0 && KeyGuidBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ ResultSize = 0;
+
+ //
+ // Search all package lists in whole database to retrieve keyboard layout.
+ //
+ for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
+ Node = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ PackageList = Node->PackageList;
+ for (Link1 = PackageList->KeyboardLayoutHdr.ForwardLink;
+ Link1 != &PackageList->KeyboardLayoutHdr;
+ Link1 = Link1->ForwardLink
+ ) {
+ //
+ // Find out all Keyboard Layout packages in this package list.
+ //
+ Package = CR (
+ Link1,
+ HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE,
+ KeyboardEntry,
+ HII_KB_LAYOUT_PACKAGE_SIGNATURE
+ );
+ Layout = (UINT8 *) Package->KeyboardPkg + sizeof (EFI_HII_PACKAGE_HEADER) + sizeof (UINT16);
+ CopyMem (
+ &LayoutCount,
+ (UINT8 *) Package->KeyboardPkg + sizeof (EFI_HII_PACKAGE_HEADER),
+ sizeof (UINT16)
+ );
+ for (Index = 0; Index < LayoutCount; Index++) {
+ ResultSize += sizeof (EFI_GUID);
+ if (ResultSize <= *KeyGuidBufferLength) {
+ CopyMem (KeyGuidBuffer + Index, Layout + sizeof (UINT16), sizeof (EFI_GUID));
+ CopyMem (&LayoutLength, Layout, sizeof (UINT16));
+ Layout = Layout + LayoutLength;
+ }
+ }
+ }
+ }
+
+ if (ResultSize == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (*KeyGuidBufferLength < ResultSize) {
+ *KeyGuidBufferLength = ResultSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *KeyGuidBufferLength = ResultSize;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This routine retrieves the requested keyboard layout. The layout is a physical description of the keys
+ on a keyboard and the character(s) that are associated with a particular set of key strokes.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param KeyGuid A pointer to the unique ID associated with a given
+ keyboard layout. If KeyGuid is NULL then the
+ current layout will be retrieved.
+ @param KeyboardLayoutLength On input, a pointer to the length of the
+ KeyboardLayout buffer. On output, the length of
+ the data placed into KeyboardLayout.
+ @param KeyboardLayout A pointer to a buffer containing the retrieved
+ keyboard layout.
+
+ @retval EFI_SUCCESS The keyboard layout was retrieved successfully.
+ @retval EFI_NOT_FOUND The requested keyboard layout was not found.
+ @retval EFI_INVALID_PARAMETER The KeyboardLayout or KeyboardLayoutLength was
+ NULL.
+ @retval EFI_BUFFER_TOO_SMALL The KeyboardLayoutLength parameter indicates
+ that KeyboardLayout is too small to support the
+ requested keyboard layout. KeyboardLayoutLength is
+ updated with a value that will enable the
+ data to fit.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetKeyboardLayout (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN CONST EFI_GUID *KeyGuid,
+ IN OUT UINT16 *KeyboardLayoutLength,
+ OUT EFI_HII_KEYBOARD_LAYOUT *KeyboardLayout
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+ HII_DATABASE_RECORD *Node;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *Link1;
+ UINTN Index;
+ UINT8 *Layout;
+ UINT16 LayoutCount;
+ UINT16 LayoutLength;
+ HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE *Package;
+
+ if (This == NULL || KeyboardLayoutLength == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (*KeyboardLayoutLength > 0 && KeyboardLayout == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ //
+ // Retrieve the current keyboard layout.
+ //
+ if (KeyGuid == NULL) {
+ if (Private->CurrentLayout == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ CopyMem (&LayoutLength, Private->CurrentLayout, sizeof (UINT16));
+ if (*KeyboardLayoutLength < LayoutLength) {
+ *KeyboardLayoutLength = LayoutLength;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ CopyMem (KeyboardLayout, Private->CurrentLayout, LayoutLength);
+ return EFI_SUCCESS;
+ }
+
+ for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
+ Node = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ PackageList = (HII_DATABASE_PACKAGE_LIST_INSTANCE *) (Node->PackageList);
+ for (Link1 = PackageList->KeyboardLayoutHdr.ForwardLink;
+ Link1 != &PackageList->KeyboardLayoutHdr;
+ Link1 = Link1->ForwardLink
+ ) {
+ Package = CR (
+ Link1,
+ HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE,
+ KeyboardEntry,
+ HII_KB_LAYOUT_PACKAGE_SIGNATURE
+ );
+
+ Layout = (UINT8 *) Package->KeyboardPkg +
+ sizeof (EFI_HII_PACKAGE_HEADER) + sizeof (UINT16);
+ CopyMem (&LayoutCount, Layout - sizeof (UINT16), sizeof (UINT16));
+ for (Index = 0; Index < LayoutCount; Index++) {
+ CopyMem (&LayoutLength, Layout, sizeof (UINT16));
+ if (CompareMem (Layout + sizeof (UINT16), KeyGuid, sizeof (EFI_GUID)) == 0) {
+ if (LayoutLength <= *KeyboardLayoutLength) {
+ CopyMem (KeyboardLayout, Layout, LayoutLength);
+ return EFI_SUCCESS;
+ } else {
+ *KeyboardLayoutLength = LayoutLength;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ }
+ Layout = Layout + LayoutLength;
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ This routine sets the default keyboard layout to the one referenced by KeyGuid. When this routine
+ is called, an event will be signaled of the EFI_HII_SET_KEYBOARD_LAYOUT_EVENT_GUID
+ group type. This is so that agents which are sensitive to the current keyboard layout being changed
+ can be notified of this change.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param KeyGuid A pointer to the unique ID associated with a given
+ keyboard layout.
+
+ @retval EFI_SUCCESS The current keyboard layout was successfully set.
+ @retval EFI_NOT_FOUND The referenced keyboard layout was not found, so
+ action was taken.
+ @retval EFI_INVALID_PARAMETER The KeyGuid was NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiSetKeyboardLayout (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN CONST EFI_GUID *KeyGuid
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+ EFI_HII_KEYBOARD_LAYOUT *KeyboardLayout;
+ UINT16 KeyboardLayoutLength;
+ EFI_STATUS Status;
+
+ if (This == NULL || KeyGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // The specified GUID equals the current keyboard layout GUID,
+ // return directly.
+ //
+ if (CompareGuid (&Private->CurrentLayoutGuid, KeyGuid)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Try to find the incoming keyboard layout data in current database.
+ //
+ KeyboardLayoutLength = 0;
+ KeyboardLayout = NULL;
+ Status = HiiGetKeyboardLayout (This, KeyGuid, &KeyboardLayoutLength, KeyboardLayout);
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ return Status;
+ }
+
+ KeyboardLayout = (EFI_HII_KEYBOARD_LAYOUT *) AllocateZeroPool (KeyboardLayoutLength);
+ ASSERT (KeyboardLayout != NULL);
+ Status = HiiGetKeyboardLayout (This, KeyGuid, &KeyboardLayoutLength, KeyboardLayout);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Backup current keyboard layout.
+ //
+ CopyMem (&Private->CurrentLayoutGuid, KeyGuid, sizeof (EFI_GUID));
+ SafeFreePool(Private->CurrentLayout);
+ Private->CurrentLayout = KeyboardLayout;
+
+ //
+ // Signal EFI_HII_SET_KEYBOARD_LAYOUT_EVENT_GUID group to notify
+ // current keyboard layout is changed.
+ //
+ Status = gBS->SignalEvent (gHiiKeyboardLayoutChanged);
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Return the EFI handle associated with a package list.
+
+ @param This A pointer to the EFI_HII_DATABASE_PROTOCOL
+ instance.
+ @param PackageListHandle An EFI_HII_HANDLE that corresponds to the desired
+ package list in the HIIdatabase.
+ @param DriverHandle On return, contains the EFI_HANDLE which was
+ registered with the package list in
+ NewPackageList().
+
+ @retval EFI_SUCCESS The DriverHandle was returned successfully.
+ @retval EFI_INVALID_PARAMETER The PackageListHandle was not valid or
+ DriverHandle was NULL.
+ @retval EFI_NOT_FOUND This PackageList handle can not be found in
+ current database.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetPackageListHandle (
+ IN CONST EFI_HII_DATABASE_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageListHandle,
+ OUT EFI_HANDLE *DriverHandle
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+ HII_DATABASE_RECORD *Node;
+ LIST_ENTRY *Link;
+
+ if (This == NULL || DriverHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!IsHiiHandleValid (PackageListHandle)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+
+ for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
+ Node = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ if (Node->Handle == PackageListHandle) {
+ *DriverHandle = Node->DriverHandle;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
diff --git a/MdeModulePkg/Universal/HiiDatabaseDxe/Font.c b/MdeModulePkg/Universal/HiiDatabaseDxe/Font.c new file mode 100644 index 0000000000..a5363d43bd --- /dev/null +++ b/MdeModulePkg/Universal/HiiDatabaseDxe/Font.c @@ -0,0 +1,2395 @@ +/** @file
+
+Copyright (c) 2007, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ Font.c
+
+Abstract:
+
+ Implementation for EFI_HII_FONT_PROTOCOL.
+
+Revision History
+
+
+**/
+
+
+#include "HiiDatabase.h"
+
+static EFI_GRAPHICS_OUTPUT_BLT_PIXEL mEfiColors[16] = {
+ //
+ // B G R
+ //
+ 0x00, 0x00, 0x00, 0x00, // BLACK
+ 0x98, 0x00, 0x00, 0x00, // BLUE
+ 0x00, 0x98, 0x00, 0x00, // GREEN
+ 0x98, 0x98, 0x00, 0x00, // CYAN
+ 0x00, 0x00, 0x98, 0x00, // RED
+ 0x98, 0x00, 0x98, 0x00, // MAGENTA
+ 0x00, 0x98, 0x98, 0x00, // BROWN
+ 0x98, 0x98, 0x98, 0x00, // LIGHTGRAY
+ 0x30, 0x30, 0x30, 0x00, // DARKGRAY - BRIGHT BLACK
+ 0xff, 0x00, 0x00, 0x00, // LIGHTBLUE
+ 0x00, 0xff, 0x00, 0x00, // LIGHTGREEN
+ 0xff, 0xff, 0x00, 0x00, // LIGHTCYAN
+ 0x00, 0x00, 0xff, 0x00, // LIGHTRED
+ 0xff, 0x00, 0xff, 0x00, // LIGHTMAGENTA
+ 0x00, 0xff, 0xff, 0x00, // YELLOW
+ 0xff, 0xff, 0xff, 0x00, // WHITE
+};
+
+
+/**
+ Insert a character cell information to the list specified by GlyphInfoList.
+
+ @param CharValue Unicode character value, which identifies a glyph
+ block.
+ @param GlyphInfoList HII_GLYPH_INFO list head.
+ @param Cell Incoming character cell information.
+
+ @retval EFI_SUCCESS Cell information is added to the GlyphInfoList.
+ @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the
+ task.
+
+**/
+STATIC
+EFI_STATUS
+NewCell (
+ IN CHAR16 CharValue,
+ IN LIST_ENTRY *GlyphInfoList,
+ IN EFI_HII_GLYPH_INFO *Cell
+ )
+{
+ HII_GLYPH_INFO *GlyphInfo;
+
+ ASSERT (Cell != NULL && GlyphInfoList != NULL);
+
+ GlyphInfo = (HII_GLYPH_INFO *) AllocateZeroPool (sizeof (HII_GLYPH_INFO));
+ if (GlyphInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // GlyphInfoList stores a list of default character cell information, each is
+ // identified by "CharId".
+ //
+ GlyphInfo->Signature = HII_GLYPH_INFO_SIGNATURE;
+ GlyphInfo->CharId = CharValue;
+ CopyMem (&GlyphInfo->Cell, Cell, sizeof (EFI_HII_GLYPH_INFO));
+ InsertTailList (GlyphInfoList, &GlyphInfo->Entry);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Get a character cell information from the list specified by GlyphInfoList.
+
+ @param CharValue Unicode character value, which identifies a glyph
+ block.
+ @param GlyphInfoList HII_GLYPH_INFO list head.
+ @param Cell Buffer which stores output character cell
+ information.
+
+ @retval EFI_SUCCESS Cell information is added to the GlyphInfoList.
+ @retval EFI_NOT_FOUND The character info specified by CharValue does
+ not exist.
+
+**/
+STATIC
+EFI_STATUS
+GetCell (
+ IN CHAR16 CharValue,
+ IN LIST_ENTRY *GlyphInfoList,
+ OUT EFI_HII_GLYPH_INFO *Cell
+ )
+{
+ HII_GLYPH_INFO *GlyphInfo;
+ LIST_ENTRY *Link;
+
+ ASSERT (Cell != NULL && GlyphInfoList != NULL);
+
+ //
+ // Since the EFI_HII_GIBT_DEFAULTS block won't increment CharValueCurrent,
+ // the value of "CharId" of a default character cell which is used for a
+ // EFI_HII_GIBT_GLYPH_DEFAULT or EFI_HII_GIBT_GLYPHS_DEFAULT should be
+ // less or equal to the value of "CharValueCurrent" of this default block.
+ //
+ // For instance, if the CharId of a GlyphInfoList is {1, 3, 7}, a default glyph
+ // with CharValue equals "7" uses the GlyphInfo with CharId = 7;
+ // a default glyph with CharValue equals "6" uses the GlyphInfo with CharId = 3.
+ //
+ for (Link = GlyphInfoList->BackLink; Link != GlyphInfoList; Link = Link->BackLink) {
+ GlyphInfo = CR (Link, HII_GLYPH_INFO, Entry, HII_GLYPH_INFO_SIGNATURE);
+ if (GlyphInfo->CharId <= CharValue) {
+ CopyMem (Cell, &GlyphInfo->Cell, sizeof (EFI_HII_GLYPH_INFO));
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Convert the glyph for a single character into a bitmap.
+
+ @param Private HII database driver private data.
+ @param Char Character to retrieve.
+ @param StringInfo Points to the string font and color information
+ or NULL if the string should use the default
+ system font and color.
+ @param GlyphBuffer Buffer to store the retrieved bitmap data.
+ @param Cell Points to EFI_HII_GLYPH_INFO structure.
+ @param Attributes If not NULL, output the glyph attributes if any.
+
+ @retval EFI_SUCCESS Glyph bitmap outputted.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate the output buffer GlyphBuffer.
+ @retval EFI_NOT_FOUND The glyph was unknown can not be found.
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+
+**/
+STATIC
+EFI_STATUS
+GetGlyphBuffer (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN CHAR16 Char,
+ IN EFI_FONT_INFO *StringInfo,
+ OUT UINT8 **GlyphBuffer,
+ OUT EFI_HII_GLYPH_INFO *Cell,
+ OUT UINT8 *Attributes OPTIONAL
+ )
+{
+ HII_DATABASE_RECORD *Node;
+ LIST_ENTRY *Link;
+ HII_SIMPLE_FONT_PACKAGE_INSTANCE *SimpleFont;
+ LIST_ENTRY *Link1;
+ UINT16 Index;
+ EFI_NARROW_GLYPH Narrow;
+ EFI_WIDE_GLYPH Wide;
+ HII_GLOBAL_FONT_INFO *GlobalFont;
+ UINTN HeaderSize;
+ EFI_NARROW_GLYPH *NarrowPtr;
+ EFI_WIDE_GLYPH *WidePtr;
+
+ if (GlyphBuffer == NULL || Cell == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Private == NULL || Private->Signature != HII_DATABASE_PRIVATE_DATA_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (Cell, sizeof (EFI_HII_GLYPH_INFO));
+
+ //
+ // If StringInfo is not NULL, it must point to an existing EFI_FONT_INFO rather
+ // than system default font and color.
+ // If NULL, try to find the character in simplified font packages since
+ // default system font is the fixed font (narrow or wide glyph).
+ //
+ if (StringInfo != NULL) {
+ if(!IsFontInfoExisted (Private, StringInfo, NULL, NULL, &GlobalFont)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Attributes != NULL) {
+ *Attributes = PROPORTIONAL_GLYPH;
+ }
+ return FindGlyphBlock (GlobalFont->FontPackage, Char, GlyphBuffer, Cell, NULL);
+ } else {
+ HeaderSize = sizeof (EFI_HII_SIMPLE_FONT_PACKAGE_HDR);
+
+ for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
+ Node = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ for (Link1 = Node->PackageList->SimpleFontPkgHdr.ForwardLink;
+ Link1 != &Node->PackageList->SimpleFontPkgHdr;
+ Link1 = Link1->ForwardLink
+ ) {
+ SimpleFont = CR (Link1, HII_SIMPLE_FONT_PACKAGE_INSTANCE, SimpleFontEntry, HII_S_FONT_PACKAGE_SIGNATURE);
+ //
+ // Search the narrow glyph array
+ //
+ NarrowPtr = (EFI_NARROW_GLYPH *) ((UINT8 *) (SimpleFont->SimpleFontPkgHdr) + HeaderSize);
+ for (Index = 0; Index < SimpleFont->SimpleFontPkgHdr->NumberOfNarrowGlyphs; Index++) {
+ CopyMem (&Narrow, NarrowPtr + Index,sizeof (EFI_NARROW_GLYPH));
+ if (Narrow.UnicodeWeight == Char) {
+ *GlyphBuffer = (UINT8 *) AllocateZeroPool (EFI_GLYPH_HEIGHT);
+ if (*GlyphBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Cell->Width = EFI_GLYPH_WIDTH;
+ Cell->Height = EFI_GLYPH_HEIGHT;
+ Cell->OffsetY = NARROW_BASELINE;
+ Cell->AdvanceX = Cell->Width;
+ CopyMem (*GlyphBuffer, Narrow.GlyphCol1, Cell->Height);
+ if (Attributes != NULL) {
+ *Attributes = (UINT8) (Narrow.Attributes | NARROW_GLYPH);
+ }
+ return EFI_SUCCESS;
+ }
+ }
+ //
+ // Search the wide glyph array
+ //
+ WidePtr = (EFI_WIDE_GLYPH *) (NarrowPtr + SimpleFont->SimpleFontPkgHdr->NumberOfNarrowGlyphs);
+ for (Index = 0; Index < SimpleFont->SimpleFontPkgHdr->NumberOfWideGlyphs; Index++) {
+ CopyMem (&Wide, WidePtr + Index, sizeof (EFI_WIDE_GLYPH));
+ if (Wide.UnicodeWeight == Char) {
+ *GlyphBuffer = (UINT8 *) AllocateZeroPool (EFI_GLYPH_HEIGHT * 2);
+ if (*GlyphBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Cell->Width = EFI_GLYPH_WIDTH * 2;
+ Cell->Height = EFI_GLYPH_HEIGHT;
+ Cell->OffsetY = WIDE_BASELINE;
+ Cell->AdvanceX = Cell->Width;
+ CopyMem (*GlyphBuffer, Wide.GlyphCol1, EFI_GLYPH_HEIGHT);
+ CopyMem (*GlyphBuffer + EFI_GLYPH_HEIGHT, Wide.GlyphCol2, EFI_GLYPH_HEIGHT);
+ if (Attributes != NULL) {
+ *Attributes = (UINT8) (Wide.Attributes | EFI_GLYPH_WIDE);
+ }
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+STATIC
+VOID
+NarrowGlyphToBlt (
+ IN UINT8 *GlyphBuffer,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background,
+ IN UINTN ImageWidth,
+ IN UINTN ImageHeight,
+ IN BOOLEAN Transparent,
+ IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **Origin
+ )
+{
+ UINT8 X;
+ UINT8 Y;
+ UINT8 Height;
+ UINT8 Width;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Buffer;
+
+ ASSERT (GlyphBuffer != NULL && Origin != NULL && *Origin != NULL);
+
+ Height = EFI_GLYPH_HEIGHT;
+ Width = EFI_GLYPH_WIDTH;
+
+ ASSERT (Width <= ImageWidth && Height <= ImageHeight);
+
+ Buffer = *Origin;
+
+ for (Y = 0; Y < Height; Y++) {
+ for (X = 0; X < Width; X++) {
+ if ((GlyphBuffer[Y] & (1 << X)) != 0) {
+ Buffer[Y * ImageWidth + (Width - X - 1)] = Foreground;
+ } else {
+ if (!Transparent) {
+ Buffer[Y * ImageWidth + (Width - X - 1)] = Background;
+ }
+ }
+ }
+ }
+
+ *Origin = Buffer + Width;
+}
+
+
+/**
+ Convert bitmap data of the glyph to blt structure.
+
+ @param GlyphBuffer Buffer points to bitmap data of glyph.
+ @param Foreground The color of the "on" pixels in the glyph in the
+ bitmap.
+ @param Background The color of the "off" pixels in the glyph in the
+ bitmap.
+ @param Width Width of the character or character cell, in
+ pixels.
+ @param Height Height of the character or character cell, in
+ pixels.
+ @param Transparent If TRUE, the Background color is ignored and all
+ "off" pixels in the character's drawn wil use the
+ pixel value from BltBuffer.
+ @param BltBuffer Points to the blt buffer.
+
+
+**/
+STATIC
+VOID
+GlyphToBlt (
+ IN UINT8 *GlyphBuffer,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background,
+ IN UINTN ImageWidth,
+ IN UINTN ImageHeight,
+ IN BOOLEAN Transparent,
+ IN EFI_HII_GLYPH_INFO Cell,
+ IN UINT8 Attributes,
+ IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **Origin
+ )
+{
+ UINT8 X;
+ UINT8 Y;
+ UINT8 Data;
+ UINT8 Index;
+ UINTN OffsetY;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
+
+ ASSERT (GlyphBuffer != NULL && Origin != NULL && *Origin != NULL);
+ ASSERT (Cell.Width <= ImageWidth && Cell.Height <= ImageHeight);
+
+ BltBuffer = *Origin;
+
+ //
+ // Since non-spacing key will be printed OR'd with the previous glyph, don't
+ // write 0.
+ //
+ if ((Attributes & EFI_GLYPH_NON_SPACING) == EFI_GLYPH_NON_SPACING) {
+ Transparent = TRUE;
+ }
+
+ //
+ // The glyph's upper left hand corner pixel is the most significant bit of the
+ // first bitmap byte.
+ //
+ for (Y = 0; Y < Cell.Height; Y++) {
+ OffsetY = BITMAP_LEN_1_BIT (Cell.Width, Y);
+
+ //
+ // All bits in these bytes are meaningful.
+ //
+ for (X = 0; X < Cell.Width / 8; X++) {
+ Data = *(GlyphBuffer + OffsetY + X);
+ for (Index = 0; Index < 8; Index++) {
+ if ((Data & (1 << Index)) != 0) {
+ BltBuffer[Y * ImageWidth + X * 8 + (8 - Index - 1)] = Foreground;
+ } else {
+ if (!Transparent) {
+ BltBuffer[Y * ImageWidth + X * 8 + (8 - Index - 1)] = Background;
+ }
+ }
+ }
+ }
+
+ if (Cell.Width % 8 != 0) {
+ //
+ // There are some padding bits in this byte. Ignore them.
+ //
+ Data = *(GlyphBuffer + OffsetY + X);
+ for (Index = 0; Index < Cell.Width % 8; Index++) {
+ if ((Data & (1 << (8 - Index - 1))) != 0) {
+ BltBuffer[Y * ImageWidth + X * 8 + Index] = Foreground;
+ } else {
+ if (!Transparent) {
+ BltBuffer[Y * ImageWidth + X * 8 + Index] = Background;
+ }
+ }
+ }
+ } // end of if (Width % 8...)
+
+ } // end of for (Y=0...)
+
+ *Origin = BltBuffer + Cell.Width;
+}
+
+
+/**
+ Convert bitmap data of the glyph to blt structure.
+
+ @param GlyphBuffer Buffer points to bitmap data of glyph.
+ @param Foreground The color of the "on" pixels in the glyph in the
+ bitmap.
+ @param Background The color of the "off" pixels in the glyph in the
+ bitmap.
+ @param Width Width of the character or character cell, in
+ pixels.
+ @param Height Height of the character or character cell, in
+ pixels.
+ @param Transparent If TRUE, the Background color is ignored and all
+ "off" pixels in the character's drawn wil use the
+ pixel value from BltBuffer.
+ @param Cell Points to EFI_HII_GLYPH_INFO structure.
+ @param Attributes The attribute of incoming glyph in GlyphBuffer.
+ @param Origin On input, points to the origin of the to be
+ displayed character, on output, points to the
+ next glyph's origin.
+
+ @return Points to the address of next origin node in BltBuffer.
+
+**/
+STATIC
+VOID
+GlyphToImage (
+ IN UINT8 *GlyphBuffer,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background,
+ IN UINTN ImageWidth,
+ IN UINTN ImageHeight,
+ IN BOOLEAN Transparent,
+ IN EFI_HII_GLYPH_INFO Cell,
+ IN UINT8 Attributes,
+ IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **Origin
+ )
+{
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Buffer;
+
+ ASSERT (GlyphBuffer != NULL && Origin != NULL && *Origin != NULL);
+ ASSERT (Cell.Width <= ImageWidth && Cell.Height <= ImageHeight);
+
+ Buffer = *Origin;
+
+ if ((Attributes & EFI_GLYPH_NON_SPACING) == EFI_GLYPH_NON_SPACING) {
+ //
+ // This character is a non-spacing key, print it OR'd with the previous glyph.
+ // without advancing cursor.
+ //
+ Buffer -= Cell.Width;
+ GlyphToBlt (
+ GlyphBuffer,
+ Foreground,
+ Background,
+ ImageWidth,
+ ImageHeight,
+ Transparent,
+ Cell,
+ Attributes,
+ &Buffer
+ );
+
+ } else if ((Attributes & EFI_GLYPH_WIDE) == EFI_GLYPH_WIDE) {
+ //
+ // This character is wide glyph, i.e. 16 pixels * 19 pixels.
+ // Draw it as two narrow glyphs.
+ //
+ NarrowGlyphToBlt (
+ GlyphBuffer,
+ Foreground,
+ Background,
+ ImageWidth,
+ ImageHeight,
+ Transparent,
+ Origin
+ );
+
+ NarrowGlyphToBlt (
+ GlyphBuffer + EFI_GLYPH_HEIGHT,
+ Foreground,
+ Background,
+ ImageWidth,
+ ImageHeight,
+ Transparent,
+ Origin
+ );
+
+ } else if ((Attributes & NARROW_GLYPH) == NARROW_GLYPH) {
+ //
+ // This character is narrow glyph, i.e. 8 pixels * 19 pixels.
+ //
+ NarrowGlyphToBlt (
+ GlyphBuffer,
+ Foreground,
+ Background,
+ ImageWidth,
+ ImageHeight,
+ Transparent,
+ Origin
+ );
+
+ } else if ((Attributes & PROPORTIONAL_GLYPH) == PROPORTIONAL_GLYPH) {
+ //
+ // This character is proportional glyph, i.e. Cell.Width * Cell.Height pixels.
+ //
+ GlyphToBlt (
+ GlyphBuffer,
+ Foreground,
+ Background,
+ ImageWidth,
+ ImageHeight,
+ Transparent,
+ Cell,
+ Attributes,
+ Origin
+ );
+ }
+}
+
+
+/**
+ Write the output parameters of FindGlyphBlock().
+
+ @param BufferIn Buffer which stores the bitmap data of the found
+ block.
+ @param BufferLen Length of BufferIn.
+ @param InputCell Buffer which stores cell information of the
+ encoded bitmap.
+ @param GlyphBuffer Output the corresponding bitmap data of the found
+ block. It is the caller's responsiblity to free
+ this buffer.
+ @param Cell Output cell information of the encoded bitmap.
+ @param GlyphBufferLen If not NULL, output the length of GlyphBuffer.
+
+ @retval EFI_SUCCESS The operation is performed successfully.
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+ @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the
+ task.
+
+**/
+STATIC
+EFI_STATUS
+WriteOutputParam (
+ IN UINT8 *BufferIn,
+ IN UINTN BufferLen,
+ IN EFI_HII_GLYPH_INFO *InputCell,
+ OUT UINT8 **GlyphBuffer, OPTIONAL
+ OUT EFI_HII_GLYPH_INFO *Cell, OPTIONAL
+ OUT UINTN *GlyphBufferLen OPTIONAL
+ )
+{
+ if (BufferIn == NULL || BufferLen < 1 || InputCell == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Cell != NULL) {
+ CopyMem (Cell, InputCell, sizeof (EFI_HII_GLYPH_INFO));
+ }
+
+ if (GlyphBuffer != NULL) {
+ *GlyphBuffer = (UINT8 *) AllocateZeroPool (BufferLen);
+ if (*GlyphBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (*GlyphBuffer, BufferIn, BufferLen);
+ }
+
+ if (GlyphBufferLen != NULL) {
+ *GlyphBufferLen = BufferLen;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Parse all glyph blocks to find a glyph block specified by CharValue.
+ If CharValue = (CHAR16) (-1), collect all default character cell information
+ within this font package and backup its information.
+
+ @param FontPackage Hii string package instance.
+ @param CharValue Unicode character value, which identifies a glyph
+ block.
+ @param GlyphBuffer Output the corresponding bitmap data of the found
+ block. It is the caller's responsiblity to free
+ this buffer.
+ @param Cell Output cell information of the encoded bitmap.
+ @param GlyphBufferLen If not NULL, output the length of GlyphBuffer.
+
+ @retval EFI_SUCCESS The bitmap data is retrieved successfully.
+ @retval EFI_NOT_FOUND The specified CharValue does not exist in current
+ database.
+ @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the
+ task.
+
+**/
+EFI_STATUS
+FindGlyphBlock (
+ IN HII_FONT_PACKAGE_INSTANCE *FontPackage,
+ IN CHAR16 CharValue,
+ OUT UINT8 **GlyphBuffer, OPTIONAL
+ OUT EFI_HII_GLYPH_INFO *Cell, OPTIONAL
+ OUT UINTN *GlyphBufferLen OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *BlockPtr;
+ UINT16 CharCurrent;
+ UINT16 Length16;
+ UINT32 Length32;
+ EFI_HII_GIBT_GLYPHS_BLOCK Glyphs;
+ UINTN BufferLen;
+ UINT16 Index;
+ EFI_HII_GLYPH_INFO DefaultCell;
+ EFI_HII_GLYPH_INFO LocalCell;
+
+ ASSERT (FontPackage != NULL);
+ ASSERT (FontPackage->Signature == HII_FONT_PACKAGE_SIGNATURE);
+
+ if (CharValue == (CHAR16) (-1)) {
+ //
+ // Collect the cell information specified in font package fixed header.
+ // Use CharValue =0 to represent this particular cell.
+ //
+ Status = NewCell (
+ 0,
+ &FontPackage->GlyphInfoList,
+ (EFI_HII_GLYPH_INFO *) ((UINT8 *) FontPackage->FontPkgHdr + 3 * sizeof (UINT32))
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ BlockPtr = FontPackage->GlyphBlock;
+ CharCurrent = 1;
+ BufferLen = 0;
+
+ while (*BlockPtr != EFI_HII_GIBT_END) {
+ switch (*BlockPtr) {
+ case EFI_HII_GIBT_DEFAULTS:
+ //
+ // Collect all default character cell information specified by
+ // EFI_HII_GIBT_DEFAULTS.
+ //
+ if (CharValue == (CHAR16) (-1)) {
+ Status = NewCell (
+ CharCurrent,
+ &FontPackage->GlyphInfoList,
+ (EFI_HII_GLYPH_INFO *) (BlockPtr + sizeof (EFI_HII_GLYPH_BLOCK))
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ BlockPtr += sizeof (EFI_HII_GIBT_DEFAULTS_BLOCK);
+ break;
+
+ case EFI_HII_GIBT_DUPLICATE:
+ if (CharCurrent == CharValue) {
+ CopyMem (&CharValue, BlockPtr + sizeof (EFI_HII_GLYPH_BLOCK), sizeof (CHAR16));
+ CharCurrent = 1;
+ BlockPtr = FontPackage->GlyphBlock;
+ continue;
+ }
+ CharCurrent++;
+ BlockPtr += sizeof (EFI_HII_GIBT_DUPLICATE_BLOCK);
+ break;
+
+ case EFI_HII_GIBT_EXT1:
+ BlockPtr += *(BlockPtr + sizeof (EFI_HII_GLYPH_BLOCK) + sizeof (UINT8));
+ break;
+ case EFI_HII_GIBT_EXT2:
+ CopyMem (
+ &Length16,
+ BlockPtr + sizeof (EFI_HII_GLYPH_BLOCK) + sizeof (UINT8),
+ sizeof (UINT16)
+ );
+ BlockPtr += Length16;
+ break;
+ case EFI_HII_GIBT_EXT4:
+ CopyMem (
+ &Length32,
+ BlockPtr + sizeof (EFI_HII_GLYPH_BLOCK) + sizeof (UINT8),
+ sizeof (UINT32)
+ );
+ BlockPtr += Length32;
+ break;
+
+ case EFI_HII_GIBT_GLYPH:
+ CopyMem (
+ &LocalCell,
+ BlockPtr + sizeof (EFI_HII_GLYPH_BLOCK),
+ sizeof (EFI_HII_GLYPH_INFO)
+ );
+ BufferLen = BITMAP_LEN_1_BIT (LocalCell.Width, LocalCell.Height);
+ if (CharCurrent == CharValue) {
+ return WriteOutputParam (
+ BlockPtr + sizeof (EFI_HII_GIBT_GLYPH_BLOCK) - sizeof (UINT8),
+ BufferLen,
+ &LocalCell,
+ GlyphBuffer,
+ Cell,
+ GlyphBufferLen
+ );
+ }
+ CharCurrent++;
+ BlockPtr += sizeof (EFI_HII_GIBT_GLYPH_BLOCK) - sizeof (UINT8) + BufferLen;
+ break;
+
+ case EFI_HII_GIBT_GLYPHS:
+ BlockPtr += sizeof (EFI_HII_GLYPH_BLOCK);
+ CopyMem (&Glyphs.Cell, BlockPtr, sizeof (EFI_HII_GLYPH_INFO));
+ BlockPtr += sizeof (EFI_HII_GLYPH_INFO);
+ CopyMem (&Glyphs.Count, BlockPtr, sizeof (UINT16));
+ BlockPtr += sizeof (UINT16);
+
+ BufferLen = BITMAP_LEN_1_BIT (Glyphs.Cell.Width, Glyphs.Cell.Height);
+ for (Index = 0; Index < Glyphs.Count; Index++) {
+ if (CharCurrent + Index == CharValue) {
+ return WriteOutputParam (
+ BlockPtr,
+ BufferLen,
+ &Glyphs.Cell,
+ GlyphBuffer,
+ Cell,
+ GlyphBufferLen
+ );
+ }
+ BlockPtr += BufferLen;
+ }
+ CharCurrent = (UINT16) (CharCurrent + Glyphs.Count);
+ break;
+
+ case EFI_HII_GIBT_GLYPH_DEFAULT:
+ Status = GetCell (CharCurrent, &FontPackage->GlyphInfoList, &DefaultCell);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ BufferLen = BITMAP_LEN_1_BIT (DefaultCell.Width, DefaultCell.Height);
+
+ if (CharCurrent == CharValue) {
+ return WriteOutputParam (
+ BlockPtr + sizeof (EFI_HII_GLYPH_BLOCK),
+ BufferLen,
+ &DefaultCell,
+ GlyphBuffer,
+ Cell,
+ GlyphBufferLen
+ );
+ }
+ CharCurrent++;
+ BlockPtr += sizeof (EFI_HII_GLYPH_BLOCK) + BufferLen;
+ break;
+
+ case EFI_HII_GIBT_GLYPHS_DEFAULT:
+ CopyMem (&Length16, BlockPtr + sizeof (EFI_HII_GLYPH_BLOCK), sizeof (UINT16));
+ Status = GetCell (CharCurrent, &FontPackage->GlyphInfoList, &DefaultCell);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ BufferLen = BITMAP_LEN_1_BIT (DefaultCell.Width, DefaultCell.Height);
+ BlockPtr += sizeof (EFI_HII_GIBT_GLYPHS_DEFAULT_BLOCK) - sizeof (UINT8);
+ for (Index = 0; Index < Length16; Index++) {
+ if (CharCurrent + Index == CharValue) {
+ return WriteOutputParam (
+ BlockPtr,
+ BufferLen,
+ &DefaultCell,
+ GlyphBuffer,
+ Cell,
+ GlyphBufferLen
+ );
+ }
+ BlockPtr += BufferLen;
+ }
+ CharCurrent = (UINT16) (CharCurrent + Length16);
+ break;
+
+ case EFI_HII_GIBT_SKIP1:
+ CharCurrent = (UINT16) (CharCurrent + (UINT16) (*(BlockPtr + sizeof (EFI_HII_GLYPH_BLOCK))));
+ BlockPtr += sizeof (EFI_HII_GIBT_SKIP1_BLOCK);
+ break;
+ case EFI_HII_GIBT_SKIP2:
+ CopyMem (&Length16, BlockPtr + sizeof (EFI_HII_GLYPH_BLOCK), sizeof (UINT16));
+ CharCurrent = (UINT16) (CharCurrent + Length16);
+ BlockPtr += sizeof (EFI_HII_GIBT_SKIP2_BLOCK);
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ if (CharValue < CharCurrent) {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ if (CharValue == (CHAR16) (-1)) {
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Copy a Font Name to a new created EFI_FONT_INFO structure.
+
+ @param FontName NULL-terminated string.
+ @param FontInfo a new EFI_FONT_INFO which stores the FontName.
+ It's caller's responsibility to free this buffer.
+
+ @retval EFI_SUCCESS FontInfo is allocated and copied with FontName.
+ @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the
+ task.
+
+**/
+STATIC
+EFI_STATUS
+SaveFontName (
+ IN EFI_STRING FontName,
+ OUT EFI_FONT_INFO **FontInfo
+ )
+{
+ UINTN FontInfoLen;
+
+ ASSERT (FontName != NULL && FontInfo != NULL);
+
+ FontInfoLen = sizeof (EFI_FONT_INFO) - sizeof (CHAR16) + StrSize (FontName);
+ *FontInfo = (EFI_FONT_INFO *) AllocateZeroPool (FontInfoLen);
+ if (*FontInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ StrCpy ((*FontInfo)->FontName, FontName);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Retrieve system default font and color.
+
+ @param Private HII database driver private data.
+ @param FontInfo Points to system default font output-related
+ information. It's caller's responsibility to free
+ this buffer.
+ @param FontInfoSize If not NULL, output the size of buffer FontInfo.
+
+ @retval EFI_SUCCESS Cell information is added to the GlyphInfoList.
+ @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the
+ task.
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+
+**/
+EFI_STATUS
+GetSystemFont (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ OUT EFI_FONT_DISPLAY_INFO **FontInfo,
+ OUT UINTN *FontInfoSize OPTIONAL
+ )
+{
+ EFI_FONT_DISPLAY_INFO *Info;
+ UINTN InfoSize;
+
+ if (Private == NULL || Private->Signature != HII_DATABASE_PRIVATE_DATA_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (FontInfo == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // The standard font always has the name "sysdefault".
+ //
+ InfoSize = sizeof (EFI_FONT_DISPLAY_INFO) - sizeof (CHAR16) + StrSize (L"sysdefault");
+ Info = (EFI_FONT_DISPLAY_INFO *) AllocateZeroPool (InfoSize);
+ if (Info == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Info->ForegroundColor = mEfiColors[Private->Attribute & 0x0f];
+ Info->BackgroundColor = mEfiColors[Private->Attribute >> 4];
+ Info->FontInfoMask = EFI_FONT_INFO_SYS_FONT | EFI_FONT_INFO_SYS_SIZE | EFI_FONT_INFO_SYS_STYLE;
+ Info->FontInfo.FontStyle = 0;
+ Info->FontInfo.FontSize = EFI_GLYPH_HEIGHT;
+ StrCpy (Info->FontInfo.FontName, L"sysdefault");
+
+ *FontInfo = Info;
+ if (FontInfoSize != NULL) {
+ *FontInfoSize = InfoSize;
+ }
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Check whether EFI_FONT_DISPLAY_INFO points to system default font and color.
+
+ @param Private HII database driver private data.
+ @param StringInfo Points to the string output information,
+ including the color and font.
+ @param SystemInfo If not NULL, points to system default font and
+ color when incoming StringInfo does not match the
+ default. Points to NULL if matches. It's
+ caller's reponsibility to free this buffer.
+ @param SystemInfoLen If not NULL, output the length of default system
+ info.
+
+ @retval TRUE Yes, it points to system default.
+ @retval FALSE No.
+
+**/
+STATIC
+BOOLEAN
+IsSystemFontInfo (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_FONT_DISPLAY_INFO *StringInfo,
+ OUT EFI_FONT_DISPLAY_INFO **SystemInfo, OPTIONAL
+ OUT UINTN *SystemInfoLen OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_FONT_DISPLAY_INFO *SystemDefault;
+ UINTN DefaultLen;
+
+ ASSERT (Private != NULL && Private->Signature == HII_DATABASE_PRIVATE_DATA_SIGNATURE);
+
+ if (StringInfo == NULL && SystemInfo == NULL) {
+ return TRUE;
+ }
+
+ //
+ // Check whether incoming string font and color matches system default.
+ //
+ Status = GetSystemFont (Private, &SystemDefault, &DefaultLen);
+ ASSERT_EFI_ERROR (Status);
+
+ if (SystemInfo != NULL) {
+ *SystemInfo = SystemDefault;
+ } else {
+ SafeFreePool (SystemDefault);
+ }
+
+ if (SystemInfoLen != NULL) {
+ *SystemInfoLen = DefaultLen;
+ }
+
+ if (StringInfo == NULL ||
+ (StringInfo != NULL && CompareMem (SystemDefault, StringInfo, DefaultLen) == 0)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/**
+ This function checks whether EFI_FONT_INFO exists in current database. If
+ FontInfoMask is specified, check what options can be used to make a match.
+ Note that the masks relate to where the system default should be supplied
+ are ignored by this function.
+
+ @param Private Hii database private structure.
+ @param FontInfo Points to EFI_FONT_INFO structure.
+ @param FontInfoMask If not NULL, describes what options can be used
+ to make a match between the font requested and
+ the font available. The caller must guarantee
+ this mask is valid.
+ @param FontHandle On entry, Points to the font handle returned by a
+ previous call to GetFontInfo() or NULL to start
+ with the first font.
+ @param GlobalFontInfo If not NULL, output the corresponding globa font
+ info.
+
+ @retval TRUE Existed
+ @retval FALSE Not existed
+
+**/
+BOOLEAN
+IsFontInfoExisted (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN EFI_FONT_INFO *FontInfo,
+ IN EFI_FONT_INFO_MASK *FontInfoMask, OPTIONAL
+ IN EFI_FONT_HANDLE FontHandle, OPTIONAL
+ OUT HII_GLOBAL_FONT_INFO **GlobalFontInfo OPTIONAL
+ )
+{
+ HII_GLOBAL_FONT_INFO *GlobalFont;
+ HII_GLOBAL_FONT_INFO *GlobalFontBackup1;
+ HII_GLOBAL_FONT_INFO *GlobalFontBackup2;
+ LIST_ENTRY *Link;
+ EFI_FONT_INFO_MASK Mask;
+ BOOLEAN Matched;
+ BOOLEAN VagueMatched1;
+ BOOLEAN VagueMatched2;
+
+ ASSERT (Private != NULL && Private->Signature == HII_DATABASE_PRIVATE_DATA_SIGNATURE);
+ ASSERT (FontInfo != NULL);
+
+ //
+ // Matched flag represents an exactly match; VagueMatched1 repensents a RESIZE
+ // or RESTYLE match; VagueMatched2 represents a RESIZE | RESTYLE match.
+ //
+ Matched = FALSE;
+ VagueMatched1 = FALSE;
+ VagueMatched2 = FALSE;
+
+ Mask = 0;
+ GlobalFontBackup1 = NULL;
+ GlobalFontBackup2 = NULL;
+
+ // The process of where the system default should be supplied instead of
+ // the specified font info beyonds this function's scope.
+ //
+ if (FontInfoMask != NULL) {
+ Mask = *FontInfoMask & (~SYS_FONT_INFO_MASK);
+ }
+
+ //
+ // If not NULL, FontHandle points to the next node of the last searched font
+ // node by previous call.
+ //
+ if (FontHandle == NULL) {
+ Link = Private->FontInfoList.ForwardLink;
+ } else {
+ Link = (LIST_ENTRY *) FontHandle;
+ }
+
+ for (; Link != &Private->FontInfoList; Link = Link->ForwardLink) {
+ GlobalFont = CR (Link, HII_GLOBAL_FONT_INFO, Entry, HII_GLOBAL_FONT_INFO_SIGNATURE);
+ if (FontInfoMask == NULL) {
+ if (CompareMem (GlobalFont->FontInfo, FontInfo, GlobalFont->FontInfoSize) == 0) {
+ if (GlobalFontInfo != NULL) {
+ *GlobalFontInfo = GlobalFont;
+ }
+ return TRUE;
+ }
+ } else {
+ //
+ // Check which options could be used to make a match.
+ //
+ switch (Mask) {
+ case EFI_FONT_INFO_ANY_FONT:
+ if (GlobalFont->FontInfo->FontStyle == FontInfo->FontStyle &&
+ GlobalFont->FontInfo->FontSize == FontInfo->FontSize) {
+ Matched = TRUE;
+ }
+ break;
+ case EFI_FONT_INFO_ANY_FONT | EFI_FONT_INFO_ANY_STYLE:
+ if (GlobalFont->FontInfo->FontSize == FontInfo->FontSize) {
+ Matched = TRUE;
+ }
+ break;
+ case EFI_FONT_INFO_ANY_FONT | EFI_FONT_INFO_ANY_SIZE:
+ if (GlobalFont->FontInfo->FontStyle == FontInfo->FontStyle) {
+ Matched = TRUE;
+ }
+ break;
+ case EFI_FONT_INFO_ANY_FONT | EFI_FONT_INFO_ANY_SIZE | EFI_FONT_INFO_ANY_STYLE:
+ Matched = TRUE;
+ break;
+ //
+ // If EFI_FONT_INFO_RESTYLE is specified, then the system may attempt to
+ // remove some of the specified styles to meet the style requested.
+ //
+ case EFI_FONT_INFO_ANY_FONT | EFI_FONT_INFO_RESTYLE:
+ if (GlobalFont->FontInfo->FontSize == FontInfo->FontSize) {
+ if (GlobalFont->FontInfo->FontStyle == FontInfo->FontStyle) {
+ Matched = TRUE;
+ } else if ((GlobalFont->FontInfo->FontStyle & FontInfo->FontStyle) == FontInfo->FontStyle) {
+ VagueMatched1 = TRUE;
+ GlobalFontBackup1 = GlobalFont;
+ }
+ }
+ break;
+ //
+ // If EFI_FONT_INFO_RESIZE is specified, then the sytem may attempt to
+ // stretch or shrink a font to meet the size requested.
+ //
+ case EFI_FONT_INFO_ANY_FONT | EFI_FONT_INFO_RESIZE:
+ if (GlobalFont->FontInfo->FontStyle == FontInfo->FontStyle) {
+ if (GlobalFont->FontInfo->FontSize == FontInfo->FontSize) {
+ Matched = TRUE;
+ } else {
+ VagueMatched1 = TRUE;
+ GlobalFontBackup1 = GlobalFont;
+ }
+ }
+ break;
+ case EFI_FONT_INFO_ANY_FONT | EFI_FONT_INFO_RESTYLE | EFI_FONT_INFO_RESIZE:
+ if (GlobalFont->FontInfo->FontStyle == FontInfo->FontStyle) {
+ if (GlobalFont->FontInfo->FontSize == FontInfo->FontSize) {
+ Matched = TRUE;
+ } else {
+ VagueMatched1 = TRUE;
+ GlobalFontBackup1 = GlobalFont;
+ }
+ } else if ((GlobalFont->FontInfo->FontStyle & FontInfo->FontStyle) == FontInfo->FontStyle) {
+ if (GlobalFont->FontInfo->FontSize == FontInfo->FontSize) {
+ VagueMatched1 = TRUE;
+ GlobalFontBackup1 = GlobalFont;
+ } else {
+ VagueMatched2 = TRUE;
+ GlobalFontBackup2 = GlobalFont;
+ }
+ }
+ break;
+ case EFI_FONT_INFO_ANY_FONT | EFI_FONT_INFO_ANY_STYLE | EFI_FONT_INFO_RESIZE:
+ if (GlobalFont->FontInfo->FontSize == FontInfo->FontSize) {
+ Matched = TRUE;
+ } else {
+ VagueMatched1 = TRUE;
+ GlobalFontBackup1 = GlobalFont;
+ }
+ break;
+ case EFI_FONT_INFO_ANY_FONT | EFI_FONT_INFO_ANY_SIZE | EFI_FONT_INFO_RESTYLE:
+ if (GlobalFont->FontInfo->FontStyle == FontInfo->FontStyle) {
+ Matched = TRUE;
+ } else if ((GlobalFont->FontInfo->FontStyle & FontInfo->FontStyle) == FontInfo->FontStyle) {
+ VagueMatched1 = TRUE;
+ GlobalFontBackup1 = GlobalFont;
+ }
+ break;
+ case EFI_FONT_INFO_ANY_STYLE:
+ if ((CompareMem (
+ GlobalFont->FontInfo->FontName,
+ FontInfo->FontName,
+ StrSize (FontInfo->FontName)
+ ) == 0) &&
+ GlobalFont->FontInfo->FontSize == FontInfo->FontSize) {
+ Matched = TRUE;
+ }
+ break;
+ case EFI_FONT_INFO_ANY_STYLE | EFI_FONT_INFO_ANY_SIZE:
+ if (CompareMem (
+ GlobalFont->FontInfo->FontName,
+ FontInfo->FontName,
+ StrSize (FontInfo->FontName)
+ ) == 0) {
+ Matched = TRUE;
+ }
+ break;
+ case EFI_FONT_INFO_ANY_STYLE | EFI_FONT_INFO_RESIZE:
+ if (CompareMem (
+ GlobalFont->FontInfo->FontName,
+ FontInfo->FontName,
+ StrSize (FontInfo->FontName)
+ ) == 0) {
+ if (GlobalFont->FontInfo->FontSize == FontInfo->FontSize) {
+ Matched = TRUE;
+ } else {
+ VagueMatched1 = TRUE;
+ GlobalFontBackup1 = GlobalFont;
+ }
+ }
+ break;
+ case EFI_FONT_INFO_ANY_SIZE:
+ if ((CompareMem (
+ GlobalFont->FontInfo->FontName,
+ FontInfo->FontName,
+ StrSize (FontInfo->FontName)
+ ) == 0) &&
+ GlobalFont->FontInfo->FontStyle == FontInfo->FontStyle) {
+ Matched = TRUE;
+ }
+ break;
+ case EFI_FONT_INFO_ANY_SIZE | EFI_FONT_INFO_RESTYLE:
+ if (CompareMem (
+ GlobalFont->FontInfo->FontName,
+ FontInfo->FontName,
+ StrSize (FontInfo->FontName)
+ ) == 0) {
+ if (GlobalFont->FontInfo->FontStyle == FontInfo->FontStyle) {
+ Matched = TRUE;
+ } else if ((GlobalFont->FontInfo->FontStyle & FontInfo->FontStyle) == FontInfo->FontStyle) {
+ VagueMatched1 = TRUE;
+ GlobalFontBackup1 = GlobalFont;
+ }
+ }
+ break;
+ case EFI_FONT_INFO_RESTYLE:
+ if ((CompareMem (
+ GlobalFont->FontInfo->FontName,
+ FontInfo->FontName,
+ StrSize (FontInfo->FontName)
+ ) == 0) &&
+ GlobalFont->FontInfo->FontSize == FontInfo->FontSize) {
+
+ if (GlobalFont->FontInfo->FontStyle == FontInfo->FontStyle) {
+ Matched = TRUE;
+ } else if ((GlobalFont->FontInfo->FontStyle & FontInfo->FontStyle) == FontInfo->FontStyle) {
+ VagueMatched1 = TRUE;
+ GlobalFontBackup1 = GlobalFont;
+ }
+ }
+ break;
+ case EFI_FONT_INFO_RESIZE:
+ if ((CompareMem (
+ GlobalFont->FontInfo->FontName,
+ FontInfo->FontName,
+ StrSize (FontInfo->FontName)
+ ) == 0) &&
+ GlobalFont->FontInfo->FontStyle == FontInfo->FontStyle) {
+
+ if (GlobalFont->FontInfo->FontSize == FontInfo->FontSize) {
+ Matched = TRUE;
+ } else {
+ VagueMatched1 = TRUE;
+ GlobalFontBackup1 = GlobalFont;
+ }
+ }
+ break;
+ case EFI_FONT_INFO_RESIZE | EFI_FONT_INFO_RESTYLE:
+ if (CompareMem (
+ GlobalFont->FontInfo->FontName,
+ FontInfo->FontName,
+ StrSize (FontInfo->FontName)
+ ) == 0) {
+ if (GlobalFont->FontInfo->FontStyle == FontInfo->FontStyle) {
+ if (GlobalFont->FontInfo->FontSize == FontInfo->FontSize) {
+ Matched = TRUE;
+ } else {
+ VagueMatched1 = TRUE;
+ GlobalFontBackup1 = GlobalFont;
+ }
+ } else if ((GlobalFont->FontInfo->FontStyle & FontInfo->FontStyle) == FontInfo->FontStyle) {
+ if (GlobalFont->FontInfo->FontSize == FontInfo->FontSize) {
+ VagueMatched1 = TRUE;
+ GlobalFontBackup1 = GlobalFont;
+ } else {
+ VagueMatched2 = TRUE;
+ GlobalFontBackup2 = GlobalFont;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (Matched) {
+ if (GlobalFontInfo != NULL) {
+ *GlobalFontInfo = GlobalFont;
+ }
+ return TRUE;
+ }
+ }
+ }
+
+ if (VagueMatched1) {
+ if (GlobalFontInfo != NULL) {
+ *GlobalFontInfo = GlobalFontBackup1;
+ }
+ return TRUE;
+ } else if (VagueMatched2) {
+ if (GlobalFontInfo != NULL) {
+ *GlobalFontInfo = GlobalFontBackup2;
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/**
+ Check whether the unicode represents a line break or not.
+
+ @param Char Unicode character
+
+ @retval 0 Yes, it is a line break.
+ @retval 1 Yes, it is a hyphen that desires a line break
+ after this character.
+ @retval 2 Yes, it is a dash that desires a line break
+ before and after it.
+ @retval -1 No, it is not a link break.
+
+**/
+STATIC
+INT8
+IsLineBreak (
+ IN CHAR16 Char
+ )
+{
+ UINT8 Byte1;
+ UINT8 Byte2;
+
+ //
+ // In little endian, Byte1 is the low byte of Char, Byte2 is the high byte of Char.
+ //
+ Byte1 = *((UINT8 *) (&Char));
+ Byte2 = *(((UINT8 *) (&Char) + 1));
+
+ if (Byte2 == 0x20) {
+ switch (Byte1) {
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x08:
+ case 0x09:
+ case 0x0A:
+ case 0x0B:
+ case 0x28:
+ case 0x29:
+ case 0x5F:
+ return 0;
+ case 0x10:
+ case 0x12:
+ case 0x13:
+ return 1;
+ case 0x14:
+ //
+ // BUGBUG: Does it really require line break before it and after it?
+ //
+ return 2;
+ }
+ } else if (Byte2 == 0x00) {
+ switch (Byte1) {
+ case 0x20:
+ case 0x0C:
+ case 0x0D:
+ return 0;
+ }
+ }
+
+ switch (Char) {
+ case 0x1680:
+ return 0;
+ case 0x058A:
+ case 0x0F0B:
+ case 0x1361:
+ case 0x17D5:
+ return 1;
+ }
+
+ return -1;
+}
+
+
+/**
+ Renders a string to a bitmap or to the display.
+
+ @param This A pointer to the EFI_HII_FONT_PROTOCOL instance.
+ @param Flags Describes how the string is to be drawn.
+ @param String Points to the null-terminated string to be
+ displayed.
+ @param StringInfo Points to the string output information,
+ including the color and font. If NULL, then the
+ string will be output in the default system font
+ and color.
+ @param Blt If this points to a non-NULL on entry, this
+ points to the image, which is Width pixels wide
+ and Height pixels high. The string will be drawn
+ onto this image and
+ EFI_HII_OUT_FLAG_CLIP is implied. If this points
+ to a NULL on entry, then a buffer
+ will be allocated to hold the generated image and
+ the pointer updated on exit. It is the caller¡¯s
+ responsibility to free this buffer.
+ @param BltX,BLTY Specifies the offset from the left and top edge
+ of the image of the first character cell in the
+ image.
+ @param RowInfoArray If this is non-NULL on entry, then on exit, this
+ will point to an allocated buffer containing
+ row information and RowInfoArraySize will be
+ updated to contain the number of elements.
+ This array describes the characters which were at
+ least partially drawn and the heights of the
+ rows. It is the caller¡¯s responsibility to free
+ this buffer.
+ @param RowInfoArraySize If this is non-NULL on entry, then on exit it
+ contains the number of elements in RowInfoArray.
+ @param ColumnInfoArray If this is non-NULL, then on return it will be
+ filled with the horizontal offset for each
+ character in the string on the row where it is
+ displayed. Non-printing characters will have
+ the offset ~0. The caller is responsible to
+ allocate a buffer large enough so that there
+ is one entry for each character in the string,
+ not including the null-terminator. It is possible
+ when character display is normalized that some
+ character cells overlap.
+
+ @retval EFI_SUCCESS The string was successfully rendered.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate an output buffer for
+ RowInfoArray or Blt.
+ @retval EFI_INVALID_PARAMETER The String or Blt was NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiStringToImage (
+ IN CONST EFI_HII_FONT_PROTOCOL *This,
+ IN EFI_HII_OUT_FLAGS Flags,
+ IN CONST EFI_STRING String,
+ IN CONST EFI_FONT_DISPLAY_INFO *StringInfo OPTIONAL,
+ IN OUT EFI_IMAGE_OUTPUT **Blt,
+ IN UINTN BltX,
+ IN UINTN BltY,
+ OUT EFI_HII_ROW_INFO **RowInfoArray OPTIONAL,
+ OUT UINTN *RowInfoArraySize OPTIONAL,
+ OUT UINTN *ColumnInfoArray OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ UINT8 **GlyphBuf;
+ EFI_HII_GLYPH_INFO *Cell;
+ UINT8 *Attributes;
+ EFI_IMAGE_OUTPUT *Image;
+ EFI_STRING StringPtr;
+ EFI_STRING StringTmp;
+ EFI_HII_ROW_INFO *RowInfo;
+ UINTN LineWidth;
+ UINTN LineHeight;
+ UINTN BaseLineOffset;
+ UINT16 MaxRowNum;
+ UINT16 RowIndex;
+ UINTN Index;
+ UINTN Index1;
+ EFI_FONT_DISPLAY_INFO *StringInfoOut;
+ EFI_FONT_DISPLAY_INFO *SystemDefault;
+ EFI_FONT_HANDLE FontHandle;
+ EFI_STRING StringIn;
+ EFI_STRING StringIn2;
+ UINT16 Height;
+ EFI_FONT_INFO *FontInfo;
+ BOOLEAN SysFontFlag;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;
+ BOOLEAN Transparent;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BufferPtr;
+ UINTN RowInfoSize;
+ BOOLEAN LineBreak;
+
+ //
+ // Check incoming parameters.
+ //
+
+ if (This == NULL || String == NULL || Blt == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (*Blt == NULL) {
+ //
+ // These two flag cannot be used if Blt is NULL upon entry.
+ //
+ if ((Flags & EFI_HII_OUT_FLAG_TRANSPARENT) == EFI_HII_OUT_FLAG_TRANSPARENT) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((Flags & EFI_HII_OUT_FLAG_CLIP) == EFI_HII_OUT_FLAG_CLIP) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // These two flags require that EFI_HII_OUT_FLAG_CLIP be also set.
+ //
+ if ((Flags & (EFI_HII_OUT_FLAG_CLIP | EFI_HII_OUT_FLAG_CLEAN_X)) == EFI_HII_OUT_FLAG_CLEAN_X) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((Flags & (EFI_HII_OUT_FLAG_CLIP | EFI_HII_OUT_FLAG_CLEAN_Y)) == EFI_HII_OUT_FLAG_CLEAN_Y) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // This flag cannot be used with EFI_HII_OUT_FLAG_CLEAN_X.
+ //
+ if ((Flags & (EFI_HII_OUT_FLAG_WRAP | EFI_HII_OUT_FLAG_CLEAN_X)) == (EFI_HII_OUT_FLAG_WRAP | EFI_HII_OUT_FLAG_CLEAN_X)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ GlyphBuf = (UINT8 **) AllocateZeroPool (MAX_STRING_LENGTH * sizeof (UINT8 *));
+ ASSERT (GlyphBuf != NULL);
+ Cell = (EFI_HII_GLYPH_INFO *) AllocateZeroPool (MAX_STRING_LENGTH * sizeof (EFI_HII_GLYPH_INFO));
+ ASSERT (Cell != NULL);
+ Attributes = (UINT8 *) AllocateZeroPool (MAX_STRING_LENGTH * sizeof (UINT8));
+ ASSERT (Attributes != NULL);
+
+ RowInfo = NULL;
+ Status = EFI_SUCCESS;
+ StringIn2 = NULL;
+ SystemDefault = NULL;
+
+ //
+ // Calculate the string output information, including specified color and font .
+ // If StringInfo does not points to system font info, it must indicate an existing
+ // EFI_FONT_INFO.
+ //
+ StringInfoOut = NULL;
+ FontHandle = NULL;
+ Private = HII_FONT_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ SysFontFlag = IsSystemFontInfo (Private, (EFI_FONT_DISPLAY_INFO *) StringInfo, &SystemDefault, NULL);
+
+ if (SysFontFlag) {
+ FontInfo = NULL;
+ Height = SystemDefault->FontInfo.FontSize;
+ Foreground = SystemDefault->ForegroundColor;
+ Background = SystemDefault->BackgroundColor;
+
+ } else {
+ Status = HiiGetFontInfo (This, &FontHandle, (EFI_FONT_DISPLAY_INFO *) StringInfo, &StringInfoOut, NULL);
+ if (Status == EFI_NOT_FOUND) {
+ //
+ // The specified EFI_FONT_DISPLAY_INFO does not exist in current database.
+ // Use the system font instead. Still use the color specified by StringInfo.
+ //
+ SysFontFlag = TRUE;
+ FontInfo = NULL;
+ Height = SystemDefault->FontInfo.FontSize;
+ Foreground = ((EFI_FONT_DISPLAY_INFO *) StringInfo)->ForegroundColor;
+ Background = ((EFI_FONT_DISPLAY_INFO *) StringInfo)->BackgroundColor;
+
+ } else {
+ FontInfo = &StringInfoOut->FontInfo;
+ Height = StringInfoOut->FontInfo.FontSize;
+ Foreground = StringInfoOut->ForegroundColor;
+ Background = StringInfoOut->BackgroundColor;
+ }
+ }
+
+ //
+ // Parse the string to be displayed to drop some ignored characters.
+ //
+
+ StringPtr = String;
+ StringIn = NULL;
+
+ //
+ // Ignore line-break characters only. Hyphens or dash character will be displayed
+ // without line-break opportunity.
+ //
+ if ((Flags & EFI_HII_IGNORE_LINE_BREAK) == EFI_HII_IGNORE_LINE_BREAK) {
+ StringIn = AllocateZeroPool (StrSize (StringPtr));
+ if (StringIn == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ StringTmp = StringIn;
+ while (*StringPtr != 0) {
+ if (IsLineBreak (*StringPtr) == 0) {
+ StringPtr++;
+ } else {
+ *StringTmp++ = *StringPtr++;
+ }
+ }
+ *StringTmp = 0;
+ StringPtr = StringIn;
+ }
+ //
+ // If EFI_HII_IGNORE_IF_NO_GLYPH is set, then characters which have no glyphs
+ // are not drawn. Otherwise they are replaced wth Unicode character 0xFFFD.
+ //
+ StringIn2 = AllocateZeroPool (StrSize (StringPtr));
+ if (StringIn2 == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ Index = 0;
+ StringTmp = StringIn2;
+
+ while (*StringPtr != 0 && Index < MAX_STRING_LENGTH) {
+ Status = GetGlyphBuffer (Private, *StringPtr, FontInfo, &GlyphBuf[Index], &Cell[Index], &Attributes[Index]);
+ if (Status == EFI_NOT_FOUND) {
+ if ((Flags & EFI_HII_IGNORE_IF_NO_GLYPH) == EFI_HII_IGNORE_IF_NO_GLYPH) {
+ SafeFreePool (GlyphBuf[Index]);
+ GlyphBuf[Index] = NULL;
+ StringPtr++;
+ } else {
+ //
+ // Unicode 0xFFFD must exist in current hii database if this flag is not set.
+ //
+ Status = GetGlyphBuffer (
+ Private,
+ REPLACE_UNKNOWN_GLYPH,
+ FontInfo,
+ &GlyphBuf[Index],
+ &Cell[Index],
+ &Attributes[Index]
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+ *StringTmp++ = *StringPtr++;
+ Index++;
+ }
+ } else if (EFI_ERROR (Status)) {
+ goto Exit;
+ } else {
+ *StringTmp++ = *StringPtr++;
+ Index++;
+ }
+ }
+ *StringTmp = 0;
+ StringPtr = StringIn2;
+
+ //
+ // Draw the string according to the specified EFI_HII_OUT_FLAGS and Blt.
+ // If Blt is not NULL, then EFI_HII_OUT_FLAG_CLIP is implied, render this string
+ // to an existing image (bitmap or screen depending on flags) pointed by "*Blt".
+ // Otherwise render this string to a new allocated image and output it.
+ //
+ if (*Blt != NULL) {
+ Image = *Blt;
+ BufferPtr = Image->Image.Bitmap + Image->Width * BltY + BltX;
+ MaxRowNum = (UINT16) (Image->Height / Height);
+ if (Image->Height % Height != 0) {
+ MaxRowNum++;
+ }
+
+ RowInfo = (EFI_HII_ROW_INFO *) AllocateZeroPool (MaxRowNum * sizeof (EFI_HII_ROW_INFO));
+ if (RowInfo == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ //
+ // Format the glyph buffer according to flags.
+ //
+
+ Transparent = (BOOLEAN) ((Flags & EFI_HII_OUT_FLAG_TRANSPARENT) == EFI_HII_OUT_FLAG_TRANSPARENT ? TRUE : FALSE);
+ if ((Flags & EFI_HII_OUT_FLAG_CLEAN_Y) == EFI_HII_OUT_FLAG_CLEAN_Y) {
+ //
+ // Don't draw at all if there is only one row and
+ // the row's bottom-most on pixel cannot fit.
+ //
+ if (MaxRowNum == 1 && SysFontFlag) {
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+ }
+
+ for (RowIndex = 0, Index = 0; RowIndex < MaxRowNum && StringPtr[Index] != 0; ) {
+ LineWidth = 0;
+ LineHeight = 0;
+ BaseLineOffset = 0;
+ LineBreak = FALSE;
+
+ //
+ // Calculate how many characters there are in a row.
+ //
+ RowInfo[RowIndex].StartIndex = Index;
+
+ while (LineWidth + BltX < Image->Width && StringPtr[Index] != 0) {
+ LineWidth += (UINTN) Cell[Index].AdvanceX;
+ if (LineHeight < Cell[Index].Height) {
+ LineHeight = (UINTN) Cell[Index].Height;
+ }
+ BaseLineOffset += (UINTN) Cell[Index].OffsetY;
+
+ if ((Flags & EFI_HII_IGNORE_LINE_BREAK) == 0 &&
+ (Flags & EFI_HII_OUT_FLAG_WRAP) == 0 &&
+ IsLineBreak (StringPtr[Index]) > 0) {
+ //
+ // It is a line break that ends this row.
+ //
+ Index++;
+ break;
+ }
+
+ Index++;
+ }
+
+ //
+ // If this character is the last character of a row, we need not
+ // draw its (AdvanceX - Width) for next character.
+ //
+ Index--;
+ if (!SysFontFlag) {
+ LineWidth -= (UINTN) (Cell[Index].AdvanceX - Cell[Index].Width);
+ }
+
+ //
+ // EFI_HII_OUT_FLAG_WRAP will wrap the text at the right-most line-break
+ // opportunity prior to a character whose right-most extent would exceed Width.
+ // Search the right-most line-break opportunity here.
+ //
+ if ((Flags & EFI_HII_OUT_FLAG_WRAP) == EFI_HII_OUT_FLAG_WRAP) {
+ if ((Flags & EFI_HII_IGNORE_LINE_BREAK) == 0) {
+ for (Index1 = RowInfo[RowIndex].EndIndex; Index1 >= RowInfo[RowIndex].StartIndex; Index1--) {
+ if (IsLineBreak (StringPtr[Index1]) > 0) {
+ LineBreak = TRUE;
+ RowInfo[RowIndex].EndIndex = Index1 - 1;
+ break;
+ }
+ }
+ }
+ //
+ // If no line-break opportunity can be found, then the text will
+ // behave as if EFI_HII_OUT_FLAG_CLEAN_X is set.
+ //
+ if (!LineBreak) {
+ Flags &= (~ (EFI_HII_OUT_FLAGS) EFI_HII_OUT_FLAG_WRAP);
+ Flags |= EFI_HII_OUT_FLAG_CLEAN_X;
+ }
+ }
+
+ //
+ // Clip the right-most character if cannot fit when EFI_HII_OUT_FLAG_CLEAN_X is set.
+ //
+ if (LineWidth + BltX <= Image->Width ||
+ (LineWidth + BltX > Image->Width && (Flags & EFI_HII_OUT_FLAG_CLEAN_X) == 0)) {
+ //
+ // Record right-most character in RowInfo even if it is partially displayed.
+ //
+ RowInfo[RowIndex].EndIndex = Index;
+ RowInfo[RowIndex].LineWidth = LineWidth;
+ RowInfo[RowIndex].LineHeight = LineHeight;
+ RowInfo[RowIndex].BaselineOffset = BaseLineOffset;
+ } else {
+ //
+ // When EFI_HII_OUT_FLAG_CLEAN_X is set, it will not draw a character
+ // if its right-most on pixel cannot fit.
+ //
+ if (Index > 0) {
+ RowInfo[RowIndex].EndIndex = Index - 1;
+ RowInfo[RowIndex].LineWidth = LineWidth - Cell[Index].AdvanceX;
+ RowInfo[RowIndex].BaselineOffset = BaseLineOffset - Cell[Index].OffsetY;
+ if (LineHeight > Cell[Index - 1].Height) {
+ LineHeight = Cell[Index - 1].Height;
+ }
+ RowInfo[RowIndex].LineHeight = LineHeight;
+ } else {
+ //
+ // There is only one column and it can not be drawn so that return directly.
+ //
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+ }
+
+ //
+ // Clip the final row if the row's bottom-most on pixel cannot fit when
+ // EFI_HII_OUT_FLAG_CLEAN_Y is set.
+ //
+ if (RowIndex == MaxRowNum - 1 && Image->Height < LineHeight) {
+ LineHeight = Image->Height;
+ if ((Flags & EFI_HII_OUT_FLAG_CLEAN_Y) == EFI_HII_OUT_FLAG_CLEAN_Y) {
+ //
+ // Don't draw at all if the row's bottom-most on pixel cannot fit.
+ //
+ break;
+ }
+ }
+
+ //
+ // Draw it to screen or existing bitmap depending on whether
+ // EFI_HII_DIRECT_TO_SCREEN is set.
+ //
+ if ((Flags & EFI_HII_DIRECT_TO_SCREEN) == EFI_HII_DIRECT_TO_SCREEN) {
+ BltBuffer = AllocateZeroPool (RowInfo[RowIndex].LineWidth * RowInfo[RowIndex].LineHeight * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+ if (BltBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ BufferPtr = BltBuffer;
+ for (Index1 = RowInfo[RowIndex].StartIndex; Index1 <= RowInfo[RowIndex].EndIndex; Index1++) {
+ GlyphToImage (
+ GlyphBuf[Index1],
+ Foreground,
+ Background,
+ RowInfo[RowIndex].LineWidth,
+ RowInfo[RowIndex].LineHeight,
+ Transparent,
+ Cell[Index1],
+ Attributes[Index1],
+ &BufferPtr
+ );
+ if (ColumnInfoArray != NULL) {
+ if (Index1 == RowInfo[RowIndex].StartIndex) {
+ *ColumnInfoArray = 0;
+ } else {
+ *ColumnInfoArray = Cell[Index1 -1].AdvanceX;
+ }
+ ColumnInfoArray++;
+ }
+ }
+ Status = Image->Image.Screen->Blt (
+ Image->Image.Screen,
+ BltBuffer,
+ EfiBltBufferToVideo,
+ 0,
+ 0,
+ BltX,
+ BltY,
+ RowInfo[RowIndex].LineWidth,
+ RowInfo[RowIndex].LineHeight,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ SafeFreePool (BltBuffer);
+ goto Exit;
+ }
+
+ SafeFreePool (BltBuffer);
+
+ } else {
+ for (Index1 = RowInfo[RowIndex].StartIndex; Index1 <= RowInfo[RowIndex].EndIndex; Index1++) {
+ GlyphToImage (
+ GlyphBuf[Index1],
+ Foreground,
+ Background,
+ Image->Width,
+ Image->Height,
+ Transparent,
+ Cell[Index1],
+ Attributes[Index1],
+ &BufferPtr
+ );
+ if (ColumnInfoArray != NULL) {
+ if (Index1 == RowInfo[RowIndex].StartIndex) {
+ *ColumnInfoArray = 0;
+ } else {
+ *ColumnInfoArray = Cell[Index1 -1].AdvanceX;
+ }
+ ColumnInfoArray++;
+ }
+ }
+ //
+ // Jump to next row
+ //
+ BufferPtr += BltX + Image->Width * (LineHeight - 1);
+ }
+
+ Index++;
+ RowIndex++;
+
+ }
+
+ //
+ // Write output parameters.
+ //
+ RowInfoSize = RowIndex * sizeof (EFI_HII_ROW_INFO);
+ if (RowInfoArray != NULL) {
+ *RowInfoArray = AllocateZeroPool (RowInfoSize);
+ if (*RowInfoArray == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ CopyMem (*RowInfoArray, RowInfo, RowInfoSize);
+ }
+ if (RowInfoArraySize != NULL) {
+ *RowInfoArraySize = RowIndex;
+ }
+
+ } else {
+ //
+ // Create a new bitmap and draw the string onto this image.
+ //
+ Image = AllocateZeroPool (sizeof (EFI_IMAGE_OUTPUT));
+ if (Image == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Image->Width = 800;
+ Image->Height = 600;
+ Image->Image.Bitmap = AllocateZeroPool (Image->Width * Image->Height *sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+ if (Image->Image.Bitmap == NULL) {
+ SafeFreePool (Image);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Other flags are not permitted when Blt is NULL.
+ //
+ Flags &= EFI_HII_OUT_FLAG_WRAP | EFI_HII_IGNORE_IF_NO_GLYPH | EFI_HII_IGNORE_LINE_BREAK;
+ Status = HiiStringToImage (
+ This,
+ Flags,
+ String,
+ StringInfo,
+ &Image,
+ BltX,
+ BltY,
+ RowInfoArray,
+ RowInfoArraySize,
+ ColumnInfoArray
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *Blt = Image;
+ }
+
+ Status = EFI_SUCCESS;
+
+Exit:
+
+ for (Index = 0; Index < MAX_STRING_LENGTH; Index++) {
+ SafeFreePool (GlyphBuf[Index]);
+ }
+ SafeFreePool (StringIn);
+ SafeFreePool (StringIn2);
+ SafeFreePool (StringInfoOut);
+ SafeFreePool (RowInfo);
+ SafeFreePool (SystemDefault);
+ SafeFreePool (GlyphBuf);
+ SafeFreePool (Cell);
+ SafeFreePool (Attributes);
+
+ return Status;
+}
+
+
+/**
+ Render a string to a bitmap or the screen containing the contents of the specified string.
+
+ @param This A pointer to the EFI_HII_FONT_PROTOCOL instance.
+ @param Flags Describes how the string is to be drawn.
+ @param PackageList The package list in the HII database to search
+ for the specified string.
+ @param StringId The string¡¯s id, which is unique within
+ PackageList.
+ @param Language Points to the language for the retrieved string.
+ If NULL, then the current system language is
+ used.
+ @param StringInfo Points to the string output information,
+ including the color and font. If NULL, then the
+ string will be output in the default system font
+ and color.
+ @param Blt If this points to a non-NULL on entry, this
+ points to the image, which is Width pixels wide
+ and Height pixels high. The string will be drawn
+ onto this image and
+ EFI_HII_OUT_FLAG_CLIP is implied. If this points
+ to a NULL on entry, then a buffer
+ will be allocated to hold the generated image and
+ the pointer updated on exit. It is the caller¡¯s
+ responsibility to free this buffer.
+ @param BltX,BLTY Specifies the offset from the left and top edge
+ of the image of the first character cell in the
+ image.
+ @param RowInfoArray If this is non-NULL on entry, then on exit, this
+ will point to an allocated buffer containing
+ row information and RowInfoArraySize will be
+ updated to contain the number of elements.
+ This array describes the characters which were at
+ least partially drawn and the heights of the
+ rows. It is the caller¡¯s responsibility to free
+ this buffer.
+ @param RowInfoArraySize If this is non-NULL on entry, then on exit it
+ contains the number of elements in RowInfoArray.
+ @param ColumnInfoArray If this is non-NULL, then on return it will be
+ filled with the horizontal offset for each
+ character in the string on the row where it is
+ displayed. Non-printing characters will have
+ the offset ~0. The caller is responsible to
+ allocate a buffer large enough so that there
+ is one entry for each character in the string,
+ not including the null-terminator. It is possible
+ when character display is normalized that some
+ character cells overlap.
+
+ @retval EFI_SUCCESS The string was successfully rendered.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate an output buffer for
+ RowInfoArray or Blt.
+ @retval EFI_INVALID_PARAMETER The PackageList was NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiStringIdToImage (
+ IN CONST EFI_HII_FONT_PROTOCOL *This,
+ IN EFI_HII_OUT_FLAGS Flags,
+ IN EFI_HII_HANDLE PackageList,
+ IN EFI_STRING_ID StringId,
+ IN CONST CHAR8* Language,
+ IN CONST EFI_FONT_DISPLAY_INFO *StringInfo OPTIONAL,
+ IN OUT EFI_IMAGE_OUTPUT **Blt,
+ IN UINTN BltX,
+ IN UINTN BltY,
+ OUT EFI_HII_ROW_INFO **RowInfoArray OPTIONAL,
+ OUT UINTN *RowInfoArraySize OPTIONAL,
+ OUT UINTN *ColumnInfoArray OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ EFI_STRING String;
+ UINTN StringSize;
+
+ if (This == NULL || PackageList == NULL || Blt == NULL || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!IsHiiHandleValid (PackageList)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Private = HII_FONT_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // Get the string to be displayed.
+ //
+
+ StringSize = MAX_STRING_LENGTH;
+ String = (EFI_STRING) AllocateZeroPool (StringSize);
+ if (String == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = Private->HiiString.GetString (
+ &Private->HiiString,
+ Language,
+ PackageList,
+ StringId,
+ String,
+ &StringSize,
+ NULL
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ SafeFreePool (String);
+ String = (EFI_STRING) AllocateZeroPool (StringSize);
+ if (String == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = Private->HiiString.GetString (
+ &Private->HiiString,
+ Language,
+ PackageList,
+ StringId,
+ String,
+ &StringSize,
+ NULL
+ );
+
+ }
+
+ if (EFI_ERROR (Status)) {
+ SafeFreePool (String);
+ return Status;
+ }
+
+ return HiiStringToImage (
+ This,
+ Flags,
+ String,
+ StringInfo,
+ Blt,
+ BltX,
+ BltY,
+ RowInfoArray,
+ RowInfoArraySize,
+ ColumnInfoArray
+ );
+
+}
+
+
+/**
+ Convert the glyph for a single character into a bitmap.
+
+ @param This A pointer to the EFI_HII_FONT_PROTOCOL instance.
+ @param Char Character to retrieve.
+ @param StringInfo Points to the string font and color information
+ or NULL if the string should use the default
+ system font and color.
+ @param Blt Thus must point to a NULL on entry. A buffer will
+ be allocated to hold the output and the pointer
+ updated on exit. It is the caller¡¯s
+ responsibility to free this buffer.
+ @param Baseline Number of pixels from the bottom of the bitmap to
+ the baseline.
+
+ @retval EFI_SUCCESS Glyph bitmap created.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate the output buffer Blt.
+ @retval EFI_WARN_UNKNOWN_GLYPH The glyph was unknown and was replaced with the
+ glyph for Unicode character 0xFFFD.
+ @retval EFI_INVALID_PARAMETER Blt is NULL or *Blt is not NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetGlyph (
+ IN CONST EFI_HII_FONT_PROTOCOL *This,
+ IN CHAR16 Char,
+ IN CONST EFI_FONT_DISPLAY_INFO *StringInfo,
+ OUT EFI_IMAGE_OUTPUT **Blt,
+ OUT UINTN *Baseline OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ EFI_IMAGE_OUTPUT *Image;
+ UINT8 *GlyphBuffer;
+ EFI_FONT_DISPLAY_INFO *SystemDefault;
+ EFI_FONT_DISPLAY_INFO *StringInfoOut;
+ BOOLEAN Default;
+ EFI_FONT_HANDLE FontHandle;
+ EFI_STRING String;
+ EFI_HII_GLYPH_INFO Cell;
+ EFI_FONT_INFO *FontInfo;
+ UINT8 Attributes;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
+
+ if (This == NULL || Blt == NULL || *Blt != NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = HII_FONT_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+
+ Default = FALSE;
+ Image = NULL;
+ SystemDefault = NULL;
+ FontHandle = NULL;
+ String = NULL;
+ GlyphBuffer = NULL;
+ StringInfoOut = NULL;
+ FontInfo = NULL;
+
+ ZeroMem (&Foreground, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+ ZeroMem (&Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+
+ Default = IsSystemFontInfo (Private, (EFI_FONT_DISPLAY_INFO *) StringInfo, &SystemDefault, NULL);
+
+ if (!Default) {
+ //
+ // Find out a EFI_FONT_DISPLAY_INFO which could display the character in
+ // the specified color and font.
+ //
+ String = (EFI_STRING) AllocateZeroPool (sizeof (CHAR16) * 2);
+ if (String == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ *String = Char;
+ *(String + 1) = 0;
+
+ Status = HiiGetFontInfo (This, &FontHandle, StringInfo, &StringInfoOut, String);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+ FontInfo = &StringInfoOut->FontInfo;
+ Foreground = StringInfoOut->ForegroundColor;
+ Background = StringInfoOut->BackgroundColor;
+ } else {
+ Foreground = SystemDefault->ForegroundColor;
+ Background = SystemDefault->BackgroundColor;
+ }
+
+ Status = GetGlyphBuffer (Private, Char, FontInfo, &GlyphBuffer, &Cell, &Attributes);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ Image = (EFI_IMAGE_OUTPUT *) AllocateZeroPool (sizeof (EFI_IMAGE_OUTPUT));
+ if (Image == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ Image->Width = Cell.Width;
+ Image->Height = Cell.Height;
+
+ Image->Image.Bitmap = AllocateZeroPool (Image->Width * Image->Height * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+ if (Image->Image.Bitmap == NULL) {
+ SafeFreePool (Image);
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ BltBuffer = Image->Image.Bitmap;
+ GlyphToImage (
+ GlyphBuffer,
+ Foreground,
+ Background,
+ Image->Width,
+ Image->Height,
+ FALSE,
+ Cell,
+ Attributes,
+ &BltBuffer
+ );
+
+ *Blt = Image;
+ if (Baseline != NULL) {
+ *Baseline = Cell.OffsetY;
+ }
+
+ Status = EFI_SUCCESS;
+
+Exit:
+
+ if (Status == EFI_NOT_FOUND) {
+ //
+ // Glyph is unknown and replaced with the glyph for unicode character 0xFFFD
+ //
+ if (Char != REPLACE_UNKNOWN_GLYPH) {
+ Status = HiiGetGlyph (This, REPLACE_UNKNOWN_GLYPH, StringInfo, Blt, Baseline);
+ if (!EFI_ERROR (Status)) {
+ Status = EFI_WARN_UNKNOWN_GLYPH;
+ }
+ } else {
+ Status = EFI_WARN_UNKNOWN_GLYPH;
+ }
+ }
+
+ SafeFreePool (SystemDefault);
+ SafeFreePool (StringInfoOut);
+ SafeFreePool (String);
+ SafeFreePool (GlyphBuffer);
+
+ return Status;
+}
+
+
+/**
+ This function iterates through fonts which match the specified font, using
+ the specified criteria. If String is non-NULL, then all of the characters in
+ the string must exist in order for a candidate font to be returned.
+
+ @param This A pointer to the EFI_HII_FONT_PROTOCOL instance.
+ @param FontHandle On entry, points to the font handle returned by a
+ previous call to GetFontInfo() or NULL to start
+ with the first font. On return, points to the
+ returned font handle or points to NULL if there
+ are no more matching fonts.
+ @param StringInfoIn Upon entry, points to the font to return
+ information about.
+ @param StringInfoOut Upon return, contains the matching font¡¯s
+ information. If NULL, then no information is
+ returned. It's caller's responsibility to free
+ this buffer.
+ @param String Points to the string which will be tested to
+ determine if all characters are available. If
+ NULL, then any font is acceptable.
+
+ @retval EFI_SUCCESS Matching font returned successfully.
+ @retval EFI_NOT_FOUND No matching font was found.
+ @retval EFI_INVALID_PARAMETER StringInfoIn is NULL.
+ @retval EFI_OUT_OF_RESOURCES There were insufficient resources to complete the
+ request.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetFontInfo (
+ IN CONST EFI_HII_FONT_PROTOCOL *This,
+ IN OUT EFI_FONT_HANDLE *FontHandle,
+ IN CONST EFI_FONT_DISPLAY_INFO *StringInfoIn,
+ OUT EFI_FONT_DISPLAY_INFO **StringInfoOut,
+ IN CONST EFI_STRING String OPTIONAL
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+ EFI_STATUS Status;
+ EFI_FONT_DISPLAY_INFO *SystemDefault;
+ EFI_FONT_DISPLAY_INFO InfoOut;
+ UINTN StringInfoOutLen;
+ EFI_FONT_INFO *FontInfo;
+ HII_GLOBAL_FONT_INFO *GlobalFont;
+ EFI_STRING StringIn;
+ EFI_FONT_HANDLE LocalFontHandle;
+
+ if (This == NULL || StringInfoIn == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check the font information mask to make sure it is valid.
+ //
+ if (((StringInfoIn->FontInfoMask & (EFI_FONT_INFO_SYS_FONT | EFI_FONT_INFO_ANY_FONT)) ==
+ (EFI_FONT_INFO_SYS_FONT | EFI_FONT_INFO_ANY_FONT)) ||
+ ((StringInfoIn->FontInfoMask & (EFI_FONT_INFO_SYS_SIZE | EFI_FONT_INFO_ANY_SIZE)) ==
+ (EFI_FONT_INFO_SYS_SIZE | EFI_FONT_INFO_ANY_SIZE)) ||
+ ((StringInfoIn->FontInfoMask & (EFI_FONT_INFO_SYS_STYLE | EFI_FONT_INFO_ANY_STYLE)) ==
+ (EFI_FONT_INFO_SYS_STYLE | EFI_FONT_INFO_ANY_STYLE)) ||
+ ((StringInfoIn->FontInfoMask & (EFI_FONT_INFO_RESIZE | EFI_FONT_INFO_ANY_SIZE)) ==
+ (EFI_FONT_INFO_RESIZE | EFI_FONT_INFO_ANY_SIZE)) ||
+ ((StringInfoIn->FontInfoMask & (EFI_FONT_INFO_RESTYLE | EFI_FONT_INFO_ANY_STYLE)) ==
+ (EFI_FONT_INFO_RESTYLE | EFI_FONT_INFO_ANY_STYLE))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FontInfo = NULL;
+ LocalFontHandle = NULL;
+ if (FontHandle != NULL) {
+ LocalFontHandle = *FontHandle;
+ }
+
+ //
+ // Get default system display info, if StringInfoIn points to
+ // system display info, return it directly.
+ //
+ Private = HII_FONT_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+
+ if (IsSystemFontInfo (Private, (EFI_FONT_DISPLAY_INFO *) StringInfoIn, &SystemDefault, &StringInfoOutLen)) {
+ if (StringInfoOut != NULL) {
+ *StringInfoOut = AllocateCopyPool (StringInfoOutLen, (EFI_FONT_DISPLAY_INFO *) StringInfoIn);
+ if (*StringInfoOut == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ LocalFontHandle = NULL;
+ goto Exit;
+ }
+ }
+
+ LocalFontHandle = Private->FontInfoList.ForwardLink;
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+
+ //
+ // Parse the font information mask to find a matching font.
+ //
+
+ CopyMem (&InfoOut, (EFI_FONT_DISPLAY_INFO *) StringInfoIn, sizeof (EFI_FONT_DISPLAY_INFO));
+
+ if ((StringInfoIn->FontInfoMask & EFI_FONT_INFO_SYS_FONT) == EFI_FONT_INFO_SYS_FONT) {
+ Status = SaveFontName (SystemDefault->FontInfo.FontName, &FontInfo);
+ } else {
+ Status = SaveFontName (((EFI_FONT_DISPLAY_INFO *) StringInfoIn)->FontInfo.FontName, &FontInfo);
+ }
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ if ((StringInfoIn->FontInfoMask & EFI_FONT_INFO_SYS_SIZE) == EFI_FONT_INFO_SYS_SIZE) {
+ InfoOut.FontInfo.FontSize = SystemDefault->FontInfo.FontSize;
+ } else if ((StringInfoIn->FontInfoMask & EFI_FONT_INFO_SYS_STYLE) == EFI_FONT_INFO_SYS_STYLE) {
+ InfoOut.FontInfo.FontStyle = SystemDefault->FontInfo.FontStyle;
+ } else if ((StringInfoIn->FontInfoMask & EFI_FONT_INFO_SYS_FORE_COLOR) == EFI_FONT_INFO_SYS_FORE_COLOR) {
+ InfoOut.ForegroundColor = SystemDefault->ForegroundColor;
+ } else if ((StringInfoIn->FontInfoMask & EFI_FONT_INFO_SYS_BACK_COLOR) == EFI_FONT_INFO_SYS_BACK_COLOR) {
+ InfoOut.BackgroundColor = SystemDefault->BackgroundColor;
+ }
+
+ FontInfo->FontSize = InfoOut.FontInfo.FontSize;
+ FontInfo->FontStyle = InfoOut.FontInfo.FontStyle;
+
+ if (IsFontInfoExisted (Private, FontInfo, &InfoOut.FontInfoMask, LocalFontHandle, &GlobalFont)) {
+ if (String != NULL) {
+ //
+ // Test to guarantee all characters are available in the found font.
+ //
+ StringIn = String;
+ while (*StringIn != 0) {
+ Status = FindGlyphBlock (GlobalFont->FontPackage, *StringIn, NULL, NULL, NULL);
+ if (EFI_ERROR (Status)) {
+ LocalFontHandle = NULL;
+ goto Exit;
+ }
+ StringIn++;
+ }
+
+ //
+ // Write to output parameter
+ //
+ if (StringInfoOut != NULL) {
+ StringInfoOutLen = sizeof (EFI_FONT_DISPLAY_INFO) - sizeof (EFI_FONT_INFO) + GlobalFont->FontInfoSize;
+ *StringInfoOut = (EFI_FONT_DISPLAY_INFO *) AllocateZeroPool (StringInfoOutLen);
+ if (*StringInfoOut == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ LocalFontHandle = NULL;
+ goto Exit;
+ }
+ CopyMem (*StringInfoOut, &InfoOut, sizeof (EFI_FONT_DISPLAY_INFO));
+ CopyMem (&(*StringInfoOut)->FontInfo, GlobalFont->FontInfo, GlobalFont->FontInfoSize);
+ }
+ LocalFontHandle = GlobalFont->Entry.ForwardLink;
+
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+ } else {
+ LocalFontHandle = NULL;
+ }
+
+ Status = EFI_NOT_FOUND;
+
+Exit:
+
+ if (FontHandle != NULL) {
+ *FontHandle = LocalFontHandle;
+ }
+
+ SafeFreePool (SystemDefault);
+ SafeFreePool (FontInfo);
+ return Status;
+}
+
diff --git a/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabase.h b/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabase.h new file mode 100644 index 0000000000..cf3519b853 --- /dev/null +++ b/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabase.h @@ -0,0 +1,1694 @@ +/** @file + +Copyright (c) 2007, Intel Corporation +All rights reserved. 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. + +Module Name: + + HiiDatabase.h + +Abstract: + + Private structures definitions in HiiDatabase. + +Revision History + + +**/ + +#ifndef __HII_DATABASE_PRIVATE_H__ +#define __HII_DATABASE_PRIVATE_H__ + +#include <PiDxe.h> + +#include <Protocol/ConsoleControl.h> +#include <Protocol/DevicePath.h> +#include <Protocol/HiiFont.h> +#include <Protocol/HiiImage.h> +#include <Protocol/HiiString.h> +#include <Protocol/HiiDatabase.h> +#include <Protocol/HiiConfigRouting.h> +#include <Protocol/HiiConfigAccess.h> +#include <Protocol/SimpleTextOut.h> + +#include <Guid/HiiKeyBoardLayout.h> + + +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/UefiDriverEntryPoint.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/BaseLib.h> +#include <Library/DevicePathLib.h> +#include <Library/MemoryAllocationLib.h> + +#define HII_DATABASE_NOTIFY_GUID \ + { \ + 0xc1c76, 0xd79e, 0x42fe, 0x86, 0xb, 0x8b, 0xe8, 0x7b, 0x3e, 0x7a, 0x78 \ + } + +#define MAX_STRING_LENGTH 1024 +#define MAX_FONT_NAME_LEN 256 +#define NARROW_BASELINE 15 +#define WIDE_BASELINE 14 +#define SYS_FONT_INFO_MASK 0x37 +#define REPLACE_UNKNOWN_GLYPH 0xFFFD +#define PROPORTIONAL_GLYPH 0x80 +#define NARROW_GLYPH 0x40 + +#define BITMAP_LEN_1_BIT(Width, Height) (((Width) + 7) / 8 * (Height)) +#define BITMAP_LEN_4_BIT(Width, Height) (((Width) + 1) / 2 * (Height)) +#define BITMAP_LEN_8_BIT(Width, Height) ((Width) * (Height)) +#define BITMAP_LEN_24_BIT(Width, Height) ((Width) * (Height) * 3) + +// +// Storage types +// +#define EFI_HII_VARSTORE_BUFFER 0 +#define EFI_HII_VARSTORE_NAME_VALUE 1 +#define EFI_HII_VARSTORE_EFI_VARIABLE 2 + +#define HII_FORMSET_STORAGE_SIGNATURE EFI_SIGNATURE_32 ('H', 'S', 'T', 'G') +typedef struct { + UINTN Signature; + LIST_ENTRY Entry; + + EFI_HII_HANDLE HiiHandle; + EFI_HANDLE DriverHandle; + + UINT8 Type; // EFI_HII_VARSTORE_BUFFER, EFI_HII_VARSTORE_NAME_VALUE, EFI_HII_VARSTORE_EFI_VARIABLE + EFI_GUID Guid; + CHAR16 *Name; + UINT16 Size; +} HII_FORMSET_STORAGE; + +#define HII_FORMSET_STORAGE_FROM_LINK(a) CR (a, HII_FORMSET_STORAGE, Link, HII_FORMSET_STORAGE_SIGNATURE) + + +// +// String Package definitions +// +#define HII_STRING_PACKAGE_SIGNATURE EFI_SIGNATURE_32 ('h','i','s','p') +typedef struct _HII_STRING_PACKAGE_INSTANCE { + UINTN Signature; + EFI_HII_STRING_PACKAGE_HDR *StringPkgHdr; + UINT8 *StringBlock; + LIST_ENTRY StringEntry; + LIST_ENTRY FontInfoList; // local font info list + UINT8 FontId; +} HII_STRING_PACKAGE_INSTANCE; + +// +// Form Package definitions +// +#define HII_IFR_PACKAGE_SIGNATURE EFI_SIGNATURE_32 ('h','f','r','p') +typedef struct _HII_IFR_PACKAGE_INSTANCE { + UINTN Signature; + EFI_HII_PACKAGE_HEADER FormPkgHdr; + UINT8 *IfrData; + LIST_ENTRY IfrEntry; +} HII_IFR_PACKAGE_INSTANCE; + +// +// Simple Font Package definitions +// +#define HII_S_FONT_PACKAGE_SIGNATURE EFI_SIGNATURE_32 ('h','s','f','p') +typedef struct _HII_SIMPLE_FONT_PACKAGE_INSTANCE { + UINTN Signature; + EFI_HII_SIMPLE_FONT_PACKAGE_HDR *SimpleFontPkgHdr; + LIST_ENTRY SimpleFontEntry; +} HII_SIMPLE_FONT_PACKAGE_INSTANCE; + +// +// Font Package definitions +// +#define HII_FONT_PACKAGE_SIGNATURE EFI_SIGNATURE_32 ('h','i','f','p') +typedef struct _HII_FONT_PACKAGE_INSTANCE { + UINTN Signature; + EFI_HII_FONT_PACKAGE_HDR *FontPkgHdr; + UINT8 *GlyphBlock; + LIST_ENTRY FontEntry; + LIST_ENTRY GlyphInfoList; +} HII_FONT_PACKAGE_INSTANCE; + +#define HII_GLYPH_INFO_SIGNATURE EFI_SIGNATURE_32 ('h','g','i','s') +typedef struct _HII_GLYPH_INFO { + UINTN Signature; + LIST_ENTRY Entry; + CHAR16 CharId; + EFI_HII_GLYPH_INFO Cell; +} HII_GLYPH_INFO; + +#define HII_FONT_INFO_SIGNATURE EFI_SIGNATURE_32 ('h','l','f','i') +typedef struct _HII_FONT_INFO { + UINTN Signature; + LIST_ENTRY Entry; + LIST_ENTRY *GlobalEntry; + UINT8 FontId; +} HII_FONT_INFO; + +#define HII_GLOBAL_FONT_INFO_SIGNATURE EFI_SIGNATURE_32 ('h','g','f','i') +typedef struct _HII_GLOBAL_FONT_INFO { + UINTN Signature; + LIST_ENTRY Entry; + HII_FONT_PACKAGE_INSTANCE *FontPackage; + UINTN FontInfoSize; + EFI_FONT_INFO *FontInfo; +} HII_GLOBAL_FONT_INFO; + +// +// Image Package definitions +// + +#define HII_PIXEL_MASK 0x80 + +typedef struct _HII_IMAGE_PACKAGE_INSTANCE { + EFI_HII_IMAGE_PACKAGE_HDR ImagePkgHdr; + UINT32 ImageBlockSize; + UINT32 PaletteInfoSize; + UINT8 *ImageBlock; + UINT8 *PaletteBlock; +} HII_IMAGE_PACKAGE_INSTANCE; + +// +// Keyboard Layout Pacakge definitions +// +#define HII_KB_LAYOUT_PACKAGE_SIGNATURE EFI_SIGNATURE_32 ('h','k','l','p') +typedef struct _HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE { + UINTN Signature; + UINT8 *KeyboardPkg; + LIST_ENTRY KeyboardEntry; +} HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE; + +// +// Guid Package definitions +// +#define HII_GUID_PACKAGE_SIGNATURE EFI_SIGNATURE_32 ('h','i','g','p') +typedef struct _HII_GUID_PACKAGE_INSTANCE { + UINTN Signature; + UINT8 *GuidPkg; + LIST_ENTRY GuidEntry; +} HII_GUID_PACKAGE_INSTANCE; + +// +// A package list can contain only one or less than one device path package. +// This rule also applies to image package since ImageId can not be duplicate. +// +typedef struct _HII_DATABASE_PACKAGE_LIST_INSTANCE { + EFI_HII_PACKAGE_LIST_HEADER PackageListHdr; + LIST_ENTRY GuidPkgHdr; + LIST_ENTRY FormPkgHdr; + LIST_ENTRY KeyboardLayoutHdr; + LIST_ENTRY StringPkgHdr; + LIST_ENTRY FontPkgHdr; + HII_IMAGE_PACKAGE_INSTANCE *ImagePkg; + LIST_ENTRY SimpleFontPkgHdr; + UINT8 *DevicePathPkg; +} HII_DATABASE_PACKAGE_LIST_INSTANCE; + +#define HII_HANDLE_SIGNATURE EFI_SIGNATURE_32 ('h','i','h','l') + +typedef struct { + UINTN Signature; + LIST_ENTRY Handle; + UINTN Key; +} HII_HANDLE; + +#define HII_DATABASE_RECORD_SIGNATURE EFI_SIGNATURE_32 ('h','i','d','r') + +typedef struct _HII_DATABASE_RECORD { + UINTN Signature; + HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList; + EFI_HANDLE DriverHandle; + EFI_HII_HANDLE Handle; + LIST_ENTRY DatabaseEntry; +} HII_DATABASE_RECORD; + +#define HII_DATABASE_NOTIFY_SIGNATURE EFI_SIGNATURE_32 ('h','i','d','n') + +typedef struct _HII_DATABASE_NOTIFY { + UINTN Signature; + EFI_HANDLE NotifyHandle; + UINT8 PackageType; + EFI_GUID *PackageGuid; + EFI_HII_DATABASE_NOTIFY PackageNotifyFn; + EFI_HII_DATABASE_NOTIFY_TYPE NotifyType; + LIST_ENTRY DatabaseNotifyEntry; +} HII_DATABASE_NOTIFY; + +#define HII_DATABASE_PRIVATE_DATA_SIGNATURE EFI_SIGNATURE_32 ('H', 'i', 'D', 'p') + +typedef struct _HII_DATABASE_PRIVATE_DATA { + UINTN Signature; + LIST_ENTRY DatabaseList; + LIST_ENTRY DatabaseNotifyList; + EFI_HII_FONT_PROTOCOL HiiFont; +#ifndef DISABLE_UNUSED_HII_PROTOCOLS + EFI_HII_IMAGE_PROTOCOL HiiImage; +#endif + EFI_HII_STRING_PROTOCOL HiiString; + EFI_HII_DATABASE_PROTOCOL HiiDatabase; + EFI_HII_CONFIG_ROUTING_PROTOCOL ConfigRouting; + LIST_ENTRY HiiHandleList; + INTN HiiHandleCount; + LIST_ENTRY FontInfoList; // global font info list + UINTN Attribute; // default system color + EFI_GUID CurrentLayoutGuid; + EFI_HII_KEYBOARD_LAYOUT *CurrentLayout; +} HII_DATABASE_PRIVATE_DATA; + +#define HII_FONT_DATABASE_PRIVATE_DATA_FROM_THIS(a) \ + CR (a, \ + HII_DATABASE_PRIVATE_DATA, \ + HiiFont, \ + HII_DATABASE_PRIVATE_DATA_SIGNATURE \ + ) + +#define HII_IMAGE_DATABASE_PRIVATE_DATA_FROM_THIS(a) \ + CR (a, \ + HII_DATABASE_PRIVATE_DATA, \ + HiiImage, \ + HII_DATABASE_PRIVATE_DATA_SIGNATURE \ + ) + +#define HII_STRING_DATABASE_PRIVATE_DATA_FROM_THIS(a) \ + CR (a, \ + HII_DATABASE_PRIVATE_DATA, \ + HiiString, \ + HII_DATABASE_PRIVATE_DATA_SIGNATURE \ + ) + +#define HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS(a) \ + CR (a, \ + HII_DATABASE_PRIVATE_DATA, \ + HiiDatabase, \ + HII_DATABASE_PRIVATE_DATA_SIGNATURE \ + ) + +#define CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS(a) \ + CR (a, \ + HII_DATABASE_PRIVATE_DATA, \ + ConfigRouting, \ + HII_DATABASE_PRIVATE_DATA_SIGNATURE \ + ) + +// +// Internal function prototypes. +// + +/** + This function checks whether a handle is a valid EFI_HII_HANDLE + + @param Handle Pointer to a EFI_HII_HANDLE + + @retval TRUE Valid + @retval FALSE Invalid + +**/ +BOOLEAN +IsHiiHandleValid ( + EFI_HII_HANDLE Handle + ) +; + + +/** + This function checks whether EFI_FONT_INFO exists in current database. If + FontInfoMask is specified, check what options can be used to make a match. + Note that the masks relate to where the system default should be supplied + are ignored by this function. + + @param Private Hii database private structure. + @param FontInfo Points to EFI_FONT_INFO structure. + @param FontInfoMask If not NULL, describes what options can be used + to make a match between the font requested and + the font available. The caller must guarantee + this mask is valid. + @param FontHandle On entry, Points to the font handle returned by a + previous call to GetFontInfo() or NULL to start + with the first font. + @param GlobalFontInfo If not NULL, output the corresponding globa font + info. + + @retval TRUE Existed + @retval FALSE Not existed + +**/ +BOOLEAN +IsFontInfoExisted ( + IN HII_DATABASE_PRIVATE_DATA *Private, + IN EFI_FONT_INFO *FontInfo, + IN EFI_FONT_INFO_MASK *FontInfoMask, OPTIONAL + IN EFI_FONT_HANDLE FontHandle, OPTIONAL + OUT HII_GLOBAL_FONT_INFO **GlobalFontInfo OPTIONAL + ) +; + + +/** + Retrieve system default font and color. + + @param Private HII database driver private data. + @param FontInfo Points to system default font output-related + information. It's caller's responsibility to free + this buffer. + @param FontInfoSize If not NULL, output the size of buffer FontInfo. + + @retval EFI_SUCCESS Cell information is added to the GlyphInfoList. + @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the + task. + @retval EFI_INVALID_PARAMETER Any input parameter is invalid. + +**/ +EFI_STATUS +GetSystemFont ( + IN HII_DATABASE_PRIVATE_DATA *Private, + OUT EFI_FONT_DISPLAY_INFO **FontInfo, + OUT UINTN *FontInfoSize OPTIONAL + ) +; + + +/** + Parse all string blocks to find a String block specified by StringId. + If StringId = (EFI_STRING_ID) (-1), find out all EFI_HII_SIBT_FONT blocks + within this string package and backup its information. + If StringId = 0, output the string id of last string block (EFI_HII_SIBT_END). + + @param Private Hii database private structure. + @param StringPackage Hii string package instance. + @param StringId The string¡¯s id, which is unique within + PackageList. + @param BlockType Output the block type of found string block. + @param StringBlockAddr Output the block address of found string block. + @param StringTextOffset Offset, relative to the found block address, of + the string text information. + @param LastStringId Output the last string id when StringId = 0. + + @retval EFI_SUCCESS The string text and font is retrieved + successfully. + @retval EFI_NOT_FOUND The specified text or font info can not be found + out. + @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the + task. + +**/ +EFI_STATUS +FindStringBlock ( + IN HII_DATABASE_PRIVATE_DATA *Private, + IN HII_STRING_PACKAGE_INSTANCE *StringPackage, + IN EFI_STRING_ID StringId, + OUT UINT8 *BlockType, OPTIONAL + OUT UINT8 **StringBlockAddr, OPTIONAL + OUT UINTN *StringTextOffset, OPTIONAL + OUT EFI_STRING_ID *LastStringId OPTIONAL + ) +; + + +/** + Parse all glyph blocks to find a glyph block specified by CharValue. + If CharValue = (CHAR16) (-1), collect all default character cell information + within this font package and backup its information. + + @param FontPackage Hii string package instance. + @param CharValue Unicode character value, which identifies a glyph + block. + @param GlyphBuffer Output the corresponding bitmap data of the found + block. It is the caller's responsiblity to free + this buffer. + @param Cell Output cell information of the encoded bitmap. + @param GlyphBufferLen If not NULL, output the length of GlyphBuffer. + + @retval EFI_SUCCESS The bitmap data is retrieved successfully. + @retval EFI_NOT_FOUND The specified CharValue does not exist in current + database. + @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the + task. + +**/ +EFI_STATUS +FindGlyphBlock ( + IN HII_FONT_PACKAGE_INSTANCE *FontPackage, + IN CHAR16 CharValue, + OUT UINT8 **GlyphBuffer, OPTIONAL + OUT EFI_HII_GLYPH_INFO *Cell, OPTIONAL + OUT UINTN *GlyphBufferLen OPTIONAL + ) +; + +// +// EFI_HII_FONT_PROTOCOL protocol interfaces +// + + +/** + Renders a string to a bitmap or to the display. + + @param This A pointer to the EFI_HII_FONT_PROTOCOL instance. + @param Flags Describes how the string is to be drawn. + @param String Points to the null-terminated string to be + displayed. + @param StringInfo Points to the string output information, + including the color and font. If NULL, then the + string will be output in the default system font + and color. + @param Blt If this points to a non-NULL on entry, this + points to the image, which is Width pixels wide + and Height pixels high. The string will be drawn + onto this image and + EFI_HII_OUT_FLAG_CLIP is implied. If this points + to a NULL on entry, then a buffer + will be allocated to hold the generated image and + the pointer updated on exit. It is the caller¡¯s + responsibility to free this buffer. + @param BltX,BLTY Specifies the offset from the left and top edge + of the image of the first character cell in the + image. + @param RowInfoArray If this is non-NULL on entry, then on exit, this + will point to an allocated buffer containing + row information and RowInfoArraySize will be + updated to contain the number of elements. + This array describes the characters which were at + least partially drawn and the heights of the + rows. It is the caller¡¯s responsibility to free + this buffer. + @param RowInfoArraySize If this is non-NULL on entry, then on exit it + contains the number of elements in RowInfoArray. + @param ColumnInfoArray If this is non-NULL, then on return it will be + filled with the horizontal offset for each + character in the string on the row where it is + displayed. Non-printing characters will have + the offset ~0. The caller is responsible to + allocate a buffer large enough so that there + is one entry for each character in the string, + not including the null-terminator. It is possible + when character display is normalized that some + character cells overlap. + + @retval EFI_SUCCESS The string was successfully rendered. + @retval EFI_OUT_OF_RESOURCES Unable to allocate an output buffer for + RowInfoArray or Blt. + @retval EFI_INVALID_PARAMETER The String was NULL. + +**/ +EFI_STATUS +EFIAPI +HiiStringToImage ( + IN CONST EFI_HII_FONT_PROTOCOL *This, + IN EFI_HII_OUT_FLAGS Flags, + IN CONST EFI_STRING String, + IN CONST EFI_FONT_DISPLAY_INFO *StringInfo OPTIONAL, + IN OUT EFI_IMAGE_OUTPUT **Blt, + IN UINTN BltX, + IN UINTN BltY, + OUT EFI_HII_ROW_INFO **RowInfoArray OPTIONAL, + OUT UINTN *RowInfoArraySize OPTIONAL, + OUT UINTN *ColumnInfoArray OPTIONAL + ) +; + + +/** + Render a string to a bitmap or the screen containing the contents of the specified string. + + @param This A pointer to the EFI_HII_FONT_PROTOCOL instance. + @param Flags Describes how the string is to be drawn. + @param PackageList The package list in the HII database to search + for the specified string. + @param StringId The string¡¯s id, which is unique within + PackageList. + @param Language Points to the language for the retrieved string. + If NULL, then the current system language is + used. + @param StringInfo Points to the string output information, + including the color and font. If NULL, then the + string will be output in the default system font + and color. + @param Blt If this points to a non-NULL on entry, this + points to the image, which is Width pixels wide + and Height pixels high. The string will be drawn + onto this image and + EFI_HII_OUT_FLAG_CLIP is implied. If this points + to a NULL on entry, then a buffer + will be allocated to hold the generated image and + the pointer updated on exit. It is the caller¡¯s + responsibility to free this buffer. + @param BltX,BLTY Specifies the offset from the left and top edge + of the image of the first character cell in the + image. + @param RowInfoArray If this is non-NULL on entry, then on exit, this + will point to an allocated buffer containing + row information and RowInfoArraySize will be + updated to contain the number of elements. + This array describes the characters which were at + least partially drawn and the heights of the + rows. It is the caller¡¯s responsibility to free + this buffer. + @param RowInfoArraySize If this is non-NULL on entry, then on exit it + contains the number of elements in RowInfoArray. + @param ColumnInfoArray If this is non-NULL, then on return it will be + filled with the horizontal offset for each + character in the string on the row where it is + displayed. Non-printing characters will have + the offset ~0. The caller is responsible to + allocate a buffer large enough so that there + is one entry for each character in the string, + not including the null-terminator. It is possible + when character display is normalized that some + character cells overlap. + + @retval EFI_SUCCESS The string was successfully rendered. + @retval EFI_OUT_OF_RESOURCES Unable to allocate an output buffer for + RowInfoArray or Blt. + @retval EFI_INVALID_PARAMETER The String was NULL. + +**/ +EFI_STATUS +EFIAPI +HiiStringIdToImage ( + IN CONST EFI_HII_FONT_PROTOCOL *This, + IN EFI_HII_OUT_FLAGS Flags, + IN EFI_HII_HANDLE PackageList, + IN EFI_STRING_ID StringId, + IN CONST CHAR8* Language, + IN CONST EFI_FONT_DISPLAY_INFO *StringInfo OPTIONAL, + IN OUT EFI_IMAGE_OUTPUT **Blt, + IN UINTN BltX, + IN UINTN BltY, + OUT EFI_HII_ROW_INFO **RowInfoArray OPTIONAL, + OUT UINTN *RowInfoArraySize OPTIONAL, + OUT UINTN *ColumnInfoArray OPTIONAL + ) +; + + +/** + Convert the glyph for a single character into a bitmap. + + @param This A pointer to the EFI_HII_FONT_PROTOCOL instance. + @param Char Character to retrieve. + @param StringInfo Points to the string font and color information + or NULL if the string should use the default + system font and color. + @param Blt Thus must point to a NULL on entry. A buffer will + be allocated to hold the output and the pointer + updated on exit. It is the caller¡¯s + responsibility to free this buffer. + @param Baseline Number of pixels from the bottom of the bitmap to + the baseline. + + @retval EFI_SUCCESS Glyph bitmap created. + @retval EFI_OUT_OF_RESOURCES Unable to allocate the output buffer Blt. + @retval EFI_WARN_UNKNOWN_GLYPH The glyph was unknown and was replaced with the + glyph for Unicode character 0xFFFD. + @retval EFI_INVALID_PARAMETER Blt is NULL or *Blt is not NULL. + +**/ +EFI_STATUS +EFIAPI +HiiGetGlyph ( + IN CONST EFI_HII_FONT_PROTOCOL *This, + IN CHAR16 Char, + IN CONST EFI_FONT_DISPLAY_INFO *StringInfo, + OUT EFI_IMAGE_OUTPUT **Blt, + OUT UINTN *Baseline OPTIONAL + ) +; + + +/** + This function iterates through fonts which match the specified font, using + the specified criteria. If String is non-NULL, then all of the characters in + the string must exist in order for a candidate font to be returned. + + @param This A pointer to the EFI_HII_FONT_PROTOCOL instance. + @param FontHandle On entry, points to the font handle returned by a + previous call to GetFontInfo() or NULL to start + with the first font. On return, points to the + returned font handle or points to NULL if there + are no more matching fonts. + @param StringInfoIn Upon entry, points to the font to return + information about. + @param StringInfoOut Upon return, contains the matching font¡¯s + information. If NULL, then no information is + returned. It's caller's responsibility to free + this buffer. + @param String Points to the string which will be tested to + determine if all characters are available. If + NULL, then any font is acceptable. + + @retval EFI_SUCCESS Matching font returned successfully. + @retval EFI_NOT_FOUND No matching font was found. + @retval EFI_INVALID_PARAMETER StringInfoIn is NULL. + @retval EFI_OUT_OF_RESOURCES There were insufficient resources to complete the + request. + +**/ +EFI_STATUS +EFIAPI +HiiGetFontInfo ( + IN CONST EFI_HII_FONT_PROTOCOL *This, + IN OUT EFI_FONT_HANDLE *FontHandle, + IN CONST EFI_FONT_DISPLAY_INFO *StringInfoIn, + OUT EFI_FONT_DISPLAY_INFO **StringInfoOut, + IN CONST EFI_STRING String OPTIONAL + ) +; + +// +// EFI_HII_IMAGE_PROTOCOL interfaces +// + + +/** + This function adds the image Image to the group of images owned by PackageList, and returns + a new image identifier (ImageId). + + @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance. + @param PackageList Handle of the package list where this image will + be added. + @param ImageId On return, contains the new image id, which is + unique within PackageList. + @param Image Points to the image. + + @retval EFI_SUCCESS The new image was added successfully. + @retval EFI_NOT_FOUND The specified PackageList could not be found in + database. + @retval EFI_OUT_OF_RESOURCES Could not add the image due to lack of resources. + @retval EFI_INVALID_PARAMETER Image is NULL or ImageId is NULL. + +**/ +EFI_STATUS +EFIAPI +HiiNewImage ( + IN CONST EFI_HII_IMAGE_PROTOCOL *This, + IN EFI_HII_HANDLE PackageList, + OUT EFI_IMAGE_ID *ImageId, + IN CONST EFI_IMAGE_INPUT *Image + ) +; + + +/** + This function retrieves the image specified by ImageId which is associated with + the specified PackageList and copies it into the buffer specified by Image. + + @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance. + @param PackageList Handle of the package list where this image will + be searched. + @param ImageId The image¡¯s id,, which is unique within + PackageList. + @param Image Points to the image. + @param ImageSize On entry, points to the size of the buffer + pointed to by Image, in bytes. On return, points + to the length of the image, in bytes. + + @retval EFI_SUCCESS The new image was returned successfully. + @retval EFI_NOT_FOUND The image specified by ImageId is not available. + @retval EFI_BUFFER_TOO_SMALL The buffer specified by ImageSize is too small to + hold the image. + @retval EFI_INVALID_PARAMETER The Image or ImageSize was NULL. + +**/ +EFI_STATUS +EFIAPI +HiiGetImage ( + IN CONST EFI_HII_IMAGE_PROTOCOL *This, + IN EFI_HII_HANDLE PackageList, + IN EFI_IMAGE_ID ImageId, + OUT EFI_IMAGE_INPUT *Image, + OUT UINTN *ImageSize + ) +; + + +/** + This function updates the image specified by ImageId in the specified PackageListHandle to + the image specified by Image. + + @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance. + @param PackageList The package list containing the images. + @param ImageId The image¡¯s id,, which is unique within + PackageList. + @param Image Points to the image. + + @retval EFI_SUCCESS The new image was updated successfully. + @retval EFI_NOT_FOUND The image specified by ImageId is not in the + database. + @retval EFI_INVALID_PARAMETER The Image was NULL. + +**/ +EFI_STATUS +EFIAPI +HiiSetImage ( + IN CONST EFI_HII_IMAGE_PROTOCOL *This, + IN EFI_HII_HANDLE PackageList, + IN EFI_IMAGE_ID ImageId, + IN CONST EFI_IMAGE_INPUT *Image + ) +; + + +/** + This function renders an image to a bitmap or the screen using the specified + color and options. It draws the image on an existing bitmap, allocates a new + bitmap or uses the screen. The images can be clipped. + + @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance. + @param Flags Describes how the image is to be drawn. + @param Image Points to the image to be displayed. + @param Blt If this points to a non-NULL on entry, this + points to the image, which is Width pixels wide + and Height pixels high. The image will be drawn + onto this image and EFI_HII_DRAW_FLAG_CLIP is + implied. If this points to a NULL on entry, then + a buffer will be allocated to hold the generated + image and the pointer updated on exit. It is the + caller¡¯s responsibility to free this buffer. + @param BltY Specifies the offset from the left and top edge + of the output image of the first pixel in the + image. + + @retval EFI_SUCCESS The image was successfully drawn. + @retval EFI_OUT_OF_RESOURCES Unable to allocate an output buffer for Blt. + @retval EFI_INVALID_PARAMETER The Image or Blt was NULL. + @retval EFI_INVALID_PARAMETER Any combination of Flags is invalid. + +**/ +EFI_STATUS +EFIAPI +HiiDrawImage ( + IN CONST EFI_HII_IMAGE_PROTOCOL *This, + IN EFI_HII_DRAW_FLAGS Flags, + IN CONST EFI_IMAGE_INPUT *Image, + IN OUT EFI_IMAGE_OUTPUT **Blt, + IN UINTN BltX, + IN UINTN BltY + ) +; + + +/** + This function renders an image to a bitmap or the screen using the specified + color and options. It draws the image on an existing bitmap, allocates a new + bitmap or uses the screen. The images can be clipped. + + @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance. + @param Flags Describes how the image is to be drawn. + @param PackageList The package list in the HII database to search + for the specified image. + @param ImageId The image's id, which is unique within + PackageList. + @param Blt If this points to a non-NULL on entry, this + points to the image, which is Width pixels wide + and Height pixels high. The image will be drawn + onto this image and + EFI_HII_DRAW_FLAG_CLIP is implied. If this points + to a NULL on entry, then a buffer will be + allocated to hold the generated image and the + pointer updated on exit. It is the caller¡¯s + responsibility to free this buffer. + @param BltY Specifies the offset from the left and top edge + of the output image of the first pixel in the + image. + + @retval EFI_SUCCESS The image was successfully drawn. + @retval EFI_OUT_OF_RESOURCES Unable to allocate an output buffer for Blt. + @retval EFI_INVALID_PARAMETER The Image was NULL. + @retval EFI_NOT_FOUND The specified packagelist could not be found in + current database. + +**/ +EFI_STATUS +EFIAPI +HiiDrawImageId ( + IN CONST EFI_HII_IMAGE_PROTOCOL *This, + IN EFI_HII_DRAW_FLAGS Flags, + IN EFI_HII_HANDLE PackageList, + IN EFI_IMAGE_ID ImageId, + IN OUT EFI_IMAGE_OUTPUT **Blt, + IN UINTN BltX, + IN UINTN BltY + ) + +; + +// +// EFI_HII_STRING_PROTOCOL +// + + +/** + This function adds the string String to the group of strings owned by PackageList, with the + specified font information StringFontInfo and returns a new string id. + + @param This A pointer to the EFI_HII_STRING_PROTOCOL + instance. + @param PackageList Handle of the package list where this string will + be added. + @param StringId On return, contains the new strings id, which is + unique within PackageList. + @param Language Points to the language for the new string. + @param LanguageName Points to the printable language name to + associate with the passed in Language field.If + LanguageName is not NULL and the string package + header's LanguageName associated with a given + Language is not zero, the LanguageName being + passed in will be ignored. + @param String Points to the new null-terminated string. + @param StringFontInfo Points to the new string¡¯s font information or + NULL if the string should have the default system + font, size and style. + + @retval EFI_SUCCESS The new string was added successfully. + @retval EFI_NOT_FOUND The specified PackageList could not be found in + database. + @retval EFI_OUT_OF_RESOURCES Could not add the string due to lack of + resources. + @retval EFI_INVALID_PARAMETER String is NULL or StringId is NULL or Language is + NULL. + +**/ +EFI_STATUS +EFIAPI +HiiNewString ( + IN CONST EFI_HII_STRING_PROTOCOL *This, + IN EFI_HII_HANDLE PackageList, + OUT EFI_STRING_ID *StringId, + IN CONST CHAR8 *Language, + IN CONST CHAR16 *LanguageName, OPTIONAL + IN CONST EFI_STRING String, + IN CONST EFI_FONT_INFO *StringFontInfo OPTIONAL + ) +; + + +/** + This function retrieves the string specified by StringId which is associated + with the specified PackageList in the language Language and copies it into + the buffer specified by String. + + @param This A pointer to the EFI_HII_STRING_PROTOCOL + instance. + @param Language Points to the language for the retrieved string. + @param PackageList The package list in the HII database to search + for the specified string. + @param StringId The string's id, which is unique within + PackageList. + @param String Points to the new null-terminated string. + @param StringSize On entry, points to the size of the buffer + pointed to by String, in bytes. On return, + points to the length of the string, in bytes. + @param StringFontInfo If not NULL, points to the string¡¯s font + information. It's caller's responsibility to + free this buffer. + + @retval EFI_SUCCESS The string was returned successfully. + @retval EFI_NOT_FOUND The string specified by StringId is not + available. + @retval EFI_NOT_FOUND The string specified by StringId is available but + not in the specified language. + @retval EFI_BUFFER_TOO_SMALL The buffer specified by StringSize is too small + to hold the string. + @retval EFI_INVALID_PARAMETER The String or Language or StringSize was NULL. + @retval EFI_OUT_OF_RESOURCES There were insufficient resources to complete the + request. + +**/ +EFI_STATUS +EFIAPI +HiiGetString ( + IN CONST EFI_HII_STRING_PROTOCOL *This, + IN CONST CHAR8 *Language, + IN EFI_HII_HANDLE PackageList, + IN EFI_STRING_ID StringId, + OUT EFI_STRING String, + IN OUT UINTN *StringSize, + OUT EFI_FONT_INFO **StringFontInfo OPTIONAL + ) +; + + +/** + This function updates the string specified by StringId in the specified PackageList to the text + specified by String and, optionally, the font information specified by StringFontInfo. + + @param This A pointer to the EFI_HII_STRING_PROTOCOL + instance. + @param PackageList The package list containing the strings. + @param StringId The string¡¯s id, which is unique within + PackageList. + @param Language Points to the language for the updated string. + @param String Points to the new null-terminated string. + @param StringFontInfo Points to the string¡¯s font information or NULL + if the string font information is not changed. + + @retval EFI_SUCCESS The string was updated successfully. + @retval EFI_NOT_FOUND The string specified by StringId is not in the + database. + @retval EFI_INVALID_PARAMETER The String or Language was NULL. + @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the + task. + +**/ +EFI_STATUS +EFIAPI +HiiSetString ( + IN CONST EFI_HII_STRING_PROTOCOL *This, + IN EFI_HII_HANDLE PackageList, + IN EFI_STRING_ID StringId, + IN CONST CHAR8 *Language, + IN CONST EFI_STRING String, + IN CONST EFI_FONT_INFO *StringFontInfo OPTIONAL + ) +; + + +/** + This function returns the list of supported languages, in the format specified + in Appendix M of UEFI 2.1 spec. + + @param This A pointer to the EFI_HII_STRING_PROTOCOL + instance. + @param PackageList The package list to examine. + @param Languages Points to the buffer to hold the returned string. + @param LanguagesSize On entry, points to the size of the buffer + pointed to by Languages, in bytes. On return, + points to the length of Languages, in bytes. + + @retval EFI_SUCCESS The languages were returned successfully. + @retval EFI_INVALID_PARAMETER The Languages or LanguagesSize was NULL. + @retval EFI_BUFFER_TOO_SMALL The LanguagesSize is too small to hold the list + of supported languages. LanguageSize is updated + to contain the required size. + @retval EFI_NOT_FOUND Could not find string package in specified + packagelist. + +**/ +EFI_STATUS +EFIAPI +HiiGetLanguages ( + IN CONST EFI_HII_STRING_PROTOCOL *This, + IN EFI_HII_HANDLE PackageList, + IN OUT CHAR8 *Languages, + IN OUT UINTN *LanguagesSize + ) +; + + +/** + Each string package has associated with it a single primary language and zero + or more secondary languages. This routine returns the secondary languages + associated with a package list. + + @param This A pointer to the EFI_HII_STRING_PROTOCOL + instance. + @param PackageList The package list to examine. + @param FirstLanguage Points to the primary language. + @param SecondaryLanguages Points to the buffer to hold the returned list of + secondary languages for the specified + FirstLanguage. If there are no secondary + languages, the function returns successfully, + but this is set to NULL. + @param SecondaryLanguageSize On entry, points to the size of the buffer + pointed to by SecondLanguages, in bytes. On + return, points to the length of SecondLanguages + in bytes. + + @retval EFI_SUCCESS Secondary languages were correctly returned. + @retval EFI_INVALID_PARAMETER FirstLanguage or SecondLanguages or + SecondLanguagesSize was NULL. + @retval EFI_BUFFER_TOO_SMALL The buffer specified by SecondLanguagesSize is + too small to hold the returned information. + SecondLanguageSize is updated to hold the size of + the buffer required. + @retval EFI_NOT_FOUND The language specified by FirstLanguage is not + present in the specified package list. + +**/ +EFI_STATUS +EFIAPI +HiiGetSecondaryLanguages ( + IN CONST EFI_HII_STRING_PROTOCOL *This, + IN EFI_HII_HANDLE PackageList, + IN CONST CHAR8 *FirstLanguage, + IN OUT CHAR8 *SecondLanguages, + IN OUT UINTN *SecondLanguagesSize + ) +; + +// +// EFI_HII_DATABASE_PROTOCOL protocol interfaces +// + + +/** + This function adds the packages in the package list to the database and returns a handle. If there is a + EFI_DEVICE_PATH_PROTOCOL associated with the DriverHandle, then this function will + create a package of type EFI_PACKAGE_TYPE_DEVICE_PATH and add it to the package list. + + @param This A pointer to the EFI_HII_DATABASE_PROTOCOL + instance. + @param PackageList A pointer to an EFI_HII_PACKAGE_LIST_HEADER + structure. + @param DriverHandle Associate the package list with this EFI handle. + @param Handle A pointer to the EFI_HII_HANDLE instance. + + @retval EFI_SUCCESS The package list associated with the Handle was + added to the HII database. + @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the + new database contents. + @retval EFI_INVALID_PARAMETER PackageList is NULL or Handle is NULL. + +**/ +EFI_STATUS +EFIAPI +HiiNewPackageList ( + IN CONST EFI_HII_DATABASE_PROTOCOL *This, + IN CONST EFI_HII_PACKAGE_LIST_HEADER *PackageList, + IN CONST EFI_HANDLE DriverHandle, + OUT EFI_HII_HANDLE *Handle + ) +; + + +/** + This function removes the package list that is associated with a handle Handle + from the HII database. Before removing the package, any registered functions + with the notification type REMOVE_PACK and the same package type will be called. + + @param This A pointer to the EFI_HII_DATABASE_PROTOCOL + instance. + @param Handle The handle that was registered to the data that + is requested for removal. + + @retval EFI_SUCCESS The data associated with the Handle was removed + from the HII database. + @retval EFI_NOT_FOUND The specified PackageList could not be found in + database. + @retval EFI_INVALID_PARAMETER The Handle was not valid. + +**/ +EFI_STATUS +EFIAPI +HiiRemovePackageList ( + IN CONST EFI_HII_DATABASE_PROTOCOL *This, + IN EFI_HII_HANDLE Handle + ) +; + + +/** + This function updates the existing package list (which has the specified Handle) + in the HII databases, using the new package list specified by PackageList. + + @param This A pointer to the EFI_HII_DATABASE_PROTOCOL + instance. + @param Handle The handle that was registered to the data that + is requested to be updated. + @param PackageList A pointer to an EFI_HII_PACKAGE_LIST_HEADER + package. + + @retval EFI_SUCCESS The HII database was successfully updated. + @retval EFI_OUT_OF_RESOURCES Unable to allocate enough memory for the updated + database. + @retval EFI_INVALID_PARAMETER Handle or PackageList was NULL. + @retval EFI_NOT_FOUND The Handle was not valid or could not be found in + database. + +**/ +EFI_STATUS +EFIAPI +HiiUpdatePackageList ( + IN CONST EFI_HII_DATABASE_PROTOCOL *This, + IN EFI_HII_HANDLE Handle, + IN CONST EFI_HII_PACKAGE_LIST_HEADER *PackageList + ) +; + + +/** + This function returns a list of the package handles of the specified type + that are currently active in the database. The pseudo-type + EFI_HII_PACKAGE_TYPE_ALL will cause all package handles to be listed. + + @param This A pointer to the EFI_HII_DATABASE_PROTOCOL + instance. + @param PackageType Specifies the package type of the packages to + list or EFI_HII_PACKAGE_TYPE_ALL for all packages + to be listed. + @param PackageGuid If PackageType is EFI_HII_PACKAGE_TYPE_GUID, then + this is the pointer to the GUID which must match + the Guid field of EFI_HII_GUID_PACKAGE_GUID_HDR. + Otherwise, it must be NULL. + @param HandleBufferLength On input, a pointer to the length of the handle + buffer. On output, the length of the handle + buffer that is required for the handles found. + @param Handle An array of EFI_HII_HANDLE instances returned. + + @retval EFI_SUCCESS The matching handles are outputed successfully. + @retval EFI_BUFFER_TO_SMALL The HandleBufferLength parameter indicates that + Handle is too small to support the number of + handles. HandleBufferLength is updated with a + value that will enable the data to fit. + @retval EFI_NOT_FOUND No matching handle could not be found in + database. + @retval EFI_INVALID_PARAMETER Handle or HandleBufferLength was NULL. + +**/ +EFI_STATUS +EFIAPI +HiiListPackageLists ( + IN CONST EFI_HII_DATABASE_PROTOCOL *This, + IN UINT8 PackageType, + IN CONST EFI_GUID *PackageGuid, + IN OUT UINTN *HandleBufferLength, + OUT EFI_HII_HANDLE *Handle + ) +; + + +/** + This function will export one or all package lists in the database to a buffer. + For each package list exported, this function will call functions registered + with EXPORT_PACK and then copy the package list to the buffer. + + @param This A pointer to the EFI_HII_DATABASE_PROTOCOL + instance. + @param Handle An EFI_HII_HANDLE that corresponds to the desired + package list in the HII database to export or + NULL to indicate all package lists should be + exported. + @param BufferSize On input, a pointer to the length of the buffer. + On output, the length of the buffer that is + required for the exported data. + @param Buffer A pointer to a buffer that will contain the + results of the export function. + + @retval EFI_SUCCESS Package exported. + @retval EFI_BUFFER_TO_SMALL The HandleBufferLength parameter indicates that + Handle is too small to support the number of + handles. HandleBufferLength is updated with + a value that will enable the data to fit. + @retval EFI_NOT_FOUND The specifiecd Handle could not be found in the + current database. + @retval EFI_INVALID_PARAMETER Handle or Buffer or BufferSize was NULL. + +**/ +EFI_STATUS +EFIAPI +HiiExportPackageLists ( + IN CONST EFI_HII_DATABASE_PROTOCOL *This, + IN EFI_HII_HANDLE Handle, + IN OUT UINTN *BufferSize, + OUT EFI_HII_PACKAGE_LIST_HEADER *Buffer + ) +; + + +/** + This function registers a function which will be called when specified actions related to packages of + the specified type occur in the HII database. By registering a function, other HII-related drivers are + notified when specific package types are added, removed or updated in the HII database. + Each driver or application which registers a notification should use + EFI_HII_DATABASE_PROTOCOL.UnregisterPackageNotify() before exiting. + + @param This A pointer to the EFI_HII_DATABASE_PROTOCOL + instance. + @param PackageType Specifies the package type of the packages to + list or EFI_HII_PACKAGE_TYPE_ALL for all packages + to be listed. + @param PackageGuid If PackageType is EFI_HII_PACKAGE_TYPE_GUID, then + this is the pointer to the GUID which must match + the Guid field of + EFI_HII_GUID_PACKAGE_GUID_HDR. Otherwise, it must + be NULL. + @param PackageNotifyFn Points to the function to be called when the + event specified by + NotificationType occurs. + @param NotifyType Describes the types of notification which this + function will be receiving. + @param NotifyHandle Points to the unique handle assigned to the + registered notification. Can be used in + EFI_HII_DATABASE_PROTOCOL.UnregisterPackageNotify() + to stop notifications. + + @retval EFI_SUCCESS Notification registered successfully. + @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary data structures + @retval EFI_INVALID_PARAMETER NotifyHandle is NULL. + @retval EFI_INVALID_PARAMETER PackageGuid is not NULL when PackageType is not + EFI_HII_PACKAGE_TYPE_GUID. + @retval EFI_INVALID_PARAMETER PackageGuid is NULL when PackageType is + EFI_HII_PACKAGE_TYPE_GUID. + +**/ +EFI_STATUS +EFIAPI +HiiRegisterPackageNotify ( + IN CONST EFI_HII_DATABASE_PROTOCOL *This, + IN UINT8 PackageType, + IN CONST EFI_GUID *PackageGuid, + IN CONST EFI_HII_DATABASE_NOTIFY PackageNotifyFn, + IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType, + OUT EFI_HANDLE *NotifyHandle + ) +; + + +/** + Removes the specified HII database package-related notification. + + @param This A pointer to the EFI_HII_DATABASE_PROTOCOL + instance. + @param NotifyHandle The handle of the notification function being + unregistered. + + @retval EFI_SUCCESS Notification is unregistered successfully. + @retval EFI_INVALID_PARAMETER The Handle is invalid. + +**/ +EFI_STATUS +EFIAPI +HiiUnregisterPackageNotify ( + IN CONST EFI_HII_DATABASE_PROTOCOL *This, + IN EFI_HANDLE NotificationHandle + ) +; + + +/** + This routine retrieves an array of GUID values for each keyboard layout that + was previously registered in the system. + + @param This A pointer to the EFI_HII_DATABASE_PROTOCOL + instance. + @param KeyGuidBufferLength On input, a pointer to the length of the keyboard + GUID buffer. On output, the length of the handle + buffer that is required for the handles found. + @param KeyGuidBuffer An array of keyboard layout GUID instances + returned. + + @retval EFI_SUCCESS KeyGuidBuffer was updated successfully. + @retval EFI_BUFFER_TOO_SMALL The KeyGuidBufferLength parameter indicates + that KeyGuidBuffer is too small to support the + number of GUIDs. KeyGuidBufferLength is + updated with a value that will enable the data to + fit. + @retval EFI_INVALID_PARAMETER The KeyGuidBuffer or KeyGuidBufferLength was + NULL. + @retval EFI_NOT_FOUND There was no keyboard layout. + +**/ +EFI_STATUS +EFIAPI +HiiFindKeyboardLayouts ( + IN CONST EFI_HII_DATABASE_PROTOCOL *This, + IN OUT UINT16 *KeyGuidBufferLength, + OUT EFI_GUID *KeyGuidBuffer + ) +; + + +/** + This routine retrieves the requested keyboard layout. The layout is a physical description of the keys + on a keyboard and the character(s) that are associated with a particular set of key strokes. + + @param This A pointer to the EFI_HII_DATABASE_PROTOCOL + instance. + @param KeyGuid A pointer to the unique ID associated with a + given keyboard layout. If KeyGuid is NULL then + the current layout will be retrieved. + @param KeyboardLayoutLength On input, a pointer to the length of the + KeyboardLayout buffer. On output, the length of + the data placed into KeyboardLayout. + @param KeyboardLayout A pointer to a buffer containing the retrieved + keyboard layout. + + @retval EFI_SUCCESS The keyboard layout was retrieved successfully. + @retval EFI_NOT_FOUND The requested keyboard layout was not found. + @retval EFI_INVALID_PARAMETER The KeyboardLayout or KeyboardLayoutLength was + NULL. + +**/ +EFI_STATUS +EFIAPI +HiiGetKeyboardLayout ( + IN CONST EFI_HII_DATABASE_PROTOCOL *This, + IN CONST EFI_GUID *KeyGuid, + IN OUT UINT16 *KeyboardLayoutLength, + OUT EFI_HII_KEYBOARD_LAYOUT *KeyboardLayout + ) +; + + +/** + This routine sets the default keyboard layout to the one referenced by KeyGuid. When this routine + is called, an event will be signaled of the EFI_HII_SET_KEYBOARD_LAYOUT_EVENT_GUID + group type. This is so that agents which are sensitive to the current keyboard layout being changed + can be notified of this change. + + @param This A pointer to the EFI_HII_DATABASE_PROTOCOL + instance. + @param KeyGuid A pointer to the unique ID associated with a + given keyboard layout. + + @retval EFI_SUCCESS The current keyboard layout was successfully set. + @retval EFI_NOT_FOUND The referenced keyboard layout was not found, so + action was taken. + @retval EFI_INVALID_PARAMETER The KeyGuid was NULL. + +**/ +EFI_STATUS +EFIAPI +HiiSetKeyboardLayout ( + IN CONST EFI_HII_DATABASE_PROTOCOL *This, + IN CONST EFI_GUID *KeyGuid + ) +; + + +/** + Return the EFI handle associated with a package list. + + @param This A pointer to the EFI_HII_DATABASE_PROTOCOL + instance. + @param PackageListHandle An EFI_HII_HANDLE that corresponds to the desired + package list in the HIIdatabase. + @param DriverHandle On return, contains the EFI_HANDLE which was + registered with the package list in + NewPackageList(). + + @retval EFI_SUCCESS The DriverHandle was returned successfully. + @retval EFI_INVALID_PARAMETER The PackageListHandle was not valid or + DriverHandle was NULL. + +**/ +EFI_STATUS +EFIAPI +HiiGetPackageListHandle ( + IN CONST EFI_HII_DATABASE_PROTOCOL *This, + IN EFI_HII_HANDLE PackageListHandle, + OUT EFI_HANDLE *DriverHandle + ) +; + +// +// EFI_HII_CONFIG_ROUTING_PROTOCOL interfaces +// + + +/** + This function allows a caller to extract the current configuration + for one or more named elements from one or more drivers. + + @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL + instance. + @param Request A null-terminated Unicode string in + <MultiConfigRequest> format. + @param Progress On return, points to a character in the Request + string. Points to the string's null terminator if + request was successful. Points to the most recent + & before the first failing name / value pair (or + the beginning of the string if the failure is in + the first name / value pair) if the request was + not successful. + @param Results Null-terminated Unicode string in + <MultiConfigAltResp> format which has all values + filled in for the names in the Request string. + String to be allocated by the called function. + + @retval EFI_SUCCESS The Results string is filled with the values + corresponding to all requested names. + @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the + results that must be stored awaiting possible + future protocols. + @retval EFI_NOT_FOUND Routing data doesn¡¯t match any known driver. + Progress set to the ¡°G¡± in ¡°GUID¡± of the + routing header that doesn¡¯t match. Note: There + is no requirement that all routing data + be validated before any configuration extraction. + @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Request + parameter would result in this type of error. The + Progress parameter is set to NULL. + @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set to most recent & + before the error or the beginning of the string. + @retval EFI_INVALID_PARAMETER Unknown name. Progress points to the & before the + name in question. + +**/ +EFI_STATUS +EFIAPI +HiiConfigRoutingExtractConfig ( + IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This, + IN CONST EFI_STRING Request, + OUT EFI_STRING *Progress, + OUT EFI_STRING *Results + ) +; + + +/** + This function allows the caller to request the current configuration for the + entirety of the current HII database and returns the data in a null-terminated Unicode string. + + @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL + instance. + @param Results Null-terminated Unicode string in + <MultiConfigAltResp> format which has all values + filled in for the names in the Request string. + String to be allocated by the called function. + De-allocation is up to the caller. + + @retval EFI_SUCCESS The Results string is filled with the values + corresponding to all requested names. + @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the + results that must be stored awaiting possible + future protocols. + @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Results + parameter would result in this type of error. + +**/ +EFI_STATUS +EFIAPI +HiiConfigRoutingExportConfig ( + IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This, + OUT EFI_STRING *Results + ) +; + + +/** + This function processes the results of processing forms and routes it to the + appropriate handlers or storage. + + @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL + instance. + @param Configuration A null-terminated Unicode string in + <MulltiConfigResp> format. + @param Progress A pointer to a string filled in with the offset + of the most recent & before the first failing + name / value pair (or the beginning of the string + if the failure is in the first name / value pair) + or the terminating NULL if all was successful. + + @retval EFI_SUCCESS The results have been distributed or are awaiting + distribution. + @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the + results that must be stored awaiting possible + future protocols. + @retval EFI_INVALID_PARAMETER Passing in a NULL for the Configuration parameter + would result in this type of error. + @retval EFI_NOT_FOUND Target for the specified routing data was not + found. + +**/ +EFI_STATUS +EFIAPI +HiiConfigRoutingRoutConfig ( + IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This, + IN CONST EFI_STRING Configuration, + OUT EFI_STRING *Progress + ) +; + + + +/** + This helper function is to be called by drivers to map configuration data stored + in byte array (¡°block¡±) formats such as UEFI Variables into current configuration strings. + + @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL + instance. + @param ConfigRequest A null-terminated Unicode string in + <ConfigRequest> format. + @param Block Array of bytes defining the block's + configuration. + @param BlockSize Length in bytes of Block. + @param Config Filled-in configuration string. String allocated + by the function. Returned only if call is + successful. + @param Progress A pointer to a string filled in with the offset + of the most recent & before the first failing + name/value pair (or the beginning of the string + if the failure is in the first name / value pair) + or the terminating NULL if all was successful. + + @retval EFI_SUCCESS The request succeeded. Progress points to the + null terminator at the end of the ConfigRequest + string. + @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. + Progress points to the first character of + ConfigRequest. + @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigRequest or + Block parameter would result in this type of + error. Progress points to the first character of + ConfigRequest. + @retval EFI_NOT_FOUND Target for the specified routing data was not + found. Progress points to the ¡°G¡± in ¡°GUID¡± of + the errant routing data. + @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined. + @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted string. + Block is left updated and Progress points at + the ¡®&¡¯ preceding the first non-<BlockName>. + +**/ +EFI_STATUS +EFIAPI +HiiBlockToConfig ( + IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This, + IN CONST EFI_STRING ConfigRequest, + IN CONST UINT8 *Block, + IN CONST UINTN BlockSize, + OUT EFI_STRING *Config, + OUT EFI_STRING *Progress + ) +; + + +/** + This helper function is to be called by drivers to map configuration strings + to configurations stored in byte array (¡°block¡±) formats such as UEFI Variables. + + @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL + instance. + @param ConfigResp A null-terminated Unicode string in <ConfigResp> + format. + @param Block A possibly null array of bytes representing the + current block. Only bytes referenced in the + ConfigResp string in the block are modified. If + this parameter is null or if the *BlockSize + parameter is (on input) shorter than required by + the Configuration string, only the BlockSize + parameter is updated and an appropriate status + (see below) is returned. + @param BlockSize The length of the Block in units of UINT8. On + input, this is the size of the Block. On output, + if successful, contains the index of the last + modified byte in the Block. + @param Progress On return, points to an element of the ConfigResp + string filled in with the offset of the most + recent '&' before the first failing name / value + pair (or the beginning of the string if the + failure is in the first name / value pair) or + the terminating NULL if all was successful. + + @retval EFI_SUCCESS The request succeeded. Progress points to the + null terminator at the end of the ConfigResp + string. + @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. + Progress points to the first character of + ConfigResp. + @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigResp or + Block parameter would result in this type of + error. Progress points to the first character of + ConfigResp. + @retval EFI_NOT_FOUND Target for the specified routing data was not + found. Progress points to the ¡°G¡± in ¡°GUID¡± of + the errant routing data. + @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted name / + value pair. Block is left updated and + Progress points at the ¡®&¡¯ preceding the first + non-<BlockName>. + +**/ +EFI_STATUS +EFIAPI +HiiConfigToBlock ( + IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This, + IN CONST EFI_STRING ConfigResp, + IN OUT UINT8 *Block, + IN OUT UINTN *BlockSize, + OUT EFI_STRING *Progress + ) +; + + +/** + This helper function is to be called by drivers to extract portions of + a larger configuration string. + + @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL + instance. + @param Configuration A null-terminated Unicode string in + <MultiConfigAltResp> format. + @param Guid A pointer to the GUID value to search for in the + routing portion of the ConfigResp string when + retrieving the requested data. If Guid is NULL, + then all GUID values will be searched for. + @param Name A pointer to the NAME value to search for in the + routing portion of the ConfigResp string when + retrieving the requested data. If Name is NULL, + then all Name values will be searched for. + @param DevicePath A pointer to the PATH value to search for in the + routing portion of the ConfigResp string when + retrieving the requested data. If DevicePath is + NULL, then all DevicePath values will be + searched for. + @param AltCfgId A pointer to the ALTCFG value to search for in + the routing portion of the ConfigResp string + when retrieving the requested data. If this + parameter is NULL, then the current setting will + be retrieved. + @param AltCfgResp A pointer to a buffer which will be allocated by + the function which contains the retrieved string + as requested. This buffer is only allocated if + the call was successful. + + @retval EFI_SUCCESS The request succeeded. The requested data was + extracted and placed in the newly allocated + AltCfgResp buffer. + @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate AltCfgResp. + @retval EFI_INVALID_PARAMETER Any parameter is invalid. + @retval EFI_NOT_FOUND Target for the specified routing data was not + found. + +**/ +EFI_STATUS +EFIAPI +HiiGetAltCfg ( + IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This, + IN CONST EFI_STRING Configuration, + IN CONST EFI_GUID *Guid, + IN CONST EFI_STRING Name, + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN CONST UINT16 *AltCfgId, + OUT EFI_STRING *AltCfgResp + ) +; + + +// +// Global variables +// +extern EFI_EVENT gHiiKeyboardLayoutChanged; + +#include "R8Lib.h" + +#endif diff --git a/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabase.msa b/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabase.msa new file mode 100644 index 0000000000..2b3cf9b460 --- /dev/null +++ b/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabase.msa @@ -0,0 +1,79 @@ +<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <MsaHeader>
+ <ModuleName>HiiDatabase</ModuleName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <GuidValue>348C4D62-BFBD-4882-9ECE-C80BB1C4783B</GuidValue>
+ <Version>1.0</Version>
+ <Abstract>Component name for module HiiDatabase</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2007, Intel Corporation. All rights reserved.</Copyright>
+ <License>All rights reserved. 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.</License>
+ <Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
+ </MsaHeader>
+ <ModuleDefinitions>
+ <SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>
+ <BinaryModule>false</BinaryModule>
+ <OutputFileBasename>HiiDatabase</OutputFileBasename>
+ </ModuleDefinitions>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>DebugLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>BaseMemoryLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiDriverEntryPoint</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiBootServicesTableLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>BaseLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>DevicePathLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>MemoryAllocationLib</Keyword>
+ </LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>R8Lib.c</Filename>
+ <Filename>R8Lib.h</Filename>
+ <Filename>Font.c</Filename>
+ <Filename>Database.c</Filename>
+ <Filename>String.c</Filename>
+ <Filename>ConfigRouting.c</Filename>
+ <Filename>HiiDatabase.dxs</Filename>
+ <Filename>HiiDatabase.h</Filename>
+ <Filename>Image.c</Filename>
+ <Filename>HiiDatabaseEntry.c</Filename>
+ <Filename>CVS\TortoiseCVS.Status</Filename>
+ </SourceFiles>
+ <PackageDependencies>
+ <Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>
+ <Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>
+ </PackageDependencies>
+ <Protocols>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiDevicePathProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiConsoleControlProtocolGuid</ProtocolCName>
+ </Protocol>
+ </Protocols>
+ <Externs>
+ <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
+ <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
+ <Extern>
+ <ModuleEntryPoint>InitializeHiiDatabase</ModuleEntryPoint>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
\ No newline at end of file diff --git a/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf b/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf new file mode 100644 index 0000000000..2bafb25b18 --- /dev/null +++ b/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf @@ -0,0 +1,75 @@ +#/** @file
+# Component name for module HiiDatabase
+#
+# FIX ME!
+# Copyright (c) 2007, Intel Corporation. All rights reserved.
+#
+# All rights reserved. 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 = 0x00010005
+ BASE_NAME = HiiDatabase
+ FILE_GUID = 348C4D62-BFBD-4882-9ECE-C80BB1C4783B
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ EDK_RELEASE_VERSION = 0x00020000
+ EFI_SPECIFICATION_VERSION = 0x0002000A
+
+ ENTRY_POINT = InitializeHiiDatabase
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+ HiiDatabaseEntry.c
+ Image.c
+ HiiDatabase.h
+ ConfigRouting.c
+ String.c
+ Database.c
+ Font.c
+ R8Lib.h
+ R8Lib.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ MemoryAllocationLib
+ DevicePathLib
+ BaseLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ DebugLib
+
+
+[Protocols]
+ gEfiConsoleControlProtocolGuid
+ gEfiDevicePathProtocolGuid
+ gEfiHiiStringProtocolGuid
+ gEfiHiiImageProtocolGuid
+ gEfiHiiConfigRoutingProtocolGuid
+ gEfiHiiDatabaseProtocolGuid
+ gEfiHiiFontProtocolGuid
+ gEfiHiiConfigAccessProtocolGuid
+
+
+[Depex]
+ TRUE
+
diff --git a/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseEntry.c b/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseEntry.c new file mode 100644 index 0000000000..99084db068 --- /dev/null +++ b/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseEntry.c @@ -0,0 +1,197 @@ +/** @file
+
+Copyright (c) 2007, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ HiiDatabaseEntry.c
+
+Abstract:
+
+ This file contains the entry code to the HII database, which is defined by
+ UEFI 2.1 specification.
+
+Revision History
+
+
+**/
+
+
+#include "HiiDatabase.h"
+
+//
+// Global variables
+//
+EFI_EVENT gHiiKeyboardLayoutChanged;
+STATIC EFI_GUID gHiiSetKbdLayoutEventGuid = EFI_HII_SET_KEYBOARD_LAYOUT_EVENT_GUID;
+
+STATIC HII_DATABASE_PRIVATE_DATA mPrivate = {
+ HII_DATABASE_PRIVATE_DATA_SIGNATURE,
+ {
+ (LIST_ENTRY *) NULL,
+ (LIST_ENTRY *) NULL
+ },
+ {
+ (LIST_ENTRY *) NULL,
+ (LIST_ENTRY *) NULL
+ },
+ {
+ HiiStringToImage,
+ HiiStringIdToImage,
+ HiiGetGlyph,
+ HiiGetFontInfo
+ },
+#ifndef DISABLE_UNUSED_HII_PROTOCOLS
+ {
+ HiiNewImage,
+ HiiGetImage,
+ HiiSetImage,
+ HiiDrawImage,
+ HiiDrawImageId
+ },
+#endif
+ {
+ HiiNewString,
+ HiiGetString,
+ HiiSetString,
+ HiiGetLanguages,
+ HiiGetSecondaryLanguages
+ },
+ {
+ HiiNewPackageList,
+ HiiRemovePackageList,
+ HiiUpdatePackageList,
+ HiiListPackageLists,
+ HiiExportPackageLists,
+ HiiRegisterPackageNotify,
+ HiiUnregisterPackageNotify,
+ HiiFindKeyboardLayouts,
+ HiiGetKeyboardLayout,
+ HiiSetKeyboardLayout,
+ HiiGetPackageListHandle
+ },
+ {
+ HiiConfigRoutingExtractConfig,
+ HiiConfigRoutingExportConfig,
+ HiiConfigRoutingRoutConfig,
+ HiiBlockToConfig,
+ HiiConfigToBlock,
+ HiiGetAltCfg
+ },
+ {
+ (LIST_ENTRY *) NULL,
+ (LIST_ENTRY *) NULL
+ },
+ 0,
+ {
+ (LIST_ENTRY *) NULL,
+ (LIST_ENTRY *) NULL
+ },
+ EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK),
+ {
+ 0x00000000,
+ 0x0000,
+ 0x0000,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ },
+ NULL
+};
+
+//@MT: EFI_DRIVER_ENTRY_POINT (InitializeHiiDatabase)
+
+EFI_STATUS
+EFIAPI
+InitializeHiiDatabase (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+/*++
+
+Routine Description:
+ Initialize HII Database
+
+Arguments:
+ (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT)
+
+Returns:
+ EFI_SUCCESS -
+ other -
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+ EFI_HANDLE *HandleBuffer;
+ UINTN HandleCount;
+
+ //@MT: EfiInitializeDriverLib (ImageHandle, SystemTable);
+
+ //
+ // There will be only one HII Database in the system
+ // If there is another out there, someone is trying to install us
+ // again. Fail that scenario.
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiHiiDatabaseProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+
+ //
+ // If there was no error, assume there is an installation and fail to load
+ //
+ if (!EFI_ERROR (Status)) {
+ if (HandleBuffer != NULL) {
+ gBS->FreePool (HandleBuffer);
+ }
+ return EFI_DEVICE_ERROR;
+ }
+
+ InitializeListHead (&mPrivate.DatabaseList);
+ InitializeListHead (&mPrivate.DatabaseNotifyList);
+ InitializeListHead (&mPrivate.HiiHandleList);
+ InitializeListHead (&mPrivate.FontInfoList);
+
+ //
+ // Create a event with EFI_HII_SET_KEYBOARD_LAYOUT_EVENT_GUID group type.
+ //
+ Status = gBS->CreateEventEx (
+ 0,
+ 0,
+ NULL,
+ NULL,
+ &gHiiSetKbdLayoutEventGuid,
+ &gHiiKeyboardLayoutChanged
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Handle = NULL;
+ return gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEfiHiiFontProtocolGuid,
+ &mPrivate.HiiFont,
+#ifndef DISABLE_UNUSED_HII_PROTOCOLS
+ &gEfiHiiImageProtocolGuid,
+ &mPrivate.HiiImage,
+#endif
+ &gEfiHiiStringProtocolGuid,
+ &mPrivate.HiiString,
+ &gEfiHiiDatabaseProtocolGuid,
+ &mPrivate.HiiDatabase,
+ &gEfiHiiConfigRoutingProtocolGuid,
+ &mPrivate.ConfigRouting,
+ NULL
+ );
+}
+
diff --git a/MdeModulePkg/Universal/HiiDatabaseDxe/Image.c b/MdeModulePkg/Universal/HiiDatabaseDxe/Image.c new file mode 100644 index 0000000000..06d783a880 --- /dev/null +++ b/MdeModulePkg/Universal/HiiDatabaseDxe/Image.c @@ -0,0 +1,1509 @@ +/** @file
+
+Copyright (c) 2007, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ Image.c
+
+Abstract:
+
+ Implementation for EFI_HII_IMAGE_PROTOCOL.
+
+Revision History
+
+
+**/
+
+
+#include "HiiDatabase.h"
+
+#ifndef DISABLE_UNUSED_HII_PROTOCOLS
+
+STATIC
+UINT8*
+GetImageIdOrAddress (
+ IN UINT8 *ImageBlock,
+ IN OUT EFI_IMAGE_ID *ImageId
+ )
+/*++
+
+ Routine Description:
+ Get the imageid of last image block: EFI_HII_IIBT_END_BLOCK when input
+ ImageId is zero, otherwise return the address of the
+ corresponding image block with identifier specified by ImageId.
+
+ Arguments:
+ ImageBlock - Points to the beginning of a series of image blocks stored in order.
+ ImageId - If input ImageId is 0, output the image id of the EFI_HII_IIBT_END_BLOCK;
+ else use this id to find its corresponding image block address.
+
+ Returns:
+ The image block address when input ImageId is not zero; otherwise return NULL.
+
+--*/
+{
+ EFI_IMAGE_ID ImageIdCurrent;
+ UINT8 *ImageBlockHdr;
+ UINT8 Length8;
+ UINT16 Length16;
+ UINT32 Length32;
+ EFI_HII_IIBT_IMAGE_1BIT_BLOCK Iibt1bit;
+ EFI_HII_IIBT_IMAGE_4BIT_BLOCK Iibt4bit;
+ EFI_HII_IIBT_IMAGE_8BIT_BLOCK Iibt8bit;
+ UINT16 Width;
+ UINT16 Height;
+
+ ASSERT (ImageBlock != NULL && ImageId != NULL);
+
+ ImageBlockHdr = ImageBlock;
+ ImageIdCurrent = 1;
+
+ while (((EFI_HII_IMAGE_BLOCK *) ImageBlock)->BlockType != EFI_HII_IIBT_END) {
+ if (*ImageId > 0) {
+ if (*ImageId == ImageIdCurrent) {
+ //
+ // If the found image block is a duplicate block, update the ImageId to
+ // find the previous defined image block.
+ //
+ if (((EFI_HII_IMAGE_BLOCK *) ImageBlock)->BlockType == EFI_HII_IIBT_DUPLICATE) {
+ CopyMem (ImageId, ImageBlock + sizeof (EFI_HII_IMAGE_BLOCK), sizeof (EFI_IMAGE_ID));
+ ASSERT (*ImageId != ImageIdCurrent);
+ ImageBlock = ImageBlockHdr;
+ ImageIdCurrent = 1;
+ continue;
+ }
+
+ return ImageBlock;
+ }
+ if (*ImageId < ImageIdCurrent) {
+ //
+ // Can not find the specified image block in this image.
+ //
+ return NULL;
+ }
+ }
+ switch (((EFI_HII_IMAGE_BLOCK *) ImageBlock)->BlockType) {
+ case EFI_HII_IIBT_EXT1:
+ Length8 = *(ImageBlock + sizeof (EFI_HII_IMAGE_BLOCK) + sizeof (UINT8));
+ ImageBlock += Length8;
+ ImageIdCurrent++;
+ break;
+ case EFI_HII_IIBT_EXT2:
+ CopyMem (
+ &Length16,
+ ImageBlock + sizeof (EFI_HII_IMAGE_BLOCK) + sizeof (UINT8),
+ sizeof (UINT16)
+ );
+ ImageBlock += Length16;
+ ImageIdCurrent++;
+ break;
+ case EFI_HII_IIBT_EXT4:
+ CopyMem (
+ &Length32,
+ ImageBlock + sizeof (EFI_HII_IMAGE_BLOCK) + sizeof (UINT8),
+ sizeof (UINT32)
+ );
+ ImageBlock += Length32;
+ ImageIdCurrent++;
+ break;
+
+ case EFI_HII_IIBT_IMAGE_1BIT:
+ case EFI_HII_IIBT_IMAGE_1BIT_TRANS:
+ CopyMem (&Iibt1bit, ImageBlock, sizeof (EFI_HII_IIBT_IMAGE_1BIT_BLOCK));
+ ImageBlock += sizeof (EFI_HII_IIBT_IMAGE_1BIT_BLOCK) - sizeof (UINT8) +
+ BITMAP_LEN_1_BIT (Iibt1bit.Bitmap.Width, Iibt1bit.Bitmap.Height);
+ ImageIdCurrent++;
+ break;
+
+ case EFI_HII_IIBT_IMAGE_4BIT:
+ case EFI_HII_IIBT_IMAGE_4BIT_TRANS:
+ CopyMem (&Iibt4bit, ImageBlock, sizeof (EFI_HII_IIBT_IMAGE_4BIT_BLOCK));
+ ImageBlock += sizeof (EFI_HII_IIBT_IMAGE_4BIT_BLOCK) - sizeof (UINT8) +
+ BITMAP_LEN_4_BIT (Iibt4bit.Bitmap.Width, Iibt4bit.Bitmap.Height);
+ ImageIdCurrent++;
+ break;
+
+ case EFI_HII_IIBT_IMAGE_8BIT:
+ case EFI_HII_IIBT_IMAGE_8BIT_TRANS:
+ CopyMem (&Iibt8bit, ImageBlock, sizeof (EFI_HII_IIBT_IMAGE_8BIT_BLOCK));
+ ImageBlock += sizeof (EFI_HII_IIBT_IMAGE_8BIT_BLOCK) - sizeof (UINT8) +
+ BITMAP_LEN_8_BIT (Iibt8bit.Bitmap.Width, Iibt8bit.Bitmap.Height);
+ ImageIdCurrent++;
+ break;
+
+ case EFI_HII_IIBT_IMAGE_24BIT:
+ case EFI_HII_IIBT_IMAGE_24BIT_TRANS:
+ CopyMem (&Width, ImageBlock + sizeof (EFI_HII_IMAGE_BLOCK), sizeof (UINT16));
+ CopyMem (
+ &Height,
+ ImageBlock + sizeof (EFI_HII_IMAGE_BLOCK) + sizeof (UINT16),
+ sizeof (UINT16)
+ );
+ ImageBlock += sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL) +
+ BITMAP_LEN_24_BIT (Width, Height);
+ ImageIdCurrent++;
+ break;
+
+ case EFI_HII_IIBT_DUPLICATE:
+ ImageBlock += sizeof (EFI_HII_IIBT_DUPLICATE_BLOCK);
+ ImageIdCurrent++;
+ break;
+
+ case EFI_HII_IIBT_IMAGE_JPEG:
+ CopyMem (&Length32, ImageBlock + sizeof (EFI_HII_IMAGE_BLOCK), sizeof (UINT32));
+ ImageBlock += Length32;
+ ImageIdCurrent++;
+ break;
+
+ case EFI_HII_IIBT_SKIP1:
+ Length8 = *(ImageBlock + sizeof (EFI_HII_IMAGE_BLOCK));
+ ImageBlock += sizeof (EFI_HII_IIBT_SKIP1_BLOCK);
+ ImageIdCurrent = (UINT16) (ImageIdCurrent + Length8);
+ break;
+
+ case EFI_HII_IIBT_SKIP2:
+ CopyMem (&Length16, ImageBlock + sizeof (EFI_HII_IMAGE_BLOCK), sizeof (UINT16));
+ ImageBlock += sizeof (EFI_HII_IIBT_SKIP2_BLOCK);
+ ImageIdCurrent = (UINT16) (ImageIdCurrent + Length16);
+ break;
+
+ default:
+ //
+ // Unknown image blocks can not be skipped, processing halts.
+ //
+ ASSERT (FALSE);
+ }
+ }
+
+ //
+ // When ImageId is zero, return the imageid of last image block: EFI_HII_IIBT_END_BLOCK.
+ //
+ if (*ImageId == 0) {
+ *ImageId = ImageIdCurrent;
+ return ImageBlock;
+ }
+
+ return NULL;
+}
+
+
+
+/**
+ Convert pixels from EFI_GRAPHICS_OUTPUT_BLT_PIXEL to EFI_HII_RGB_PIXEL style.
+
+ @param BitMapOut Pixels in EFI_HII_RGB_PIXEL format.
+ @param BitMapIn Pixels in EFI_GRAPHICS_OUTPUT_BLT_PIXEL format.
+ @param PixelNum The number of pixels to be converted.
+
+
+**/
+STATIC
+VOID
+CopyGopToRgbPixel (
+ OUT EFI_HII_RGB_PIXEL *BitMapOut,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapIn,
+ IN UINTN PixelNum
+ )
+{
+ UINTN Index;
+
+ ASSERT (BitMapOut != NULL && BitMapIn != NULL);
+
+ for (Index = 0; Index < PixelNum; Index++) {
+ CopyMem (BitMapOut + Index, BitMapIn + Index, sizeof (EFI_HII_RGB_PIXEL));
+ }
+}
+
+
+/**
+ Convert pixels from EFI_HII_RGB_PIXEL to EFI_GRAPHICS_OUTPUT_BLT_PIXEL style.
+
+ @param BitMapOut Pixels in EFI_GRAPHICS_OUTPUT_BLT_PIXEL format.
+ @param BitMapIn Pixels in EFI_HII_RGB_PIXEL format.
+ @param PixelNum The number of pixels to be converted.
+
+
+**/
+STATIC
+VOID
+CopyRgbToGopPixel (
+ OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapOut,
+ IN EFI_HII_RGB_PIXEL *BitMapIn,
+ IN UINTN PixelNum
+ )
+{
+ UINTN Index;
+
+ ASSERT (BitMapOut != NULL && BitMapIn != NULL);
+
+ for (Index = 0; Index < PixelNum; Index++) {
+ CopyMem (BitMapOut + Index, BitMapIn + Index, sizeof (EFI_HII_RGB_PIXEL));
+ }
+}
+
+
+/**
+ Output pixels in "1 bit per pixel" format to an image.
+
+ @param Image Points to the image which will store the pixels.
+ @param Data Stores the value of output pixels, 0 or 1.
+ @param PaletteInfo PaletteInfo which stores the color of the output
+ pixels. First entry corresponds to color 0 and
+ second one to color 1.
+
+
+**/
+STATIC
+VOID
+Output1bitPixel (
+ IN OUT EFI_IMAGE_INPUT *Image,
+ IN UINT8 *Data,
+ IN EFI_HII_IMAGE_PALETTE_INFO *PaletteInfo
+ )
+{
+ UINT16 X;
+ UINT16 Y;
+ UINTN OffsetY;
+ UINT8 Index;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapPtr;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL PaletteValue[2];
+ EFI_HII_IMAGE_PALETTE_INFO *Palette;
+ UINT16 PaletteSize;
+ UINT8 Byte;
+
+ ASSERT (Image != NULL && Data != NULL && PaletteInfo != NULL);
+
+ BitMapPtr = Image->Bitmap;
+
+ //
+ // First entry corresponds to color 0 and second entry corresponds to color 1.
+ //
+ CopyMem (&PaletteSize, PaletteInfo, sizeof (UINT16));
+ PaletteSize += sizeof (UINT16);
+ Palette = AllocateZeroPool (PaletteSize);
+ ASSERT (Palette != NULL);
+ CopyMem (Palette, PaletteInfo, PaletteSize);
+
+ ZeroMem (PaletteValue, sizeof (PaletteValue));
+ CopyRgbToGopPixel (&PaletteValue[0], &Palette->PaletteValue[0], 1);
+ CopyRgbToGopPixel (&PaletteValue[1], &Palette->PaletteValue[1], 1);
+ SafeFreePool (Palette);
+
+ //
+ // Convert the pixel from one bit to corresponding color.
+ //
+ for (Y = 0; Y < Image->Height; Y++) {
+ OffsetY = BITMAP_LEN_1_BIT (Image->Width, Y);
+ //
+ // All bits in these bytes are meaningful
+ //
+ for (X = 0; X < Image->Width / 8; X++) {
+ Byte = *(Data + OffsetY + X);
+ for (Index = 0; Index < 8; Index++) {
+ if ((Byte & (1 << Index)) != 0) {
+ BitMapPtr[Y * Image->Width + X * 8 + (8 - Index - 1)] = PaletteValue[1];
+ } else {
+ BitMapPtr[Y * Image->Width + X * 8 + (8 - Index - 1)] = PaletteValue[0];
+ }
+ }
+ }
+
+ if (Image->Width % 8 != 0) {
+ //
+ // Padding bits in this byte should be ignored.
+ //
+ Byte = *(Data + OffsetY + X);
+ for (Index = 0; Index < Image->Width % 8; Index++) {
+ if ((Byte & (1 << (8 - Index - 1))) != 0) {
+ BitMapPtr[Y * Image->Width + X * 8 + Index] = PaletteValue[1];
+ } else {
+ BitMapPtr[Y * Image->Width + X * 8 + Index] = PaletteValue[0];
+ }
+ }
+ }
+ }
+}
+
+
+/**
+ Output pixels in "4 bit per pixel" format to an image.
+
+ @param Image Points to the image which will store the pixels.
+ @param Data Stores the value of output pixels, 0 ~ 15.
+ @param PaletteInfo PaletteInfo which stores the color of the output
+ pixels. Each entry corresponds to a color within
+ [0, 15].
+
+
+**/
+STATIC
+VOID
+Output4bitPixel (
+ IN OUT EFI_IMAGE_INPUT *Image,
+ IN UINT8 *Data,
+ IN EFI_HII_IMAGE_PALETTE_INFO *PaletteInfo
+ )
+{
+ UINT16 X;
+ UINT16 Y;
+ UINTN OffsetY;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapPtr;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL PaletteValue[16];
+ EFI_HII_IMAGE_PALETTE_INFO *Palette;
+ UINT16 PaletteSize;
+ UINT16 PaletteNum;
+ UINT8 Byte;
+
+ ASSERT (Image != NULL && Data != NULL && PaletteInfo != NULL);
+
+ BitMapPtr = Image->Bitmap;
+
+ //
+ // The bitmap should allocate each color index starting from 0.
+ //
+ CopyMem (&PaletteSize, PaletteInfo, sizeof (UINT16));
+ PaletteSize += sizeof (UINT16);
+ Palette = AllocateZeroPool (PaletteSize);
+ ASSERT (Palette != NULL);
+ CopyMem (Palette, PaletteInfo, PaletteSize);
+ PaletteNum = (UINT16)(Palette->PaletteSize / sizeof (EFI_HII_RGB_PIXEL));
+
+ ZeroMem (PaletteValue, sizeof (PaletteValue));
+ CopyRgbToGopPixel (PaletteValue, Palette->PaletteValue, PaletteNum);
+ SafeFreePool (Palette);
+
+ //
+ // Convert the pixel from 4 bit to corresponding color.
+ //
+ for (Y = 0; Y < Image->Height; Y++) {
+ OffsetY = BITMAP_LEN_4_BIT (Image->Width, Y);
+ //
+ // All bits in these bytes are meaningful
+ //
+ for (X = 0; X < Image->Width / 2; X++) {
+ Byte = *(Data + OffsetY + X);
+ BitMapPtr[Y * Image->Width + X * 2] = PaletteValue[Byte >> 4];
+ BitMapPtr[Y * Image->Width + X * 2 + 1] = PaletteValue[Byte & 0x0F];
+ }
+
+ if (Image->Width % 2 != 0) {
+ //
+ // Padding bits in this byte should be ignored.
+ //
+ Byte = *(Data + OffsetY + X);
+ BitMapPtr[Y * Image->Width + X * 2] = PaletteValue[Byte >> 4];
+ }
+ }
+}
+
+
+/**
+ Output pixels in "8 bit per pixel" format to an image.
+
+ @param Image Points to the image which will store the pixels.
+ @param Data Stores the value of output pixels, 0 ~ 255.
+ @param PaletteInfo PaletteInfo which stores the color of the output
+ pixels. Each entry corresponds to a color within
+ [0, 255].
+
+
+**/
+STATIC
+VOID
+Output8bitPixel (
+ IN OUT EFI_IMAGE_INPUT *Image,
+ IN UINT8 *Data,
+ IN EFI_HII_IMAGE_PALETTE_INFO *PaletteInfo
+ )
+{
+ UINT16 X;
+ UINT16 Y;
+ UINTN OffsetY;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapPtr;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL PaletteValue[256];
+ EFI_HII_IMAGE_PALETTE_INFO *Palette;
+ UINT16 PaletteSize;
+ UINT16 PaletteNum;
+ UINT8 Byte;
+
+ ASSERT (Image != NULL && Data != NULL && PaletteInfo != NULL);
+
+ BitMapPtr = Image->Bitmap;
+
+ //
+ // The bitmap should allocate each color index starting from 0.
+ //
+ CopyMem (&PaletteSize, PaletteInfo, sizeof (UINT16));
+ PaletteSize += sizeof (UINT16);
+ Palette = AllocateZeroPool (PaletteSize);
+ ASSERT (Palette != NULL);
+ CopyMem (Palette, PaletteInfo, PaletteSize);
+ PaletteNum = (UINT16)(Palette->PaletteSize / sizeof (EFI_HII_RGB_PIXEL));
+ ZeroMem (PaletteValue, sizeof (PaletteValue));
+ CopyRgbToGopPixel (PaletteValue, Palette->PaletteValue, PaletteNum);
+ SafeFreePool (Palette);
+
+ //
+ // Convert the pixel from 8 bits to corresponding color.
+ //
+ for (Y = 0; Y < Image->Height; Y++) {
+ OffsetY = BITMAP_LEN_8_BIT (Image->Width, Y);
+ //
+ // All bits are meaningful since the bitmap is 8 bits per pixel.
+ //
+ for (X = 0; X < Image->Width; X++) {
+ Byte = *(Data + OffsetY + X);
+ BitMapPtr[OffsetY + X] = PaletteValue[Byte];
+ }
+ }
+
+}
+
+
+/**
+ Output pixels in "24 bit per pixel" format to an image.
+
+ @param Image Points to the image which will store the pixels.
+ @param Data Stores the color of output pixels, allowing 16.8
+ millions colors.
+
+
+**/
+STATIC
+VOID
+Output24bitPixel (
+ IN OUT EFI_IMAGE_INPUT *Image,
+ IN EFI_HII_RGB_PIXEL *Data
+ )
+{
+ UINT16 Y;
+ UINTN OffsetY;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapPtr;
+
+ ASSERT (Image != NULL && Data != NULL);
+
+ BitMapPtr = Image->Bitmap;
+
+ for (Y = 0; Y < Image->Height; Y++) {
+ OffsetY = BITMAP_LEN_8_BIT (Image->Width, Y);
+ CopyRgbToGopPixel (&BitMapPtr[OffsetY], &Data[OffsetY], Image->Width);
+ }
+
+}
+
+
+/**
+ Convert the image from EFI_IMAGE_INPUT to EFI_IMAGE_OUTPUT format.
+
+ @param BltBuffer Buffer points to bitmap data of incoming image.
+ @param BltY Specifies the offset from the left and top edge of
+ the output image of the first pixel in the image.
+ @param Width Width of the incoming image, in pixels.
+ @param Height Height of the incoming image, in pixels.
+ @param Transparent If TRUE, all "off" pixels in the image will be
+ drawn using the pixel value from blt and all other
+ pixels will be copied.
+ @param Blt Buffer points to bitmap data of output image.
+
+ @retval EFI_SUCCESS The image was successfully converted.
+ @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
+
+**/
+STATIC
+EFI_STATUS
+ImageToBlt (
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer,
+ IN UINTN BltX,
+ IN UINTN BltY,
+ IN UINTN Width,
+ IN UINTN Height,
+ IN BOOLEAN Transparent,
+ IN OUT EFI_IMAGE_OUTPUT **Blt
+ )
+{
+ EFI_IMAGE_OUTPUT *ImageOut;
+ UINTN X;
+ UINTN Y;
+ UINTN OffsetY1; // src buffer
+ UINTN OffsetY2; // dest buffer
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL SrcPixel;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL ZeroPixel;
+
+ if (BltBuffer == NULL || Blt == NULL || *Blt == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ImageOut = *Blt;
+
+ if (Width + BltX > ImageOut->Width) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Height + BltY > ImageOut->Height) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (&ZeroPixel, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+
+ for (Y = 0; Y < Height; Y++) {
+ OffsetY1 = Width * Y;
+ OffsetY2 = ImageOut->Width * (BltY + Y);
+ for (X = 0; X < Width; X++) {
+ SrcPixel = BltBuffer[OffsetY1 + X];
+ if (Transparent) {
+ if (CompareMem (&SrcPixel, &ZeroPixel, 3) != 0) {
+ ImageOut->Image.Bitmap[OffsetY2 + BltX + X] = SrcPixel;
+ }
+ } else {
+ ImageOut->Image.Bitmap[OffsetY2 + BltX + X] = SrcPixel;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function adds the image Image to the group of images owned by PackageList, and returns
+ a new image identifier (ImageId).
+
+ @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance.
+ @param PackageList Handle of the package list where this image will
+ be added.
+ @param ImageId On return, contains the new image id, which is
+ unique within PackageList.
+ @param Image Points to the image.
+
+ @retval EFI_SUCCESS The new image was added successfully.
+ @retval EFI_NOT_FOUND The specified PackageList could not be found in
+ database.
+ @retval EFI_OUT_OF_RESOURCES Could not add the image due to lack of resources.
+ @retval EFI_INVALID_PARAMETER Image is NULL or ImageId is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiNewImage (
+ IN CONST EFI_HII_IMAGE_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ OUT EFI_IMAGE_ID *ImageId,
+ IN CONST EFI_IMAGE_INPUT *Image
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+ LIST_ENTRY *Link;
+ HII_DATABASE_RECORD *DatabaseRecord;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
+ HII_IMAGE_PACKAGE_INSTANCE *ImagePackage;
+ UINT8 *ImageBlock;
+ UINTN BlockSize;
+ UINT8 *NewBlock;
+ UINT8 *NewBlockPtr;
+ UINTN NewBlockSize;
+ EFI_IMAGE_INPUT *ImageIn;
+
+ if (This == NULL || ImageId == NULL || Image == NULL || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!IsHiiHandleValid (PackageList)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Private = HII_IMAGE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // Get the specified package list
+ //
+
+ PackageListNode = NULL;
+
+ for (Link = Private->DatabaseList.ForwardLink;
+ Link != &Private->DatabaseList;
+ Link = Link->ForwardLink
+ ) {
+ DatabaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ if (DatabaseRecord->Handle == PackageList) {
+ PackageListNode = DatabaseRecord->PackageList;
+ break;
+ }
+ }
+
+ if (PackageListNode == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ ImageIn = (EFI_IMAGE_INPUT *) Image;
+
+ NewBlockSize = sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL) +
+ BITMAP_LEN_24_BIT (ImageIn->Width, ImageIn->Height);
+
+ //
+ // Get the image package in the package list,
+ // or create a new image package if image package does not exist.
+ //
+ if (PackageListNode->ImagePkg != NULL) {
+ ImagePackage = PackageListNode->ImagePkg;
+
+ //
+ // Output the image id of the incoming image being inserted, which is the
+ // image id of the EFI_HII_IIBT_END block of old image package.
+ //
+ *ImageId = 0;
+ GetImageIdOrAddress (ImagePackage->ImageBlock, ImageId);
+
+ //
+ // Update the package's image block by appending the new block to the end.
+ //
+ BlockSize = ImagePackage->ImageBlockSize + NewBlockSize;
+ ImageBlock = (UINT8 *) AllocateZeroPool (BlockSize);
+ if (ImageBlock == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Copy the original content.
+ //
+ CopyMem (
+ ImageBlock,
+ ImagePackage->ImageBlock,
+ ImagePackage->ImageBlockSize - sizeof (EFI_HII_IIBT_END_BLOCK)
+ );
+ SafeFreePool (ImagePackage->ImageBlock);
+ ImagePackage->ImageBlock = ImageBlock;
+ ImageBlock += ImagePackage->ImageBlockSize - sizeof (EFI_HII_IIBT_END_BLOCK);
+ //
+ // Temp memory to store new block.
+ //
+ NewBlock = AllocateZeroPool (NewBlockSize);
+ if (NewBlock == NULL) {
+ SafeFreePool (ImagePackage->ImageBlock);
+ ImagePackage->ImageBlock = NULL;
+ return EFI_OUT_OF_RESOURCES;
+ }
+ NewBlockPtr = NewBlock;
+
+ //
+ // Update the length record.
+ //
+ ImagePackage->ImageBlockSize = (UINT32) BlockSize;
+ ImagePackage->ImagePkgHdr.Header.Length += (UINT32) NewBlockSize;
+ PackageListNode->PackageListHdr.PackageLength += (UINT32) NewBlockSize;
+
+ } else {
+ //
+ // The specified package list does not contain image package.
+ // Create one to add this image block.
+ //
+ ImagePackage = (HII_IMAGE_PACKAGE_INSTANCE *) AllocateZeroPool (sizeof (HII_IMAGE_PACKAGE_INSTANCE));
+ if (ImagePackage == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Output the image id of the incoming image being inserted, which is the
+ // first image block so that id is initially to one.
+ //
+ *ImageId = 1;
+ BlockSize = sizeof (EFI_HII_IIBT_END_BLOCK) + NewBlockSize;
+ //
+ // Fill in image package header.
+ //
+ ImagePackage->ImagePkgHdr.Header.Length = (UINT32) BlockSize + sizeof (EFI_HII_IMAGE_PACKAGE_HDR);
+ ImagePackage->ImagePkgHdr.Header.Type = EFI_HII_PACKAGE_IMAGES;
+ ImagePackage->ImagePkgHdr.ImageInfoOffset = sizeof (EFI_HII_IMAGE_PACKAGE_HDR);
+ ImagePackage->ImagePkgHdr.PaletteInfoOffset = 0;
+
+ //
+ // Fill in palette info.
+ //
+ ImagePackage->PaletteBlock = NULL;
+ ImagePackage->PaletteInfoSize = 0;
+
+ //
+ // Fill in image blocks.
+ //
+ ImagePackage->ImageBlockSize = (UINT32) BlockSize;
+ ImagePackage->ImageBlock = (UINT8 *) AllocateZeroPool (BlockSize);
+ if (ImagePackage->ImageBlock == NULL) {
+ SafeFreePool (ImagePackage);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ImageBlock = ImagePackage->ImageBlock;
+
+ //
+ // Temp memory to store new block.
+ //
+ NewBlock = AllocateZeroPool (NewBlockSize);
+ if (NewBlock == NULL) {
+ SafeFreePool (ImagePackage->ImageBlock);
+ SafeFreePool (ImagePackage);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ NewBlockPtr = NewBlock;
+
+ //
+ // Insert this image package.
+ //
+ PackageListNode->ImagePkg = ImagePackage;
+ PackageListNode->PackageListHdr.PackageLength += ImagePackage->ImagePkgHdr.Header.Length;
+ }
+
+ //
+ // Append the new block here
+ //
+ if (ImageIn->Flags == EFI_IMAGE_TRANSPARENT) {
+ *NewBlock = EFI_HII_IIBT_IMAGE_24BIT_TRANS;
+ } else {
+ *NewBlock = EFI_HII_IIBT_IMAGE_24BIT;
+ }
+ NewBlock++;
+ CopyMem (NewBlock, &ImageIn->Width, sizeof (UINT16));
+ NewBlock += sizeof (UINT16);
+ CopyMem (NewBlock, &ImageIn->Height, sizeof (UINT16));
+ NewBlock += sizeof (UINT16);
+ CopyGopToRgbPixel ((EFI_HII_RGB_PIXEL *) NewBlock, ImageIn->Bitmap, ImageIn->Width * ImageIn->Height);
+
+ CopyMem (ImageBlock, NewBlockPtr, NewBlockSize);
+ SafeFreePool (NewBlockPtr);
+
+ //
+ // Append the block end
+ //
+ ImageBlock += NewBlockSize;
+ ((EFI_HII_IIBT_END_BLOCK *) (ImageBlock))->Header.BlockType = EFI_HII_IIBT_END;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function retrieves the image specified by ImageId which is associated with
+ the specified PackageList and copies it into the buffer specified by Image.
+
+ @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance.
+ @param PackageList Handle of the package list where this image will
+ be searched.
+ @param ImageId The image¡¯s id,, which is unique within
+ PackageList.
+ @param Image Points to the image.
+ @param ImageSize On entry, points to the size of the buffer pointed
+ to by Image, in bytes. On return, points to the
+ length of the image, in bytes.
+
+ @retval EFI_SUCCESS The new image was returned successfully.
+ @retval EFI_NOT_FOUND The image specified by ImageId is not available.
+ @retval EFI_BUFFER_TOO_SMALL The buffer specified by ImageSize is too small to
+ hold the image.
+ @retval EFI_INVALID_PARAMETER The Image or ImageSize was NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetImage (
+ IN CONST EFI_HII_IMAGE_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ IN EFI_IMAGE_ID ImageId,
+ OUT EFI_IMAGE_INPUT *Image,
+ OUT UINTN *ImageSize
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+ LIST_ENTRY *Link;
+ HII_DATABASE_RECORD *DatabaseRecord;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
+ HII_IMAGE_PACKAGE_INSTANCE *ImagePackage;
+ UINT8 *ImageBlock;
+ EFI_IMAGE_ID LocalImageId;
+ UINT8 BlockType;
+ EFI_HII_IIBT_IMAGE_1BIT_BLOCK Iibt1bit;
+ UINT16 Width;
+ UINT16 Height;
+ UINTN ImageLength;
+ BOOLEAN Flag;
+ UINT8 *PaletteInfo;
+ UINT8 PaletteIndex;
+ UINT16 PaletteSize;
+
+ if (This == NULL || ImageSize == NULL || Image == NULL || ImageId < 1 || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!IsHiiHandleValid (PackageList)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Private = HII_IMAGE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // Get the specified package list and image package.
+ //
+ PackageListNode = NULL;
+ for (Link = Private->DatabaseList.ForwardLink;
+ Link != &Private->DatabaseList;
+ Link = Link->ForwardLink
+ ) {
+ DatabaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ if (DatabaseRecord->Handle == PackageList) {
+ PackageListNode = DatabaseRecord->PackageList;
+ break;
+ }
+ }
+ if (PackageListNode == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ ImagePackage = PackageListNode->ImagePkg;
+ if (ImagePackage == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Find the image block specified by ImageId
+ //
+ LocalImageId = ImageId;
+ ImageBlock = GetImageIdOrAddress (ImagePackage->ImageBlock, &LocalImageId);
+ if (ImageBlock == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ Flag = FALSE;
+ BlockType = *ImageBlock;
+
+ switch (BlockType) {
+ case EFI_HII_IIBT_IMAGE_JPEG:
+ //
+ // BUGBUG: need to be supported as soon as image tool is designed.
+ //
+ return EFI_UNSUPPORTED;
+ break;
+
+ case EFI_HII_IIBT_IMAGE_1BIT_TRANS:
+ case EFI_HII_IIBT_IMAGE_4BIT_TRANS:
+ case EFI_HII_IIBT_IMAGE_8BIT_TRANS:
+ Flag = TRUE;
+ //
+ // fall through
+ //
+ case EFI_HII_IIBT_IMAGE_1BIT:
+ case EFI_HII_IIBT_IMAGE_4BIT:
+ case EFI_HII_IIBT_IMAGE_8BIT:
+ //
+ // Use the common block code since the definition of these structures is the same.
+ //
+ CopyMem (&Iibt1bit, ImageBlock, sizeof (EFI_HII_IIBT_IMAGE_1BIT_BLOCK));
+ ImageLength = sizeof (EFI_IMAGE_INPUT) + sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) *
+ (Iibt1bit.Bitmap.Width * Iibt1bit.Bitmap.Height - 1);
+ if (*ImageSize < ImageLength) {
+ *ImageSize = ImageLength;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ ZeroMem (Image, ImageLength);
+
+ if (Flag) {
+ Image->Flags = EFI_IMAGE_TRANSPARENT;
+ }
+ Image->Width = Iibt1bit.Bitmap.Width;
+ Image->Height = Iibt1bit.Bitmap.Height;
+
+ PaletteInfo = ImagePackage->PaletteBlock + sizeof (EFI_HII_IMAGE_PALETTE_INFO_HEADER);
+ for (PaletteIndex = 1; PaletteIndex < Iibt1bit.PaletteIndex; PaletteIndex++) {
+ CopyMem (&PaletteSize, PaletteInfo, sizeof (UINT16));
+ PaletteInfo += PaletteSize + sizeof (UINT16);
+ }
+ ASSERT (PaletteIndex == Iibt1bit.PaletteIndex);
+
+ //
+ // Output bitmap data
+ //
+ if (BlockType == EFI_HII_IIBT_IMAGE_1BIT || BlockType == EFI_HII_IIBT_IMAGE_1BIT_TRANS) {
+ Output1bitPixel (
+ Image,
+ (UINT8 *) (ImageBlock + sizeof (EFI_HII_IIBT_IMAGE_1BIT_BLOCK) - sizeof (UINT8)),
+ (EFI_HII_IMAGE_PALETTE_INFO *) PaletteInfo
+ );
+ } else if (BlockType == EFI_HII_IIBT_IMAGE_4BIT || BlockType == EFI_HII_IIBT_IMAGE_4BIT_TRANS) {
+ Output4bitPixel (
+ Image,
+ (UINT8 *) (ImageBlock + sizeof (EFI_HII_IIBT_IMAGE_4BIT_BLOCK) - sizeof (UINT8)),
+ (EFI_HII_IMAGE_PALETTE_INFO *) PaletteInfo
+ );
+ } else {
+ Output8bitPixel (
+ Image,
+ (UINT8 *) (ImageBlock + sizeof (EFI_HII_IIBT_IMAGE_8BIT_BLOCK) - sizeof (UINT8)),
+ (EFI_HII_IMAGE_PALETTE_INFO *) PaletteInfo
+ );
+ }
+
+ return EFI_SUCCESS;
+ break;
+
+ case EFI_HII_IIBT_IMAGE_24BIT_TRANS:
+ Flag = TRUE;
+ //
+ // fall through
+ //
+ case EFI_HII_IIBT_IMAGE_24BIT:
+ CopyMem (&Width, ImageBlock + sizeof (EFI_HII_IMAGE_BLOCK), sizeof (UINT16));
+ CopyMem (
+ &Height,
+ ImageBlock + sizeof (EFI_HII_IMAGE_BLOCK) + sizeof (UINT16),
+ sizeof (UINT16)
+ );
+ ImageLength = sizeof (EFI_IMAGE_INPUT) +
+ sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * (Width * Height - 1);
+ if (*ImageSize < ImageLength) {
+ *ImageSize = ImageLength;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ ZeroMem (Image, ImageLength);
+
+ if (Flag) {
+ Image->Flags = EFI_IMAGE_TRANSPARENT;
+ }
+ Image->Width = Width;
+ Image->Height = Height;
+
+ //
+ // Output the bimap data directly.
+ //
+ Output24bitPixel (
+ Image,
+ (EFI_HII_RGB_PIXEL *) (ImageBlock + sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL))
+ );
+ return EFI_SUCCESS;
+ break;
+
+ default:
+ return EFI_NOT_FOUND;
+ break;
+ }
+}
+
+
+/**
+ This function updates the image specified by ImageId in the specified PackageListHandle to
+ the image specified by Image.
+
+ @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance.
+ @param PackageList The package list containing the images.
+ @param ImageId The image¡¯s id,, which is unique within
+ PackageList.
+ @param Image Points to the image.
+
+ @retval EFI_SUCCESS The new image was updated successfully.
+ @retval EFI_NOT_FOUND The image specified by ImageId is not in the
+ database.
+ @retval EFI_INVALID_PARAMETER The Image was NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiSetImage (
+ IN CONST EFI_HII_IMAGE_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ IN EFI_IMAGE_ID ImageId,
+ IN CONST EFI_IMAGE_INPUT *Image
+ )
+{
+ HII_DATABASE_PRIVATE_DATA *Private;
+ LIST_ENTRY *Link;
+ HII_DATABASE_RECORD *DatabaseRecord;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
+ HII_IMAGE_PACKAGE_INSTANCE *ImagePackage;
+ UINT8 *ImageBlock;
+ EFI_IMAGE_ID LocalImageId;
+ UINT8 BlockType;
+ EFI_HII_IIBT_IMAGE_1BIT_BLOCK Iibt1bit;
+ EFI_HII_IIBT_IMAGE_4BIT_BLOCK Iibt4bit;
+ EFI_HII_IIBT_IMAGE_8BIT_BLOCK Iibt8bit;
+ UINT16 Width;
+ UINT16 Height;
+ UINT32 BlockSize;
+ UINT32 NewBlockSize;
+ UINT32 OldBlockSize;
+ EFI_IMAGE_INPUT *ImageIn;
+ UINT8 *NewBlock;
+ UINT8 *NewBlockPtr;
+ UINT8 *Block;
+ UINT8 *BlockPtr;
+ UINT32 Part1Size;
+ UINT32 Part2Size;
+
+ if (This == NULL || Image == NULL || ImageId < 1 || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!IsHiiHandleValid (PackageList)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Private = HII_IMAGE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // Get the specified package list and image package.
+ //
+ PackageListNode = NULL;
+ for (Link = Private->DatabaseList.ForwardLink;
+ Link != &Private->DatabaseList;
+ Link = Link->ForwardLink
+ ) {
+ DatabaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ if (DatabaseRecord->Handle == PackageList) {
+ PackageListNode = DatabaseRecord->PackageList;
+ break;
+ }
+ }
+ if (PackageListNode == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ ImagePackage = PackageListNode->ImagePkg;
+ if (ImagePackage == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Find the image block specified by ImageId
+ //
+ LocalImageId = ImageId;
+ ImageBlock = GetImageIdOrAddress (ImagePackage->ImageBlock, &LocalImageId);
+ if (ImageBlock == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ BlockType = *ImageBlock;
+
+ //
+ // Get the size of original image block. Use some common block code here
+ // since the definition of some structures is the same.
+ //
+ switch (BlockType) {
+ case EFI_HII_IIBT_IMAGE_JPEG:
+ //
+ // BUGBUG: need to be supported as soon as image tool is designed.
+ //
+ return EFI_UNSUPPORTED;
+ break;
+
+ case EFI_HII_IIBT_IMAGE_1BIT:
+ case EFI_HII_IIBT_IMAGE_1BIT_TRANS:
+ CopyMem (&Iibt1bit, ImageBlock, sizeof (EFI_HII_IIBT_IMAGE_1BIT_BLOCK));
+ OldBlockSize = sizeof (EFI_HII_IIBT_IMAGE_1BIT_BLOCK) - sizeof (UINT8) +
+ BITMAP_LEN_1_BIT (Iibt1bit.Bitmap.Width, Iibt1bit.Bitmap.Height);
+ break;
+ case EFI_HII_IIBT_IMAGE_4BIT:
+ case EFI_HII_IIBT_IMAGE_4BIT_TRANS:
+ CopyMem (&Iibt4bit, ImageBlock, sizeof (EFI_HII_IIBT_IMAGE_4BIT_BLOCK));
+ OldBlockSize = sizeof (EFI_HII_IIBT_IMAGE_4BIT_BLOCK) - sizeof (UINT8) +
+ BITMAP_LEN_4_BIT (Iibt4bit.Bitmap.Width, Iibt4bit.Bitmap.Height);
+ break;
+ case EFI_HII_IIBT_IMAGE_8BIT:
+ case EFI_HII_IIBT_IMAGE_8BIT_TRANS:
+ CopyMem (&Iibt8bit, ImageBlock, sizeof (EFI_HII_IIBT_IMAGE_8BIT_BLOCK));
+ OldBlockSize = sizeof (EFI_HII_IIBT_IMAGE_8BIT_BLOCK) - sizeof (UINT8) +
+ BITMAP_LEN_8_BIT (Iibt8bit.Bitmap.Width, Iibt8bit.Bitmap.Height);
+ break;
+ case EFI_HII_IIBT_IMAGE_24BIT:
+ case EFI_HII_IIBT_IMAGE_24BIT_TRANS:
+ CopyMem (&Width, ImageBlock + sizeof (EFI_HII_IMAGE_BLOCK), sizeof (UINT16));
+ CopyMem (
+ &Height,
+ ImageBlock + sizeof (EFI_HII_IMAGE_BLOCK) + sizeof (UINT16),
+ sizeof (UINT16)
+ );
+ OldBlockSize = sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL) +
+ BITMAP_LEN_24_BIT (Width , Height);
+ break;
+ default:
+ return EFI_NOT_FOUND;
+ break;
+ }
+
+ //
+ // Create the new image block according to input image.
+ //
+ ImageIn = (EFI_IMAGE_INPUT *) Image;
+ NewBlockSize = sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL) +
+ BITMAP_LEN_24_BIT (ImageIn->Width, ImageIn->Height);
+ NewBlock = (UINT8 *) AllocateZeroPool (NewBlockSize);
+ if (NewBlock == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewBlockPtr = NewBlock;
+ if ((ImageIn->Flags & EFI_IMAGE_TRANSPARENT) == EFI_IMAGE_TRANSPARENT) {
+ *NewBlockPtr = EFI_HII_IIBT_IMAGE_24BIT_TRANS;
+ } else {
+ *NewBlockPtr = EFI_HII_IIBT_IMAGE_24BIT;
+ }
+ NewBlockPtr++;
+
+ CopyMem (NewBlockPtr, &ImageIn->Width, sizeof (UINT16));
+ NewBlockPtr += sizeof (UINT16);
+ CopyMem (NewBlockPtr, &ImageIn->Height, sizeof (UINT16));
+ NewBlockPtr += sizeof (UINT16);
+
+ CopyGopToRgbPixel ((EFI_HII_RGB_PIXEL *) NewBlockPtr, ImageIn->Bitmap, ImageIn->Width * ImageIn->Height);
+
+ //
+ // Adjust the image package to remove the original block firstly then add the new block.
+ //
+ BlockSize = ImagePackage->ImageBlockSize + NewBlockSize - OldBlockSize;
+ Block = (UINT8 *) AllocateZeroPool (BlockSize);
+ if (Block == NULL) {
+ SafeFreePool (NewBlock);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ BlockPtr = Block;
+ Part1Size = (UINT32) (ImageBlock - ImagePackage->ImageBlock);
+ Part2Size = ImagePackage->ImageBlockSize - Part1Size - OldBlockSize;
+ CopyMem (BlockPtr, ImagePackage->ImageBlock, Part1Size);
+ BlockPtr += Part1Size;
+ CopyMem (BlockPtr, NewBlock, NewBlockSize);
+ BlockPtr += NewBlockSize;
+ CopyMem (BlockPtr, ImageBlock + OldBlockSize, Part2Size);
+
+ SafeFreePool (ImagePackage->ImageBlock);
+ SafeFreePool (NewBlock);
+ ImagePackage->ImageBlock = Block;
+ ImagePackage->ImageBlockSize = BlockSize;
+ ImagePackage->ImagePkgHdr.Header.Length += NewBlockSize - OldBlockSize;
+ PackageListNode->PackageListHdr.PackageLength += NewBlockSize - OldBlockSize;
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+ This function renders an image to a bitmap or the screen using the specified
+ color and options. It draws the image on an existing bitmap, allocates a new
+ bitmap or uses the screen. The images can be clipped.
+
+ @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance.
+ @param Flags Describes how the image is to be drawn.
+ @param Image Points to the image to be displayed.
+ @param Blt If this points to a non-NULL on entry, this points
+ to the image, which is Width pixels wide and
+ Height pixels high. The image will be drawn onto
+ this image and EFI_HII_DRAW_FLAG_CLIP is implied.
+ If this points to a NULL on entry, then a buffer
+ will be allocated to hold the generated image and
+ the pointer updated on exit. It is the caller¡¯s
+ responsibility to free this buffer.
+ @param BltY Specifies the offset from the left and top edge of
+ the output image of the first pixel in the image.
+
+ @retval EFI_SUCCESS The image was successfully drawn.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate an output buffer for Blt.
+ @retval EFI_INVALID_PARAMETER The Image or Blt was NULL.
+ @retval EFI_INVALID_PARAMETER Any combination of Flags is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiDrawImage (
+ IN CONST EFI_HII_IMAGE_PROTOCOL *This,
+ IN EFI_HII_DRAW_FLAGS Flags,
+ IN CONST EFI_IMAGE_INPUT *Image,
+ IN OUT EFI_IMAGE_OUTPUT **Blt,
+ IN UINTN BltX,
+ IN UINTN BltY
+ )
+{
+ EFI_STATUS Status;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ BOOLEAN Transparent;
+ EFI_IMAGE_INPUT *ImageIn;
+ EFI_IMAGE_OUTPUT *ImageOut;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
+ UINTN BufferLen;
+ UINTN Width;
+ UINTN Height;
+ UINTN X;
+ UINTN Y;
+ UINTN OffsetY1;
+ UINTN OffsetY2;
+ EFI_FONT_DISPLAY_INFO *FontInfo;
+ UINTN Index;
+ EFI_CONSOLE_CONTROL_PROTOCOL *Console;
+
+ if (This == NULL || Image == NULL || Blt == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Flags & EFI_HII_DRAW_FLAG_CLIP) == EFI_HII_DRAW_FLAG_CLIP && *Blt == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Flags & EFI_HII_DRAW_FLAG_TRANSPARENT) == EFI_HII_DRAW_FLAG_TRANSPARENT) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ImageIn = (EFI_IMAGE_INPUT *) Image;
+
+ //
+ // Check whether the image will be drawn transparently or opaquely.
+ //
+ Transparent = FALSE;
+ if ((Flags & EFI_HII_DRAW_FLAG_TRANSPARENT) == EFI_HII_DRAW_FLAG_FORCE_TRANS) {
+ Transparent = TRUE;
+ } else if ((Flags & EFI_HII_DRAW_FLAG_TRANSPARENT) == EFI_HII_DRAW_FLAG_FORCE_OPAQUE){
+ Transparent = FALSE;
+ } else {
+ //
+ // Now EFI_HII_DRAW_FLAG_DEFAULT is set, whether image will be drawn depending
+ // on the image's transparency setting.
+ //
+ if ((ImageIn->Flags & EFI_IMAGE_TRANSPARENT) == EFI_IMAGE_TRANSPARENT) {
+ Transparent = TRUE;
+ }
+ }
+
+ //
+ // Image cannot be drawn transparently if Blt points to NULL on entry.
+ // Currently output to Screen transparently is not supported, either.
+ //
+ if (Transparent) {
+ if (*Blt == NULL) {
+ return EFI_INVALID_PARAMETER;
+ } else if ((Flags & EFI_HII_DIRECT_TO_SCREEN) == EFI_HII_DIRECT_TO_SCREEN) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ Private = HII_IMAGE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // When Blt points to a non-NULL on entry, this image will be drawn onto
+ // this bitmap or screen pointed by "*Blt" and EFI_HII_DRAW_FLAG_CLIP is implied.
+ // Otherwise a new bitmap will be allocated to hold this image.
+ //
+ if (*Blt != NULL) {
+ //
+ // Clip the image by (Width, Height)
+ //
+
+ Width = ImageIn->Width;
+ Height = ImageIn->Height;
+
+ if (Width > (*Blt)->Width - BltX) {
+ Width = (*Blt)->Width - BltX;
+ }
+ if (Height > (*Blt)->Height - BltY) {
+ Height = (*Blt)->Height - BltY;
+ }
+
+ BufferLen = Width * Height * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
+ BltBuffer = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) AllocateZeroPool (BufferLen);
+ if (BltBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (Width == ImageIn->Width && Height == ImageIn->Height) {
+ CopyMem (BltBuffer, ImageIn->Bitmap, BufferLen);
+ } else {
+ for (Y = 0; Y < Height; Y++) {
+ OffsetY1 = ImageIn->Width * Y;
+ OffsetY2 = Width * Y;
+ for (X = 0; X < Width; X++) {
+ BltBuffer[OffsetY2 + X] = ImageIn->Bitmap[OffsetY1 + X];
+ }
+ }
+ }
+
+ //
+ // Draw the image to existing bitmap or screen depending on flag.
+ //
+ if ((Flags & EFI_HII_DIRECT_TO_SCREEN) == EFI_HII_DIRECT_TO_SCREEN) {
+ Status = gBS->LocateProtocol (
+ &gEfiConsoleControlProtocolGuid,
+ NULL,
+ (VOID **) &Console
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Console->SetMode (Console, EfiConsoleControlScreenGraphics);
+ //
+ // Write the image directly to the output device specified by Screen.
+ //
+ Status = (*Blt)->Image.Screen->Blt (
+ (*Blt)->Image.Screen,
+ BltBuffer,
+ EfiBltBufferToVideo,
+ 0,
+ 0,
+ BltX,
+ BltY,
+ Width,
+ Height,
+ 0
+ );
+ } else {
+ //
+ // Draw the image onto the existing bitmap specified by Bitmap.
+ //
+ Status = ImageToBlt (
+ BltBuffer,
+ BltX,
+ BltY,
+ Width,
+ Height,
+ Transparent,
+ Blt
+ );
+
+ }
+
+ SafeFreePool (BltBuffer);
+ return Status;
+
+ } else {
+ //
+ // Allocate a new bitmap to hold the incoming image.
+ //
+ Width = ImageIn->Width + BltX;
+ Height = ImageIn->Height + BltY;
+
+ BufferLen = Width * Height * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
+ BltBuffer = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) AllocateZeroPool (BufferLen);
+ if (BltBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ImageOut = (EFI_IMAGE_OUTPUT *) AllocateZeroPool (sizeof (EFI_IMAGE_OUTPUT));
+ if (ImageOut == NULL) {
+ SafeFreePool (BltBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ImageOut->Width = (UINT16) Width;
+ ImageOut->Height = (UINT16) Height;
+ ImageOut->Image.Bitmap = BltBuffer;
+
+ //
+ // BUGBUG: Now all the "blank" pixels are filled with system default background
+ // color. Not sure if it need to be updated or not.
+ //
+ Status = GetSystemFont (Private, &FontInfo, NULL);
+ if (EFI_ERROR (Status)) {
+ SafeFreePool (BltBuffer);
+ SafeFreePool (ImageOut);
+ return Status;
+ }
+ for (Index = 0; Index < Width * Height; Index++) {
+ BltBuffer[Index] = FontInfo->BackgroundColor;
+ }
+ SafeFreePool (FontInfo);
+
+ //
+ // Draw the incoming image to the new created image.
+ //
+ *Blt = ImageOut;
+ return ImageToBlt (
+ ImageIn->Bitmap,
+ BltX,
+ BltY,
+ ImageIn->Width,
+ ImageIn->Height,
+ Transparent,
+ Blt
+ );
+
+ }
+}
+
+
+/**
+ This function renders an image to a bitmap or the screen using the specified
+ color and options. It draws the image on an existing bitmap, allocates a new
+ bitmap or uses the screen. The images can be clipped.
+
+ @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance.
+ @param Flags Describes how the image is to be drawn.
+ @param PackageList The package list in the HII database to search for
+ the specified image.
+ @param ImageId The image's id, which is unique within
+ PackageList.
+ @param Blt If this points to a non-NULL on entry, this points
+ to the image, which is Width pixels wide and
+ Height pixels high. The image will be drawn onto
+ this image and
+ EFI_HII_DRAW_FLAG_CLIP is implied. If this points
+ to a NULL on entry, then a buffer will be
+ allocated to hold the generated image and the
+ pointer updated on exit. It is the caller¡¯s
+ responsibility to free this buffer.
+ @param BltY Specifies the offset from the left and top edge of
+ the output image of the first pixel in the image.
+
+ @retval EFI_SUCCESS The image was successfully drawn.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate an output buffer for Blt.
+ @retval EFI_INVALID_PARAMETER The Image was NULL.
+ @retval EFI_NOT_FOUND The specified packagelist could not be found in
+ current database.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiDrawImageId (
+ IN CONST EFI_HII_IMAGE_PROTOCOL *This,
+ IN EFI_HII_DRAW_FLAGS Flags,
+ IN EFI_HII_HANDLE PackageList,
+ IN EFI_IMAGE_ID ImageId,
+ IN OUT EFI_IMAGE_OUTPUT **Blt,
+ IN UINTN BltX,
+ IN UINTN BltY
+ )
+{
+ EFI_STATUS Status;
+ EFI_IMAGE_INPUT ImageTemp;
+ EFI_IMAGE_INPUT *Image;
+ UINTN ImageSize;
+
+ //
+ // Check input parameter.
+ //
+ if (This == NULL || PackageList == NULL || Blt == NULL || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!IsHiiHandleValid (PackageList)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get the specified Image.
+ //
+ ImageSize = 0;
+ Status = HiiGetImage (This, PackageList, ImageId, &ImageTemp, &ImageSize);
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ return Status;
+ }
+
+ Image = (EFI_IMAGE_INPUT *) AllocateZeroPool (ImageSize);
+ if (Image == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = HiiGetImage (This, PackageList, ImageId, Image, &ImageSize);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Draw this image.
+ //
+ Status = HiiDrawImage (This, Flags, Image, Blt, BltX, BltY);
+ SafeFreePool (Image);
+ return Status;
+}
+
+#endif
+
diff --git a/MdeModulePkg/Universal/HiiDatabaseDxe/R8Lib.c b/MdeModulePkg/Universal/HiiDatabaseDxe/R8Lib.c new file mode 100644 index 0000000000..5458b16b61 --- /dev/null +++ b/MdeModulePkg/Universal/HiiDatabaseDxe/R8Lib.c @@ -0,0 +1,284 @@ +/**@file
+ Copyright (c) 2007, Intel Corporation
+
+ All rights reserved. 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 "HiiDatabase.h"
+
+
+CHAR16
+NibbleToHexChar (
+ IN UINT8 Nibble
+ )
+/*++
+
+ Routine Description:
+ Converts the low nibble of a byte to hex unicode character.
+
+ Arguments:
+ Nibble - lower nibble of a byte.
+
+ Returns:
+ Hex unicode character.
+
+--*/
+{
+ Nibble &= 0x0F;
+ if (Nibble <= 0x9) {
+ return (CHAR16)(Nibble + L'0');
+ }
+
+ return (CHAR16)(Nibble - 0xA + L'A');
+}
+
+/**
+ Compare whether two names of languages are identical.
+
+ @param Language1 Name of language 1
+ @param Language2 Name of language 2
+
+ @retval TRUE same
+ @retval FALSE not same
+
+**/
+BOOLEAN
+R8_EfiLibCompareLanguage (
+ IN CHAR8 *Language1,
+ IN CHAR8 *Language2
+ )
+{
+ //
+ // Porting Guide:
+ // This library interface is simply obsolete.
+ // Include the source code to user code.
+ //
+ UINTN Index;
+
+ for (Index = 0; (Language1[Index] != 0) && (Language2[Index] != 0); Index++) {
+ if (Language1[Index] != Language2[Index]) {
+ return FALSE;
+ }
+ }
+
+ if (((Language1[Index] == 0) && (Language2[Index] == 0)) ||
+ ((Language1[Index] == 0) && (Language2[Index] != ';')) ||
+ ((Language1[Index] == ';') && (Language2[Index] != 0)) ||
+ ((Language1[Index] == ';') && (Language2[Index] != ';'))) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+
+
+/**
+ Converts binary buffer to Unicode string.
+ At a minimum, any blob of data could be represented as a hex string.
+
+ @param Str Pointer to the string.
+ @param HexStringBufferLength Length in bytes of buffer to hold the hex string.
+ Includes tailing '\0' character. If routine return
+ with EFI_SUCCESS, containing length of hex string
+ buffer. If routine return with
+ EFI_BUFFER_TOO_SMALL, containg length of hex
+ string buffer desired.
+ @param Buf Buffer to be converted from.
+ @param Len Length in bytes of the buffer to be converted.
+
+ @retval EFI_SUCCESS Routine success.
+ @retval EFI_BUFFER_TOO_SMALL The hex string buffer is too small.
+
+**/
+EFI_STATUS
+R8_BufToHexString (
+ IN OUT CHAR16 *Str,
+ IN OUT UINTN *HexStringBufferLength,
+ IN UINT8 *Buf,
+ IN UINTN Len
+ )
+{
+ //
+ // Porting Guide:
+ // This library interface is simply obsolete.
+ // Include the source code to user code.
+ //
+ UINTN Idx;
+ UINT8 Byte;
+ UINTN StrLen;
+
+ //
+ // Make sure string is either passed or allocate enough.
+ // It takes 2 Unicode characters (4 bytes) to represent 1 byte of the binary buffer.
+ // Plus the Unicode termination character.
+ //
+ StrLen = Len * 2;
+ if (StrLen > ((*HexStringBufferLength) - 1)) {
+ *HexStringBufferLength = StrLen + 1;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *HexStringBufferLength = StrLen + 1;
+ //
+ // Ends the string.
+ //
+ Str[StrLen] = L'\0';
+
+ for (Idx = 0; Idx < Len; Idx++) {
+
+ Byte = Buf[Idx];
+ Str[StrLen - 1 - Idx * 2] = NibbleToHexChar (Byte);
+ Str[StrLen - 2 - Idx * 2] = NibbleToHexChar ((UINT8)(Byte >> 4));
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+
+
+/**
+ Converts Unicode string to binary buffer.
+ The conversion may be partial.
+ The first character in the string that is not hex digit stops the conversion.
+ At a minimum, any blob of data could be represented as a hex string.
+
+ @param Buf Pointer to buffer that receives the data.
+ @param Len Length in bytes of the buffer to hold converted
+ data. If routine return with EFI_SUCCESS,
+ containing length of converted data. If routine
+ return with EFI_BUFFER_TOO_SMALL, containg length
+ of buffer desired.
+ @param Str String to be converted from.
+ @param ConvertedStrLen Length of the Hex String consumed.
+
+ @retval EFI_SUCCESS Routine Success.
+ @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold converted data.
+
+**/
+EFI_STATUS
+R8_HexStringToBuf (
+ IN OUT UINT8 *Buf,
+ IN OUT UINTN *Len,
+ IN CHAR16 *Str,
+ OUT UINTN *ConvertedStrLen OPTIONAL
+ )
+{
+ //
+ // Porting Guide:
+ // This library interface is simply obsolete.
+ // Include the source code to user code.
+ //
+
+ UINTN HexCnt;
+ UINTN Idx;
+ UINTN BufferLength;
+ UINT8 Digit;
+ UINT8 Byte;
+
+ //
+ // Find out how many hex characters the string has.
+ //
+ for (Idx = 0, HexCnt = 0; R8_IsHexDigit (&Digit, Str[Idx]); Idx++, HexCnt++);
+
+ if (HexCnt == 0) {
+ *Len = 0;
+ return EFI_SUCCESS;
+ }
+ //
+ // Two Unicode characters make up 1 buffer byte. Round up.
+ //
+ BufferLength = (HexCnt + 1) / 2;
+
+ //
+ // Test if buffer is passed enough.
+ //
+ if (BufferLength > (*Len)) {
+ *Len = BufferLength;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *Len = BufferLength;
+
+ for (Idx = 0; Idx < HexCnt; Idx++) {
+
+ R8_IsHexDigit (&Digit, Str[HexCnt - 1 - Idx]);
+
+ //
+ // For odd charaters, write the lower nibble for each buffer byte,
+ // and for even characters, the upper nibble.
+ //
+ if ((Idx & 1) == 0) {
+ Byte = Digit;
+ } else {
+ Byte = Buf[Idx / 2];
+ Byte &= 0x0F;
+ Byte = (UINT8) (Byte | Digit << 4);
+ }
+
+ Buf[Idx / 2] = Byte;
+ }
+
+ if (ConvertedStrLen != NULL) {
+ *ConvertedStrLen = HexCnt;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+
+
+/**
+ Determines if a Unicode character is a hexadecimal digit.
+ The test is case insensitive.
+
+ @param Digit Pointer to byte that receives the value of the hex
+ character.
+ @param Char Unicode character to test.
+
+ @retval TRUE If the character is a hexadecimal digit.
+ @retval FALSE Otherwise.
+
+**/
+BOOLEAN
+R8_IsHexDigit (
+ OUT UINT8 *Digit,
+ IN CHAR16 Char
+ )
+{
+ //
+ // Porting Guide:
+ // This library interface is simply obsolete.
+ // Include the source code to user code.
+ //
+
+ if ((Char >= L'0') && (Char <= L'9')) {
+ *Digit = (UINT8) (Char - L'0');
+ return TRUE;
+ }
+
+ if ((Char >= L'A') && (Char <= L'F')) {
+ *Digit = (UINT8) (Char - L'A' + 0x0A);
+ return TRUE;
+ }
+
+ if ((Char >= L'a') && (Char <= L'f')) {
+ *Digit = (UINT8) (Char - L'a' + 0x0A);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
diff --git a/MdeModulePkg/Universal/HiiDatabaseDxe/R8Lib.h b/MdeModulePkg/Universal/HiiDatabaseDxe/R8Lib.h new file mode 100644 index 0000000000..4e6e1a1e61 --- /dev/null +++ b/MdeModulePkg/Universal/HiiDatabaseDxe/R8Lib.h @@ -0,0 +1,121 @@ +/**@file + Copyright (c) 2007, Intel Corporation + + All rights reserved. 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 __R8_LIB_H__ +#define __R8_LIB_H__ + + +/** + Compare whether two names of languages are identical. + + @param Language1 Name of language 1 + @param Language2 Name of language 2 + + @retval TRUE same + @retval FALSE not same + +**/ +BOOLEAN +R8_EfiLibCompareLanguage ( + IN CHAR8 *Language1, + IN CHAR8 *Language2 + ) +; + + + + +/** + Converts binary buffer to Unicode string. + At a minimum, any blob of data could be represented as a hex string. + + @param Str Pointer to the string. + @param HexStringBufferLength Length in bytes of buffer to hold the hex string. + Includes tailing '\0' character. If routine return + with EFI_SUCCESS, containing length of hex string + buffer. If routine return with + EFI_BUFFER_TOO_SMALL, containg length of hex + string buffer desired. + @param Buf Buffer to be converted from. + @param Len Length in bytes of the buffer to be converted. + + @retval EFI_SUCCESS Routine success. + @retval EFI_BUFFER_TOO_SMALL The hex string buffer is too small. + +**/ +EFI_STATUS +R8_BufToHexString ( + IN OUT CHAR16 *Str, + IN OUT UINTN *HexStringBufferLength, + IN UINT8 *Buf, + IN UINTN Len + ) +; + + + + +/** + Converts Unicode string to binary buffer. + The conversion may be partial. + The first character in the string that is not hex digit stops the conversion. + At a minimum, any blob of data could be represented as a hex string. + + @param Buf Pointer to buffer that receives the data. + @param Len Length in bytes of the buffer to hold converted + data. If routine return with EFI_SUCCESS, + containing length of converted data. If routine + return with EFI_BUFFER_TOO_SMALL, containg length + of buffer desired. + @param Str String to be converted from. + @param ConvertedStrLen Length of the Hex String consumed. + + @retval EFI_SUCCESS Routine Success. + @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold converted data. + +**/ +EFI_STATUS +R8_HexStringToBuf ( + IN OUT UINT8 *Buf, + IN OUT UINTN *Len, + IN CHAR16 *Str, + OUT UINTN *ConvertedStrLen OPTIONAL + ) +; + + + + +/** + Determines if a Unicode character is a hexadecimal digit. + The test is case insensitive. + + @param Digit Pointer to byte that receives the value of the hex + character. + @param Char Unicode character to test. + + @retval TRUE If the character is a hexadecimal digit. + @retval FALSE Otherwise. + +**/ +BOOLEAN +R8_IsHexDigit ( + OUT UINT8 *Digit, + IN CHAR16 Char + ) +; + + +#endif + diff --git a/MdeModulePkg/Universal/HiiDatabaseDxe/String.c b/MdeModulePkg/Universal/HiiDatabaseDxe/String.c new file mode 100644 index 0000000000..d408365a89 --- /dev/null +++ b/MdeModulePkg/Universal/HiiDatabaseDxe/String.c @@ -0,0 +1,1606 @@ +/** @file
+
+Copyright (c) 2007, Intel Corporation
+All rights reserved. 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.
+
+Module Name:
+
+ String.c
+
+Abstract:
+
+ Implementation for EFI_HII_STRING_PROTOCOL.
+
+Revision History
+
+
+**/
+
+
+#include "HiiDatabase.h"
+
+CHAR16 mLanguageWindow[16] = {
+ 0x0000, 0x0080, 0x0100, 0x0300,
+ 0x2000, 0x2080, 0x2100, 0x3000,
+ 0x0080, 0x00C0, 0x0400, 0x0600,
+ 0x0900, 0x3040, 0x30A0, 0xFF00
+};
+
+
+/**
+ This function checks whether a global font info is referred by local
+ font info list or not. (i.e. HII_FONT_INFO is generated.) If not, create
+ a HII_FONT_INFO to refer it locally.
+
+ @param Private Hii database private structure.
+ @param StringPackage HII string package instance.
+ @param DuplicateEnable If true, duplicate HII_FONT_INFO which refers to
+ the same EFI_FONT_INFO is permitted. Otherwise it
+ is not allowed.
+ @param GlobalFontInfo Input a global font info which specify a
+ EFI_FONT_INFO.
+ @param LocalFontInfo Output a local font info which refers to a
+ EFI_FONT_INFO.
+
+ @retval TRUE Already referred before calling this function.
+ @retval FALSE Not referred before calling this function.
+
+**/
+STATIC
+BOOLEAN
+ReferFontInfoLocally (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN HII_STRING_PACKAGE_INSTANCE *StringPackage,
+ IN BOOLEAN DuplicateEnable,
+ IN HII_GLOBAL_FONT_INFO *GlobalFontInfo,
+ OUT HII_FONT_INFO **LocalFontInfo
+ )
+{
+ HII_FONT_INFO *LocalFont;
+ LIST_ENTRY *Link;
+
+ ASSERT (Private != NULL && StringPackage != NULL && GlobalFontInfo != NULL && LocalFontInfo != NULL);
+
+ if (!DuplicateEnable) {
+ for (Link = StringPackage->FontInfoList.ForwardLink;
+ Link != &StringPackage->FontInfoList;
+ Link = Link->ForwardLink
+ ) {
+ LocalFont = CR (Link, HII_FONT_INFO, Entry, HII_FONT_INFO_SIGNATURE);
+ if (LocalFont->GlobalEntry == &GlobalFontInfo->Entry) {
+ //
+ // Already referred by local font info list, return directly.
+ //
+ *LocalFontInfo = LocalFont;
+ return TRUE;
+ }
+ }
+ }
+ //
+ // Since string package tool set FontId initially to 0 and increases it
+ // progressively by one, StringPackage->FondId always represents an unique
+ // and available FontId.
+ //
+ // FontId identifies EFI_FONT_INFO in local string package uniquely.
+ // GlobalEntry points to a HII_GLOBAL_FONT_INFO which identifies
+ // EFI_FONT_INFO uniquely in whole hii database.
+ //
+ LocalFont = (HII_FONT_INFO *) AllocateZeroPool (sizeof (HII_FONT_INFO));
+ ASSERT (LocalFont != NULL);
+
+ LocalFont->Signature = HII_FONT_INFO_SIGNATURE;
+ LocalFont->FontId = StringPackage->FontId;
+ LocalFont->GlobalEntry = &GlobalFontInfo->Entry;
+ InsertTailList (&StringPackage->FontInfoList, &LocalFont->Entry);
+
+ StringPackage->FontId++;
+
+ *LocalFontInfo = LocalFont;
+ return FALSE;
+}
+
+
+/**
+ Convert Ascii string text to unicode string test.
+
+ @param StringSrc Points to current null-terminated Ascii string.
+ @param StringDest Buffer to store the converted string text.
+ @param BufferSize Length of the buffer.
+
+ @retval EFI_SUCCESS The string text was outputed successfully.
+ @retval EFI_BUFFER_TOO_SMALL Buffer is insufficient to store the found string
+ text. BufferSize is updated to the required buffer
+ size.
+
+**/
+STATIC
+EFI_STATUS
+ConvertToUnicodeText (
+ OUT EFI_STRING StringDest,
+ IN CHAR8 *StringSrc,
+ IN OUT UINTN *BufferSize
+ )
+{
+ UINTN StringSize;
+ UINTN Index;
+
+ ASSERT (StringSrc != NULL && BufferSize != NULL);
+
+ StringSize = AsciiStrSize (StringSrc) * 2;
+ if (*BufferSize < StringSize) {
+ *BufferSize = StringSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ for (Index = 0; Index < AsciiStrLen (StringSrc); Index++) {
+ StringDest[Index] = (CHAR16) StringSrc[Index];
+ }
+
+ StringDest[Index] = 0;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Calculate the size of StringSrc and output it. If StringDest is not NULL,
+ copy string text from src to dest.
+
+ @param StringSrc Points to current null-terminated string.
+ @param StringDest Buffer to store the string text.
+ @param BufferSize Length of the buffer.
+
+ @retval EFI_SUCCESS The string text was outputed successfully.
+ @retval EFI_BUFFER_TOO_SMALL Buffer is insufficient to store the found string
+ text. BufferSize is updated to the required buffer
+ size.
+
+**/
+STATIC
+EFI_STATUS
+GetUnicodeStringTextOrSize (
+ OUT EFI_STRING StringDest, OPTIONAL
+ IN UINT8 *StringSrc,
+ IN OUT UINTN *BufferSize
+ )
+{
+ UINTN StringSize;
+ CHAR16 Zero;
+ UINT8 *StringPtr;
+
+ ASSERT (StringSrc != NULL && BufferSize != NULL);
+
+ ZeroMem (&Zero, sizeof (CHAR16));
+ StringSize = sizeof (CHAR16);
+ StringPtr = StringSrc;
+ while (CompareMem (StringPtr, &Zero, sizeof (CHAR16)) != 0) {
+ StringSize += sizeof (CHAR16);
+ StringPtr += sizeof (CHAR16);
+ }
+
+ if (StringDest != NULL) {
+ if (*BufferSize < StringSize) {
+ *BufferSize = StringSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ CopyMem (StringDest, StringSrc, StringSize);
+ return EFI_SUCCESS;
+ }
+
+ *BufferSize = StringSize;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Copy string font info to a buffer.
+
+ @param StringPackage Hii string package instance.
+ @param FontId Font identifier which is unique in a string
+ package.
+ @param StringFontInfo Buffer to record the output font info. It's
+ caller's responsibility to free this buffer.
+
+ @retval EFI_SUCCESS The string font is outputed successfully.
+ @retval EFI_NOT_FOUND The specified font id does not exist.
+
+**/
+STATIC
+EFI_STATUS
+GetStringFontInfo (
+ IN HII_STRING_PACKAGE_INSTANCE *StringPackage,
+ IN UINT8 FontId,
+ OUT EFI_FONT_INFO **StringFontInfo
+ )
+{
+ LIST_ENTRY *Link;
+ HII_FONT_INFO *FontInfo;
+ HII_GLOBAL_FONT_INFO *GlobalFont;
+
+ ASSERT (StringFontInfo != NULL && StringPackage != NULL);
+
+ for (Link = StringPackage->FontInfoList.ForwardLink; Link != &StringPackage->FontInfoList; Link = Link->ForwardLink) {
+ FontInfo = CR (Link, HII_FONT_INFO, Entry, HII_FONT_INFO_SIGNATURE);
+ if (FontInfo->FontId == FontId) {
+ GlobalFont = CR (FontInfo->GlobalEntry, HII_GLOBAL_FONT_INFO, Entry, HII_GLOBAL_FONT_INFO_SIGNATURE);
+ *StringFontInfo = (EFI_FONT_INFO *) AllocateZeroPool (GlobalFont->FontInfoSize);
+ if (*StringFontInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (*StringFontInfo, GlobalFont->FontInfo, GlobalFont->FontInfoSize);
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Parse all string blocks to find a String block specified by StringId.
+ If StringId = (EFI_STRING_ID) (-1), find out all EFI_HII_SIBT_FONT blocks
+ within this string package and backup its information.
+ If StringId = 0, output the string id of last string block (EFI_HII_SIBT_END).
+
+ @param Private Hii database private structure.
+ @param StringPackage Hii string package instance.
+ @param StringId The string¡¯s id, which is unique within
+ PackageList.
+ @param BlockType Output the block type of found string block.
+ @param StringBlockAddr Output the block address of found string block.
+ @param StringTextOffset Offset, relative to the found block address, of
+ the string text information.
+ @param LastStringId Output the last string id when StringId = 0.
+
+ @retval EFI_SUCCESS The string text and font is retrieved
+ successfully.
+ @retval EFI_NOT_FOUND The specified text or font info can not be found
+ out.
+ @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the
+ task.
+
+**/
+EFI_STATUS
+FindStringBlock (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN HII_STRING_PACKAGE_INSTANCE *StringPackage,
+ IN EFI_STRING_ID StringId,
+ OUT UINT8 *BlockType, OPTIONAL
+ OUT UINT8 **StringBlockAddr, OPTIONAL
+ OUT UINTN *StringTextOffset, OPTIONAL
+ OUT EFI_STRING_ID *LastStringId OPTIONAL
+ )
+{
+ UINT8 *BlockHdr;
+ EFI_STRING_ID CurrentStringId;
+ UINTN BlockSize;
+ UINTN Index;
+ UINT8 *StringTextPtr;
+ UINTN Offset;
+ HII_FONT_INFO *LocalFont;
+ EFI_FONT_INFO *FontInfo;
+ HII_GLOBAL_FONT_INFO *GlobalFont;
+ UINTN FontInfoSize;
+ UINT16 StringCount;
+ UINT16 SkipCount;
+ EFI_HII_FONT_STYLE FontStyle;
+ UINT16 FontSize;
+ UINT8 Length8;
+ EFI_HII_SIBT_EXT2_BLOCK Ext2;
+ UINT32 Length32;
+ UINTN StringSize;
+ CHAR16 Zero;
+
+ ASSERT (StringPackage != NULL);
+ ASSERT (StringPackage->Signature == HII_STRING_PACKAGE_SIGNATURE);
+
+ CurrentStringId = 1;
+
+ if (StringId != (EFI_STRING_ID) (-1) && StringId != 0) {
+ ASSERT (BlockType != NULL && StringBlockAddr != NULL && StringTextOffset != NULL);
+ } else {
+ ASSERT (Private != NULL && Private->Signature == HII_DATABASE_PRIVATE_DATA_SIGNATURE);
+ }
+
+ ZeroMem (&Zero, sizeof (CHAR16));
+
+ //
+ // Parse the string blocks to get the string text and font.
+ //
+ BlockHdr = StringPackage->StringBlock;
+ BlockSize = 0;
+ Offset = 0;
+ while (*BlockHdr != EFI_HII_SIBT_END) {
+ switch (*BlockHdr) {
+ case EFI_HII_SIBT_STRING_SCSU:
+ Offset = sizeof (EFI_HII_STRING_BLOCK);
+ StringTextPtr = BlockHdr + Offset;
+ BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr);
+ CurrentStringId++;
+ break;
+
+ case EFI_HII_SIBT_STRING_SCSU_FONT:
+ Offset = sizeof (EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK) - sizeof (UINT8);
+ StringTextPtr = BlockHdr + Offset;
+ BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr);
+ CurrentStringId++;
+ break;
+
+ case EFI_HII_SIBT_STRINGS_SCSU:
+ CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
+ StringTextPtr = BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_BLOCK) - sizeof (UINT8);
+ BlockSize += StringTextPtr - BlockHdr;
+
+ for (Index = 0; Index < StringCount; Index++) {
+ BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr);
+ if (CurrentStringId == StringId) {
+ *BlockType = *BlockHdr;
+ *StringBlockAddr = BlockHdr;
+ *StringTextOffset = StringTextPtr - BlockHdr;
+ return EFI_SUCCESS;
+ }
+ StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr);
+ CurrentStringId++;
+ }
+ break;
+
+ case EFI_HII_SIBT_STRINGS_SCSU_FONT:
+ CopyMem (
+ &StringCount,
+ BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8),
+ sizeof (UINT16)
+ );
+ StringTextPtr = BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK) - sizeof (UINT8);
+ BlockSize += StringTextPtr - BlockHdr;
+
+ for (Index = 0; Index < StringCount; Index++) {
+ BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr);
+ if (CurrentStringId == StringId) {
+ *BlockType = *BlockHdr;
+ *StringBlockAddr = BlockHdr;
+ *StringTextOffset = StringTextPtr - BlockHdr;
+ return EFI_SUCCESS;
+ }
+ StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr);
+ CurrentStringId++;
+ }
+ break;
+
+ case EFI_HII_SIBT_STRING_UCS2:
+ Offset = sizeof (EFI_HII_STRING_BLOCK);
+ StringTextPtr = BlockHdr + Offset;
+ //
+ // Use StringSize to store the size of the specified string, including the NULL
+ // terminator.
+ //
+ GetUnicodeStringTextOrSize (NULL, StringTextPtr, &StringSize);
+ BlockSize += Offset + StringSize;
+ CurrentStringId++;
+ break;
+
+ case EFI_HII_SIBT_STRING_UCS2_FONT:
+ Offset = sizeof (EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK) - sizeof (CHAR16);
+ StringTextPtr = BlockHdr + Offset;
+ //
+ // Use StrSize to store the size of the specified string, including the NULL
+ // terminator.
+ //
+ GetUnicodeStringTextOrSize (NULL, StringTextPtr, &StringSize);
+ BlockSize += Offset + StringSize;
+ CurrentStringId++;
+ break;
+
+ case EFI_HII_SIBT_STRINGS_UCS2:
+ Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_BLOCK) - sizeof (CHAR16);
+ StringTextPtr = BlockHdr + Offset;
+ BlockSize += Offset;
+ CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
+ for (Index = 0; Index < StringCount; Index++) {
+ GetUnicodeStringTextOrSize (NULL, StringTextPtr, &StringSize);
+ BlockSize += StringSize;
+ if (CurrentStringId == StringId) {
+ *BlockType = *BlockHdr;
+ *StringBlockAddr = BlockHdr;
+ *StringTextOffset = StringTextPtr - BlockHdr;
+ return EFI_SUCCESS;
+ }
+ StringTextPtr = StringTextPtr + StringSize;
+ CurrentStringId++;
+ }
+ break;
+
+ case EFI_HII_SIBT_STRINGS_UCS2_FONT:
+ Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK) - sizeof (CHAR16);
+ StringTextPtr = BlockHdr + Offset;
+ BlockSize += Offset;
+ CopyMem (
+ &StringCount,
+ BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8),
+ sizeof (UINT16)
+ );
+ for (Index = 0; Index < StringCount; Index++) {
+ GetUnicodeStringTextOrSize (NULL, StringTextPtr, &StringSize);
+ BlockSize += StringSize;
+ if (CurrentStringId == StringId) {
+ *BlockType = *BlockHdr;
+ *StringBlockAddr = BlockHdr;
+ *StringTextOffset = StringTextPtr - BlockHdr;
+ return EFI_SUCCESS;
+ }
+ StringTextPtr = StringTextPtr + StringSize;
+ CurrentStringId++;
+ }
+ break;
+
+ case EFI_HII_SIBT_DUPLICATE:
+ if (CurrentStringId == StringId) {
+ //
+ // Incoming StringId is an id of a duplicate string block.
+ // Update the StringId to be the previous string block.
+ // Go back to the header of string block to search.
+ //
+ CopyMem (
+ &StringId,
+ BlockHdr + sizeof (EFI_HII_STRING_BLOCK),
+ sizeof (EFI_STRING_ID)
+ );
+ ASSERT (StringId != CurrentStringId);
+ CurrentStringId = 1;
+ BlockSize = 0;
+ } else {
+ BlockSize += sizeof (EFI_HII_SIBT_DUPLICATE_BLOCK);
+ CurrentStringId++;
+ }
+ break;
+
+ case EFI_HII_SIBT_SKIP1:
+ SkipCount = (UINT16) (*(BlockHdr + sizeof (EFI_HII_STRING_BLOCK)));
+ CurrentStringId = (UINT16) (CurrentStringId + SkipCount);
+ BlockSize += sizeof (EFI_HII_SIBT_SKIP1_BLOCK);
+ break;
+
+ case EFI_HII_SIBT_SKIP2:
+ CopyMem (&SkipCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
+ CurrentStringId = (UINT16) (CurrentStringId + SkipCount);
+ BlockSize += sizeof (EFI_HII_SIBT_SKIP2_BLOCK);
+ break;
+
+ case EFI_HII_SIBT_EXT1:
+ CopyMem (
+ &Length8,
+ BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8),
+ sizeof (UINT8)
+ );
+ BlockSize += Length8;
+ break;
+
+ case EFI_HII_SIBT_EXT2:
+ CopyMem (&Ext2, BlockHdr, sizeof (EFI_HII_SIBT_EXT2_BLOCK));
+ if (Ext2.BlockType2 == EFI_HII_SIBT_FONT && StringId == (EFI_STRING_ID) (-1)) {
+ //
+ // Find the relationship between global font info and the font info of
+ // this EFI_HII_SIBT_FONT block then backup its information in local package.
+ //
+ BlockHdr += sizeof (EFI_HII_SIBT_EXT2_BLOCK) + sizeof (UINT8);
+ CopyMem (&FontSize, BlockHdr, sizeof (UINT16));
+ BlockHdr += sizeof (UINT16);
+ CopyMem (&FontStyle, BlockHdr, sizeof (EFI_HII_FONT_STYLE));
+ BlockHdr += sizeof (EFI_HII_FONT_STYLE);
+ GetUnicodeStringTextOrSize (NULL, BlockHdr, &StringSize);
+
+ FontInfoSize = sizeof (EFI_FONT_INFO) - sizeof (CHAR16) + StringSize;
+ FontInfo = (EFI_FONT_INFO *) AllocateZeroPool (FontInfoSize);
+ if (FontInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ FontInfo->FontStyle = FontStyle;
+ FontInfo->FontSize = FontSize;
+ CopyMem (FontInfo->FontName, BlockHdr, StringSize);
+
+ if (IsFontInfoExisted (Private, FontInfo, NULL, NULL, &GlobalFont)) {
+ //
+ // If find the corresponding global font info, save the relationship.
+ //
+ ReferFontInfoLocally (Private, StringPackage, TRUE, GlobalFont, &LocalFont);
+ }
+
+ //
+ // If can not find, ignore this EFI_HII_SIBT_FONT block.
+ //
+ SafeFreePool (FontInfo);
+ }
+
+ BlockSize += Ext2.Length;
+
+ break;
+
+ case EFI_HII_SIBT_EXT4:
+ CopyMem (
+ &Length32,
+ BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8),
+ sizeof (UINT32)
+ );
+
+ BlockSize += Length32;
+ break;
+
+ default:
+ break;
+ }
+
+ if (StringId > 0) {
+ if (StringId == CurrentStringId - 1) {
+ *BlockType = *BlockHdr;
+ *StringBlockAddr = BlockHdr;
+ *StringTextOffset = Offset;
+ return EFI_SUCCESS;
+ }
+
+ if (StringId < CurrentStringId - 1) {
+ return EFI_NOT_FOUND;
+ }
+ }
+ BlockHdr = StringPackage->StringBlock + BlockSize;
+
+ }
+
+ if (StringId == (EFI_STRING_ID) (-1)) {
+ return EFI_SUCCESS;
+ }
+
+ if (StringId == 0 && LastStringId != NULL) {
+ *LastStringId = CurrentStringId;
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Parse all string blocks to get a string specified by StringId.
+
+ @param Private Hii database private structure.
+ @param StringPackage Hii string package instance.
+ @param StringId The string¡¯s id, which is unique within
+ PackageList.
+ @param String Points to retrieved null-terminated string.
+ @param StringSize On entry, points to the size of the buffer pointed
+ to by String, in bytes. On return, points to the
+ length of the string, in bytes.
+ @param StringFontInfo If not NULL, allocate a buffer to record the
+ output font info. It's caller's responsibility to
+ free this buffer.
+
+ @retval EFI_SUCCESS The string text and font is retrieved
+ successfully.
+ @retval EFI_NOT_FOUND The specified text or font info can not be found
+ out.
+ @retval EFI_BUFFER_TOO_SMALL The buffer specified by StringSize is too small to
+ hold the string.
+
+**/
+STATIC
+EFI_STATUS
+GetStringWorker (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN HII_STRING_PACKAGE_INSTANCE *StringPackage,
+ IN EFI_STRING_ID StringId,
+ OUT EFI_STRING String,
+ IN OUT UINTN *StringSize,
+ OUT EFI_FONT_INFO **StringFontInfo OPTIONAL
+ )
+{
+ UINT8 *StringTextPtr;
+ UINT8 BlockType;
+ UINT8 *StringBlockAddr;
+ UINTN StringTextOffset;
+ EFI_STATUS Status;
+ UINT8 FontId;
+
+ ASSERT (StringPackage != NULL && StringSize != NULL);
+ ASSERT (Private != NULL && Private->Signature == HII_DATABASE_PRIVATE_DATA_SIGNATURE);
+
+ //
+ // Find the specified string block
+ //
+ Status = FindStringBlock (
+ Private,
+ StringPackage,
+ StringId,
+ &BlockType,
+ &StringBlockAddr,
+ &StringTextOffset,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the string text.
+ //
+ StringTextPtr = StringBlockAddr + StringTextOffset;
+ switch (BlockType) {
+ case EFI_HII_SIBT_STRING_SCSU:
+ case EFI_HII_SIBT_STRING_SCSU_FONT:
+ case EFI_HII_SIBT_STRINGS_SCSU:
+ case EFI_HII_SIBT_STRINGS_SCSU_FONT:
+ Status = ConvertToUnicodeText (String, (CHAR8 *) StringTextPtr, StringSize);
+ break;
+ case EFI_HII_SIBT_STRING_UCS2:
+ case EFI_HII_SIBT_STRING_UCS2_FONT:
+ case EFI_HII_SIBT_STRINGS_UCS2:
+ case EFI_HII_SIBT_STRINGS_UCS2_FONT:
+ Status = GetUnicodeStringTextOrSize (String, StringTextPtr, StringSize);
+ break;
+ default:
+ return EFI_NOT_FOUND;
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the string font.
+ //
+ if (StringFontInfo != NULL) {
+ switch (BlockType) {
+ case EFI_HII_SIBT_STRING_SCSU_FONT:
+ case EFI_HII_SIBT_STRINGS_SCSU_FONT:
+ case EFI_HII_SIBT_STRING_UCS2_FONT:
+ case EFI_HII_SIBT_STRINGS_UCS2_FONT:
+ FontId = *(StringBlockAddr + sizeof (EFI_HII_STRING_BLOCK));
+ return GetStringFontInfo (StringPackage, FontId, StringFontInfo);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Parse all string blocks to set a String specified by StringId.
+
+ @param Private HII database driver private structure.
+ @param StringPackage HII string package instance.
+ @param StringId The string¡¯s id, which is unique within
+ PackageList.
+ @param String Points to the new null-terminated string.
+ @param StringFontInfo Points to the input font info.
+
+ @retval EFI_SUCCESS The string was updated successfully.
+ @retval EFI_NOT_FOUND The string specified by StringId is not in the
+ database.
+ @retval EFI_INVALID_PARAMETER The String or Language was NULL.
+ @retval EFI_INVALID_PARAMETER The specified StringFontInfo does not exist in
+ current database.
+ @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the
+ task.
+
+**/
+STATIC
+EFI_STATUS
+SetStringWorker (
+ IN HII_DATABASE_PRIVATE_DATA *Private,
+ IN OUT HII_STRING_PACKAGE_INSTANCE *StringPackage,
+ IN EFI_STRING_ID StringId,
+ IN EFI_STRING String,
+ IN EFI_FONT_INFO *StringFontInfo OPTIONAL
+ )
+{
+ UINT8 *StringTextPtr;
+ UINT8 BlockType;
+ UINT8 *StringBlockAddr;
+ UINTN StringTextOffset;
+ EFI_STATUS Status;
+ UINT8 *Block;
+ UINT8 *BlockPtr;
+ UINTN BlockSize;
+ UINTN OldBlockSize;
+ HII_FONT_INFO *LocalFont;
+ HII_GLOBAL_FONT_INFO *GlobalFont;
+ BOOLEAN Referred;
+ EFI_HII_SIBT_EXT2_BLOCK Ext2;
+ UINTN StringSize;
+ UINTN TmpSize;
+
+
+ ASSERT (Private != NULL && StringPackage != NULL && String != NULL);
+ ASSERT (Private->Signature == HII_DATABASE_PRIVATE_DATA_SIGNATURE);
+ //
+ // Find the specified string block
+ //
+ Status = FindStringBlock (
+ Private,
+ StringPackage,
+ StringId,
+ &BlockType,
+ &StringBlockAddr,
+ &StringTextOffset,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ LocalFont = NULL;
+ GlobalFont = NULL;
+ Referred = FALSE;
+
+ //
+ // Set the string font according to input font information.
+ //
+ if (StringFontInfo != NULL) {
+ //
+ // The input StringFontInfo should exist in current database
+ //
+ if (!IsFontInfoExisted (Private, StringFontInfo, NULL, NULL, &GlobalFont)) {
+ return EFI_INVALID_PARAMETER;
+ } else {
+ Referred = ReferFontInfoLocally (Private, StringPackage, FALSE, GlobalFont, &LocalFont);
+ }
+
+ //
+ // Update the FontId of the specified string block
+ //
+ switch (BlockType) {
+ case EFI_HII_SIBT_STRING_SCSU_FONT:
+ case EFI_HII_SIBT_STRINGS_SCSU_FONT:
+ case EFI_HII_SIBT_STRING_UCS2_FONT:
+ case EFI_HII_SIBT_STRINGS_UCS2_FONT:
+ *(StringBlockAddr + sizeof (EFI_HII_STRING_BLOCK)) = LocalFont->FontId;
+ break;
+ default:
+ return EFI_NOT_FOUND;
+ }
+
+ }
+
+ OldBlockSize = StringPackage->StringPkgHdr->Header.Length - StringPackage->StringPkgHdr->HdrSize;
+
+ //
+ // Set the string text.
+ //
+ StringTextPtr = StringBlockAddr + StringTextOffset;
+ switch (BlockType) {
+ case EFI_HII_SIBT_STRING_SCSU:
+ case EFI_HII_SIBT_STRING_SCSU_FONT:
+ case EFI_HII_SIBT_STRINGS_SCSU:
+ case EFI_HII_SIBT_STRINGS_SCSU_FONT:
+ BlockSize = OldBlockSize + StrLen (String);
+ BlockSize -= AsciiStrLen ((CHAR8 *) StringTextPtr);
+ Block = AllocateZeroPool (BlockSize);
+ if (Block == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (Block, StringPackage->StringBlock, StringTextPtr - StringPackage->StringBlock);
+ BlockPtr = Block + (StringTextPtr - StringPackage->StringBlock);
+
+ while (*String != 0) {
+ *BlockPtr++ = (CHAR8) *String++;
+ }
+ *BlockPtr++ = 0;
+
+
+ TmpSize = OldBlockSize - (StringTextPtr - StringPackage->StringBlock) - AsciiStrSize ((CHAR8 *) StringTextPtr);
+ CopyMem (
+ BlockPtr,
+ StringTextPtr + AsciiStrSize ((CHAR8 *)StringTextPtr),
+ TmpSize
+ );
+
+ SafeFreePool (StringPackage->StringBlock);
+ StringPackage->StringBlock = Block;
+ StringPackage->StringPkgHdr->Header.Length += (UINT32) (BlockSize - OldBlockSize);
+ break;
+
+ case EFI_HII_SIBT_STRING_UCS2:
+ case EFI_HII_SIBT_STRING_UCS2_FONT:
+ case EFI_HII_SIBT_STRINGS_UCS2:
+ case EFI_HII_SIBT_STRINGS_UCS2_FONT:
+ //
+ // Use StrSize to store the size of the specified string, including the NULL
+ // terminator.
+ //
+ GetUnicodeStringTextOrSize (NULL, StringTextPtr, &StringSize);
+
+ BlockSize = OldBlockSize + StrSize (String) - StringSize;
+ Block = AllocateZeroPool (BlockSize);
+ if (Block == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (Block, StringPackage->StringBlock, StringTextPtr - StringPackage->StringBlock);
+ BlockPtr = Block + (StringTextPtr - StringPackage->StringBlock);
+
+ CopyMem (BlockPtr, String, StrSize (String));
+ BlockPtr += StrSize (String);
+
+ CopyMem (
+ BlockPtr,
+ StringTextPtr + StringSize,
+ OldBlockSize - (StringTextPtr - StringPackage->StringBlock) - StringSize
+ );
+
+ SafeFreePool (StringPackage->StringBlock);
+ StringPackage->StringBlock = Block;
+ StringPackage->StringPkgHdr->Header.Length += (UINT32) (BlockSize - OldBlockSize);
+ break;
+
+ default:
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Insert a new EFI_HII_SIBT_FONT_BLOCK to the header of string block, if incoming
+ // StringFontInfo does not exist in current string package.
+ //
+ // This new block does not impact on the value of StringId.
+ //
+ //
+ if (StringFontInfo == NULL || Referred) {
+ return EFI_SUCCESS;
+ }
+
+ OldBlockSize = StringPackage->StringPkgHdr->Header.Length - StringPackage->StringPkgHdr->HdrSize;
+ BlockSize = OldBlockSize + sizeof (EFI_HII_SIBT_FONT_BLOCK) - sizeof (CHAR16) +
+ StrSize (GlobalFont->FontInfo->FontName);
+
+ Block = AllocateZeroPool (BlockSize);
+ if (Block == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ BlockPtr = Block;
+ Ext2.Header.BlockType = EFI_HII_SIBT_EXT2;
+ Ext2.BlockType2 = EFI_HII_SIBT_FONT;
+ Ext2.Length = (UINT16) (BlockSize - OldBlockSize);
+ CopyMem (BlockPtr, &Ext2, sizeof (EFI_HII_SIBT_EXT2_BLOCK));
+ BlockPtr += sizeof (EFI_HII_SIBT_EXT2_BLOCK);
+
+ *BlockPtr = LocalFont->FontId;
+ BlockPtr += sizeof (UINT8);
+ CopyMem (BlockPtr, &GlobalFont->FontInfo->FontSize, sizeof (UINT16));
+ BlockPtr += sizeof (UINT16);
+ CopyMem (BlockPtr, &GlobalFont->FontInfo->FontStyle, sizeof (UINT32));
+ BlockPtr += sizeof (UINT32);
+ CopyMem (
+ BlockPtr,
+ GlobalFont->FontInfo->FontName,
+ StrSize (GlobalFont->FontInfo->FontName)
+ );
+ BlockPtr += StrSize (GlobalFont->FontInfo->FontName);
+
+ CopyMem (BlockPtr, StringPackage->StringBlock, OldBlockSize);
+
+ SafeFreePool (StringPackage->StringBlock);
+ StringPackage->StringBlock = Block;
+ StringPackage->StringPkgHdr->Header.Length += Ext2.Length;
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+ This function adds the string String to the group of strings owned by PackageList, with the
+ specified font information StringFontInfo and returns a new string id.
+
+ @param This A pointer to the EFI_HII_STRING_PROTOCOL instance.
+ @param PackageList Handle of the package list where this string will
+ be added.
+ @param StringId On return, contains the new strings id, which is
+ unique within PackageList.
+ @param Language Points to the language for the new string.
+ @param LanguageName Points to the printable language name to associate
+ with the passed in Language field.If LanguageName
+ is not NULL and the string package header's
+ LanguageName associated with a given Language is
+ not zero, the LanguageName being passed in will
+ be ignored.
+ @param String Points to the new null-terminated string.
+ @param StringFontInfo Points to the new string¡¯s font information or
+ NULL if the string should have the default system
+ font, size and style.
+
+ @retval EFI_SUCCESS The new string was added successfully.
+ @retval EFI_NOT_FOUND The specified PackageList could not be found in
+ database.
+ @retval EFI_OUT_OF_RESOURCES Could not add the string due to lack of resources.
+ @retval EFI_INVALID_PARAMETER String is NULL or StringId is NULL or Language is
+ NULL.
+ @retval EFI_INVALID_PARAMETER The specified StringFontInfo does not exist in
+ current database.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiNewString (
+ IN CONST EFI_HII_STRING_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ OUT EFI_STRING_ID *StringId,
+ IN CONST CHAR8 *Language,
+ IN CONST CHAR16 *LanguageName, OPTIONAL
+ IN CONST EFI_STRING String,
+ IN CONST EFI_FONT_INFO *StringFontInfo OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ BOOLEAN Matched;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ HII_DATABASE_RECORD *DatabaseRecord;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
+ HII_STRING_PACKAGE_INSTANCE *StringPackage;
+ UINT32 HeaderSize;
+ UINT32 BlockSize;
+ UINT32 OldBlockSize;
+ UINT8 *StringBlock;
+ UINT8 *BlockPtr;
+ UINT32 Ucs2BlockSize;
+ UINT32 FontBlockSize;
+ UINT32 Ucs2FontBlockSize;
+ EFI_HII_SIBT_EXT2_BLOCK Ext2;
+ HII_FONT_INFO *LocalFont;
+ HII_GLOBAL_FONT_INFO *GlobalFont;
+
+ if (This == NULL || String == NULL || StringId == NULL || Language == NULL || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!IsHiiHandleValid (PackageList)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Private = HII_STRING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ GlobalFont = NULL;
+
+ //
+ // If StringFontInfo specify a paritcular font, it should exist in current database.
+ //
+ if (StringFontInfo != NULL) {
+ if (!IsFontInfoExisted (Private, (EFI_FONT_INFO *) StringFontInfo, NULL, NULL, &GlobalFont)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // Get the matching package list.
+ //
+ PackageListNode = NULL;
+ for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
+ DatabaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ if (DatabaseRecord->Handle == PackageList) {
+ PackageListNode = DatabaseRecord->PackageList;
+ break;
+ }
+ }
+ if (PackageListNode == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Try to get the matching string package. Create a new string package when failed.
+ //
+ StringPackage = NULL;
+ Matched = FALSE;
+ for (Link = PackageListNode->StringPkgHdr.ForwardLink;
+ Link != &PackageListNode->StringPkgHdr;
+ Link = Link->ForwardLink
+ ) {
+ StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
+ if (R8_EfiLibCompareLanguage (StringPackage->StringPkgHdr->Language, (CHAR8 *) Language)) {
+ Matched = TRUE;
+ break;
+ }
+ }
+
+ if (!Matched) {
+ //
+ // LanguageName is required to create a new string package.
+ //
+ if (LanguageName == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ StringPackage = AllocateZeroPool (sizeof (HII_STRING_PACKAGE_INSTANCE));
+ if (StringPackage == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ StringPackage->Signature = HII_STRING_PACKAGE_SIGNATURE;
+ StringPackage->FontId = 0;
+ InitializeListHead (&StringPackage->FontInfoList);
+
+ //
+ // Fill in the string package header
+ //
+ HeaderSize = (UINT32) (AsciiStrSize ((CHAR8 *) Language) - 1 + sizeof (EFI_HII_STRING_PACKAGE_HDR));
+ StringPackage->StringPkgHdr = AllocateZeroPool (HeaderSize);
+ if (StringPackage->StringPkgHdr == NULL) {
+ SafeFreePool (StringPackage);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ StringPackage->StringPkgHdr->Header.Type = EFI_HII_PACKAGE_STRINGS;
+ StringPackage->StringPkgHdr->HdrSize = HeaderSize;
+ StringPackage->StringPkgHdr->StringInfoOffset = HeaderSize;
+ CopyMem (StringPackage->StringPkgHdr->LanguageWindow, mLanguageWindow, 16 * sizeof (CHAR16));;
+ StringPackage->StringPkgHdr->LanguageName = 1;
+ AsciiStrCpy (StringPackage->StringPkgHdr->Language, (CHAR8 *) Language);
+
+ //
+ // Calculate the length of the string blocks, including string block to record
+ // printable language full name and EFI_HII_SIBT_END_BLOCK.
+ //
+ Ucs2BlockSize = (UINT32) (StrSize ((CHAR16 *) LanguageName) +
+ sizeof (EFI_HII_SIBT_STRING_UCS2_BLOCK) - sizeof (CHAR16));
+
+ BlockSize = Ucs2BlockSize + sizeof (EFI_HII_SIBT_END_BLOCK);
+ StringPackage->StringBlock = (UINT8 *) AllocateZeroPool (BlockSize);
+ if (StringPackage->StringBlock == NULL) {
+ SafeFreePool (StringPackage->StringPkgHdr);
+ SafeFreePool (StringPackage);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Insert the string block of printable language full name
+ //
+ BlockPtr = StringPackage->StringBlock;
+ *BlockPtr = EFI_HII_SIBT_STRING_UCS2;
+ BlockPtr += sizeof (EFI_HII_STRING_BLOCK);
+ CopyMem (BlockPtr, (EFI_STRING) LanguageName, StrSize ((EFI_STRING) LanguageName));
+ BlockPtr += StrSize ((EFI_STRING) LanguageName);
+
+ //
+ // Insert the end block
+ //
+ *BlockPtr = EFI_HII_SIBT_END;
+
+ //
+ // Append this string package node to string package array in this package list.
+ //
+ StringPackage->StringPkgHdr->Header.Length = HeaderSize + BlockSize;
+ PackageListNode->PackageListHdr.PackageLength += StringPackage->StringPkgHdr->Header.Length;
+ InsertTailList (&PackageListNode->StringPkgHdr, &StringPackage->StringEntry);
+
+ }
+
+ //
+ // Create a string block and corresponding font block if exists, then append them
+ // to the end of the string package.
+ //
+ Status = FindStringBlock (
+ Private,
+ StringPackage,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ StringId
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ OldBlockSize = StringPackage->StringPkgHdr->Header.Length - StringPackage->StringPkgHdr->HdrSize;
+
+ if (StringFontInfo == NULL) {
+ //
+ // Create a EFI_HII_SIBT_STRING_UCS2_BLOCK since font info is not specified.
+ //
+
+ Ucs2BlockSize = (UINT32) (StrSize (String) + sizeof (EFI_HII_SIBT_STRING_UCS2_BLOCK)
+ - sizeof (CHAR16));
+
+ StringBlock = (UINT8 *) AllocateZeroPool (OldBlockSize + Ucs2BlockSize);
+ if (StringBlock == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Copy original string blocks, except the EFI_HII_SIBT_END.
+ //
+ CopyMem (StringBlock, StringPackage->StringBlock, OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK));
+ //
+ // Create a EFI_HII_SIBT_STRING_UCS2 block
+ //
+ BlockPtr = StringBlock + OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK);
+ *BlockPtr = EFI_HII_SIBT_STRING_UCS2;
+ BlockPtr += sizeof (EFI_HII_STRING_BLOCK);
+ CopyMem (BlockPtr, (EFI_STRING) String, StrSize ((EFI_STRING) String));
+ BlockPtr += StrSize ((EFI_STRING) String);
+
+ //
+ // Append a EFI_HII_SIBT_END block to the end.
+ //
+ *BlockPtr = EFI_HII_SIBT_END;
+ SafeFreePool (StringPackage->StringBlock);
+ StringPackage->StringBlock = StringBlock;
+ StringPackage->StringPkgHdr->Header.Length += Ucs2BlockSize;
+ PackageListNode->PackageListHdr.PackageLength += Ucs2BlockSize;
+
+ } else {
+ //
+ // StringFontInfo is specified here. If there is a EFI_HII_SIBT_FONT_BLOCK
+ // which refers to this font info, create a EFI_HII_SIBT_STRING_UCS2_FONT block
+ // only. Otherwise create a EFI_HII_SIBT_FONT block with a EFI_HII_SIBT_STRING
+ // _UCS2_FONT block.
+ //
+ Ucs2FontBlockSize = (UINT32) (StrSize (String) + sizeof (EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK) -
+ sizeof (CHAR16));
+ if (ReferFontInfoLocally (Private, StringPackage, FALSE, GlobalFont, &LocalFont)) {
+ //
+ // Create a EFI_HII_SIBT_STRING_UCS2_FONT block only.
+ //
+ StringBlock = (UINT8 *) AllocateZeroPool (OldBlockSize + Ucs2FontBlockSize);
+ if (StringBlock == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Copy original string blocks, except the EFI_HII_SIBT_END.
+ //
+ CopyMem (StringBlock, StringPackage->StringBlock, OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK));
+ //
+ // Create a EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK
+ //
+ BlockPtr = StringBlock + OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK);
+ *BlockPtr = EFI_HII_SIBT_STRING_UCS2_FONT;
+ BlockPtr += sizeof (EFI_HII_STRING_BLOCK);
+ *BlockPtr = LocalFont->FontId;
+ BlockPtr += sizeof (UINT8);
+ CopyMem (BlockPtr, (EFI_STRING) String, StrSize ((EFI_STRING) String));
+ BlockPtr += StrSize ((EFI_STRING) String);
+
+ //
+ // Append a EFI_HII_SIBT_END block to the end.
+ //
+ *BlockPtr = EFI_HII_SIBT_END;
+ SafeFreePool (StringPackage->StringBlock);
+ StringPackage->StringBlock = StringBlock;
+ StringPackage->StringPkgHdr->Header.Length += Ucs2FontBlockSize;
+ PackageListNode->PackageListHdr.PackageLength += Ucs2FontBlockSize;
+
+ } else {
+ //
+ // EFI_HII_SIBT_FONT_BLOCK does not exist in current string package, so
+ // create a EFI_HII_SIBT_FONT block to record the font info, then generate
+ // a EFI_HII_SIBT_STRING_UCS2_FONT block to record the incoming string.
+ //
+ FontBlockSize = (UINT32) (StrSize (((EFI_FONT_INFO *) StringFontInfo)->FontName) +
+ sizeof (EFI_HII_SIBT_FONT_BLOCK) - sizeof (CHAR16));
+ StringBlock = (UINT8 *) AllocateZeroPool (OldBlockSize + FontBlockSize + Ucs2FontBlockSize);
+ if (StringBlock == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Copy original string blocks, except the EFI_HII_SIBT_END.
+ //
+ CopyMem (StringBlock, StringPackage->StringBlock, OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK));
+
+ //
+ // Create a EFI_HII_SIBT_FONT block firstly and then backup its info in string
+ // package instance for future reference.
+ //
+ BlockPtr = StringBlock + OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK);
+
+ Ext2.Header.BlockType = EFI_HII_SIBT_EXT2;
+ Ext2.BlockType2 = EFI_HII_SIBT_FONT;
+ Ext2.Length = (UINT16) FontBlockSize;
+ CopyMem (BlockPtr, &Ext2, sizeof (EFI_HII_SIBT_EXT2_BLOCK));
+ BlockPtr += sizeof (EFI_HII_SIBT_EXT2_BLOCK);
+
+ *BlockPtr = LocalFont->FontId;
+ BlockPtr += sizeof (UINT8);
+ CopyMem (BlockPtr, &((EFI_FONT_INFO *) StringFontInfo)->FontSize, sizeof (UINT16));
+ BlockPtr += sizeof (UINT16);
+ CopyMem (BlockPtr, &((EFI_FONT_INFO *) StringFontInfo)->FontStyle, sizeof (EFI_HII_FONT_STYLE));
+ BlockPtr += sizeof (EFI_HII_FONT_STYLE);
+ CopyMem (
+ BlockPtr,
+ &((EFI_FONT_INFO *) StringFontInfo)->FontName,
+ StrSize (((EFI_FONT_INFO *) StringFontInfo)->FontName)
+ );
+
+ //
+ // Create a EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK
+ //
+ *BlockPtr = EFI_HII_SIBT_STRING_UCS2_FONT;
+ BlockPtr += sizeof (EFI_HII_STRING_BLOCK);
+ *BlockPtr = LocalFont->FontId;
+ BlockPtr += sizeof (UINT8);
+ CopyMem (BlockPtr, (EFI_STRING) String, StrSize ((EFI_STRING) String));
+ BlockPtr += StrSize ((EFI_STRING) String);
+
+ //
+ // Append a EFI_HII_SIBT_END block to the end.
+ //
+ *BlockPtr = EFI_HII_SIBT_END;
+ SafeFreePool (StringPackage->StringBlock);
+ StringPackage->StringBlock = StringBlock;
+ StringPackage->StringPkgHdr->Header.Length += FontBlockSize + Ucs2FontBlockSize;
+ PackageListNode->PackageListHdr.PackageLength += FontBlockSize + Ucs2FontBlockSize;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function retrieves the string specified by StringId which is associated
+ with the specified PackageList in the language Language and copies it into
+ the buffer specified by String.
+
+ @param This A pointer to the EFI_HII_STRING_PROTOCOL instance.
+ @param Language Points to the language for the retrieved string.
+ @param PackageList The package list in the HII database to search for
+ the specified string.
+ @param StringId The string's id, which is unique within
+ PackageList.
+ @param String Points to the new null-terminated string.
+ @param StringSize On entry, points to the size of the buffer pointed
+ to by String, in bytes. On return, points to the
+ length of the string, in bytes.
+ @param StringFontInfo If not NULL, points to the string¡¯s font
+ information. It's caller's responsibility to free
+ this buffer.
+
+ @retval EFI_SUCCESS The string was returned successfully.
+ @retval EFI_NOT_FOUND The string specified by StringId is not available.
+ @retval EFI_NOT_FOUND The string specified by StringId is available but
+ not in the specified language.
+ @retval EFI_BUFFER_TOO_SMALL The buffer specified by StringSize is too small to
+ hold the string.
+ @retval EFI_INVALID_PARAMETER The String or Language or StringSize was NULL.
+ @retval EFI_OUT_OF_RESOURCES There were insufficient resources to complete the
+ request.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetString (
+ IN CONST EFI_HII_STRING_PROTOCOL *This,
+ IN CONST CHAR8 *Language,
+ IN EFI_HII_HANDLE PackageList,
+ IN EFI_STRING_ID StringId,
+ OUT EFI_STRING String,
+ IN OUT UINTN *StringSize,
+ OUT EFI_FONT_INFO **StringFontInfo OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ HII_DATABASE_RECORD *DatabaseRecord;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
+ HII_STRING_PACKAGE_INSTANCE *StringPackage;
+
+ if (This == NULL || Language == NULL || StringId < 1 || StringSize == NULL || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (String == NULL && *StringSize != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!IsHiiHandleValid (PackageList)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Private = HII_STRING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ PackageListNode = NULL;
+
+ for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
+ DatabaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ if (DatabaseRecord->Handle == PackageList) {
+ PackageListNode = DatabaseRecord->PackageList;
+ break;
+ }
+ }
+
+ if (PackageListNode != NULL) {
+ for (Link = PackageListNode->StringPkgHdr.ForwardLink;
+ Link != &PackageListNode->StringPkgHdr;
+ Link = Link->ForwardLink
+ ) {
+ StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
+ if (R8_EfiLibCompareLanguage (StringPackage->StringPkgHdr->Language, (CHAR8 *) Language)) {
+ Status = GetStringWorker (Private, StringPackage, StringId, String, StringSize, StringFontInfo);
+ if (Status != EFI_NOT_FOUND) {
+ return Status;
+ }
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+
+/**
+ This function updates the string specified by StringId in the specified PackageList to the text
+ specified by String and, optionally, the font information specified by StringFontInfo.
+
+ @param This A pointer to the EFI_HII_STRING_PROTOCOL instance.
+ @param PackageList The package list containing the strings.
+ @param StringId The string¡¯s id, which is unique within
+ PackageList.
+ @param Language Points to the language for the updated string.
+ @param String Points to the new null-terminated string.
+ @param StringFontInfo Points to the string¡¯s font information or NULL if
+ the string font information is not changed.
+
+ @retval EFI_SUCCESS The string was updated successfully.
+ @retval EFI_NOT_FOUND The string specified by StringId is not in the
+ database.
+ @retval EFI_INVALID_PARAMETER The String or Language was NULL.
+ @retval EFI_INVALID_PARAMETER The specified StringFontInfo does not exist in
+ current database.
+ @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the
+ task.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiSetString (
+ IN CONST EFI_HII_STRING_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ IN EFI_STRING_ID StringId,
+ IN CONST CHAR8 *Language,
+ IN CONST EFI_STRING String,
+ IN CONST EFI_FONT_INFO *StringFontInfo OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ HII_DATABASE_RECORD *DatabaseRecord;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
+ HII_STRING_PACKAGE_INSTANCE *StringPackage;
+ UINT32 OldPackageLen;
+
+ if (This == NULL || Language == NULL || StringId < 1 || String == NULL || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!IsHiiHandleValid (PackageList)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Private = HII_STRING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ PackageListNode = NULL;
+
+ for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
+ DatabaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ if (DatabaseRecord->Handle == PackageList) {
+ PackageListNode = (HII_DATABASE_PACKAGE_LIST_INSTANCE *) (DatabaseRecord->PackageList);
+ }
+ }
+
+ if (PackageListNode != NULL) {
+ for (Link = PackageListNode->StringPkgHdr.ForwardLink;
+ Link != &PackageListNode->StringPkgHdr;
+ Link = Link->ForwardLink
+ ) {
+ StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
+ if (R8_EfiLibCompareLanguage (StringPackage->StringPkgHdr->Language, (CHAR8 *) Language)) {
+ OldPackageLen = StringPackage->StringPkgHdr->Header.Length;
+ Status = SetStringWorker (
+ Private,
+ StringPackage,
+ StringId,
+ (EFI_STRING) String,
+ (EFI_FONT_INFO *) StringFontInfo
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ PackageListNode->PackageListHdr.PackageLength += StringPackage->StringPkgHdr->Header.Length - OldPackageLen;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+
+/**
+ This function returns the list of supported languages, in the format specified
+ in Appendix M of UEFI 2.1 spec.
+
+ @param This A pointer to the EFI_HII_STRING_PROTOCOL instance.
+ @param PackageList The package list to examine.
+ @param Languages Points to the buffer to hold the returned string.
+ @param LanguagesSize On entry, points to the size of the buffer pointed
+ to by Languages, in bytes. On return, points to
+ the length of Languages, in bytes.
+
+ @retval EFI_SUCCESS The languages were returned successfully.
+ @retval EFI_INVALID_PARAMETER The Languages or LanguagesSize was NULL.
+ @retval EFI_BUFFER_TOO_SMALL The LanguagesSize is too small to hold the list of
+ supported languages. LanguageSize is updated to
+ contain the required size.
+ @retval EFI_NOT_FOUND Could not find string package in specified
+ packagelist.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetLanguages (
+ IN CONST EFI_HII_STRING_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ IN OUT CHAR8 *Languages,
+ IN OUT UINTN *LanguagesSize
+ )
+{
+ LIST_ENTRY *Link;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ HII_DATABASE_RECORD *DatabaseRecord;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
+ HII_STRING_PACKAGE_INSTANCE *StringPackage;
+ UINTN ResultSize;
+
+ if (This == NULL || Languages == NULL || LanguagesSize == NULL || PackageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (!IsHiiHandleValid (PackageList)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Private = HII_STRING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+
+ PackageListNode = NULL;
+ for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
+ DatabaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ if (DatabaseRecord->Handle == PackageList) {
+ PackageListNode = DatabaseRecord->PackageList;
+ break;
+ }
+ }
+ if (PackageListNode == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Search the languages in the specified packagelist.
+ //
+ ResultSize = 0;
+ for (Link = PackageListNode->StringPkgHdr.ForwardLink;
+ Link != &PackageListNode->StringPkgHdr;
+ Link = Link->ForwardLink
+ ) {
+ StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
+ ResultSize += AsciiStrSize (StringPackage->StringPkgHdr->Language);
+ if (ResultSize < *LanguagesSize) {
+ AsciiStrCpy (Languages, StringPackage->StringPkgHdr->Language);
+ Languages += AsciiStrSize (StringPackage->StringPkgHdr->Language);
+ *(Languages - 1) = L';';
+ }
+ }
+ if (ResultSize == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (*LanguagesSize < ResultSize) {
+ *LanguagesSize = ResultSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *(Languages - 1) = 0;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Each string package has associated with it a single primary language and zero
+ or more secondary languages. This routine returns the secondary languages
+ associated with a package list.
+
+ @param This A pointer to the EFI_HII_STRING_PROTOCOL instance.
+ @param PackageList The package list to examine.
+ @param FirstLanguage Points to the primary language.
+ @param SecondaryLanguages Points to the buffer to hold the returned list of
+ secondary languages for the specified
+ FirstLanguage. If there are no secondary
+ languages, the function returns successfully, but
+ this is set to NULL.
+ @param SecondaryLanguageSize On entry, points to the size of the buffer pointed
+ to by SecondLanguages, in bytes. On return,
+ points to the length of SecondLanguages in bytes.
+
+ @retval EFI_SUCCESS Secondary languages were correctly returned.
+ @retval EFI_INVALID_PARAMETER FirstLanguage or SecondLanguages or
+ SecondLanguagesSize was NULL.
+ @retval EFI_BUFFER_TOO_SMALL The buffer specified by SecondLanguagesSize is
+ too small to hold the returned information.
+ SecondLanguageSize is updated to hold the size of
+ the buffer required.
+ @retval EFI_NOT_FOUND The language specified by FirstLanguage is not
+ present in the specified package list.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiGetSecondaryLanguages (
+ IN CONST EFI_HII_STRING_PROTOCOL *This,
+ IN EFI_HII_HANDLE PackageList,
+ IN CONST CHAR8 *FirstLanguage,
+ IN OUT CHAR8 *SecondLanguages,
+ IN OUT UINTN *SecondLanguagesSize
+ )
+{
+ LIST_ENTRY *Link;
+ LIST_ENTRY *Link1;
+ HII_DATABASE_PRIVATE_DATA *Private;
+ HII_DATABASE_RECORD *DatabaseRecord;
+ HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
+ HII_STRING_PACKAGE_INSTANCE *StringPackage;
+ CHAR8 *Languages;
+ UINTN ResultSize;
+
+ if (This == NULL || PackageList == NULL || FirstLanguage == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (SecondLanguages == NULL || SecondLanguagesSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (!IsHiiHandleValid (PackageList)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Private = HII_STRING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
+ Languages = NULL;
+ ResultSize = 0;
+
+ for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) {
+ DatabaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
+ if (DatabaseRecord->Handle == PackageList) {
+ PackageListNode = (HII_DATABASE_PACKAGE_LIST_INSTANCE *) (DatabaseRecord->PackageList);
+ for (Link1 = PackageListNode->StringPkgHdr.ForwardLink;
+ Link1 != &PackageListNode->StringPkgHdr;
+ Link1 = Link1->ForwardLink
+ ) {
+ StringPackage = CR (Link1, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
+ if (R8_EfiLibCompareLanguage (StringPackage->StringPkgHdr->Language, (CHAR8 *) FirstLanguage)) {
+ Languages = StringPackage->StringPkgHdr->Language;
+ //
+ // Language is a series of ';' terminated strings, first one is primary
+ // language and following with other secondary languages or NULL if no
+ // secondary languages any more.
+ //
+ Languages = AsciiStrStr (Languages, ";");
+ if (Languages == NULL) {
+ break;
+ }
+ Languages++;
+
+ ResultSize = AsciiStrSize (Languages);
+ if (ResultSize <= *SecondLanguagesSize) {
+ AsciiStrCpy (SecondLanguages, Languages);
+ } else {
+ *SecondLanguagesSize = ResultSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Colors.h b/MdeModulePkg/Universal/SetupBrowserDxe/Colors.h new file mode 100644 index 0000000000..1b355ec5b6 --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Colors.h @@ -0,0 +1,55 @@ +/** @file + +Copyright (c) 2004, Intel Corporation +All rights reserved. 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. + +Module Name: + + Colors.h + +Abstract: + + +Revision History + + +**/ + +#ifndef _COLORS_H +#define _COLORS_H + +// +// Screen Color Settings +// +#define PICKLIST_HIGHLIGHT_TEXT EFI_WHITE +#define PICKLIST_HIGHLIGHT_BACKGROUND EFI_BACKGROUND_CYAN +#define TITLE_TEXT EFI_WHITE +#define TITLE_BACKGROUND EFI_BACKGROUND_BLUE +#define KEYHELP_TEXT EFI_LIGHTGRAY +#define KEYHELP_BACKGROUND EFI_BACKGROUND_BLACK +#define SUBTITLE_TEXT EFI_BLUE +#define SUBTITLE_BACKGROUND EFI_BACKGROUND_LIGHTGRAY +#define BANNER_TEXT EFI_BLUE +#define BANNER_BACKGROUND EFI_BACKGROUND_LIGHTGRAY +#define FIELD_TEXT EFI_BLACK +#define FIELD_TEXT_GRAYED EFI_DARKGRAY +#define FIELD_BACKGROUND EFI_BACKGROUND_LIGHTGRAY +#define FIELD_TEXT_HIGHLIGHT EFI_LIGHTGRAY +#define FIELD_BACKGROUND_HIGHLIGHT EFI_BACKGROUND_BLACK +#define POPUP_TEXT EFI_LIGHTGRAY +#define POPUP_BACKGROUND EFI_BACKGROUND_BLUE +#define POPUP_INVERSE_TEXT EFI_LIGHTGRAY +#define POPUP_INVERSE_BACKGROUND EFI_BACKGROUND_BLACK +#define HELP_TEXT EFI_BLUE +#define ERROR_TEXT EFI_RED | EFI_BRIGHT +#define INFO_TEXT EFI_YELLOW | EFI_BRIGHT +#define ARROW_TEXT EFI_RED | EFI_BRIGHT +#define ARROW_BACKGROUND EFI_BACKGROUND_LIGHTGRAY + +#endif diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c b/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c new file mode 100644 index 0000000000..adeada2b29 --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c @@ -0,0 +1,1938 @@ +/** @file + +Copyright (c) 2007, Intel Corporation +All rights reserved. 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. + +Module Name: + + Expression.c + +Abstract: + + Expression evaluation. + + +**/ + +#include "Ui.h" +#include "Setup.h" + +// +// Global stack used to evaluate boolean expresions +// +EFI_HII_VALUE *mOpCodeScopeStack = NULL; +EFI_HII_VALUE *mOpCodeScopeStackEnd = NULL; +EFI_HII_VALUE *mOpCodeScopeStackPointer = NULL; + +EFI_HII_VALUE *mExpressionEvaluationStack = NULL; +EFI_HII_VALUE *mExpressionEvaluationStackEnd = NULL; +EFI_HII_VALUE *mExpressionEvaluationStackPointer = NULL; + +// +// Unicode collation protocol interface +// +EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL; + + +/** + Grow size of the stack + + @param Stack On input: old stack; On output: new stack + @param StackPtr On input: old stack pointer; On output: new stack + pointer + @param StackPtr On input: old stack end; On output: new stack end + + @retval EFI_SUCCESS Grow stack success. + @retval EFI_OUT_OF_RESOURCES No enough memory for stack space. + +**/ +STATIC +EFI_STATUS +GrowStack ( + IN OUT EFI_HII_VALUE **Stack, + IN OUT EFI_HII_VALUE **StackPtr, + IN OUT EFI_HII_VALUE **StackEnd + ) +{ + UINTN Size; + EFI_HII_VALUE *NewStack; + + Size = EXPRESSION_STACK_SIZE_INCREMENT; + if (*StackPtr != NULL) { + Size = Size + (*StackEnd - *Stack); + } + + NewStack = AllocatePool (Size * sizeof (EFI_HII_VALUE)); + if (NewStack == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (*StackPtr != NULL) { + // + // Copy from Old Stack to the New Stack + // + CopyMem ( + NewStack, + *Stack, + (*StackEnd - *Stack) * sizeof (EFI_HII_VALUE) + ); + + // + // Free The Old Stack + // + gBS->FreePool (*Stack); + } + + // + // Make the Stack pointer point to the old data in the new stack + // + *StackPtr = NewStack + (*StackPtr - *Stack); + *Stack = NewStack; + *StackEnd = NewStack + Size; + + return EFI_SUCCESS; +} + + +/** + Push an element onto the Boolean Stack + + @param Stack On input: old stack; On output: new stack + @param StackPtr On input: old stack pointer; On output: new stack + pointer + @param StackPtr On input: old stack end; On output: new stack end + @param Data Data to push. + + @retval EFI_SUCCESS Push stack success. + +**/ +EFI_STATUS +PushStack ( + IN OUT EFI_HII_VALUE **Stack, + IN OUT EFI_HII_VALUE **StackPtr, + IN OUT EFI_HII_VALUE **StackEnd, + IN EFI_HII_VALUE *Data + ) +{ + EFI_STATUS Status; + + // + // Check for a stack overflow condition + // + if (*StackPtr >= *StackEnd) { + // + // Grow the stack + // + Status = GrowStack (Stack, StackPtr, StackEnd); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Push the item onto the stack + // + CopyMem (*StackPtr, Data, sizeof (EFI_HII_VALUE)); + *StackPtr = *StackPtr + 1; + + return EFI_SUCCESS; +} + + +/** + Pop an element from the stack. + + @param Stack On input: old stack; On output: new stack + @param StackPtr On input: old stack pointer; On output: new stack + pointer + @param StackPtr On input: old stack end; On output: new stack end + @param Data Data to pop. + + @retval EFI_SUCCESS The value was popped onto the stack. + @retval EFI_ACCESS_DENIED The pop operation underflowed the stack + +**/ +EFI_STATUS +PopStack ( + IN OUT EFI_HII_VALUE **Stack, + IN OUT EFI_HII_VALUE **StackPtr, + IN OUT EFI_HII_VALUE **StackEnd, + OUT EFI_HII_VALUE *Data + ) +{ + // + // Check for a stack underflow condition + // + if (*StackPtr == *Stack) { + return EFI_ACCESS_DENIED; + } + + // + // Pop the item off the stack + // + *StackPtr = *StackPtr - 1; + CopyMem (Data, *StackPtr, sizeof (EFI_HII_VALUE)); + return EFI_SUCCESS; +} + + +/** + Reset stack pointer to begin of the stack. + + None. + + @return None. + +**/ +VOID +ResetScopeStack ( + VOID + ) +{ + mOpCodeScopeStackPointer = mOpCodeScopeStack; +} + + +/** + Push an Operand onto the Stack + + @param Operand Operand to push. + + @retval EFI_SUCCESS The value was pushed onto the stack. + @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the + stack. + +**/ +EFI_STATUS +PushScope ( + IN UINT8 Operand + ) +{ + EFI_HII_VALUE Data; + + Data.Type = EFI_IFR_TYPE_NUM_SIZE_8; + Data.Value.u8 = Operand; + + return PushStack ( + &mOpCodeScopeStack, + &mOpCodeScopeStackPointer, + &mOpCodeScopeStackEnd, + &Data + ); +} + + +/** + Pop an Operand from the Stack + + @param Operand Operand to pop. + + @retval EFI_SUCCESS The value was pushed onto the stack. + @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the + stack. + +**/ +EFI_STATUS +PopScope ( + OUT UINT8 *Operand + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Data; + + Status = PopStack ( + &mOpCodeScopeStack, + &mOpCodeScopeStackPointer, + &mOpCodeScopeStackEnd, + &Data + ); + + *Operand = Data.Value.u8; + + return Status; +} + + +/** + Reset stack pointer to begin of the stack. + + None. + + @return None. + +**/ +VOID +ResetExpressionStack ( + VOID + ) +{ + mExpressionEvaluationStackPointer = mExpressionEvaluationStack; +} + + +/** + Push an Expression value onto the Stack + + @param Value Expression value to push. + + @retval EFI_SUCCESS The value was pushed onto the stack. + @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the + stack. + +**/ +EFI_STATUS +PushExpression ( + IN EFI_HII_VALUE *Value + ) +{ + return PushStack ( + &mExpressionEvaluationStack, + &mExpressionEvaluationStackPointer, + &mExpressionEvaluationStackEnd, + Value + ); +} + + +/** + Pop an Expression value from the stack. + + @param Value Expression value to pop. + + @retval EFI_SUCCESS The value was popped onto the stack. + @retval EFI_ACCESS_DENIED The pop operation underflowed the stack + +**/ +EFI_STATUS +PopExpression ( + OUT EFI_HII_VALUE *Value + ) +{ + return PopStack ( + &mExpressionEvaluationStack, + &mExpressionEvaluationStackPointer, + &mExpressionEvaluationStackEnd, + Value + ); +} + + +/** + Get Form given its FormId. + + @param FormSet The formset which contains this form. + @param FormId Id of this form. + + @retval Pointer The form. + @retval NULL Specified Form is not found in the formset. + +**/ +FORM_BROWSER_FORM * +IdToForm ( + IN FORM_BROWSER_FORMSET *FormSet, + IN UINT16 FormId +) +{ + LIST_ENTRY *Link; + FORM_BROWSER_FORM *Form; + + Link = GetFirstNode (&FormSet->FormListHead); + while (!IsNull (&FormSet->FormListHead, Link)) { + Form = FORM_BROWSER_FORM_FROM_LINK (Link); + + if (Form->FormId == FormId) { + return Form; + } + + Link = GetNextNode (&FormSet->FormListHead, Link); + } + + return NULL; +} + + +/** + Search a Question in Form scope using its QuestionId. + + @param Form The form which contains this Question. + @param QuestionId Id of this Question. + + @retval Pointer The Question. + @retval NULL Specified Question not found in the form. + +**/ +FORM_BROWSER_STATEMENT * +IdToQuestion2 ( + IN FORM_BROWSER_FORM *Form, + IN UINT16 QuestionId + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Question; + + if (QuestionId == 0) { + // + // The value of zero is reserved + // + return NULL; + } + + Link = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, Link)) { + Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + + if (Question->QuestionId == QuestionId) { + return Question; + } + + Link = GetNextNode (&Form->StatementListHead, Link); + } + + return NULL; +} + + +/** + Search a Question in Formset scope using its QuestionId. + + @param FormSet The formset which contains this form. + @param Form The form which contains this Question. + @param QuestionId Id of this Question. + + @retval Pointer The Question. + @retval NULL Specified Question not found in the form. + +**/ +FORM_BROWSER_STATEMENT * +IdToQuestion ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN UINT16 QuestionId + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Question; + + // + // Search in the form scope first + // + Question = IdToQuestion2 (Form, QuestionId); + if (Question != NULL) { + return Question; + } + + // + // Search in the formset scope + // + Link = GetFirstNode (&FormSet->FormListHead); + while (!IsNull (&FormSet->FormListHead, Link)) { + Form = FORM_BROWSER_FORM_FROM_LINK (Link); + + Question = IdToQuestion2 (Form, QuestionId); + if (Question != NULL) { + return Question; + } + + Link = GetNextNode (&FormSet->FormListHead, Link); + } + + return NULL; +} + + +/** + Get Expression given its RuleId. + + @param Form The form which contains this Expression. + @param RuleId Id of this Expression. + + @retval Pointer The Expression. + @retval NULL Specified Expression not found in the form. + +**/ +FORM_EXPRESSION * +RuleIdToExpression ( + IN FORM_BROWSER_FORM *Form, + IN UINT8 RuleId + ) +{ + LIST_ENTRY *Link; + FORM_EXPRESSION *Expression; + + Link = GetFirstNode (&Form->ExpressionListHead); + while (!IsNull (&Form->ExpressionListHead, Link)) { + Expression = FORM_EXPRESSION_FROM_LINK (Link); + + if (Expression->Type == EFI_HII_EXPRESSION_RULE && Expression->RuleId == RuleId) { + return Expression; + } + + Link = GetNextNode (&Form->ExpressionListHead, Link); + } + + return NULL; +} + + +/** + Locate the Unicode Collation Protocol interface for later use. + + None. + + @retval EFI_SUCCESS Protocol interface initialize success. + @retval Other Protocol interface initialize failed. + +**/ +EFI_STATUS +InitializeUnicodeCollationProtocol ( + VOID + ) +{ + EFI_STATUS Status; + + if (mUnicodeCollation != NULL) { + return EFI_SUCCESS; + } + + // + // BUGBUG: Proper impelmentation is to locate all Unicode Collation Protocol + // instances first and then select one which support English language. + // Current implementation just pick the first instance. + // + Status = gBS->LocateProtocol ( + &gEfiUnicodeCollation2ProtocolGuid, + NULL, + (VOID **) &mUnicodeCollation + ); + return Status; +} + +VOID +IfrStrToUpper ( + CHAR16 *String + ) +{ + while (*String != 0) { + if ((*String >= 'a') && (*String <= 'z')) { + *String = (UINT16) ((*String) & ((UINT16) ~0x20)); + } + String++; + } +} + + +/** + Evaluate opcode EFI_IFR_TO_STRING. + + @param FormSet Formset which contains this opcode. + @param Format String format in EFI_IFR_TO_STRING. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrToString ( + IN FORM_BROWSER_FORMSET *FormSet, + IN UINT8 Format, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value; + CHAR16 *String; + CHAR16 *PrintFormat; + CHAR16 Buffer[MAXIMUM_VALUE_CHARACTERS]; + UINTN BufferSize; + + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + + switch (Value.Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + case EFI_IFR_TYPE_NUM_SIZE_16: + case EFI_IFR_TYPE_NUM_SIZE_32: + case EFI_IFR_TYPE_NUM_SIZE_64: + BufferSize = MAXIMUM_VALUE_CHARACTERS * sizeof (CHAR16); + switch (Format) { + case EFI_IFR_STRING_UNSIGNED_DEC: + case EFI_IFR_STRING_SIGNED_DEC: + PrintFormat = L"%ld"; + break; + + case EFI_IFR_STRING_LOWERCASE_HEX: + PrintFormat = L"%lx"; + break; + + case EFI_IFR_STRING_UPPERCASE_HEX: + PrintFormat = L"%lX"; + break; + + default: + return EFI_UNSUPPORTED; + } + UnicodeSPrint (Buffer, BufferSize, PrintFormat, Value.Value.u64); + String = Buffer; + break; + + case EFI_IFR_TYPE_STRING: + CopyMem (Result, &Value, sizeof (EFI_HII_VALUE)); + return EFI_SUCCESS; + + case EFI_IFR_TYPE_BOOLEAN: + String = (Value.Value.b) ? L"True" : L"False"; + break; + + default: + return EFI_UNSUPPORTED; + } + + Result->Type = EFI_IFR_TYPE_STRING; + Result->Value.string = NewString (String, FormSet->HiiHandle); + return EFI_SUCCESS; +} + + +/** + Evaluate opcode EFI_IFR_TO_UINT. + + @param FormSet Formset which contains this opcode. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrToUint ( + IN FORM_BROWSER_FORMSET *FormSet, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value; + CHAR16 *String; + CHAR16 *StringPtr; + UINTN BufferSize; + + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Value.Type >= EFI_IFR_TYPE_OTHER) { + return EFI_UNSUPPORTED; + } + + Status = EFI_SUCCESS; + if (Value.Type == EFI_IFR_TYPE_STRING) { + String = GetToken (Value.Value.string, FormSet->HiiHandle); + if (String == NULL) { + return EFI_NOT_FOUND; + } + + IfrStrToUpper (String); + StringPtr = StrStr (String, L"0X"); + if (StringPtr != NULL) { + // + // Hex string + // + BufferSize = sizeof (UINT64); + Status = R8_HexStringToBuf ((UINT8 *) &Result->Value.u64, &BufferSize, StringPtr + 2, NULL); + } else { + // + // BUGBUG: Need handle decimal string + // + } + gBS->FreePool (String); + } else { + CopyMem (Result, &Value, sizeof (EFI_HII_VALUE)); + } + + Result->Type = EFI_IFR_TYPE_NUM_SIZE_64; + return Status; +} + + +/** + Evaluate opcode EFI_IFR_CATENATE. + + @param FormSet Formset which contains this opcode. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrCatenate ( + IN FORM_BROWSER_FORMSET *FormSet, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value; + CHAR16 *String[2]; + UINTN Index; + CHAR16 *StringPtr; + UINTN Size; + + // + // String[0] - The second string + // String[1] - The first string + // + String[0] = NULL; + String[1] = NULL; + StringPtr = NULL; + Status = EFI_SUCCESS; + + for (Index = 0; Index < 2; Index++) { + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Value.Type != EFI_IFR_TYPE_STRING) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle); + if (String== NULL) { + Status = EFI_NOT_FOUND; + goto Done; + } + } + + Size = StrSize (String[0]); + StringPtr= AllocatePool (StrSize (String[1]) + Size); + ASSERT (StringPtr != NULL); + StrCpy (StringPtr, String[1]); + StrCat (StringPtr, String[0]); + + Result->Type = EFI_IFR_TYPE_STRING; + Result->Value.string = NewString (StringPtr, FormSet->HiiHandle); + +Done: + SafeFreePool (String[0]); + SafeFreePool (String[1]); + SafeFreePool (StringPtr); + + return Status; +} + + +/** + Evaluate opcode EFI_IFR_MATCH. + + @param FormSet Formset which contains this opcode. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrMatch ( + IN FORM_BROWSER_FORMSET *FormSet, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value; + CHAR16 *String[2]; + UINTN Index; + + // + // String[0] - The string to search + // String[1] - pattern + // + String[0] = NULL; + String[1] = NULL; + Status = EFI_SUCCESS; + for (Index = 0; Index < 2; Index++) { + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Value.Type != EFI_IFR_TYPE_STRING) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle); + if (String== NULL) { + Status = EFI_NOT_FOUND; + goto Done; + } + } + + Result->Type = EFI_IFR_TYPE_BOOLEAN; + Result->Value.b = mUnicodeCollation->MetaiMatch (mUnicodeCollation, String[0], String[1]); + +Done: + SafeFreePool (String[0]); + SafeFreePool (String[1]); + + return Status; +} + + +/** + Evaluate opcode EFI_IFR_FIND. + + @param FormSet Formset which contains this opcode. + @param Format Case sensitive or insensitive. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrFind ( + IN FORM_BROWSER_FORMSET *FormSet, + IN UINT8 Format, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value; + CHAR16 *String[2]; + UINTN Base; + CHAR16 *StringPtr; + UINTN Index; + + if (Format > EFI_IFR_FF_CASE_INSENSITIVE) { + return EFI_UNSUPPORTED; + } + + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) { + return EFI_UNSUPPORTED; + } + Base = (UINTN) Value.Value.u64; + + // + // String[0] - sub-string + // String[1] - The string to search + // + String[0] = NULL; + String[1] = NULL; + for (Index = 0; Index < 2; Index++) { + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Value.Type != EFI_IFR_TYPE_STRING) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle); + if (String== NULL) { + Status = EFI_NOT_FOUND; + goto Done; + } + + if (Format == EFI_IFR_FF_CASE_INSENSITIVE) { + // + // Case insensitive, convert both string to upper case + // + IfrStrToUpper (String[Index]); + } + } + + Result->Type = EFI_IFR_TYPE_NUM_SIZE_64; + if (Base >= StrLen (String[1])) { + Result->Value.u64 = 0xFFFFFFFFFFFFFFFF; + } else { + StringPtr = StrStr (String[1] + Base, String[0]); + Result->Value.u64 = (StringPtr == NULL) ? 0xFFFFFFFFFFFFFFFF : (StringPtr - String[1]); + } + +Done: + SafeFreePool (String[0]); + SafeFreePool (String[1]); + + return Status; +} + + +/** + Evaluate opcode EFI_IFR_MID. + + @param FormSet Formset which contains this opcode. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrMid ( + IN FORM_BROWSER_FORMSET *FormSet, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value; + CHAR16 *String; + UINTN Base; + UINTN Length; + CHAR16 *SubString; + + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) { + return EFI_UNSUPPORTED; + } + Length = (UINTN) Value.Value.u64; + + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) { + return EFI_UNSUPPORTED; + } + Base = (UINTN) Value.Value.u64; + + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + if (Value.Type != EFI_IFR_TYPE_STRING) { + return EFI_UNSUPPORTED; + } + String = GetToken (Value.Value.string, FormSet->HiiHandle); + if (String == NULL) { + return EFI_NOT_FOUND; + } + + if (Length == 0 || Base >= StrLen (String)) { + SubString = gEmptyString; + } else { + SubString = String + Base; + if ((Base + Length) < StrLen (String)) { + SubString[Length] = L'\0'; + } + } + + Result->Type = EFI_IFR_TYPE_STRING; + Result->Value.string = NewString (SubString, FormSet->HiiHandle); + + gBS->FreePool (String); + + return Status; +} + + +/** + Evaluate opcode EFI_IFR_TOKEN. + + @param FormSet Formset which contains this opcode. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrToken ( + IN FORM_BROWSER_FORMSET *FormSet, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value; + CHAR16 *String[2]; + UINTN Count; + CHAR16 *Delimiter; + CHAR16 *SubString; + CHAR16 *StringPtr; + UINTN Index; + + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) { + return EFI_UNSUPPORTED; + } + Count = (UINTN) Value.Value.u64; + + // + // String[0] - Delimiter + // String[1] - The string to search + // + String[0] = NULL; + String[1] = NULL; + for (Index = 0; Index < 2; Index++) { + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Value.Type != EFI_IFR_TYPE_STRING) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle); + if (String== NULL) { + Status = EFI_NOT_FOUND; + goto Done; + } + } + + Delimiter = String[0]; + SubString = String[1]; + while (Count > 0) { + SubString = StrStr (SubString, Delimiter); + if (SubString != NULL) { + // + // Skip over the delimiter + // + SubString = SubString + StrLen (Delimiter); + } else { + break; + } + Count--; + } + + if (SubString == NULL) { + // + // nth delimited sub-string not found, push an empty string + // + SubString = gEmptyString; + } else { + // + // Put a NULL terminator for nth delimited sub-string + // + StringPtr = StrStr (SubString, Delimiter); + if (StringPtr != NULL) { + *StringPtr = L'\0'; + } + } + + Result->Type = EFI_IFR_TYPE_STRING; + Result->Value.string = NewString (SubString, FormSet->HiiHandle); + +Done: + SafeFreePool (String[0]); + SafeFreePool (String[1]); + + return Status; +} + + +/** + Evaluate opcode EFI_IFR_SPAN. + + @param FormSet Formset which contains this opcode. + @param Flags FIRST_MATCHING or FIRST_NON_MATCHING. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrSpan ( + IN FORM_BROWSER_FORMSET *FormSet, + IN UINT8 Flags, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value; + CHAR16 *String[2]; + CHAR16 *Charset; + UINTN Base; + UINTN Index; + CHAR16 *StringPtr; + BOOLEAN Found; + + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) { + return EFI_UNSUPPORTED; + } + Base = (UINTN) Value.Value.u64; + + // + // String[0] - Charset + // String[1] - The string to search + // + String[0] = NULL; + String[1] = NULL; + for (Index = 0; Index < 2; Index++) { + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Value.Type != EFI_IFR_TYPE_STRING) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle); + if (String== NULL) { + Status = EFI_NOT_FOUND; + goto Done; + } + } + + if (Base >= StrLen (String[1])) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + Found = FALSE; + StringPtr = String[1] + Base; + Charset = String[0]; + while (*StringPtr != 0 && !Found) { + Index = 0; + while (Charset[Index] != 0) { + if (*StringPtr >= Charset[Index] && *StringPtr <= Charset[Index + 1]) { + if (Flags == EFI_IFR_FLAGS_FIRST_MATCHING) { + Found = TRUE; + break; + } + } else { + if (Flags == EFI_IFR_FLAGS_FIRST_NON_MATCHING) { + Found = TRUE; + break; + } + } + // + // Skip characters pair representing low-end of a range and high-end of a range + // + Index += 2; + } + + if (!Found) { + StringPtr++; + } + } + + Result->Type = EFI_IFR_TYPE_NUM_SIZE_64; + Result->Value.u64 = StringPtr - String[1]; + +Done: + SafeFreePool (String[0]); + SafeFreePool (String[1]); + + return Status; +} + + +/** + Zero extend integer/boolean/date/time to UINT64 for comparing. + + @param Value HII Value to be converted. + + @return None. + +**/ +VOID +ExtendValueToU64 ( + IN EFI_HII_VALUE *Value + ) +{ + UINT64 Temp; + + Temp = 0; + switch (Value->Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + Temp = Value->Value.u8; + break; + + case EFI_IFR_TYPE_NUM_SIZE_16: + Temp = Value->Value.u16; + break; + + case EFI_IFR_TYPE_NUM_SIZE_32: + Temp = Value->Value.u32; + break; + + case EFI_IFR_TYPE_BOOLEAN: + Temp = Value->Value.b; + break; + + case EFI_IFR_TYPE_TIME: + Temp = Value->Value.u32 & 0xffffff; + break; + + case EFI_IFR_TYPE_DATE: + Temp = Value->Value.u32; + break; + + default: + return; + } + + Value->Value.u64 = Temp; +} + + +/** + Compare two Hii value. + + @param Value1 Expression value to compare on left-hand + @param Value2 Expression value to compare on right-hand + @param HiiHandle Only required for string compare + + @retval EFI_INVALID_PARAMETER Could not perform comparation on two values + @retval 0 Two operators equeal + @retval 0 Value1 is greater than Value2 + @retval 0 Value1 is less than Value2 + +**/ +INTN +CompareHiiValue ( + IN EFI_HII_VALUE *Value1, + IN EFI_HII_VALUE *Value2, + IN EFI_HII_HANDLE HiiHandle OPTIONAL + ) +{ + INTN Result; + INT64 Temp64; + CHAR16 *Str1; + CHAR16 *Str2; + + if (Value1->Type >= EFI_IFR_TYPE_OTHER || Value2->Type >= EFI_IFR_TYPE_OTHER ) { + return EFI_INVALID_PARAMETER; + } + + if (Value1->Type == EFI_IFR_TYPE_STRING || Value2->Type == EFI_IFR_TYPE_STRING ) { + if (Value1->Type != Value2->Type) { + // + // Both Operator should be type of String + // + return EFI_INVALID_PARAMETER; + } + + if (Value1->Value.string == 0 || Value2->Value.string == 0) { + // + // StringId 0 is reserved + // + return EFI_INVALID_PARAMETER; + } + + if (Value1->Value.string == Value2->Value.string) { + return 0; + } + + Str1 = GetToken (Value1->Value.string, HiiHandle); + if (Str1 == NULL) { + // + // String not found + // + return EFI_INVALID_PARAMETER; + } + + Str2 = GetToken (Value2->Value.string, HiiHandle); + if (Str2 == NULL) { + gBS->FreePool (Str1); + return EFI_INVALID_PARAMETER; + } + + Result = StrCmp (Str1, Str2); + + gBS->FreePool (Str1); + gBS->FreePool (Str2); + + return Result; + } + + // + // Take remain types(integer, boolean, date/time) as integer + // + Temp64 = (INT64) (Value1->Value.u64 - Value2->Value.u64); + if (Temp64 > 0) { + Result = 1; + } else if (Temp64 < 0) { + Result = -1; + } else { + Result = 0; + } + + return Result; +} + + +/** + Evaluate the result of a HII expression + + @param FormSet FormSet associated with this expression. + @param Form Form associated with this expression. + @param Expression Expression to be evaluated. + + @retval EFI_SUCCESS The expression evaluated successfuly + @retval EFI_NOT_FOUND The Question which referenced by a QuestionId + could not be found. + @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the + stack. + @retval EFI_ACCESS_DENIED The pop operation underflowed the stack + @retval EFI_INVALID_PARAMETER Syntax error with the Expression + +**/ +EFI_STATUS +EvaluateExpression ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_EXPRESSION *Expression + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + EXPRESSION_OPCODE *OpCode; + FORM_BROWSER_STATEMENT *Question; + FORM_BROWSER_STATEMENT *Question2; + UINT16 Index; + EFI_HII_VALUE Data1; + EFI_HII_VALUE Data2; + EFI_HII_VALUE Data3; + FORM_EXPRESSION *RuleExpression; + EFI_HII_VALUE *Value; + INTN Result; + CHAR16 *StrPtr; + UINT32 TempValue; + + // + // Always reset the stack before evaluating an Expression + // + ResetExpressionStack (); + + Expression->Result.Type = EFI_IFR_TYPE_OTHER; + + Link = GetFirstNode (&Expression->OpCodeListHead); + while (!IsNull (&Expression->OpCodeListHead, Link)) { + OpCode = EXPRESSION_OPCODE_FROM_LINK (Link); + + Link = GetNextNode (&Expression->OpCodeListHead, Link); + + ZeroMem (&Data1, sizeof (EFI_HII_VALUE)); + ZeroMem (&Data2, sizeof (EFI_HII_VALUE)); + ZeroMem (&Data3, sizeof (EFI_HII_VALUE)); + + Value = &Data3; + Value->Type = EFI_IFR_TYPE_BOOLEAN; + Status = EFI_SUCCESS; + + switch (OpCode->Operand) { + // + // Built-in functions + // + case EFI_IFR_EQ_ID_VAL_OP: + Question = IdToQuestion (FormSet, Form, OpCode->QuestionId); + if (Question == NULL) { + return EFI_NOT_FOUND; + } + + Result = CompareHiiValue (&Question->HiiValue, &OpCode->Value, NULL); + if (Result == EFI_INVALID_PARAMETER) { + return EFI_INVALID_PARAMETER; + } + Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE); + break; + + case EFI_IFR_EQ_ID_ID_OP: + Question = IdToQuestion (FormSet, Form, OpCode->QuestionId); + if (Question == NULL) { + return EFI_NOT_FOUND; + } + + Question2 = IdToQuestion (FormSet, Form, OpCode->QuestionId2); + if (Question2 == NULL) { + return EFI_NOT_FOUND; + } + + Result = CompareHiiValue (&Question->HiiValue, &Question2->HiiValue, FormSet->HiiHandle); + if (Result == EFI_INVALID_PARAMETER) { + return EFI_INVALID_PARAMETER; + } + Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE); + break; + + case EFI_IFR_EQ_ID_LIST_OP: + Question = IdToQuestion (FormSet, Form, OpCode->QuestionId); + if (Question == NULL) { + return EFI_NOT_FOUND; + } + + Value->Value.b = FALSE; + for (Index =0; Index < OpCode->ListLength; Index++) { + if (Question->HiiValue.Value.u16 == OpCode->ValueList[Index]) { + Value->Value.b = TRUE; + break; + } + } + break; + + case EFI_IFR_DUP_OP: + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PushExpression (Value); + break; + + case EFI_IFR_QUESTION_REF1_OP: + case EFI_IFR_THIS_OP: + Question = IdToQuestion (FormSet, Form, OpCode->QuestionId); + if (Question == NULL) { + return EFI_NOT_FOUND; + } + + Value = &Question->HiiValue; + break; + + case EFI_IFR_QUESTION_REF3_OP: + if (OpCode->DevicePath == 0) { + // + // EFI_IFR_QUESTION_REF3 + // Pop an expression from the expression stack + // + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Validate the expression value + // + if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) { + return EFI_NOT_FOUND; + } + + Question = IdToQuestion (FormSet, Form, Value->Value.u16); + if (Question == NULL) { + return EFI_NOT_FOUND; + } + + // + // push the questions' value on to the expression stack + // + Value = &Question->HiiValue; + } else { + // + // BUGBUG: push 0 for EFI_IFR_QUESTION_REF3_2 and EFI_IFR_QUESTION_REF3_3, + // since it is impractical to evaluate the value of a Question in another + // Hii Package list. + // + ZeroMem (Value, sizeof (EFI_HII_VALUE)); + } + break; + + case EFI_IFR_RULE_REF_OP: + // + // Find expression for this rule + // + RuleExpression = RuleIdToExpression (Form, OpCode->RuleId); + if (RuleExpression == NULL) { + return EFI_NOT_FOUND; + } + + // + // Evaluate this rule expression + // + Status = EvaluateExpression (FormSet, Form, RuleExpression); + if (EFI_ERROR (Status)) { + return Status; + } + + Value = &RuleExpression->Result; + break; + + case EFI_IFR_STRING_REF1_OP: + Value->Type = EFI_IFR_TYPE_STRING; + Value->Value.string = OpCode->Value.Value.string; + break; + + // + // Constant + // + case EFI_IFR_TRUE_OP: + case EFI_IFR_FALSE_OP: + case EFI_IFR_ONE_OP: + case EFI_IFR_ONES_OP: + case EFI_IFR_UINT8_OP: + case EFI_IFR_UINT16_OP: + case EFI_IFR_UINT32_OP: + case EFI_IFR_UINT64_OP: + case EFI_IFR_UNDEFINED_OP: + case EFI_IFR_VERSION_OP: + case EFI_IFR_ZERO_OP: + Value = &OpCode->Value; + break; + + // + // unary-op + // + case EFI_IFR_LENGTH_OP: + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + return Status; + } + if (Value->Type != EFI_IFR_TYPE_STRING) { + return EFI_INVALID_PARAMETER; + } + + StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle); + if (StrPtr == NULL) { + return EFI_INVALID_PARAMETER; + } + + Value->Type = EFI_IFR_TYPE_NUM_SIZE_64; + Value->Value.u64 = StrLen (StrPtr); + gBS->FreePool (StrPtr); + break; + + case EFI_IFR_NOT_OP: + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + return Status; + } + if (Value->Type != EFI_IFR_TYPE_BOOLEAN) { + return EFI_INVALID_PARAMETER; + } + Value->Value.b = (BOOLEAN) (!Value->Value.b); + break; + + case EFI_IFR_QUESTION_REF2_OP: + // + // Pop an expression from the expression stack + // + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Validate the expression value + // + if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) { + return EFI_NOT_FOUND; + } + + Question = IdToQuestion (FormSet, Form, Value->Value.u16); + if (Question == NULL) { + return EFI_NOT_FOUND; + } + + Value = &Question->HiiValue; + break; + + case EFI_IFR_STRING_REF2_OP: + // + // Pop an expression from the expression stack + // + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Validate the expression value + // + if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) { + return EFI_NOT_FOUND; + } + + Value->Type = EFI_IFR_TYPE_STRING; + StrPtr = GetToken (Value->Value.u16, FormSet->HiiHandle); + if (StrPtr == NULL) { + // + // If String not exit, push an empty string + // + Value->Value.string = NewString (gEmptyString, FormSet->HiiHandle); + } else { + Index = (UINT16) Value->Value.u64; + Value->Value.string = Index; + gBS->FreePool (StrPtr); + } + break; + + case EFI_IFR_TO_BOOLEAN_OP: + // + // Pop an expression from the expression stack + // + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Convert an expression to a Boolean + // + if (Value->Type <= EFI_IFR_TYPE_DATE) { + // + // When converting from an unsigned integer, zero will be converted to + // FALSE and any other value will be converted to TRUE. + // + Value->Value.b = (BOOLEAN) ((Value->Value.u64) ? TRUE : FALSE); + + Value->Type = EFI_IFR_TYPE_BOOLEAN; + } else if (Value->Type == EFI_IFR_TYPE_STRING) { + // + // When converting from a string, if case-insensitive compare + // with "true" is True, then push True. If a case-insensitive compare + // with "false" is True, then push False. + // + StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle); + if (StrPtr == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((StrCmp (StrPtr, L"true") == 0) || (StrCmp (StrPtr, L"false") == 0)){ + Value->Value.b = TRUE; + } else { + Value->Value.b = FALSE; + } + gBS->FreePool (StrPtr); + Value->Type = EFI_IFR_TYPE_BOOLEAN; + } + break; + + case EFI_IFR_TO_STRING_OP: + Status = IfrToString (FormSet, OpCode->Format, Value); + break; + + case EFI_IFR_TO_UINT_OP: + Status = IfrToUint (FormSet, Value); + break; + + case EFI_IFR_TO_LOWER_OP: + case EFI_IFR_TO_UPPER_OP: + Status = InitializeUnicodeCollationProtocol (); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Value->Type != EFI_IFR_TYPE_STRING) { + return EFI_UNSUPPORTED; + } + + StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle); + if (StrPtr == NULL) { + return EFI_NOT_FOUND; + } + + if (OpCode->Operand == EFI_IFR_TO_LOWER_OP) { + mUnicodeCollation->StrLwr (mUnicodeCollation, StrPtr); + } else { + mUnicodeCollation->StrUpr (mUnicodeCollation, StrPtr); + } + Value->Value.string = NewString (StrPtr, FormSet->HiiHandle); + gBS->FreePool (StrPtr); + break; + + case EFI_IFR_BITWISE_NOT_OP: + // + // Pop an expression from the expression stack + // + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + return Status; + } + if (Value->Type > EFI_IFR_TYPE_DATE) { + return EFI_INVALID_PARAMETER; + } + + Value->Type = EFI_IFR_TYPE_NUM_SIZE_64; + Value->Value.u64 = ~Value->Value.u64; + break; + + // + // binary-op + // + case EFI_IFR_ADD_OP: + case EFI_IFR_SUBTRACT_OP: + case EFI_IFR_MULTIPLY_OP: + case EFI_IFR_DIVIDE_OP: + case EFI_IFR_MODULO_OP: + case EFI_IFR_BITWISE_AND_OP: + case EFI_IFR_BITWISE_OR_OP: + case EFI_IFR_SHIFT_LEFT_OP: + case EFI_IFR_SHIFT_RIGHT_OP: + // + // Pop an expression from the expression stack + // + Status = PopExpression (&Data2); + if (EFI_ERROR (Status)) { + return Status; + } + if (Data2.Type > EFI_IFR_TYPE_DATE) { + return EFI_INVALID_PARAMETER; + } + + // + // Pop another expression from the expression stack + // + Status = PopExpression (&Data1); + if (EFI_ERROR (Status)) { + return Status; + } + if (Data1.Type > EFI_IFR_TYPE_DATE) { + return EFI_INVALID_PARAMETER; + } + + Value->Type = EFI_IFR_TYPE_NUM_SIZE_64; + + switch (OpCode->Operand) { + case EFI_IFR_ADD_OP: + Value->Value.u64 = Data1.Value.u64 + Data2.Value.u64; + break; + + case EFI_IFR_SUBTRACT_OP: + Value->Value.u64 = Data1.Value.u64 - Data2.Value.u64; + break; + + case EFI_IFR_MULTIPLY_OP: + Value->Value.u64 = MultU64x32 (Data1.Value.u64, (UINT32) Data2.Value.u64); + break; + + case EFI_IFR_DIVIDE_OP: + Value->Value.u64 = DivU64x32 (Data1.Value.u64, (UINT32) Data2.Value.u64); + break; + + case EFI_IFR_MODULO_OP: + DivU64x32Remainder (Data1.Value.u64, (UINT32) Data2.Value.u64, &TempValue); + Value->Value.u64 = TempValue; + break; + + case EFI_IFR_BITWISE_AND_OP: + Value->Value.u64 = Data1.Value.u64 & Data2.Value.u64; + break; + + case EFI_IFR_BITWISE_OR_OP: + Value->Value.u64 = Data1.Value.u64 | Data2.Value.u64; + break; + + case EFI_IFR_SHIFT_LEFT_OP: + Value->Value.u64 = LShiftU64 (Data1.Value.u64, (UINTN) Data2.Value.u64); + break; + + case EFI_IFR_SHIFT_RIGHT_OP: + Value->Value.u64 = RShiftU64 (Data1.Value.u64, (UINTN) Data2.Value.u64); + break; + + default: + break; + } + break; + + case EFI_IFR_AND_OP: + case EFI_IFR_OR_OP: + // + // Two Boolean operator + // + Status = PopExpression (&Data2); + if (EFI_ERROR (Status)) { + return Status; + } + if (Data2.Type != EFI_IFR_TYPE_BOOLEAN) { + return EFI_INVALID_PARAMETER; + } + + // + // Pop another expression from the expression stack + // + Status = PopExpression (&Data1); + if (EFI_ERROR (Status)) { + return Status; + } + if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) { + return EFI_INVALID_PARAMETER; + } + + if (OpCode->Operand == EFI_IFR_AND_OP) { + Value->Value.b = (BOOLEAN) (Data1.Value.b && Data2.Value.b); + } else { + Value->Value.b = (BOOLEAN) (Data1.Value.b || Data2.Value.b); + } + break; + + case EFI_IFR_EQUAL_OP: + case EFI_IFR_NOT_EQUAL_OP: + case EFI_IFR_GREATER_EQUAL_OP: + case EFI_IFR_GREATER_THAN_OP: + case EFI_IFR_LESS_EQUAL_OP: + case EFI_IFR_LESS_THAN_OP: + // + // Compare two integer, string, boolean or date/time + // + Status = PopExpression (&Data2); + if (EFI_ERROR (Status)) { + return Status; + } + if (Data2.Type > EFI_IFR_TYPE_BOOLEAN && Data2.Type != EFI_IFR_TYPE_STRING) { + return EFI_INVALID_PARAMETER; + } + + // + // Pop another expression from the expression stack + // + Status = PopExpression (&Data1); + if (EFI_ERROR (Status)) { + return Status; + } + + Result = CompareHiiValue (&Data1, &Data2, FormSet->HiiHandle); + if (Result == EFI_INVALID_PARAMETER) { + return EFI_INVALID_PARAMETER; + } + + switch (OpCode->Operand) { + case EFI_IFR_EQUAL_OP: + Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE); + break; + + case EFI_IFR_NOT_EQUAL_OP: + Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE); + break; + + case EFI_IFR_GREATER_EQUAL_OP: + Value->Value.b = (BOOLEAN) ((Result >= 0) ? TRUE : FALSE); + break; + + case EFI_IFR_GREATER_THAN_OP: + Value->Value.b = (BOOLEAN) ((Result > 0) ? TRUE : FALSE); + break; + + case EFI_IFR_LESS_EQUAL_OP: + Value->Value.b = (BOOLEAN) ((Result <= 0) ? TRUE : FALSE); + break; + + case EFI_IFR_LESS_THAN_OP: + Value->Value.b = (BOOLEAN) ((Result < 0) ? TRUE : FALSE); + break; + + default: + break; + } + break; + + case EFI_IFR_MATCH_OP: + Status = IfrMatch (FormSet, Value); + break; + + case EFI_IFR_CATENATE_OP: + Status = IfrCatenate (FormSet, Value); + break; + + // + // ternary-op + // + case EFI_IFR_CONDITIONAL_OP: + // + // Pop third expression from the expression stack + // + Status = PopExpression (&Data3); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Pop second expression from the expression stack + // + Status = PopExpression (&Data2); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Pop first expression from the expression stack + // + Status = PopExpression (&Data1); + if (EFI_ERROR (Status)) { + return Status; + } + if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) { + return EFI_INVALID_PARAMETER; + } + + if (Data1.Value.b) { + Value = &Data3; + } else { + Value = &Data2; + } + break; + + case EFI_IFR_FIND_OP: + Status = IfrFind (FormSet, OpCode->Format, Value); + break; + + case EFI_IFR_MID_OP: + Status = IfrMid (FormSet, Value); + break; + + case EFI_IFR_TOKEN_OP: + Status = IfrToken (FormSet, Value); + break; + + case EFI_IFR_SPAN_OP: + Status = IfrSpan (FormSet, OpCode->Flags, Value); + break; + + default: + break; + } + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PushExpression (Value); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Pop the final result from expression stack + // + Value = &Data1; + Status = PopExpression (Value); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // After evaluating an expression, there should be only one value left on the expression stack + // + if (PopExpression (Value) != EFI_ACCESS_DENIED) { + return EFI_INVALID_PARAMETER; + } + + CopyMem (&Expression->Result, Value, sizeof (EFI_HII_VALUE)); + + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c b/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c new file mode 100644 index 0000000000..4b68047156 --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c @@ -0,0 +1,1640 @@ +/** @file +Copyright (c) 2007, Intel Corporation +All rights reserved. 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. + +Module Name: + + IfrParse.c + +Abstract: + + Parser for IFR binary encoding. + + +**/ + +#include "Setup.h" +#include "Ui.h" +//@MT:#include "EfiPrintLib.h" + +UINT16 mStatementIndex; +UINT16 mExpressionOpCodeIndex; + +BOOLEAN mInScopeSubtitle; +BOOLEAN mInScopeSuppress; +BOOLEAN mInScopeGrayOut; +FORM_EXPRESSION *mSuppressExpression; +FORM_EXPRESSION *mGrayOutExpression; + +EFI_GUID gTianoHiiIfrGuid = EFI_IFR_TIANO_GUID; + + +/** + Initialize Statement header members. + + @param OpCodeData Pointer of the raw OpCode data. + @param FormSet Pointer of the current FormSe. + @param Form Pointer of the current Form. + + @return The Statement. + +**/ +FORM_BROWSER_STATEMENT * +CreateStatement ( + IN UINT8 *OpCodeData, + IN OUT FORM_BROWSER_FORMSET *FormSet, + IN OUT FORM_BROWSER_FORM *Form + ) +{ + FORM_BROWSER_STATEMENT *Statement; + EFI_IFR_STATEMENT_HEADER *StatementHdr; + + if (Form == NULL) { + // + // We are currently not in a Form Scope, so just skip this Statement + // + return NULL; + } + + Statement = &FormSet->StatementBuffer[mStatementIndex]; + mStatementIndex++; + + InitializeListHead (&Statement->DefaultListHead); + InitializeListHead (&Statement->OptionListHead); + InitializeListHead (&Statement->InconsistentListHead); + InitializeListHead (&Statement->NoSubmitListHead); + + Statement->Signature = FORM_BROWSER_STATEMENT_SIGNATURE; + + Statement->Operand = ((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode; + + StatementHdr = (EFI_IFR_STATEMENT_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER)); + CopyMem (&Statement->Prompt, &StatementHdr->Prompt, sizeof (EFI_STRING_ID)); + CopyMem (&Statement->Help, &StatementHdr->Help, sizeof (EFI_STRING_ID)); + + if (mInScopeSuppress) { + Statement->SuppressExpression = mSuppressExpression; + } + + if (mInScopeGrayOut) { + Statement->GrayOutExpression = mGrayOutExpression; + } + + Statement->InSubtitle = mInScopeSubtitle; + + // + // Insert this Statement into current Form + // + InsertTailList (&Form->StatementListHead, &Statement->Link); + + return Statement; +} + + +/** + Initialize Question's members. + + @param OpCodeData Pointer of the raw OpCode data. + @param FormSet Pointer of the current FormSet. + @param Form Pointer of the current Form. + + @return The Question. + +**/ +FORM_BROWSER_STATEMENT * +CreateQuestion ( + IN UINT8 *OpCodeData, + IN OUT FORM_BROWSER_FORMSET *FormSet, + IN OUT FORM_BROWSER_FORM *Form + ) +{ + FORM_BROWSER_STATEMENT *Statement; + EFI_IFR_QUESTION_HEADER *QuestionHdr; + LIST_ENTRY *Link; + FORMSET_STORAGE *Storage; + NAME_VALUE_NODE *NameValueNode; + + Statement = CreateStatement (OpCodeData, FormSet, Form); + if (Statement == NULL) { + return NULL; + } + + QuestionHdr = (EFI_IFR_QUESTION_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER)); + CopyMem (&Statement->QuestionId, &QuestionHdr->QuestionId, sizeof (EFI_QUESTION_ID)); + CopyMem (&Statement->VarStoreId, &QuestionHdr->VarStoreId, sizeof (EFI_VARSTORE_ID)); + CopyMem (&Statement->VarStoreInfo.VarOffset, &QuestionHdr->VarStoreInfo.VarOffset, sizeof (UINT16)); + + Statement->QuestionFlags = QuestionHdr->Flags; + + if (Statement->VarStoreId == 0) { + // + // VarStoreId of zero indicates no variable storage + // + return Statement; + } + + // + // Find Storage for this Question + // + Link = GetFirstNode (&FormSet->StorageListHead); + while (!IsNull (&FormSet->StorageListHead, Link)) { + Storage = FORMSET_STORAGE_FROM_LINK (Link); + + if (Storage->VarStoreId == Statement->VarStoreId) { + Statement->Storage = Storage; + break; + } + + Link = GetNextNode (&FormSet->StorageListHead, Link); + } + ASSERT (Statement->Storage != NULL); + + // + // Initialilze varname for Name/Value or EFI Variable + // + if ((Statement->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) || + (Statement->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE)) { + Statement->VariableName = GetToken (Statement->VarStoreInfo.VarName, FormSet->HiiHandle); + ASSERT (Statement->VariableName != NULL); + + if (Statement->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) { + // + // Insert to Name/Value varstore list + // + NameValueNode = AllocateZeroPool (sizeof (NAME_VALUE_NODE)); + ASSERT (NameValueNode != NULL); + NameValueNode->Signature = NAME_VALUE_NODE_SIGNATURE; + NameValueNode->Name = AllocateCopyPool (StrSize (Statement->VariableName), Statement->VariableName); + ASSERT (NameValueNode->Name != NULL); + NameValueNode->Value = AllocateZeroPool (0x10); + ASSERT (NameValueNode->Value != NULL); + NameValueNode->EditValue = AllocateZeroPool (0x10); + ASSERT (NameValueNode->EditValue != NULL); + + InsertTailList (&Statement->Storage->NameValueListHead, &NameValueNode->Link); + } + } + + return Statement; +} + + +/** + Allocate a FORM_EXPRESSION node. + + @param Form The Form associated with this Expression + + @return Pointer to a FORM_EXPRESSION data structure. + +**/ +FORM_EXPRESSION * +CreateExpression ( + IN OUT FORM_BROWSER_FORM *Form + ) +{ + FORM_EXPRESSION *Expression; + + Expression = AllocateZeroPool (sizeof (FORM_EXPRESSION)); + Expression->Signature = FORM_EXPRESSION_SIGNATURE; + InitializeListHead (&Expression->OpCodeListHead); + + return Expression; +} + + +/** + Allocate a FORMSET_STORAGE data structure and insert to FormSet Storage List. + + @param FormSet Pointer of the current FormSet + + @return Pointer to a FORMSET_STORAGE data structure. + +**/ +FORMSET_STORAGE * +CreateStorage ( + IN FORM_BROWSER_FORMSET *FormSet + ) +{ + FORMSET_STORAGE *Storage; + + Storage = AllocateZeroPool (sizeof (FORMSET_STORAGE)); + Storage->Signature = FORMSET_STORAGE_SIGNATURE; + InitializeListHead (&Storage->NameValueListHead); + InsertTailList (&FormSet->StorageListHead, &Storage->Link); + + return Storage; +} + + +/** + Create ConfigHdr string for a storage. + + @param FormSet Pointer of the current FormSet + @param Storage Pointer of the storage + + @retval EFI_SUCCESS Initialize ConfigHdr success + +**/ +EFI_STATUS +InitializeConfigHdr ( + IN FORM_BROWSER_FORMSET *FormSet, + IN OUT FORMSET_STORAGE *Storage + ) +{ + EFI_STATUS Status; + UINTN StrBufferLen; + CHAR16 *Name; + + if (Storage->Type == EFI_HII_VARSTORE_BUFFER) { + Name = Storage->Name; + } else { + Name = NULL; + } + + StrBufferLen = 0; + Status = ConstructConfigHdr ( + Storage->ConfigHdr, + &StrBufferLen, + &Storage->Guid, + Name, + FormSet->DriverHandle + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + Storage->ConfigHdr = AllocateZeroPool (StrBufferLen); + Status = ConstructConfigHdr ( + Storage->ConfigHdr, + &StrBufferLen, + &Storage->Guid, + Name, + FormSet->DriverHandle + ); + } + + if (EFI_ERROR (Status)) { + return Status; + } + + Storage->ConfigRequest = AllocateCopyPool (StrBufferLen, Storage->ConfigHdr); + Storage->SpareStrLen = 0; + + return EFI_SUCCESS; +} + + +/** + Initialize Request Element of a Question. <RequestElement> ::= '&'<BlockName> | '&'<Label> + + @param FormSet Pointer of the current FormSet. + @param Question The Question to be initialized. + + @retval EFI_SUCCESS Function success. + @retval EFI_INVALID_PARAMETER No storage associated with the Question. + +**/ +EFI_STATUS +InitializeRequestElement ( + IN OUT FORM_BROWSER_FORMSET *FormSet, + IN OUT FORM_BROWSER_STATEMENT *Question + ) +{ + FORMSET_STORAGE *Storage; + UINTN StrLen; + UINTN StringSize; + CHAR16 *NewStr; + CHAR16 RequestElement[30]; + + Storage = Question->Storage; + if (Storage == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + // + // <ConfigRequest> is unnecessary for EFI variable storage, + // GetVariable()/SetVariable() will be used to retrieve/save values + // + return EFI_SUCCESS; + } + + // + // Prepare <RequestElement> + // + if (Storage->Type == EFI_HII_VARSTORE_BUFFER) { + StrLen = UnicodeSPrint ( + RequestElement, + 30 * sizeof (CHAR16), + L"&OFFSET=%x&WIDTH=%x", + Question->VarStoreInfo.VarOffset, + Question->StorageWidth + ); + Question->BlockName = AllocateCopyPool ((StrLen + 1) * sizeof (CHAR16), RequestElement); + } else { + StrLen = UnicodeSPrint (RequestElement, 30 * sizeof (CHAR16), L"&%s", Question->VariableName); + } + + if ((Question->Operand == EFI_IFR_PASSWORD_OP) && (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK)) { + // + // Password with CALLBACK flag is stored in encoded format, + // so don't need to append it to <ConfigRequest>\ + // + return EFI_SUCCESS; + } + + // + // Append <RequestElement> to <ConfigRequest> + // + if (StrLen > Storage->SpareStrLen) { + // + // Old String buffer is not sufficient for RequestElement, allocate a new one + // + StringSize = (Storage->ConfigRequest != NULL) ? StrSize (Storage->ConfigRequest) : 0; + NewStr = AllocateZeroPool (StringSize + CONFIG_REQUEST_STRING_INCREMENTAL * sizeof (CHAR16)); + if (Storage->ConfigRequest != NULL) { + CopyMem (NewStr, Storage->ConfigRequest, StringSize); + gBS->FreePool (Storage->ConfigRequest); + } + Storage->ConfigRequest = NewStr; + Storage->SpareStrLen = CONFIG_REQUEST_STRING_INCREMENTAL; + } + + StrCat (Storage->ConfigRequest, RequestElement); + Storage->ElementCount++; + Storage->SpareStrLen -= StrLen; + + return EFI_SUCCESS; +} + + +/** + Free resources of a Expression + + @param FormSet Pointer of the Expression + + @return None. + +**/ +VOID +DestroyExpression ( + IN FORM_EXPRESSION *Expression + ) +{ + LIST_ENTRY *Link; + EXPRESSION_OPCODE *OpCode; + + while (!IsListEmpty (&Expression->OpCodeListHead)) { + Link = GetFirstNode (&Expression->OpCodeListHead); + OpCode = EXPRESSION_OPCODE_FROM_LINK (Link); + RemoveEntryList (&OpCode->Link); + + SafeFreePool (OpCode->ValueList); + } + + // + // Free this Expression + // + gBS->FreePool (Expression); +} + + +/** + Free resources of a storage + + @param Storage Pointer of the storage + + @return None. + +**/ +VOID +DestroyStorage ( + IN FORMSET_STORAGE *Storage + ) +{ + LIST_ENTRY *Link; + NAME_VALUE_NODE *NameValueNode; + + if (Storage == NULL) { + return; + } + + SafeFreePool (Storage->Name); + SafeFreePool (Storage->Buffer); + SafeFreePool (Storage->EditBuffer); + + while (!IsListEmpty (&Storage->NameValueListHead)) { + Link = GetFirstNode (&Storage->NameValueListHead); + NameValueNode = NAME_VALUE_NODE_FROM_LINK (Link); + RemoveEntryList (&NameValueNode->Link); + + SafeFreePool (NameValueNode->Name); + SafeFreePool (NameValueNode->Value); + SafeFreePool (NameValueNode->EditValue); + SafeFreePool (NameValueNode); + } + + SafeFreePool (Storage->ConfigHdr); + SafeFreePool (Storage->ConfigRequest); + + gBS->FreePool (Storage); +} + + +/** + Free resources of a Statement + + @param Statement Pointer of the Statement + + @return None. + +**/ +VOID +DestroyStatement ( + IN OUT FORM_BROWSER_STATEMENT *Statement + ) +{ + LIST_ENTRY *Link; + QUESTION_DEFAULT *Default; + QUESTION_OPTION *Option; + FORM_EXPRESSION *Expression; + + // + // Free Default value List + // + while (!IsListEmpty (&Statement->DefaultListHead)) { + Link = GetFirstNode (&Statement->DefaultListHead); + Default = QUESTION_DEFAULT_FROM_LINK (Link); + RemoveEntryList (&Default->Link); + + gBS->FreePool (Default); + } + + // + // Free Options List + // + while (!IsListEmpty (&Statement->OptionListHead)) { + Link = GetFirstNode (&Statement->OptionListHead); + Option = QUESTION_OPTION_FROM_LINK (Link); + RemoveEntryList (&Option->Link); + + gBS->FreePool (Option); + } + + // + // Free Inconsistent List + // + while (!IsListEmpty (&Statement->InconsistentListHead)) { + Link = GetFirstNode (&Statement->InconsistentListHead); + Expression = FORM_EXPRESSION_FROM_LINK (Link); + RemoveEntryList (&Expression->Link); + + DestroyExpression (Expression); + } + + // + // Free NoSubmit List + // + while (!IsListEmpty (&Statement->NoSubmitListHead)) { + Link = GetFirstNode (&Statement->NoSubmitListHead); + Expression = FORM_EXPRESSION_FROM_LINK (Link); + RemoveEntryList (&Expression->Link); + + DestroyExpression (Expression); + } + + SafeFreePool (Statement->VariableName); + SafeFreePool (Statement->BlockName); +} + + +/** + Free resources of a Form + + @param Form Pointer of the Form + + @return None. + +**/ +VOID +DestroyForm ( + IN OUT FORM_BROWSER_FORM *Form + ) +{ + LIST_ENTRY *Link; + FORM_EXPRESSION *Expression; + FORM_BROWSER_STATEMENT *Statement; + + // + // Free Form Expressions + // + while (!IsListEmpty (&Form->ExpressionListHead)) { + Link = GetFirstNode (&Form->ExpressionListHead); + Expression = FORM_EXPRESSION_FROM_LINK (Link); + RemoveEntryList (&Expression->Link); + + DestroyExpression (Expression); + } + + // + // Free Statements/Questions + // + while (!IsListEmpty (&Form->StatementListHead)) { + Link = GetFirstNode (&Form->StatementListHead); + Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + RemoveEntryList (&Statement->Link); + + DestroyStatement (Statement); + } + + // + // Free this Form + // + gBS->FreePool (Form); +} + + +/** + Free resources allocated for a FormSet + + @param FormSet Pointer of the FormSet + + @return None. + +**/ +VOID +DestroyFormSet ( + IN OUT FORM_BROWSER_FORMSET *FormSet + ) +{ + LIST_ENTRY *Link; + FORMSET_STORAGE *Storage; + FORMSET_DEFAULTSTORE *DefaultStore; + FORM_BROWSER_FORM *Form; + + // + // Free IFR binary buffer + // + SafeFreePool (FormSet->IfrBinaryData); + + // + // Free FormSet Storage + // + if (FormSet->StorageListHead.ForwardLink != NULL) { + while (!IsListEmpty (&FormSet->StorageListHead)) { + Link = GetFirstNode (&FormSet->StorageListHead); + Storage = FORMSET_STORAGE_FROM_LINK (Link); + RemoveEntryList (&Storage->Link); + + DestroyStorage (Storage); + } + } + + // + // Free FormSet Default Store + // + if (FormSet->DefaultStoreListHead.ForwardLink != NULL) { + while (!IsListEmpty (&FormSet->DefaultStoreListHead)) { + Link = GetFirstNode (&FormSet->DefaultStoreListHead); + DefaultStore = FORMSET_DEFAULTSTORE_FROM_LINK (Link); + RemoveEntryList (&DefaultStore->Link); + + gBS->FreePool (DefaultStore); + } + } + + // + // Free Forms + // + if (FormSet->FormListHead.ForwardLink != NULL) { + while (!IsListEmpty (&FormSet->FormListHead)) { + Link = GetFirstNode (&FormSet->FormListHead); + Form = FORM_BROWSER_FORM_FROM_LINK (Link); + RemoveEntryList (&Form->Link); + + DestroyForm (Form); + } + } + + SafeFreePool (FormSet->StatementBuffer); + SafeFreePool (FormSet->ExpressionBuffer); + + SafeFreePool (FormSet); +} + + +/** + Tell whether this Operand is an Expression OpCode or not + + @param Operand Operand of an IFR OpCode. + + @retval TRUE This is an Expression OpCode. + @retval FALSE Not an Expression OpCode. + +**/ +BOOLEAN +IsExpressionOpCode ( + IN UINT8 Operand + ) +{ + if (((Operand >= EFI_IFR_EQ_ID_VAL_OP) && (Operand <= EFI_IFR_NOT_OP)) || + ((Operand >= EFI_IFR_MATCH_OP) && (Operand <= EFI_IFR_SPAN_OP)) || + (Operand == EFI_IFR_CATENATE_OP) + ) { + return TRUE; + } else { + return FALSE; + } +} + + +/** + Calculate number of Statemens(Questions) and Expression OpCodes. + + @param FormSet The FormSet to be counted. + @param NumberOfStatement Number of Statemens(Questions) + @param NumberOfExpression Number of Expression OpCodes + + @return None. + +**/ +VOID +CountOpCodes ( + IN FORM_BROWSER_FORMSET *FormSet, + IN OUT UINT16 *NumberOfStatement, + IN OUT UINT16 *NumberOfExpression + ) +{ + UINT16 StatementCount; + UINT16 ExpressionCount; + UINT8 *OpCodeData; + UINTN Offset; + UINTN OpCodeLen; + + Offset = 0; + StatementCount = 0; + ExpressionCount = 0; + + while (Offset < FormSet->IfrBinaryLength) { + OpCodeData = FormSet->IfrBinaryData + Offset; + OpCodeLen = ((EFI_IFR_OP_HEADER *) OpCodeData)->Length; + Offset += OpCodeLen; + + if (IsExpressionOpCode (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode)) { + ExpressionCount++; + } else { + StatementCount++; + } + } + + *NumberOfStatement = StatementCount; + *NumberOfExpression = ExpressionCount; +} + + +/** + Parse opcodes in the formset IFR binary. + + @param FormSet Pointer of the FormSet data structure. + + @retval EFI_SUCCESS Opcode parse success. + @retval Other Opcode parse fail. + +**/ +EFI_STATUS +ParseOpCodes ( + IN FORM_BROWSER_FORMSET *FormSet + ) +{ + EFI_STATUS Status; + UINT16 Index; + FORM_BROWSER_FORM *CurrentForm; + FORM_BROWSER_STATEMENT *CurrentStatement; + EXPRESSION_OPCODE *ExpressionOpCode; + FORM_EXPRESSION *CurrentExpression; + UINT8 Operand; + UINT8 Scope; + UINTN OpCodeOffset; + UINTN OpCodeLength; + UINT8 *OpCodeData; + UINT8 ScopeOpCode; + FORMSET_STORAGE *Storage; + FORMSET_DEFAULTSTORE *DefaultStore; + QUESTION_DEFAULT *CurrentDefault; + QUESTION_OPTION *CurrentOption; + CHAR8 *AsciiString; + UINT16 NumberOfStatement; + UINT16 NumberOfExpression; + EFI_IMAGE_ID *ImageId; + BOOLEAN SuppressForOption; + BOOLEAN InScopeOptionSuppress; + FORM_EXPRESSION *OptionSuppressExpression; + BOOLEAN InScopeDisable; + UINT16 DepthOfDisable; + BOOLEAN OpCodeDisabled; + BOOLEAN SingleOpCodeExpression; + BOOLEAN InScopeDefault; + EFI_HII_VALUE *Value; + + mInScopeSubtitle = FALSE; + SuppressForOption = FALSE; + mInScopeSuppress = FALSE; + InScopeOptionSuppress = FALSE; + mInScopeGrayOut = FALSE; + InScopeDisable = FALSE; + DepthOfDisable = 0; + OpCodeDisabled = FALSE; + SingleOpCodeExpression = FALSE; + InScopeDefault = FALSE; + CurrentExpression = NULL; + CurrentDefault = NULL; + CurrentOption = NULL; + OptionSuppressExpression = NULL; + + // + // Get the number of Statements and Expressions + // + CountOpCodes (FormSet, &NumberOfStatement, &NumberOfExpression); + + mStatementIndex = 0; + FormSet->StatementBuffer = AllocateZeroPool (NumberOfStatement * sizeof (FORM_BROWSER_STATEMENT)); + if (FormSet->StatementBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + mExpressionOpCodeIndex = 0; + FormSet->ExpressionBuffer = AllocateZeroPool (NumberOfExpression * sizeof (EXPRESSION_OPCODE)); + if (FormSet->ExpressionBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + InitializeListHead (&FormSet->StorageListHead); + InitializeListHead (&FormSet->DefaultStoreListHead); + InitializeListHead (&FormSet->FormListHead); + + CurrentForm = NULL; + CurrentStatement = NULL; + + ResetScopeStack (); + + OpCodeOffset = 0; + while (OpCodeOffset < FormSet->IfrBinaryLength) { + OpCodeData = FormSet->IfrBinaryData + OpCodeOffset; + + OpCodeLength = ((EFI_IFR_OP_HEADER *) OpCodeData)->Length; + OpCodeOffset += OpCodeLength; + Operand = ((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode; + Scope = ((EFI_IFR_OP_HEADER *) OpCodeData)->Scope; + + // + // If scope bit set, push onto scope stack + // + if (Scope) { + PushScope (Operand); + } + + if (OpCodeDisabled) { + // + // DisableIf Expression is evaluated to be TRUE, try to find its end. + // Here only cares the EFI_IFR_DISABLE_IF and EFI_IFR_END + // + if (Operand == EFI_IFR_DISABLE_IF_OP) { + DepthOfDisable++; + } else if (Operand == EFI_IFR_END_OP) { + Status = PopScope (&ScopeOpCode); + if (EFI_ERROR (Status)) { + return Status; + } + + if (ScopeOpCode == EFI_IFR_DISABLE_IF_OP) { + if (DepthOfDisable == 0) { + InScopeDisable = FALSE; + OpCodeDisabled = FALSE; + } else { + DepthOfDisable--; + } + } + } + continue; + } + + if (IsExpressionOpCode (Operand)) { + ExpressionOpCode = &FormSet->ExpressionBuffer[mExpressionOpCodeIndex]; + mExpressionOpCodeIndex++; + + ExpressionOpCode->Signature = EXPRESSION_OPCODE_SIGNATURE; + ExpressionOpCode->Operand = Operand; + Value = &ExpressionOpCode->Value; + + switch (Operand) { + case EFI_IFR_EQ_ID_VAL_OP: + CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_VAL *) OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID)); + + Value->Type = EFI_IFR_TYPE_NUM_SIZE_16; + CopyMem (&Value->Value.u16, &((EFI_IFR_EQ_ID_VAL *) OpCodeData)->Value, sizeof (UINT16)); + break; + + case EFI_IFR_EQ_ID_ID_OP: + CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_ID *) OpCodeData)->QuestionId1, sizeof (EFI_QUESTION_ID)); + CopyMem (&ExpressionOpCode->QuestionId2, &((EFI_IFR_EQ_ID_ID *) OpCodeData)->QuestionId2, sizeof (EFI_QUESTION_ID)); + break; + + case EFI_IFR_EQ_ID_LIST_OP: + CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_LIST *) OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID)); + CopyMem (&ExpressionOpCode->ListLength, &((EFI_IFR_EQ_ID_LIST *) OpCodeData)->ListLength, sizeof (UINT16)); + ExpressionOpCode->ValueList = AllocateCopyPool (ExpressionOpCode->ListLength * sizeof (UINT16), &((EFI_IFR_EQ_ID_LIST *) OpCodeData)->ValueList); + break; + + case EFI_IFR_TO_STRING_OP: + case EFI_IFR_FIND_OP: + ExpressionOpCode->Format = (( EFI_IFR_TO_STRING *) OpCodeData)->Format; + break; + + case EFI_IFR_STRING_REF1_OP: + Value->Type = EFI_IFR_TYPE_STRING; + CopyMem (&Value->Value.string, &(( EFI_IFR_STRING_REF1 *) OpCodeData)->StringId, sizeof (EFI_STRING_ID)); + break; + + case EFI_IFR_RULE_REF_OP: + ExpressionOpCode->RuleId = (( EFI_IFR_RULE_REF *) OpCodeData)->RuleId; + break; + + case EFI_IFR_SPAN_OP: + ExpressionOpCode->Flags = (( EFI_IFR_SPAN *) OpCodeData)->Flags; + break; + + case EFI_IFR_THIS_OP: + ExpressionOpCode->QuestionId = CurrentStatement->QuestionId; + break; + + case EFI_IFR_QUESTION_REF1_OP: + CopyMem (&ExpressionOpCode->QuestionId, &((EFI_IFR_EQ_ID_LIST *) OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID)); + break; + + case EFI_IFR_QUESTION_REF3_OP: + if (OpCodeLength >= sizeof (EFI_IFR_QUESTION_REF3_2)) { + CopyMem (&ExpressionOpCode->DevicePath, &(( EFI_IFR_QUESTION_REF3_2 *) OpCodeData)->DevicePath, sizeof (EFI_STRING_ID)); + + if (OpCodeLength >= sizeof (EFI_IFR_QUESTION_REF3_3)) { + CopyMem (&ExpressionOpCode->Guid, &(( EFI_IFR_QUESTION_REF3_3 *) OpCodeData)->Guid, sizeof (EFI_GUID)); + } + } + break; + + // + // constant + // + case EFI_IFR_TRUE_OP: + Value->Type = EFI_IFR_TYPE_BOOLEAN; + Value->Value.b = TRUE; + break; + + case EFI_IFR_FALSE_OP: + Value->Type = EFI_IFR_TYPE_BOOLEAN; + Value->Value.b = FALSE; + break; + + case EFI_IFR_ONE_OP: + Value->Type = EFI_IFR_TYPE_NUM_SIZE_8; + Value->Value.u8 = 1; + break; + + case EFI_IFR_ZERO_OP: + Value->Type = EFI_IFR_TYPE_NUM_SIZE_8; + Value->Value.u8 = 0; + break; + + case EFI_IFR_ONES_OP: + Value->Type = EFI_IFR_TYPE_NUM_SIZE_64; + Value->Value.u64 = 0xffffffffffffffff; + break; + + case EFI_IFR_UINT8_OP: + Value->Type = EFI_IFR_TYPE_NUM_SIZE_8; + Value->Value.u8 = (( EFI_IFR_UINT8 *) OpCodeData)->Value; + break; + + case EFI_IFR_UINT16_OP: + Value->Type = EFI_IFR_TYPE_NUM_SIZE_16; + CopyMem (&Value->Value.u16, &(( EFI_IFR_UINT16 *) OpCodeData)->Value, sizeof (UINT16)); + break; + + case EFI_IFR_UINT32_OP: + Value->Type = EFI_IFR_TYPE_NUM_SIZE_32; + CopyMem (&Value->Value.u32, &(( EFI_IFR_UINT32 *) OpCodeData)->Value, sizeof (UINT32)); + break; + + case EFI_IFR_UINT64_OP: + Value->Type = EFI_IFR_TYPE_NUM_SIZE_64; + CopyMem (&Value->Value.u64, &(( EFI_IFR_UINT64 *) OpCodeData)->Value, sizeof (UINT64)); + break; + + case EFI_IFR_UNDEFINED_OP: + Value->Type = EFI_IFR_TYPE_OTHER; + break; + + case EFI_IFR_VERSION_OP: + Value->Type = EFI_IFR_TYPE_NUM_SIZE_16; + Value->Value.u16 = EFI_IFR_SPECIFICATION_VERSION; + break; + + default: + break; + } + + InsertTailList (&CurrentExpression->OpCodeListHead, &ExpressionOpCode->Link); + + if (SingleOpCodeExpression) { + // + // There are two cases to indicate the end of an Expression: + // for single OpCode expression: one Expression OpCode + // for expression consists of more than one OpCode: EFI_IFR_END + // + SingleOpCodeExpression = FALSE; + + if (InScopeDisable) { + // + // Evaluate DisableIf expression + // + Status = EvaluateExpression (FormSet, CurrentForm, CurrentExpression); + if (EFI_ERROR (Status)) { + return Status; + } + if (CurrentExpression->Result.Type != EFI_IFR_TYPE_BOOLEAN) { + return EFI_INVALID_PARAMETER; + } + + OpCodeDisabled = CurrentExpression->Result.Value.b; + } + + CurrentExpression = NULL; + } + + continue; + } + + // + // Parse the Opcode + // + switch (Operand) { + + case EFI_IFR_FORM_SET_OP: + // + // check the formset GUID + // + if (CompareMem (&FormSet->Guid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID)) != 0) { + return EFI_INVALID_PARAMETER; + } + + CopyMem (&FormSet->FormSetTitle, &((EFI_IFR_FORM_SET *) OpCodeData)->FormSetTitle, sizeof (EFI_STRING_ID)); + CopyMem (&FormSet->Help, &((EFI_IFR_FORM_SET *) OpCodeData)->Help, sizeof (EFI_STRING_ID)); + break; + + case EFI_IFR_FORM_OP: + // + // Create a new Form for this FormSet + // + CurrentForm = AllocateZeroPool (sizeof (FORM_BROWSER_FORM)); + CurrentForm->Signature = FORM_BROWSER_FORM_SIGNATURE; + InitializeListHead (&CurrentForm->ExpressionListHead); + InitializeListHead (&CurrentForm->StatementListHead); + + CopyMem (&CurrentForm->FormId, &((EFI_IFR_FORM *) OpCodeData)->FormId, sizeof (UINT16)); + CopyMem (&CurrentForm->FormTitle, &((EFI_IFR_FORM *) OpCodeData)->FormTitle, sizeof (EFI_STRING_ID)); + + // + // Insert into Form list of this FormSet + // + InsertTailList (&FormSet->FormListHead, &CurrentForm->Link); + break; + + // + // Storage + // + case EFI_IFR_VARSTORE_OP: + // + // Create a buffer Storage for this FormSet + // + Storage = CreateStorage (FormSet); + Storage->Type = EFI_HII_VARSTORE_BUFFER; + + CopyMem (&Storage->VarStoreId, &((EFI_IFR_VARSTORE *) OpCodeData)->VarStoreId, sizeof (EFI_VARSTORE_ID)); + CopyMem (&Storage->Guid, &((EFI_IFR_VARSTORE *) OpCodeData)->Guid, sizeof (EFI_GUID)); + CopyMem (&Storage->Size, &((EFI_IFR_VARSTORE *) OpCodeData)->Size, sizeof (UINT16)); + + Storage->Buffer = AllocateZeroPool (Storage->Size); + Storage->EditBuffer = AllocateZeroPool (Storage->Size); + + AsciiString = (CHAR8 *) ((EFI_IFR_VARSTORE *) OpCodeData)->Name; + Storage->Name = AllocateZeroPool (AsciiStrSize (AsciiString) * 2); + ASSERT (Storage->Name != NULL); + for (Index = 0; AsciiString[Index] != 0; Index++) { + Storage->Name[Index] = (CHAR16) AsciiString[Index]; + } + + // + // Initialize <ConfigHdr> + // + InitializeConfigHdr (FormSet, Storage); + break; + + case EFI_IFR_VARSTORE_NAME_VALUE_OP: + // + // Create a name/value Storage for this FormSet + // + Storage = CreateStorage (FormSet); + Storage->Type = EFI_HII_VARSTORE_NAME_VALUE; + + CopyMem (&Storage->VarStoreId, &((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->VarStoreId, sizeof (EFI_VARSTORE_ID)); + CopyMem (&Storage->Guid, &((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->Guid, sizeof (EFI_GUID)); + + // + // Initialize <ConfigHdr> + // + InitializeConfigHdr (FormSet, Storage); + break; + + case EFI_IFR_VARSTORE_EFI_OP: + // + // Create a EFI variable Storage for this FormSet + // + Storage = CreateStorage (FormSet); + Storage->Type = EFI_HII_VARSTORE_EFI_VARIABLE; + + CopyMem (&Storage->VarStoreId, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->VarStoreId, sizeof (EFI_VARSTORE_ID)); + CopyMem (&Storage->Guid, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Guid, sizeof (EFI_GUID)); + CopyMem (&Storage->Attributes, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Attributes, sizeof (UINT32)); + break; + + // + // DefaultStore + // + case EFI_IFR_DEFAULTSTORE_OP: + DefaultStore = AllocateZeroPool (sizeof (FORMSET_DEFAULTSTORE)); + DefaultStore->Signature = FORMSET_DEFAULTSTORE_SIGNATURE; + + CopyMem (&DefaultStore->DefaultId, &((EFI_IFR_DEFAULTSTORE *) OpCodeData)->DefaultId, sizeof (UINT16)); + CopyMem (&DefaultStore->DefaultName, &((EFI_IFR_DEFAULTSTORE *) OpCodeData)->DefaultName, sizeof (EFI_STRING_ID)); + + // + // Insert to DefaultStore list of this Formset + // + InsertTailList (&FormSet->DefaultStoreListHead, &DefaultStore->Link); + break; + + // + // Statements + // + case EFI_IFR_SUBTITLE_OP: + CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm); + CurrentStatement->Flags = ((EFI_IFR_SUBTITLE *) OpCodeData)->Flags; + + if (Scope) { + mInScopeSubtitle = TRUE; + } + break; + + case EFI_IFR_TEXT_OP: + CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm); + + CopyMem (&CurrentStatement->TextTwo, &((EFI_IFR_TEXT *) OpCodeData)->TextTwo, sizeof (EFI_STRING_ID)); + break; + + // + // Questions + // + case EFI_IFR_ACTION_OP: + CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm); + + if (OpCodeLength == sizeof (EFI_IFR_ACTION_1)) { + // + // No QuestionConfig present, so no configuration string will be processed + // + CurrentStatement->QuestionConfig = 0; + } else { + CopyMem (&CurrentStatement->QuestionConfig, &((EFI_IFR_ACTION *) OpCodeData)->QuestionConfig, sizeof (EFI_STRING_ID)); + } + break; + + case EFI_IFR_RESET_BUTTON_OP: + CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm); + + CopyMem (&CurrentStatement->DefaultId, &((EFI_IFR_RESET_BUTTON *) OpCodeData)->DefaultId, sizeof (EFI_DEFAULT_ID)); + break; + + case EFI_IFR_REF_OP: + CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm); + + CopyMem (&CurrentStatement->RefFormId, &((EFI_IFR_REF *) OpCodeData)->FormId, sizeof (EFI_FORM_ID)); + if (OpCodeLength >= sizeof (EFI_IFR_REF2)) { + CopyMem (&CurrentStatement->RefQuestionId, &((EFI_IFR_REF2 *) OpCodeData)->QuestionId, sizeof (EFI_QUESTION_ID)); + + if (OpCodeLength >= sizeof (EFI_IFR_REF3)) { + CopyMem (&CurrentStatement->RefFormSetId, &((EFI_IFR_REF3 *) OpCodeData)->FormSetId, sizeof (EFI_GUID)); + + if (OpCodeLength >= sizeof (EFI_IFR_REF4)) { + CopyMem (&CurrentStatement->RefDevicePath, &((EFI_IFR_REF4 *) OpCodeData)->DevicePath, sizeof (EFI_STRING_ID)); + } + } + } + break; + + case EFI_IFR_ONE_OF_OP: + case EFI_IFR_NUMERIC_OP: + CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm); + + CurrentStatement->Flags = ((EFI_IFR_ONE_OF *) OpCodeData)->Flags; + Value = &CurrentStatement->HiiValue; + + switch (CurrentStatement->Flags & EFI_IFR_NUMERIC_SIZE) { + case EFI_IFR_NUMERIC_SIZE_1: + CurrentStatement->Minimum = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u8.MinValue; + CurrentStatement->Maximum = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u8.MaxValue; + CurrentStatement->Step = ((EFI_IFR_NUMERIC *) OpCodeData)->data.u8.Step; + CurrentStatement->StorageWidth = sizeof (UINT8); + Value->Type = EFI_IFR_TYPE_NUM_SIZE_8; + break; + + case EFI_IFR_NUMERIC_SIZE_2: + CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u16.MinValue, sizeof (UINT16)); + CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u16.MaxValue, sizeof (UINT16)); + CopyMem (&CurrentStatement->Step, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u16.Step, sizeof (UINT16)); + CurrentStatement->StorageWidth = sizeof (UINT16); + Value->Type = EFI_IFR_TYPE_NUM_SIZE_16; + break; + + case EFI_IFR_NUMERIC_SIZE_4: + CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.MinValue, sizeof (UINT32)); + CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.MaxValue, sizeof (UINT32)); + CopyMem (&CurrentStatement->Step, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u32.Step, sizeof (UINT32)); + CurrentStatement->StorageWidth = sizeof (UINT32); + Value->Type = EFI_IFR_TYPE_NUM_SIZE_32; + break; + + case EFI_IFR_NUMERIC_SIZE_8: + CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u64.MinValue, sizeof (UINT64)); + CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u64.MaxValue, sizeof (UINT64)); + CopyMem (&CurrentStatement->Step, &((EFI_IFR_NUMERIC *) OpCodeData)->data.u64.Step, sizeof (UINT64)); + CurrentStatement->StorageWidth = sizeof (UINT64); + Value->Type = EFI_IFR_TYPE_NUM_SIZE_64; + break; + + default: + break; + } + + InitializeRequestElement (FormSet, CurrentStatement); + + if ((Operand == EFI_IFR_ONE_OF_OP) && Scope) { + SuppressForOption = TRUE; + } + break; + + case EFI_IFR_ORDERED_LIST_OP: + CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm); + + CurrentStatement->Flags = ((EFI_IFR_ORDERED_LIST *) OpCodeData)->Flags; + CurrentStatement->MaxContainers = ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers; + CurrentStatement->StorageWidth = (UINT16)(CurrentStatement->MaxContainers * sizeof (UINT8)); + InitializeRequestElement (FormSet, CurrentStatement); + + // + // No buffer type is defined in EFI_IFR_TYPE_VALUE, so a Configuration Driver + // has to use FormBrowser2.Callback() to retrieve the uncommited data for + // an interactive orderedlist (i.e. with EFI_IFR_FLAG_CALLBACK flag set). + // + CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_OTHER; + CurrentStatement->BufferValue = AllocateZeroPool (CurrentStatement->StorageWidth); + + if (Scope) { + SuppressForOption = TRUE; + } + break; + + case EFI_IFR_CHECKBOX_OP: + CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm); + + CurrentStatement->Flags = ((EFI_IFR_CHECKBOX *) OpCodeData)->Flags; + CurrentStatement->StorageWidth = sizeof (BOOLEAN); + CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_BOOLEAN; + + InitializeRequestElement (FormSet, CurrentStatement); + break; + + case EFI_IFR_STRING_OP: + CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm); + + // + // MinSize is the minimum number of characters that can be accepted for this opcode, + // MaxSize is the maximum number of characters that can be accepted for this opcode. + // The characters are stored as Unicode, so the storage width should multiply 2. + // + CurrentStatement->Minimum = ((EFI_IFR_STRING *) OpCodeData)->MinSize; + CurrentStatement->Maximum = ((EFI_IFR_STRING *) OpCodeData)->MaxSize; + CurrentStatement->StorageWidth = (UINT16)((UINTN) CurrentStatement->Maximum * sizeof (UINT16)); + CurrentStatement->Flags = ((EFI_IFR_STRING *) OpCodeData)->Flags; + + CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_STRING; + CurrentStatement->BufferValue = AllocateZeroPool (CurrentStatement->StorageWidth); + + InitializeRequestElement (FormSet, CurrentStatement); + break; + + case EFI_IFR_PASSWORD_OP: + CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm); + + // + // MinSize is the minimum number of characters that can be accepted for this opcode, + // MaxSize is the maximum number of characters that can be accepted for this opcode. + // The characters are stored as Unicode, so the storage width should multiply 2. + // + CopyMem (&CurrentStatement->Minimum, &((EFI_IFR_PASSWORD *) OpCodeData)->MinSize, sizeof (UINT16)); + CopyMem (&CurrentStatement->Maximum, &((EFI_IFR_PASSWORD *) OpCodeData)->MaxSize, sizeof (UINT16)); + CurrentStatement->StorageWidth = (UINT16)((UINTN) CurrentStatement->Maximum * sizeof (UINT16)); + + CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_STRING; + CurrentStatement->BufferValue = AllocateZeroPool (CurrentStatement->StorageWidth); + + InitializeRequestElement (FormSet, CurrentStatement); + break; + + case EFI_IFR_DATE_OP: + CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm); + + CurrentStatement->Flags = ((EFI_IFR_DATE *) OpCodeData)->Flags; + CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_DATE; + + if ((CurrentStatement->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_NORMAL) { + CurrentStatement->StorageWidth = sizeof (EFI_HII_DATE); + + InitializeRequestElement (FormSet, CurrentStatement); + } else { + // + // Don't assign storage for RTC type of date/time + // + CurrentStatement->Storage = NULL; + CurrentStatement->StorageWidth = 0; + } + break; + + case EFI_IFR_TIME_OP: + CurrentStatement = CreateQuestion (OpCodeData, FormSet, CurrentForm); + + CurrentStatement->Flags = ((EFI_IFR_TIME *) OpCodeData)->Flags; + CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_TIME; + + if ((CurrentStatement->Flags & QF_TIME_STORAGE) == QF_TIME_STORAGE_NORMAL) { + CurrentStatement->StorageWidth = sizeof (EFI_IFR_TIME); + + InitializeRequestElement (FormSet, CurrentStatement); + } else { + // + // Don't assign storage for RTC type of date/time + // + CurrentStatement->Storage = NULL; + CurrentStatement->StorageWidth = 0; + } + break; + + // + // Default + // + case EFI_IFR_DEFAULT_OP: + // + // EFI_IFR_DEFAULT appear in scope of a Question, + // It creates a default value for the current question. + // A Question may have more than one Default value which have different default types. + // + CurrentDefault = AllocateZeroPool (sizeof (QUESTION_DEFAULT)); + CurrentDefault->Signature = QUESTION_DEFAULT_SIGNATURE; + + CurrentDefault->Value.Type = ((EFI_IFR_DEFAULT *) OpCodeData)->Type; + CopyMem (&CurrentDefault->DefaultId, &((EFI_IFR_DEFAULT *) OpCodeData)->DefaultId, sizeof (UINT16)); + CopyMem (&CurrentDefault->Value.Value, &((EFI_IFR_DEFAULT *) OpCodeData)->Value, sizeof (EFI_IFR_TYPE_VALUE)); + ExtendValueToU64 (&CurrentDefault->Value); + + // + // Insert to Default Value list of current Question + // + InsertTailList (&CurrentStatement->DefaultListHead, &CurrentDefault->Link); + + if (Scope) { + InScopeDefault = TRUE; + } + break; + + // + // Option + // + case EFI_IFR_ONE_OF_OPTION_OP: + // + // EFI_IFR_ONE_OF_OPTION appear in scope of a Question. + // It create a selection for use in current Question. + // + CurrentOption = AllocateZeroPool (sizeof (QUESTION_OPTION)); + CurrentOption->Signature = QUESTION_OPTION_SIGNATURE; + + CurrentOption->Flags = ((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Flags; + CurrentOption->Value.Type = ((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Type; + CopyMem (&CurrentOption->Text, &((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Option, sizeof (EFI_STRING_ID)); + CopyMem (&CurrentOption->Value.Value, &((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Value, sizeof (EFI_IFR_TYPE_VALUE)); + ExtendValueToU64 (&CurrentOption->Value); + + if (InScopeOptionSuppress) { + CurrentOption->SuppressExpression = OptionSuppressExpression; + } + + // + // Insert to Option list of current Question + // + InsertTailList (&CurrentStatement->OptionListHead, &CurrentOption->Link); + break; + + // + // Conditional + // + case EFI_IFR_NO_SUBMIT_IF_OP: + case EFI_IFR_INCONSISTENT_IF_OP: + // + // Create an Expression node + // + CurrentExpression = CreateExpression (CurrentForm); + CopyMem (&CurrentExpression->Error, &((EFI_IFR_INCONSISTENT_IF *) OpCodeData)->Error, sizeof (EFI_STRING_ID)); + + if (Operand == EFI_IFR_NO_SUBMIT_IF_OP) { + CurrentExpression->Type = EFI_HII_EXPRESSION_NO_SUBMIT_IF; + InsertTailList (&CurrentStatement->NoSubmitListHead, &CurrentExpression->Link); + } else { + CurrentExpression->Type = EFI_HII_EXPRESSION_INCONSISTENT_IF; + InsertTailList (&CurrentStatement->InconsistentListHead, &CurrentExpression->Link); + } + break; + + case EFI_IFR_SUPPRESS_IF_OP: + // + // Question and Option will appear in scope of this OpCode + // + CurrentExpression = CreateExpression (CurrentForm); + CurrentExpression->Type = EFI_HII_EXPRESSION_SUPPRESS_IF; + InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link); + + if (SuppressForOption) { + InScopeOptionSuppress = TRUE; + OptionSuppressExpression = CurrentExpression; + } else { + mInScopeSuppress = TRUE; + mSuppressExpression = CurrentExpression; + } + break; + + case EFI_IFR_GRAY_OUT_IF_OP: + // + // Questions will appear in scope of this OpCode + // + CurrentExpression = CreateExpression (CurrentForm); + CurrentExpression->Type = EFI_HII_EXPRESSION_GRAY_OUT_IF; + InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link); + + mInScopeGrayOut = TRUE; + mGrayOutExpression = CurrentExpression; + break; + + case EFI_IFR_DISABLE_IF_OP: + // + // The DisableIf expression should only rely on constant, so it could be + // evaluated at initialization and it will not be queued + // + CurrentExpression = AllocateZeroPool (sizeof (FORM_EXPRESSION)); + CurrentExpression->Signature = FORM_EXPRESSION_SIGNATURE; + CurrentExpression->Type = EFI_HII_EXPRESSION_DISABLE_IF; + InitializeListHead (&CurrentExpression->OpCodeListHead); + + InScopeDisable = TRUE; + OpCodeDisabled = FALSE; + + // + // Take a look at next OpCode to see whether current expression consists + // of single OpCode + // + if (((EFI_IFR_OP_HEADER *) (OpCodeData + OpCodeLength))->Scope == 0) { + SingleOpCodeExpression = TRUE; + } + break; + + // + // Expression + // + case EFI_IFR_VALUE_OP: + CurrentExpression = CreateExpression (CurrentForm); + CurrentExpression->Type = EFI_HII_EXPRESSION_VALUE; + InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link); + + if (InScopeDefault) { + // + // Used for default (EFI_IFR_DEFAULT) + // + CurrentDefault->ValueExpression = CurrentExpression; + } else { + // + // If used for a question, then the question will be read-only + // + CurrentStatement->ValueExpression = CurrentExpression; + } + break; + + case EFI_IFR_RULE_OP: + CurrentExpression = CreateExpression (CurrentForm); + CurrentExpression->Type = EFI_HII_EXPRESSION_RULE; + + CurrentExpression->RuleId = ((EFI_IFR_RULE *) OpCodeData)->RuleId; + InsertTailList (&CurrentForm->ExpressionListHead, &CurrentExpression->Link); + break; + + // + // Image + // + case EFI_IFR_IMAGE_OP: + // + // Get ScopeOpcode from top of stack + // + PopScope (&ScopeOpCode); + PushScope (ScopeOpCode); + + switch (ScopeOpCode) { + case EFI_IFR_FORM_SET_OP: + ImageId = &FormSet->ImageId; + break; + + case EFI_IFR_FORM_OP: + ImageId = &CurrentForm->ImageId; + break; + + case EFI_IFR_ONE_OF_OPTION_OP: + ImageId = &CurrentOption->ImageId; + break; + + default: + ImageId = &CurrentStatement->ImageId; + break; + } + + CopyMem (ImageId, &((EFI_IFR_IMAGE *) OpCodeData)->Id, sizeof (EFI_IMAGE_ID)); + break; + + // + // Refresh + // + case EFI_IFR_REFRESH_OP: + CurrentStatement->RefreshInterval = ((EFI_IFR_REFRESH *) OpCodeData)->RefreshInterval; + break; + + // + // Vendor specific + // + case EFI_IFR_GUID_OP: + if (CompareGuid (&gTianoHiiIfrGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) { + // + // Tiano specific GUIDed opcodes + // + switch (((EFI_IFR_GUID_LABEL *) OpCodeData)->ExtendOpCode) { + case EFI_IFR_EXTEND_OP_LABEL: + // + // just ignore label + // + break; + + case EFI_IFR_EXTEND_OP_BANNER: + if (FormSet->SubClass == EFI_FRONT_PAGE_SUBCLASS) { + CopyMem ( + &BannerData->Banner[((EFI_IFR_GUID_BANNER *) OpCodeData)->LineNumber][ + ((EFI_IFR_GUID_BANNER *) OpCodeData)->Alignment], + &((EFI_IFR_GUID_BANNER *) OpCodeData)->Title, + sizeof (EFI_STRING_ID) + ); + } + break; + + case EFI_IFR_EXTEND_OP_CLASS: + CopyMem (&FormSet->Class, &((EFI_IFR_GUID_CLASS *) OpCodeData)->Class, sizeof (UINT16)); + break; + + case EFI_IFR_EXTEND_OP_SUBCLASS: + CopyMem (&FormSet->SubClass, &((EFI_IFR_GUID_SUBCLASS *) OpCodeData)->SubClass, sizeof (UINT16)); + break; + + default: + break; + } + } + break; + + // + // Scope End + // + case EFI_IFR_END_OP: + Status = PopScope (&ScopeOpCode); + if (EFI_ERROR (Status)) { + ResetScopeStack (); + return Status; + } + + switch (ScopeOpCode) { + case EFI_IFR_FORM_SET_OP: + // + // End of FormSet, update FormSet IFR binary length + // to stop parsing substantial OpCodes + // + FormSet->IfrBinaryLength = OpCodeOffset; + break; + + case EFI_IFR_FORM_OP: + // + // End of Form + // + CurrentForm = NULL; + break; + + case EFI_IFR_ONE_OF_OPTION_OP: + // + // End of Option + // + CurrentOption = NULL; + break; + + case EFI_IFR_SUBTITLE_OP: + mInScopeSubtitle = FALSE; + break; + + case EFI_IFR_NO_SUBMIT_IF_OP: + case EFI_IFR_INCONSISTENT_IF_OP: + // + // Ignore end of EFI_IFR_NO_SUBMIT_IF and EFI_IFR_INCONSISTENT_IF + // + break; + + case EFI_IFR_SUPPRESS_IF_OP: + if (SuppressForOption) { + InScopeOptionSuppress = FALSE; + } else { + mInScopeSuppress = FALSE; + } + break; + + case EFI_IFR_GRAY_OUT_IF_OP: + mInScopeGrayOut = FALSE; + break; + + case EFI_IFR_DISABLE_IF_OP: + InScopeDisable = FALSE; + OpCodeDisabled = FALSE; + break; + + case EFI_IFR_ONE_OF_OP: + case EFI_IFR_ORDERED_LIST_OP: + SuppressForOption = FALSE; + break; + + case EFI_IFR_DEFAULT_OP: + InScopeDefault = FALSE; + break; + + default: + if (IsExpressionOpCode (ScopeOpCode)) { + if (InScopeDisable) { + // + // Evaluate DisableIf expression + // + Status = EvaluateExpression (FormSet, CurrentForm, CurrentExpression); + if (EFI_ERROR (Status)) { + return Status; + } + if (CurrentExpression->Result.Type != EFI_IFR_TYPE_BOOLEAN) { + return EFI_INVALID_PARAMETER; + } + + OpCodeDisabled = CurrentExpression->Result.Value.b; + // + // DisableIf Expression is only used once and not quequed, free it + // + DestroyExpression (CurrentExpression); + } + + // + // End of current Expression + // + CurrentExpression = NULL; + } + break; + } + break; + + default: + break; + } + } + + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/InputHandler.c b/MdeModulePkg/Universal/SetupBrowserDxe/InputHandler.c new file mode 100644 index 0000000000..5257f32b66 --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/InputHandler.c @@ -0,0 +1,1146 @@ +/** @file + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. 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. + +Module Name: + + InputHandler.c + +Abstract: + + Implementation for handling user input from the User Interface + +Revision History + + +**/ + +#include "Ui.h" +#include "Setup.h" + + +/** + Get string or password input from user. + + @param MenuOption Pointer to the current input menu. + @param Prompt The prompt string shown on popup window. + @param StringPtr Destination for use input string. + + @retval EFI_SUCCESS If string input is read successfully + @retval EFI_DEVICE_ERROR If operation fails + +**/ +EFI_STATUS +ReadString ( + IN UI_MENU_OPTION *MenuOption, + IN CHAR16 *Prompt, + OUT CHAR16 *StringPtr + ) +{ + EFI_STATUS Status; + EFI_INPUT_KEY Key; + CHAR16 NullCharacter; + UINTN ScreenSize; + CHAR16 Space[2]; + CHAR16 KeyPad[2]; + CHAR16 *TempString; + CHAR16 *BufferedString; + UINTN Index; + UINTN Count; + UINTN Start; + UINTN Top; + UINTN DimensionsWidth; + UINTN DimensionsHeight; + BOOLEAN CursorVisible; + UINTN Minimum; + UINTN Maximum; + FORM_BROWSER_STATEMENT *Question; + BOOLEAN IsPassword; + + DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn; + DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow; + + NullCharacter = CHAR_NULL; + ScreenSize = GetStringWidth (Prompt) / sizeof (CHAR16); + Space[0] = L' '; + Space[1] = CHAR_NULL; + + Question = MenuOption->ThisTag; + Minimum = (UINTN) Question->Minimum; + Maximum = (UINTN) Question->Maximum; + + if (Question->Operand == EFI_IFR_PASSWORD_OP) { + IsPassword = TRUE; + } else { + IsPassword = FALSE; + } + + TempString = AllocateZeroPool ((Maximum + 1)* sizeof (CHAR16)); + ASSERT (TempString); + + if (ScreenSize < (Maximum + 1)) { + ScreenSize = Maximum + 1; + } + + if ((ScreenSize + 2) > DimensionsWidth) { + ScreenSize = DimensionsWidth - 2; + } + + BufferedString = AllocateZeroPool (ScreenSize * 2); + ASSERT (BufferedString); + + Start = (DimensionsWidth - ScreenSize - 2) / 2 + gScreenDimensions.LeftColumn + 1; + Top = ((DimensionsHeight - 6) / 2) + gScreenDimensions.TopRow - 1; + + // + // Display prompt for string + // + CreatePopUp (ScreenSize, 4, &NullCharacter, Prompt, Space, &NullCharacter); + + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY)); + + CursorVisible = gST->ConOut->Mode->CursorVisible; + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + + do { + Status = WaitForKeyStroke (&Key); + ASSERT_EFI_ERROR (Status); + + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY)); + switch (Key.UnicodeChar) { + case CHAR_NULL: + switch (Key.ScanCode) { + case SCAN_LEFT: + break; + + case SCAN_RIGHT: + break; + + case SCAN_ESC: + gBS->FreePool (TempString); + gBS->FreePool (BufferedString); + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->EnableCursor (gST->ConOut, CursorVisible); + return EFI_DEVICE_ERROR; + + default: + break; + } + + break; + + case CHAR_CARRIAGE_RETURN: + if (GetStringWidth (StringPtr) >= ((Minimum + 1) * sizeof (CHAR16))) { + + gBS->FreePool (TempString); + gBS->FreePool (BufferedString); + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->EnableCursor (gST->ConOut, CursorVisible); + return EFI_SUCCESS; + } else { + // + // Simply create a popup to tell the user that they had typed in too few characters. + // To save code space, we can then treat this as an error and return back to the menu. + // + do { + CreateDialog (4, TRUE, 0, NULL, &Key, &NullCharacter, gMiniString, gPressEnter, &NullCharacter); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + + gBS->FreePool (TempString); + gBS->FreePool (BufferedString); + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->EnableCursor (gST->ConOut, CursorVisible); + return EFI_DEVICE_ERROR; + } + + break; + + case CHAR_BACKSPACE: + if (StringPtr[0] != CHAR_NULL) { + for (Index = 0; StringPtr[Index] != CHAR_NULL; Index++) { + TempString[Index] = StringPtr[Index]; + } + // + // Effectively truncate string by 1 character + // + TempString[Index - 1] = CHAR_NULL; + StrCpy (StringPtr, TempString); + } + + default: + // + // If it is the beginning of the string, don't worry about checking maximum limits + // + if ((StringPtr[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) { + StrnCpy (StringPtr, &Key.UnicodeChar, 1); + StrnCpy (TempString, &Key.UnicodeChar, 1); + } else if ((GetStringWidth (StringPtr) < ((Maximum + 1) * sizeof (CHAR16))) && (Key.UnicodeChar != CHAR_BACKSPACE)) { + KeyPad[0] = Key.UnicodeChar; + KeyPad[1] = CHAR_NULL; + StrCat (StringPtr, KeyPad); + StrCat (TempString, KeyPad); + } + + // + // If the width of the input string is now larger than the screen, we nee to + // adjust the index to start printing portions of the string + // + SetUnicodeMem (BufferedString, ScreenSize - 1, L' '); + PrintStringAt (Start + 1, Top + 3, BufferedString); + + if ((GetStringWidth (StringPtr) / 2) > (DimensionsWidth - 2)) { + Index = (GetStringWidth (StringPtr) / 2) - DimensionsWidth + 2; + } else { + Index = 0; + } + + if (IsPassword) { + gST->ConOut->SetCursorPosition (gST->ConOut, Start + 1, Top + 3); + } + + for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) { + BufferedString[Count] = StringPtr[Index]; + + if (IsPassword) { + PrintChar (L'*'); + } + } + + if (!IsPassword) { + PrintStringAt (Start + 1, Top + 3, BufferedString); + } + break; + } + + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->SetCursorPosition (gST->ConOut, Start + GetStringWidth (StringPtr) / 2, Top + 3); + } while (TRUE); + +} + + +/** + This routine reads a numeric value from the user input. + + @param Selection Pointer to current selection. + @param MenuOption Pointer to the current input menu. + + @retval EFI_SUCCESS If numerical input is read successfully + @retval EFI_DEVICE_ERROR If operation fails + +**/ +EFI_STATUS +GetNumericInput ( + IN UI_MENU_SELECTION *Selection, + IN UI_MENU_OPTION *MenuOption + ) +{ + EFI_STATUS Status; + UINTN Column; + UINTN Row; + CHAR16 InputText[23]; + CHAR16 FormattedNumber[22]; + UINT64 PreviousNumber[20]; + UINTN Count; + UINTN Loop; + BOOLEAN ManualInput; + BOOLEAN HexInput; + BOOLEAN DateOrTime; + UINTN InputWidth; + UINT64 EditValue; + UINT64 Step; + UINT64 Minimum; + UINT64 Maximum; + UINTN EraseLen; + UINT8 Digital; + EFI_INPUT_KEY Key; + EFI_HII_VALUE *QuestionValue; + FORM_BROWSER_FORM *Form; + FORM_BROWSER_FORMSET *FormSet; + FORM_BROWSER_STATEMENT *Question; + + Column = MenuOption->OptCol; + Row = MenuOption->Row; + PreviousNumber[0] = 0; + Count = 0; + InputWidth = 0; + Digital = 0; + + FormSet = Selection->FormSet; + Form = Selection->Form; + Question = MenuOption->ThisTag; + QuestionValue = &Question->HiiValue; + Step = Question->Step; + Minimum = Question->Minimum; + Maximum = Question->Maximum; + + if ((Question->Operand == EFI_IFR_DATE_OP) || (Question->Operand == EFI_IFR_TIME_OP)) { + DateOrTime = TRUE; + } else { + DateOrTime = FALSE; + } + + // + // Prepare Value to be edit + // + EraseLen = 0; + EditValue = 0; + if (Question->Operand == EFI_IFR_DATE_OP) { + Step = 1; + Minimum = 1; + + switch (MenuOption->Sequence) { + case 0: + Maximum = 12; + EraseLen = 4; + EditValue = QuestionValue->Value.date.Month; + break; + + case 1: + Maximum = 31; + EraseLen = 3; + EditValue = QuestionValue->Value.date.Day; + break; + + case 2: + Maximum = 0xffff; + EraseLen = 5; + EditValue = QuestionValue->Value.date.Year; + break; + + default: + break; + } + } else if (Question->Operand == EFI_IFR_TIME_OP) { + Step = 1; + Minimum = 0; + + switch (MenuOption->Sequence) { + case 0: + Maximum = 23; + EraseLen = 4; + EditValue = QuestionValue->Value.time.Hour; + break; + + case 1: + Maximum = 59; + EraseLen = 3; + EditValue = QuestionValue->Value.time.Minute; + break; + + case 2: + Maximum = 59; + EraseLen = 3; + EditValue = QuestionValue->Value.time.Second; + break; + + default: + break; + } + } else { + // + // Numeric + // + EraseLen = gOptionBlockWidth; + EditValue = QuestionValue->Value.u64; + if (Maximum == 0) { + Maximum = (UINT64) -1; + } + } + + if (Step == 0) { + ManualInput = TRUE; + } else { + ManualInput = FALSE; + } + + if ((Question->Operand == EFI_IFR_NUMERIC_OP) && + ((Question->Flags & EFI_IFR_DISPLAY) == EFI_IFR_DISPLAY_UINT_HEX)) { + HexInput = TRUE; + } else { + HexInput = FALSE; + } + + if (ManualInput) { + if (HexInput) { + InputWidth = Question->StorageWidth * 2; + } else { + switch (Question->StorageWidth) { + case 1: + InputWidth = 3; + break; + + case 2: + InputWidth = 5; + break; + + case 4: + InputWidth = 10; + break; + + case 8: + InputWidth = 20; + break; + + default: + InputWidth = 0; + break; + } + } + + InputText[0] = LEFT_NUMERIC_DELIMITER; + SetUnicodeMem (InputText + 1, InputWidth, L' '); + InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER; + InputText[InputWidth + 2] = L'\0'; + + PrintAt (Column, Row, InputText); + Column++; + } + + // + // First time we enter this handler, we need to check to see if + // we were passed an increment or decrement directive + // + do { + Key.UnicodeChar = CHAR_NULL; + if (gDirection != 0) { + Key.ScanCode = gDirection; + gDirection = 0; + goto TheKey2; + } + + Status = WaitForKeyStroke (&Key); + +TheKey2: + switch (Key.UnicodeChar) { + + case '+': + case '-': + if (Key.UnicodeChar == '+') { + Key.ScanCode = SCAN_RIGHT; + } else { + Key.ScanCode = SCAN_LEFT; + } + Key.UnicodeChar = CHAR_NULL; + goto TheKey2; + + case CHAR_NULL: + switch (Key.ScanCode) { + case SCAN_LEFT: + case SCAN_RIGHT: + if (DateOrTime) { + // + // By setting this value, we will return back to the caller. + // We need to do this since an auto-refresh will destroy the adjustment + // based on what the real-time-clock is showing. So we always commit + // upon changing the value. + // + gDirection = SCAN_DOWN; + } + + if (!ManualInput) { + if (Key.ScanCode == SCAN_LEFT) { + if (EditValue > Step) { + EditValue = EditValue - Step; + } else { + EditValue = Minimum; + } + } else if (Key.ScanCode == SCAN_RIGHT) { + EditValue = EditValue + Step; + if (EditValue > Maximum) { + EditValue = Maximum; + } + } + + ZeroMem (FormattedNumber, 21 * sizeof (CHAR16)); + if (Question->Operand == EFI_IFR_DATE_OP) { + if (MenuOption->Sequence == 2) { + // + // Year + // + UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%04d", EditValue); + } else { + // + // Month/Day + // + UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", EditValue); + } + + if (MenuOption->Sequence == 0) { + FormattedNumber[EraseLen - 2] = DATE_SEPARATOR; + } else if (MenuOption->Sequence == 1) { + FormattedNumber[EraseLen - 1] = DATE_SEPARATOR; + } + } else if (Question->Operand == EFI_IFR_TIME_OP) { + UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", EditValue); + + if (MenuOption->Sequence == 0) { + FormattedNumber[EraseLen - 2] = TIME_SEPARATOR; + } else if (MenuOption->Sequence == 1) { + FormattedNumber[EraseLen - 1] = TIME_SEPARATOR; + } + } else { + QuestionValue->Value.u64 = EditValue; + PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16)); + } + + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); + for (Loop = 0; Loop < EraseLen; Loop++) { + PrintAt (MenuOption->OptCol + Loop, MenuOption->Row, L" "); + } + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT); + + if (MenuOption->Sequence == 0) { + PrintCharAt (MenuOption->OptCol, Row, LEFT_NUMERIC_DELIMITER); + Column = MenuOption->OptCol + 1; + } + + PrintStringAt (Column, Row, FormattedNumber); + + if (!DateOrTime || MenuOption->Sequence == 2) { + PrintChar (RIGHT_NUMERIC_DELIMITER); + } + } + break; + + case SCAN_UP: + case SCAN_DOWN: + goto EnterCarriageReturn; + + case SCAN_ESC: + return EFI_DEVICE_ERROR; + + default: + break; + } + + break; + +EnterCarriageReturn: + + case CHAR_CARRIAGE_RETURN: + // + // Store Edit value back to Question + // + if (Question->Operand == EFI_IFR_DATE_OP) { + switch (MenuOption->Sequence) { + case 0: + QuestionValue->Value.date.Month = (UINT8) EditValue; + break; + + case 1: + QuestionValue->Value.date.Day = (UINT8) EditValue; + break; + + case 2: + QuestionValue->Value.date.Year = (UINT16) EditValue; + break; + + default: + break; + } + } else if (Question->Operand == EFI_IFR_TIME_OP) { + switch (MenuOption->Sequence) { + case 0: + QuestionValue->Value.time.Hour = (UINT8) EditValue; + break; + + case 1: + QuestionValue->Value.time.Minute = (UINT8) EditValue; + break; + + case 2: + QuestionValue->Value.time.Second = (UINT8) EditValue; + break; + + default: + break; + } + } else { + // + // Numeric + // + QuestionValue->Value.u64 = EditValue; + } + + // + // Check to see if the Value is something reasonable against consistency limitations. + // If not, let's kick the error specified. + // + Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF); + if (EFI_ERROR (Status)) { + // + // Input value is not valid, restore Question Value + // + GetQuestionValue (FormSet, Form, Question, TRUE); + } else { + SetQuestionValue (FormSet, Form, Question, TRUE); + if (!DateOrTime || (Question->Storage != NULL)) { + // + // NV flag is unnecessary for RTC type of Date/Time + // + UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE); + } + } + + return Status; + break; + + case CHAR_BACKSPACE: + if (ManualInput) { + if (Count == 0) { + break; + } + // + // Remove a character + // + EditValue = PreviousNumber[Count - 1]; + UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, FALSE); + Count--; + Column--; + PrintAt (Column, Row, L" "); + } + break; + + default: + if (ManualInput) { + if (HexInput) { + if (!R8_IsHexDigit (&Digital, Key.UnicodeChar)) { + UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, TRUE); + break; + } + } else { + if (Key.UnicodeChar > L'9' || Key.UnicodeChar < L'0') { + UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, TRUE); + break; + } + } + + // + // If Count exceed input width, there is no way more is valid + // + if (Count >= InputWidth) { + break; + } + // + // Someone typed something valid! + // + if (Count != 0) { + if (HexInput) { + EditValue = LShiftU64 (EditValue, 4) + Digital; + } else { + EditValue = MultU64x32 (EditValue, 10) + (Key.UnicodeChar - L'0'); + } + } else { + if (HexInput) { + EditValue = Digital; + } else { + EditValue = Key.UnicodeChar - L'0'; + } + } + + if (EditValue > Maximum) { + UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, TRUE); + EditValue = PreviousNumber[Count]; + break; + } else { + UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, FALSE); + } + + Count++; + PreviousNumber[Count] = EditValue; + + PrintCharAt (Column, Row, Key.UnicodeChar); + Column++; + } + break; + } + } while (TRUE); + +} + + +/** + Get selection for OneOf and OrderedList (Left/Right will be ignored). + + @param Selection Pointer to current selection. + @param MenuOption Pointer to the current input menu. + + @retval EFI_SUCCESS If Option input is processed successfully + @retval EFI_DEVICE_ERROR If operation fails + +**/ +EFI_STATUS +GetSelectionInputPopUp ( + IN UI_MENU_SELECTION *Selection, + IN UI_MENU_OPTION *MenuOption + ) +{ + EFI_STATUS Status; + EFI_INPUT_KEY Key; + UINTN Index; + CHAR16 *StringPtr; + CHAR16 *TempStringPtr; + UINTN Index2; + UINTN TopOptionIndex; + UINTN HighlightOptionIndex; + UINTN Start; + UINTN End; + UINTN Top; + UINTN Bottom; + UINTN PopUpMenuLines; + UINTN MenuLinesInView; + UINTN PopUpWidth; + CHAR16 Character; + INT32 SavedAttribute; + BOOLEAN ShowDownArrow; + BOOLEAN ShowUpArrow; + UINTN DimensionsWidth; + LIST_ENTRY *Link; + BOOLEAN OrderedList; + UINT8 *ValueArray; + EFI_HII_VALUE HiiValue; + EFI_HII_VALUE *HiiValueArray; + UINTN OptionCount; + QUESTION_OPTION *OneOfOption; + QUESTION_OPTION *CurrentOption; + FORM_BROWSER_STATEMENT *Question; + + DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn; + + ValueArray = NULL; + CurrentOption = NULL; + ShowDownArrow = FALSE; + ShowUpArrow = FALSE; + + StringPtr = AllocateZeroPool ((gOptionBlockWidth + 1) * 2); + ASSERT (StringPtr); + + Question = MenuOption->ThisTag; + if (Question->Operand == EFI_IFR_ORDERED_LIST_OP) { + ValueArray = Question->BufferValue; + OrderedList = TRUE; + } else { + OrderedList = FALSE; + } + + // + // Calculate Option count + // + if (OrderedList) { + for (Index = 0; Index < Question->MaxContainers; Index++) { + if (ValueArray[Index] == 0) { + break; + } + } + + OptionCount = Index; + } else { + OptionCount = 0; + Link = GetFirstNode (&Question->OptionListHead); + while (!IsNull (&Question->OptionListHead, Link)) { + OneOfOption = QUESTION_OPTION_FROM_LINK (Link); + + OptionCount++; + + Link = GetNextNode (&Question->OptionListHead, Link); + } + } + + // + // Prepare HiiValue array + // + HiiValueArray = AllocateZeroPool (OptionCount * sizeof (EFI_HII_VALUE)); + ASSERT (HiiValueArray != NULL); + Link = GetFirstNode (&Question->OptionListHead); + for (Index = 0; Index < OptionCount; Index++) { + if (OrderedList) { + HiiValueArray[Index].Type = EFI_IFR_TYPE_NUM_SIZE_8; + HiiValueArray[Index].Value.u8 = ValueArray[Index]; + } else { + OneOfOption = QUESTION_OPTION_FROM_LINK (Link); + CopyMem (&HiiValueArray[Index], &OneOfOption->Value, sizeof (EFI_HII_VALUE)); + Link = GetNextNode (&Question->OptionListHead, Link); + } + } + + // + // Move Suppressed Option to list tail + // + PopUpMenuLines = 0; + for (Index = 0; Index < OptionCount; Index++) { + OneOfOption = ValueToOption (Question, &HiiValueArray[OptionCount - Index - 1]); + if (OneOfOption == NULL) { + return EFI_NOT_FOUND; + } + + RemoveEntryList (&OneOfOption->Link); + + if ((OneOfOption->SuppressExpression != NULL) && + (OneOfOption->SuppressExpression->Result.Value.b)) { + // + // This option is suppressed, insert to tail + // + InsertTailList (&Question->OptionListHead, &OneOfOption->Link); + } else { + // + // Insert to head + // + InsertHeadList (&Question->OptionListHead, &OneOfOption->Link); + + PopUpMenuLines++; + } + } + + // + // Get the number of one of options present and its size + // + PopUpWidth = 0; + HighlightOptionIndex = 0; + Link = GetFirstNode (&Question->OptionListHead); + for (Index = 0; Index < PopUpMenuLines; Index++) { + OneOfOption = QUESTION_OPTION_FROM_LINK (Link); + + StringPtr = GetToken (OneOfOption->Text, MenuOption->Handle); + if (StrLen (StringPtr) > PopUpWidth) { + PopUpWidth = StrLen (StringPtr); + } + gBS->FreePool (StringPtr); + + if (!OrderedList && CompareHiiValue (&Question->HiiValue, &OneOfOption->Value, NULL) == 0) { + // + // Find current selected Option for OneOf + // + HighlightOptionIndex = Index; + } + + Link = GetNextNode (&Question->OptionListHead, Link); + } + + // + // Perform popup menu initialization. + // + PopUpWidth = PopUpWidth + POPUP_PAD_SPACE_COUNT; + + SavedAttribute = gST->ConOut->Mode->Attribute; + gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND); + + if ((PopUpWidth + POPUP_FRAME_WIDTH) > DimensionsWidth) { + PopUpWidth = DimensionsWidth - POPUP_FRAME_WIDTH; + } + + Start = (DimensionsWidth - PopUpWidth - POPUP_FRAME_WIDTH) / 2 + gScreenDimensions.LeftColumn; + End = Start + PopUpWidth + POPUP_FRAME_WIDTH; + Top = gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT; + Bottom = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT - 1; + + MenuLinesInView = Bottom - Top - 1; + if (MenuLinesInView >= PopUpMenuLines) { + Top = Top + (MenuLinesInView - PopUpMenuLines) / 2; + Bottom = Top + PopUpMenuLines + 1; + } else { + ShowDownArrow = TRUE; + } + + if (HighlightOptionIndex > (MenuLinesInView - 1)) { + TopOptionIndex = HighlightOptionIndex - MenuLinesInView + 1; + } else { + TopOptionIndex = 0; + } + + do { + // + // Clear that portion of the screen + // + ClearLines (Start, End, Top, Bottom, POPUP_TEXT | POPUP_BACKGROUND); + + // + // Draw "One of" pop-up menu + // + Character = BOXDRAW_DOWN_RIGHT; + PrintCharAt (Start, Top, Character); + for (Index = Start; Index + 2 < End; Index++) { + if ((ShowUpArrow) && ((Index + 1) == (Start + End) / 2)) { + Character = GEOMETRICSHAPE_UP_TRIANGLE; + } else { + Character = BOXDRAW_HORIZONTAL; + } + + PrintChar (Character); + } + + Character = BOXDRAW_DOWN_LEFT; + PrintChar (Character); + Character = BOXDRAW_VERTICAL; + for (Index = Top + 1; Index < Bottom; Index++) { + PrintCharAt (Start, Index, Character); + PrintCharAt (End - 1, Index, Character); + } + + // + // Move to top Option + // + Link = GetFirstNode (&Question->OptionListHead); + for (Index = 0; Index < TopOptionIndex; Index++) { + Link = GetNextNode (&Question->OptionListHead, Link); + } + + // + // Display the One of options + // + Index2 = Top + 1; + for (Index = TopOptionIndex; (Index < PopUpMenuLines) && (Index2 < Bottom); Index++) { + OneOfOption = QUESTION_OPTION_FROM_LINK (Link); + Link = GetNextNode (&Question->OptionListHead, Link); + + StringPtr = GetToken (OneOfOption->Text, MenuOption->Handle); + // + // If the string occupies multiple lines, truncate it to fit in one line, + // and append a "..." for indication. + // + if (StrLen (StringPtr) > (PopUpWidth - 1)) { + TempStringPtr = AllocateZeroPool (sizeof (CHAR16) * (PopUpWidth - 1)); + ASSERT ( TempStringPtr != NULL ); + CopyMem (TempStringPtr, StringPtr, (sizeof (CHAR16) * (PopUpWidth - 5))); + gBS->FreePool (StringPtr); + StringPtr = TempStringPtr; + StrCat (StringPtr, L"..."); + } + + if (Index == HighlightOptionIndex) { + // + // Highlight the selected one + // + CurrentOption = OneOfOption; + + gST->ConOut->SetAttribute (gST->ConOut, PICKLIST_HIGHLIGHT_TEXT | PICKLIST_HIGHLIGHT_BACKGROUND); + PrintStringAt (Start + 2, Index2, StringPtr); + gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND); + } else { + gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND); + PrintStringAt (Start + 2, Index2, StringPtr); + } + + Index2++; + gBS->FreePool (StringPtr); + } + + Character = BOXDRAW_UP_RIGHT; + PrintCharAt (Start, Bottom, Character); + for (Index = Start; Index + 2 < End; Index++) { + if ((ShowDownArrow) && ((Index + 1) == (Start + End) / 2)) { + Character = GEOMETRICSHAPE_DOWN_TRIANGLE; + } else { + Character = BOXDRAW_HORIZONTAL; + } + + PrintChar (Character); + } + + Character = BOXDRAW_UP_LEFT; + PrintChar (Character); + + // + // Get User selection + // + Key.UnicodeChar = CHAR_NULL; + if ((gDirection == SCAN_UP) || (gDirection == SCAN_DOWN)) { + Key.ScanCode = gDirection; + gDirection = 0; + goto TheKey; + } + + Status = WaitForKeyStroke (&Key); + +TheKey: + switch (Key.UnicodeChar) { + case '+': + if (OrderedList) { + if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) { + // + // Highlight reaches the top of the popup window, scroll one menu item. + // + TopOptionIndex--; + ShowDownArrow = TRUE; + } + + if (TopOptionIndex == 0) { + ShowUpArrow = FALSE; + } + + if (HighlightOptionIndex > 0) { + HighlightOptionIndex--; + + SwapListEntries (CurrentOption->Link.BackLink, &CurrentOption->Link); + } + } + break; + + case '-': + // + // If an ordered list op-code, we will allow for a popup of +/- keys + // to create an ordered list of items + // + if (OrderedList) { + if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) && + (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) { + // + // Highlight reaches the bottom of the popup window, scroll one menu item. + // + TopOptionIndex++; + ShowUpArrow = TRUE; + } + + if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) { + ShowDownArrow = FALSE; + } + + if (HighlightOptionIndex < (PopUpMenuLines - 1)) { + HighlightOptionIndex++; + + SwapListEntries (&CurrentOption->Link, CurrentOption->Link.ForwardLink); + } + } + break; + + case CHAR_NULL: + switch (Key.ScanCode) { + case SCAN_UP: + case SCAN_DOWN: + if (Key.ScanCode == SCAN_UP) { + if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) { + // + // Highlight reaches the top of the popup window, scroll one menu item. + // + TopOptionIndex--; + ShowDownArrow = TRUE; + } + + if (TopOptionIndex == 0) { + ShowUpArrow = FALSE; + } + + if (HighlightOptionIndex > 0) { + HighlightOptionIndex--; + } + } else { + if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) && + (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) { + // + // Highlight reaches the bottom of the popup window, scroll one menu item. + // + TopOptionIndex++; + ShowUpArrow = TRUE; + } + + if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) { + ShowDownArrow = FALSE; + } + + if (HighlightOptionIndex < (PopUpMenuLines - 1)) { + HighlightOptionIndex++; + } + } + break; + + case SCAN_ESC: + gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute); + + // + // Restore link list order for orderedlist + // + if (OrderedList) { + HiiValue.Type = EFI_IFR_TYPE_NUM_SIZE_8; + HiiValue.Value.u64 = 0; + for (Index = 0; Index < Question->MaxContainers; Index++) { + HiiValue.Value.u8 = ValueArray[Index]; + if (HiiValue.Value.u8) { + break; + } + + OneOfOption = ValueToOption (Question, &HiiValue); + if (OneOfOption == NULL) { + return EFI_NOT_FOUND; + } + + RemoveEntryList (&OneOfOption->Link); + InsertTailList (&Question->OptionListHead, &OneOfOption->Link); + } + } + + gBS->FreePool (HiiValueArray); + return EFI_DEVICE_ERROR; + + default: + break; + } + + break; + + case CHAR_CARRIAGE_RETURN: + // + // return the current selection + // + if (OrderedList) { + Index = 0; + Link = GetFirstNode (&Question->OptionListHead); + while (!IsNull (&Question->OptionListHead, Link)) { + OneOfOption = QUESTION_OPTION_FROM_LINK (Link); + + Question->BufferValue[Index] = OneOfOption->Value.Value.u8; + + Index++; + if (Index > Question->MaxContainers) { + break; + } + + Link = GetNextNode (&Question->OptionListHead, Link); + } + } else { + CopyMem (&Question->HiiValue, &CurrentOption->Value, sizeof (EFI_HII_VALUE)); + } + + gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute); + gBS->FreePool (HiiValueArray); + + Status = ValidateQuestion (Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF); + if (EFI_ERROR (Status)) { + // + // Input value is not valid, restore Question Value + // + GetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE); + } else { + SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE); + UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE); + } + + return Status; + + default: + break; + } + } while (TRUE); + +} + +EFI_STATUS +WaitForKeyStroke ( + OUT EFI_INPUT_KEY *Key + ) +{ + EFI_STATUS Status; + + do { + UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0, 0); + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, Key); + } while (EFI_ERROR(Status)); + + return Status; +} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c b/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c new file mode 100644 index 0000000000..631f6413b8 --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c @@ -0,0 +1,928 @@ +/** @file +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. 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. + +Module Name: + Presentation.c + +Abstract: + + Some presentation routines. + + +**/ + +#include "Setup.h" +#include "Ui.h" + +BOOLEAN mHiiPackageListUpdated; +UI_MENU_SELECTION *gCurrentSelection; + + +/** + Clear retangle with specified text attribute. + + @param LeftColumn Left column of retangle. + @param RightColumn Right column of retangle. + @param TopRow Start row of retangle. + @param BottomRow End row of retangle. + @param TextAttribute The character foreground and background. + + @return None. + +**/ +VOID +ClearLines ( + UINTN LeftColumn, + UINTN RightColumn, + UINTN TopRow, + UINTN BottomRow, + UINTN TextAttribute + ) +{ + CHAR16 *Buffer; + UINTN Row; + + // + // For now, allocate an arbitrarily long buffer + // + Buffer = AllocateZeroPool (0x10000); + ASSERT (Buffer != NULL); + + // + // Set foreground and background as defined + // + gST->ConOut->SetAttribute (gST->ConOut, TextAttribute); + + // + // Much faster to buffer the long string instead of print it a character at a time + // + SetUnicodeMem (Buffer, RightColumn - LeftColumn, L' '); + + // + // Clear the desired area with the appropriate foreground/background + // + for (Row = TopRow; Row <= BottomRow; Row++) { + PrintStringAt (LeftColumn, Row, Buffer); + } + + gST->ConOut->SetCursorPosition (gST->ConOut, LeftColumn, TopRow); + + gBS->FreePool (Buffer); + return ; +} + +VOID +NewStrCat ( + CHAR16 *Destination, + CHAR16 *Source + ) +{ + UINTN Length; + + for (Length = 0; Destination[Length] != 0; Length++) + ; + + // + // We now have the length of the original string + // We can safely assume for now that we are concatenating a narrow value to this string. + // For instance, the string is "XYZ" and cat'ing ">" + // If this assumption changes, we need to make this routine a bit more complex + // + Destination[Length] = NARROW_CHAR; + Length++; + + StrCpy (Destination + Length, Source); +} + +UINTN +GetStringWidth ( + CHAR16 *String + ) +{ + UINTN Index; + UINTN Count; + UINTN IncrementValue; + + Index = 0; + Count = 0; + IncrementValue = 1; + + do { + // + // Advance to the null-terminator or to the first width directive + // + for (; + (String[Index] != NARROW_CHAR) && (String[Index] != WIDE_CHAR) && (String[Index] != 0); + Index++, Count = Count + IncrementValue + ) + ; + + // + // We hit the null-terminator, we now have a count + // + if (String[Index] == 0) { + break; + } + // + // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed + // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2) + // + if (String[Index] == NARROW_CHAR) { + // + // Skip to the next character + // + Index++; + IncrementValue = 1; + } else { + // + // Skip to the next character + // + Index++; + IncrementValue = 2; + } + } while (String[Index] != 0); + + // + // Increment by one to include the null-terminator in the size + // + Count++; + + return Count * sizeof (CHAR16); +} + +VOID +DisplayPageFrame ( + VOID + ) +{ + UINTN Index; + UINT8 Line; + UINT8 Alignment; + CHAR16 Character; + CHAR16 *Buffer; + CHAR16 *StrFrontPageBanner; + UINTN Row; + EFI_SCREEN_DESCRIPTOR LocalScreen; + + ZeroMem (&LocalScreen, sizeof (EFI_SCREEN_DESCRIPTOR)); + gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &LocalScreen.RightColumn, &LocalScreen.BottomRow); + ClearLines (0, LocalScreen.RightColumn, 0, LocalScreen.BottomRow, KEYHELP_BACKGROUND); + + CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + + // + // For now, allocate an arbitrarily long buffer + // + Buffer = AllocateZeroPool (0x10000); + ASSERT (Buffer != NULL); + + Character = BOXDRAW_HORIZONTAL; + + for (Index = 0; Index + 2 < (LocalScreen.RightColumn - LocalScreen.LeftColumn); Index++) { + Buffer[Index] = Character; + } + + if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) { + // + // ClearLines(0, LocalScreen.RightColumn, 0, BANNER_HEIGHT-1, BANNER_TEXT | BANNER_BACKGROUND); + // + ClearLines ( + LocalScreen.LeftColumn, + LocalScreen.RightColumn, + LocalScreen.TopRow, + FRONT_PAGE_HEADER_HEIGHT - 1 + LocalScreen.TopRow, + BANNER_TEXT | BANNER_BACKGROUND + ); + // + // for (Line = 0; Line < BANNER_HEIGHT; Line++) { + // + for (Line = (UINT8) LocalScreen.TopRow; Line < BANNER_HEIGHT + (UINT8) LocalScreen.TopRow; Line++) { + // + // for (Alignment = 0; Alignment < BANNER_COLUMNS; Alignment++) { + // + for (Alignment = (UINT8) LocalScreen.LeftColumn; + Alignment < BANNER_COLUMNS + (UINT8) LocalScreen.LeftColumn; + Alignment++ + ) { + if (BannerData->Banner[Line - (UINT8) LocalScreen.TopRow][Alignment - (UINT8) LocalScreen.LeftColumn] != 0x0000) { + StrFrontPageBanner = GetToken ( + BannerData->Banner[Line - (UINT8) LocalScreen.TopRow][Alignment - (UINT8) LocalScreen.LeftColumn], + FrontPageHandle + ); + } else { + continue; + } + + switch (Alignment - LocalScreen.LeftColumn) { + case 0: + // + // Handle left column + // + PrintStringAt (LocalScreen.LeftColumn, Line, StrFrontPageBanner); + break; + + case 1: + // + // Handle center column + // + PrintStringAt ( + LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3, + Line, + StrFrontPageBanner + ); + break; + + case 2: + // + // Handle right column + // + PrintStringAt ( + LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) * 2 / 3, + Line, + StrFrontPageBanner + ); + break; + } + + gBS->FreePool (StrFrontPageBanner); + } + } + } + + ClearLines ( + LocalScreen.LeftColumn, + LocalScreen.RightColumn, + LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT, + LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 1, + KEYHELP_TEXT | KEYHELP_BACKGROUND + ); + + if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) { + ClearLines ( + LocalScreen.LeftColumn, + LocalScreen.RightColumn, + LocalScreen.TopRow, + LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 1, + TITLE_TEXT | TITLE_BACKGROUND + ); + // + // Print Top border line + // +------------------------------------------------------------------------------+ + // ? ? + // +------------------------------------------------------------------------------+ + // + Character = BOXDRAW_DOWN_RIGHT; + + PrintChar (Character); + PrintString (Buffer); + + Character = BOXDRAW_DOWN_LEFT; + PrintChar (Character); + + Character = BOXDRAW_VERTICAL; + for (Row = LocalScreen.TopRow + 1; Row <= LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 2; Row++) { + PrintCharAt (LocalScreen.LeftColumn, Row, Character); + PrintCharAt (LocalScreen.RightColumn - 1, Row, Character); + } + + Character = BOXDRAW_UP_RIGHT; + PrintCharAt (LocalScreen.LeftColumn, LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 1, Character); + PrintString (Buffer); + + Character = BOXDRAW_UP_LEFT; + PrintChar (Character); + + if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) { + // + // Print Bottom border line + // +------------------------------------------------------------------------------+ + // ? ? + // +------------------------------------------------------------------------------+ + // + Character = BOXDRAW_DOWN_RIGHT; + PrintCharAt (LocalScreen.LeftColumn, LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT, Character); + + PrintString (Buffer); + + Character = BOXDRAW_DOWN_LEFT; + PrintChar (Character); + Character = BOXDRAW_VERTICAL; + for (Row = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT + 1; + Row <= LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 2; + Row++ + ) { + PrintCharAt (LocalScreen.LeftColumn, Row, Character); + PrintCharAt (LocalScreen.RightColumn - 1, Row, Character); + } + + Character = BOXDRAW_UP_RIGHT; + PrintCharAt (LocalScreen.LeftColumn, LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 1, Character); + + PrintString (Buffer); + + Character = BOXDRAW_UP_LEFT; + PrintChar (Character); + } + } + + gBS->FreePool (Buffer); + +} + + +/** + Evaluate all expressions in a Form. + + @param FormSet FormSet this Form belongs to. + @param Form The Form. + + @retval EFI_SUCCESS The expression evaluated successfuly + +**/ +EFI_STATUS +EvaluateFormExpressions ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + FORM_EXPRESSION *Expression; + + Link = GetFirstNode (&Form->ExpressionListHead); + while (!IsNull (&Form->ExpressionListHead, Link)) { + Expression = FORM_EXPRESSION_FROM_LINK (Link); + Link = GetNextNode (&Form->ExpressionListHead, Link); + + if (Expression->Type == EFI_HII_EXPRESSION_INCONSISTENT_IF || + Expression->Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) { + // + // Postpone Form validation to Question editing or Form submiting + // + continue; + } + + Status = EvaluateExpression (FormSet, Form, Expression); + if (EFI_ERROR (Status)) { + return Status; + } + } + + return EFI_SUCCESS; +} + +/* ++------------------------------------------------------------------------------+ +?F2=Previous Page Setup Page ? ++------------------------------------------------------------------------------+ + + + + + + + + + + + + + + + + + ++------------------------------------------------------------------------------+ +?F1=Scroll Help F9=Reset to Defaults F10=Save and Exit ? +| ^"=Move Highlight <Spacebar> Toggles Checkbox Esc=Discard Changes | ++------------------------------------------------------------------------------+ +*/ +EFI_STATUS +DisplayForm ( + IN OUT UI_MENU_SELECTION *Selection + ) +{ + CHAR16 *StringPtr; + UINT16 MenuItemCount; + EFI_HII_HANDLE Handle; + BOOLEAN Suppress; + EFI_SCREEN_DESCRIPTOR LocalScreen; + UINT16 Width; + UINTN ArrayEntry; + CHAR16 *OutputString; + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Statement; + UINT16 NumberOfLines; + EFI_STATUS Status; + + Handle = Selection->Handle; + MenuItemCount = 0; + ArrayEntry = 0; + OutputString = NULL; + + UiInitMenu (); + + CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + + StringPtr = GetToken (Selection->FormSet->FormSetTitle, Handle); + + if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) { + gST->ConOut->SetAttribute (gST->ConOut, TITLE_TEXT | TITLE_BACKGROUND); + PrintStringAt ( + (LocalScreen.RightColumn + LocalScreen.LeftColumn - GetStringWidth (StringPtr) / 2) / 2, + LocalScreen.TopRow + 1, + StringPtr + ); + } + + if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) { + gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_TEXT | KEYHELP_BACKGROUND); + + // + // Display the infrastructure strings + // + if (!IsListEmpty (&gMenuList)) { + PrintStringAt (LocalScreen.LeftColumn + 2, LocalScreen.TopRow + 1, gFunctionTwoString); + } + + PrintStringAt (LocalScreen.LeftColumn + 2, LocalScreen.BottomRow - 4, gFunctionOneString); + PrintStringAt ( + LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3, + LocalScreen.BottomRow - 4, + gFunctionNineString + ); + PrintStringAt ( + LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) * 2 / 3, + LocalScreen.BottomRow - 4, + gFunctionTenString + ); + PrintAt (LocalScreen.LeftColumn + 2, LocalScreen.BottomRow - 3, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); + PrintStringAt ( + LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3, + LocalScreen.BottomRow - 3, + gEscapeString + ); + } + // + // Remove Buffer allocated for StringPtr after it has been used. + // + gBS->FreePool (StringPtr); + + // + // Evaluate all the Expressions in this Form + // + Status = EvaluateFormExpressions (Selection->FormSet, Selection->Form); + if (EFI_ERROR (Status)) { + return Status; + } + + Link = GetFirstNode (&Selection->Form->StatementListHead); + while (!IsNull (&Selection->Form->StatementListHead, Link)) { + Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + + if (Statement->SuppressExpression != NULL) { + Suppress = Statement->SuppressExpression->Result.Value.b; + } else { + Suppress = FALSE; + } + + if (!Suppress) { + StringPtr = GetToken (Statement->Prompt, Handle); + + Width = GetWidth (Statement, Handle); + + NumberOfLines = 1; + ArrayEntry = 0; + for (; GetLineByWidth (StringPtr, Width, &ArrayEntry, &OutputString) != 0x0000;) { + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&StringPtr[ArrayEntry])) { + NumberOfLines++; + } + + gBS->FreePool (OutputString); + } + + // + // We are NOT!! removing this StringPtr buffer via FreePool since it is being used in the menuoptions, we will do + // it in UiFreeMenu. + // + UiAddMenuOption (StringPtr, Selection->Handle, Statement, NumberOfLines, MenuItemCount); + MenuItemCount++; + } + + Link = GetNextNode (&Selection->Form->StatementListHead, Link); + } + + Status = UiDisplayMenu (Selection); + + UiFreeMenu (); + + return Status; +} + +VOID +InitializeBrowserStrings ( + VOID + ) +{ + gFunctionOneString = GetToken (STRING_TOKEN (FUNCTION_ONE_STRING), gHiiHandle); + gFunctionTwoString = GetToken (STRING_TOKEN (FUNCTION_TWO_STRING), gHiiHandle); + gFunctionNineString = GetToken (STRING_TOKEN (FUNCTION_NINE_STRING), gHiiHandle); + gFunctionTenString = GetToken (STRING_TOKEN (FUNCTION_TEN_STRING), gHiiHandle); + gEnterString = GetToken (STRING_TOKEN (ENTER_STRING), gHiiHandle); + gEnterCommitString = GetToken (STRING_TOKEN (ENTER_COMMIT_STRING), gHiiHandle); + gEscapeString = GetToken (STRING_TOKEN (ESCAPE_STRING), gHiiHandle); + gSaveFailed = GetToken (STRING_TOKEN (SAVE_FAILED), gHiiHandle); + gMoveHighlight = GetToken (STRING_TOKEN (MOVE_HIGHLIGHT), gHiiHandle); + gMakeSelection = GetToken (STRING_TOKEN (MAKE_SELECTION), gHiiHandle); + gDecNumericInput = GetToken (STRING_TOKEN (DEC_NUMERIC_INPUT), gHiiHandle); + gHexNumericInput = GetToken (STRING_TOKEN (HEX_NUMERIC_INPUT), gHiiHandle); + gToggleCheckBox = GetToken (STRING_TOKEN (TOGGLE_CHECK_BOX), gHiiHandle); + gPromptForData = GetToken (STRING_TOKEN (PROMPT_FOR_DATA), gHiiHandle); + gPromptForPassword = GetToken (STRING_TOKEN (PROMPT_FOR_PASSWORD), gHiiHandle); + gPromptForNewPassword = GetToken (STRING_TOKEN (PROMPT_FOR_NEW_PASSWORD), gHiiHandle); + gConfirmPassword = GetToken (STRING_TOKEN (CONFIRM_PASSWORD), gHiiHandle); + gConfirmError = GetToken (STRING_TOKEN (CONFIRM_ERROR), gHiiHandle); + gPassowordInvalid = GetToken (STRING_TOKEN (PASSWORD_INVALID), gHiiHandle); + gPressEnter = GetToken (STRING_TOKEN (PRESS_ENTER), gHiiHandle); + gEmptyString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); + gAreYouSure = GetToken (STRING_TOKEN (ARE_YOU_SURE), gHiiHandle); + gYesResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_YES), gHiiHandle); + gNoResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_NO), gHiiHandle); + gMiniString = GetToken (STRING_TOKEN (MINI_STRING), gHiiHandle); + gPlusString = GetToken (STRING_TOKEN (PLUS_STRING), gHiiHandle); + gMinusString = GetToken (STRING_TOKEN (MINUS_STRING), gHiiHandle); + gAdjustNumber = GetToken (STRING_TOKEN (ADJUST_NUMBER), gHiiHandle); + return ; +} + +VOID +FreeBrowserStrings ( + VOID + ) +{ + SafeFreePool (gFunctionOneString); + SafeFreePool (gFunctionTwoString); + SafeFreePool (gFunctionNineString); + SafeFreePool (gFunctionTenString); + SafeFreePool (gEnterString); + SafeFreePool (gEnterCommitString); + SafeFreePool (gEscapeString); + SafeFreePool (gMoveHighlight); + SafeFreePool (gMakeSelection); + SafeFreePool (gDecNumericInput); + SafeFreePool (gHexNumericInput); + SafeFreePool (gToggleCheckBox); + SafeFreePool (gPromptForData); + SafeFreePool (gPromptForPassword); + SafeFreePool (gPromptForNewPassword); + SafeFreePool (gConfirmPassword); + SafeFreePool (gPassowordInvalid); + SafeFreePool (gConfirmError); + SafeFreePool (gPressEnter); + SafeFreePool (gEmptyString); + SafeFreePool (gAreYouSure); + SafeFreePool (gYesResponse); + SafeFreePool (gNoResponse); + SafeFreePool (gMiniString); + SafeFreePool (gPlusString); + SafeFreePool (gMinusString); + SafeFreePool (gAdjustNumber); + return ; +} + + +/** + Update key's help imformation + + @param MenuOption The Menu option + @param Selected Whether or not a tag be selected + + @return None + +**/ +VOID +UpdateKeyHelp ( + IN UI_MENU_OPTION *MenuOption, + IN BOOLEAN Selected + ) +{ + UINTN SecCol; + UINTN ThdCol; + UINTN LeftColumnOfHelp; + UINTN RightColumnOfHelp; + UINTN TopRowOfHelp; + UINTN BottomRowOfHelp; + UINTN StartColumnOfHelp; + EFI_SCREEN_DESCRIPTOR LocalScreen; + FORM_BROWSER_STATEMENT *Statement; + + CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + + SecCol = LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3; + ThdCol = LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) * 2 / 3; + + StartColumnOfHelp = LocalScreen.LeftColumn + 2; + LeftColumnOfHelp = LocalScreen.LeftColumn + 1; + RightColumnOfHelp = LocalScreen.RightColumn - 2; + TopRowOfHelp = LocalScreen.BottomRow - 4; + BottomRowOfHelp = LocalScreen.BottomRow - 3; + + if (gClassOfVfr == EFI_GENERAL_APPLICATION_SUBCLASS) { + return ; + } + + gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_TEXT | KEYHELP_BACKGROUND); + + Statement = MenuOption->ThisTag; + switch (Statement->Operand) { + case EFI_IFR_ORDERED_LIST_OP: + case EFI_IFR_ONE_OF_OP: + case EFI_IFR_NUMERIC_OP: + case EFI_IFR_TIME_OP: + case EFI_IFR_DATE_OP: + ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND); + + if (!Selected) { + if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) { + PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gFunctionOneString); + PrintStringAt (SecCol, TopRowOfHelp, gFunctionNineString); + PrintStringAt (ThdCol, TopRowOfHelp, gFunctionTenString); + PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); + } + + if ((Statement->Operand == EFI_IFR_DATE_OP) || + (Statement->Operand == EFI_IFR_TIME_OP) || + (Statement->Operand == EFI_IFR_NUMERIC_OP && Statement->Step != 0)) { + PrintAt ( + StartColumnOfHelp, + BottomRowOfHelp, + L"%c%c%c%c%s", + ARROW_UP, + ARROW_DOWN, + ARROW_RIGHT, + ARROW_LEFT, + gMoveHighlight + ); + PrintStringAt (SecCol, BottomRowOfHelp, gAdjustNumber); + } else { + PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); + PrintStringAt (SecCol, BottomRowOfHelp, gEnterString); + } + } else { + PrintStringAt (SecCol, BottomRowOfHelp, gEnterCommitString); + + // + // If it is a selected numeric with manual input, display different message + // + if ((Statement->Operand == EFI_IFR_NUMERIC_OP) && (Statement->Step == 0)) { + PrintStringAt ( + SecCol, + TopRowOfHelp, + (Statement->Flags & EFI_IFR_DISPLAY_UINT_HEX) ? gHexNumericInput : gDecNumericInput + ); + } else if (Statement->Operand != EFI_IFR_ORDERED_LIST_OP) { + PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); + } + + if (Statement->Operand == EFI_IFR_ORDERED_LIST_OP) { + PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gPlusString); + PrintStringAt (ThdCol, TopRowOfHelp, gMinusString); + } + + PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); + } + break; + + case EFI_IFR_CHECKBOX_OP: + ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND); + + if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) { + PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gFunctionOneString); + PrintStringAt (SecCol, TopRowOfHelp, gFunctionNineString); + PrintStringAt (ThdCol, TopRowOfHelp, gFunctionTenString); + PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); + } + + PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); + PrintStringAt (SecCol, BottomRowOfHelp, gToggleCheckBox); + break; + + case EFI_IFR_REF_OP: + case EFI_IFR_PASSWORD_OP: + case EFI_IFR_STRING_OP: + case EFI_IFR_TEXT_OP: + case EFI_IFR_ACTION_OP: + case EFI_IFR_RESET_BUTTON_OP: + ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND); + + if (!Selected) { + if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) { + PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gFunctionOneString); + PrintStringAt (SecCol, TopRowOfHelp, gFunctionNineString); + PrintStringAt (ThdCol, TopRowOfHelp, gFunctionTenString); + PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); + } + + PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); + if (Statement->Operand != EFI_IFR_TEXT_OP) { + PrintStringAt (SecCol, BottomRowOfHelp, gEnterString); + } + } else { + if (Statement->Operand != EFI_IFR_REF_OP) { + PrintStringAt ( + (LocalScreen.RightColumn - GetStringWidth (gEnterCommitString) / 2) / 2, + BottomRowOfHelp, + gEnterCommitString + ); + PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); + } + } + break; + + default: + break; + } +} + +EFI_STATUS +FormUpdateNotify ( + IN UINT8 PackageType, + IN CONST EFI_GUID *PackageGuid, + IN CONST EFI_HII_PACKAGE_HEADER *Package, + IN EFI_HII_HANDLE Handle, + IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType + ) +{ + mHiiPackageListUpdated = TRUE; + + return EFI_SUCCESS; +} + +EFI_STATUS +SetupBrowser ( + IN OUT UI_MENU_SELECTION *Selection + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + EFI_BROWSER_ACTION_REQUEST ActionRequest; + EFI_HANDLE NotifyHandle; + EFI_HII_VALUE *HiiValue; + FORM_BROWSER_STATEMENT *Statement; + EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; + + gMenuRefreshHead = NULL; + gResetRequired = FALSE; + gNvUpdateRequired = FALSE; + + UiInitMenuList (); + + // + // Register notify for Form package update + // + Status = mHiiDatabase->RegisterPackageNotify ( + mHiiDatabase, + EFI_HII_PACKAGE_FORM, + NULL, + FormUpdateNotify, + EFI_HII_DATABASE_NOTIFY_REMOVE_PACK, + &NotifyHandle + ); + if (EFI_ERROR (Status)) { + return Status; + } + + do { + // + // Displays the Header and Footer borders + // + DisplayPageFrame (); + + // + // Initialize Selection->Form + // + if (Selection->FormId == 0) { + // + // Zero FormId indicates display the first Form in a FormSet + // + Link = GetFirstNode (&Selection->FormSet->FormListHead); + + Selection->Form = FORM_BROWSER_FORM_FROM_LINK (Link); + Selection->FormId = Selection->Form->FormId; + } else { + Selection->Form = IdToForm (Selection->FormSet, Selection->FormId); + } + + // + // Load Questions' Value for display + // + Status = LoadFormConfig (Selection->FormSet, Selection->Form); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Display form + // + Status = DisplayForm (Selection); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Check Selected Statement (if press ESC, Selection->Statement will be NULL) + // + Statement = Selection->Statement; + if (Statement != NULL) { + if (Statement->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) { + gResetRequired = TRUE; + } + + // + // Reset FormPackage update flag + // + mHiiPackageListUpdated = FALSE; + + if (Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK && Statement->Operand != EFI_IFR_PASSWORD_OP) { + ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; + + HiiValue = &Statement->HiiValue; + if (HiiValue->Type == EFI_IFR_TYPE_STRING) { + // + // Create String in HII database for Configuration Driver to retrieve + // + HiiValue->Value.string = NewString ((CHAR16 *) Statement->BufferValue, Selection->FormSet->HiiHandle); + } + + ConfigAccess = Selection->FormSet->ConfigAccess; + if (ConfigAccess == NULL) { + return EFI_UNSUPPORTED; + } + Status = ConfigAccess->Callback ( + ConfigAccess, + EFI_BROWSER_ACTION_CHANGING, + Statement->QuestionId, + HiiValue->Type, + &HiiValue->Value, + &ActionRequest + ); + + if (HiiValue->Type == EFI_IFR_TYPE_STRING) { + // + // Clean the String in HII Database + // + DeleteString (HiiValue->Value.string, Selection->FormSet->HiiHandle); + } + + if (!EFI_ERROR (Status)) { + switch (ActionRequest) { + case EFI_BROWSER_ACTION_REQUEST_RESET: + gResetRequired = TRUE; + break; + + case EFI_BROWSER_ACTION_REQUEST_SUBMIT: + SubmitForm (Selection->FormSet, Selection->Form); + break; + + case EFI_BROWSER_ACTION_REQUEST_EXIT: + Selection->Action = UI_ACTION_EXIT; + gNvUpdateRequired = FALSE; + break; + + default: + break; + } + } + } + + // + // Check whether Form Package has been updated during Callback + // + if (mHiiPackageListUpdated && (Selection->Action == UI_ACTION_REFRESH_FORM)) { + // + // Force to reparse IFR binary of target Formset + // + Selection->Action = UI_ACTION_REFRESH_FORMSET; + } + } + } while (Selection->Action == UI_ACTION_REFRESH_FORM); + + // + // Unregister notify for Form package update + // + Status = mHiiDatabase->UnregisterPackageNotify ( + mHiiDatabase, + NotifyHandle + ); + return Status; +} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Print.c b/MdeModulePkg/Universal/SetupBrowserDxe/Print.c new file mode 100644 index 0000000000..6cc50c3ad5 --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Print.c @@ -0,0 +1,331 @@ +/** @file + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. 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. + +Module Name: + + Print.c + +Abstract: + + Basic Ascii AvSPrintf() function named VSPrint(). VSPrint() enables very + simple implemenation of SPrint() and Print() to support debug. + + You can not Print more than EFI_DRIVER_LIB_MAX_PRINT_BUFFER characters at a + time. This makes the implementation very simple. + + VSPrint, Print, SPrint format specification has the follwoing form + + %type + + type: + 'S','s' - argument is an Unicode string + 'c' - argument is an ascii character + '%' - Print a % + + +**/ + +//@MT:#include "Tiano.h" +//@MT:#include "EfiDriverLib.h" +//@MT:#include "EfiPrintLib.h" +//@MT:#include "EfiStdArg.h" +//@MT:#include "TianoHii.h" +#include "Setup.h" + +UINTN +ValueToString ( + IN OUT CHAR16 *Buffer, + IN BOOLEAN Flags, + IN INT64 Value + ); + +UINTN +PrintInternal ( + IN UINTN Column, + IN UINTN Row, + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Out, + IN CHAR16 *fmt, + IN VA_LIST args + ) +// +// Display string worker for: Print, PrintAt, IPrint, IPrintAt +// +{ + CHAR16 *Buffer; + CHAR16 *BackupBuffer; + UINTN Index; + UINTN PreviousIndex; + + // + // For now, allocate an arbitrarily long buffer + // + Buffer = AllocateZeroPool (0x10000); + BackupBuffer = AllocateZeroPool (0x10000); + ASSERT (Buffer); + ASSERT (BackupBuffer); + + if (Column != (UINTN) -1) { + Out->SetCursorPosition (Out, Column, Row); + } + + UnicodeVSPrint (Buffer, 0x10000, fmt, args); + + Out->Mode->Attribute = Out->Mode->Attribute & 0x7f; + + Out->SetAttribute (Out, Out->Mode->Attribute); + + Index = 0; + PreviousIndex = 0; + + do { + for (; (Buffer[Index] != NARROW_CHAR) && (Buffer[Index] != WIDE_CHAR) && (Buffer[Index] != 0); Index++) { + BackupBuffer[Index] = Buffer[Index]; + } + + if (Buffer[Index] == 0) { + break; + } + // + // Null-terminate the temporary string + // + BackupBuffer[Index] = 0; + + // + // Print this out, we are about to switch widths + // + Out->OutputString (Out, &BackupBuffer[PreviousIndex]); + + // + // Preserve the current index + 1, since this is where we will start printing from next + // + PreviousIndex = Index + 1; + + // + // We are at a narrow or wide character directive. Set attributes and strip it and print it + // + if (Buffer[Index] == NARROW_CHAR) { + // + // Preserve bits 0 - 6 and zero out the rest + // + Out->Mode->Attribute = Out->Mode->Attribute & 0x7f; + Out->SetAttribute (Out, Out->Mode->Attribute); + } else { + // + // Must be wide, set bit 7 ON + // + Out->Mode->Attribute = Out->Mode->Attribute | EFI_WIDE_ATTRIBUTE; + Out->SetAttribute (Out, Out->Mode->Attribute); + } + + Index++; + + } while (Buffer[Index] != 0); + + // + // We hit the end of the string - print it + // + Out->OutputString (Out, &BackupBuffer[PreviousIndex]); + + gBS->FreePool (Buffer); + gBS->FreePool (BackupBuffer); + return EFI_SUCCESS; +} + + +/** + Prints a formatted unicode string to the default console + + @param fmt Format string + + @return Length of string printed to the console + +**/ +UINTN +ConsolePrint ( + IN CHAR16 *fmt, + ... + ) +{ + VA_LIST args; + + VA_START (args, fmt); + return PrintInternal ((UINTN) -1, (UINTN) -1, gST->ConOut, fmt, args); +} + + +/** + Prints a unicode string to the default console, + using L"%s" format. + + @param String String pointer. + + @return Length of string printed to the console + +**/ +UINTN +PrintString ( + CHAR16 *String + ) +{ + return ConsolePrint (L"%s", String); +} + + +/** + Prints a chracter to the default console, + using L"%c" format. + + @param Character Character to print. + + @return Length of string printed to the console. + +**/ +UINTN +PrintChar ( + CHAR16 Character + ) +{ + return ConsolePrint (L"%c", Character); +} + + +/** + Prints a formatted unicode string to the default console, at + the supplied cursor position + + @param Row The cursor position to print the string at + @param fmt Format string + + @return Length of string printed to the console + +**/ +UINTN +PrintAt ( + IN UINTN Column, + IN UINTN Row, + IN CHAR16 *fmt, + ... + ) +{ + VA_LIST args; + + VA_START (args, fmt); + return PrintInternal (Column, Row, gST->ConOut, fmt, args); +} + + +/** + Prints a unicode string to the default console, at + the supplied cursor position, using L"%s" format. + + @param Row The cursor position to print the string at + @param String String pointer. + + @return Length of string printed to the console + +**/ +UINTN +PrintStringAt ( + IN UINTN Column, + IN UINTN Row, + CHAR16 *String + ) +{ + return PrintAt (Column, Row, L"%s", String); +} + + +/** + Prints a chracter to the default console, at + the supplied cursor position, using L"%c" format. + + @param Row The cursor position to print the string at + @param Character Character to print. + + @return Length of string printed to the console. + +**/ +UINTN +PrintCharAt ( + IN UINTN Column, + IN UINTN Row, + CHAR16 Character + ) +{ + return PrintAt (Column, Row, L"%c", Character); +} + + +/** + VSPrint worker function that prints a Value as a decimal number in Buffer + + @param Buffer Location to place ascii decimal number string of Value. + @param Value Decimal value to convert to a string in Buffer. + @param Flags Flags to use in printing decimal string, see file header for + details. + + @return Number of characters printed. + +**/ +UINTN +ValueToString ( + IN OUT CHAR16 *Buffer, + IN BOOLEAN Flags, + IN INT64 Value + ) +{ + CHAR16 TempBuffer[30]; + CHAR16 *TempStr; + CHAR16 *BufferPtr; + UINTN Count; + UINTN NumberCount; + UINT32 Remainder; + BOOLEAN Negative; + + Negative = FALSE; + TempStr = TempBuffer; + BufferPtr = Buffer; + Count = 0; + NumberCount = 0; + + if (Value < 0) { + Negative = TRUE; + Value = -Value; + } + + do { + Value = (INT64) DivU64x32Remainder ((UINT64) Value, 10, &Remainder); + *(TempStr++) = (CHAR16) (Remainder + '0'); + Count++; + NumberCount++; + if ((Flags & COMMA_TYPE) == COMMA_TYPE) { + if (NumberCount % 3 == 0 && Value != 0) { + *(TempStr++) = ','; + Count++; + } + } + } while (Value != 0); + + if (Negative) { + *(BufferPtr++) = '-'; + Count++; + } + + // + // Reverse temp string into Buffer. + // + while (TempStr != TempBuffer) { + *(BufferPtr++) = *(--TempStr); + } + + *BufferPtr = 0; + return Count; +} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Print.h b/MdeModulePkg/Universal/SetupBrowserDxe/Print.h new file mode 100644 index 0000000000..c473a26cfa --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Print.h @@ -0,0 +1,38 @@ +/** @file + +Copyright (c) 2004, Intel Corporation +All rights reserved. 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. + +Module Name: + + Print.h + +Abstract: + + Private data for Print.c + + +**/ + +#ifndef _PRINT_H_ +#define _PRINT_H_ + +#define LEFT_JUSTIFY 0x01 +#define PREFIX_SIGN 0x02 +#define PREFIX_BLANK 0x04 +#define COMMA_TYPE 0x08 +#define LONG_TYPE 0x10 +#define PREFIX_ZERO 0x20 + +// +// Largest number of characters that can be printed out. +// +#define EFI_DRIVER_LIB_MAX_PRINT_BUFFER (80 * 4) + +#endif diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/ProcessOptions.c b/MdeModulePkg/Universal/SetupBrowserDxe/ProcessOptions.c new file mode 100644 index 0000000000..ac9eeda777 --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/ProcessOptions.c @@ -0,0 +1,986 @@ +/** @file + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. 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. + +Module Name: + + ProcessOptions.c + +Abstract: + + Implementation for handling the User Interface option processing. + +Revision History + + +**/ + +#include "Ui.h" +#include "Setup.h" + + +/** + Process Question Config. + + @param Selection The UI menu selection. + @param Question The Question to be peocessed. + + @retval EFI_SUCCESS Question Config process success. + @retval Other Question Config process fail. + +**/ +EFI_STATUS +ProcessQuestionConfig ( + IN UI_MENU_SELECTION *Selection, + IN FORM_BROWSER_STATEMENT *Question + ) +{ + EFI_STATUS Status; + CHAR16 *ConfigResp; + CHAR16 *Progress; + EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; + + if (Question->QuestionConfig == 0) { + return EFI_SUCCESS; + } + + // + // Get <ConfigResp> + // + ConfigResp = GetToken (Question->QuestionConfig, Selection->FormSet->HiiHandle); + if (ConfigResp == NULL) { + return EFI_NOT_FOUND; + } + + // + // Send config to Configuration Driver + // + ConfigAccess = Selection->FormSet->ConfigAccess; + if (ConfigAccess == NULL) { + return EFI_UNSUPPORTED; + } + Status = ConfigAccess->RouteConfig ( + ConfigAccess, + ConfigResp, + &Progress + ); + + return Status; +} + + +/** + Search an Option of a Question by its value. + + @param Question The Question + @param OptionValue Value for Option to be searched. + + @retval Pointer Pointer to the found Option. + @retval NULL Option not found. + +**/ +QUESTION_OPTION * +ValueToOption ( + IN FORM_BROWSER_STATEMENT *Question, + IN EFI_HII_VALUE *OptionValue + ) +{ + LIST_ENTRY *Link; + QUESTION_OPTION *Option; + + Link = GetFirstNode (&Question->OptionListHead); + while (!IsNull (&Question->OptionListHead, Link)) { + Option = QUESTION_OPTION_FROM_LINK (Link); + + if (CompareHiiValue (&Option->Value, OptionValue, NULL) == 0) { + return Option; + } + + Link = GetNextNode (&Question->OptionListHead, Link); + } + + return NULL; +} + + +/** + Print Question Value according to it's storage width and display attributes. + + @param Event The event to wait for + @param FormattedNumber Buffer for output string. + @param BufferSize The FormattedNumber buffer size in bytes. + + @retval EFI_SUCCESS Print success. + @retval EFI_BUFFER_TOO_SMALL Buffer size is not enough for formatted number. + +**/ +EFI_STATUS +PrintFormattedNumber ( + IN FORM_BROWSER_STATEMENT *Question, + IN OUT CHAR16 *FormattedNumber, + IN UINTN BufferSize + ) +{ + INT64 Value; + CHAR16 *Format; + EFI_HII_VALUE *QuestionValue; + + if (BufferSize < (21 * sizeof (CHAR16))) { + return EFI_BUFFER_TOO_SMALL; + } + + QuestionValue = &Question->HiiValue; + + Value = (INT64) QuestionValue->Value.u64; + switch (Question->Flags & EFI_IFR_DISPLAY) { + case EFI_IFR_DISPLAY_INT_DEC: + switch (QuestionValue->Type) { + case EFI_IFR_NUMERIC_SIZE_1: + Value = (INT64) ((INT8) QuestionValue->Value.u8); + break; + + case EFI_IFR_NUMERIC_SIZE_2: + Value = (INT64) ((INT16) QuestionValue->Value.u16); + break; + + case EFI_IFR_NUMERIC_SIZE_4: + Value = (INT64) ((INT32) QuestionValue->Value.u32); + break; + + case EFI_IFR_NUMERIC_SIZE_8: + default: + break; + } + + if (Value < 0) { + Value = -Value; + Format = L"-%ld"; + } else { + Format = L"%ld"; + } + break; + + case EFI_IFR_DISPLAY_UINT_DEC: + Format = L"%ld"; + break; + + case EFI_IFR_DISPLAY_UINT_HEX: + Format = L"%lx"; + break; + + default: + return EFI_UNSUPPORTED; + break; + } + + UnicodeSPrint (FormattedNumber, BufferSize, Format, Value); + + return EFI_SUCCESS; +} + + +/** + Password may be stored as encrypted by Configuration Driver. When change a + password, user will be challenged with old password. To validate user input old + password, we will send the clear text to Configuration Driver via Callback(). + Configuration driver is responsible to check the passed in password and return + the validation result. If validation pass, state machine in password Callback() + will transit from BROWSER_STATE_VALIDATE_PASSWORD to BROWSER_STATE_SET_PASSWORD. + After user type in new password twice, Callback() will be invoked to send the + new password to Configuration Driver. + + @param Selection Pointer to UI_MENU_SELECTION. + @param MenuOption The MenuOption for this password Question. + @param String The clear text of password. + + @retval EFI_NOT_AVAILABLE_YET Callback() request to terminate password input. + @return In state of BROWSER_STATE_VALIDATE_PASSWORD: + @retval EFI_SUCCESS Password correct, Browser will prompt for new + password. + @retval EFI_NOT_READY Password incorrect, Browser will show error + message. + @retval Other Browser will do nothing. + @return In state of BROWSER_STATE_SET_PASSWORD: + @retval EFI_SUCCESS Set password success. + @retval Other Set password failed. + +**/ +EFI_STATUS +PasswordCallback ( + IN UI_MENU_SELECTION *Selection, + IN UI_MENU_OPTION *MenuOption, + IN CHAR16 *String + ) +{ + EFI_STATUS Status; + EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; + EFI_BROWSER_ACTION_REQUEST ActionRequest; + EFI_HII_VALUE *QuestionValue; + + QuestionValue = &MenuOption->ThisTag->HiiValue; + ConfigAccess = Selection->FormSet->ConfigAccess; + if (ConfigAccess == NULL) { + return EFI_UNSUPPORTED; + } + + // + // Prepare password string in HII database + // + if (String != NULL) { + QuestionValue->Value.string = NewString (String, Selection->FormSet->HiiHandle); + } else { + QuestionValue->Value.string = 0; + } + + // + // Send password to Configuration Driver for validation + // + Status = ConfigAccess->Callback ( + ConfigAccess, + EFI_BROWSER_ACTION_CHANGING, + MenuOption->ThisTag->QuestionId, + QuestionValue->Type, + &QuestionValue->Value, + &ActionRequest + ); + + // + // Remove password string from HII database + // + if (String != NULL) { + DeleteString (QuestionValue->Value.string, Selection->FormSet->HiiHandle); + } + + return Status; +} + + +/** + Display error message for invalid password. + + None. + + @return None. + +**/ +VOID +PasswordInvalid ( + VOID + ) +{ + EFI_INPUT_KEY Key; + + // + // Invalid password, prompt error message + // + do { + CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gPassowordInvalid, gPressEnter, gEmptyString); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); +} + + +/** + Process a Question's Option (whether selected or un-selected). + + @param Selection Pointer to UI_MENU_SELECTION. + @param MenuOption The MenuOption for this Question. + @param Selected TRUE: if Question is selected. + @param OptionString Pointer of the Option String to be displayed. + + @retval EFI_SUCCESS Question Option process success. + @retval Other Question Option process fail. + +**/ +EFI_STATUS +ProcessOptions ( + IN UI_MENU_SELECTION *Selection, + IN UI_MENU_OPTION *MenuOption, + IN BOOLEAN Selected, + OUT CHAR16 **OptionString + ) +{ + EFI_STATUS Status; + CHAR16 *StringPtr; + CHAR16 *TempString; + UINTN Index; + FORM_BROWSER_STATEMENT *Question; + CHAR16 FormattedNumber[21]; + UINT16 Number; + CHAR16 Character[2]; + EFI_INPUT_KEY Key; + UINTN BufferSize; + QUESTION_OPTION *OneOfOption; + LIST_ENTRY *Link; + EFI_HII_VALUE HiiValue; + EFI_HII_VALUE *QuestionValue; + BOOLEAN Suppress; + UINT16 Maximum; + + Status = EFI_SUCCESS; + + StringPtr = NULL; + Character[1] = L'\0'; + *OptionString = NULL; + + ZeroMem (FormattedNumber, 21 * sizeof (CHAR16)); + BufferSize = (gOptionBlockWidth + 1) * 2 * gScreenDimensions.BottomRow; + + Question = MenuOption->ThisTag; + QuestionValue = &Question->HiiValue; + Maximum = (UINT16) Question->Maximum; + + switch (Question->Operand) { + case EFI_IFR_ORDERED_LIST_OP: + // + // Initialize Option value array + // + if (Question->BufferValue[0] == 0) { + GetQuestionDefault (Selection->FormSet, Selection->Form, Question, 0); + } + + if (Selected) { + // + // Go ask for input + // + Status = GetSelectionInputPopUp (Selection, MenuOption); + } else { + // + // We now know how many strings we will have, so we can allocate the + // space required for the array or strings. + // + *OptionString = AllocateZeroPool (Question->MaxContainers * BufferSize); + ASSERT (*OptionString); + + HiiValue.Type = EFI_IFR_TYPE_NUM_SIZE_8; + HiiValue.Value.u64 = 0; + for (Index = 0; Index < Question->MaxContainers; Index++) { + HiiValue.Value.u8 = Question->BufferValue[Index]; + if (HiiValue.Value.u8 == 0) { + // + // Values for the options in ordered lists should never be a 0 + // + break; + } + + OneOfOption = ValueToOption (Question, &HiiValue); + if (OneOfOption == NULL) { + gBS->FreePool (*OptionString); + return EFI_NOT_FOUND; + } + + Suppress = FALSE; + if ((OneOfOption->SuppressExpression != NULL) && + (OneOfOption->SuppressExpression->Result.Value.b)) { + // + // This option is suppressed + // + Suppress = TRUE; + } + + if (!Suppress) { + Character[0] = LEFT_ONEOF_DELIMITER; + NewStrCat (OptionString[0], Character); + StringPtr = GetToken (OneOfOption->Text, Selection->Handle); + NewStrCat (OptionString[0], StringPtr); + Character[0] = RIGHT_ONEOF_DELIMITER; + NewStrCat (OptionString[0], Character); + Character[0] = CHAR_CARRIAGE_RETURN; + NewStrCat (OptionString[0], Character); + + gBS->FreePool (StringPtr); + } + } + } + break; + + case EFI_IFR_ONE_OF_OP: + if (Selected) { + // + // Go ask for input + // + Status = GetSelectionInputPopUp (Selection, MenuOption); + } else { + *OptionString = AllocateZeroPool (BufferSize); + ASSERT (*OptionString); + + OneOfOption = ValueToOption (Question, QuestionValue); + if (OneOfOption == NULL) { + gBS->FreePool (*OptionString); + return EFI_NOT_FOUND; + } + + if ((OneOfOption->SuppressExpression != NULL) && + (OneOfOption->SuppressExpression->Result.Value.b)) { + // + // This option is suppressed + // + Suppress = TRUE; + } else { + Suppress = FALSE; + } + + if (Suppress) { + // + // Current selected option happen to be suppressed, + // enforce to select on a non-suppressed option + // + Link = GetFirstNode (&Question->OptionListHead); + while (!IsNull (&Question->OptionListHead, Link)) { + OneOfOption = QUESTION_OPTION_FROM_LINK (Link); + + if ((OneOfOption->SuppressExpression == NULL) || + !OneOfOption->SuppressExpression->Result.Value.b) { + Suppress = FALSE; + CopyMem (QuestionValue, &OneOfOption->Value, sizeof (EFI_HII_VALUE)); + SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE); + break; + } + + Link = GetNextNode (&Question->OptionListHead, Link); + } + } + + if (!Suppress) { + Character[0] = LEFT_ONEOF_DELIMITER; + NewStrCat (OptionString[0], Character); + StringPtr = GetToken (OneOfOption->Text, Selection->Handle); + NewStrCat (OptionString[0], StringPtr); + Character[0] = RIGHT_ONEOF_DELIMITER; + NewStrCat (OptionString[0], Character); + + gBS->FreePool (StringPtr); + } + } + break; + + case EFI_IFR_CHECKBOX_OP: + *OptionString = AllocateZeroPool (BufferSize); + ASSERT (*OptionString); + + *OptionString[0] = LEFT_CHECKBOX_DELIMITER; + + if (Selected) { + // + // Since this is a BOOLEAN operation, flip it upon selection + // + QuestionValue->Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE); + + // + // Perform inconsistent check + // + Status = ValidateQuestion (Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF); + if (EFI_ERROR (Status)) { + // + // Inconsistent check fail, restore Question Value + // + QuestionValue->Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE); + gBS->FreePool (*OptionString); + return Status; + } + + // + // Save Question value + // + Status = SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE); + UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE); + } + + if (QuestionValue->Value.b) { + *(OptionString[0] + 1) = CHECK_ON; + } else { + *(OptionString[0] + 1) = CHECK_OFF; + } + *(OptionString[0] + 2) = RIGHT_CHECKBOX_DELIMITER; + break; + + case EFI_IFR_NUMERIC_OP: + if (Selected) { + // + // Go ask for input + // + Status = GetNumericInput (Selection, MenuOption); + } else { + *OptionString = AllocateZeroPool (BufferSize); + ASSERT (*OptionString); + + *OptionString[0] = LEFT_NUMERIC_DELIMITER; + + // + // Formatted print + // + PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16)); + Number = (UINT16) GetStringWidth (FormattedNumber); + CopyMem (OptionString[0] + 1, FormattedNumber, Number); + + *(OptionString[0] + Number / 2) = RIGHT_NUMERIC_DELIMITER; + } + break; + + case EFI_IFR_DATE_OP: + if (Selected) { + // + // This is similar to numerics + // + Status = GetNumericInput (Selection, MenuOption); + } else { + *OptionString = AllocateZeroPool (BufferSize); + ASSERT (*OptionString); + + switch (MenuOption->Sequence) { + case 0: + *OptionString[0] = LEFT_NUMERIC_DELIMITER; + UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Month); + *(OptionString[0] + 3) = DATE_SEPARATOR; + break; + + case 1: + SetUnicodeMem (OptionString[0], 4, L' '); + UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Day); + *(OptionString[0] + 6) = DATE_SEPARATOR; + break; + + case 2: + SetUnicodeMem (OptionString[0], 7, L' '); + UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%4d", QuestionValue->Value.date.Year); + *(OptionString[0] + 11) = RIGHT_NUMERIC_DELIMITER; + break; + } + } + break; + + case EFI_IFR_TIME_OP: + if (Selected) { + // + // This is similar to numerics + // + Status = GetNumericInput (Selection, MenuOption); + } else { + *OptionString = AllocateZeroPool (BufferSize); + ASSERT (*OptionString); + + switch (MenuOption->Sequence) { + case 0: + *OptionString[0] = LEFT_NUMERIC_DELIMITER; + UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Hour); + *(OptionString[0] + 3) = TIME_SEPARATOR; + break; + + case 1: + SetUnicodeMem (OptionString[0], 4, L' '); + UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Minute); + *(OptionString[0] + 6) = TIME_SEPARATOR; + break; + + case 2: + SetUnicodeMem (OptionString[0], 7, L' '); + UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Second); + *(OptionString[0] + 9) = RIGHT_NUMERIC_DELIMITER; + break; + } + } + break; + + case EFI_IFR_STRING_OP: + if (Selected) { + StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16)); + ASSERT (StringPtr); + + Status = ReadString (MenuOption, gPromptForData, StringPtr); + if (!EFI_ERROR (Status)) { + CopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16)); + SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE); + + UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE); + } + + gBS->FreePool (StringPtr); + } else { + *OptionString = AllocateZeroPool (BufferSize); + ASSERT (*OptionString); + + if (((CHAR16 *) Question->BufferValue)[0] == 0x0000) { + *(OptionString[0]) = '_'; + } else { + if ((Maximum * sizeof (CHAR16)) < BufferSize) { + BufferSize = Maximum * sizeof (CHAR16); + } + CopyMem (OptionString[0], (CHAR16 *) Question->BufferValue, BufferSize); + } + } + break; + + case EFI_IFR_PASSWORD_OP: + if (Selected) { + StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16)); + ASSERT (StringPtr); + + // + // For interactive passwords, old password is validated by callback + // + if (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) { + // + // Use a NULL password to test whether old password is required + // + *StringPtr = 0; + Status = PasswordCallback (Selection, MenuOption, StringPtr); + if (Status == EFI_NOT_AVAILABLE_YET) { + // + // Callback request to terminate password input + // + gBS->FreePool (StringPtr); + return EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + // + // Old password exist, ask user for the old password + // + Status = ReadString (MenuOption, gPromptForPassword, StringPtr); + if (EFI_ERROR (Status)) { + gBS->FreePool (StringPtr); + return Status; + } + + // + // Check user input old password + // + Status = PasswordCallback (Selection, MenuOption, StringPtr); + if (EFI_ERROR (Status)) { + if (Status == EFI_NOT_READY) { + // + // Typed in old password incorrect + // + PasswordInvalid (); + } else { + Status = EFI_SUCCESS; + } + + gBS->FreePool (StringPtr); + return Status; + } + } + } else { + // + // For non-interactive password, validate old password in local + // + if (*((CHAR16 *) Question->BufferValue) != 0) { + // + // There is something there! Prompt for password + // + Status = ReadString (MenuOption, gPromptForPassword, StringPtr); + if (EFI_ERROR (Status)) { + gBS->FreePool (StringPtr); + return Status; + } + + TempString = AllocateCopyPool ((Maximum + 1) * sizeof (CHAR16), Question->BufferValue); + TempString[Maximum] = L'\0'; + + if (StrCmp (StringPtr, TempString) != 0) { + // + // Typed in old password incorrect + // + PasswordInvalid (); + + gBS->FreePool (StringPtr); + gBS->FreePool (TempString); + return Status; + } + + gBS->FreePool (TempString); + } + } + + // + // Ask for new password + // + ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16)); + Status = ReadString (MenuOption, gPromptForNewPassword, StringPtr); + if (EFI_ERROR (Status)) { + // + // Reset state machine for interactive password + // + if (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) { + PasswordCallback (Selection, MenuOption, NULL); + } + + gBS->FreePool (StringPtr); + return Status; + } + + // + // Confirm new password + // + TempString = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16)); + ASSERT (TempString); + Status = ReadString (MenuOption, gConfirmPassword, TempString); + if (EFI_ERROR (Status)) { + // + // Reset state machine for interactive password + // + if (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) { + PasswordCallback (Selection, MenuOption, NULL); + } + + gBS->FreePool (StringPtr); + gBS->FreePool (TempString); + return Status; + } + + // + // Compare two typed-in new passwords + // + if (StrCmp (StringPtr, TempString) == 0) { + // + // Two password match, send it to Configuration Driver + // + if (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) { + PasswordCallback (Selection, MenuOption, StringPtr); + } else { + CopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16)); + SetQuestionValue (Selection->FormSet, Selection->Form, Question, FALSE); + } + } else { + // + // Reset state machine for interactive password + // + if (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) { + PasswordCallback (Selection, MenuOption, NULL); + } + + // + // Two password mismatch, prompt error message + // + do { + CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gConfirmError, gPressEnter, gEmptyString); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + } + + gBS->FreePool (TempString); + gBS->FreePool (StringPtr); + } + break; + + default: + break; + } + + return Status; +} + + +/** + Process the help string: Split StringPtr to several lines of strings stored in + FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth. + + @param StringPtr The entire help string. + @param MenuOption The MenuOption for this Question. + @param RowCount TRUE: if Question is selected. + @param OptionString Pointer of the Option String to be displayed. + + @return None. + +**/ +VOID +ProcessHelpString ( + IN CHAR16 *StringPtr, + OUT CHAR16 **FormattedString, + IN UINTN RowCount + ) +{ + CONST UINTN BlockWidth = (UINTN) gHelpBlockWidth - 1; + UINTN AllocateSize; + // + // [PrevCurrIndex, CurrIndex) forms a range of a screen-line + // + UINTN CurrIndex; + UINTN PrevCurrIndex; + UINTN LineCount; + UINTN VirtualLineCount; + // + // GlyphOffset stores glyph width of current screen-line + // + UINTN GlyphOffset; + // + // GlyphWidth equals to 2 if we meet width directive + // + UINTN GlyphWidth; + // + // during scanning, we remember the position of last space character + // in case that if next word cannot put in current line, we could restore back to the position + // of last space character + // while we should also remmeber the glyph width of the last space character for restoring + // + UINTN LastSpaceIndex; + UINTN LastSpaceGlyphWidth; + // + // every time we begin to form a new screen-line, we should remember glyph width of single character + // of last line + // + UINTN LineStartGlyphWidth; + UINTN *IndexArray; + UINTN *OldIndexArray; + + // + // every three elements of IndexArray form a screen-line of string:[ IndexArray[i*3], IndexArray[i*3+1] ) + // IndexArray[i*3+2] stores the initial glyph width of single character. to save this is because we want + // to bring the width directive of the last line to current screen-line. + // e.g.: "\wideabcde ... fghi", if "fghi" also has width directive but is splitted to the next screen-line + // different from that of "\wideabcde", we should remember the width directive. + // + AllocateSize = 0x20; + IndexArray = AllocatePool (AllocateSize * sizeof (UINTN) * 3); + + if (*FormattedString != NULL) { + gBS->FreePool (*FormattedString); + *FormattedString = NULL; + } + + for (PrevCurrIndex = 0, CurrIndex = 0, LineCount = 0, LastSpaceIndex = 0, + IndexArray[0] = 0, GlyphWidth = 1, GlyphOffset = 0, LastSpaceGlyphWidth = 1, LineStartGlyphWidth = 1; + (StringPtr[CurrIndex] != CHAR_NULL); + CurrIndex ++) { + + if (LineCount == AllocateSize) { + AllocateSize += 0x10; + OldIndexArray = IndexArray; + IndexArray = AllocatePool (AllocateSize * sizeof (UINTN) * 3); + CopyMem (IndexArray, OldIndexArray, LineCount * sizeof (UINTN) * 3); + gBS->FreePool (OldIndexArray); + } + switch (StringPtr[CurrIndex]) { + + case NARROW_CHAR: + case WIDE_CHAR: + GlyphWidth = ((StringPtr[CurrIndex] == WIDE_CHAR) ? 2 : 1); + if (CurrIndex == 0) { + LineStartGlyphWidth = GlyphWidth; + } + break; + + // + // char is '\n' + // "\r\n" isn't handled here, handled by case CHAR_CARRIAGE_RETURN + // + case CHAR_LINEFEED: + // + // Store a range of string as a line + // + IndexArray[LineCount*3] = PrevCurrIndex; + IndexArray[LineCount*3+1] = CurrIndex; + IndexArray[LineCount*3+2] = LineStartGlyphWidth; + LineCount ++; + // + // Reset offset and save begin position of line + // + GlyphOffset = 0; + LineStartGlyphWidth = GlyphWidth; + PrevCurrIndex = CurrIndex + 1; + break; + + // + // char is '\r' + // "\r\n" and "\r" both are handled here + // + case CHAR_CARRIAGE_RETURN: + if (StringPtr[CurrIndex + 1] == CHAR_LINEFEED) { + // + // next char is '\n' + // + IndexArray[LineCount*3] = PrevCurrIndex; + IndexArray[LineCount*3+1] = CurrIndex; + IndexArray[LineCount*3+2] = LineStartGlyphWidth; + LineCount ++; + CurrIndex ++; + } + GlyphOffset = 0; + LineStartGlyphWidth = GlyphWidth; + PrevCurrIndex = CurrIndex + 1; + break; + + // + // char is space or other char + // + default: + GlyphOffset += GlyphWidth; + if (GlyphOffset >= BlockWidth) { + if (LastSpaceIndex > PrevCurrIndex) { + // + // LastSpaceIndex points to space inside current screen-line, + // restore to LastSpaceIndex + // (Otherwise the word is too long to fit one screen-line, just cut it) + // + CurrIndex = LastSpaceIndex; + GlyphWidth = LastSpaceGlyphWidth; + } else if (GlyphOffset > BlockWidth) { + // + // the word is too long to fit one screen-line and we don't get the chance + // of GlyphOffset == BlockWidth because GlyphWidth = 2 + // + CurrIndex --; + } + + IndexArray[LineCount*3] = PrevCurrIndex; + IndexArray[LineCount*3+1] = CurrIndex + 1; + IndexArray[LineCount*3+2] = LineStartGlyphWidth; + LineStartGlyphWidth = GlyphWidth; + LineCount ++; + // + // Reset offset and save begin position of line + // + GlyphOffset = 0; + PrevCurrIndex = CurrIndex + 1; + } + + // + // LastSpaceIndex: remember position of last space + // + if (StringPtr[CurrIndex] == CHAR_SPACE) { + LastSpaceIndex = CurrIndex; + LastSpaceGlyphWidth = GlyphWidth; + } + break; + } + } + + if (GlyphOffset > 0) { + IndexArray[LineCount*3] = PrevCurrIndex; + IndexArray[LineCount*3+1] = CurrIndex; + IndexArray[LineCount*3+2] = GlyphWidth; + LineCount ++; + } + + if (LineCount == 0) { + // + // in case we meet null string + // + IndexArray[0] = 0; + IndexArray[1] = 1; + // + // we assume null string's glyph width is 1 + // + IndexArray[1] = 1; + LineCount ++; + } + + VirtualLineCount = RowCount * (LineCount / RowCount + (LineCount % RowCount > 0)); + *FormattedString = AllocateZeroPool (VirtualLineCount * (BlockWidth + 1) * sizeof (CHAR16) * 2); + + for (CurrIndex = 0; CurrIndex < LineCount; CurrIndex ++) { + *(*FormattedString + CurrIndex * 2 * (BlockWidth + 1)) = (CHAR16) ((IndexArray[CurrIndex*3+2] == 2) ? WIDE_CHAR : NARROW_CHAR); + StrnCpy ( + *FormattedString + CurrIndex * 2 * (BlockWidth + 1) + 1, + StringPtr + IndexArray[CurrIndex*3], + IndexArray[CurrIndex*3+1]-IndexArray[CurrIndex*3] + ); + } + + gBS->FreePool (IndexArray); +} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/R8Lib.c b/MdeModulePkg/Universal/SetupBrowserDxe/R8Lib.c new file mode 100644 index 0000000000..1ffeb1bb9d --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/R8Lib.c @@ -0,0 +1,243 @@ +/**@file + Copyright (c) 2007, Intel Corporation + + All rights reserved. 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 "Setup.h" + +CHAR16 +NibbleToHexChar ( + IN UINT8 Nibble + ) +/*++ + + Routine Description: + Converts the low nibble of a byte to hex unicode character. + + Arguments: + Nibble - lower nibble of a byte. + + Returns: + Hex unicode character. + +--*/ +{ + Nibble &= 0x0F; + if (Nibble <= 0x9) { + return (CHAR16)(Nibble + L'0'); + } + + return (CHAR16)(Nibble - 0xA + L'A'); +} + + + +/** + Converts binary buffer to Unicode string. + At a minimum, any blob of data could be represented as a hex string. + + @param Str Pointer to the string. + @param HexStringBufferLength Length in bytes of buffer to hold the hex string. + Includes tailing '\0' character. If routine return + with EFI_SUCCESS, containing length of hex string + buffer. If routine return with + EFI_BUFFER_TOO_SMALL, containg length of hex + string buffer desired. + @param Buf Buffer to be converted from. + @param Len Length in bytes of the buffer to be converted. + + @retval EFI_SUCCESS Routine success. + @retval EFI_BUFFER_TOO_SMALL The hex string buffer is too small. + +**/ +EFI_STATUS +R8_BufToHexString ( + IN OUT CHAR16 *Str, + IN OUT UINTN *HexStringBufferLength, + IN UINT8 *Buf, + IN UINTN Len + ) +{ + // + // Porting Guide: + // This library interface is simply obsolete. + // Include the source code to user code. + // + UINTN Idx; + UINT8 Byte; + UINTN StrLen; + + // + // Make sure string is either passed or allocate enough. + // It takes 2 Unicode characters (4 bytes) to represent 1 byte of the binary buffer. + // Plus the Unicode termination character. + // + StrLen = Len * 2; + if (StrLen > ((*HexStringBufferLength) - 1)) { + *HexStringBufferLength = StrLen + 1; + return EFI_BUFFER_TOO_SMALL; + } + + *HexStringBufferLength = StrLen + 1; + // + // Ends the string. + // + Str[StrLen] = L'\0'; + + for (Idx = 0; Idx < Len; Idx++) { + + Byte = Buf[Idx]; + Str[StrLen - 1 - Idx * 2] = NibbleToHexChar (Byte); + Str[StrLen - 2 - Idx * 2] = NibbleToHexChar ((UINT8)(Byte >> 4)); + } + + return EFI_SUCCESS; +} + + + + +/** + Converts Unicode string to binary buffer. + The conversion may be partial. + The first character in the string that is not hex digit stops the conversion. + At a minimum, any blob of data could be represented as a hex string. + + @param Buf Pointer to buffer that receives the data. + @param Len Length in bytes of the buffer to hold converted + data. If routine return with EFI_SUCCESS, + containing length of converted data. If routine + return with EFI_BUFFER_TOO_SMALL, containg length + of buffer desired. + @param Str String to be converted from. + @param ConvertedStrLen Length of the Hex String consumed. + + @retval EFI_SUCCESS Routine Success. + @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold converted data. + +**/ +EFI_STATUS +R8_HexStringToBuf ( + IN OUT UINT8 *Buf, + IN OUT UINTN *Len, + IN CHAR16 *Str, + OUT UINTN *ConvertedStrLen OPTIONAL + ) +{ + // + // Porting Guide: + // This library interface is simply obsolete. + // Include the source code to user code. + // + + UINTN HexCnt; + UINTN Idx; + UINTN BufferLength; + UINT8 Digit; + UINT8 Byte; + + // + // Find out how many hex characters the string has. + // + for (Idx = 0, HexCnt = 0; R8_IsHexDigit (&Digit, Str[Idx]); Idx++, HexCnt++); + + if (HexCnt == 0) { + *Len = 0; + return EFI_SUCCESS; + } + // + // Two Unicode characters make up 1 buffer byte. Round up. + // + BufferLength = (HexCnt + 1) / 2; + + // + // Test if buffer is passed enough. + // + if (BufferLength > (*Len)) { + *Len = BufferLength; + return EFI_BUFFER_TOO_SMALL; + } + + *Len = BufferLength; + + for (Idx = 0; Idx < HexCnt; Idx++) { + + R8_IsHexDigit (&Digit, Str[HexCnt - 1 - Idx]); + + // + // For odd charaters, write the lower nibble for each buffer byte, + // and for even characters, the upper nibble. + // + if ((Idx & 1) == 0) { + Byte = Digit; + } else { + Byte = Buf[Idx / 2]; + Byte &= 0x0F; + Byte = (UINT8) (Byte | Digit << 4); + } + + Buf[Idx / 2] = Byte; + } + + if (ConvertedStrLen != NULL) { + *ConvertedStrLen = HexCnt; + } + + return EFI_SUCCESS; +} + + + + +/** + Determines if a Unicode character is a hexadecimal digit. + The test is case insensitive. + + @param Digit Pointer to byte that receives the value of the hex + character. + @param Char Unicode character to test. + + @retval TRUE If the character is a hexadecimal digit. + @retval FALSE Otherwise. + +**/ +BOOLEAN +R8_IsHexDigit ( + OUT UINT8 *Digit, + IN CHAR16 Char + ) +{ + // + // Porting Guide: + // This library interface is simply obsolete. + // Include the source code to user code. + // + + if ((Char >= L'0') && (Char <= L'9')) { + *Digit = (UINT8) (Char - L'0'); + return TRUE; + } + + if ((Char >= L'A') && (Char <= L'F')) { + *Digit = (UINT8) (Char - L'A' + 0x0A); + return TRUE; + } + + if ((Char >= L'a') && (Char <= L'f')) { + *Digit = (UINT8) (Char - L'a' + 0x0A); + return TRUE; + } + + return FALSE; +} + + diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/R8Lib.h b/MdeModulePkg/Universal/SetupBrowserDxe/R8Lib.h new file mode 100644 index 0000000000..a0903196e6 --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/R8Lib.h @@ -0,0 +1,97 @@ +/**@file + Copyright (c) 2007, Intel Corporation + + All rights reserved. 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. + + +**/ + + + +/** + Converts binary buffer to Unicode string. + At a minimum, any blob of data could be represented as a hex string. + + @param Str Pointer to the string. + @param HexStringBufferLength Length in bytes of buffer to hold the hex string. + Includes tailing '\0' character. If routine return + with EFI_SUCCESS, containing length of hex string + buffer. If routine return with + EFI_BUFFER_TOO_SMALL, containg length of hex + string buffer desired. + @param Buf Buffer to be converted from. + @param Len Length in bytes of the buffer to be converted. + + @retval EFI_SUCCESS Routine success. + @retval EFI_BUFFER_TOO_SMALL The hex string buffer is too small. + +**/ +EFI_STATUS +R8_BufToHexString ( + IN OUT CHAR16 *Str, + IN OUT UINTN *HexStringBufferLength, + IN UINT8 *Buf, + IN UINTN Len + ) +; + + + + +/** + Converts Unicode string to binary buffer. + The conversion may be partial. + The first character in the string that is not hex digit stops the conversion. + At a minimum, any blob of data could be represented as a hex string. + + @param Buf Pointer to buffer that receives the data. + @param Len Length in bytes of the buffer to hold converted + data. If routine return with EFI_SUCCESS, + containing length of converted data. If routine + return with EFI_BUFFER_TOO_SMALL, containg length + of buffer desired. + @param Str String to be converted from. + @param ConvertedStrLen Length of the Hex String consumed. + + @retval EFI_SUCCESS Routine Success. + @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold converted data. + +**/ +EFI_STATUS +R8_HexStringToBuf ( + IN OUT UINT8 *Buf, + IN OUT UINTN *Len, + IN CHAR16 *Str, + OUT UINTN *ConvertedStrLen OPTIONAL + ) +; + + + + +/** + Determines if a Unicode character is a hexadecimal digit. + The test is case insensitive. + + @param Digit Pointer to byte that receives the value of the hex + character. + @param Char Unicode character to test. + + @retval TRUE If the character is a hexadecimal digit. + @retval FALSE Otherwise. + +**/ +BOOLEAN +R8_IsHexDigit ( + OUT UINT8 *Digit, + IN CHAR16 Char + ) +; + + diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c new file mode 100644 index 0000000000..d14dac0373 --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c @@ -0,0 +1,2286 @@ +/** @file +Copyright (c) 2007, Intel Corporation +All rights reserved. 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. + +Module Name: + + Setup.c + +Abstract: + + Entry and initialization module for the browser. + + +**/ + +#include "Setup.h" +#include "Ui.h" + + +SETUP_DRIVER_PRIVATE_DATA mPrivateData = { + SETUP_DRIVER_SIGNATURE, + NULL, + { + SendForm, + BrowserCallback + }, + { + UnicodeVSPrint + } +}; + +EFI_HII_DATABASE_PROTOCOL *mHiiDatabase; +EFI_HII_STRING_PROTOCOL *mHiiString; +EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting; + +BANNER_DATA *BannerData; +EFI_HII_HANDLE FrontPageHandle; +UINTN gClassOfVfr; +UINTN gFunctionKeySetting; +BOOLEAN gResetRequired; +BOOLEAN gNvUpdateRequired; +EFI_HII_HANDLE gHiiHandle; +BOOLEAN gFirstIn; +UINT16 gDirection; +EFI_SCREEN_DESCRIPTOR gScreenDimensions; +BOOLEAN gUpArrow; +BOOLEAN gDownArrow; + +// +// Browser Global Strings +// +CHAR16 *gFunctionOneString; +CHAR16 *gFunctionTwoString; +CHAR16 *gFunctionNineString; +CHAR16 *gFunctionTenString; +CHAR16 *gEnterString; +CHAR16 *gEnterCommitString; +CHAR16 *gEscapeString; +CHAR16 *gSaveFailed; +CHAR16 *gMoveHighlight; +CHAR16 *gMakeSelection; +CHAR16 *gDecNumericInput; +CHAR16 *gHexNumericInput; +CHAR16 *gToggleCheckBox; +CHAR16 *gPromptForData; +CHAR16 *gPromptForPassword; +CHAR16 *gPromptForNewPassword; +CHAR16 *gConfirmPassword; +CHAR16 *gConfirmError; +CHAR16 *gPassowordInvalid; +CHAR16 *gPressEnter; +CHAR16 *gEmptyString; +CHAR16 *gAreYouSure; +CHAR16 *gYesResponse; +CHAR16 *gNoResponse; +CHAR16 *gMiniString; +CHAR16 *gPlusString; +CHAR16 *gMinusString; +CHAR16 *gAdjustNumber; + +CHAR16 gPromptBlockWidth; +CHAR16 gOptionBlockWidth; +CHAR16 gHelpBlockWidth; + +EFI_GUID gZeroGuid = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +EFI_GUID gSetupBrowserGuid = { + 0xab368524, 0xb60c, 0x495b, 0xa0, 0x9, 0x12, 0xe8, 0x5b, 0x1a, 0xea, 0x32 +}; + +FUNCTIION_KEY_SETTING gFunctionKeySettingTable[] = { + // + // Boot Manager + // + { + { + 0x847bc3fe, + 0xb974, + 0x446d, + 0x94, + 0x49, + 0x5a, + 0xd5, + 0x41, + 0x2e, + 0x99, + 0x3b + }, + NONE_FUNCTION_KEY_SETTING + }, + // + // Device Manager + // + { + { + 0x3ebfa8e6, + 0x511d, + 0x4b5b, + 0xa9, + 0x5f, + 0xfb, + 0x38, + 0x26, + 0xf, + 0x1c, + 0x27 + }, + NONE_FUNCTION_KEY_SETTING + }, + // + // BMM FormSet. + // + { + { + 0x642237c7, + 0x35d4, + 0x472d, + 0x83, + 0x65, + 0x12, + 0xe0, + 0xcc, + 0xf2, + 0x7a, + 0x22 + }, + NONE_FUNCTION_KEY_SETTING + }, + // + // BMM File Explorer FormSet. + // + { + { + 0x1f2d63e1, + 0xfebd, + 0x4dc7, + 0x9c, + 0xc5, + 0xba, + 0x2b, + 0x1c, + 0xef, + 0x9c, + 0x5b + }, + NONE_FUNCTION_KEY_SETTING + }, +}; + +//@MT: EFI_DRIVER_ENTRY_POINT (InitializeSetup) + +EFI_STATUS +EFIAPI +SendForm ( + IN CONST EFI_FORM_BROWSER2_PROTOCOL *This, + IN EFI_HII_HANDLE *Handles, + IN UINTN HandleCount, + IN EFI_GUID *FormSetGuid, OPTIONAL + IN UINT16 FormId, OPTIONAL + IN CONST EFI_SCREEN_DESCRIPTOR *ScreenDimensions, OPTIONAL + OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest OPTIONAL + ) +/*++ + +Routine Description: + This is the routine which an external caller uses to direct the browser + where to obtain it's information. + +Arguments: + This - The Form Browser protocol instanse. + Handles - A pointer to an array of Handles. If HandleCount > 1 we + display a list of the formsets for the handles specified. + HandleCount - The number of Handles specified in Handle. + FormSetGuid - This field points to the EFI_GUID which must match the Guid + field in the EFI_IFR_FORM_SET op-code for the specified + forms-based package. If FormSetGuid is NULL, then this + function will display the first found forms package. + FormId - This field specifies which EFI_IFR_FORM to render as the first + displayable page. If this field has a value of 0x0000, then + the forms browser will render the specified forms in their encoded order. + ScreenDimenions - This allows the browser to be called so that it occupies a + portion of the physical screen instead of dynamically determining the screen dimensions. + ActionRequest - Points to the action recommended by the form. + +Returns: + EFI_SUCCESS - The function completed successfully. + EFI_INVALID_PARAMETER - One of the parameters has an invalid value. + EFI_NOT_FOUND - No valid forms could be found to display. + +--*/ +{ + EFI_STATUS Status; + UI_MENU_SELECTION *Selection; + UINTN Index; + FORM_BROWSER_FORMSET *FormSet; + + Status = EFI_SUCCESS; + ZeroMem (&gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + + // + // Seed the dimensions in the global + // + gST->ConOut->QueryMode ( + gST->ConOut, + gST->ConOut->Mode->Mode, + &gScreenDimensions.RightColumn, + &gScreenDimensions.BottomRow + ); + + if (ScreenDimensions != NULL) { + // + // Check local dimension vs. global dimension. + // + if ((gScreenDimensions.RightColumn < ScreenDimensions->RightColumn) || + (gScreenDimensions.BottomRow < ScreenDimensions->BottomRow) + ) { + return EFI_INVALID_PARAMETER; + } else { + // + // Local dimension validation. + // + if ((ScreenDimensions->RightColumn > ScreenDimensions->LeftColumn) && + (ScreenDimensions->BottomRow > ScreenDimensions->TopRow) && + ((ScreenDimensions->RightColumn - ScreenDimensions->LeftColumn) > 2) && + ( + (ScreenDimensions->BottomRow - ScreenDimensions->TopRow) > STATUS_BAR_HEIGHT + + SCROLL_ARROW_HEIGHT * + 2 + + FRONT_PAGE_HEADER_HEIGHT + + FOOTER_HEIGHT + + 1 + ) + ) { + CopyMem (&gScreenDimensions, (VOID *) ScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + } else { + return EFI_INVALID_PARAMETER; + } + } + } + + gOptionBlockWidth = (CHAR16) ((gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3); + gHelpBlockWidth = gOptionBlockWidth; + gPromptBlockWidth = gOptionBlockWidth; + + // + // Initialize the strings for the browser, upon exit of the browser, the strings will be freed + // + InitializeBrowserStrings (); + + gFunctionKeySetting = DEFAULT_FUNCTION_KEY_SETTING; + gClassOfVfr = EFI_SETUP_APPLICATION_SUBCLASS; + + // + // Ensure we are in Text mode + // + if (gFirstIn) { + gFirstIn = FALSE; + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + DisableQuietBoot (); + } + + for (Index = 0; Index < HandleCount; Index++) { + Selection = AllocateZeroPool (sizeof (UI_MENU_SELECTION)); + ASSERT (Selection != NULL); + + Selection->Handle = Handles[Index]; + if (FormSetGuid != NULL) { + CopyMem (&Selection->FormSetGuid, FormSetGuid, sizeof (EFI_GUID)); + Selection->FormId = FormId; + } + + do { + FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET)); + ASSERT (FormSet != NULL); + + // + // Initialize internal data structures of FormSet + // + Status = InitializeFormSet (Selection->Handle, &Selection->FormSetGuid, FormSet); + if (EFI_ERROR (Status)) { + DestroyFormSet (FormSet); + break; + } + Selection->FormSet = FormSet; + + // + // Initialize current settings of Questions in this FormSet + // + Status = InitializeCurrentSetting (FormSet); + if (EFI_ERROR (Status)) { + DestroyFormSet (FormSet); + break; + } + + // + // Display this formset + // + gCurrentSelection = Selection; + + Status = SetupBrowser (Selection); + + gCurrentSelection = NULL; + DestroyFormSet (FormSet); + + if (EFI_ERROR (Status)) { + break; + } + + } while (Selection->Action == UI_ACTION_REFRESH_FORMSET); + + gBS->FreePool (Selection); + } + + if (ActionRequest != NULL) { + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; + if (gResetRequired) { + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET; + } + } + + FreeBrowserStrings (); + + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->ClearScreen (gST->ConOut); + + return Status; +} + + +/** + This function is called by a callback handler to retrieve uncommitted state + data from the browser. + + @param This A pointer to the EFI_FORM_BROWSER2_PROTOCOL + instance. + @param ResultsDataSize A pointer to the size of the buffer associated + with ResultsData. + @param ResultsData A string returned from an IFR browser or + equivalent. The results string will have no + routing information in them. + @param RetrieveData A BOOLEAN field which allows an agent to retrieve + (if RetrieveData = TRUE) data from the uncommitted + browser state information or set (if RetrieveData + = FALSE) data in the uncommitted browser state + information. + @param VariableGuid An optional field to indicate the target variable + GUID name to use. + @param VariableName An optional field to indicate the target + human-readable variable name. + + @retval EFI_SUCCESS The results have been distributed or are awaiting + distribution. + @retval EFI_BUFFER_TOO_SMALL The ResultsDataSize specified was too small to + contain the results data. + +**/ +EFI_STATUS +EFIAPI +BrowserCallback ( + IN CONST EFI_FORM_BROWSER2_PROTOCOL *This, + IN OUT UINTN *ResultsDataSize, + IN OUT EFI_STRING ResultsData, + IN BOOLEAN RetrieveData, + IN CONST EFI_GUID *VariableGuid, OPTIONAL + IN CONST CHAR16 *VariableName OPTIONAL + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + FORMSET_STORAGE *Storage; + FORM_BROWSER_FORMSET *FormSet; + BOOLEAN Found; + CHAR16 *ConfigResp; + CHAR16 *StrPtr; + UINTN BufferSize; + UINTN TmpSize; + + if (ResultsDataSize == NULL || ResultsData == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (gCurrentSelection == NULL) { + return EFI_NOT_READY; + } + + Storage = NULL; + ConfigResp = NULL; + FormSet = gCurrentSelection->FormSet; + + // + // Find target storage + // + Link = GetFirstNode (&FormSet->StorageListHead); + if (IsNull (&FormSet->StorageListHead, Link)) { + return EFI_UNSUPPORTED; + } + + if (VariableGuid != NULL) { + // + // Try to find target storage + // + Found = FALSE; + while (!IsNull (&FormSet->StorageListHead, Link)) { + Storage = FORMSET_STORAGE_FROM_LINK (Link); + Link = GetNextNode (&FormSet->StorageListHead, Link); + + if (CompareGuid (&Storage->Guid, (EFI_GUID *) VariableGuid)) { + if (Storage->Type == EFI_HII_VARSTORE_BUFFER) { + // + // Buffer storage require both GUID and Name + // + if (VariableName == NULL) { + return EFI_NOT_FOUND; + } + + if (StrCmp (Storage->Name, (CHAR16 *) VariableName) != 0) { + continue; + } + } + Found = TRUE; + break; + } + } + + if (!Found) { + return EFI_NOT_FOUND; + } + } else { + // + // GUID/Name is not specified, take the first storage in FormSet + // + Storage = FORMSET_STORAGE_FROM_LINK (Link); + } + + if (RetrieveData) { + // + // Skip if there is no RequestElement + // + if (Storage->ElementCount == 0) { + return EFI_SUCCESS; + } + + // + // Generate <ConfigResp> + // + Status = StorageToConfigResp (Storage, &ConfigResp); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Skip <ConfigHdr> and '&' to point to <ConfigBody> + // + StrPtr = ConfigResp + StrLen (Storage->ConfigHdr) + 1; + + BufferSize = StrSize (StrPtr); + if (*ResultsDataSize < BufferSize) { + *ResultsDataSize = BufferSize; + + gBS->FreePool (ConfigResp); + return EFI_BUFFER_TOO_SMALL; + } + + *ResultsDataSize = BufferSize; + CopyMem (ResultsData, StrPtr, BufferSize); + + gBS->FreePool (ConfigResp); + } else { + // + // Prepare <ConfigResp> + // + TmpSize = StrLen (ResultsData); + BufferSize = (TmpSize + StrLen (Storage->ConfigHdr) + 2) * sizeof (CHAR16); + ConfigResp = AllocateZeroPool (BufferSize); + ASSERT (ConfigResp != NULL); + + StrCpy (ConfigResp, Storage->ConfigHdr); + StrCat (ConfigResp, L"&"); + StrCat (ConfigResp, ResultsData); + + // + // Update Browser uncommited data + // + Status = ConfigRespToStorage (Storage, ConfigResp); + if (EFI_ERROR (Status)) { + return Status; + } + } + + return EFI_SUCCESS; +} + + +/** + Initialize Setup + + @param entry EFI_IMAGE_ENTRY_POINT) + + @retval EFI_SUCCESS Setup loaded. + @retval other Setup Error + +**/ +EFI_STATUS +EFIAPI +InitializeSetup ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE HiiDriverHandle; + EFI_HII_PACKAGE_LIST_HEADER *PackageList; + + //@MT: EfiInitializeDriverLib (ImageHandle, SystemTable); + + // + // Locate required Hii relative protocols + // + Status = gBS->LocateProtocol ( + &gEfiHiiDatabaseProtocolGuid, + NULL, + (VOID **) &mHiiDatabase + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol ( + &gEfiHiiStringProtocolGuid, + NULL, + (VOID **) &mHiiString + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol ( + &gEfiHiiConfigRoutingProtocolGuid, + NULL, + (VOID **) &mHiiConfigRouting + ); + ASSERT_EFI_ERROR (Status); + + // + // Publish our HII data + // + Status = HiiLibCreateHiiDriverHandle (&HiiDriverHandle); + ASSERT_EFI_ERROR (Status); + + PackageList = PreparePackageList (1, &gSetupBrowserGuid, SetupBrowserStrings); + ASSERT (PackageList != NULL); + Status = mHiiDatabase->NewPackageList ( + mHiiDatabase, + PackageList, + HiiDriverHandle, + &gHiiHandle + ); + ASSERT_EFI_ERROR (Status); + + // + // Initialize Driver private data + // + gFirstIn = TRUE; + BannerData = AllocateZeroPool (sizeof (BANNER_DATA)); + ASSERT (BannerData != NULL); + + // + // Install FormBrowser2 protocol + // + mPrivateData.Handle = NULL; + Status = gBS->InstallProtocolInterface ( + &mPrivateData.Handle, + &gEfiFormBrowser2ProtocolGuid, + EFI_NATIVE_INTERFACE, + &mPrivateData.FormBrowser2 + ); + ASSERT_EFI_ERROR (Status); + + // + // Install Print protocol + // + Status = gBS->InstallProtocolInterface ( + &mPrivateData.Handle, + &gEfiPrintProtocolGuid, + EFI_NATIVE_INTERFACE, + &mPrivateData.Print + ); + + return Status; +} + + +/** + Create a new string in HII Package List. + + @param String The String to be added + @param HiiHandle The package list in the HII database to insert the + specified string. + + @return The output string. + +**/ +EFI_STRING_ID +NewString ( + IN CHAR16 *String, + IN EFI_HII_HANDLE HiiHandle + ) +{ + EFI_STRING_ID StringId; + EFI_STATUS Status; + + StringId = 0; + Status = IfrLibNewString (HiiHandle, &StringId, String); + ASSERT_EFI_ERROR (Status); + + return StringId; +} + + +/** + Delete a string from HII Package List. + + @param StringId Id of the string in HII database. + @param HiiHandle The HII package list handle. + + @retval EFI_SUCCESS The string was deleted successfully. + +**/ +EFI_STATUS +DeleteString ( + IN EFI_STRING_ID StringId, + IN EFI_HII_HANDLE HiiHandle + ) +{ + CHAR16 NullChar; + + NullChar = CHAR_NULL; + return IfrLibSetString (HiiHandle, StringId, &NullChar); +} + + +/** + Get the string based on the StringId and HII Package List Handle. + + @param Token The String's ID. + @param HiiHandle The package list in the HII database to search for + the specified string. + + @return The output string. + +**/ +CHAR16 * +GetToken ( + IN EFI_STRING_ID Token, + IN EFI_HII_HANDLE HiiHandle + ) +{ + EFI_STATUS Status; + CHAR16 *String; + UINTN BufferLength; + + // + // Set default string size assumption at no more than 256 bytes + // + BufferLength = 0x100; + String = AllocateZeroPool (BufferLength); + ASSERT (String != NULL); + + Status = IfrLibGetString (HiiHandle, Token, String, &BufferLength); + + if (Status == EFI_BUFFER_TOO_SMALL) { + gBS->FreePool (String); + String = AllocateZeroPool (BufferLength); + ASSERT (String != NULL); + + Status = IfrLibGetString (HiiHandle, Token, String, &BufferLength); + } + ASSERT_EFI_ERROR (Status); + + return String; +} + + +/** + Allocate new memory and then copy the Unicode string Source to Destination. + + @param Dest Location to copy string + @param Src String to copy + + @return NONE + +**/ +VOID +NewStringCpy ( + IN OUT CHAR16 **Dest, + IN CHAR16 *Src + ) +{ + SafeFreePool (*Dest); + *Dest = AllocateCopyPool (StrSize (Src), Src); + ASSERT (*Dest != NULL); +} + + +/** + Allocate new memory and concatinate Source on the end of Destination. + + @param Dest String to added to the end of. + @param Src String to concatinate. + + @return NONE + +**/ +VOID +NewStringCat ( + IN OUT CHAR16 **Dest, + IN CHAR16 *Src + ) +{ + CHAR16 *NewString; + UINTN TmpSize; + + if (*Dest == NULL) { + NewStringCpy (Dest, Src); + return; + } + + TmpSize = StrSize (*Dest); + NewString = AllocateZeroPool (TmpSize + StrSize (Src) - 1); + ASSERT (NewString != NULL); + + StrCpy (NewString, *Dest); + StrCat (NewString, Src); + + gBS->FreePool (*Dest); + *Dest = NewString; +} + + +/** + Synchronize Storage's Edit copy to Shadow copy. + + @param Storage The Storage to be synchronized. + + @return NONE + +**/ +VOID +SynchronizeStorage ( + IN FORMSET_STORAGE *Storage + ) +{ + LIST_ENTRY *Link; + NAME_VALUE_NODE *Node; + + switch (Storage->Type) { + case EFI_HII_VARSTORE_BUFFER: + CopyMem (Storage->Buffer, Storage->EditBuffer, Storage->Size); + break; + + case EFI_HII_VARSTORE_NAME_VALUE: + Link = GetFirstNode (&Storage->NameValueListHead); + while (!IsNull (&Storage->NameValueListHead, Link)) { + Node = NAME_VALUE_NODE_FROM_LINK (Link); + + NewStringCpy (&Node->Value, Node->EditValue); + + Link = GetNextNode (&Storage->NameValueListHead, Link); + } + break; + + case EFI_HII_VARSTORE_EFI_VARIABLE: + default: + break; + } +} + + +/** + Get Value for given Name from a NameValue Storage. + + @param Storage The NameValue Storage. + @param Name The Name. + @param Value The retured Value. + + @retval EFI_SUCCESS Value found for given Name. + @retval EFI_NOT_FOUND No such Name found in NameValue storage. + +**/ +EFI_STATUS +GetValueByName ( + IN FORMSET_STORAGE *Storage, + IN CHAR16 *Name, + IN OUT CHAR16 **Value + ) +{ + LIST_ENTRY *Link; + NAME_VALUE_NODE *Node; + + *Value = NULL; + + Link = GetFirstNode (&Storage->NameValueListHead); + while (!IsNull (&Storage->NameValueListHead, Link)) { + Node = NAME_VALUE_NODE_FROM_LINK (Link); + + if (StrCmp (Name, Node->Name) == 0) { + NewStringCpy (Value, Node->EditValue); + return EFI_SUCCESS; + } + + Link = GetNextNode (&Storage->NameValueListHead, Link); + } + + return EFI_NOT_FOUND; +} + + +/** + Set Value of given Name in a NameValue Storage. + + @param Storage The NameValue Storage. + @param Name The Name. + @param Value The Value to set. + + @retval EFI_SUCCESS Value found for given Name. + @retval EFI_NOT_FOUND No such Name found in NameValue storage. + +**/ +EFI_STATUS +SetValueByName ( + IN FORMSET_STORAGE *Storage, + IN CHAR16 *Name, + IN CHAR16 *Value + ) +{ + LIST_ENTRY *Link; + NAME_VALUE_NODE *Node; + + Link = GetFirstNode (&Storage->NameValueListHead); + while (!IsNull (&Storage->NameValueListHead, Link)) { + Node = NAME_VALUE_NODE_FROM_LINK (Link); + + if (StrCmp (Name, Node->Name) == 0) { + SafeFreePool (Node->EditValue); + Node->EditValue = AllocateCopyPool (StrSize (Value), Value); + ASSERT (Node->EditValue != NULL); + return EFI_SUCCESS; + } + + Link = GetNextNode (&Storage->NameValueListHead, Link); + } + + return EFI_NOT_FOUND; +} + + +/** + Convert setting of Buffer Storage or NameValue Storage to <ConfigResp>. + + @param Storage The Storage to be conveted. + @param ConfigResp The returned <ConfigResp>. + + @retval EFI_SUCCESS Convert success. + @retval EFI_INVALID_PARAMETER Incorrect storage type. + +**/ +EFI_STATUS +StorageToConfigResp ( + IN FORMSET_STORAGE *Storage, + IN CHAR16 **ConfigResp + ) +{ + EFI_STATUS Status; + EFI_STRING Progress; + LIST_ENTRY *Link; + NAME_VALUE_NODE *Node; + + Status = EFI_SUCCESS; + + switch (Storage->Type) { + case EFI_HII_VARSTORE_BUFFER: + Status = mHiiConfigRouting->BlockToConfig ( + mHiiConfigRouting, + Storage->ConfigRequest, + Storage->EditBuffer, + Storage->Size, + ConfigResp, + &Progress + ); + break; + + case EFI_HII_VARSTORE_NAME_VALUE: + *ConfigResp = NULL; + NewStringCat (ConfigResp, Storage->ConfigHdr); + + Link = GetFirstNode (&Storage->NameValueListHead); + while (!IsNull (&Storage->NameValueListHead, Link)) { + Node = NAME_VALUE_NODE_FROM_LINK (Link); + + NewStringCat (ConfigResp, L"&"); + NewStringCat (ConfigResp, Node->Name); + NewStringCat (ConfigResp, L"="); + NewStringCat (ConfigResp, Node->EditValue); + + Link = GetNextNode (&Storage->NameValueListHead, Link); + } + break; + + case EFI_HII_VARSTORE_EFI_VARIABLE: + default: + Status = EFI_INVALID_PARAMETER; + break; + } + + return Status; +} + + +/** + Convert <ConfigResp> to settings in Buffer Storage or NameValue Storage. + + @param Storage The Storage to receive the settings. + @param ConfigResp The <ConfigResp> to be converted. + + @retval EFI_SUCCESS Convert success. + @retval EFI_INVALID_PARAMETER Incorrect storage type. + +**/ +EFI_STATUS +ConfigRespToStorage ( + IN FORMSET_STORAGE *Storage, + IN CHAR16 *ConfigResp + ) +{ + EFI_STATUS Status; + EFI_STRING Progress; + UINTN BufferSize; + CHAR16 *StrPtr; + CHAR16 *Name; + CHAR16 *Value; + + Status = EFI_SUCCESS; + + switch (Storage->Type) { + case EFI_HII_VARSTORE_BUFFER: + BufferSize = Storage->Size; + Status = mHiiConfigRouting->ConfigToBlock ( + mHiiConfigRouting, + ConfigResp, + Storage->EditBuffer, + &BufferSize, + &Progress + ); + break; + + case EFI_HII_VARSTORE_NAME_VALUE: + StrPtr = StrStr (ConfigResp, L"&"); + while (StrPtr != NULL) { + // + // Skip '&' + // + StrPtr = StrPtr + 1; + Name = StrPtr; + StrPtr = StrStr (StrPtr, L"="); + if (StrPtr == NULL) { + break; + } + *StrPtr = 0; + + // + // Skip '=' + // + StrPtr = StrPtr + 1; + Value = StrPtr; + StrPtr = StrStr (StrPtr, L"&"); + if (StrPtr != NULL) { + *StrPtr = 0; + } + SetValueByName (Storage, Name, Value); + } + break; + + case EFI_HII_VARSTORE_EFI_VARIABLE: + default: + Status = EFI_INVALID_PARAMETER; + break; + } + + return Status; +} + + +/** + Get Question's current Value. + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param Question Question to be initialized. + @param Cached TRUE: get from Edit copy FALSE: get from original + Storage + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +GetQuestionValue ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_BROWSER_STATEMENT *Question, + IN BOOLEAN Cached + ) +{ + EFI_STATUS Status; + BOOLEAN Enabled; + BOOLEAN Pending; + UINT8 *Dst; + UINTN StorageWidth; + EFI_TIME EfiTime; + FORMSET_STORAGE *Storage; + EFI_IFR_TYPE_VALUE *QuestionValue; + CHAR16 *ConfigRequest; + CHAR16 *Progress; + CHAR16 *Result; + CHAR16 *Value; + UINTN Length; + BOOLEAN IsBufferStorage; + BOOLEAN IsString; + + Status = EFI_SUCCESS; + + // + // Statement don't have storage, skip them + // + if (Question->QuestionId == 0) { + return Status; + } + + // + // Question value is provided by an Expression, evaluate it + // + if (Question->ValueExpression != NULL) { + Status = EvaluateExpression (FormSet, Form, Question->ValueExpression); + if (!EFI_ERROR (Status)) { + CopyMem (&Question->HiiValue, &Question->ValueExpression->Result, sizeof (EFI_HII_VALUE)); + } + return Status; + } + + // + // Question value is provided by RTC + // + Storage = Question->Storage; + QuestionValue = &Question->HiiValue.Value; + if (Storage == NULL) { + // + // It's a Question without storage, or RTC date/time + // + if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) { + // + // Date and time define the same Flags bit + // + switch (Question->Flags & EFI_QF_DATE_STORAGE) { + case QF_DATE_STORAGE_TIME: + Status = gRT->GetTime (&EfiTime, NULL); + break; + + case QF_DATE_STORAGE_WAKEUP: + Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime); + break; + + case QF_DATE_STORAGE_NORMAL: + default: + // + // For date/time without storage + // + return EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + return Status; + } + + if (Question->Operand == EFI_IFR_DATE_OP) { + QuestionValue->date.Year = EfiTime.Year; + QuestionValue->date.Month = EfiTime.Month; + QuestionValue->date.Day = EfiTime.Day; + } else { + QuestionValue->time.Hour = EfiTime.Hour; + QuestionValue->time.Minute = EfiTime.Minute; + QuestionValue->time.Second = EfiTime.Second; + } + } + + return EFI_SUCCESS; + } + + // + // Question value is provided by EFI variable + // + StorageWidth = Question->StorageWidth; + if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + if (Question->BufferValue != NULL) { + Dst = Question->BufferValue; + } else { + Dst = (UINT8 *) QuestionValue; + } + + Status = gRT->GetVariable ( + Question->VariableName, + &Storage->Guid, + NULL, + &StorageWidth, + Dst + ); + // + // Always return success, even this EFI variable doesn't exist + // + return EFI_SUCCESS; + } + + // + // Question Value is provided by Buffer Storage or NameValue Storage + // + if (Question->BufferValue != NULL) { + // + // This Question is password or orderedlist + // + Dst = Question->BufferValue; + } else { + // + // Other type of Questions + // + Dst = (UINT8 *) &Question->HiiValue.Value; + } + + IsBufferStorage = (BOOLEAN) ((Storage->Type == EFI_HII_VARSTORE_BUFFER) ? TRUE : FALSE); + IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE); + if (Cached) { + if (IsBufferStorage) { + // + // Copy from storage Edit buffer + // + CopyMem (Dst, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, StorageWidth); + } else { + Status = GetValueByName (Storage, Question->VariableName, &Value); + if (EFI_ERROR (Status)) { + return Status; + } + + if (IsString) { + StrCpy ((CHAR16 *) Dst, Value); + } else { + Status = R8_HexStringToBuf (Dst, &StorageWidth, Value, NULL); + } + + gBS->FreePool (Value); + } + } else { + // + // Request current settings from Configuration Driver + // + if (FormSet->ConfigAccess == NULL) { + return EFI_NOT_FOUND; + } + + // + // <ConfigRequest> ::= <ConfigHdr> + <BlockName> || + // <ConfigHdr> + "&" + <VariableName> + // + if (IsBufferStorage) { + Length = StrLen (Storage->ConfigHdr); + Length += StrLen (Question->BlockName); + } else { + Length = StrLen (Storage->ConfigHdr); + Length += StrLen (Question->VariableName) + 1; + } + ConfigRequest = AllocateZeroPool ((Length + 1) * sizeof (CHAR16)); + ASSERT (ConfigRequest != NULL); + + StrCpy (ConfigRequest, Storage->ConfigHdr); + if (IsBufferStorage) { + StrCat (ConfigRequest, Question->BlockName); + } else { + StrCat (ConfigRequest, L"&"); + StrCat (ConfigRequest, Question->VariableName); + } + + Status = FormSet->ConfigAccess->ExtractConfig ( + FormSet->ConfigAccess, + ConfigRequest, + &Progress, + &Result + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Skip <ConfigRequest> + // + Value = Result + Length; + if (IsBufferStorage) { + // + // Skip "&VALUE" + // + Value = Value + 6; + } + if (*Value != '=') { + gBS->FreePool (Result); + return EFI_NOT_FOUND; + } + // + // Skip '=', point to value + // + Value = Value + 1; + if (!IsBufferStorage && IsString) { + StrCpy ((CHAR16 *) Dst, Value); + } else { + Status = R8_HexStringToBuf (Dst, &StorageWidth, Value, NULL); + if (EFI_ERROR (Status)) { + gBS->FreePool (Result); + return Status; + } + } + + // + // Synchronize Edit Buffer + // + if (IsBufferStorage) { + CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Dst, StorageWidth); + } else { + SetValueByName (Storage, Question->VariableName, Value); + } + gBS->FreePool (Result); + } + + return Status; +} + + +/** + Save Question Value to edit copy(cached) or Storage(uncached). + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param Question Pointer to the Question. + @param Cached TRUE: set to Edit copy FALSE: set to original + Storage + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +SetQuestionValue ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_BROWSER_STATEMENT *Question, + IN BOOLEAN Cached + ) +{ + EFI_STATUS Status; + BOOLEAN Enabled; + BOOLEAN Pending; + UINT8 *Src; + EFI_TIME EfiTime; + UINTN BufferLen; + UINTN StorageWidth; + FORMSET_STORAGE *Storage; + EFI_IFR_TYPE_VALUE *QuestionValue; + CHAR16 *ConfigResp; + CHAR16 *Progress; + CHAR16 *Value; + UINTN Length; + BOOLEAN IsBufferStorage; + BOOLEAN IsString; + + Status = EFI_SUCCESS; + + // + // Statement don't have storage, skip them + // + if (Question->QuestionId == 0) { + return Status; + } + + // + // If Question value is provided by an Expression, then it is read only + // + if (Question->ValueExpression != NULL) { + return Status; + } + + // + // Question value is provided by RTC + // + Storage = Question->Storage; + QuestionValue = &Question->HiiValue.Value; + if (Storage == NULL) { + // + // It's a Question without storage, or RTC date/time + // + if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) { + // + // Date and time define the same Flags bit + // + switch (Question->Flags & EFI_QF_DATE_STORAGE) { + case QF_DATE_STORAGE_TIME: + Status = gRT->GetTime (&EfiTime, NULL); + break; + + case QF_DATE_STORAGE_WAKEUP: + Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime); + break; + + case QF_DATE_STORAGE_NORMAL: + default: + // + // For date/time without storage + // + return EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + return Status; + } + + if (Question->Operand == EFI_IFR_DATE_OP) { + EfiTime.Year = QuestionValue->date.Year; + EfiTime.Month = QuestionValue->date.Month; + EfiTime.Day = QuestionValue->date.Day; + } else { + EfiTime.Hour = QuestionValue->time.Hour; + EfiTime.Minute = QuestionValue->time.Minute; + EfiTime.Second = QuestionValue->time.Second; + } + + if ((Question->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_TIME) { + Status = gRT->SetTime (&EfiTime); + } else { + Status = gRT->SetWakeupTime (TRUE, &EfiTime); + } + } + + return Status; + } + + // + // Question value is provided by EFI variable + // + StorageWidth = Question->StorageWidth; + if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + if (Question->BufferValue != NULL) { + Src = Question->BufferValue; + } else { + Src = (UINT8 *) QuestionValue; + } + + Status = gRT->SetVariable ( + Question->VariableName, + &Storage->Guid, + Storage->Attributes, + StorageWidth, + Src + ); + return Status; + } + + // + // Question Value is provided by Buffer Storage or NameValue Storage + // + if (Question->BufferValue != NULL) { + Src = Question->BufferValue; + } else { + Src = (UINT8 *) &Question->HiiValue.Value; + } + + IsBufferStorage = (BOOLEAN) ((Storage->Type == EFI_HII_VARSTORE_BUFFER) ? TRUE : FALSE); + IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE); + if (IsBufferStorage) { + // + // Copy to storage edit buffer + // + CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth); + } else { + if (IsString) { + Value = NULL; + NewStringCpy (&Value, (CHAR16 *) Src); + } else { + BufferLen = (StorageWidth * 2 + 1) * sizeof (CHAR16); + Value = AllocateZeroPool (BufferLen); + ASSERT (Value != NULL); + R8_BufToHexString (Value, &BufferLen, Src, StorageWidth); + } + + Status = SetValueByName (Storage, Question->VariableName, Value); + gBS->FreePool (Value); + } + + if (!Cached) { + // + // <ConfigResp> ::= <ConfigHdr> + <BlockName> + "&VALUE=" + "<HexCh>StorageWidth * 2" || + // <ConfigHdr> + "&" + <VariableName> + "=" + "<HexCh>StorageWidth * 2" + // + if (IsBufferStorage) { + Length = StrLen (Question->BlockName) + 7; + } else { + Length = StrLen (Question->VariableName) + 2; + } + if (!IsBufferStorage && IsString) { + Length += StrLen ((CHAR16 *) Src); + } else { + Length += (StorageWidth * 2); + } + ConfigResp = AllocateZeroPool ((StrLen (Storage->ConfigHdr) + Length + 1) * sizeof (CHAR16)); + ASSERT (ConfigResp != NULL); + + StrCpy (ConfigResp, Storage->ConfigHdr); + if (IsBufferStorage) { + StrCat (ConfigResp, Question->BlockName); + StrCat (ConfigResp, L"&VALUE="); + } else { + StrCat (ConfigResp, L"&"); + StrCat (ConfigResp, Question->VariableName); + StrCat (ConfigResp, L"="); + } + + Value = ConfigResp + StrLen (ConfigResp); + if (!IsBufferStorage && IsString) { + StrCpy (Value, (CHAR16 *) Src); + } else { + BufferLen = (StorageWidth * 2 + 1) * sizeof (CHAR16); + R8_BufToHexString (Value, &BufferLen, Src, StorageWidth); + } + + // + // Submit Question Value to Configuration Driver + // + if (FormSet->ConfigAccess != NULL) { + Status = FormSet->ConfigAccess->RouteConfig ( + FormSet->ConfigAccess, + ConfigResp, + &Progress + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (ConfigResp); + return Status; + } + } + gBS->FreePool (ConfigResp); + + // + // Synchronize shadow Buffer + // + SynchronizeStorage (Storage); + } + + return Status; +} + + +/** + Perform inconsistent check for a Form. + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param Question The Question to be validated. + @param Type Validation type: InConsistent or NoSubmit + + @retval EFI_SUCCESS Form validation pass. + @retval other Form validation failed. + +**/ +EFI_STATUS +ValidateQuestion ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN FORM_BROWSER_STATEMENT *Question, + IN UINTN Type + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + LIST_ENTRY *ListHead; + EFI_STRING PopUp; + EFI_INPUT_KEY Key; + FORM_EXPRESSION *Expression; + + if (Type == EFI_HII_EXPRESSION_INCONSISTENT_IF) { + ListHead = &Question->InconsistentListHead; + } else if (Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) { + ListHead = &Question->NoSubmitListHead; + } else { + return EFI_UNSUPPORTED; + } + + Link = GetFirstNode (ListHead); + while (!IsNull (ListHead, Link)) { + Expression = FORM_EXPRESSION_FROM_LINK (Link); + + // + // Evaluate the expression + // + Status = EvaluateExpression (FormSet, Form, Expression); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Expression->Result.Value.b) { + // + // Condition meet, show up error message + // + if (Expression->Error != 0) { + PopUp = GetToken (Expression->Error, FormSet->HiiHandle); + do { + CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, PopUp, gPressEnter, gEmptyString); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + gBS->FreePool (PopUp); + } + + return EFI_NOT_READY; + } + + Link = GetNextNode (ListHead, Link); + } + + return EFI_SUCCESS; +} + + +/** + Perform NoSubmit check for a Form. + + @param FormSet FormSet data structure. + @param Form Form data structure. + + @retval EFI_SUCCESS Form validation pass. + @retval other Form validation failed. + +**/ +EFI_STATUS +NoSubmitCheck ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Question; + + Link = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, Link)) { + Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + + Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_NO_SUBMIT_IF); + if (EFI_ERROR (Status)) { + return Status; + } + + Link = GetNextNode (&Form->StatementListHead, Link); + } + + return EFI_SUCCESS; +} + + +/** + Submit a Form. + + @param FormSet FormSet data structure. + @param Form Form data structure. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +SubmitForm ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + EFI_STRING ConfigResp; + EFI_STRING Progress; + FORMSET_STORAGE *Storage; + + // + // Validate the Form by NoSubmit check + // + Status = NoSubmitCheck (FormSet, Form); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Submit Buffer storage or Name/Value storage + // + Link = GetFirstNode (&FormSet->StorageListHead); + while (!IsNull (&FormSet->StorageListHead, Link)) { + Storage = FORMSET_STORAGE_FROM_LINK (Link); + Link = GetNextNode (&FormSet->StorageListHead, Link); + + if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + continue; + } + + // + // Skip if there is no RequestElement + // + if (Storage->ElementCount == 0) { + continue; + } + + // + // Prepare <ConfigResp> + // + Status = StorageToConfigResp (Storage, &ConfigResp); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Send <ConfigResp> to Configuration Driver + // + if (FormSet->ConfigAccess != NULL) { + Status = FormSet->ConfigAccess->RouteConfig ( + FormSet->ConfigAccess, + ConfigResp, + &Progress + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (ConfigResp); + return Status; + } + } + gBS->FreePool (ConfigResp); + + // + // Config success, update storage shadow Buffer + // + SynchronizeStorage (Storage); + } + + gNvUpdateRequired = FALSE; + + return EFI_SUCCESS; +} + + +/** + Reset Question to its default value. + + @param FormSet FormSet data structure. + @param DefaultId The Class of the default. + + @retval EFI_SUCCESS Question is reset to default value. + +**/ +EFI_STATUS +GetQuestionDefault ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN FORM_BROWSER_STATEMENT *Question, + IN UINT16 DefaultId + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + QUESTION_DEFAULT *Default; + QUESTION_OPTION *Option; + EFI_HII_VALUE *HiiValue; + UINT8 Index; + + Status = EFI_SUCCESS; + + // + // Statement don't have storage, skip them + // + if (Question->QuestionId == 0) { + return Status; + } + + // + // There are three ways to specify default value for a Question: + // 1, use nested EFI_IFR_DEFAULT (highest priority) + // 2, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default) + // 3, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority) + // + HiiValue = &Question->HiiValue; + + // + // EFI_IFR_DEFAULT has highest priority + // + if (!IsListEmpty (&Question->DefaultListHead)) { + Link = GetFirstNode (&Question->DefaultListHead); + while (!IsNull (&Question->DefaultListHead, Link)) { + Default = QUESTION_DEFAULT_FROM_LINK (Link); + + if (Default->DefaultId == DefaultId) { + if (Default->ValueExpression != NULL) { + // + // Default is provided by an Expression, evaluate it + // + Status = EvaluateExpression (FormSet, Form, Default->ValueExpression); + if (EFI_ERROR (Status)) { + return Status; + } + + CopyMem (HiiValue, &Default->ValueExpression->Result, sizeof (EFI_HII_VALUE)); + } else { + // + // Default value is embedded in EFI_IFR_DEFAULT + // + CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE)); + } + + return EFI_SUCCESS; + } + + Link = GetNextNode (&Question->DefaultListHead, Link); + } + } + + // + // EFI_ONE_OF_OPTION + // + if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) { + if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) { + // + // OneOfOption could only provide Standard and Manufacturing default + // + Link = GetFirstNode (&Question->OptionListHead); + while (!IsNull (&Question->OptionListHead, Link)) { + Option = QUESTION_OPTION_FROM_LINK (Link); + + if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && (Option->Flags & EFI_IFR_OPTION_DEFAULT)) || + ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && (Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG)) + ) { + CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE)); + + return EFI_SUCCESS; + } + + Link = GetNextNode (&Question->OptionListHead, Link); + } + } + } + + // + // EFI_IFR_CHECKBOX - lowest priority + // + if (Question->Operand == EFI_IFR_CHECKBOX_OP) { + if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) { + // + // Checkbox could only provide Standard and Manufacturing default + // + if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && (Question->Flags & EFI_IFR_CHECKBOX_DEFAULT)) || + ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && (Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG)) + ) { + HiiValue->Value.b = TRUE; + } else { + HiiValue->Value.b = FALSE; + } + + return EFI_SUCCESS; + } + } + + // + // For Questions without default + // + switch (Question->Operand) { + case EFI_IFR_NUMERIC_OP: + // + // Take minimal value as numeric's default value + // + HiiValue->Value.u64 = Question->Minimum; + break; + + case EFI_IFR_ONE_OF_OP: + // + // Take first oneof option as oneof's default value + // + Link = GetFirstNode (&Question->OptionListHead); + if (!IsNull (&Question->OptionListHead, Link)) { + Option = QUESTION_OPTION_FROM_LINK (Link); + CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE)); + } + break; + + case EFI_IFR_ORDERED_LIST_OP: + // + // Take option sequence in IFR as ordered list's default value + // + Index = 0; + Link = GetFirstNode (&Question->OptionListHead); + while (!IsNull (&Question->OptionListHead, Link)) { + Option = QUESTION_OPTION_FROM_LINK (Link); + + Question->BufferValue[Index] = Option->Value.Value.u8; + + Index++; + if (Index >= Question->MaxContainers) { + break; + } + + Link = GetNextNode (&Question->OptionListHead, Link); + } + break; + + default: + Status = EFI_NOT_FOUND; + break; + } + + return Status; +} + + +/** + Reset Questions in a Form to their default value. + + @param FormSet FormSet data structure. + @param Form The Form which to be reset. + @param DefaultId The Class of the default. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +ExtractFormDefault ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN UINT16 DefaultId + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Question; + + Link = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, Link)) { + Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + Link = GetNextNode (&Form->StatementListHead, Link); + + // + // Reset Question to its default value + // + Status = GetQuestionDefault (FormSet, Form, Question, DefaultId); + if (EFI_ERROR (Status)) { + continue; + } + + // + // Synchronize Buffer storage's Edit buffer + // + if ((Question->Storage != NULL) && + (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) { + SetQuestionValue (FormSet, Form, Question, TRUE); + } + } + + return EFI_SUCCESS; +} + + +/** + Initialize Question's Edit copy from Storage. + + @param FormSet FormSet data structure. + @param Form Form data structure. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +LoadFormConfig ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Question; + + Link = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, Link)) { + Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + + // + // Initialize local copy of Value for each Question + // + Status = GetQuestionValue (FormSet, Form, Question, TRUE); + if (EFI_ERROR (Status)) { + return Status; + } + + Link = GetNextNode (&Form->StatementListHead, Link); + } + + return EFI_SUCCESS; +} + + +/** + Fill storage's edit copy with settings requested from Configuration Driver. + + @param FormSet FormSet data structure. + @param Storage Buffer Storage. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +LoadStorage ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORMSET_STORAGE *Storage + ) +{ + EFI_STATUS Status; + EFI_STRING Progress; + EFI_STRING Result; + CHAR16 *StrPtr; + + if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + return EFI_SUCCESS; + } + + if (FormSet->ConfigAccess == NULL) { + return EFI_NOT_FOUND; + } + + if (Storage->ElementCount == 0) { + // + // Skip if there is no RequestElement + // + return EFI_SUCCESS; + } + + // + // Request current settings from Configuration Driver + // + Status = FormSet->ConfigAccess->ExtractConfig ( + FormSet->ConfigAccess, + Storage->ConfigRequest, + &Progress, + &Result + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Convert Result from <ConfigAltResp> to <ConfigResp> + // + StrPtr = StrStr (Result, L"ALTCFG"); + if (StrPtr != NULL) { + *StrPtr = L'\0'; + } + + Status = ConfigRespToStorage (Storage, Result); + gBS->FreePool (Result); + return Status; +} + + +/** + Get current setting of Questions. + + @param FormSet FormSet data structure. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +InitializeCurrentSetting ( + IN OUT FORM_BROWSER_FORMSET *FormSet + ) +{ + LIST_ENTRY *Link; + FORMSET_STORAGE *Storage; + FORM_BROWSER_FORM *Form; + EFI_STATUS Status; + + // + // Extract default from IFR binary + // + Link = GetFirstNode (&FormSet->FormListHead); + while (!IsNull (&FormSet->FormListHead, Link)) { + Form = FORM_BROWSER_FORM_FROM_LINK (Link); + + Status = ExtractFormDefault (FormSet, Form, EFI_HII_DEFAULT_CLASS_STANDARD); + + Link = GetNextNode (&FormSet->FormListHead, Link); + } + + // + // Request current settings from Configuration Driver + // + Link = GetFirstNode (&FormSet->StorageListHead); + while (!IsNull (&FormSet->StorageListHead, Link)) { + Storage = FORMSET_STORAGE_FROM_LINK (Link); + + Status = LoadStorage (FormSet, Storage); + + // + // Now Edit Buffer is filled with default values(lower priority) and current + // settings(higher priority), sychronize it to shadow Buffer + // + if (!EFI_ERROR (Status)) { + SynchronizeStorage (Storage); + } + + Link = GetNextNode (&FormSet->StorageListHead, Link); + } + + return EFI_SUCCESS; +} + + +/** + Fetch the Ifr binary data of a FormSet. + + @param Handle PackageList Handle + @param FormSetGuid GUID of a formset. If not specified (NULL or zero + GUID), take the first FormSet found in package + list. + @param BinaryLength The length of the FormSet IFR binary. + @param BinaryData The buffer designed to receive the FormSet. + + @retval EFI_SUCCESS Buffer filled with the requested FormSet. + BufferLength was updated. + @retval EFI_INVALID_PARAMETER The handle is unknown. + @retval EFI_NOT_FOUND A form or FormSet on the requested handle cannot + be found with the requested FormId. + +**/ +EFI_STATUS +GetIfrBinaryData ( + IN EFI_HII_HANDLE Handle, + IN OUT EFI_GUID *FormSetGuid, + OUT UINTN *BinaryLength, + OUT UINT8 **BinaryData + ) +{ + EFI_STATUS Status; + EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList; + UINTN BufferSize; + UINT8 *Package; + UINT8 *OpCodeData; + UINT32 Offset; + UINT32 Offset2; + BOOLEAN ReturnDefault; + UINT32 PackageListLength; + EFI_HII_PACKAGE_HEADER PackageHeader; + + OpCodeData = NULL; + Package = NULL; + ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));; + + // + // if FormSetGuid is NULL or zero GUID, return first FormSet in the package list + // + if (FormSetGuid == NULL || CompareGuid (FormSetGuid, &gZeroGuid)) { + ReturnDefault = TRUE; + } else { + ReturnDefault = FALSE; + } + + // + // Get HII PackageList + // + BufferSize = 0; + HiiPackageList = NULL; + Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList); + if (Status == EFI_BUFFER_TOO_SMALL) { + HiiPackageList = AllocatePool (BufferSize); + ASSERT (HiiPackageList != NULL); + + Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList); + } + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get Form package from this HII package List + // + Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER); + Offset2 = 0; + CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32)); + + while (Offset < PackageListLength) { + Package = ((UINT8 *) HiiPackageList) + Offset; + CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER)); + + if (PackageHeader.Type == EFI_HII_PACKAGE_FORM) { + // + // Search FormSet in this Form Package + // + Offset2 = sizeof (EFI_HII_PACKAGE_HEADER); + while (Offset2 < PackageHeader.Length) { + OpCodeData = Package + Offset2; + + if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) { + // + // Check whether return default FormSet + // + if (ReturnDefault) { + break; + } + + // + // FormSet GUID is specified, check it + // + if (CompareGuid (FormSetGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) { + break; + } + } + + Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length; + } + + if (Offset2 < PackageHeader.Length) { + // + // Target formset found + // + break; + } + } + + Offset += PackageHeader.Length; + } + + if (Offset >= PackageListLength) { + // + // Form package not found in this Package List + // + gBS->FreePool (HiiPackageList); + return EFI_NOT_FOUND; + } + + if (ReturnDefault && FormSetGuid != NULL) { + // + // Return the default FormSet GUID + // + CopyMem (FormSetGuid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID)); + } + + // + // To determine the length of a whole FormSet IFR binary, one have to parse all the Opcodes + // in this FormSet; So, here just simply copy the data from start of a FormSet to the end + // of the Form Package. + // + *BinaryLength = PackageHeader.Length - Offset2; + *BinaryData = AllocateCopyPool (*BinaryLength, OpCodeData); + + gBS->FreePool (HiiPackageList); + + if (*BinaryData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + + +/** + Initialize the internal data structure of a FormSet. + + @param Handle PackageList Handle + @param FormSetGuid GUID of a formset. If not specified (NULL or zero + GUID), take the first FormSet found in package + list. + @param FormSet FormSet data structure. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_NOT_FOUND The specified FormSet could not be found. + +**/ +EFI_STATUS +InitializeFormSet ( + IN EFI_HII_HANDLE Handle, + IN OUT EFI_GUID *FormSetGuid, + OUT FORM_BROWSER_FORMSET *FormSet + ) +{ + EFI_STATUS Status; + EFI_HANDLE DriverHandle; + UINT16 Index; + + Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData); + if (EFI_ERROR (Status)) { + return Status; + } + + FormSet->HiiHandle = Handle; + CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID)); + + // + // Retrieve ConfigAccess Protocol associated with this HiiPackageList + // + Status = mHiiDatabase->GetPackageListHandle (mHiiDatabase, Handle, &DriverHandle); + if (EFI_ERROR (Status)) { + return Status; + } + FormSet->DriverHandle = DriverHandle; + Status = gBS->HandleProtocol ( + DriverHandle, + &gEfiHiiConfigAccessProtocolGuid, + (VOID **) &FormSet->ConfigAccess + ); + if (EFI_ERROR (Status)) { + // + // Configuration Driver don't attach ConfigAccess protocol to its HII package + // list, then there will be no configuration action required + // + FormSet->ConfigAccess = NULL; + } + + // + // Parse the IFR binary OpCodes + // + Status = ParseOpCodes (FormSet); + if (EFI_ERROR (Status)) { + return Status; + } + + gClassOfVfr = FormSet->SubClass; + if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) { + FrontPageHandle = FormSet->HiiHandle; + } + + // + // Match GUID to find out the function key setting. If match fail, use the default setting. + // + for (Index = 0; Index < sizeof (gFunctionKeySettingTable) / sizeof (FUNCTIION_KEY_SETTING); Index++) { + if (CompareGuid (&FormSet->Guid, &(gFunctionKeySettingTable[Index].FormSetGuid))) { + // + // Update the function key setting. + // + gFunctionKeySetting = gFunctionKeySettingTable[Index].KeySetting; + // + // Function key prompt can not be displayed if the function key has been disabled. + // + if ((gFunctionKeySetting & FUNCTION_ONE) != FUNCTION_ONE) { + gFunctionOneString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); + } + + if ((gFunctionKeySetting & FUNCTION_TWO) != FUNCTION_TWO) { + gFunctionTwoString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); + } + + if ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE) { + gFunctionNineString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); + } + + if ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN) { + gFunctionTenString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); + } + } + } + + return Status; +} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h new file mode 100644 index 0000000000..3ade4dac57 --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h @@ -0,0 +1,760 @@ +/** @file + +Copyright (c) 2007, Intel Corporation +All rights reserved. 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. + +Module Name: + + Setup.h + +Abstract: + + +Revision History + + +**/ + +#ifndef _SETUP_H +#define _SETUP_H + + +#include <PiDxe.h> + +#include <Protocol/Print.h> +#include <Protocol/SimpleTextOut.h> +#include <Protocol/SimpleTextIn.h> +#include <Protocol/FormBrowser2.h> +#include <Protocol/DevicePath.h> +#include <Protocol/UnicodeCollation.h> +#include <Protocol/HiiConfigAccess.h> +#include <Protocol/HiiConfigRouting.h> +#include <Protocol/HiiDatabase.h> +#include <Protocol/HiiString.h> + +#include <MdeModuleHii.h> + +#include <Library/GraphicsLib.h> +#include <Library/PrintLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/UefiRuntimeServicesTableLib.h> +#include <Library/UefiDriverEntryPoint.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/BaseLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/IfrSupportLib.h> +#include <Library/HiiLib.h> + +#include "R8Lib.h" + +#include "Colors.h" + +//@MT:#include EFI_PROTOCOL_DEFINITION (HiiDatabase) +//@MT:#include EFI_PROTOCOL_DEFINITION (HiiString) +//@MT:#include EFI_PROTOCOL_DEFINITION (HiiConfigRouting) +//@MT:#include EFI_PROTOCOL_DEFINITION (HiiConfigAccess) +//@MT:#include EFI_PROTOCOL_DEFINITION (FormBrowser2) + +//@MT:#include EFI_GUID_DEFINITION (GlobalVariable) +//@MT:#include EFI_PROTOCOL_DEFINITION (DevicePath) +//@MT:#include EFI_PROTOCOL_DEFINITION (SimpleTextOut) +//@MT:#include EFI_PROTOCOL_DEFINITION (SimpleTextIn) +//@MT:#include EFI_PROTOCOL_DEFINITION (Print) +//@MT:#include EFI_PROTOCOL_DEFINITION (UnicodeCollation) + +// +// This is the generated header file which includes whatever needs to be exported (strings + IFR) +// + +extern UINT8 SetupBrowserStrings[]; + +// +// Screen definitions +// +#define BANNER_HEIGHT 6 +#define BANNER_COLUMNS 3 + +#define FRONT_PAGE_HEADER_HEIGHT 6 +#define NONE_FRONT_PAGE_HEADER_HEIGHT 3 +#define LEFT_SKIPPED_COLUMNS 4 +#define FOOTER_HEIGHT 4 +#define STATUS_BAR_HEIGHT 1 +#define SCROLL_ARROW_HEIGHT 1 +#define POPUP_PAD_SPACE_COUNT 5 +#define POPUP_FRAME_WIDTH 2 + +// +// Definition for function key setting +// +#define NONE_FUNCTION_KEY_SETTING 0 +#define DEFAULT_FUNCTION_KEY_SETTING (FUNCTION_ONE | FUNCTION_TWO | FUNCTION_NINE | FUNCTION_TEN) + +#define FUNCTION_ONE (1 << 0) +#define FUNCTION_TWO (1 << 1) +#define FUNCTION_NINE (1 << 2) +#define FUNCTION_TEN (1 << 3) + +typedef struct { + EFI_GUID FormSetGuid; + UINTN KeySetting; +} FUNCTIION_KEY_SETTING; + +// +// Character definitions +// +#define CHAR_SPACE 0x0020 +#define UPPER_LOWER_CASE_OFFSET 0x20 + +// +// Time definitions +// +#define ONE_SECOND 10000000 + +// +// Display definitions +// +#define LEFT_HYPER_DELIMITER L'<' +#define RIGHT_HYPER_DELIMITER L'>' + +#define LEFT_ONEOF_DELIMITER L'<' +#define RIGHT_ONEOF_DELIMITER L'>' + +#define LEFT_NUMERIC_DELIMITER L'[' +#define RIGHT_NUMERIC_DELIMITER L']' + +#define LEFT_CHECKBOX_DELIMITER L'[' +#define RIGHT_CHECKBOX_DELIMITER L']' + +#define CHECK_ON L'X' +#define CHECK_OFF L' ' + +#define TIME_SEPARATOR L':' +#define DATE_SEPARATOR L'/' + +#define YES_ANSWER L'Y' +#define NO_ANSWER L'N' + +// +// This is the Input Error Message +// +#define INPUT_ERROR 1 + +// +// This is the NV RAM update required Message +// +#define NV_UPDATE_REQUIRED 2 + +// +// Refresh the Status Bar with flags +// +#define REFRESH_STATUS_BAR 0xff + +// +// Incremental string lenght of ConfigRequest +// +#define CONFIG_REQUEST_STRING_INCREMENTAL 1024 + +// +// HII value compare result +// +#define HII_VALUE_UNDEFINED 0 +#define HII_VALUE_EQUAL 1 +#define HII_VALUE_LESS_THAN 2 +#define HII_VALUE_GREATER_THAN 3 + +// +// Incremental size of stack for expression +// +#define EXPRESSION_STACK_SIZE_INCREMENT 0x100 + + +#define EFI_SPECIFICATION_ERRATA_VERSION 0 + +#define EFI_IFR_SPECIFICATION_VERSION \ + ((((EFI_SPECIFICATION_VERSION) >> 8) & 0xff00) | \ + (((EFI_SPECIFICATION_VERSION) & 0xf) << 4) | \ + ((EFI_SPECIFICATION_ERRATA_VERSION) & 0xf)) + +#define SETUP_DRIVER_SIGNATURE EFI_SIGNATURE_32 ('F', 'B', 'D', 'V') +typedef struct { + UINT32 Signature; + + EFI_HANDLE Handle; + + // + // Produced protocol + // + EFI_FORM_BROWSER2_PROTOCOL FormBrowser2; + EFI_PRINT_PROTOCOL Print; + +} SETUP_DRIVER_PRIVATE_DATA; + +typedef struct { + EFI_STRING_ID Banner[BANNER_HEIGHT][BANNER_COLUMNS]; +} BANNER_DATA; + +// +// IFR relative definition +// +#define EFI_HII_EXPRESSION_INCONSISTENT_IF 0 +#define EFI_HII_EXPRESSION_NO_SUBMIT_IF 1 +#define EFI_HII_EXPRESSION_GRAY_OUT_IF 2 +#define EFI_HII_EXPRESSION_SUPPRESS_IF 3 +#define EFI_HII_EXPRESSION_DISABLE_IF 4 +#define EFI_HII_EXPRESSION_VALUE 5 +#define EFI_HII_EXPRESSION_RULE 6 + +#define EFI_HII_VARSTORE_BUFFER 0 +#define EFI_HII_VARSTORE_NAME_VALUE 1 +#define EFI_HII_VARSTORE_EFI_VARIABLE 2 + +#define FORM_INCONSISTENT_VALIDATION 0 +#define FORM_NO_SUBMIT_VALIDATION 1 + +typedef struct { + UINT8 Type; + EFI_IFR_TYPE_VALUE Value; +} EFI_HII_VALUE; + +#define NAME_VALUE_NODE_SIGNATURE EFI_SIGNATURE_32 ('N', 'V', 'S', 'T') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + CHAR16 *Name; + CHAR16 *Value; + CHAR16 *EditValue; +} NAME_VALUE_NODE; + +#define NAME_VALUE_NODE_FROM_LINK(a) CR (a, NAME_VALUE_NODE, Link, NAME_VALUE_NODE_SIGNATURE) + +#define FORMSET_STORAGE_SIGNATURE EFI_SIGNATURE_32 ('F', 'S', 'T', 'G') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + UINT8 Type; // Storage type + + UINT16 VarStoreId; + EFI_GUID Guid; + + CHAR16 *Name; // For EFI_IFR_VARSTORE + UINT16 Size; + UINT8 *Buffer; + UINT8 *EditBuffer; // Edit copy for Buffer Storage + + LIST_ENTRY NameValueListHead; // List of NAME_VALUE_NODE + + UINT32 Attributes; // For EFI_IFR_VARSTORE_EFI: EFI Variable attribute + + CHAR16 *ConfigHdr; // <ConfigHdr> + CHAR16 *ConfigRequest; // <ConfigRequest> = <ConfigHdr> + <RequestElement> + UINTN ElementCount; // Number of <RequestElement> in the <ConfigRequest> + UINTN SpareStrLen; // Spare length of ConfigRequest string buffer +} FORMSET_STORAGE; + +#define FORMSET_STORAGE_FROM_LINK(a) CR (a, FORMSET_STORAGE, Link, FORMSET_STORAGE_SIGNATURE) + +#define EXPRESSION_OPCODE_SIGNATURE EFI_SIGNATURE_32 ('E', 'X', 'O', 'P') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + UINT8 Operand; + + UINT8 Format; // For EFI_IFR_TO_STRING, EFI_IFR_FIND + UINT8 Flags; // For EFI_IFR_SPAN + UINT8 RuleId; // For EFI_IFR_RULE_REF + + EFI_HII_VALUE Value; // For EFI_IFR_EQ_ID_VAL, EFI_IFR_UINT64, EFI_IFR_UINT32, EFI_IFR_UINT16, EFI_IFR_UINT8, EFI_IFR_STRING_REF1 + + EFI_QUESTION_ID QuestionId; // For EFI_IFR_EQ_ID_ID, EFI_IFR_EQ_ID_LIST, EFI_IFR_QUESTION_REF1 + EFI_QUESTION_ID QuestionId2; + + UINT16 ListLength; // For EFI_IFR_EQ_ID_LIST + UINT16 *ValueList; + + EFI_STRING_ID DevicePath; // For EFI_IFR_QUESTION_REF3_2, EFI_IFR_QUESTION_REF3_3 + EFI_GUID Guid; +} EXPRESSION_OPCODE; + +#define EXPRESSION_OPCODE_FROM_LINK(a) CR (a, EXPRESSION_OPCODE, Link, EXPRESSION_OPCODE_SIGNATURE) + +#define FORM_EXPRESSION_SIGNATURE EFI_SIGNATURE_32 ('F', 'E', 'X', 'P') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + UINT8 Type; // Type for this expression + + UINT8 RuleId; // For EFI_IFR_RULE only + EFI_STRING_ID Error; // For EFI_IFR_NO_SUBMIT_IF, EFI_IFR_INCONSISTENT_IF only + + EFI_HII_VALUE Result; // Expression evaluation result + + LIST_ENTRY OpCodeListHead; // OpCodes consist of this expression (EXPRESSION_OPCODE) +} FORM_EXPRESSION; + +#define FORM_EXPRESSION_FROM_LINK(a) CR (a, FORM_EXPRESSION, Link, FORM_EXPRESSION_SIGNATURE) + +#define QUESTION_DEFAULT_SIGNATURE EFI_SIGNATURE_32 ('Q', 'D', 'F', 'T') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + UINT16 DefaultId; + EFI_HII_VALUE Value; // Default value + + FORM_EXPRESSION *ValueExpression; // Not-NULL indicates default value is provided by EFI_IFR_VALUE +} QUESTION_DEFAULT; + +#define QUESTION_DEFAULT_FROM_LINK(a) CR (a, QUESTION_DEFAULT, Link, QUESTION_DEFAULT_SIGNATURE) + +#define QUESTION_OPTION_SIGNATURE EFI_SIGNATURE_32 ('Q', 'O', 'P', 'T') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + EFI_STRING_ID Text; + UINT8 Flags; + EFI_HII_VALUE Value; + EFI_IMAGE_ID ImageId; + + FORM_EXPRESSION *SuppressExpression; // Non-NULL indicates nested inside of SuppressIf +} QUESTION_OPTION; + +#define QUESTION_OPTION_FROM_LINK(a) CR (a, QUESTION_OPTION, Link, QUESTION_OPTION_SIGNATURE) + +#define FORM_BROWSER_STATEMENT_SIGNATURE EFI_SIGNATURE_32 ('F', 'S', 'T', 'A') +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + UINT8 Operand; // The operand (first byte) of this Statement or Question + + // + // Statement Header + // + EFI_STRING_ID Prompt; + EFI_STRING_ID Help; + EFI_STRING_ID TextTwo; // For EFI_IFR_TEXT + + // + // Question Header + // + EFI_QUESTION_ID QuestionId; // The value of zero is reserved + EFI_VARSTORE_ID VarStoreId; // A value of zero indicates no variable storage + FORMSET_STORAGE *Storage; + union { + EFI_STRING_ID VarName; + UINT16 VarOffset; + } VarStoreInfo; + UINT16 StorageWidth; + UINT8 QuestionFlags; + CHAR16 *VariableName; // Name/Value or EFI Variable name + CHAR16 *BlockName; // Buffer storage block name: "OFFSET=...WIDTH=..." + + EFI_HII_VALUE HiiValue; // Edit copy for checkbox, numberic, oneof + UINT8 *BufferValue; // Edit copy for string, password, orderedlist + + // + // OpCode specific members + // + UINT8 Flags; // for EFI_IFR_CHECKBOX, EFI_IFR_DATE, EFI_IFR_NUMERIC, EFI_IFR_ONE_OF, + // EFI_IFR_ORDERED_LIST, EFI_IFR_STRING,EFI_IFR_SUBTITLE,EFI_IFR_TIME, EFI_IFR_BANNER + UINT8 MaxContainers; // for EFI_IFR_ORDERED_LIST + + UINT16 BannerLineNumber; // for EFI_IFR_BANNER, 1-based line number + EFI_STRING_ID QuestionConfig; // for EFI_IFR_ACTION, if 0 then no configuration string will be processed + + UINT64 Minimum; // for EFI_IFR_ONE_OF/EFI_IFR_NUMERIC, it's Min/Max value + UINT64 Maximum; // for EFI_IFR_STRING/EFI_IFR_PASSWORD, it's Min/Max length + UINT64 Step; + + EFI_DEFAULT_ID DefaultId; // for EFI_IFR_RESET_BUTTON + EFI_FORM_ID RefFormId; // for EFI_IFR_REF + EFI_QUESTION_ID RefQuestionId; // for EFI_IFR_REF2 + EFI_GUID RefFormSetId; // for EFI_IFR_REF3 + EFI_STRING_ID RefDevicePath; // for EFI_IFR_REF4 + + // + // Get from IFR parsing + // + FORM_EXPRESSION *ValueExpression; // nested EFI_IFR_VALUE, provide Question value and indicate Question is ReadOnly + LIST_ENTRY DefaultListHead; // nested EFI_IFR_DEFAULT list (QUESTION_DEFAULT), provide default values + LIST_ENTRY OptionListHead; // nested EFI_IFR_ONE_OF_OPTION list (QUESTION_OPTION) + + EFI_IMAGE_ID ImageId; // nested EFI_IFR_IMAGE + UINT8 RefreshInterval; // nested EFI_IFR_REFRESH, refresh interval(in seconds) for Question value, 0 means no refresh + BOOLEAN InSubtitle; // nesting inside of EFI_IFR_SUBTITLE + + LIST_ENTRY InconsistentListHead;// nested inconsistent expression list (FORM_EXPRESSION) + LIST_ENTRY NoSubmitListHead; // nested nosubmit expression list (FORM_EXPRESSION) + FORM_EXPRESSION *GrayOutExpression; // nesting inside of GrayOutIf + FORM_EXPRESSION *SuppressExpression; // nesting inside of SuppressIf + +} FORM_BROWSER_STATEMENT; + +#define FORM_BROWSER_STATEMENT_FROM_LINK(a) CR (a, FORM_BROWSER_STATEMENT, Link, FORM_BROWSER_STATEMENT_SIGNATURE) + +#define FORM_BROWSER_FORM_SIGNATURE EFI_SIGNATURE_32 ('F', 'F', 'R', 'M') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + UINT16 FormId; + EFI_STRING_ID FormTitle; + + EFI_IMAGE_ID ImageId; + + LIST_ENTRY ExpressionListHead; // List of Expressions (FORM_EXPRESSION) + LIST_ENTRY StatementListHead; // List of Statements and Questions (FORM_BROWSER_STATEMENT) +} FORM_BROWSER_FORM; + +#define FORM_BROWSER_FORM_FROM_LINK(a) CR (a, FORM_BROWSER_FORM, Link, FORM_BROWSER_FORM_SIGNATURE) + +#define FORMSET_DEFAULTSTORE_SIGNATURE EFI_SIGNATURE_32 ('F', 'D', 'F', 'S') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + UINT16 DefaultId; + EFI_STRING_ID DefaultName; +} FORMSET_DEFAULTSTORE; + +#define FORMSET_DEFAULTSTORE_FROM_LINK(a) CR (a, FORMSET_DEFAULTSTORE, Link, FORMSET_DEFAULTSTORE_SIGNATURE) + +typedef struct { + EFI_HII_HANDLE HiiHandle; + EFI_HANDLE DriverHandle; + EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + UINTN IfrBinaryLength; + UINT8 *IfrBinaryData; + + EFI_GUID Guid; + EFI_STRING_ID FormSetTitle; + EFI_STRING_ID Help; + UINT16 Class; + UINT16 SubClass; + EFI_IMAGE_ID ImageId; + + FORM_BROWSER_STATEMENT *StatementBuffer; // Buffer for all Statements and Questions + EXPRESSION_OPCODE *ExpressionBuffer; // Buffer for all Expression OpCode + + LIST_ENTRY StorageListHead; // Storage list (FORMSET_STORAGE) + LIST_ENTRY DefaultStoreListHead; // DefaultStore list (FORMSET_DEFAULTSTORE) + LIST_ENTRY FormListHead; // Form list (FORM_BROWSER_FORM) +} FORM_BROWSER_FORMSET; + + +extern EFI_HII_DATABASE_PROTOCOL *mHiiDatabase; +extern EFI_HII_STRING_PROTOCOL *mHiiString; +extern EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting; + +extern BANNER_DATA *BannerData; +extern EFI_HII_HANDLE FrontPageHandle; +extern UINTN gClassOfVfr; +extern UINTN gFunctionKeySetting; +extern BOOLEAN gResetRequired; +extern BOOLEAN gNvUpdateRequired; +extern EFI_HII_HANDLE gHiiHandle; +extern BOOLEAN gFirstIn; +extern UINT16 gDirection; +extern EFI_SCREEN_DESCRIPTOR gScreenDimensions; +extern BOOLEAN gUpArrow; +extern BOOLEAN gDownArrow; + +// +// Browser Global Strings +// +extern CHAR16 *gFunctionOneString; +extern CHAR16 *gFunctionTwoString; +extern CHAR16 *gFunctionNineString; +extern CHAR16 *gFunctionTenString; +extern CHAR16 *gEnterString; +extern CHAR16 *gEnterCommitString; +extern CHAR16 *gEscapeString; +extern CHAR16 *gSaveFailed; +extern CHAR16 *gMoveHighlight; +extern CHAR16 *gMakeSelection; +extern CHAR16 *gDecNumericInput; +extern CHAR16 *gHexNumericInput; +extern CHAR16 *gToggleCheckBox; +extern CHAR16 *gPromptForData; +extern CHAR16 *gPromptForPassword; +extern CHAR16 *gPromptForNewPassword; +extern CHAR16 *gConfirmPassword; +extern CHAR16 *gConfirmError; +extern CHAR16 *gPassowordInvalid; +extern CHAR16 *gPressEnter; +extern CHAR16 *gEmptyString; +extern CHAR16 *gAreYouSure; +extern CHAR16 *gYesResponse; +extern CHAR16 *gNoResponse; +extern CHAR16 *gMiniString; +extern CHAR16 *gPlusString; +extern CHAR16 *gMinusString; +extern CHAR16 *gAdjustNumber; + +extern CHAR16 gPromptBlockWidth; +extern CHAR16 gOptionBlockWidth; +extern CHAR16 gHelpBlockWidth; + +extern EFI_GUID gZeroGuid; +extern EFI_GUID gTianoHiiIfrGuid; + +// +// Global Procedure Defines +// +VOID +InitializeBrowserStrings ( + VOID + ) +; + +UINTN +_Print ( + IN CHAR16 *fmt, + ... + ) +; + +UINTN +PrintString ( + CHAR16 *String + ) +; + +UINTN +PrintChar ( + CHAR16 Character + ) +; + +UINTN +PrintAt ( + IN UINTN Column, + IN UINTN Row, + IN CHAR16 *fmt, + ... + ) +; + +UINTN +PrintStringAt ( + IN UINTN Column, + IN UINTN Row, + CHAR16 *String + ) +; + +UINTN +PrintCharAt ( + IN UINTN Column, + IN UINTN Row, + CHAR16 Character + ) +; + +EFI_STATUS +ParseOpCodes ( + IN FORM_BROWSER_FORMSET *FormSet + ) +; + +VOID +DestroyFormSet ( + IN OUT FORM_BROWSER_FORMSET *FormSet + ) +; + +VOID +DisplayPageFrame ( + VOID + ) +; + +EFI_STRING_ID +NewString ( + IN CHAR16 *String, + IN EFI_HII_HANDLE HiiHandle + ) +; + +EFI_STATUS +DeleteString ( + IN EFI_STRING_ID StringId, + IN EFI_HII_HANDLE HiiHandle + ) +; +CHAR16 * +GetToken ( + IN EFI_STRING_ID Token, + IN EFI_HII_HANDLE HiiHandle + ) +; + +VOID +CreateSharedPopUp ( + IN UINTN RequestedWidth, + IN UINTN NumberOfLines, + IN CHAR16 **ArrayOfStrings + ) +; + +EFI_STATUS +CreateDialog ( + IN UINTN NumberOfLines, + IN BOOLEAN HotKey, + IN UINTN MaximumStringSize, + OUT CHAR16 *StringBuffer, + OUT EFI_INPUT_KEY *KeyValue, + IN CHAR16 *String, + ... + ) +; + +EFI_STATUS +GetQuestionValue ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_BROWSER_STATEMENT *Question, + IN BOOLEAN Cached + ) +; + +EFI_STATUS +SetQuestionValue ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_BROWSER_STATEMENT *Question, + IN BOOLEAN Cached + ) +; + +EFI_STATUS +ValidateQuestion ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN FORM_BROWSER_STATEMENT *Question, + IN UINTN Type + ) +; + +EFI_STATUS +SubmitForm ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +; + +EFI_STATUS +GetQuestionDefault ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN FORM_BROWSER_STATEMENT *Question, + IN UINT16 DefaultId + ) +; + +EFI_STATUS +InitializeCurrentSetting ( + IN OUT FORM_BROWSER_FORMSET *FormSet + ) +; + +EFI_STATUS +InitializeFormSet ( + IN EFI_HII_HANDLE Handle, + IN OUT EFI_GUID *FormSetGuid, + OUT FORM_BROWSER_FORMSET *FormSet + ) +; + +EFI_STATUS +ExtractFormDefault ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN UINT16 DefaultId + ) +; + +EFI_STATUS +LoadFormConfig ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +; + +EFI_STATUS +StorageToConfigResp ( + IN FORMSET_STORAGE *Storage, + IN CHAR16 **ConfigResp + ) +; + +EFI_STATUS +ConfigRespToStorage ( + IN FORMSET_STORAGE *Storage, + IN CHAR16 *ConfigResp + ) +; + +EFI_STATUS +LoadStorage ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORMSET_STORAGE *Storage + ) +; + +EFI_STATUS +GetIfrBinaryData ( + IN EFI_HII_HANDLE Handle, + IN OUT EFI_GUID *FormSetGuid, + OUT UINTN *BinaryLength, + OUT UINT8 **BinaryData + ) +; + +EFI_STATUS +EFIAPI +SendForm ( + IN CONST EFI_FORM_BROWSER2_PROTOCOL *This, + IN EFI_HII_HANDLE *Handles, + IN UINTN HandleCount, + IN EFI_GUID *FormSetGuid, OPTIONAL + IN UINT16 FormId, OPTIONAL + IN CONST EFI_SCREEN_DESCRIPTOR *ScreenDimensions, OPTIONAL + OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest OPTIONAL + ) +; + +EFI_STATUS +EFIAPI +BrowserCallback ( + IN CONST EFI_FORM_BROWSER2_PROTOCOL *This, + IN OUT UINTN *ResultsDataSize, + IN OUT EFI_STRING ResultsData, + IN BOOLEAN RetrieveData, + IN CONST EFI_GUID *VariableGuid, OPTIONAL + IN CONST CHAR16 *VariableName OPTIONAL + ) +; + +#endif diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowser.msa b/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowser.msa new file mode 100644 index 0000000000..57774992fe --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowser.msa @@ -0,0 +1,84 @@ +<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <MsaHeader>
+ <ModuleName>SetupBrowser</ModuleName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <GuidValue>EBf342FE-B1D3-4EF8-957C-8048606FF671</GuidValue>
+ <Version>1.0</Version>
+ <Abstract>Component name for module SetupBrowser</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2007, Intel Corporation. All rights reserved.</Copyright>
+ <License>All rights reserved. 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.</License>
+ <Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
+ </MsaHeader>
+ <ModuleDefinitions>
+ <SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>
+ <BinaryModule>false</BinaryModule>
+ <OutputFileBasename>SetupBrowser</OutputFileBasename>
+ </ModuleDefinitions>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>PrintLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>DebugLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>BaseMemoryLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiRuntimeServicesTableLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiDriverEntryPoint</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiBootServicesTableLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>BaseLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>MemoryAllocationLib</Keyword>
+ </LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>R8Lib.h</Filename>
+ <Filename>Print.h</Filename>
+ <Filename>Setup.c</Filename>
+ <Filename>Setup.h</Filename>
+ <Filename>Ui.h</Filename>
+ <Filename>Print.c</Filename>
+ <Filename>SetupBrowser.dxs</Filename>
+ <Filename>R8Lib.c</Filename>
+ <Filename>ProcessOptions.c</Filename>
+ <Filename>InputHandler.c</Filename>
+ <Filename>Ui.c</Filename>
+ <Filename>IfrParse.c</Filename>
+ <Filename>Expression.c</Filename>
+ <Filename>Colors.h</Filename>
+ <Filename>Presentation.c</Filename>
+ <Filename>SetupBrowserStr.uni</Filename>
+ </SourceFiles>
+ <PackageDependencies>
+ <Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>
+ <Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>
+ </PackageDependencies>
+ <Protocols>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiPrintProtocolGuid</ProtocolCName>
+ </Protocol>
+ </Protocols>
+ <Externs>
+ <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
+ <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
+ <Extern>
+ <ModuleEntryPoint>InitializeSetup</ModuleEntryPoint>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
\ No newline at end of file diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf b/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf new file mode 100644 index 0000000000..807076e8ad --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf @@ -0,0 +1,82 @@ +#/** @file
+# Component name for module SetupBrowser
+#
+# FIX ME!
+# Copyright (c) 2007, Intel Corporation. All rights reserved.
+#
+# All rights reserved. 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 = 0x00010005
+ BASE_NAME = SetupBrowser
+ FILE_GUID = EBf342FE-B1D3-4EF8-957C-8048606FF671
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ EDK_RELEASE_VERSION = 0x00020000
+ EFI_SPECIFICATION_VERSION = 0x0002000A
+
+ ENTRY_POINT = InitializeSetup
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+ SetupBrowserStr.uni
+ Setup.c
+ Setup.h
+ IfrParse.c
+ Expression.c
+ InputHandler.c
+ Print.c
+ Print.h
+ Presentation.c
+ ProcessOptions.c
+ Ui.c
+ Ui.h
+ R8Lib.c
+ R8Lib.h
+ Colors.h
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiRuntimeServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ PrintLib
+ GraphicsLib
+ IfrSupportLib
+ HiiLib
+
+[Protocols]
+ gEfiPrintProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiHiiConfigAccessProtocolGuid
+ gEfiHiiStringProtocolGuid
+ gEfiFormBrowser2ProtocolGuid
+ gEfiHiiConfigRoutingProtocolGuid
+ gEfiHiiDatabaseProtocolGuid
+ gEfiUnicodeCollation2ProtocolGuid
+
+[Depex]
+ gEfiHiiDatabaseProtocolGuid AND gEfiHiiConfigRoutingProtocolGuid
+
diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserStr.uni b/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserStr.uni Binary files differnew file mode 100644 index 0000000000..5b5e282d84 --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserStr.uni diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Ui.c b/MdeModulePkg/Universal/SetupBrowserDxe/Ui.c new file mode 100644 index 0000000000..34ec5260de --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Ui.c @@ -0,0 +1,2830 @@ +/** @file + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. 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. + +Module Name: + + Ui.c + +Abstract: + + Implementation for UI. + +Revision History + + +**/ + +#include "Ui.h" +#include "Setup.h" + +LIST_ENTRY Menu; +LIST_ENTRY gMenuList; +MENU_REFRESH_ENTRY *gMenuRefreshHead; + +// +// Search table for UiDisplayMenu() +// +SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation[] = { + SCAN_UP, + UiUp, + SCAN_DOWN, + UiDown, + SCAN_PAGE_UP, + UiPageUp, + SCAN_PAGE_DOWN, + UiPageDown, + SCAN_ESC, + UiReset, + SCAN_F2, + UiPrevious, + SCAN_LEFT, + UiLeft, + SCAN_RIGHT, + UiRight, + SCAN_F9, + UiDefault, + SCAN_F10, + UiSave +}; + +SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag[] = { + UiNoOperation, + CfUiNoOperation, + UiDefault, + CfUiDefault, + UiSelect, + CfUiSelect, + UiUp, + CfUiUp, + UiDown, + CfUiDown, + UiLeft, + CfUiLeft, + UiRight, + CfUiRight, + UiReset, + CfUiReset, + UiSave, + CfUiSave, + UiPrevious, + CfUiPrevious, + UiPageUp, + CfUiPageUp, + UiPageDown, + CfUiPageDown +}; + + +/** + Set Buffer to Value for Size bytes. + + @param Buffer Memory to set. + @param Size Number of bytes to set + @param Value Value of the set operation. + + @return None + +**/ +VOID +SetUnicodeMem ( + IN VOID *Buffer, + IN UINTN Size, + IN CHAR16 Value + ) +{ + CHAR16 *Ptr; + + Ptr = Buffer; + while (Size--) { + *(Ptr++) = Value; + } +} + + +/** + Initialize Menu option list. + + None. + + @return None. + +**/ +VOID +UiInitMenu ( + VOID + ) +{ + InitializeListHead (&Menu); +} + + +/** + Initialize Menu option list. + + None. + + @return None. + +**/ +VOID +UiInitMenuList ( + VOID + ) +{ + InitializeListHead (&gMenuList); +} + + +/** + Remove a Menu in list, and return FormId/QuestionId for previous Menu. + + @param Selection Menu selection. + + @return None. + +**/ +VOID +UiRemoveMenuListEntry ( + IN OUT UI_MENU_SELECTION *Selection + ) +{ + UI_MENU_LIST *UiMenuList; + + if (!IsListEmpty (&gMenuList)) { + UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE); + + Selection->FormId = UiMenuList->FormId; + Selection->QuestionId = UiMenuList->QuestionId; + RemoveEntryList (&UiMenuList->MenuLink); + gBS->FreePool (UiMenuList); + } +} + + +/** + Free Menu option linked list. + + None. + + @return None. + +**/ +VOID +UiFreeMenuList ( + VOID + ) +{ + UI_MENU_LIST *UiMenuList; + + while (!IsListEmpty (&gMenuList)) { + UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE); + RemoveEntryList (&UiMenuList->MenuLink); + gBS->FreePool (UiMenuList); + } +} + + +/** + Add one menu entry to the linked lst + + @param Selection Menu selection. + + @return None. + +**/ +VOID +UiAddMenuListEntry ( + IN UI_MENU_SELECTION *Selection + ) +{ + UI_MENU_LIST *UiMenuList; + + UiMenuList = AllocateZeroPool (sizeof (UI_MENU_LIST)); + ASSERT (UiMenuList != NULL); + + UiMenuList->Signature = UI_MENU_LIST_SIGNATURE; + UiMenuList->FormId = Selection->FormId; + UiMenuList->QuestionId = Selection->QuestionId; + + InsertHeadList (&gMenuList, &UiMenuList->MenuLink); +} + + +/** + Free Menu option linked list. + + None. + + @return None. + +**/ +VOID +UiFreeMenu ( + VOID + ) +{ + UI_MENU_OPTION *MenuOption; + + while (!IsListEmpty (&Menu)) { + MenuOption = MENU_OPTION_FROM_LINK (Menu.ForwardLink); + RemoveEntryList (&MenuOption->Link); + + // + // We allocated space for this description when we did a GetToken, free it here + // + if (MenuOption->Skip != 0) { + // + // For date/time, MenuOption->Description is shared by three Menu Options + // Data format : [01/02/2004] [11:22:33] + // Line number : 0 0 1 0 0 1 + // + gBS->FreePool (MenuOption->Description); + } + gBS->FreePool (MenuOption); + } +} + + +/** + Free Menu option linked list. + + None. + + @return None. + +**/ +VOID +UiFreeRefreshList ( + VOID + ) +{ + MENU_REFRESH_ENTRY *OldMenuRefreshEntry; + + while (gMenuRefreshHead != NULL) { + OldMenuRefreshEntry = gMenuRefreshHead->Next; + gBS->FreePool (gMenuRefreshHead); + gMenuRefreshHead = OldMenuRefreshEntry; + } + + gMenuRefreshHead = NULL; +} + + + +/** + Refresh screen. + + None. + + @return None. + +**/ +VOID +RefreshForm ( + VOID + ) +{ + CHAR16 *OptionString; + MENU_REFRESH_ENTRY *MenuRefreshEntry; + UINTN Index; + UINTN Loop; + EFI_STATUS Status; + UI_MENU_SELECTION *Selection; + FORM_BROWSER_STATEMENT *Question; + + OptionString = NULL; + + if (gMenuRefreshHead != NULL) { + + MenuRefreshEntry = gMenuRefreshHead; + + do { + gST->ConOut->SetAttribute (gST->ConOut, MenuRefreshEntry->CurrentAttribute); + + Selection = MenuRefreshEntry->Selection; + Question = MenuRefreshEntry->MenuOption->ThisTag; + + // + // Don't update Question being edited + // + if (Question != MenuRefreshEntry->Selection->Statement) { + + Status = GetQuestionValue (Selection->FormSet, Selection->Form, Question, FALSE); + if (EFI_ERROR (Status)) { + return; + } + + ProcessOptions (Selection, MenuRefreshEntry->MenuOption, FALSE, &OptionString); + + if (OptionString != NULL) { + // + // If leading spaces on OptionString - remove the spaces + // + for (Index = 0; OptionString[Index] == L' '; Index++) + ; + + for (Loop = 0; OptionString[Index] != CHAR_NULL; Index++) { + OptionString[Loop] = OptionString[Index]; + Loop++; + } + + OptionString[Loop] = CHAR_NULL; + + PrintStringAt (MenuRefreshEntry->CurrentColumn, MenuRefreshEntry->CurrentRow, OptionString); + gBS->FreePool (OptionString); + } + } + + MenuRefreshEntry = MenuRefreshEntry->Next; + + } while (MenuRefreshEntry != NULL); + } +} + + +/** + Wait for a given event to fire, or for an optional timeout to expire. + + @param Event The event to wait for + @param Timeout An optional timeout value in 100 ns units. + @param RefreshInterval Menu refresh interval (in seconds). + + @retval EFI_SUCCESS Event fired before Timeout expired. + @retval EFI_TIME_OUT Timout expired before Event fired. + +**/ +EFI_STATUS +UiWaitForSingleEvent ( + IN EFI_EVENT Event, + IN UINT64 Timeout, OPTIONAL + IN UINT8 RefreshInterval OPTIONAL + ) +{ + EFI_STATUS Status; + UINTN Index; + EFI_EVENT TimerEvent; + EFI_EVENT WaitList[2]; + + if (Timeout) { + // + // Create a timer event + // + Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent); + if (!EFI_ERROR (Status)) { + // + // Set the timer event + // + gBS->SetTimer ( + TimerEvent, + TimerRelative, + Timeout + ); + + // + // Wait for the original event or the timer + // + WaitList[0] = Event; + WaitList[1] = TimerEvent; + Status = gBS->WaitForEvent (2, WaitList, &Index); + gBS->CloseEvent (TimerEvent); + + // + // If the timer expired, change the return to timed out + // + if (!EFI_ERROR (Status) && Index == 1) { + Status = EFI_TIMEOUT; + } + } + } else { + // + // Update screen every second + // + if (RefreshInterval == 0) { + Timeout = ONE_SECOND; + } else { + Timeout = RefreshInterval * ONE_SECOND; + } + + do { + Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent); + + // + // Set the timer event + // + gBS->SetTimer ( + TimerEvent, + TimerRelative, + Timeout + ); + + // + // Wait for the original event or the timer + // + WaitList[0] = Event; + WaitList[1] = TimerEvent; + Status = gBS->WaitForEvent (2, WaitList, &Index); + + // + // If the timer expired, update anything that needs a refresh and keep waiting + // + if (!EFI_ERROR (Status) && Index == 1) { + Status = EFI_TIMEOUT; + if (RefreshInterval != 0) { + RefreshForm (); + } + } + + gBS->CloseEvent (TimerEvent); + } while (Status == EFI_TIMEOUT); + } + + return Status; +} + + +/** + Add one menu option by specified description and context. + + @param String String description for this option. + @param Handle Hii handle for the package list. + @param Statement Statement of this Menu Option. + @param NumberOfLines Display lines for this Menu Option. + @param MenuItemCount The index for this Option in the Menu. + + @return None. + +**/ +VOID +UiAddMenuOption ( + IN CHAR16 *String, + IN EFI_HII_HANDLE Handle, + IN FORM_BROWSER_STATEMENT *Statement, + IN UINT16 NumberOfLines, + IN UINT16 MenuItemCount + ) +{ + UI_MENU_OPTION *MenuOption; + UINTN Index; + UINTN Count; + + Count = 1; + + if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) { + // + // Add three MenuOptions for Date/Time + // Data format : [01/02/2004] [11:22:33] + // Line number : 0 0 1 0 0 1 + // + NumberOfLines = 0; + Count = 3; + + if (Statement->Storage == NULL) { + // + // For RTC type of date/time, set default refresh interval to be 1 second + // + if (Statement->RefreshInterval == 0) { + Statement->RefreshInterval = 1; + } + } + } + + for (Index = 0; Index < Count; Index++) { + MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION)); + ASSERT (MenuOption); + + MenuOption->Signature = UI_MENU_OPTION_SIGNATURE; + MenuOption->Description = String; + MenuOption->Handle = Handle; + MenuOption->ThisTag = Statement; + MenuOption->EntryNumber = MenuItemCount; + + if (Index == 2) { + // + // Override LineNumber for the MenuOption in Date/Time sequence + // + MenuOption->Skip = 1; + } else { + MenuOption->Skip = NumberOfLines; + } + MenuOption->Sequence = Index; + + if (Statement->GrayOutExpression != NULL) { + MenuOption->GrayOut = Statement->GrayOutExpression->Result.Value.b; + } + + if ((Statement->ValueExpression != NULL) || + (Statement->QuestionFlags & EFI_IFR_FLAG_READ_ONLY)) { + MenuOption->ReadOnly = TRUE; + } + + InsertTailList (&Menu, &MenuOption->Link); + } +} + + +/** + Routine used to abstract a generic dialog interface and return the selected key or string + + @param NumberOfLines The number of lines for the dialog box + @param HotKey Defines whether a single character is parsed + (TRUE) and returned in KeyValue or a string is + returned in StringBuffer. Two special characters + are considered when entering a string, a SCAN_ESC + and an CHAR_CARRIAGE_RETURN. SCAN_ESC terminates + string input and returns + @param MaximumStringSize The maximum size in bytes of a typed in string + (each character is a CHAR16) and the minimum + string returned is two bytes + @param StringBuffer The passed in pointer to the buffer which will + hold the typed in string if HotKey is FALSE + @param KeyValue The EFI_KEY value returned if HotKey is TRUE.. + @param String Pointer to the first string in the list + @param ... A series of (quantity == NumberOfLines) text + strings which will be used to construct the dialog + box + + @retval EFI_SUCCESS Displayed dialog and received user interaction + @retval EFI_INVALID_PARAMETER One of the parameters was invalid (e.g. + (StringBuffer == NULL) && (HotKey == FALSE)) + @retval EFI_DEVICE_ERROR User typed in an ESC character to exit the routine + +**/ +EFI_STATUS +CreateDialog ( + IN UINTN NumberOfLines, + IN BOOLEAN HotKey, + IN UINTN MaximumStringSize, + OUT CHAR16 *StringBuffer, + OUT EFI_INPUT_KEY *KeyValue, + IN CHAR16 *String, + ... + ) +{ + VA_LIST Marker; + UINTN Count; + EFI_INPUT_KEY Key; + UINTN LargestString; + CHAR16 *TempString; + CHAR16 *BufferedString; + CHAR16 *StackString; + CHAR16 KeyPad[2]; + UINTN Start; + UINTN Top; + UINTN Index; + EFI_STATUS Status; + BOOLEAN SelectionComplete; + UINTN InputOffset; + UINTN CurrentAttribute; + UINTN DimensionsWidth; + UINTN DimensionsHeight; + + DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn; + DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow; + + SelectionComplete = FALSE; + InputOffset = 0; + TempString = AllocateZeroPool (MaximumStringSize * 2); + BufferedString = AllocateZeroPool (MaximumStringSize * 2); + CurrentAttribute = gST->ConOut->Mode->Attribute; + + ASSERT (TempString); + ASSERT (BufferedString); + + VA_START (Marker, String); + + // + // Zero the outgoing buffer + // + ZeroMem (StringBuffer, MaximumStringSize); + + if (HotKey) { + if (KeyValue == NULL) { + return EFI_INVALID_PARAMETER; + } + } else { + if (StringBuffer == NULL) { + return EFI_INVALID_PARAMETER; + } + } + // + // Disable cursor + // + gST->ConOut->EnableCursor (gST->ConOut, FALSE); + + LargestString = (GetStringWidth (String) / 2); + + if (*String == L' ') { + InputOffset = 1; + } + // + // Determine the largest string in the dialog box + // Notice we are starting with 1 since String is the first string + // + for (Count = 1; Count < NumberOfLines; Count++) { + StackString = VA_ARG (Marker, CHAR16 *); + + if (StackString[0] == L' ') { + InputOffset = Count + 1; + } + + if ((GetStringWidth (StackString) / 2) > LargestString) { + // + // Size of the string visually and subtract the width by one for the null-terminator + // + LargestString = (GetStringWidth (StackString) / 2); + } + } + + Start = (DimensionsWidth - LargestString - 2) / 2 + gScreenDimensions.LeftColumn + 1; + Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gScreenDimensions.TopRow - 1; + + Count = 0; + + // + // Display the Popup + // + CreateSharedPopUp (LargestString, NumberOfLines, &String); + + // + // Take the first key typed and report it back? + // + if (HotKey) { + Status = WaitForKeyStroke (&Key); + ASSERT_EFI_ERROR (Status); + CopyMem (KeyValue, &Key, sizeof (EFI_INPUT_KEY)); + + } else { + do { + Status = WaitForKeyStroke (&Key); + + switch (Key.UnicodeChar) { + case CHAR_NULL: + switch (Key.ScanCode) { + case SCAN_ESC: + gBS->FreePool (TempString); + gBS->FreePool (BufferedString); + gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + return EFI_DEVICE_ERROR; + + default: + break; + } + + break; + + case CHAR_CARRIAGE_RETURN: + SelectionComplete = TRUE; + gBS->FreePool (TempString); + gBS->FreePool (BufferedString); + gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + return EFI_SUCCESS; + break; + + case CHAR_BACKSPACE: + if (StringBuffer[0] != CHAR_NULL) { + for (Index = 0; StringBuffer[Index] != CHAR_NULL; Index++) { + TempString[Index] = StringBuffer[Index]; + } + // + // Effectively truncate string by 1 character + // + TempString[Index - 1] = CHAR_NULL; + StrCpy (StringBuffer, TempString); + } + + default: + // + // If it is the beginning of the string, don't worry about checking maximum limits + // + if ((StringBuffer[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) { + StrnCpy (StringBuffer, &Key.UnicodeChar, 1); + StrnCpy (TempString, &Key.UnicodeChar, 1); + } else if ((GetStringWidth (StringBuffer) < MaximumStringSize) && (Key.UnicodeChar != CHAR_BACKSPACE)) { + KeyPad[0] = Key.UnicodeChar; + KeyPad[1] = CHAR_NULL; + StrCat (StringBuffer, KeyPad); + StrCat (TempString, KeyPad); + } + // + // If the width of the input string is now larger than the screen, we nee to + // adjust the index to start printing portions of the string + // + SetUnicodeMem (BufferedString, LargestString, L' '); + + PrintStringAt (Start + 1, Top + InputOffset, BufferedString); + + if ((GetStringWidth (StringBuffer) / 2) > (DimensionsWidth - 2)) { + Index = (GetStringWidth (StringBuffer) / 2) - DimensionsWidth + 2; + } else { + Index = 0; + } + + for (Count = 0; Index + 1 < GetStringWidth (StringBuffer) / 2; Index++, Count++) { + BufferedString[Count] = StringBuffer[Index]; + } + + PrintStringAt (Start + 1, Top + InputOffset, BufferedString); + break; + } + } while (!SelectionComplete); + } + + gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + return EFI_SUCCESS; +} + +VOID +CreateSharedPopUp ( + IN UINTN RequestedWidth, + IN UINTN NumberOfLines, + IN CHAR16 **ArrayOfStrings + ) +{ + UINTN Index; + UINTN Count; + CHAR16 Character; + UINTN Start; + UINTN End; + UINTN Top; + UINTN Bottom; + CHAR16 *String; + UINTN DimensionsWidth; + UINTN DimensionsHeight; + + DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn; + DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow; + + Count = 0; + + gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND); + + if ((RequestedWidth + 2) > DimensionsWidth) { + RequestedWidth = DimensionsWidth - 2; + } + + // + // Subtract the PopUp width from total Columns, allow for one space extra on + // each end plus a border. + // + Start = (DimensionsWidth - RequestedWidth - 2) / 2 + gScreenDimensions.LeftColumn + 1; + End = Start + RequestedWidth + 1; + + Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gScreenDimensions.TopRow - 1; + Bottom = Top + NumberOfLines + 2; + + Character = BOXDRAW_DOWN_RIGHT; + PrintCharAt (Start, Top, Character); + Character = BOXDRAW_HORIZONTAL; + for (Index = Start; Index + 2 < End; Index++) { + PrintChar (Character); + } + + Character = BOXDRAW_DOWN_LEFT; + PrintChar (Character); + Character = BOXDRAW_VERTICAL; + for (Index = Top; Index + 2 < Bottom; Index++) { + String = ArrayOfStrings[Count]; + Count++; + + // + // This will clear the background of the line - we never know who might have been + // here before us. This differs from the next clear in that it used the non-reverse + // video for normal printing. + // + if (GetStringWidth (String) / 2 > 1) { + ClearLines (Start, End, Index + 1, Index + 1, POPUP_TEXT | POPUP_BACKGROUND); + } + + // + // Passing in a space results in the assumption that this is where typing will occur + // + if (String[0] == L' ') { + ClearLines (Start + 1, End - 1, Index + 1, Index + 1, POPUP_INVERSE_TEXT | POPUP_INVERSE_BACKGROUND); + } + + // + // Passing in a NULL results in a blank space + // + if (String[0] == CHAR_NULL) { + ClearLines (Start, End, Index + 1, Index + 1, POPUP_TEXT | POPUP_BACKGROUND); + } + + PrintStringAt ( + ((DimensionsWidth - GetStringWidth (String) / 2) / 2) + gScreenDimensions.LeftColumn + 1, + Index + 1, + String + ); + gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND); + PrintCharAt (Start, Index + 1, Character); + PrintCharAt (End - 1, Index + 1, Character); + } + + Character = BOXDRAW_UP_RIGHT; + PrintCharAt (Start, Bottom - 1, Character); + Character = BOXDRAW_HORIZONTAL; + for (Index = Start; Index + 2 < End; Index++) { + PrintChar (Character); + } + + Character = BOXDRAW_UP_LEFT; + PrintChar (Character); +} + +VOID +CreatePopUp ( + IN UINTN RequestedWidth, + IN UINTN NumberOfLines, + IN CHAR16 *ArrayOfStrings, + ... + ) +{ + CreateSharedPopUp (RequestedWidth, NumberOfLines, &ArrayOfStrings); +} + + +/** + Update status bar on the bottom of menu. + + @param MessageType The type of message to be shown. + @param Flags The flags in Question header. + @param State Set or clear. + + @return None. + +**/ +VOID +UpdateStatusBar ( + IN UINTN MessageType, + IN UINT8 Flags, + IN BOOLEAN State + ) +{ + UINTN Index; + STATIC BOOLEAN InputError; + CHAR16 *NvUpdateMessage; + CHAR16 *InputErrorMessage; + + NvUpdateMessage = GetToken (STRING_TOKEN (NV_UPDATE_MESSAGE), gHiiHandle); + InputErrorMessage = GetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE), gHiiHandle); + + switch (MessageType) { + case INPUT_ERROR: + if (State) { + gST->ConOut->SetAttribute (gST->ConOut, ERROR_TEXT); + PrintStringAt ( + gScreenDimensions.LeftColumn + gPromptBlockWidth, + gScreenDimensions.BottomRow - 1, + InputErrorMessage + ); + InputError = TRUE; + } else { + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT); + for (Index = 0; Index < (GetStringWidth (InputErrorMessage) - 2) / 2; Index++) { + PrintAt (gScreenDimensions.LeftColumn + gPromptBlockWidth + Index, gScreenDimensions.BottomRow - 1, L" "); + } + + InputError = FALSE; + } + break; + + case NV_UPDATE_REQUIRED: + if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) { + if (State) { + gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT); + PrintStringAt ( + gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth, + gScreenDimensions.BottomRow - 1, + NvUpdateMessage + ); + gResetRequired = (BOOLEAN) (gResetRequired | ((Flags & EFI_IFR_FLAG_RESET_REQUIRED) == EFI_IFR_FLAG_RESET_REQUIRED)); + + gNvUpdateRequired = TRUE; + } else { + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT); + for (Index = 0; Index < (GetStringWidth (NvUpdateMessage) - 2) / 2; Index++) { + PrintAt ( + (gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + Index), + gScreenDimensions.BottomRow - 1, + L" " + ); + } + + gNvUpdateRequired = FALSE; + } + } + break; + + case REFRESH_STATUS_BAR: + if (InputError) { + UpdateStatusBar (INPUT_ERROR, Flags, TRUE); + } + + if (gNvUpdateRequired) { + UpdateStatusBar (NV_UPDATE_REQUIRED, Flags, TRUE); + } + break; + + default: + break; + } + + gBS->FreePool (InputErrorMessage); + gBS->FreePool (NvUpdateMessage); + return ; +} + + +/** + Get the supported width for a particular op-code + + @param Statement The FORM_BROWSER_STATEMENT structure passed in. + @param Handle The handle in the HII database being used + + @return Returns the number of CHAR16 characters that is support. + +**/ +UINT16 +GetWidth ( + IN FORM_BROWSER_STATEMENT *Statement, + IN EFI_HII_HANDLE Handle + ) +{ + CHAR16 *String; + UINTN Size; + UINT16 Width; + + Size = 0; + + // + // See if the second text parameter is really NULL + // + if ((Statement->Operand == EFI_IFR_TEXT_OP) && (Statement->TextTwo != 0)) { + String = GetToken (Statement->TextTwo, Handle); + Size = StrLen (String); + gBS->FreePool (String); + } + + if ((Statement->Operand == EFI_IFR_SUBTITLE_OP) || + (Statement->Operand == EFI_IFR_REF_OP) || + (Statement->Operand == EFI_IFR_PASSWORD_OP) || + (Statement->Operand == EFI_IFR_ACTION_OP) || + (Statement->Operand == EFI_IFR_RESET_BUTTON_OP) || + // + // Allow a wide display if text op-code and no secondary text op-code + // + ((Statement->Operand == EFI_IFR_TEXT_OP) && (Size == 0)) + ) { + Width = (UINT16) (gPromptBlockWidth + gOptionBlockWidth); + } else { + Width = (UINT16) gPromptBlockWidth; + } + + if (Statement->InSubtitle) { + Width -= SUBTITLE_INDENT; + } + + return Width; +} + + +/** + Will copy LineWidth amount of a string in the OutputString buffer and return the + number of CHAR16 characters that were copied into the OutputString buffer. + + @param InputString String description for this option. + @param LineWidth Width of the desired string to extract in CHAR16 + characters + @param Index Where in InputString to start the copy process + @param OutputString Buffer to copy the string into + + @return Returns the number of CHAR16 characters that were copied into the OutputString buffer. + +**/ +UINT16 +GetLineByWidth ( + IN CHAR16 *InputString, + IN UINT16 LineWidth, + IN OUT UINTN *Index, + OUT CHAR16 **OutputString + ) +{ + static BOOLEAN Finished; + UINT16 Count; + UINT16 Count2; + + if (Finished) { + Finished = FALSE; + return (UINT16) 0; + } + + Count = LineWidth; + Count2 = 0; + + *OutputString = AllocateZeroPool (((UINTN) (LineWidth + 1) * 2)); + + // + // Ensure we have got a valid buffer + // + if (*OutputString != NULL) { + + // + //NARROW_CHAR can not be printed in screen, so if a line only contain the two CHARs: 'NARROW_CHAR + CHAR_CARRIAGE_RETURN' , it is a empty line in Screen. + //To avoid displaying this empty line in screen, just skip the two CHARs here. + // + if ((InputString[*Index] == NARROW_CHAR) && (InputString[*Index + 1] == CHAR_CARRIAGE_RETURN)) { + *Index = *Index + 2; + } + + // + // Fast-forward the string and see if there is a carriage-return in the string + // + for (; (InputString[*Index + Count2] != CHAR_CARRIAGE_RETURN) && (Count2 != LineWidth); Count2++) + ; + + // + // Copy the desired LineWidth of data to the output buffer. + // Also make sure that we don't copy more than the string. + // Also make sure that if there are linefeeds, we account for them. + // + if ((StrSize (&InputString[*Index]) <= ((UINTN) (LineWidth + 1) * 2)) && + (StrSize (&InputString[*Index]) <= ((UINTN) (Count2 + 1) * 2)) + ) { + // + // Convert to CHAR16 value and show that we are done with this operation + // + LineWidth = (UINT16) ((StrSize (&InputString[*Index]) - 2) / 2); + if (LineWidth != 0) { + Finished = TRUE; + } + } else { + if (Count2 == LineWidth) { + // + // Rewind the string from the maximum size until we see a space to break the line + // + for (; (InputString[*Index + LineWidth] != CHAR_SPACE) && (LineWidth != 0); LineWidth--) + ; + if (LineWidth == 0) { + LineWidth = Count; + } + } else { + LineWidth = Count2; + } + } + + CopyMem (*OutputString, &InputString[*Index], LineWidth * 2); + + // + // If currently pointing to a space, increment the index to the first non-space character + // + for (; + (InputString[*Index + LineWidth] == CHAR_SPACE) || (InputString[*Index + LineWidth] == CHAR_CARRIAGE_RETURN); + (*Index)++ + ) + ; + *Index = (UINT16) (*Index + LineWidth); + return LineWidth; + } else { + return (UINT16) 0; + } +} + + +/** + Update display lines for a Menu Option. + + @param MenuOption The MenuOption to be checked. + + @retval TRUE This Menu Option is selectable. + @retval FALSE This Menu Option could not be selected. + +**/ +VOID +UpdateOptionSkipLines ( + IN UI_MENU_SELECTION *Selection, + IN UI_MENU_OPTION *MenuOption, + IN CHAR16 **OptionalString, + IN UINTN SkipValue + ) +{ + UINTN Index; + UINT16 Width; + UINTN Row; + UINTN OriginalRow; + CHAR16 *OutputString; + CHAR16 *OptionString; + + Row = 0; + OptionString = *OptionalString; + OutputString = NULL; + + ProcessOptions (Selection, MenuOption, FALSE, &OptionString); + + if (OptionString != NULL) { + Width = (UINT16) gOptionBlockWidth; + + OriginalRow = Row; + + for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) { + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&OptionString[Index])) { + if (SkipValue == 0) { + Row++; + // + // Since the Number of lines for this menu entry may or may not be reflected accurately + // since the prompt might be 1 lines and option might be many, and vice versa, we need to do + // some testing to ensure we are keeping this in-sync. + // + // If the difference in rows is greater than or equal to the skip value, increase the skip value + // + if ((Row - OriginalRow) >= MenuOption->Skip) { + MenuOption->Skip++; + } + } + } + + gBS->FreePool (OutputString); + if (SkipValue != 0) { + SkipValue--; + } + } + + Row = OriginalRow; + } + + *OptionalString = OptionString; +} + + +/** + Check whether this Menu Option could be highlighted. + + @param MenuOption The MenuOption to be checked. + + @retval TRUE This Menu Option is selectable. + @retval FALSE This Menu Option could not be selected. + +**/ +STATIC +BOOLEAN +IsSelectable ( + UI_MENU_OPTION *MenuOption + ) +{ + if ((MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) || + MenuOption->GrayOut || MenuOption->ReadOnly) { + return FALSE; + } else { + return TRUE; + } +} + + +/** + Determine if the menu is the last menu that can be selected. + + @param Direction the scroll direction. False is down. True is up. + + @return FALSE -- the menu isn't the last menu that can be selected. + @return TRUE -- the menu is the last menu that can be selected. + +**/ +STATIC +BOOLEAN +ValueIsScroll ( + IN BOOLEAN Direction, + IN LIST_ENTRY *CurrentPos + ) +{ + LIST_ENTRY *Temp; + UI_MENU_OPTION *MenuOption; + + Temp = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink; + + if (Temp == &Menu) { + return TRUE; + } + + for (; Temp != &Menu; Temp = Direction ? Temp->BackLink : Temp->ForwardLink) { + MenuOption = MENU_OPTION_FROM_LINK (Temp); + if (IsSelectable (MenuOption)) { + return FALSE; + } + } + + return TRUE; +} + + +/** + Move to next selectable statement. + + @param GoUp The navigation direction. TRUE: up, FALSE: down. + @param CurrentPosition Current position. + + @return The row distance from current MenuOption to next selectable MenuOption. + +**/ +STATIC +INTN +MoveToNextStatement ( + IN BOOLEAN GoUp, + IN OUT LIST_ENTRY **CurrentPosition + ) +{ + INTN Distance; + LIST_ENTRY *Pos; + BOOLEAN HitEnd; + UI_MENU_OPTION *NextMenuOption; + + Distance = 0; + Pos = *CurrentPosition; + HitEnd = FALSE; + + while (TRUE) { + NextMenuOption = MENU_OPTION_FROM_LINK (Pos); + if (IsSelectable (NextMenuOption)) { + break; + } + if ((GoUp ? Pos->BackLink : Pos->ForwardLink) == &Menu) { + HitEnd = TRUE; + break; + } + Distance += NextMenuOption->Skip; + Pos = (GoUp ? Pos->BackLink : Pos->ForwardLink); + } + + if (HitEnd) { + // + // If we hit end there is still no statement can be focused, + // we go backwards to find the statement can be focused. + // + Distance = 0; + Pos = *CurrentPosition; + + while (TRUE) { + NextMenuOption = MENU_OPTION_FROM_LINK (Pos); + if (IsSelectable (NextMenuOption)) { + break; + } + if ((!GoUp ? Pos->BackLink : Pos->ForwardLink) == &Menu) { + ASSERT (FALSE); + break; + } + Distance -= NextMenuOption->Skip; + Pos = (!GoUp ? Pos->BackLink : Pos->ForwardLink); + } + } + + *CurrentPosition = &NextMenuOption->Link; + return Distance; +} + + +/** + Adjust Data and Time position accordingly. + Data format : [01/02/2004] [11:22:33] + Line number : 0 0 1 0 0 1 + + @param DirectionUp the up or down direction. False is down. True is + up. + @param CurrentPosition Current position. On return: Point to the last + Option (Year or Second) if up; Point to the first + Option (Month or Hour) if down. + + @return Return line number to pad. It is possible that we stand on a zero-advance + @return data or time opcode, so pad one line when we judge if we are going to scroll outside. + +**/ +STATIC +UINTN +AdjustDateAndTimePosition ( + IN BOOLEAN DirectionUp, + IN OUT LIST_ENTRY **CurrentPosition + ) +{ + UINTN Count; + LIST_ENTRY *NewPosition; + UI_MENU_OPTION *MenuOption; + UINTN PadLineNumber; + + PadLineNumber = 0; + NewPosition = *CurrentPosition; + MenuOption = MENU_OPTION_FROM_LINK (NewPosition); + + if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || + (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) { + // + // Calculate the distance from current position to the last Date/Time MenuOption + // + Count = 0; + while (MenuOption->Skip == 0) { + Count++; + NewPosition = NewPosition->ForwardLink; + MenuOption = MENU_OPTION_FROM_LINK (NewPosition); + PadLineNumber = 1; + } + + NewPosition = *CurrentPosition; + if (DirectionUp) { + // + // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended + // to be one that back to the previous set of MenuOptions, we need to advance to the first + // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate + // checking can be done. + // + while (Count++ < 2) { + NewPosition = NewPosition->BackLink; + } + } else { + // + // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended + // to be one that progresses to the next set of MenuOptions, we need to advance to the last + // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate + // checking can be done. + // + while (Count-- > 0) { + NewPosition = NewPosition->ForwardLink; + } + } + + *CurrentPosition = NewPosition; + } + + return PadLineNumber; +} + + +/** + Display menu and wait for user to select one menu option, then return it. + If AutoBoot is enabled, then if user doesn't select any option, + after period of time, it will automatically return the first menu option. + + + @return Return the pointer of the menu which selected, + @return otherwise return NULL. + +**/ +EFI_STATUS +UiDisplayMenu ( + IN OUT UI_MENU_SELECTION *Selection + ) +{ + INTN SkipValue; + INTN Difference; + INTN OldSkipValue; + UINTN DistanceValue; + UINTN Row; + UINTN Col; + UINTN Temp; + UINTN Temp2; + UINTN TopRow; + UINTN BottomRow; + UINTN OriginalRow; + UINTN Index; + UINT32 Count; + UINT16 Width; + CHAR16 *StringPtr; + CHAR16 *OptionString; + CHAR16 *OutputString; + CHAR16 *FormattedString; + CHAR16 YesResponse; + CHAR16 NoResponse; + BOOLEAN NewLine; + BOOLEAN Repaint; + BOOLEAN SavedValue; + EFI_STATUS Status; + EFI_INPUT_KEY Key; + LIST_ENTRY *Link; + LIST_ENTRY *NewPos; + LIST_ENTRY *TopOfScreen; + LIST_ENTRY *SavedListEntry; + UI_MENU_OPTION *MenuOption; + UI_MENU_OPTION *NextMenuOption; + UI_MENU_OPTION *SavedMenuOption; + UI_MENU_OPTION *PreviousMenuOption; + UI_CONTROL_FLAG ControlFlag; + EFI_SCREEN_DESCRIPTOR LocalScreen; + MENU_REFRESH_ENTRY *MenuRefreshEntry; + UI_SCREEN_OPERATION ScreenOperation; + UINT8 MinRefreshInterval; + UINTN BufferSize; + UINT16 DefaultId; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + FORM_BROWSER_STATEMENT *Statement; + + CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + + Status = EFI_SUCCESS; + FormattedString = NULL; + OptionString = NULL; + ScreenOperation = UiNoOperation; + NewLine = TRUE; + MinRefreshInterval = 0; + DefaultId = 0; + + OutputString = NULL; + gUpArrow = FALSE; + gDownArrow = FALSE; + SkipValue = 0; + OldSkipValue = 0; + MenuRefreshEntry = gMenuRefreshHead; + + NextMenuOption = NULL; + PreviousMenuOption = NULL; + SavedMenuOption = NULL; + + ZeroMem (&Key, sizeof (EFI_INPUT_KEY)); + + if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) { + TopRow = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT; + Row = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT; + } else { + TopRow = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT; + Row = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT; + } + + Col = LocalScreen.LeftColumn; + BottomRow = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT - SCROLL_ARROW_HEIGHT - 1; + + Selection->TopRow = TopRow; + Selection->BottomRow = BottomRow; + Selection->PromptCol = Col; + Selection->OptionCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn; + Selection->Statement = NULL; + + TopOfScreen = Menu.ForwardLink; + Repaint = TRUE; + MenuOption = NULL; + + // + // Get user's selection + // + NewPos = Menu.ForwardLink; + + gST->ConOut->EnableCursor (gST->ConOut, FALSE); + UpdateStatusBar (REFRESH_STATUS_BAR, (UINT8) 0, TRUE); + + ControlFlag = CfInitialization; + Selection->Action = UI_ACTION_NONE; + while (TRUE) { + switch (ControlFlag) { + case CfInitialization: + if (IsListEmpty (&Menu)) { + ControlFlag = CfReadKey; + } else { + ControlFlag = CfCheckSelection; + } + break; + + case CfCheckSelection: + if (Selection->Action != UI_ACTION_NONE) { + ControlFlag = CfExit; + } else { + ControlFlag = CfRepaint; + } + break; + + case CfRepaint: + ControlFlag = CfRefreshHighLight; + + if (Repaint) { + // + // Display menu + // + gDownArrow = FALSE; + gUpArrow = FALSE; + Row = TopRow; + + Temp = SkipValue; + Temp2 = SkipValue; + + ClearLines ( + LocalScreen.LeftColumn, + LocalScreen.RightColumn, + TopRow - SCROLL_ARROW_HEIGHT, + BottomRow + SCROLL_ARROW_HEIGHT, + FIELD_TEXT | FIELD_BACKGROUND + ); + + UiFreeRefreshList (); + MinRefreshInterval = 0; + + for (Link = TopOfScreen; Link != &Menu; Link = Link->ForwardLink) { + MenuOption = MENU_OPTION_FROM_LINK (Link); + MenuOption->Row = Row; + MenuOption->Col = Col; + MenuOption->OptCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn; + + Statement = MenuOption->ThisTag; + if (Statement->InSubtitle) { + MenuOption->Col += SUBTITLE_INDENT; + } + + if (MenuOption->GrayOut) { + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND); + } else { + if (Statement->Operand == EFI_IFR_SUBTITLE_OP) { + gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND); + } + } + + Width = GetWidth (Statement, MenuOption->Handle); + OriginalRow = Row; + + for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) { + if ((Temp == 0) && (Row <= BottomRow)) { + PrintStringAt (MenuOption->Col, Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&MenuOption->Description[Index])) { + if (Temp == 0) { + Row++; + } + } + + gBS->FreePool (OutputString); + if (Temp != 0) { + Temp--; + } + } + + Temp = 0; + Row = OriginalRow; + + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); + ProcessOptions (Selection, MenuOption, FALSE, &OptionString); + + if (OptionString != NULL) { + if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) { + // + // If leading spaces on OptionString - remove the spaces + // + for (Index = 0; OptionString[Index] == L' '; Index++) { + MenuOption->OptCol++; + } + + for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) { + OptionString[Count] = OptionString[Index]; + Count++; + } + + OptionString[Count] = CHAR_NULL; + } + + // + // If Question request refresh, register the op-code + // + if (Statement->RefreshInterval != 0) { + // + // Menu will be refreshed at minimal interval of all Questions + // which have refresh request + // + if (MinRefreshInterval == 0 || Statement->RefreshInterval < MinRefreshInterval) { + MinRefreshInterval = Statement->RefreshInterval; + } + + if (gMenuRefreshHead == NULL) { + MenuRefreshEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY)); + ASSERT (MenuRefreshEntry != NULL); + MenuRefreshEntry->MenuOption = MenuOption; + MenuRefreshEntry->Selection = Selection; + MenuRefreshEntry->CurrentColumn = MenuOption->OptCol; + MenuRefreshEntry->CurrentRow = MenuOption->Row; + MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND; + gMenuRefreshHead = MenuRefreshEntry; + } else { + // + // Advance to the last entry + // + for (MenuRefreshEntry = gMenuRefreshHead; + MenuRefreshEntry->Next != NULL; + MenuRefreshEntry = MenuRefreshEntry->Next + ) + ; + MenuRefreshEntry->Next = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY)); + ASSERT (MenuRefreshEntry->Next != NULL); + MenuRefreshEntry = MenuRefreshEntry->Next; + MenuRefreshEntry->MenuOption = MenuOption; + MenuRefreshEntry->Selection = Selection; + MenuRefreshEntry->CurrentColumn = MenuOption->OptCol; + MenuRefreshEntry->CurrentRow = MenuOption->Row; + MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND; + } + } + + Width = (UINT16) gOptionBlockWidth; + OriginalRow = Row; + + for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) { + if ((Temp2 == 0) && (Row <= BottomRow)) { + PrintStringAt (MenuOption->OptCol, Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&OptionString[Index])) { + if (Temp2 == 0) { + Row++; + // + // Since the Number of lines for this menu entry may or may not be reflected accurately + // since the prompt might be 1 lines and option might be many, and vice versa, we need to do + // some testing to ensure we are keeping this in-sync. + // + // If the difference in rows is greater than or equal to the skip value, increase the skip value + // + if ((Row - OriginalRow) >= MenuOption->Skip) { + MenuOption->Skip++; + } + } + } + + gBS->FreePool (OutputString); + if (Temp2 != 0) { + Temp2--; + } + } + + Temp2 = 0; + Row = OriginalRow; + + gBS->FreePool (OptionString); + } + // + // If this is a text op with secondary text information + // + if ((Statement->Operand == EFI_IFR_TEXT_OP) && (Statement->TextTwo != 0)) { + StringPtr = GetToken (Statement->TextTwo, MenuOption->Handle); + + Width = (UINT16) gOptionBlockWidth; + OriginalRow = Row; + + for (Index = 0; GetLineByWidth (StringPtr, Width, &Index, &OutputString) != 0x0000;) { + if ((Temp == 0) && (Row <= BottomRow)) { + PrintStringAt (MenuOption->OptCol, Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&StringPtr[Index])) { + if (Temp2 == 0) { + Row++; + // + // Since the Number of lines for this menu entry may or may not be reflected accurately + // since the prompt might be 1 lines and option might be many, and vice versa, we need to do + // some testing to ensure we are keeping this in-sync. + // + // If the difference in rows is greater than or equal to the skip value, increase the skip value + // + if ((Row - OriginalRow) >= MenuOption->Skip) { + MenuOption->Skip++; + } + } + } + + gBS->FreePool (OutputString); + if (Temp2 != 0) { + Temp2--; + } + } + + Row = OriginalRow; + gBS->FreePool (StringPtr); + } + + // + // Need to handle the bottom of the display + // + if (MenuOption->Skip > 1) { + Row += MenuOption->Skip - SkipValue; + SkipValue = 0; + } else { + Row += MenuOption->Skip; + } + + if (Row > BottomRow) { + if (!ValueIsScroll (FALSE, Link)) { + gDownArrow = TRUE; + } + + Row = BottomRow + 1; + break; + } + } + + if (!ValueIsScroll (TRUE, TopOfScreen)) { + gUpArrow = TRUE; + } + + if (gUpArrow) { + gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND); + PrintAt ( + LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1, + TopRow - SCROLL_ARROW_HEIGHT, + L"%c", + ARROW_UP + ); + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); + } + + if (gDownArrow) { + gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND); + PrintAt ( + LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1, + BottomRow + SCROLL_ARROW_HEIGHT, + L"%c", + ARROW_DOWN + ); + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); + } + + MenuOption = NULL; + } + break; + + case CfRefreshHighLight: + // + // MenuOption: Last menu option that need to remove hilight + // MenuOption is set to NULL in Repaint + // NewPos: Current menu option that need to hilight + // + ControlFlag = CfUpdateHelpString; + + // + // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily + // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing. + // + SavedValue = Repaint; + Repaint = FALSE; + + if (Selection->QuestionId != 0) { + NewPos = Menu.ForwardLink; + SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos); + + while (SavedMenuOption->ThisTag->QuestionId != Selection->QuestionId && NewPos->ForwardLink != &Menu) { + NewPos = NewPos->ForwardLink; + SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos); + } + if (SavedMenuOption->ThisTag->QuestionId == Selection->QuestionId) { + // + // Target Question found, find its MenuOption + // + Link = TopOfScreen; + + for (Index = TopRow; Index <= BottomRow && Link != NewPos;) { + SavedMenuOption = MENU_OPTION_FROM_LINK (Link); + Index += SavedMenuOption->Skip; + Link = Link->ForwardLink; + } + + if (Link != NewPos || Index > BottomRow) { + // + // NewPos is not in the current page, simply scroll page so that NewPos is in the end of the page + // + Link = NewPos; + for (Index = TopRow; Index <= BottomRow; ) { + Link = Link->BackLink; + SavedMenuOption = MENU_OPTION_FROM_LINK (Link); + Index += SavedMenuOption->Skip; + } + TopOfScreen = Link->ForwardLink; + + Repaint = TRUE; + NewLine = TRUE; + ControlFlag = CfRepaint; + break; + } + } else { + // + // Target Question not found, highlight the default menu option + // + NewPos = TopOfScreen; + } + + Selection->QuestionId = 0; + } + + if (NewPos != NULL && (MenuOption == NULL || NewPos != &MenuOption->Link)) { + if (MenuOption != NULL) { + // + // Remove highlight on last Menu Option + // + gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row); + ProcessOptions (Selection, MenuOption, FALSE, &OptionString); + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); + if (OptionString != NULL) { + if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || + (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP) + ) { + // + // If leading spaces on OptionString - remove the spaces + // + for (Index = 0; OptionString[Index] == L' '; Index++) + ; + + for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) { + OptionString[Count] = OptionString[Index]; + Count++; + } + + OptionString[Count] = CHAR_NULL; + } + + Width = (UINT16) gOptionBlockWidth; + OriginalRow = MenuOption->Row; + + for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) { + if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) { + PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&OptionString[Index])) { + MenuOption->Row++; + } + + gBS->FreePool (OutputString); + } + + MenuOption->Row = OriginalRow; + + gBS->FreePool (OptionString); + } else { + if (NewLine) { + if (MenuOption->GrayOut) { + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND); + } else if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) { + gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND); + } + + OriginalRow = MenuOption->Row; + Width = GetWidth (MenuOption->ThisTag, MenuOption->Handle); + + for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) { + if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) { + PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&MenuOption->Description[Index])) { + MenuOption->Row++; + } + + gBS->FreePool (OutputString); + } + + MenuOption->Row = OriginalRow; + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); + } + } + } + + // + // This is only possible if we entered this page and the first menu option is + // a "non-menu" item. In that case, force it UiDown + // + MenuOption = MENU_OPTION_FROM_LINK (NewPos); + if (!IsSelectable (MenuOption)) { + ASSERT (ScreenOperation == UiNoOperation); + ScreenOperation = UiDown; + ControlFlag = CfScreenOperation; + break; + } + + // + // This is the current selected statement + // + Statement = MenuOption->ThisTag; + Selection->Statement = Statement; + + // + // Set reverse attribute + // + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT); + gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row); + + // + // Assuming that we have a refresh linked-list created, lets annotate the + // appropriate entry that we are highlighting with its new attribute. Just prior to this + // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh + // + if (gMenuRefreshHead != NULL) { + for (MenuRefreshEntry = gMenuRefreshHead; MenuRefreshEntry != NULL; MenuRefreshEntry = MenuRefreshEntry->Next) { + MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND; + if (MenuRefreshEntry->MenuOption == MenuOption) { + MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT; + } + } + } + + ProcessOptions (Selection, MenuOption, FALSE, &OptionString); + if (OptionString != NULL) { + if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) { + // + // If leading spaces on OptionString - remove the spaces + // + for (Index = 0; OptionString[Index] == L' '; Index++) + ; + + for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) { + OptionString[Count] = OptionString[Index]; + Count++; + } + + OptionString[Count] = CHAR_NULL; + } + Width = (UINT16) gOptionBlockWidth; + + OriginalRow = MenuOption->Row; + + for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) { + if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) { + PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&OptionString[Index])) { + MenuOption->Row++; + } + + gBS->FreePool (OutputString); + } + + MenuOption->Row = OriginalRow; + + gBS->FreePool (OptionString); + } else { + if (NewLine) { + OriginalRow = MenuOption->Row; + + Width = GetWidth (Statement, MenuOption->Handle); + + for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) { + if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) { + PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&MenuOption->Description[Index])) { + MenuOption->Row++; + } + + gBS->FreePool (OutputString); + } + + MenuOption->Row = OriginalRow; + + } + } + + if (((NewPos->ForwardLink != &Menu) && (ScreenOperation == UiDown)) || + ((NewPos->BackLink != &Menu) && (ScreenOperation == UiUp)) || + (ScreenOperation == UiNoOperation) + ) { + UpdateKeyHelp (MenuOption, FALSE); + } + // + // Clear reverse attribute + // + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); + } + // + // Repaint flag will be used when process CfUpdateHelpString, so restore its value + // if we didn't break halfway when process CfRefreshHighLight. + // + Repaint = SavedValue; + break; + + case CfUpdateHelpString: + ControlFlag = CfPrepareToReadKey; + + if ((Repaint || NewLine) && (gClassOfVfr != EFI_GENERAL_APPLICATION_SUBCLASS)) { + // + // Don't print anything if it is a NULL help token + // + if (MenuOption->ThisTag->Help == 0) { + StringPtr = L"\0"; + } else { + StringPtr = GetToken (MenuOption->ThisTag->Help, MenuOption->Handle); + } + + ProcessHelpString (StringPtr, &FormattedString, BottomRow - TopRow); + + gST->ConOut->SetAttribute (gST->ConOut, HELP_TEXT | FIELD_BACKGROUND); + + for (Index = 0; Index < BottomRow - TopRow; Index++) { + // + // Pad String with spaces to simulate a clearing of the previous line + // + for (; GetStringWidth (&FormattedString[Index * gHelpBlockWidth * 2]) / 2 < gHelpBlockWidth;) { + StrCat (&FormattedString[Index * gHelpBlockWidth * 2], L" "); + } + + PrintStringAt ( + LocalScreen.RightColumn - gHelpBlockWidth, + Index + TopRow, + &FormattedString[Index * gHelpBlockWidth * 2] + ); + } + } + // + // Reset this flag every time we finish using it. + // + Repaint = FALSE; + NewLine = FALSE; + break; + + case CfPrepareToReadKey: + ControlFlag = CfReadKey; + ScreenOperation = UiNoOperation; + break; + + case CfReadKey: + ControlFlag = CfScreenOperation; + + // + // Wait for user's selection + // + do { + Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0, MinRefreshInterval); + } while (Status == EFI_TIMEOUT); + + if (Status == EFI_TIMEOUT) { + Key.UnicodeChar = CHAR_CARRIAGE_RETURN; + } else { + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + // + // if we encounter error, continue to read another key in. + // + if (EFI_ERROR (Status)) { + ControlFlag = CfReadKey; + continue; + } + } + + if (IsListEmpty (&Menu) && Key.UnicodeChar != CHAR_NULL) { + // + // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset + // + break; + } + + switch (Key.UnicodeChar) { + case CHAR_CARRIAGE_RETURN: + ScreenOperation = UiSelect; + gDirection = 0; + break; + + // + // We will push the adjustment of these numeric values directly to the input handler + // NOTE: we won't handle manual input numeric + // + case '+': + case '-': + Statement = MenuOption->ThisTag; + if ((Statement->Operand == EFI_IFR_DATE_OP) + || (Statement->Operand == EFI_IFR_TIME_OP) + || ((Statement->Operand == EFI_IFR_NUMERIC_OP) && (Statement->Step != 0)) + ){ + if (Key.UnicodeChar == '+') { + gDirection = SCAN_RIGHT; + } else { + gDirection = SCAN_LEFT; + } + Status = ProcessOptions (Selection, MenuOption, TRUE, &OptionString); + SafeFreePool (OptionString); + } + break; + + case '^': + ScreenOperation = UiUp; + break; + + case 'V': + case 'v': + ScreenOperation = UiDown; + break; + + case ' ': + if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) { + if (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !MenuOption->GrayOut) { + ScreenOperation = UiSelect; + } + } + break; + + case CHAR_NULL: + if (((Key.ScanCode == SCAN_F1) && ((gFunctionKeySetting & FUNCTION_ONE) != FUNCTION_ONE)) || + ((Key.ScanCode == SCAN_F2) && ((gFunctionKeySetting & FUNCTION_TWO) != FUNCTION_TWO)) || + ((Key.ScanCode == SCAN_F9) && ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE)) || + ((Key.ScanCode == SCAN_F10) && ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN)) + ) { + // + // If the function key has been disabled, just ignore the key. + // + } else { + for (Index = 0; Index < sizeof (gScanCodeToOperation) / sizeof (gScanCodeToOperation[0]); Index++) { + if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) { + if (Key.ScanCode == SCAN_F9) { + // + // Reset to standard default + // + DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD; + } + ScreenOperation = gScanCodeToOperation[Index].ScreenOperation; + break; + } + } + } + break; + } + break; + + case CfScreenOperation: + if (ScreenOperation != UiPrevious && ScreenOperation != UiReset) { + // + // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset + // ignore the selection and go back to reading keys. + // + if (IsListEmpty (&Menu)) { + ControlFlag = CfReadKey; + break; + } + // + // if there is nothing logical to place a cursor on, just move on to wait for a key. + // + for (Link = Menu.ForwardLink; Link != &Menu; Link = Link->ForwardLink) { + NextMenuOption = MENU_OPTION_FROM_LINK (Link); + if (IsSelectable (NextMenuOption)) { + break; + } + } + + if (Link == &Menu) { + ControlFlag = CfPrepareToReadKey; + break; + } + } else if (ScreenOperation == UiReset) { + // + // Press ESC to exit FormSet + // + Selection->Action = UI_ACTION_EXIT; + Selection->Statement = NULL; + } + + for (Index = 0; + Index < sizeof (gScreenOperationToControlFlag) / sizeof (gScreenOperationToControlFlag[0]); + Index++ + ) { + if (ScreenOperation == gScreenOperationToControlFlag[Index].ScreenOperation) { + ControlFlag = gScreenOperationToControlFlag[Index].ControlFlag; + break; + } + } + break; + + case CfUiPrevious: + ControlFlag = CfCheckSelection; + + if (IsListEmpty (&gMenuList)) { + Selection->Action = UI_ACTION_NONE; + if (IsListEmpty (&Menu)) { + ControlFlag = CfReadKey; + } + break; + } + + // + // Remove the Cached page entry + // + UiRemoveMenuListEntry (Selection); + + Selection->Action = UI_ACTION_REFRESH_FORM; + Selection->Statement = NULL; + break; + + case CfUiSelect: + ControlFlag = CfCheckSelection; + + Statement = MenuOption->ThisTag; + if ((Statement->Operand == EFI_IFR_TEXT_OP) || + (Statement->Operand == EFI_IFR_DATE_OP) || + (Statement->Operand == EFI_IFR_TIME_OP) || + (Statement->Operand == EFI_IFR_NUMERIC_OP && Statement->Step != 0)) { + break; + } + + // + // Keep highlight on current MenuOption + // + Selection->QuestionId = Statement->QuestionId; + + switch (Statement->Operand) { + case EFI_IFR_REF_OP: + if (Statement->RefDevicePath != 0) { + // + // Goto another Hii Package list + // + ControlFlag = CfUiReset; + Selection->Action = UI_ACTION_REFRESH_FORMSET; + + StringPtr = GetToken (Statement->RefDevicePath, Selection->FormSet->HiiHandle); + if (StringPtr == NULL) { + // + // No device path string not found, exit + // + Selection->Action = UI_ACTION_EXIT; + Selection->Statement = NULL; + break; + } + BufferSize = StrLen (StringPtr) / 4; + DevicePath = AllocatePool (BufferSize); + + HexStringToBuffer ((UINT8 *) DevicePath, &BufferSize, StringPtr); + Selection->Handle = DevicePathToHiiHandle (mHiiDatabase, DevicePath); + if (Selection->Handle == NULL) { + // + // If target Hii Handle not found, exit + // + Selection->Action = UI_ACTION_EXIT; + Selection->Statement = NULL; + break; + } + + gBS->FreePool (StringPtr); + gBS->FreePool (DevicePath); + + CopyMem (&Selection->FormSetGuid, &Statement->RefFormSetId, sizeof (EFI_GUID)); + Selection->FormId = Statement->RefFormId; + Selection->QuestionId = Statement->RefQuestionId; + } else if (!CompareGuid (&Statement->RefFormSetId, &gZeroGuid)) { + // + // Goto another Formset, check for uncommitted data + // + ControlFlag = CfUiReset; + Selection->Action = UI_ACTION_REFRESH_FORMSET; + + CopyMem (&Selection->FormSetGuid, &Statement->RefFormSetId, sizeof (EFI_GUID)); + Selection->FormId = Statement->RefFormId; + Selection->QuestionId = Statement->RefQuestionId; + } else if (Statement->RefFormId != 0) { + // + // Goto another form inside this formset, + // + Selection->Action = UI_ACTION_REFRESH_FORM; + + // + // Link current form so that we can always go back when someone hits the UiPrevious + // + UiAddMenuListEntry (Selection); + + Selection->FormId = Statement->RefFormId; + Selection->QuestionId = Statement->RefQuestionId; + } else if (Statement->RefQuestionId != 0) { + // + // Goto another Question + // + Selection->QuestionId = Statement->RefQuestionId; + + if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK)) { + Selection->Action = UI_ACTION_REFRESH_FORM; + } else { + Repaint = TRUE; + NewLine = TRUE; + break; + } + } + break; + + case EFI_IFR_ACTION_OP: + // + // Process the Config string <ConfigResp> + // + Status = ProcessQuestionConfig (Selection, Statement); + + if (EFI_ERROR (Status)) { + break; + } + + // + // The action button may change some Question value, so refresh the form + // + Selection->Action = UI_ACTION_REFRESH_FORM; + break; + + case EFI_IFR_RESET_BUTTON_OP: + // + // Reset Question to default value specified by DefaultId + // + ControlFlag = CfUiDefault; + DefaultId = Statement->DefaultId; + break; + + default: + // + // Editable Questions: oneof, ordered list, checkbox, numeric, string, password + // + UpdateKeyHelp (MenuOption, TRUE); + Status = ProcessOptions (Selection, MenuOption, TRUE, &OptionString); + + if (EFI_ERROR (Status)) { + Repaint = TRUE; + NewLine = TRUE; + break; + } + + if (OptionString != NULL) { + PrintStringAt (LocalScreen.LeftColumn + gPromptBlockWidth + 1, MenuOption->Row, OptionString); + gBS->FreePool (OptionString); + } + + Selection->Action = UI_ACTION_REFRESH_FORM; + break; + } + break; + + case CfUiReset: + // + // We are going to leave current FormSet, so check uncommited data in this FormSet + // + ControlFlag = CfCheckSelection; + + if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) { + // + // There is no parent menu for FrontPage + // + Selection->Action = UI_ACTION_NONE; + Selection->Statement = MenuOption->ThisTag; + break; + } + + // + // If NV flag is up, prompt user + // + if (gNvUpdateRequired) { + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + + YesResponse = gYesResponse[0]; + NoResponse = gNoResponse[0]; + + do { + CreateDialog (3, TRUE, 0, NULL, &Key, gEmptyString, gAreYouSure, gEmptyString); + } while + ( + (Key.ScanCode != SCAN_ESC) && + ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse | UPPER_LOWER_CASE_OFFSET)) && + ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse | UPPER_LOWER_CASE_OFFSET)) + ); + + // + // If the user hits the YesResponse key + // + if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) { + } else { + Repaint = TRUE; + NewLine = TRUE; + + Selection->Action = UI_ACTION_NONE; + break; + } + } + + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + + UiFreeMenuList (); + gST->ConOut->ClearScreen (gST->ConOut); + return EFI_SUCCESS; + + case CfUiLeft: + ControlFlag = CfCheckSelection; + if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) { + if (MenuOption->Sequence != 0) { + // + // In the middle or tail of the Date/Time op-code set, go left. + // + NewPos = NewPos->BackLink; + } + } + break; + + case CfUiRight: + ControlFlag = CfCheckSelection; + if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) { + if (MenuOption->Sequence != 2) { + // + // In the middle or tail of the Date/Time op-code set, go left. + // + NewPos = NewPos->ForwardLink; + } + } + break; + + case CfUiUp: + ControlFlag = CfCheckSelection; + + SavedListEntry = TopOfScreen; + + if (NewPos->BackLink != &Menu) { + NewLine = TRUE; + // + // Adjust Date/Time position before we advance forward. + // + AdjustDateAndTimePosition (TRUE, &NewPos); + + // + // Caution that we have already rewind to the top, don't go backward in this situation. + // + if (NewPos->BackLink != &Menu) { + NewPos = NewPos->BackLink; + } + + PreviousMenuOption = MENU_OPTION_FROM_LINK (NewPos); + DistanceValue = PreviousMenuOption->Skip; + + // + // Since the behavior of hitting the up arrow on a Date/Time op-code is intended + // to be one that back to the previous set of op-codes, we need to advance to the sencond + // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate + // checking can be done. + // + DistanceValue += AdjustDateAndTimePosition (TRUE, &NewPos); + + // + // Check the previous menu entry to see if it was a zero-length advance. If it was, + // don't worry about a redraw. + // + if ((INTN) MenuOption->Row - (INTN) DistanceValue < (INTN) TopRow) { + Repaint = TRUE; + TopOfScreen = NewPos; + } + + Difference = MoveToNextStatement (TRUE, &NewPos); + if ((INTN) MenuOption->Row - (INTN) DistanceValue < (INTN) TopRow) { + if (Difference > 0) { + // + // Previous focus MenuOption is above the TopOfScreen, so we need to scroll + // + TopOfScreen = NewPos; + Repaint = TRUE; + } + } + if (Difference < 0) { + // + // We want to goto previous MenuOption, but finally we go down. + // it means that we hit the begining MenuOption that can be focused + // so we simply scroll to the top + // + if (SavedListEntry != Menu.ForwardLink) { + TopOfScreen = Menu.ForwardLink; + Repaint = TRUE; + } + } + + // + // If we encounter a Date/Time op-code set, rewind to the first op-code of the set. + // + AdjustDateAndTimePosition (TRUE, &TopOfScreen); + + UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE); + } else { + SavedMenuOption = MenuOption; + MenuOption = MENU_OPTION_FROM_LINK (NewPos); + if (!IsSelectable (MenuOption)) { + // + // If we are at the end of the list and sitting on a text op, we need to more forward + // + ScreenOperation = UiDown; + ControlFlag = CfScreenOperation; + break; + } + + MenuOption = SavedMenuOption; + } + break; + + case CfUiPageUp: + ControlFlag = CfCheckSelection; + + if (NewPos->BackLink == &Menu) { + NewLine = FALSE; + Repaint = FALSE; + break; + } + + NewLine = TRUE; + Repaint = TRUE; + Link = TopOfScreen; + PreviousMenuOption = MENU_OPTION_FROM_LINK (Link); + Index = BottomRow; + while ((Index >= TopRow) && (Link->BackLink != &Menu)) { + Index = Index - PreviousMenuOption->Skip; + Link = Link->BackLink; + PreviousMenuOption = MENU_OPTION_FROM_LINK (Link); + } + + TopOfScreen = Link; + Difference = MoveToNextStatement (TRUE, &Link); + if (Difference > 0) { + // + // The focus MenuOption is above the TopOfScreen + // + TopOfScreen = Link; + } else if (Difference < 0) { + // + // This happens when there is no MenuOption can be focused from + // Current MenuOption to the first MenuOption + // + TopOfScreen = Menu.ForwardLink; + } + Index += Difference; + if (Index < TopRow) { + MenuOption = NULL; + } + + if (NewPos == Link) { + Repaint = FALSE; + NewLine = FALSE; + } else { + NewPos = Link; + } + + // + // If we encounter a Date/Time op-code set, rewind to the first op-code of the set. + // Don't do this when we are already in the first page. + // + AdjustDateAndTimePosition (TRUE, &TopOfScreen); + AdjustDateAndTimePosition (TRUE, &NewPos); + break; + + case CfUiPageDown: + ControlFlag = CfCheckSelection; + + if (NewPos->ForwardLink == &Menu) { + NewLine = FALSE; + Repaint = FALSE; + break; + } + + NewLine = TRUE; + Repaint = TRUE; + Link = TopOfScreen; + NextMenuOption = MENU_OPTION_FROM_LINK (Link); + Index = TopRow; + while ((Index <= BottomRow) && (Link->ForwardLink != &Menu)) { + Index = Index + NextMenuOption->Skip; + Link = Link->ForwardLink; + NextMenuOption = MENU_OPTION_FROM_LINK (Link); + } + + Index += MoveToNextStatement (FALSE, &Link); + if (Index > BottomRow) { + // + // There are more MenuOption needing scrolling + // + TopOfScreen = Link; + MenuOption = NULL; + } + if (NewPos == Link && Index <= BottomRow) { + // + // Finally we know that NewPos is the last MenuOption can be focused. + // + NewLine = FALSE; + Repaint = FALSE; + } else { + NewPos = Link; + } + + // + // If we encounter a Date/Time op-code set, rewind to the first op-code of the set. + // Don't do this when we are already in the last page. + // + AdjustDateAndTimePosition (TRUE, &TopOfScreen); + AdjustDateAndTimePosition (TRUE, &NewPos); + break; + + case CfUiDown: + ControlFlag = CfCheckSelection; + // + // Since the behavior of hitting the down arrow on a Date/Time op-code is intended + // to be one that progresses to the next set of op-codes, we need to advance to the last + // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate + // checking can be done. The only other logic we need to introduce is that if a Date/Time + // op-code is the last entry in the menu, we need to rewind back to the first op-code of + // the Date/Time op-code. + // + SavedListEntry = NewPos; + DistanceValue = AdjustDateAndTimePosition (FALSE, &NewPos); + + if (NewPos->ForwardLink != &Menu) { + MenuOption = MENU_OPTION_FROM_LINK (NewPos); + NewLine = TRUE; + NewPos = NewPos->ForwardLink; + NextMenuOption = MENU_OPTION_FROM_LINK (NewPos); + + DistanceValue += NextMenuOption->Skip; + DistanceValue += MoveToNextStatement (FALSE, &NewPos); + // + // An option might be multi-line, so we need to reflect that data in the overall skip value + // + UpdateOptionSkipLines (Selection, NextMenuOption, &OptionString, SkipValue); + + Temp = MenuOption->Row + MenuOption->Skip + DistanceValue - 1; + if ((MenuOption->Row + MenuOption->Skip == BottomRow + 1) && + (NextMenuOption->ThisTag->Operand == EFI_IFR_DATE_OP || + NextMenuOption->ThisTag->Operand == EFI_IFR_TIME_OP) + ) { + Temp ++; + } + + // + // If we are going to scroll, update TopOfScreen + // + if (Temp > BottomRow) { + do { + // + // Is the current top of screen a zero-advance op-code? + // If so, keep moving forward till we hit a >0 advance op-code + // + SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen); + + // + // If bottom op-code is more than one line or top op-code is more than one line + // + if ((DistanceValue > 1) || (MenuOption->Skip > 1)) { + // + // Is the bottom op-code greater than or equal in size to the top op-code? + // + if ((Temp - BottomRow) >= (SavedMenuOption->Skip - OldSkipValue)) { + // + // Skip the top op-code + // + TopOfScreen = TopOfScreen->ForwardLink; + Difference = (Temp - BottomRow) - (SavedMenuOption->Skip - OldSkipValue); + + OldSkipValue = Difference; + + SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen); + + // + // If we have a remainder, skip that many more op-codes until we drain the remainder + // + for (; + Difference >= (INTN) SavedMenuOption->Skip; + Difference = Difference - (INTN) SavedMenuOption->Skip + ) { + // + // Since the Difference is greater than or equal to this op-code's skip value, skip it + // + TopOfScreen = TopOfScreen->ForwardLink; + SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen); + if (Difference < (INTN) SavedMenuOption->Skip) { + Difference = SavedMenuOption->Skip - Difference - 1; + break; + } else { + if (Difference == (INTN) SavedMenuOption->Skip) { + TopOfScreen = TopOfScreen->ForwardLink; + SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen); + Difference = SavedMenuOption->Skip - Difference; + break; + } + } + } + // + // Since we will act on this op-code in the next routine, and increment the + // SkipValue, set the skips to one less than what is required. + // + SkipValue = Difference - 1; + + } else { + // + // Since we will act on this op-code in the next routine, and increment the + // SkipValue, set the skips to one less than what is required. + // + SkipValue = OldSkipValue + (Temp - BottomRow) - 1; + } + } else { + if ((OldSkipValue + 1) == (INTN) SavedMenuOption->Skip) { + TopOfScreen = TopOfScreen->ForwardLink; + break; + } else { + SkipValue = OldSkipValue; + } + } + // + // If the op-code at the top of the screen is more than one line, let's not skip it yet + // Let's set a skip flag to smoothly scroll the top of the screen. + // + if (SavedMenuOption->Skip > 1) { + if (SavedMenuOption == NextMenuOption) { + SkipValue = 0; + } else { + SkipValue++; + } + } else { + SkipValue = 0; + TopOfScreen = TopOfScreen->ForwardLink; + } + } while (SavedMenuOption->Skip == 0); + + Repaint = TRUE; + OldSkipValue = SkipValue; + } + + MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry); + + UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE); + + } else { + SavedMenuOption = MenuOption; + MenuOption = MENU_OPTION_FROM_LINK (NewPos); + if (!IsSelectable (MenuOption)) { + // + // If we are at the end of the list and sitting on a text op, we need to more forward + // + ScreenOperation = UiUp; + ControlFlag = CfScreenOperation; + break; + } + + MenuOption = SavedMenuOption; + // + // If we are at the end of the list and sitting on a Date/Time op, rewind to the head. + // + AdjustDateAndTimePosition (TRUE, &NewPos); + } + break; + + case CfUiSave: + ControlFlag = CfCheckSelection; + + // + // Submit the form + // + Status = SubmitForm (Selection->FormSet, Selection->Form); + + if (!EFI_ERROR (Status)) { + UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE); + UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->QuestionFlags, FALSE); + } else { + do { + CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gSaveFailed, gPressEnter, gEmptyString); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + + Repaint = TRUE; + NewLine = TRUE; + } + break; + + case CfUiDefault: + ControlFlag = CfCheckSelection; + + Status = ExtractFormDefault (Selection->FormSet, Selection->Form, DefaultId); + + if (!EFI_ERROR (Status)) { + Selection->Action = UI_ACTION_REFRESH_FORM; + + // + // Show NV update flag on status bar + // + gNvUpdateRequired = TRUE; + } + break; + + case CfUiNoOperation: + ControlFlag = CfCheckSelection; + break; + + case CfExit: + UiFreeRefreshList (); + + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->SetCursorPosition (gST->ConOut, 0, Row + 4); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + gST->ConOut->OutputString (gST->ConOut, L"\n"); + + return EFI_SUCCESS; + + default: + break; + } + } +} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Ui.h b/MdeModulePkg/Universal/SetupBrowserDxe/Ui.h new file mode 100644 index 0000000000..a5b7076be6 --- /dev/null +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Ui.h @@ -0,0 +1,478 @@ +/** @file + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. 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. + +Module Name: + + Ui.h + +Abstract: + + Head file UI + +Revision History + + +**/ + +#ifndef _UI_H +#define _UI_H + +//@MT:#include "Tiano.h" +//@MT:#include "EfiDriverLib.h" +#include "Setup.h" +//@MT:#include "GraphicsLib.h" +//@MT:#include "EfiPrintLib.h" + +// +// Globals +// +#define REGULAR_NUMERIC 0 +#define TIME_NUMERIC 1 +#define DATE_NUMERIC 2 + +#define SUBTITLE_INDENT 2 + +typedef enum { + UiNoOperation, + UiDefault, + UiSelect, + UiUp, + UiDown, + UiLeft, + UiRight, + UiReset, + UiSave, + UiPrevious, + UiPageUp, + UiPageDown, + UiMaxOperation +} UI_SCREEN_OPERATION; + +typedef enum { + CfInitialization, + CfCheckSelection, + CfRepaint, + CfRefreshHighLight, + CfUpdateHelpString, + CfPrepareToReadKey, + CfReadKey, + CfScreenOperation, + CfUiPrevious, + CfUiSelect, + CfUiReset, + CfUiLeft, + CfUiRight, + CfUiUp, + CfUiPageUp, + CfUiPageDown, + CfUiDown, + CfUiSave, + CfUiDefault, + CfUiNoOperation, + CfExit, + CfMaxControlFlag +} UI_CONTROL_FLAG; + +#define UI_ACTION_NONE 0 +#define UI_ACTION_REFRESH_FORM 1 +#define UI_ACTION_REFRESH_FORMSET 2 +#define UI_ACTION_EXIT 3 + +typedef struct { + EFI_HII_HANDLE Handle; + + // + // Target formset/form/Question information + // + EFI_GUID FormSetGuid; + UINT16 FormId; + UINT16 QuestionId; + + UINTN TopRow; + UINTN BottomRow; + UINTN PromptCol; + UINTN OptionCol; + UINTN CurrentRow; + + // + // Ation for Browser to taken: + // UI_ACTION_NONE - navigation inside a form + // UI_ACTION_REFRESH_FORM - re-evaluate expressions and repaint form + // UI_ACTION_REFRESH_FORMSET - re-parse formset IFR binary + // + UINTN Action; + + // + // Current selected fomset/form/Question + // + FORM_BROWSER_FORMSET *FormSet; + FORM_BROWSER_FORM *Form; + FORM_BROWSER_STATEMENT *Statement; +} UI_MENU_SELECTION; + +#define UI_MENU_OPTION_SIGNATURE EFI_SIGNATURE_32 ('u', 'i', 'm', 'm') +#define UI_MENU_LIST_SIGNATURE EFI_SIGNATURE_32 ('u', 'i', 'm', 'l') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + EFI_HII_HANDLE Handle; + FORM_BROWSER_STATEMENT *ThisTag; + UINT16 EntryNumber; + + UINTN Row; + UINTN Col; + UINTN OptCol; + CHAR16 *Description; + UINTN Skip; // Number of lines + + // + // Display item sequence for date/time + // Date: Month/Day/Year + // Sequence: 0 1 2 + // + // Time: Hour : Minute : Second + // Sequence: 0 1 2 + // + // + UINTN Sequence; + + BOOLEAN GrayOut; + BOOLEAN ReadOnly; +} UI_MENU_OPTION; + +#define MENU_OPTION_FROM_LINK(a) CR (a, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE) + +typedef struct { + UINTN Signature; + LIST_ENTRY MenuLink; + + UINT16 FormId; + UINT16 QuestionId; +} UI_MENU_LIST; + +typedef struct _MENU_REFRESH_ENTRY { + struct _MENU_REFRESH_ENTRY *Next; + UI_MENU_OPTION *MenuOption; // Describes the entry needing an update + UI_MENU_SELECTION *Selection; + UINTN CurrentColumn; + UINTN CurrentRow; + UINTN CurrentAttribute; +} MENU_REFRESH_ENTRY; + +typedef struct { + UINT16 ScanCode; + UI_SCREEN_OPERATION ScreenOperation; +} SCAN_CODE_TO_SCREEN_OPERATION; + +typedef struct { + UI_SCREEN_OPERATION ScreenOperation; + UI_CONTROL_FLAG ControlFlag; +} SCREEN_OPERATION_T0_CONTROL_FLAG; + + +extern LIST_ENTRY gMenuList; +extern MENU_REFRESH_ENTRY *gMenuRefreshHead; +extern UI_MENU_SELECTION *gCurrentSelection; + +// +// Global Functions +// +VOID +UiInitMenu ( + VOID + ) +; + +VOID +UiInitMenuList ( + VOID + ) +; + +VOID +UiRemoveMenuListEntry ( + OUT UI_MENU_SELECTION *Selection + ) +; + +VOID +UiFreeMenuList ( + VOID + ) +; + +VOID +UiAddMenuListEntry ( + IN UI_MENU_SELECTION *Selection + ) +; + +VOID +UiFreeMenu ( + VOID + ) +; + +VOID +UiAddMenuOption ( + IN CHAR16 *String, + IN EFI_HII_HANDLE Handle, + IN FORM_BROWSER_STATEMENT *Statement, + IN UINT16 NumberOfLines, + IN UINT16 MenuItemCount + ) +; + +EFI_STATUS +UiDisplayMenu ( + IN OUT UI_MENU_SELECTION *Selection + ) +; + +VOID +FreeBrowserStrings ( + VOID + ) +; + +EFI_STATUS +SetupBrowser ( + IN OUT UI_MENU_SELECTION *Selection + ) +; + +VOID +ValueToString ( + IN CHAR16 *Buffer, + IN BOOLEAN Comma, + IN INT64 v + ) +; + +EFI_STATUS +UiIntToString ( + IN UINTN num, + IN OUT CHAR16 *str, + IN UINT16 size + ) +; + +VOID +SetUnicodeMem ( + IN VOID *Buffer, + IN UINTN Size, + IN CHAR16 Value + ) +; + +EFI_STATUS +UiWaitForSingleEvent ( + IN EFI_EVENT Event, + IN UINT64 Timeout, OPTIONAL + IN UINT8 RefreshInterval OPTIONAL + ) +; + +VOID +CreatePopUp ( + IN UINTN ScreenWidth, + IN UINTN NumberOfLines, + IN CHAR16 *ArrayOfStrings, + ... + ) +; + +EFI_STATUS +ReadString ( + IN UI_MENU_OPTION *MenuOption, + IN CHAR16 *Prompt, + OUT CHAR16 *StringPtr + ) +; + +EFI_STATUS +GetSelectionInputPopUp ( + IN UI_MENU_SELECTION *Selection, + IN UI_MENU_OPTION *MenuOption + ) +; + +EFI_STATUS +GetNumericInput ( + IN UI_MENU_SELECTION *Selection, + IN UI_MENU_OPTION *MenuOption + ) +; + +VOID +UpdateStatusBar ( + IN UINTN MessageType, + IN UINT8 Flags, + IN BOOLEAN State + ) +; + +EFI_STATUS +ProcessQuestionConfig ( + IN UI_MENU_SELECTION *Selection, + IN FORM_BROWSER_STATEMENT *Question + ) +; + +EFI_STATUS +PrintFormattedNumber ( + IN FORM_BROWSER_STATEMENT *Question, + IN OUT CHAR16 *FormattedNumber, + IN UINTN BufferSize + ) +; + +QUESTION_OPTION * +ValueToOption ( + IN FORM_BROWSER_STATEMENT *Question, + IN EFI_HII_VALUE *OptionValue + ) +; + +EFI_STATUS +ProcessOptions ( + IN UI_MENU_SELECTION *Selection, + IN UI_MENU_OPTION *MenuOption, + IN BOOLEAN Selected, + OUT CHAR16 **OptionString + ) +; + +VOID +ProcessHelpString ( + IN CHAR16 *StringPtr, + OUT CHAR16 **FormattedString, + IN UINTN RowCount + ) +; + +VOID +UpdateKeyHelp ( + IN UI_MENU_OPTION *MenuOption, + IN BOOLEAN Selected + ) +; + +VOID +ClearLines ( + UINTN LeftColumn, + UINTN RightColumn, + UINTN TopRow, + UINTN BottomRow, + UINTN TextAttribute + ) +; + +UINTN +GetStringWidth ( + CHAR16 *String + ) +; + +UINT16 +GetLineByWidth ( + IN CHAR16 *InputString, + IN UINT16 LineWidth, + IN OUT UINTN *Index, + OUT CHAR16 **OutputString + ) +; + +UINT16 +GetWidth ( + IN FORM_BROWSER_STATEMENT *Statement, + IN EFI_HII_HANDLE Handle + ) +; + +VOID +NewStrCat ( + CHAR16 *Destination, + CHAR16 *Source + ) +; + +EFI_STATUS +WaitForKeyStroke ( + OUT EFI_INPUT_KEY *Key + ) +; + +VOID +ResetScopeStack ( + VOID + ) +; + +EFI_STATUS +PushScope ( + IN UINT8 Operand + ) +; + +EFI_STATUS +PopScope ( + OUT UINT8 *Operand + ) +; + +FORM_BROWSER_FORM * +IdToForm ( + IN FORM_BROWSER_FORMSET *FormSet, + IN UINT16 FormId +) +; + +FORM_BROWSER_STATEMENT * +IdToQuestion ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN UINT16 QuestionId + ) +; + +FORM_EXPRESSION * +IdToExpression ( + IN FORM_BROWSER_FORM *Form, + IN UINT8 RuleId + ) +; + +VOID +ExtendValueToU64 ( + IN EFI_HII_VALUE *Value + ) +; + +INTN +CompareHiiValue ( + IN EFI_HII_VALUE *Value1, + IN EFI_HII_VALUE *Value2, + IN EFI_HII_HANDLE HiiHandle OPTIONAL + ) +; + +EFI_STATUS +EvaluateExpression ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_EXPRESSION *Expression + ) +; + +#endif // _UI_H diff --git a/MdeModulePkg/Universal/iScsi/IScsi.inf b/MdeModulePkg/Universal/iScsi/IScsi.inf index faa570d435..0e4569ca7e 100644 --- a/MdeModulePkg/Universal/iScsi/IScsi.inf +++ b/MdeModulePkg/Universal/iScsi/IScsi.inf @@ -77,8 +77,8 @@ DevicePathLib
DebugLib
PrintLib
- FrameworkHiiLib
- FrameworkIfrSupportLib
+ HiiLib
+ IfrSupportLib
NetLib
[Protocols]
@@ -88,8 +88,8 @@ gEfiExtScsiPassThruProtocolGuid
gEfiDevicePathProtocolGuid
gEfiTcp4ServiceBindingProtocolGuid
- gEfiFormCallbackProtocolGuid
- gEfiFormBrowserProtocolGuid
+ gEfiHiiDatabaseProtocolGuid
+ gEfiHiiConfigAccessProtocolGuid
gEfiPciIoProtocolGuid
gEfiAcpiSupportProtocolGuid
gEfiDhcp4ProtocolGuid
diff --git a/MdeModulePkg/Universal/iScsi/IScsiCHAP.c b/MdeModulePkg/Universal/iScsi/IScsiCHAP.c index 6f4b170a60..e6ea8b5400 100644 --- a/MdeModulePkg/Universal/iScsi/IScsiCHAP.c +++ b/MdeModulePkg/Universal/iScsi/IScsiCHAP.c @@ -119,6 +119,7 @@ Returns: {
EFI_STATUS Status;
ISCSI_SESSION *Session;
+ ISCSI_SESSION_CONFIG_DATA *ConfigData;
ISCSI_CHAP_AUTH_DATA *AuthData;
CHAR8 *Value;
UINT8 *Data;
@@ -136,6 +137,7 @@ Returns: ASSERT (Conn->RspQue.BufNum != 0);
Session = Conn->Session;
+ ConfigData = &Session->ConfigData;
AuthData = &Session->AuthData;
Len = Conn->RspQue.BufSize;
@@ -151,7 +153,7 @@ Returns: //
// Build the key-value list from the data segment of the Login Response.
//
- KeyValueList = IScsiBuildKeyValueList ((CHAR8*)Data, Len);
+ KeyValueList = IScsiBuildKeyValueList (Data, Len);
if (KeyValueList == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ON_EXIT;
@@ -317,6 +319,7 @@ Returns: EFI_STATUS Status;
ISCSI_SESSION *Session;
ISCSI_LOGIN_REQUEST *LoginReq;
+ ISCSI_SESSION_CONFIG_DATA *ConfigData;
ISCSI_CHAP_AUTH_DATA *AuthData;
CHAR8 *Value;
CHAR8 ValueStr[256];
@@ -328,6 +331,7 @@ Returns: ASSERT (Conn->CurrentStage == ISCSI_SECURITY_NEGOTIATION);
Session = Conn->Session;
+ ConfigData = &Session->ConfigData;
AuthData = &Session->AuthData;
LoginReq = (ISCSI_LOGIN_REQUEST *) NetbufGetByte (Pdu, 0, 0);
Status = EFI_SUCCESS;
@@ -383,7 +387,7 @@ Returns: //
// CHAP_N=<N>
//
- IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_NAME, (CHAR8 *) &AuthData->AuthConfig.CHAPName);
+ IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_NAME, (UINT8 *) &AuthData->AuthConfig.CHAPName);
//
// CHAP_R=<R>
//
diff --git a/MdeModulePkg/Universal/iScsi/IScsiCHAP.h b/MdeModulePkg/Universal/iScsi/IScsiCHAP.h index 4a152913e2..130cccf96f 100644 --- a/MdeModulePkg/Universal/iScsi/IScsiCHAP.h +++ b/MdeModulePkg/Universal/iScsi/IScsiCHAP.h @@ -22,7 +22,7 @@ Abstract: #define ISCSI_CHAP_AUTH_INFO_GUID \
{ \
- 0x786ec0ac, 0x65ae, 0x4d1b, 0xb1, 0x37, 0xd, 0x11, 0xa, 0x48, 0x37, 0x97 \
+ 0x786ec0ac, 0x65ae, 0x4d1b, {0xb1, 0x37, 0xd, 0x11, 0xa, 0x48, 0x37, 0x97} \
}
extern EFI_GUID mIScsiCHAPAuthInfoGuid;
diff --git a/MdeModulePkg/Universal/iScsi/IScsiConfig.c b/MdeModulePkg/Universal/iScsi/IScsiConfig.c index a8ef2c79b6..67dcb8b2ae 100644 --- a/MdeModulePkg/Universal/iScsi/IScsiConfig.c +++ b/MdeModulePkg/Universal/iScsi/IScsiConfig.c @@ -22,6 +22,7 @@ Abstract: EFI_GUID mVendorGuid = ISCSI_CONFIG_GUID;
BOOLEAN mIScsiDeviceListUpdated = FALSE;
UINTN mNumberOfIScsiDevices = 0;
+ISCSI_FORM_CALLBACK_INFO *mCallbackInfo;
NET_LIST_ENTRY mIScsiConfigFormList = {
&mIScsiConfigFormList,
@@ -74,21 +75,9 @@ Returns: --*/
{
- EFI_FORM_BROWSER_PROTOCOL *FormBrowser;
- EFI_STATUS Status;
EFI_INPUT_KEY Key;
- CHAR16 Buffer[10];
-
- Status = gBS->LocateProtocol (
- &gEfiFormBrowserProtocolGuid,
- NULL,
- (VOID **)&FormBrowser
- );
- if (EFI_ERROR (Status)) {
- return ;
- }
- FormBrowser->CreatePopUp (1, TRUE, 10, Buffer, &Key, Warning);
+ IfrLibCreatePopUp (1, &Key, Warning);
}
EFI_STATUS
@@ -335,42 +324,47 @@ Returns: IScsiAsciiStrToUnicodeStr (AuthConfigData->ReverseCHAPSecret, IfrNvData->ReverseCHAPSecret);
}
+
EFI_STATUS
EFIAPI
-IScsiFormNvRead (
- IN EFI_FORM_CALLBACK_PROTOCOL * This,
- IN CHAR16 *VariableName,
- IN EFI_GUID * VendorGuid,
- OUT UINT32 *Attributes OPTIONAL,
- IN OUT UINTN *DataSize,
- OUT VOID *Buffer
+IScsiFormExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
)
/*++
-Routine Description:
-
- NV read function for the iSCSI form callback protocol.
-
-Arguments:
-
- This - The EFI form callback protocol instance.
- VariableName - Name of the variable to read.
- VendorGuid - Guid of the variable to read.
- Attributes - The storage to get the attributes of the variable.
- DataSize - The size of the buffer to store the variable.
- Buffer - The buffer to store the variable to read.
-
-Returns:
-
- EFI_SUCCESS - The variable is read.
- EFI_BUFFER_TOO_SMALL - The buffer provided is too small to hold the variable.
+ Routine Description:
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+ Arguments:
+ This - Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ Request - A null-terminated Unicode string in <ConfigRequest> format.
+ Progress - On return, points to a character in the Request string.
+ Points to the string's null terminator if request was successful.
+ Points to the most recent '&' before the first failing name/value
+ pair (or the beginning of the string if the failure is in the
+ first name/value pair) if the request was not successful.
+ Results - A null-terminated Unicode string in <ConfigAltResp> format which
+ has all values filled in for the names in the Request string.
+ String to be allocated by the called function.
+
+ Returns:
+ EFI_SUCCESS - The Results is filled with the requested values.
+ EFI_OUT_OF_RESOURCES - Not enough memory to store the results.
+ EFI_INVALID_PARAMETER - Request is NULL, illegal syntax, or unknown name.
+ EFI_NOT_FOUND - Routing data doesn't match any storage in this driver.
--*/
{
- EFI_STATUS Status;
- CHAR8 InitiatorName[ISCSI_NAME_IFR_MAX_SIZE];
- UINTN BufferSize;
- ISCSI_CONFIG_IFR_NVDATA *IfrNvData;
+ EFI_STATUS Status;
+ CHAR8 InitiatorName[ISCSI_NAME_IFR_MAX_SIZE];
+ UINTN BufferSize;
+ ISCSI_CONFIG_IFR_NVDATA *IfrNvData;
+ ISCSI_FORM_CALLBACK_INFO *Private;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
if (!mIScsiDeviceListUpdated) {
//
@@ -380,9 +374,14 @@ Returns: mIScsiDeviceListUpdated = TRUE;
}
- IfrNvData = (ISCSI_CONFIG_IFR_NVDATA *) Buffer;
- BufferSize = ISCSI_NAME_IFR_MAX_SIZE;
+ Private = ISCSI_FORM_CALLBACK_INFO_FROM_FORM_CALLBACK (This);
+ IfrNvData = AllocateZeroPool (sizeof (ISCSI_CONFIG_IFR_NVDATA));
+ ASSERT (IfrNvData != NULL);
+ if (Private->Current != NULL) {
+ IScsiConvertDeviceConfigDataToIfrNvData (Private->Current, IfrNvData);
+ }
+ BufferSize = ISCSI_NAME_IFR_MAX_SIZE;
Status = gIScsiInitiatorName.Get (&gIScsiInitiatorName, &BufferSize, InitiatorName);
if (EFI_ERROR (Status)) {
IfrNvData->InitiatorName[0] = L'\0';
@@ -390,37 +389,82 @@ Returns: IScsiAsciiStrToUnicodeStr (InitiatorName, IfrNvData->InitiatorName);
}
- return EFI_SUCCESS;
+ //
+ // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
+ //
+ HiiConfigRouting = Private->ConfigRouting;
+ BufferSize = sizeof (ISCSI_CONFIG_IFR_NVDATA);
+ Status = HiiConfigRouting->BlockToConfig (
+ HiiConfigRouting,
+ Request,
+ (UINT8 *) IfrNvData,
+ BufferSize,
+ Results,
+ Progress
+ );
+ NetFreePool (IfrNvData);
+ return Status;
}
EFI_STATUS
EFIAPI
-IScsiFormCallback (
- IN EFI_FORM_CALLBACK_PROTOCOL *This,
- IN UINT16 KeyValue,
- IN EFI_IFR_DATA_ARRAY *Data,
- OUT EFI_HII_CALLBACK_PACKET **Packet
+IScsiFormRouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
)
/*++
-Routine Description:
+ Routine Description:
+ This function processes the results of changes in configuration.
- The form callback function for iSCSI form callback protocol, it processes
- the events tiggered in the UI and take some operations to update the form,
- store the data, etc.
+ Arguments:
+ This - Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ Configuration - A null-terminated Unicode string in <ConfigResp> format.
+ Progress - A pointer to a string filled in with the offset of the most
+ recent '&' before the first failing name/value pair (or the
+ beginning of the string if the failure is in the first
+ name/value pair) or the terminating NULL if all was successful.
-Arguments:
+ Returns:
+ EFI_SUCCESS - The Results is processed successfully.
+ EFI_INVALID_PARAMETER - Configuration is NULL.
+ EFI_NOT_FOUND - Routing data doesn't match any storage in this driver.
- This - The EFI form callback protocol instance.
- KeyValue - A unique value which is sent to the original exporting driver so that it
- can identify the type of data to expect. The format of the data tends to
- vary based on the op-code that geerated the callback.
- Data - A pointer to the data being sent to the original exporting driver.
+--*/
+{
+ return EFI_SUCCESS;
+}
-Returns:
+EFI_STATUS
+EFIAPI
+IScsiFormCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID KeyValue,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+/*++
+
+ Routine Description:
+ This function processes the results of changes in configuration.
- EFI_SUCCESS - The data is valid and the correspondance operation is done.
- EFI_INVALID_PARAMETER - The data is invalid.
+ Arguments:
+ This - Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ Action - Specifies the type of action taken by the browser.
+ QuestionId - A unique value which is sent to the original exporting driver
+ so that it can identify the type of data to expect.
+ Type - The type of value for the question.
+ Value - A pointer to the data being sent to the original exporting driver.
+ ActionRequest - On return, points to the action requested by the callback function.
+
+ Returns:
+ EFI_SUCCESS - The callback successfully handled the action.
+ EFI_OUT_OF_RESOURCES - Not enough storage is available to hold the variable and its data.
+ EFI_DEVICE_ERROR - The variable could not be saved.
+ EFI_UNSUPPORTED - The specified Action is not supported by the callback.
--*/
{
@@ -440,8 +484,18 @@ Returns: EFI_STATUS Status;
Private = ISCSI_FORM_CALLBACK_INFO_FROM_FORM_CALLBACK (This);
- IfrNvData = (ISCSI_CONFIG_IFR_NVDATA *) Data->NvRamMap;
- Status = EFI_SUCCESS;
+
+ //
+ // Retrive uncommitted data from Browser
+ //
+ BufferSize = sizeof (ISCSI_CONFIG_IFR_NVDATA);
+ IfrNvData = AllocateZeroPool (BufferSize);
+ ASSERT (IfrNvData != NULL);
+ Status = GetBrowserData (NULL, NULL, &BufferSize, (UINT8 *) IfrNvData);
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (IfrNvData);
+ return Status;
+ }
switch (KeyValue) {
case KEY_INITIATOR_NAME:
@@ -633,7 +687,7 @@ Returns: BufferSize,
&Private->Current->AuthConfigData
);
-
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;
break;
default:
@@ -644,16 +698,9 @@ Returns: ConfigFormEntry = IScsiGetConfigFormEntryByIndex ((UINT32) (KeyValue - KEY_DEVICE_ENTRY_BASE));
ASSERT (ConfigFormEntry != NULL);
- UnicodeSPrint (PortString, 128, L"Port %s", ConfigFormEntry->MacString);
+ UnicodeSPrint (PortString, (UINTN) 128, L"Port %s", ConfigFormEntry->MacString);
DeviceFormTitleToken = (STRING_REF) STR_ISCSI_DEVICE_FORM_TITLE;
-
- Private->Hii->NewString (
- Private->Hii,
- NULL,
- Private->RegisteredHandle,
- &DeviceFormTitleToken,
- PortString
- );
+ IfrLibSetString (Private->RegisteredHandle, DeviceFormTitleToken, PortString);
IScsiConvertDeviceConfigDataToIfrNvData (ConfigFormEntry, IfrNvData);
@@ -663,9 +710,19 @@ Returns: break;
}
+ if (!EFI_ERROR (Status)) {
+ //
+ // Pass changed uncommitted data back to Form Browser
+ //
+ BufferSize = sizeof (ISCSI_CONFIG_IFR_NVDATA);
+ Status = SetBrowserData (NULL, NULL, BufferSize, (UINT8 *) IfrNvData, NULL);
+ }
+
+ NetFreePool (IfrNvData);
return Status;
}
+
EFI_STATUS
IScsiConfigUpdateForm (
IN EFI_HANDLE DriverBindingHandle,
@@ -695,28 +752,13 @@ Returns: NET_LIST_ENTRY *Entry;
ISCSI_CONFIG_FORM_ENTRY *ConfigFormEntry;
BOOLEAN EntryExisted;
- EFI_HII_UPDATE_DATA *UpdateData;
EFI_STATUS Status;
- EFI_FORM_CALLBACK_PROTOCOL *Callback;
- ISCSI_FORM_CALLBACK_INFO *CallbackInfo;
+ EFI_HII_UPDATE_DATA UpdateData;
EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
CHAR16 PortString[128];
UINT16 FormIndex;
UINTN BufferSize;
- //
- // Get the EFI_FORM_CALLBACK_PROTOCOL.
- //
- Status = gBS->HandleProtocol (
- DriverBindingHandle,
- &gEfiFormCallbackProtocolGuid,
- (VOID **)&Callback
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- CallbackInfo = ISCSI_FORM_CALLBACK_INFO_FROM_FORM_CALLBACK (Callback);
ConfigFormEntry = NULL;
EntryExisted = FALSE;
@@ -790,25 +832,13 @@ Returns: // Compose the Port string and create a new STRING_REF.
//
UnicodeSPrint (PortString, 128, L"Port %s", ConfigFormEntry->MacString);
- CallbackInfo->Hii->NewString (
- CallbackInfo->Hii,
- NULL,
- CallbackInfo->RegisteredHandle,
- &ConfigFormEntry->PortTitleToken,
- PortString
- );
+ IfrLibNewString (mCallbackInfo->RegisteredHandle, &ConfigFormEntry->PortTitleToken, PortString);
//
// Compose the help string of this port and create a new STRING_REF.
//
UnicodeSPrint (PortString, 128, L"Set the iSCSI parameters on port %s", ConfigFormEntry->MacString);
- CallbackInfo->Hii->NewString (
- CallbackInfo->Hii,
- NULL,
- CallbackInfo->RegisteredHandle,
- &ConfigFormEntry->PortTitleHelpToken,
- PortString
- );
+ IfrLibNewString (mCallbackInfo->RegisteredHandle, &ConfigFormEntry->PortTitleHelpToken, PortString);
NetListInsertTail (&mIScsiConfigFormList, &ConfigFormEntry->Link);
mNumberOfIScsiDevices++;
@@ -823,37 +853,11 @@ Returns: //
// Allocate space for creation of Buffer
//
- UpdateData = (EFI_HII_UPDATE_DATA *) NetAllocatePool (0x1000);
- NetZeroMem (UpdateData, 0x1000);
-
- //
- // Flag update pending in FormSet
- //
- UpdateData->FormSetUpdate = TRUE;
-
- //
- // Register CallbackHandle data for FormSet
- //
- UpdateData->FormCallbackHandle = (EFI_PHYSICAL_ADDRESS) (UINTN) CallbackInfo->CallbackHandle;
- UpdateData->FormUpdate = FALSE;
- UpdateData->FormTitle = 0;
-
- //
- // first of all, remove all the forms.
- //
- UpdateData->DataCount = 0xFF;
-
- CallbackInfo->Hii->UpdateForm (
- CallbackInfo->Hii,
- CallbackInfo->RegisteredHandle,
- (EFI_FORM_LABEL) DEVICE_ENTRY_LABEL,
- FALSE,
- UpdateData
- );
-
- UpdateData->DataCount = 1;
- FormIndex = 0;
+ UpdateData.BufferSize = 0x1000;
+ UpdateData.Data = NetAllocateZeroPool (0x1000);
+ UpdateData.Offset = 0;
+ FormIndex = 0;
NET_LIST_FOR_EACH (Entry, &mIScsiConfigFormList) {
ConfigFormEntry = NET_LIST_USER_STRUCT (Entry, ISCSI_CONFIG_FORM_ENTRY, Link);
@@ -861,23 +865,24 @@ Returns: FORMID_DEVICE_FORM,
ConfigFormEntry->PortTitleToken,
ConfigFormEntry->PortTitleHelpToken,
- EFI_IFR_FLAG_INTERACTIVE,
- (UINT16) (KEY_DEVICE_ENTRY_BASE + FormIndex),
- &UpdateData->Data
+ EFI_IFR_FLAG_CALLBACK,
+ KEY_DEVICE_ENTRY_BASE + FormIndex,
+ &UpdateData
);
- CallbackInfo->Hii->UpdateForm (
- CallbackInfo->Hii,
- CallbackInfo->RegisteredHandle,
- (EFI_FORM_LABEL) DEVICE_ENTRY_LABEL,
- TRUE,
- UpdateData
- );
-
FormIndex++;
}
- NetFreePool (UpdateData);
+ IfrLibUpdateForm (
+ mCallbackInfo->RegisteredHandle,
+ &mVendorGuid,
+ FORMID_MAIN_FORM,
+ DEVICE_ENTRY_LABEL,
+ FALSE,
+ &UpdateData
+ );
+
+ NetFreePool (UpdateData.Data);
return EFI_SUCCESS;
}
@@ -903,17 +908,14 @@ Returns: --*/
{
- EFI_STATUS Status;
- EFI_HII_PROTOCOL *Hii;
- EFI_HII_PACKAGES *PackageList;
- EFI_HII_HANDLE HiiHandle;
- EFI_HII_UPDATE_DATA *UpdateData;
- ISCSI_FORM_CALLBACK_INFO *CallbackInfo;
- EFI_GUID StringPackGuid = ISCSI_CONFIG_GUID;
-
- Status = gBS->LocateProtocol (&gEfiHiiProtocolGuid, NULL, (VOID **)&Hii);
+ EFI_STATUS Status;
+ EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
+ EFI_HII_PACKAGE_LIST_HEADER *PackageList;
+ ISCSI_FORM_CALLBACK_INFO *CallbackInfo;
+
+ Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, &HiiDatabase);
if (EFI_ERROR (Status)) {
- return Status;;
+ return Status;
}
CallbackInfo = (ISCSI_FORM_CALLBACK_INFO *) NetAllocatePool (sizeof (ISCSI_FORM_CALLBACK_INFO));
@@ -922,59 +924,55 @@ Returns: }
CallbackInfo->Signature = ISCSI_FORM_CALLBACK_INFO_SIGNATURE;
- CallbackInfo->Hii = Hii;
+ CallbackInfo->HiiDatabase = HiiDatabase;
CallbackInfo->Current = NULL;
- CallbackInfo->FormCallback.NvRead = IScsiFormNvRead;
- CallbackInfo->FormCallback.NvWrite = NULL;
- CallbackInfo->FormCallback.Callback = IScsiFormCallback;
+ CallbackInfo->ConfigAccess.ExtractConfig = IScsiFormExtractConfig;
+ CallbackInfo->ConfigAccess.RouteConfig = IScsiFormRouteConfig;
+ CallbackInfo->ConfigAccess.Callback = IScsiFormCallback;
+ Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, &CallbackInfo->ConfigRouting);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Create driver handle used by HII database
+ //
+ Status = HiiLibCreateHiiDriverHandle (&CallbackInfo->DriverHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
//
- // Install protocol interface
+ // Install Config Access protocol to driver handle
//
Status = gBS->InstallProtocolInterface (
- &DriverBindingHandle,
- &gEfiFormCallbackProtocolGuid,
+ &CallbackInfo->DriverHandle,
+ &gEfiHiiConfigAccessProtocolGuid,
EFI_NATIVE_INTERFACE,
- &CallbackInfo->FormCallback
+ &CallbackInfo->ConfigAccess
);
-
ASSERT_EFI_ERROR (Status);
-
- CallbackInfo->CallbackHandle = DriverBindingHandle;
- PackageList = PreparePackages (2, &StringPackGuid, iSCSIStrings, IScsiConfigDxeBin);
- Status = Hii->NewPack (Hii, PackageList, &HiiHandle);
- NetFreePool (PackageList);
-
- CallbackInfo->RegisteredHandle = HiiHandle;
-
+
//
- // Allocate space for creation of Buffer
+ // Publish our HII data
//
- UpdateData = (EFI_HII_UPDATE_DATA *) NetAllocatePool (0x1000);
- ASSERT (UpdateData != NULL);
- if (UpdateData == NULL) {
- return EFI_OUT_OF_RESOURCES;
+ PackageList = PreparePackageList (2, &mVendorGuid, iSCSIStrings, IScsiConfigDxeBin);
+ ASSERT (PackageList != NULL);
+
+ Status = HiiDatabase->NewPackageList (
+ HiiDatabase,
+ PackageList,
+ CallbackInfo->DriverHandle,
+ &CallbackInfo->RegisteredHandle
+ );
+ NetFreePool (PackageList);
+ if (EFI_ERROR (Status)) {
+ return Status;
}
- NetZeroMem (UpdateData, 0x1000);
-
- //
- // Flag update pending in FormSet
- //
- UpdateData->FormSetUpdate = TRUE;
-
- //
- // Register CallbackHandle data for FormSet
- //
- UpdateData->FormCallbackHandle = (EFI_PHYSICAL_ADDRESS) (UINTN) CallbackInfo->CallbackHandle;
- UpdateData->FormUpdate = FALSE;
- UpdateData->FormTitle = 0;
- UpdateData->DataCount = 0x1;
-
- Hii->UpdateForm (Hii, HiiHandle, (EFI_FORM_LABEL) 0x1000, TRUE, UpdateData);
-
- NetFreePool (UpdateData);
+ mCallbackInfo = CallbackInfo;
return Status;
}
@@ -1003,11 +1001,6 @@ Returns: --*/
{
ISCSI_CONFIG_FORM_ENTRY *ConfigFormEntry;
- EFI_STATUS Status;
- EFI_HII_PROTOCOL *Hii;
- EFI_HII_UPDATE_DATA *UpdateData;
- EFI_FORM_CALLBACK_PROTOCOL *FormCallback;
- ISCSI_FORM_CALLBACK_INFO *CallbackInfo;
while (!NetListIsEmpty (&mIScsiConfigFormList)) {
//
@@ -1021,54 +1014,25 @@ Returns: IScsiConfigUpdateForm (DriverBindingHandle, ConfigFormEntry->Controller, FALSE);
}
- Status = gBS->LocateProtocol (&gEfiHiiProtocolGuid, NULL, (VOID **)&Hii);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = gBS->HandleProtocol (DriverBindingHandle, &gEfiFormCallbackProtocolGuid, (VOID **)&FormCallback);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- CallbackInfo = ISCSI_FORM_CALLBACK_INFO_FROM_FORM_CALLBACK (FormCallback);
-
//
- // remove the form.
+ // Remove HII package list
//
- UpdateData = (EFI_HII_UPDATE_DATA *) NetAllocatePool (0x1000);
- ASSERT (UpdateData != NULL);
- if (UpdateData == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- NetZeroMem (UpdateData, 0x1000);
-
- UpdateData->FormSetUpdate = FALSE;
- UpdateData->FormCallbackHandle = 0;
- UpdateData->FormUpdate = FALSE;
- UpdateData->FormTitle = 0;
- UpdateData->DataCount = 0xFF;
-
- Hii->UpdateForm (Hii, CallbackInfo->RegisteredHandle, (EFI_FORM_LABEL) 0x1000, FALSE, UpdateData);
-
- NetFreePool (UpdateData);
+ mCallbackInfo->HiiDatabase->RemovePackageList (
+ mCallbackInfo->HiiDatabase,
+ mCallbackInfo->RegisteredHandle
+ );
//
- // Uninstall the EFI_FORM_CALLBACK_PROTOCOL.
+ // Uninstall EFI_HII_CONFIG_ACCESS_PROTOCOL
//
gBS->UninstallProtocolInterface (
- DriverBindingHandle,
- &gEfiFormCallbackProtocolGuid,
- FormCallback
+ mCallbackInfo->DriverHandle,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &mCallbackInfo->ConfigAccess
);
+ HiiLibDestroyHiiDriverHandle (mCallbackInfo->DriverHandle);
- //
- // Remove the package.
- //
- Hii->RemovePack (Hii, CallbackInfo->RegisteredHandle);
-
- NetFreePool (CallbackInfo);
+ NetFreePool (mCallbackInfo);
return EFI_SUCCESS;
}
diff --git a/MdeModulePkg/Universal/iScsi/IScsiConfig.h b/MdeModulePkg/Universal/iScsi/IScsiConfig.h index 726b7a2f71..aab488f4a0 100644 --- a/MdeModulePkg/Universal/iScsi/IScsiConfig.h +++ b/MdeModulePkg/Universal/iScsi/IScsiConfig.h @@ -21,12 +21,17 @@ Abstract: #ifndef _ISCSI_CONFIG_H_
#define _ISCSI_CONFIG_H_
-#include <Library/FrameworkHiiLib.h>
-#include <Protocol/FrameworkFormBrowser.h>
-#include <Protocol/FrameworkFormCallback.h>
-#include <Library/FrameworkIfrSupportLib.h>
+//#include "Tiano.h"
+//#include "EfiDriverLib.h"
+//#include "Base.h"
+#include <Library/HiiLib.h>
+#include <Library/IfrSupportLib.h>
#include <Library/DebugLib.h>
#include <Library/BaseLib.h>
+//#include "EfiPrintLib.h"
+//#include EFI_PROTOCOL_DEFINITION (Hii)
+//#include EFI_PROTOCOL_DEFINITION (FormBrowser)
+//#include EFI_PROTOCOL_DEFINITION (FormCallback)
#include <Library/NetLib.h>
#include "IScsiConfigNVDataStruc.h"
@@ -44,7 +49,7 @@ extern UINT8 iSCSIStrings[]; CR ( \
Callback, \
ISCSI_FORM_CALLBACK_INFO, \
- FormCallback, \
+ ConfigAccess, \
ISCSI_FORM_CALLBACK_INFO_SIGNATURE \
)
@@ -74,14 +79,15 @@ typedef struct _ISCSI_CONFIG_FORM_ENTRY { } ISCSI_CONFIG_FORM_ENTRY;
typedef struct _ISCSI_FORM_CALLBACK_INFO {
- UINTN Signature;
- EFI_HANDLE CallbackHandle;
- EFI_FORM_CALLBACK_PROTOCOL FormCallback;
- UINT16 *KeyList;
- VOID *FormBuffer;
- EFI_HII_HANDLE RegisteredHandle;
- EFI_HII_PROTOCOL *Hii;
- ISCSI_CONFIG_FORM_ENTRY *Current;
+ UINTN Signature;
+ EFI_HANDLE DriverHandle;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+ EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *ConfigRouting;
+ UINT16 *KeyList;
+ VOID *FormBuffer;
+ EFI_HII_HANDLE RegisteredHandle;
+ ISCSI_CONFIG_FORM_ENTRY *Current;
} ISCSI_FORM_CALLBACK_INFO;
EFI_STATUS
diff --git a/MdeModulePkg/Universal/iScsi/IScsiConfigDxe.vfr b/MdeModulePkg/Universal/iScsi/IScsiConfigDxe.vfr index 3df9b18cb1..db89affce2 100644 --- a/MdeModulePkg/Universal/iScsi/IScsiConfigDxe.vfr +++ b/MdeModulePkg/Universal/iScsi/IScsiConfigDxe.vfr @@ -22,6 +22,8 @@ #include "IScsiConfigNVDataStruc.h"
#define EFI_NETWORK_DEVICE_CLASS 0x04
+#define LABEL_END 0xffff
+
formset
guid = ISCSI_CONFIG_GUID,
title = STRING_TOKEN(STR_ISCSI_CONFIG_FORM_TITLE),
@@ -29,8 +31,11 @@ formset class = EFI_NETWORK_DEVICE_CLASS,
subclass = 0x03,
+ varstore ISCSI_CONFIG_IFR_NVDATA,
+ name = ISCSI_CONFIG_IFR_NVDATA,
+ guid = ISCSI_CONFIG_GUID;
form formid = FORMID_MAIN_FORM,
- title = STRING_TOKEN(STR_ISCSI_MAIN_FORM_TITLE); // note formid is a variable (for readability) (UINT16) - also added Form to the line to signify the Op-Code
+ title = STRING_TOKEN(STR_ISCSI_MAIN_FORM_TITLE);
string varid = ISCSI_CONFIG_IFR_NVDATA.InitiatorName,
prompt = STRING_TOKEN(STR_ISCSI_CONFIG_INIT_NAME),
@@ -42,6 +47,7 @@ formset endstring;
label DEVICE_ENTRY_LABEL;
+ label LABEL_END;
endform;
diff --git a/MdeModulePkg/Universal/iScsi/IScsiConfigNVDataStruc.h b/MdeModulePkg/Universal/iScsi/IScsiConfigNVDataStruc.h index 444cb69de0..7e1d2f86cd 100644 --- a/MdeModulePkg/Universal/iScsi/IScsiConfigNVDataStruc.h +++ b/MdeModulePkg/Universal/iScsi/IScsiConfigNVDataStruc.h @@ -55,19 +55,19 @@ Abstract: #define DEVICE_ENTRY_LABEL 0x1234
-#define KEY_INITIATOR_NAME 0x01
-#define KEY_DHCP_ENABLE 0x02
-#define KEY_LOCAL_IP 0x03
-#define KEY_SUBNET_MASK 0x04
-#define KEY_GATE_WAY 0x05
-#define KEY_TARGET_IP 0x06
-#define KEY_CHAP_NAME 0x07
-#define KEY_CHAP_SECRET 0x08
-#define KEY_REVERSE_CHAP_NAME 0x09
-#define KEY_REVERSE_CHAP_SECRET 0x0a
-#define KEY_SAVE_CHANGES 0x0b
-#define KEY_TARGET_NAME 0x0c
-#define KEY_BOOT_LUN 0x0d
+#define KEY_INITIATOR_NAME 0x101
+#define KEY_DHCP_ENABLE 0x102
+#define KEY_LOCAL_IP 0x103
+#define KEY_SUBNET_MASK 0x104
+#define KEY_GATE_WAY 0x105
+#define KEY_TARGET_IP 0x106
+#define KEY_CHAP_NAME 0x107
+#define KEY_CHAP_SECRET 0x108
+#define KEY_REVERSE_CHAP_NAME 0x109
+#define KEY_REVERSE_CHAP_SECRET 0x10a
+#define KEY_SAVE_CHANGES 0x10b
+#define KEY_TARGET_NAME 0x10c
+#define KEY_BOOT_LUN 0x10d
#define KEY_DEVICE_ENTRY_BASE 0x1000
diff --git a/MdeModulePkg/Universal/iScsi/IScsiDhcp.c b/MdeModulePkg/Universal/iScsi/IScsiDhcp.c index 145483b0e7..b9b8cea8ab 100644 --- a/MdeModulePkg/Universal/iScsi/IScsiDhcp.c +++ b/MdeModulePkg/Universal/iScsi/IScsiDhcp.c @@ -230,9 +230,9 @@ Returns: Status = This->Parse (This, Packet, &OptionCount, NULL);
if (Status != EFI_BUFFER_TOO_SMALL) {
- return EFI_NOT_READY;
+
return EFI_NOT_READY;
}
-
+
OptionList = NetAllocatePool (OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));
if (OptionList == NULL) {
return EFI_NOT_READY;
@@ -437,7 +437,7 @@ Returns: // Ask the server to reply with Netmask, Router, DNS and RootPath options.
//
ParaList->OpCode = DHCP4_TAG_PARA_LIST;
- ParaList->Length = (UINT8)(ConfigData->NvData.TargetInfoFromDhcp ? 4 : 3);
+ ParaList->Length = ConfigData->NvData.TargetInfoFromDhcp ? 4 : 3;
ParaList->Data[0] = DHCP4_TAG_NETMASK;
ParaList->Data[1] = DHCP4_TAG_ROUTER;
ParaList->Data[2] = DHCP4_TAG_DNS;
diff --git a/MdeModulePkg/Universal/iScsi/IScsiDhcp.h b/MdeModulePkg/Universal/iScsi/IScsiDhcp.h index f70aebd26e..9312b547bd 100644 --- a/MdeModulePkg/Universal/iScsi/IScsiDhcp.h +++ b/MdeModulePkg/Universal/iScsi/IScsiDhcp.h @@ -20,7 +20,9 @@ Abstract: #ifndef _ISCSI_DHCP_H_
#define _ISCSI_DHCP_H_
-#include <Protocol/Dhcp4.h>
+//#include "Tiano.h"
+//#include EFI_PROTOCOL_CONSUMER (Dhcp4)
+#include "protocol\Dhcp4.h"
#define DHCP4_TAG_PARA_LIST 55
#define DHCP4_TAG_NETMASK 1
diff --git a/MdeModulePkg/Universal/iScsi/IScsiIbft.c b/MdeModulePkg/Universal/iScsi/IScsiIbft.c index bf68be6a37..e5d6324727 100644 --- a/MdeModulePkg/Universal/iScsi/IScsiIbft.c +++ b/MdeModulePkg/Universal/iScsi/IScsiIbft.c @@ -101,7 +101,7 @@ Returns: // Need expand the control section if more than 2 NIC/Target sections
// exist.
//
- Control->Header.Length = (UINT16)(Control->Header.Length + (NumOffset - 4) * sizeof (UINT16));
+ Control->Header.Length += (UINT16) (NumOffset - 4) * sizeof (UINT16);
}
}
@@ -191,7 +191,7 @@ Returns: //
// Get the identifier from the handle.
//
- Status = gBS->HandleProtocol (Handle, &mIScsiPrivateGuid, (void **)&IScsiIdentifier);
+ Status = gBS->HandleProtocol (Handle, &mIScsiPrivateGuid, &IScsiIdentifier);
if (EFI_ERROR (Status)) {
ASSERT (FALSE);
return ;
@@ -278,7 +278,7 @@ Returns: Status = gBS->HandleProtocol (
Controller,
&gEfiDevicePathProtocolGuid,
- (void **)&DevicePath
+ &DevicePath
);
if (EFI_ERROR (Status)) {
return 0;
@@ -293,7 +293,7 @@ Returns: return 0;
}
- Status = gBS->HandleProtocol (PciIoHandle, &gEfiPciIoProtocolGuid, (void **)&PciIo);
+ Status = gBS->HandleProtocol (PciIoHandle, &gEfiPciIoProtocolGuid, &PciIo);
if (EFI_ERROR (Status)) {
return 0;
}
@@ -333,7 +333,7 @@ Returns: Status = gBS->HandleProtocol (
Controller,
&gEfiSimpleNetworkProtocolGuid,
- (void **)&Snp
+ &Snp
);
ASSERT_EFI_ERROR (Status);
@@ -392,7 +392,7 @@ Returns: SectionOffset = &Control->NIC0Offset;
for (Index = 0; Index < HandleCount; Index++) {
- Status = gBS->HandleProtocol (Handles[Index], &mIScsiPrivateGuid, (void **)&IScsiIdentifier);
+ Status = gBS->HandleProtocol (Handles[Index], &mIScsiPrivateGuid, &IScsiIdentifier);
if (EFI_ERROR (Status)) {
ASSERT (FALSE);
return ;
@@ -552,7 +552,7 @@ Returns: EFI_ACPI_TABLE_VERSION Version;
UINT32 Signature;
- Status = gBS->LocateProtocol (&gEfiAcpiSupportProtocolGuid, NULL, (void **)&AcpiSupport);
+ Status = gBS->LocateProtocol (&gEfiAcpiSupportProtocolGuid, NULL, &AcpiSupport);
if (EFI_ERROR (Status)) {
return ;
}
@@ -563,7 +563,7 @@ Returns: Status = AcpiSupport->GetAcpiTable (
AcpiSupport,
Index,
- (void **)&Table,
+ &Table,
&Version,
&TableHandle
);
@@ -613,7 +613,7 @@ Returns: return ;
}
- Heap = (UINT8 *) Table + IBFT_HEAP_OFFSET;
+ Heap = (CHAR8 *) Table + IBFT_HEAP_OFFSET;
//
// Fill in the various section of the iSCSI Boot Firmware Table.
diff --git a/MdeModulePkg/Universal/iScsi/IScsiImpl.h b/MdeModulePkg/Universal/iScsi/IScsiImpl.h index 535bc8461e..715f814882 100644 --- a/MdeModulePkg/Universal/iScsi/IScsiImpl.h +++ b/MdeModulePkg/Universal/iScsi/IScsiImpl.h @@ -37,7 +37,7 @@ Abstract: #define ISCSI_SESSION_SIGNATURE EFI_SIGNATURE_32 ('I', 'S', 'S', 'N')
-struct _ISCSI_SESSION {
+typedef struct _ISCSI_SESSION {
UINT32 Signature;
ISCSI_SESSION_CONFIG_DATA ConfigData;
@@ -77,11 +77,11 @@ struct _ISCSI_SESSION { BOOLEAN DataPDUInOrder;
BOOLEAN DataSequenceInOrder;
UINT8 ErrorRecoveryLevel;
-};
+} ISCSI_SESSION;
#define ISCSI_CONNECTION_SIGNATURE EFI_SIGNATURE_32 ('I', 'S', 'C', 'N')
-struct _ISCSI_CONNECTION {
+typedef struct _ISCSI_CONNECTION {
UINT32 Signature;
NET_LIST_ENTRY Link;
@@ -116,7 +116,7 @@ struct _ISCSI_CONNECTION { UINT32 MaxRecvDataSegmentLength;
ISCSI_DIGEST_TYPE HeaderDigest;
ISCSI_DIGEST_TYPE DataDigest;
-};
+} ISCSI_CONNECTION;
#define ISCSI_DRIVER_DATA_SIGNATURE EFI_SIGNATURE_32 ('I', 'S', 'D', 'A')
@@ -142,7 +142,7 @@ struct _ISCSI_CONNECTION { ISCSI_DRIVER_DATA_SIGNATURE \
)
-struct _ISCSI_DRIVER_DATA {
+typedef struct _ISCSI_DRIVER_DATA {
UINT32 Signature;
EFI_HANDLE Image;
EFI_HANDLE Controller;
@@ -156,6 +156,6 @@ struct _ISCSI_DRIVER_DATA { EFI_DEVICE_PATH_PROTOCOL *DevicePath;
ISCSI_SESSION Session;
-};
+} ISCSI_DRIVER_DATA;
#endif
diff --git a/MdeModulePkg/Universal/iScsi/IScsiMisc.c b/MdeModulePkg/Universal/iScsi/IScsiMisc.c index 214af74697..0347d32042 100644 --- a/MdeModulePkg/Universal/iScsi/IScsiMisc.c +++ b/MdeModulePkg/Universal/iScsi/IScsiMisc.c @@ -167,7 +167,7 @@ Returns: Len++;
}
- return (UINT8)(32 - Len);
+ return 32 - Len;
}
EFI_STATUS
@@ -196,7 +196,6 @@ Returns: UINT32 Index;
CHAR8 *LunUnitStr[4];
CHAR8 Digit;
- UINTN Temp;
NetZeroMem (Lun, 8);
NetZeroMem (LunUnitStr, sizeof (LunUnitStr));
@@ -204,7 +203,7 @@ Returns: Index = 0;
LunUnitStr[0] = Str;
- if (!IsHexDigit ((UINT8 *)&Digit, *Str)) {
+ if (!IsHexDigit (&Digit, *Str)) {
return EFI_INVALID_PARAMETER;
}
@@ -220,13 +219,13 @@ Returns: Index++;
if (*(Str + 1) != '\0') {
- if (!IsHexDigit ((UINT8 *)&Digit, *(Str + 1))) {
+ if (!IsHexDigit (&Digit, *(Str + 1))) {
return EFI_INVALID_PARAMETER;
}
LunUnitStr[Index] = Str + 1;
}
- } else if (!IsHexDigit ((UINT8 *)&Digit, *Str)) {
+ } else if (!IsHexDigit (&Digit, *Str)) {
return EFI_INVALID_PARAMETER;
}
@@ -238,8 +237,7 @@ Returns: return EFI_INVALID_PARAMETER;
}
- Temp = AsciiStrHexToUintn (LunUnitStr[Index]);
- *((UINT16 *) &Lun[Index * 2]) = HTONS (Temp);
+ *((UINT16 *) &Lun[Index * 2]) = HTONS (AsciiStrHexToUintn (LunUnitStr[Index]));
}
return EFI_SUCCESS;
@@ -472,7 +470,7 @@ Returns: UINT32 Index;
for (Index = 0; Index < Len; Index++) {
- Str[3 * Index] = NibbleToHexChar ((UINT8)(Mac->Addr[Index] >> 4));
+ Str[3 * Index] = NibbleToHexChar (Mac->Addr[Index] >> 4);
Str[3 * Index + 1] = NibbleToHexChar (Mac->Addr[Index]);
Str[3 * Index + 2] = L'-';
}
@@ -602,7 +600,7 @@ Returns: } else {
Byte = BinBuffer[*BinLength - 1 - Index / 2];
Byte &= 0x0F;
- Byte = (UINT8)(Byte | (Digit << 4));
+ Byte |= Digit << 4;
}
BinBuffer[*BinLength - 1 - Index / 2] = Byte;
@@ -811,7 +809,7 @@ Returns: Status = gBS->HandleProtocol (
Private->Controller,
&gEfiSimpleNetworkProtocolGuid,
- (void **)&Snp
+ &Snp
);
if (EFI_ERROR (Status)) {
return Status;
@@ -907,7 +905,7 @@ Returns: Status = gBS->HandleProtocol (
Tcp4Io->Handle,
&gEfiDevicePathProtocolGuid,
- (void **)&DevicePath
+ &DevicePath
);
if (EFI_ERROR (Status)) {
return NULL;
@@ -925,7 +923,7 @@ Returns: ) {
DPathNode->Ipv4.LocalPort = 0;
- DPathNode->Ipv4.StaticIpAddress = (BOOLEAN)(!Session->ConfigData.NvData.InitiatorInfoFromDhcp);
+ DPathNode->Ipv4.StaticIpAddress = !Session->ConfigData.NvData.InitiatorInfoFromDhcp;
break;
}
diff --git a/MdeModulePkg/Universal/iScsi/IScsiProto.c b/MdeModulePkg/Universal/iScsi/IScsiProto.c index fa1c7d6c1b..4cef3dc45d 100644 --- a/MdeModulePkg/Universal/iScsi/IScsiProto.c +++ b/MdeModulePkg/Universal/iScsi/IScsiProto.c @@ -546,7 +546,7 @@ Returns: //
// Allocate the space for the key-value pair.
//
- Data = (CHAR8 *) NetbufAllocSpace (Pdu, TotalLen, NET_BUF_TAIL);
+ Data = NetbufAllocSpace (Pdu, TotalLen, NET_BUF_TAIL);
if (Data == NULL) {
return EFI_OUT_OF_RESOURCES;
}
@@ -668,7 +668,7 @@ Returns: //
// Check whether we will issue the stage transition signal?
//
- Conn->TransitInitiated = (BOOLEAN)ISCSI_FLAG_ON (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);
+ Conn->TransitInitiated = ISCSI_FLAG_ON (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);
}
return Nbuf;
@@ -746,7 +746,7 @@ Returns: // Process the TargetAddress key-value strings in the data segment to update the
// target address info.
//
- Status = IScsiUpdateTargetAddress (Session, (CHAR8 *)DataSeg, DataSegLen);
+ Status = IScsiUpdateTargetAddress (Session, DataSeg, DataSegLen);
if (EFI_ERROR (Status)) {
return Status;
}
@@ -765,11 +765,11 @@ Returns: //
// The status is sucess, extract the wanted fields from the header segment.
//
- Transit = (BOOLEAN)ISCSI_FLAG_ON (LoginRsp, ISCSI_LOGIN_RSP_PDU_FLAG_TRANSIT);
- Continue = (BOOLEAN)ISCSI_FLAG_ON (LoginRsp, ISCSI_LOGIN_RSP_PDU_FLAG_CONTINUE);
+ Transit = ISCSI_FLAG_ON (LoginRsp, ISCSI_LOGIN_RSP_PDU_FLAG_TRANSIT);
+ Continue = ISCSI_FLAG_ON (LoginRsp, ISCSI_LOGIN_RSP_PDU_FLAG_CONTINUE);
- CurrentStage = (UINT8)ISCSI_GET_CURRENT_STAGE (LoginRsp);
- NextStage = (UINT8)ISCSI_GET_NEXT_STAGE (LoginRsp);
+ CurrentStage = ISCSI_GET_CURRENT_STAGE (LoginRsp);
+ NextStage = ISCSI_GET_NEXT_STAGE (LoginRsp);
LoginRsp->InitiatorTaskTag = NTOHL (LoginRsp->InitiatorTaskTag);
@@ -1283,7 +1283,7 @@ Returns: return EFI_OUT_OF_RESOURCES;
}
- NetbufQueCopy (&Conn->RspQue, 0, Len, (UINT8 *)Data);
+ NetbufQueCopy (&Conn->RspQue, 0, Len, Data);
Status = EFI_PROTOCOL_ERROR;
@@ -1352,7 +1352,7 @@ Returns: goto ON_ERROR;
}
- Session->InitialR2T = (BOOLEAN)(Session->InitialR2T || (AsciiStrCmp (Value, "Yes") == 0));
+ Session->InitialR2T = Session->InitialR2T || (BOOLEAN) (AsciiStrCmp (Value, "Yes") == 0);
//
// ImmediateData, result function is AND.
@@ -1362,7 +1362,7 @@ Returns: goto ON_ERROR;
}
- Session->ImmediateData = (BOOLEAN)(Session->ImmediateData && (AsciiStrCmp (Value, "Yes") == 0));
+ Session->ImmediateData = Session->ImmediateData && (BOOLEAN) (AsciiStrCmp (Value, "Yes") == 0);
//
// MaxRecvDataSegmentLength, result function is Mininum.
@@ -1422,7 +1422,7 @@ Returns: goto ON_ERROR;
}
- Session->DataPDUInOrder = (BOOLEAN)(Session->DataPDUInOrder || (AsciiStrCmp (Value, "Yes") == 0));
+ Session->DataPDUInOrder = Session->DataPDUInOrder || (BOOLEAN) (AsciiStrCmp (Value, "Yes") == 0);
//
// DataSequenceInorder, result function is OR.
@@ -1432,7 +1432,7 @@ Returns: goto ON_ERROR;
}
- Session->DataSequenceInOrder = (BOOLEAN)(Session->DataSequenceInOrder || (AsciiStrCmp (Value, "Yes") == 0));
+ Session->DataSequenceInOrder = Session->DataSequenceInOrder || (BOOLEAN) (AsciiStrCmp (Value, "Yes") == 0);
//
// DefaultTime2Wait, result function is Maximum.
@@ -1799,7 +1799,7 @@ Returns: //
// Convert the upper-case characters to lower-case ones
//
- Name[Index] = (CHAR8)(Name[Index] - 'A' + 'a');
+ Name[Index] = Name[Index] - 'A' + 'a';
}
if (!NET_IS_LOWER_CASE_CHAR (Name[Index]) &&
@@ -2048,7 +2048,7 @@ Returns: //
// The CDB exceeds 16 bytes, an extended CDB AHS is required.
//
- AHSLength = (UINT8)(AHSLength + (ISCSI_ROUNDUP (Packet->CdbLength - 16) + sizeof (ISCSI_ADDITIONAL_HEADER)));
+ AHSLength += ISCSI_ROUNDUP (Packet->CdbLength - 16) + sizeof (ISCSI_ADDITIONAL_HEADER);
}
Length = sizeof (SCSI_COMMAND) + AHSLength;
@@ -2769,7 +2769,6 @@ Returns: UINT8 *Data;
ISCSI_IN_BUFFER_CONTEXT InBufferContext;
UINT64 Timeout;
- UINT8 *Buffer;
Private = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (PassThru);
Session = &Private->Session;
@@ -2815,8 +2814,7 @@ Returns: }
XferContext = &Tcb->XferContext;
- Buffer = NetbufGetByte (Pdu, 0, NULL);
- XferContext->Offset = ISCSI_GET_DATASEG_LEN (Buffer);
+ XferContext->Offset = ISCSI_GET_DATASEG_LEN (NetbufGetByte (Pdu, 0, NULL));
//
// Transmit the SCSI Command PDU.
diff --git a/MdeModulePkg/Universal/iScsi/IScsiProto.h b/MdeModulePkg/Universal/iScsi/IScsiProto.h index d47a5b5679..59608fcec7 100644 --- a/MdeModulePkg/Universal/iScsi/IScsiProto.h +++ b/MdeModulePkg/Universal/iScsi/IScsiProto.h @@ -119,8 +119,8 @@ typedef enum { #define ISCSI_IMMEDIATE_ON(PduHdr) ((PduHdr)->OpCode & ISCSI_REQ_IMMEDIATE)
#define ISCSI_SET_FLAG(PduHdr, Flag) (((ISCSI_BASIC_HEADER *) (PduHdr))->Flags |= (Flag))
#define ISCSI_CLEAR_FLAG(PduHdr, Flag) (((ISCSI_BASIC_HEADER *) (PduHdr))->Flags &= ~(Flag))
-#define ISCSI_FLAG_ON(PduHdr, Flag) ((((ISCSI_BASIC_HEADER *) (PduHdr))->Flags & (Flag)) == (BOOLEAN)(Flag))
-#define ISCSI_SET_STAGES(PduHdr, Cur, Nxt) ((PduHdr)->Flags = (UINT8)(((PduHdr)->Flags)|(((Cur) << 2) | (Nxt))))
+#define ISCSI_FLAG_ON(PduHdr, Flag) ((((ISCSI_BASIC_HEADER *) (PduHdr))->Flags & (Flag)) == (Flag))
+#define ISCSI_SET_STAGES(PduHdr, Cur, Nxt) ((PduHdr)->Flags |= ((Cur) << 2 | (Nxt)))
#define ISCSI_GET_CURRENT_STAGE(PduHdr) (((PduHdr)->Flags >> 2) & 0x3)
#define ISCSI_GET_NEXT_STAGE(PduHdr) (((PduHdr)->Flags) & 0x3)
@@ -129,9 +129,9 @@ typedef enum { #define HTON24(Dst, Src) \
do { \
- (Dst)[0] = (UINT8)(((Src) >> 16) & 0xFF); \
- (Dst)[1] = (UINT8)(((Src) >> 8) & 0xFF); \
- (Dst)[2] = (UINT8)((Src) & 0xFF); \
+ (Dst)[0] = (UINT8) ((Src) >> 16) & 0xFF; \
+ (Dst)[1] = (UINT8) ((Src) >> 8) & 0xFF; \
+ (Dst)[2] = (UINT8) (Src) & 0xFF; \
} while (0);
#define NTOH24(src) (((src)[0] << 16) | ((src)[1] << 8) | ((src)[2]))
|