From 93e3992d1ea50fb30c48f498d257d4e66252dd9b Mon Sep 17 00:00:00 2001 From: qwang12 Date: Mon, 21 Jan 2008 14:39:56 +0000 Subject: [PATCH] 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 --- MdeModulePkg/Core/Dxe/DxeMain.inf | 3 +- MdeModulePkg/Include/Library/GenericBdsLib.h | 565 +++ MdeModulePkg/Include/Library/PlatformBdsLib.h | 98 + MdeModulePkg/Include/MdeModuleHii.h | 125 + MdeModulePkg/Library/GenericBdsLib/BdsBoot.c | 1912 +++++++++ .../Library/GenericBdsLib/BdsConnect.c | 424 ++ .../Library/GenericBdsLib/BdsConsole.c | 399 ++ MdeModulePkg/Library/GenericBdsLib/BdsMisc.c | 1415 +++++++ .../Library/GenericBdsLib/DevicePath.c | 1321 ++++++ .../Library/GenericBdsLib/Ebc/BmMachine.h | 35 + .../Library/GenericBdsLib/GenericBdsLib.inf | 119 + .../Library/GenericBdsLib/GenericBdsLib.msa | 159 + .../Library/GenericBdsLib/Ia32/BmMachine.h | 34 + .../Library/GenericBdsLib/Ia32/ClearDr.asm | 43 + .../Library/GenericBdsLib/InternalBdsLib.h | 102 + .../Library/GenericBdsLib/Ipf/BmMachine.h | 34 + .../Library/GenericBdsLib/Ipf/ShadowRom.c | 56 + .../Library/GenericBdsLib/Performance.c | 326 ++ MdeModulePkg/Library/GenericBdsLib/R8Lib.c | 114 + MdeModulePkg/Library/GenericBdsLib/R8Lib.h | 59 + .../Library/GenericBdsLib/x64/BmMachine.h | 34 + .../Library/GenericBdsLib/x64/ClearDr.asm | 41 + MdeModulePkg/Library/GraphicsLib/Graphics.c | 892 ++++ .../Library/GraphicsLib/GraphicsLib.inf | 57 + .../Library/GraphicsLib/GraphicsLib.msa | 72 + .../Library/IfrSupportLib/IfrSupportLib.inf | 71 + .../Library/IfrSupportLib/IfrSupportLib.msa | 74 + MdeModulePkg/Library/IfrSupportLib/R8Lib.c | 241 ++ MdeModulePkg/Library/IfrSupportLib/R8Lib.h | 93 + .../Library/IfrSupportLib/UefiIfrCommon.c | 369 ++ .../Library/IfrSupportLib/UefiIfrForm.c | 1121 +++++ .../IfrSupportLib/UefiIfrLibraryInternal.h | 64 + .../IfrSupportLib/UefiIfrOpCodeCreation.c | 639 +++ .../Library/IfrSupportLib/UefiIfrString.c | 681 +++ .../Library/PlatformBdsLibNull/BdsPlatform.c | 276 ++ .../Library/PlatformBdsLibNull/BdsPlatform.h | 37 + .../PlatformBdsLibNull/PlatformBdsLibNull.inf | 55 + .../Library/PlatformBdsLibNull/PlatformData.c | 52 + MdeModulePkg/MdeModulePkg.dec | 9 +- MdeModulePkg/MdeModulePkg.dsc | 26 +- MdeModulePkg/Universal/BdsDxe/Bds.h | 117 + MdeModulePkg/Universal/BdsDxe/BdsDxe.inf | 154 + MdeModulePkg/Universal/BdsDxe/BdsDxe.msa | 238 ++ MdeModulePkg/Universal/BdsDxe/BdsEntry.c | 375 ++ .../Universal/BdsDxe/BootMaint/BBSsupport.c | 1664 ++++++++ .../Universal/BdsDxe/BootMaint/BBSsupport.h | 78 + .../Universal/BdsDxe/BootMaint/Bm.vfr | 391 ++ .../Universal/BdsDxe/BootMaint/BmLib.c | 563 +++ .../Universal/BdsDxe/BootMaint/Bmstring.uni | Bin 0 -> 37774 bytes .../Universal/BdsDxe/BootMaint/BootMaint.c | 1331 ++++++ .../Universal/BdsDxe/BootMaint/BootMaint.h | 1087 +++++ .../Universal/BdsDxe/BootMaint/BootOption.c | 1697 ++++++++ .../BdsDxe/BootMaint/ConsoleOption.c | 992 +++++ .../Universal/BdsDxe/BootMaint/Data.c | 324 ++ .../Universal/BdsDxe/BootMaint/FE.vfr | 134 + .../Universal/BdsDxe/BootMaint/FileExplorer.c | 327 ++ .../Universal/BdsDxe/BootMaint/FormGuid.h | 216 + .../Universal/BdsDxe/BootMaint/UpdatePage.c | 1211 ++++++ .../Universal/BdsDxe/BootMaint/Variable.c | 1314 ++++++ .../Universal/BdsDxe/BootMngr/BootManager.c | 335 ++ .../Universal/BdsDxe/BootMngr/BootManager.h | 88 + .../BdsDxe/BootMngr/BootManagerStrings.uni | Bin 0 -> 3470 bytes .../BdsDxe/BootMngr/BootManagerVfr.Vfr | 59 + MdeModulePkg/Universal/BdsDxe/Capsules.c | 264 ++ .../BdsDxe/DeviceMngr/DeviceManager.c | 434 ++ .../BdsDxe/DeviceMngr/DeviceManager.h | 108 + .../DeviceMngr/DeviceManagerStrings.uni | Bin 0 -> 3768 bytes .../BdsDxe/DeviceMngr/DeviceManagerVfr.Vfr | 82 + MdeModulePkg/Universal/BdsDxe/FrontPage.c | 1035 +++++ MdeModulePkg/Universal/BdsDxe/FrontPage.h | 149 + .../Universal/BdsDxe/FrontPageStrings.uni | Bin 0 -> 10190 bytes .../Universal/BdsDxe/FrontPageVfr.Vfr | 145 + MdeModulePkg/Universal/BdsDxe/Hotkey.c | 769 ++++ MdeModulePkg/Universal/BdsDxe/Hotkey.h | 117 + .../Universal/BdsDxe/HwErrRecSupport.c | 62 + .../Universal/BdsDxe/HwErrRecSupport.h | 53 + MdeModulePkg/Universal/BdsDxe/Language.c | 420 ++ MdeModulePkg/Universal/BdsDxe/Language.h | 47 + MdeModulePkg/Universal/BdsDxe/MemoryTest.c | 431 ++ MdeModulePkg/Universal/BdsDxe/String.c | 104 + MdeModulePkg/Universal/BdsDxe/String.h | 61 + MdeModulePkg/Universal/BdsDxe/Strings.uni | Bin 0 -> 7496 bytes .../GraphicsConsoleDxe/GraphicsConsole.c | 180 +- .../GraphicsConsoleDxe/GraphicsConsole.h | 27 +- .../GraphicsConsoleDxe/GraphicsConsoleDxe.inf | 8 +- .../GraphicsConsoleDxe/GraphicsConsoleDxe.msa | 3 - .../DevicePathDxe/DevicePathFromText.c | 8 +- .../DevicePathDxe/DevicePathToText.c | 6 +- .../Universal/DriverSampleDxe/DriverSample.c | 788 ++++ .../Universal/DriverSampleDxe/DriverSample.h | 97 + .../DriverSampleDxe/DriverSampleDxe.inf | 72 + .../DriverSampleDxe/DriverSampleDxe.msa | 80 + .../Universal/DriverSampleDxe/NVDataStruc.h | 64 + .../Universal/DriverSampleDxe/Vfr.vfr | 504 +++ .../Universal/DriverSampleDxe/VfrStrings.uni | Bin 0 -> 37386 bytes .../Universal/DriverSampleDxe/inventory.vfr | 121 + .../DriverSampleDxe/inventorystrings.uni | Bin 0 -> 8438 bytes .../Universal/HiiDatabaseDxe/ConfigRouting.c | 2116 ++++++++++ .../Universal/HiiDatabaseDxe/Database.c | 3727 +++++++++++++++++ MdeModulePkg/Universal/HiiDatabaseDxe/Font.c | 2395 +++++++++++ .../Universal/HiiDatabaseDxe/HiiDatabase.h | 1694 ++++++++ .../Universal/HiiDatabaseDxe/HiiDatabase.msa | 79 + .../HiiDatabaseDxe/HiiDatabaseDxe.inf | 75 + .../HiiDatabaseDxe/HiiDatabaseEntry.c | 197 + MdeModulePkg/Universal/HiiDatabaseDxe/Image.c | 1509 +++++++ MdeModulePkg/Universal/HiiDatabaseDxe/R8Lib.c | 284 ++ MdeModulePkg/Universal/HiiDatabaseDxe/R8Lib.h | 121 + .../Universal/HiiDatabaseDxe/String.c | 1606 +++++++ .../Universal/SetupBrowserDxe/Colors.h | 55 + .../Universal/SetupBrowserDxe/Expression.c | 1938 +++++++++ .../Universal/SetupBrowserDxe/IfrParse.c | 1640 ++++++++ .../Universal/SetupBrowserDxe/InputHandler.c | 1146 +++++ .../Universal/SetupBrowserDxe/Presentation.c | 928 ++++ .../Universal/SetupBrowserDxe/Print.c | 331 ++ .../Universal/SetupBrowserDxe/Print.h | 38 + .../SetupBrowserDxe/ProcessOptions.c | 986 +++++ .../Universal/SetupBrowserDxe/R8Lib.c | 243 ++ .../Universal/SetupBrowserDxe/R8Lib.h | 97 + .../Universal/SetupBrowserDxe/Setup.c | 2286 ++++++++++ .../Universal/SetupBrowserDxe/Setup.h | 760 ++++ .../SetupBrowserDxe/SetupBrowser.msa | 84 + .../SetupBrowserDxe/SetupBrowserDxe.inf | 82 + .../SetupBrowserDxe/SetupBrowserStr.uni | Bin 0 -> 11422 bytes MdeModulePkg/Universal/SetupBrowserDxe/Ui.c | 2830 +++++++++++++ MdeModulePkg/Universal/SetupBrowserDxe/Ui.h | 478 +++ MdeModulePkg/Universal/iScsi/IScsi.inf | 8 +- MdeModulePkg/Universal/iScsi/IScsiCHAP.c | 8 +- MdeModulePkg/Universal/iScsi/IScsiCHAP.h | 2 +- MdeModulePkg/Universal/iScsi/IScsiConfig.c | 446 +- MdeModulePkg/Universal/iScsi/IScsiConfig.h | 32 +- .../Universal/iScsi/IScsiConfigDxe.vfr | 8 +- .../Universal/iScsi/IScsiConfigNVDataStruc.h | 26 +- MdeModulePkg/Universal/iScsi/IScsiDhcp.c | 6 +- MdeModulePkg/Universal/iScsi/IScsiDhcp.h | 4 +- MdeModulePkg/Universal/iScsi/IScsiIbft.c | 18 +- MdeModulePkg/Universal/iScsi/IScsiImpl.h | 12 +- MdeModulePkg/Universal/iScsi/IScsiMisc.c | 22 +- MdeModulePkg/Universal/iScsi/IScsiProto.c | 32 +- MdeModulePkg/Universal/iScsi/IScsiProto.h | 10 +- 139 files changed, 59160 insertions(+), 380 deletions(-) create mode 100644 MdeModulePkg/Include/Library/GenericBdsLib.h create mode 100644 MdeModulePkg/Include/Library/PlatformBdsLib.h create mode 100644 MdeModulePkg/Include/MdeModuleHii.h create mode 100644 MdeModulePkg/Library/GenericBdsLib/BdsBoot.c create mode 100644 MdeModulePkg/Library/GenericBdsLib/BdsConnect.c create mode 100644 MdeModulePkg/Library/GenericBdsLib/BdsConsole.c create mode 100644 MdeModulePkg/Library/GenericBdsLib/BdsMisc.c create mode 100644 MdeModulePkg/Library/GenericBdsLib/DevicePath.c create mode 100644 MdeModulePkg/Library/GenericBdsLib/Ebc/BmMachine.h create mode 100644 MdeModulePkg/Library/GenericBdsLib/GenericBdsLib.inf create mode 100644 MdeModulePkg/Library/GenericBdsLib/GenericBdsLib.msa create mode 100644 MdeModulePkg/Library/GenericBdsLib/Ia32/BmMachine.h create mode 100644 MdeModulePkg/Library/GenericBdsLib/Ia32/ClearDr.asm create mode 100644 MdeModulePkg/Library/GenericBdsLib/InternalBdsLib.h create mode 100644 MdeModulePkg/Library/GenericBdsLib/Ipf/BmMachine.h create mode 100644 MdeModulePkg/Library/GenericBdsLib/Ipf/ShadowRom.c create mode 100644 MdeModulePkg/Library/GenericBdsLib/Performance.c create mode 100644 MdeModulePkg/Library/GenericBdsLib/R8Lib.c create mode 100644 MdeModulePkg/Library/GenericBdsLib/R8Lib.h create mode 100644 MdeModulePkg/Library/GenericBdsLib/x64/BmMachine.h create mode 100644 MdeModulePkg/Library/GenericBdsLib/x64/ClearDr.asm create mode 100644 MdeModulePkg/Library/GraphicsLib/Graphics.c create mode 100644 MdeModulePkg/Library/GraphicsLib/GraphicsLib.inf create mode 100644 MdeModulePkg/Library/GraphicsLib/GraphicsLib.msa create mode 100644 MdeModulePkg/Library/IfrSupportLib/IfrSupportLib.inf create mode 100644 MdeModulePkg/Library/IfrSupportLib/IfrSupportLib.msa create mode 100644 MdeModulePkg/Library/IfrSupportLib/R8Lib.c create mode 100644 MdeModulePkg/Library/IfrSupportLib/R8Lib.h create mode 100644 MdeModulePkg/Library/IfrSupportLib/UefiIfrCommon.c create mode 100644 MdeModulePkg/Library/IfrSupportLib/UefiIfrForm.c create mode 100644 MdeModulePkg/Library/IfrSupportLib/UefiIfrLibraryInternal.h create mode 100644 MdeModulePkg/Library/IfrSupportLib/UefiIfrOpCodeCreation.c create mode 100644 MdeModulePkg/Library/IfrSupportLib/UefiIfrString.c create mode 100644 MdeModulePkg/Library/PlatformBdsLibNull/BdsPlatform.c create mode 100644 MdeModulePkg/Library/PlatformBdsLibNull/BdsPlatform.h create mode 100644 MdeModulePkg/Library/PlatformBdsLibNull/PlatformBdsLibNull.inf create mode 100644 MdeModulePkg/Library/PlatformBdsLibNull/PlatformData.c create mode 100644 MdeModulePkg/Universal/BdsDxe/Bds.h create mode 100644 MdeModulePkg/Universal/BdsDxe/BdsDxe.inf create mode 100644 MdeModulePkg/Universal/BdsDxe/BdsDxe.msa create mode 100644 MdeModulePkg/Universal/BdsDxe/BdsEntry.c create mode 100644 MdeModulePkg/Universal/BdsDxe/BootMaint/BBSsupport.c create mode 100644 MdeModulePkg/Universal/BdsDxe/BootMaint/BBSsupport.h create mode 100644 MdeModulePkg/Universal/BdsDxe/BootMaint/Bm.vfr create mode 100644 MdeModulePkg/Universal/BdsDxe/BootMaint/BmLib.c create mode 100644 MdeModulePkg/Universal/BdsDxe/BootMaint/Bmstring.uni create mode 100644 MdeModulePkg/Universal/BdsDxe/BootMaint/BootMaint.c create mode 100644 MdeModulePkg/Universal/BdsDxe/BootMaint/BootMaint.h create mode 100644 MdeModulePkg/Universal/BdsDxe/BootMaint/BootOption.c create mode 100644 MdeModulePkg/Universal/BdsDxe/BootMaint/ConsoleOption.c create mode 100644 MdeModulePkg/Universal/BdsDxe/BootMaint/Data.c create mode 100644 MdeModulePkg/Universal/BdsDxe/BootMaint/FE.vfr create mode 100644 MdeModulePkg/Universal/BdsDxe/BootMaint/FileExplorer.c create mode 100644 MdeModulePkg/Universal/BdsDxe/BootMaint/FormGuid.h create mode 100644 MdeModulePkg/Universal/BdsDxe/BootMaint/UpdatePage.c create mode 100644 MdeModulePkg/Universal/BdsDxe/BootMaint/Variable.c create mode 100644 MdeModulePkg/Universal/BdsDxe/BootMngr/BootManager.c create mode 100644 MdeModulePkg/Universal/BdsDxe/BootMngr/BootManager.h create mode 100644 MdeModulePkg/Universal/BdsDxe/BootMngr/BootManagerStrings.uni create mode 100644 MdeModulePkg/Universal/BdsDxe/BootMngr/BootManagerVfr.Vfr create mode 100644 MdeModulePkg/Universal/BdsDxe/Capsules.c create mode 100644 MdeModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManager.c create mode 100644 MdeModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManager.h create mode 100644 MdeModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManagerStrings.uni create mode 100644 MdeModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManagerVfr.Vfr create mode 100644 MdeModulePkg/Universal/BdsDxe/FrontPage.c create mode 100644 MdeModulePkg/Universal/BdsDxe/FrontPage.h create mode 100644 MdeModulePkg/Universal/BdsDxe/FrontPageStrings.uni create mode 100644 MdeModulePkg/Universal/BdsDxe/FrontPageVfr.Vfr create mode 100644 MdeModulePkg/Universal/BdsDxe/Hotkey.c create mode 100644 MdeModulePkg/Universal/BdsDxe/Hotkey.h create mode 100644 MdeModulePkg/Universal/BdsDxe/HwErrRecSupport.c create mode 100644 MdeModulePkg/Universal/BdsDxe/HwErrRecSupport.h create mode 100644 MdeModulePkg/Universal/BdsDxe/Language.c create mode 100644 MdeModulePkg/Universal/BdsDxe/Language.h create mode 100644 MdeModulePkg/Universal/BdsDxe/MemoryTest.c create mode 100644 MdeModulePkg/Universal/BdsDxe/String.c create mode 100644 MdeModulePkg/Universal/BdsDxe/String.h create mode 100644 MdeModulePkg/Universal/BdsDxe/Strings.uni create mode 100644 MdeModulePkg/Universal/DriverSampleDxe/DriverSample.c create mode 100644 MdeModulePkg/Universal/DriverSampleDxe/DriverSample.h create mode 100644 MdeModulePkg/Universal/DriverSampleDxe/DriverSampleDxe.inf create mode 100644 MdeModulePkg/Universal/DriverSampleDxe/DriverSampleDxe.msa create mode 100644 MdeModulePkg/Universal/DriverSampleDxe/NVDataStruc.h create mode 100644 MdeModulePkg/Universal/DriverSampleDxe/Vfr.vfr create mode 100644 MdeModulePkg/Universal/DriverSampleDxe/VfrStrings.uni create mode 100644 MdeModulePkg/Universal/DriverSampleDxe/inventory.vfr create mode 100644 MdeModulePkg/Universal/DriverSampleDxe/inventorystrings.uni create mode 100644 MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c create mode 100644 MdeModulePkg/Universal/HiiDatabaseDxe/Database.c create mode 100644 MdeModulePkg/Universal/HiiDatabaseDxe/Font.c create mode 100644 MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabase.h create mode 100644 MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabase.msa create mode 100644 MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf create mode 100644 MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseEntry.c create mode 100644 MdeModulePkg/Universal/HiiDatabaseDxe/Image.c create mode 100644 MdeModulePkg/Universal/HiiDatabaseDxe/R8Lib.c create mode 100644 MdeModulePkg/Universal/HiiDatabaseDxe/R8Lib.h create mode 100644 MdeModulePkg/Universal/HiiDatabaseDxe/String.c create mode 100644 MdeModulePkg/Universal/SetupBrowserDxe/Colors.h create mode 100644 MdeModulePkg/Universal/SetupBrowserDxe/Expression.c create mode 100644 MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c create mode 100644 MdeModulePkg/Universal/SetupBrowserDxe/InputHandler.c create mode 100644 MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c create mode 100644 MdeModulePkg/Universal/SetupBrowserDxe/Print.c create mode 100644 MdeModulePkg/Universal/SetupBrowserDxe/Print.h create mode 100644 MdeModulePkg/Universal/SetupBrowserDxe/ProcessOptions.c create mode 100644 MdeModulePkg/Universal/SetupBrowserDxe/R8Lib.c create mode 100644 MdeModulePkg/Universal/SetupBrowserDxe/R8Lib.h create mode 100644 MdeModulePkg/Universal/SetupBrowserDxe/Setup.c create mode 100644 MdeModulePkg/Universal/SetupBrowserDxe/Setup.h create mode 100644 MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowser.msa create mode 100644 MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf create mode 100644 MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserStr.uni create mode 100644 MdeModulePkg/Universal/SetupBrowserDxe/Ui.c create mode 100644 MdeModulePkg/Universal/SetupBrowserDxe/Ui.h 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 +#include +#include + + +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 +#include +#include + +// +// 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 @@ + + + GenericBdsLib + DXE_DRIVER + e405ec31-ccaa-4dd4-83e8-0aec01703f7e + 1.0 + 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. + FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052 + + + IA32 X64 IPF EBC + false + GenericBdsLib + + + + PrintLib + + + DebugLib + + + BaseMemoryLib + + + UefiBootServicesTableLib + + + UefiLib + + + MemoryAllocationLib + + + DxeServicesTableLib + + + UefiRuntimeServicesTableLib + + + HobLib + + + BaseLib + + + DevicePathLib + + + + Ipf\BmMachine.h + R8Lib.h + x64\BmMachine.h + BdsLib.h + BdsBoot.c + Ia32\BmMachine.h + x64\ClearDr.asm + Ebc\BmMachine.h + BdsConsole.c + R8Lib.c + Ia32\ClearDr.asm + BdsMisc.c + BdsConnect.c + Performance.c + DevicePath.c + Ipf\ShadowRom.c + Performance.h + + + + + + + + gEfiDevicePathProtocolGuid + + + gEfiCpuArchProtocolGuid + + + gEfiLegacyBiosProtocolGuid + + + gEfiFirmwareVolumeProtocolGuid + + + gEfiBlockIoProtocolGuid + + + gEfiSimpleTextInProtocolGuid + + + gEfiDebugPortProtocolGuid + + + gEfiSimpleNetworkProtocolGuid + + + gEfiFormBrowserProtocolGuid + + + gEfiDevicePathToTextProtocolGuid + + + gEfiLoadedImageProtocolGuid + + + gEfiPciIoProtocolGuid + + + gEfiSimpleTextOutProtocolGuid + + + gEfiSimpleFileSystemProtocolGuid + + + + + gEfiPcAnsiGuid + + + gEfiFileInfoGuid + + + gEfiVT100Guid + + + gEfiGlobalVariableGuid + + + gEfiShellFileGuid + + + gEfiHobListGuid + + + gEfiVTUTF8Guid + + + gEfiMemoryTypeInformationGuid + + + gEfiVT100PlusGuid + + + + EFI_SPECIFICATION_VERSION 0x00020000 + EDK_RELEASE_VERSION 0x00020000 + + \ 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 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +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 @@ + + + + EdkGraphicsLib + DXE_DRIVER + 08c1a0e4-1208-47f8-a2c5-f42eabee653a + 1.0 + 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. + FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052 + + + IA32 X64 IPF EBC + false + EdkGraphicsLib + + + + EdkGraphicsLib + + + PrintLib + + + BaseLib + + + MemoryAllocationLib + + + UefiBootServicesTableLib + + + + Graphics.c + + + + + + + + gEfiOEMBadgingProtocolGuid + + + gEfiFirmwareVolumeProtocolGuid + + + gEfiConsoleControlProtocolGuid + + + gEfiUgaDrawProtocolGuid + + + gEfiGraphicsOutputProtocolGuid + + + gEfiSimpleTextOutProtocolGuid + + + + EFI_SPECIFICATION_VERSION 0x00020000 + EDK_RELEASE_VERSION 0x00020000 + + \ 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 @@ + + + UefiEfiIfrSupportLib + DXE_DRIVER + bf38668e-e231-4baa-99e4-8c0e4c35dca6 + 1.0 + 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. + FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052 + + + IA32 X64 IPF EBC + false + UefiEfiIfrSupportLib + + + + DebugLib + + + BaseMemoryLib + + + UefiRuntimeServicesTableLib + + + UefiBootServicesTableLib + + + BaseLib + + + DevicePathLib + + + MemoryAllocationLib + + + + R8Lib.c + R8Lib.h + UefiIfrString.c + UefiIfrOpCodeCreation.c + UefiIfrLibraryInternal.h + UefiIfrForm.c + UefiIfrCommon.c + + + + + + + + gEfiDevicePathProtocolGuid + + + + + gEfiGlobalVariableGuid + + + + EFI_SPECIFICATION_VERSION 0x00020000 + EDK_RELEASE_VERSION 0x00020000 + + \ 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 +// +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 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 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=32&NAME=NameStrLen&PATH=DevicePathStrLen + // | 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 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. ::= + &OFFSET=&WIDTH=* + + @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 + // + ConfigHdr = mFakeConfigHdr; + HeaderLen = StrLen (ConfigHdr); + + if (RequestElement == NULL) { + // + // RequestElement not specified, use "&OFFSET=0&WIDTH=" as + // + 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 + // + Status = HiiConfigRouting->BlockToConfig ( + HiiConfigRouting, + ConfigRequest, + Buffer, + BufferSize, + &ConfigResp, + &Progress + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (ConfigResp); + return Status; + } + + // + // Skip 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 + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 @@ + + + + BdsDxe + DXE_DRIVER + FC5C7020-1A48-4198-9BE2-EAD5ABC8CF2F + 1.0 + 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. + FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052 + + + IA32 X64 IPF EBC + false + Bds + + + + UefiDriverEntryPoint + + + PrintLib + + + DebugLib + + + BaseMemoryLib + + + EfiShellLib + + + EdkGenericPlatformBdsLib + + + UefiBootServicesTableLib + + + UefiLib + + + EdkGraphicsLib + + + MemoryAllocationLib + + + DxeServicesTableLib + + + PerformanceLib + + + ReportStatusCodeLib + + + EdkGenericBdsLib + + + EdkIfrSupportLib + + + UefiRuntimeServicesTableLib + + + HobLib + + + BaseLib + + + DevicePathLib + + + + BdsEntry.c + FrontPage.c + FrontPageStrings.uni + FrontPageVfr.Vfr + Language.c + String.c + Strings.uni + Capsules.c + MemoryTest.c + Hotkey.c + BootMaint/Bmstring.uni + BootMaint/Bm.vfr + BootMaint/BmLib.c + BootMaint/BootOption.c + BootMaint/ConsoleOption.c + BootMaint/Data.c + BootMaint/Variable.c + BootMaint/UpdatePage.c + BootMaint/BBSsupport.c + BootMaint/BootMaint.c + BootMaint/FileExplorer.c + BootMaint/FE.vfr + BootMngr/BootManager.c + BootMngr/BootManagerStrings.uni + BootMngr/BootManagerVfr.Vfr + DeviceMngr/DeviceManager.c + DeviceMngr/DeviceManagerStrings.uni + DeviceMngr/DeviceManagerVfr.Vfr + Bds.dxs + DeviceMngr/DeviceManager.h + BootMaint/FormGuid.h + String.h + BootMaint/BootMaint.h + BootMngr/BootManager.h + BootMaint/BBSsupport.h + Hotkey.h + Bds.h + Language.h + FrontPage.h + EdkILib.c + + + DeviceMngr/PlatOverMngr/PlatOverMngr.c + DeviceMngr/PlatOverMngr/PlatOverMngr.dxs + DeviceMngr/PlatOverMngr/PlatOverMngr.h + DeviceMngr/PlatOverMngr/Vfr.vfr + DeviceMngr/PlatOverMngr/VfrStrings.uni + DeviceMngr/SetOptions/GetInfo.c + DeviceMngr/SetOptions/GetInfo.h + DeviceMngr/SetOptions/SetOptions.c + DeviceMngr/SetOptions/SetOptions.h + DeviceMngr/SetOptions/Vfr.vfr + DeviceMngr/SetOptions/VfrStrings.uni + HwErrRecSupport.c + HwErrRecSupport.h + + + + + + + + + gEfiDevicePathProtocolGuid + + + gEfiSerialIoProtocolGuid + + + gEfiFormBrowser2ProtocolGuid + + + gEfiHiiConfigAccessProtocolGuid + + + gEfiHiiConfigRoutingProtocolGuid + + + gEfiSimpleTextInputExProtocolGuid + + + gEfiGraphicsOutputProtocolGuid + + + gEfiBlockIoProtocolGuid + + + gEfiUgaDrawProtocolGuid + + + gEfiHiiDatabaseProtocolGuid + + + gEfiConsoleControlProtocolGuid + + + gEfiLegacyBiosProtocolGuid + + + gEfiGenericMemTestProtocolGuid + + + gEfiDataHubProtocolGuid + + + gEfiBdsArchProtocolGuid + + + gEfiCpuIoProtocolGuid + + + gEfiLoadFileProtocolGuid + + + gEfiSimpleFileSystemProtocolGuid + + + gEfiHiiStringProtocolGuid + + + + + gEfiFlashMapHobGuid + + + gTerminalDriverGuid + + + gEfiFileInfoGuid + + + gEfiFileSystemVolumeLabelInfoIdGuid + + + gEfiBootStateGuid + + + gEfiHobListGuid + + + gEfiGenericVariableGuid + + + gEfiGlobalVariableGuid + + + + EFI_SPECIFICATION_VERSION 0x00020000 + EDK_RELEASE_VERSION 0x00020000 + + BdsInitialize + + + 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 new file mode 100644 index 0000000000000000000000000000000000000000..a332fb6ea3b7139310705bb9994dc7bcbab2c540 GIT binary patch literal 37774 zcmdU2+in{<66Ny%^AAGiWoLGrtaEb`U?1dbgz*iQoMfI1-;yyVu>;A@P_Dl9J zcJ~~XX|h{Qv6`}nZ5UQ}OWkDEVO6nMEVBRi-$&+=>6u^5-|_dO`2kmtZjL>(VlK>Q z^WBWinfYM;FqgRZZ|2zijN@bT5BxpF*}~1$lKB82(p5g2xN^?B3l(BvKBYr!^*}0{F<+}3u^vQJ%UvPeg5)RD~ zK3VIPrGjO9N~Eq&mTFfDDI>jSH)xQj3-dmBZrKdYDy}yxw0K&-S}cz7N$RTHo`D*c zNHhd5)-}O3xjq7&t`&%?;7a=6;}>ZQQvD5g)v2l?BWQldT}PJx_uxS=AWfG6vXq-k zw8bkcU6d$6m-mk?)(`RQ7%lV&6olwc@XZluKY@%@e|d;f{=mP(#2v}cYqJKbcFmsI zF&p^on=M=qfN2k?@;Jh`1G8-QakgfW-Z$GguHk!Mf^UTZ z$Gv>=cN~AiFQlA$w{~5NaIt3I-IU`?9{`J8$QA2cgFMu~?fl{%Jw)}*% zR}FVkdXDg`lP&7lLul-Kw52Q09Z4};l2S;Cy^NMPwD&lTrM|s~Oq}E2$?XL7Qrf6# z%Q#-(7t&3Q6w7mt^K&a%Js{5KC_R_31Wg?8p^h*3eS&}LW)CeT8pAriH&VI)iTow7 zmBJbAfmj-1GX&Co93KGd31s!q{QF-IEHZ-1Kg~}!S3iM5c~&^)^F7dYj(YZOyR#IQ zO-?3|eJQE=Ikv!pS-0}^07qheZvKN$KI>`t30Gnlglf@@1GM@+WMtDEpk~pPZD^9v z6#w+JT%o29puWlhk>EeMkC&43OH<7u24T%{o~dE99BuxZY7SeCHE&zpT`R_Uwf-3Y z>(>5kq0P4-wX`Y+*6xfT2XRz1{HJx4x=Wp<%#4fSlt*V8&t)LH11zacYdG%1F2t~H zhvyEginofTG|S`GL{Bb0?8P^MR8<=__(%_ShCYJc$poLYa;NC2*k8H+f__MO?DA<% z&CO|u$mmn@w1zV-#u?_+Kr<}ddwWFHTz7Oc3VYD zaOB1Qs%yCGX-nfqPy3zqiM*AFNxTNPx9FK9dLhvWN-{@Ev==g_I|rf?)o@m>l*P!W zHI1uBa|NT=jk)D<1tU!vm)7NR3~Wn!>srdvn9)yq1EkWuRJ(pE?wgd7Jl9vHC~J>d zOn2M%?GIrWq{ph#DE(0NyU+tIjp%%I>+w$aGCCQp+Vbw<+KxUwerc?+6>iBib zHqNFljh*jPe6Jnzax{JQ(E2x_ce8!dH@~s{_7$#6X>=Rv^0159N)2|^vE{T+BeOB= zvl-E*cV7y}TuRfJQuemcPaGfy!5N%+eQwv{BOu1P4#qY(OV)!|KrgZj(wL?#2e+6c z>TF=Og%2%eoOPA)TjV<8ZI%lab z?1-@|5jhQ2IauAMtX5;fG9&MC>|$iDJ;i#AHFG^V@;HEWe!kXr`g81&m|4M@QHgSJ z9=KHhRF~5>)V9SoF1y4?z6b&LOSC!qO@*7m7I~ZXSd-x3sT6FU5L{U*9RluYoqPT!odG zm_P3c&h4nyW4&^xShMs6=*kX!k^3RfdW!WJb2Q7*!z`?r28|%l&GSX-uC#;8f9u^Id{A!e3g>r+n_p)HS?f3!elNTv*}{NM6{u-J^E%$9QLDK&Pb zF6&i0C{g&XMg{e>w!w9l^y+b~_ToB}U%|4xz`DI}Sikqot{Pgj>-fHzC-9HCiio*q z$5RuF`EK{+mVvw7!ePTKYgYT#4u8{t|KW&p^NQsLT1S?da6wnU;JVo|F=Y z872P{kaM0kN48h6)q6NHkCIZoYR?Zb>g77HiT#eYkx||7JL1piF4v0DXP1?wBa|{m z9UL2TMtFo@xr(u*j&z0lblcbS>zLogHAPL@rRh)7S!`VO$JKli$ymo3b81Vq)_nA~ z$M-eHxm*+4gz;VA%NRKI-J&p9keKMd>9C5l@(wWDU;M{DbBkds;58=RUSp z$*)){CCl^EoW{9sFXAZc`id&ee)g`uimBUJ=h7X+n`?Zz+Ouz?GmI`f`3_@X^>d9} z_wAg&#F*V`JD0z-fF74on^N+tr!9utYuHt;-@JX?=&!KH;%fUIymH19iQ;p3>d)Yx zKg0P1zaHaT+FS8rcptOY_$=4zoZDx<;+kFzeV_38@J@G+>nGis`aeVy3~$Bjoc9udJqo5qbYxnBP^( z4$V(<4ChTmZ|I*?=QR%S4QFM!BL#ON2{Gom24}wm4>L3bTaI7D>?7`S!JTJH;o6?Y z931KM)e)3y4UPlYXg3Q$tQ>~j@$%YI*cQV+@M8p>YtyH3)L^)YUhWW*SIv6mI#=ct z$}06zGN`AmEp9Tm#=VFR5Zze2p2>6w&Vw6Q0E=J2H3cQ}GGpk)D2!n^ge*|L=&5lu z%(G zk89Fp)~l;%=Fu6$)6I-a=C$7y#>-*TnFddZi^{%x;o5-EqKC7IrKB^D&J><5(?Eyl zJa|^;g}RJriqaIOZpQoeF%4(9Q&cwTL;iP7EnnYR#z|-!DpOecnN~BJ@Fb!R zucl)ThHeg%d-KRFX8E34u!~Wa!fe$d)rZtATQ7Wg>zKJYUgkE_^L851)F%1gHMM3+ zTVs@^Fk`fad$^74Uau*dno zJLk|WWg6L9LwUpX$!r*0LO{mtN!#`(ToBuR2uvAzAs`cma|2)FI zZcO#mW}B9?gw^_U_+Off|0jjzzgm9||1aj^|8e17pjv+p|1am{pMF3&`Ion}xcYPW zXMT9T{aY-o|JC~Q_>Xym8vDOk*#1}R&*MMl32OK+>j#Im=kXr%05!ZnDXRHl?RmV% zJU zB;3`U!*k4o(eb=gjAvJK4$m>qMaT1tVm!N=Q#{Mu$SfTWJq(Q<+qQG)vLQF*RY2meVI~yShapF|8d=J%l{7YNl%J#AJ(qrJ+9+zdFLD0#@G$2RNGhU*YY15 zp@iJ)?A;I<+1wASoc7l#NMSHN=Q+z3YV6+*biW+`VeL7*$L*k=cjk{v_AcMs$u*)M z@fNvKIw6S6qA3TbxV_ZiG%{b&OO`?;tUbj$b0(PEG)pVIozU>Ui~J$UCLbavqZ9^B zROqpYYe_pS-XP=Rz>c=vc-udJ8)r@JQIGOW)1b#8t_7a@CK~Foo{)wE$lE6J!iL3U zV-_`fY&2el9vklcwvJhVQu-p8RH=wz;oiDEip+R;*$B@xSa9{q1pk*Pd5CPt3C{S= zy;7*mrYDAv-`mgcN$TEa5F%1N*WlB<+b6w3u1+q$FHSr9V)*&>!hAP3^C`J=x$K5g z#Vowi;OAH7uEUS#emFgpTz21+G)*};#a9it!>Rg41@$d%Kg4t{7h44sws84PdvT$Z*!+<+Y^x28S;6 zxq8~#;TE@uB7Yj(hIaosw_EW9(s=|Oy|Dg@w~e%k;af3Q?fxQsF9i1);U4`wa)h#l z{{h;S*Yt>&?V0Qo)q|$c6XHm+WX!2N&u!az9d?;^dbd$qH0|tVF!U4r+f7PYVI5s< z@uF4c8)3Mk)bwrxxp=vEez5OyZ-VI(ZgKkB;zx~kZwZ<1%X0B!sa)4Yf2&KlP1DsD zuh8<{9$sOoUBYXcuC{nd&oGUYzTaxH8?MwYtjcajUt9d-y)AFiC+wNupi|YqT>b1u z@7#o36J;^XR$=kEW5qK1Oh$o2Pt)y&G=P^?r+Rz7=n4?fO^ zo!VW7_{I+IoyT!2;{viXA9r$=efK`%$cUaBqcPUU-TGv&XYT4ppIV-xKg~GuG4_6P Hwe$FYJWtCr literal 0 HcmV?d00001 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 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 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 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 new file mode 100644 index 0000000000000000000000000000000000000000..99b0cdf55124acc6943ae8abeb34462fc50234de GIT binary patch literal 3470 zcmc(h+iuf95QgU(iFYvRMWHkeLP$uJxJYPPBHAQsS^-y4b7~`U0NV}ZF%S>QTL9m` z8^=!MHtAJm*?XFu`RCu6S^xW6vXTY1XD@l4+7m{lWgFOgo7y*RW_{&}MvlcEH>P z_J_;{XbaJD?KF-VU!k!_8za$o<1QGdHbzowbM{S;510`K=^fG=p)K)QT0*yb#9Ei$ z#37L0M89_T78YjohiJI64qsWlbtt4eMdEFZ9qL4jkO}W_$%cHI+90#9Vl6vje7b@q z#rnf>(d8?2tKJSlBaLFi^CepmV|m>HXL1T+)$=O+16KT52=z~-)={l82wCY=+ zm0oEr&{o`7qx~hez&^1qTn%SY<1&_ntj>H5tp8+G}vpB(7xhh`dU8OWJ_-DSRsy6cu&Oa!l_qM^e$#;$#(9 z%C880GvX-BkuAG(l&s=4-b!EKvTfkBuV#y4O?g&9BElc#VT@(Xsv;yk)sQ&X%X3y{ zXpVT5j{&FSvqU=Px%i4i;ohP?dcNM-j`LNc9fv|Zs75H8^(fMdoVre+0Owj)Bu7MV z!R^i8Cl-r#>>{E-E8Zsdhp+bfo!)Aa*}lU0*lxqjndz%Isbg1hz4=M8++yh(^s64o zhYEa6VO5bLOkOTrVA^csArg6bvdnD8vjbacgeqQ@`)yYvPKlg0+%|Yr2R3t*hbMc& z!t?7{dSm>iAH!Ba%-=Y+Jg2IGNfq{)t33Azyu2b;8K_+G`c#eAceSWXi3QbcWr>fC zhp@a^HqY<%bCBP<=T*}Kljm8VH8--|93SMls-4)^j;V|Aq0^%KL@{`m=c&C2nb2{X zMB-g1uZ+;$`miUDf%TJ5&;7B^K-sEzNh(Wz>{k{M-==NCzQ0>GRf}yHNNYnQ6RWBe z;_CL%V$LEt^+-`avE8@zq_zfKT>kL4&OHcpZJ{vXn-J#T< rrABGS`v2h6k8s74yR!F`8%;I5y{P13`~SPXi*y379q9(LSW literal 0 HcmV?d00001 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 new file mode 100644 index 0000000000000000000000000000000000000000..99beee4c6518fa282a4079d08077e1a515e52d20 GIT binary patch literal 3768 zcmbW4+fLg+5QgWvQs2RXo0f8@s!ElRdJ!PB5s*X>puLJn!XW|@WCtiO-}d`w2c%xna= z7%rF2@s{x!97nV>D9(L61mo0hq14(F`zFvw%m{<{j_KXNEj_ci#J>B6wIRKUBM{$| zzjlx25+3M};c#XHzLI+HD8xHM5@g*v>XeI+3GaBJ4V`If7rA{~c4Rw@_X}7utdFjX zAzz^@o^}ixag;WKz9cJQtWyubnOZ?w4SE&+3s!+FrO&;|(d+E17nfPI9I6<5~ba>YN@N!sc>->nI% zt{qy(zVU6?0pk`rjnJyv9eAAxy%I$IuL z+364G=SkqJIE}Dch#v8MDn+-3cdpFyX3*nTTlSM`w2USt^>U6`T8oe}Vb`%+bO~E% zT^^p`)l0d(Y21eV6+E}^o_c}}<&}L-C2wfp>#}^`y`_hZ6$SZUhU9*3r6LY_^K1GF zxRw{W2n$YYB5H%C zN9-%ktLv!>qBdw|_UOJ}S5L|xUC&E(ELR1U>VP{kiEffQmQ$wdlSw=H^dUQ|;i`g2 zxh+%)Fm{s={|bxR~6gXD>~)n2;Ny#rcz$dSTAAg zdj+viRFq+?g6+uTF;uE~jJhe)%<(@MyI7!AimHgT3dX>zj)ru@l{B+b%nb+dlTqo6c7&R38nI2TJf~p%k*kf{+5Q*8mm|{y>$0By~^xS Nq1MSsRlGKM%wHn0D^UOd literal 0 HcmV?d00001 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 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 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 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 new file mode 100644 index 0000000000000000000000000000000000000000..b22fa5aa2ad9c12a18ee8185f4d75472454228ba GIT binary patch literal 10190 zcmds--A)@v6vyYfQr}@kRHaEvNJ!c=k$Pc+Nv#?iVe--3ST;7`7EEh9r1YWkOucJ( ziMIdW9FKR`Ud-AgGC~&nHM3{V`JeAu{`+^$t+~kEci-surTap6YvXg|Hr%QE-JQF> z>$*dCLpevXcqJ0 z6$bvU;|8M8cV{}b-2*+_)B0UKjYO?4DuwAyIzK(F0mbNQypa>d<7i$f4kJK&k8MFYZ zhAaFZXvA~@*MDl(Bv)x<49#=RYI*q&B!gi9Ps0SV*v(M7c(I4nZOT4#bW9g9xqH?6afJrzb&rhx-u6Eq6tGO3C7TmV(%fd7gs+{-qwCsxR zrLIaI>6fmmb4kx*3b7W-vg49w)IH^zt|C$8xS}(3p}L}T(cg3T?U=X7z1BE<)%=Rw z7qk+bRrS0qs?ezU)pvCV?>uA8JC|p()g+H#ul)Os&sjxtLGUrv7Wj#i(TPg1JOH^9rZKj7Q7yri@gqW z(Tlvd9eC<#Z^72^v!Z4UBoBT#)XF?1B7`eq$S_mNU5%WH@<4z1V=B@bl1EB@W=_ds#gZF!4W(HY!& z?jId_*WR>MgJ)ZWGuv+XH?f#K*APAh`9Von*wLP}kAGzSVqV^9r9*L_mH-*x1;mIC zJEK{~PZq_+pJnlqL}fNFcZ5=Gnb;{le;F|Y`^T@>Pal|ZIibs32TzG;a*A3 zT`#d^X_NW($xHsPdRZH)!W%xOZz;y*m-n@g;^ZnaDRnyaGS#6yu{yx2_(#6he<&-0 z{soMPNi+~SUqD>eH>LcZFg68)7Km-80!s? zCUQxM3%cLZXiFnq_lGdL&=YzKW==~xU+$q|OzV=`^o8mX(`Fvqt*H)NR{kk^J6a?Q zr6qr~kQJ{>13S_%^+;EmIdLEK+2$P(y@EWSN<&ouf>J2}fj`*TWj9o;-$NH=wlzU?g0ITMZ88|kZ? z1o5}}TbD+jNF(37r}D#R(j_|qc4Tj@s`-{n>v|e%)*>AFhX`%^Muc6mitw1lZx$z$eQ&%kOJpI&u)h;_ zRo?5$b``0ys1q5DcSr}R*gy1EMb=7U%xtW!rQ@lmZF?Q*EV!%~wjr6=-z2Ky36ltz z-0Ytd37VS44CY$avwT8Mw_F_wp|t!|nN3+6BS*Sor_^d%^NfJQh5Yg23OlIyYV(D> zBJ2sV%gBz<#x*^I=oe&X=bD=1P+Z$S((<%(Bs6WG4;>Y~0^5oQnI%$)H30~wRphyBoa#=a=^y*J`#u`N=8 zEl*R#hOW3F&coHQy0bJI^j=6x<$J7aW;e&U*a#kCh{XDi5n)d3Y1y6_x?0vSG%mA_ zqVh~le#1^0U7Y#UuGX0K%VQmMRm8f`ZJQT`C_jt({9{@COy`?)~iL%2t6UFv`1OSGRCxqLe++(mbd27 z8DE?7*n1wGrLm^2Ba5;R)AJsFQ*1vQ!@J6va7;}@yoU4ZBRTB}d63LogUx6CH&-K9 z)m)2t#rzuO3(+g};Cvm_3;q7v|C(-;ddSYN+brTj{6ktK(b{x*4iK@><+MPWDBStc@@CUn%EN!%{y| zFY`YE7KwxPe42BX4Nlfc74NS>2J6T|#%+x=ZdQ*+U()uu52>eR0*~4Gg}si7ethw> z|8S}5JHl16XGuja3;(rnbH8nG%NpzcTOV@fl{$~S+p;XI5BuW(#_B%L+ugD(>uR3< E2dUe4O#lD@ literal 0 HcmV?d00001 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 new file mode 100644 index 0000000000000000000000000000000000000000..c83bb8a991326530132fe0fff78d02de9e2b0035 GIT binary patch literal 7496 zcmc(k?M@p<7=`C|rQX99ROO=qs;W|@Nc~~3om$1%!q6saDhse7R=}oSL&_DmzKOQy znb*V4nq6bmNUN3iV|I4tyyyL#@xTAmK&?*&|T`D5vCf0^NCtVx*JC`)YOZ9*$k?Ox>-{1GlZVBh5cjYogJn8s)-|c%|nPjX2PCrXEB8d?t(&ccq@ZyVG}L^-t6S z2F4xf?oy)#nHgp3zrNJFGu@3n0>%yF^Yvgc!>#T|8sWs9>ddS+9tC4(NNlbvk2;J3 zGVqS>*+8a=JCDBGbv;+t^L`FXhV_%@;!J1I<)s}74I{#a@x@%Jo{{=gID-~o)p!N} zx!#yAK>eqBEu+daV{G23*QuBPTrwC3V46kDVmCAC;z{dgb&oA^zv?}>I(|l;YnlmU z2WoF=RL1D|*$?#ucG{TpNWJL8tk$ckzI^#k*PrzU~a7 zIqUMPz+1Q`dOs20*aB8@AYESR?sY*=tfwc+XS?c=N*?@hrkQCaB7{3)$gEJxL%q4x$fAV%QL99a66w2lTg#5wP=ju(_6%buJAT?f9cG( z_NC1lJli6i*>>Ms1-5-C4c4UZzV4f9?F$M1v9H4r#^(&njb^$K`n&|l@S8@l_&(K@ zD2nAVHr7A{CW`#Nz!;DI|L=?N#Y`DKtidwRAF^YjwAnINY7u$tC9_y=*aO~8v71>m z5)mu9+cV@GfLYFQ;!5#HD$%J|$Dz6(ilCQHQ1Cpw77HQ8lAx@z91 zzbiuekXdk%l|Yy3Zkf?N>7P7mmJ_2bA?Fz}n z=a*DysUxh~2z+*wKSC}{RoA=_yGS>Y4CH-$)U26^!dS$XP-QgTFO}-z>Cz=$KJyN$ zki2)8H^dqw?&C4U;TxS}iOckvc}7!gx5TF9*VPuejy{9dz+tsls0=L{uAbqkZ;KEu z`-3qFF6tXRqvk8s5Z8+%Nybo5d12327I3thry@Md7N0THlfI}5hdR(J*1V-(RZPWJ zl_;Lhg%6(`<#3hR6x?7<$Fe43E|H+EHmjzH6I4S7YN2`y$2yGF#m%{_iE0NsKb0;m z(h@Jo8q_MGLin`EC86RCy^UXDVRa0fEv9028MXN}Sc8>XOI>|Ub|kme7I||ZK3Mw% zS<19RwBGYoXRO}9jzFeuuclq&SN7#?R^oBW&ch*moNc40S~LI)gDgeO}*cj zS5v#Mt`P$6B1Fp`-q5;?O1Lf^&GaK*Rpry=SjsGBU)E9+c2+EJKC8uqoQ)4&RLV*m z=|cX@v{c57t@DUqeR0D&uq~$I8Yoyvd|l6CLd|R3u%fe7l2z_m&dApj+sb6ymD$#% zd#30Da`t3c=@Hdf(_2M1SCpFT*&-P-gxD5K7t2t_eAj1<=7RIS&ns=8W2i`vO00Ap z=DQwwSc$S*GStsjmsF9&5hCw%A?PWR(l*gKbsy#9*Q!RV^z6Cf9Xmy^jyBj4vYi03 zobi4o9U#%jYbln5{XX_~kcRAPtF9nXnJ&obZLbN|Sgc;rKwnzNGi(Rup+?rx#n(cT z-(gF&vVwnfQl=Zr>mBW}RHX@U8`qZKml?NrL6*P0jj>{5ZgHHKjtZ``CsO_@AYQ8b`9?p>v#cm>z%iGY8vy0U_0yi!Fy@& zz2b6JdSEq=&(5R+^Ni2w7kTN*q7?a=-L$tpHU({wL2M6sSu^&$j(*ybEXxq)E7=}7 z|1exD8rVM=1NT*BS}5k6%u8;Vdkygq$Bp+EayU}l`e+nTm$BQ^{u)uAOpwJK;y=6j z@%k?2c^!6pxrk3?O-0W?7M7i`sCf6pTip||hX{{t82(TrWos2fJ(OhN z4*4UWIaWs?_~-u#a&NX<5%0mp+=u)1bik@*D#qirHvb5PRd#heKa-|29D%pub+i48 JW?0#U{|_+@3XT8( literal 0 HcmV?d00001 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 -#include +//#include #include #include #include @@ -32,10 +32,17 @@ Revision History #include #include #include -#include +//#include #include #include #include +#include +#include + +#include + +#include +#include 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 @@ -306,11 +313,6 @@ GraphicsConsoleConOutEnableCursor ( IN BOOLEAN Visible ); -EFI_STATUS -EfiLocateHiiProtocol ( - VOID - ); - EFI_STATUS EFIAPI GraphicsConsoleControllerDriverSupported ( @@ -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 @@ gEfiGraphicsOutputProtocolGuid - - gEfiHiiProtocolGuid - gEfiSimpleTextOutProtocolGuid 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 + 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 + 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 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 + 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 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 + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +#include "NVDataStruc.h" + +// +// This is the generated 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 @@ + + + DriverSample + DXE_DRIVER + FE3542FE-C1D3-4EF8-657C-8048606FF671 + 1.0 + 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. + FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052 + + + IA32 X64 IPF EBC + false + DriverSample + + + + DebugLib + + + BaseMemoryLib + + + UefiRuntimeServicesTableLib + + + UefiDriverEntryPoint + + + UefiBootServicesTableLib + + + MemoryAllocationLib + + + + DriverSample.h + VfrStrings.uni + NVDataStruc.h + inventorystrings.uni + DriverSample.c + DriverSample.dxs + + + + + + + + gEfiHiiDatabaseProtocolGuid + + + gEfiFormBrowser2ProtocolGuid + + + gEfiHiiConfigAccessProtocolGuid + + + gEfiHiiConfigRoutingProtocolGuid + + + gEfiHiiStringProtocolGuid + + + + EFI_SPECIFICATION_VERSION 0x00020000 + EDK_RELEASE_VERSION 0x00020000 + + DriverSampleInit + + + \ 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 new file mode 100644 index 0000000000000000000000000000000000000000..fb72d1a2bc8d75b1d239225961f9392e744c4aaa GIT binary patch literal 37386 zcmeI5*=`)i6^8pZ0rCzL=^~03(Gukq2n>oGNkmAB&`@#&7!bHgrp-m>P?G64^ket| zbP?n}$^X@v!|I;t?&?{{CS_tkPESvF^{KzkUZ-mQ_usi}F6(3;WgqMHm+a5kpY(Yy z9N9OE*-`d7JI#)>z3f%?Lw2I8Z)Mxr-}Qbs`%JGdvrlxqoE_@B-E3dS+;gnE_`j*M zdpbJQ`HOzhAM3?}=z_A?i+=dDoApKWarRdKce2|$x1m1n>1;>zAB*l+p$`Z8ys19y z=>0@j?1s@8(3O05s{0OgeMe{LHSO-{Xg{8VefP6owxrK11zJXX z7pZ?25Z%^)=q+NlC;E5>m>TLly|2$;w2~9%qR3)(^sVaJGI2~ z9|zhx*>`I1N$A6x&M)ivJneCy^NBvuOU^;vhOXrr=(DRH=vwG}uJ?cH8~O-c-N93= zzuoL#XYIt+mxbE8B$j6`1ua+An@D{;S`~lq1bIX9)+8?nl7Vl|Y(%`0R-Z{Wk43Xd zF#52sC%z45|g?RL(dVAST@>;!H1Qaa*Lf373?dOnhkp6dlVUk@~3 zPZXc156GNdf#&1f?c7r$RZsNY+n|Zuc0CH8PD1Oa6;ysIN&iSvPdolMm;EEVdG_h1 z=t0}Q8qnX-a}IUa(=f{LU^je=_UcPV+z5A$-UY^=W)A}IaMy!?-=Pph_xA_)ISn^; zCXNT#AT=*^7u>h1Be-ru@9^A)I0dPzdPQp9=xMLigJLgkNOG{8?*hV%#fGkd0;mIZ zxE2f;z1;z=RZpAjd>M^-%qF985*%Ly4YVTp8}3ONjd^akA>7<5nr+-v8+~Dj$6=Oz zM@a7l?**Lmme%fg6Yw^#1`Zt2HrM6* zys4*y99~rPORYDLM3Z@0d92Y8?peIkeTK>RLfVcOq?3!U@AX{#HIsmRAMH$HAstHhl4yEVjh%o)^AL ziY3-00ju))78_$+CTT^l#k9bZbOHQupt0UQ>qC3ek7lZ(2??_t4qO_&?sC5D$y>iK z@5eo5yk_FA4Lzay)fBhBCQ*SyA=tz7Za%oQKdr?X@<|v^tt8u$K z6>h{oL^{>jPx4LKcoi**Kex(4EJ`mvm0Wp_Voe#0G$m!vEt4;6-8gqwBVxWWUUfTY znAE4J8V9R7t}q8# zvd&;-X%oNOG=X1pD*ByfVqUCVY|XOoZRv|LZrD^0-weD;<}oaS@2gkD_3#eo=m}QH zKH*`KfA_16-?ze9nuf8*&1$1P=1rpN8> zCDN^BxH)~z^sD1GU(0Qbh-bB{GQws0)yI_k=Px;KPTzRA-J2S>o^%B{OZ0j_SRuC@ zi;7do5&R^5exw=D%cI51`0n0BdhYY7@p~9F|EavIqTRh(=zTsBdS6V9UN=}+uOhfw zn0=AJ?7n#7vHWd(@F&U)Fn^k|t4%arPrev6AN$G?9O-ouDkbm=FSmq#IRRcNd)frA zmEZ@F7rt6}eU-p#G0gidYOel;diGfPp(b%&+LA6v=i}+)9b-W)maqtg8XL0-#3t=o zg-9dxF~Y=8(^ZIt(wD2jZpM^5>=3!)ion`*Ig>I}PG zweU*MCqkzBH;El4`RS_TOduTH{&$%pY6h73aY^Ay0eFF;~e(R_T*9 z%|)$-D92`dt2J}plBV^^BUy-d(r;LBJQTCo9p!P!b-V4zw>kZB8C6Bgy{H<515wbC zUqhDr$8c;m6K@KuxN}BbQ_PsjqfWQplP{yLXxUPjvBIJkXnd`87VX%yrU;Hw+7!(^ z2UbVk&C$dMGSBrx=0R%27vu>sGq9oxj&fdXj#`!6-cmk<=xj%lb0}O-uK*`jQQVXx zSA{HkazV(JGG$noHAuT|U=gRomtxV^>|rGQ-Vh*CRILZMA`96tJ~k=k2k^ z&*FP*vF8tnY&WD~SXu8lDnGyPVH@l}#*8YmFJ<0y2d&sX)g~OfXKO)V< zuqNf`P>alMJ~=)&#$JvT85SxmEgI)ai%YD2pxt~3$eSnSd5t({pU-)~F`dlD+VG)w zmRqnqAoK3nm%Nu|c^1o9P+w|UDSML5gIVP%T*WA?3ngaL!G8P9>ofZDzF+kEjQSJh zQ8y;iuT`gKuq`k~v&JK5LQUaGtte4sy~m0VW@-qY*5L3PUu%^X@x&aMVl zm5|TBnM9_guP03N^~-(vlcx2FlJNeSD}N{bZ!4>)^In#ZO}>@L%V+f3S_d>df9i1s zaU;I6&DS0bRsj+Zeybj&dQlZCjE=%6=A*iB)}zo?{N$?HaVHt z{&2p88i;t0=PvyDquL-MW!RuO=z-OJSnF%rLB#iYu`>~YB2{*mqv5f89Qj!sm2ppT zrl~9BEHh-*1{BaHtQPSYoSKpM!q{^mwytkDn?e4fC^M|EGp(A}PF9;?=pLQrEUKjD zp)A0L{^D*Q^_dDot*qb0IjruPR`>O(aJARv&jS0{Mj185QFtcIPXkB8)nH@0iy&Q* zs^%EgN0ZZGw{+OWEy-J;N4t%#LEVbDHfmHp-J}Oox4@gW%g>udSvNZ^GgN ze1G!nwj&POxL8r!4&J{FsPmZ&s#>cmJM*;1id8HNd3N_Zs&qnr1lEN|k>H)C$g{3U8O!5BY`Gq3awt08x?w)Ptu_K}z!Y=SnP4i&fT8O5r}*GaTj zLq$Y>#eMZWejI@`+GvMjWb5-Hqxi%5?Qr#ER910r8J6jYD~)Bj?m$~0QO2)6Bias* z<5M^ehWQ*oxot~h*ejrw%1=a2pT$ubbwzJ{lsd+>DhD(UcFuq0xY4^Z>WbdfIHQ}+ z{mcT<*hU%kMQq2XeiH0`Wi0Oso0W zd7_LXn(*^oNgO@_Qa6ez=e?#Rzk>vRCixz;@MXe%R=uejnjI><}S>CaX=lH-E{_Fy4T=($y>ixTOzb-pH$JRrLO zShknE=k3<&8;5;)%j=h~dovy*ZY4`hotNbmG=A)`5t z-yKo1-x6t0JFzl@>V!!>f&3~8YD3!@ky%JMNKh*@sf>e!Nq5Ad$`6d=&rZ#(2C_)C z-a?gWy8669lemkhg`KpBdnU6`kq15xcIoQ!0CPr$2D3nu#WKzZc`VX=z^}E~Ox{w` zQ#lVlAd<4^i8%X@#Rv4=_r52-i_z^x@PPe76!knDy--G}s~vkqcG7Y`S5qd&>%%0tm&w8T;ohzsG}A+Mm>21w1}2f(N)9epABrM0vG$nZz}*d&9W<%#>N`zE;ZE{s%6JZPkM}(-%#t zuj2U>_T{tt7lpl7bWfw1NAE48eiB`s!rrN`!rp!j__-n>@*&N*esViF%=h-I;8p{8 za>cm58SRtdUe56sg}d|2DA!JNW>y?ukGs=eg*%x);v0S&n&`jTd~g}xHPbZ}Ze*5zIDizjhKU#iXVzAvMo=-Z4^Fdhcg+-Q`R zQBc&^kpj0EYNjjpZcUMdg;_PvSvp`F>EHVijFg_%Oq1yGQ2N z@uV06>_%@B(qO6P8jb9$bno-3bnsa)w(~12KR!80-y8@A; zt=nNU{xVnmjqO>W>2%cVjreqYS17O*)Abaj$I_pkM`035%JaFAx-=!rp=zL`3fCpQ zCZS<^FP7Cd3&NMRM~f3uF|T{;UTGxO<)3yZLf~HQlbgu)Q~5>r2hXmPhGzr4vZi-x UCF^<|zf1RhRXH5fDaHZ+2ejmb$p8QV literal 0 HcmV?d00001 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 new file mode 100644 index 0000000000000000000000000000000000000000..8d944564d7164c2c067509cc70d73aa41f28a941 GIT binary patch literal 8438 zcmd^^+fo}x5Qh6YRe6UkxJjIVI2fC_Di<6?tg$=(LaBetYncrvmdy=wQs1E24!R$*0IlaWnF9A zv3;~YeZR9q`<`;i7Pwy8k33iGjCV(N!n3~V@|EuUw6=LVqy4e3SewY!z$Ijf7Co;W zSr5!zyWrlmdDTWX2G%utkGi-!0C{XZnwu~? z(x}CoFr(7r3%$}fN4W}faz(ELXQYKzffZrW*P~a0UKZbHhF`f~$QJ_t`o8P4F^{Y+ z^Il5LPmh)ZbZOdL>dib-KJptK^ZsfH`umglc#;zI4SQ{6SgPBOZQC#0*Q`ptf(=Gk zp~?oW6LYxi*A{(+^8@7@-bhE`DqoKh z^ex-3138KG3ar)fSdF>qQSK&f67-Pxu8dnU&vjry%y_~Xg`c>4o`n}ojoNh$otu5{YkZ1##FRDzQ!CmQ*&5| zW^0D|(L2Si9uZ>3zsr8pLaRC3a?6>a6klgBrnuj`{wf}SmX?HnF(;4t4NhvdN4ez| zSmjBU*PxW$HLw4mDc)cIn)I;=NV_vIb>S#q5xWG$&zxLbeP% z2aVICeqB8e^Du+LT!lI1hz>Y|&6MFydHpX(9c)awqRVyUbJQ8k&!h}1CcVWY^YqF? zD{qQzL};}}5%X)rs13^T7?)Re(JHoR`Ac>N6jO#Xwt5{hYv*pU@~SN)bm8jK*$|FV z$?CJuIFh6Fpw?ZX-b2b~E-|dUtrd*c1!6ULd{{GyPpx!fTh8ODcv~LBX?ys;F+6UR zSiB=XgjvaBIBmm|+3sG-b~mw?KELV4i#m4O_H3xwCVw1`4qCVTNu-bm#Ypesd5_4j zLnIEFU$Iyjy@Bk!YaE`l-kQyAflcM~i2d9W8EnCpxrhDT($rYKKkSq8ep`f&hO+q0 zSulz751Ad^Y*)E zs)%*caORYkykOn9jDO7A%GA7LQiMf0TrSLE-EBYY{IeV`!k(gyI9#3@i<4t4%H#9G zJZ{{&Mv^^7wg{Iczb{a$vXd%JasBkQh>LQ(Qkdhs{F-iCcCS}F(CJ{u*SFeVDjJ8~ z(6pj)8fjjAT=Ye`fAPTFzd?S(cM3ZHJS7+E+-{4tlJ>AqoB46D7v=rsBk-;@qfVaN zzSsLNv3@)9qMWZjDCZ4!^>yO+E~j-mB~S(x|DUk?b1XlsC0p#QJH(ylleYb0x)hz4 zpB{8x7Fn&Va{4O!*EwEtMwb_Fi?`+N>(VC_<4C_5Z&7}=%E*qKhc~_7&wiC{(TaMG zl}m{1b-bYRq;30Vyv6xld_aCH>>hRQc4B`p$|`KH*mGvI%zE)D=g+%w7w0=~hd7Qs z>+DDWUFw`u|JrO&>g-tO;a}W>=cmT$_}K2^O_ot-)%C&u9|-@o)%Yha>$_?hhqr0j KSr|9|SL9y>1t|ys literal 0 HcmV?d00001 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 or + 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 / should be "&GUID=". + // Will meet '\0' if there is only one /. + // + 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 of . + + @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 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 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 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 from String then output it. + + @param String A sub string of a configuration string in + 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 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 , + , or . 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 in format, i.e. the value of OFFSET + or WIDTH or VALUE. + ::= 'OFFSET='&'WIDTH='&'VALUE'= + + @param StringPtr String in format and points to the + first character of . + @param Number The output value. Caller takes the responsibility + to free memory. + @param Len Length of the , in characters. + + @retval EFI_OUT_OF_RESOURCES Insufficient resources to store neccessary + structures. + @retval EFI_SUCCESS Value of 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 + 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 + 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 should be + // , which is in '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 + // or most recent & before the error. + // + if (StringPtr == Request) { + *Progress = StringPtr; + } else { + *Progress = StringPtr - 1; + } + + // + // Process each of + // + 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 . + // Map it to the progress on then return it. + // + RemainSize = StrSize (AccessProgress); + for (TmpPtr = StringPtr; CompareMem (TmpPtr, AccessProgress, RemainSize) != 0; TmpPtr++); + *Progress = TmpPtr; + + SafeFreePool (ConfigRequest); + return Status; + } + + // + // Attach this to a + // + ASSERT (*AccessProgress == 0); + Status = AppendToMultiString (Results, AccessResults); + ASSERT_EFI_ERROR (Status); + SafeFreePool (AccessResults); + AccessResults = NULL; + SafeFreePool (ConfigRequest); + ConfigRequest = NULL; + + // + // Go to next (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 + 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 with one and zero . + // 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 + // ::= '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 + // ::= 'NAME=' + // + 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 + // ::= '' + // + 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 or a + // is required to call ConfigAccess.ExtractConfig(). + // + // Here we use 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 to a + // + 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 + 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 should be + // , which is in '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 + // or most recent & before the error. + // + if (StringPtr == Configuration) { + *Progress = StringPtr; + } else { + *Progress = StringPtr - 1; + } + + // + // Process each of + // + 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 . + // Map it to the progress on 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 (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 + 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 formatted string. + Block is left updated and Progress points at + the "&" preceding the first non-. + +**/ +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 + // + 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 and an additional '&' to + // + Length = StringPtr - ConfigRequest; + CopyMem (*Config, ConfigRequest, Length * sizeof (CHAR16)); + + // + // Parse each if exists + // Only format is supported by this help function. + // ::= 'OFFSET='&'WIDTH=' + // + while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) { + // + // Back up the header of one + // + 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 + 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 formatted name / + value pair. Block is left updated and + Progress points at the '&' preceding the first + non-. + +**/ +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 + // + 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 if exists + // Only format is supported by this help function. + // ::= 'OFFSET='&'WIDTH='&'VALUE=' + // + 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 + 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 + // + 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 + // + 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 or + // + 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 to get the 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 and + // + 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +#include +#include +#include +#include +#include +#include +#include + +#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 + 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 + 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 + 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 + 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 + 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 formatted string. + Block is left updated and Progress points at + the ¡®&¡¯ preceding the first non-. + +**/ +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 + 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 formatted name / + value pair. Block is left updated and + Progress points at the ¡®&¡¯ preceding the first + non-. + +**/ +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 + 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 @@ + + + HiiDatabase + DXE_DRIVER + 348C4D62-BFBD-4882-9ECE-C80BB1C4783B + 1.0 + 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. + FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052 + + + IA32 X64 IPF EBC + false + HiiDatabase + + + + DebugLib + + + BaseMemoryLib + + + UefiDriverEntryPoint + + + UefiBootServicesTableLib + + + BaseLib + + + DevicePathLib + + + MemoryAllocationLib + + + + R8Lib.c + R8Lib.h + Font.c + Database.c + String.c + ConfigRouting.c + HiiDatabase.dxs + HiiDatabase.h + Image.c + HiiDatabaseEntry.c + CVS\TortoiseCVS.Status + + + + + + + + gEfiDevicePathProtocolGuid + + + gEfiConsoleControlProtocolGuid + + + + EFI_SPECIFICATION_VERSION 0x00020000 + EDK_RELEASE_VERSION 0x00020000 + + InitializeHiiDatabase + + + \ 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. ::= '&' | '&'