From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=192.55.52.43; helo=mga05.intel.com; envelope-from=eric.dong@intel.com; receiver=edk2-devel@lists.01.org Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id EE4F3201B0433 for ; Sun, 17 Feb 2019 23:47:47 -0800 (PST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga007.fm.intel.com ([10.253.24.52]) by fmsmga105.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 17 Feb 2019 23:47:47 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.58,383,1544515200"; d="scan'208";a="123258230" Received: from fmsmsx105.amr.corp.intel.com ([10.18.124.203]) by fmsmga007.fm.intel.com with ESMTP; 17 Feb 2019 23:47:47 -0800 Received: from fmsmsx114.amr.corp.intel.com (10.18.116.8) by FMSMSX105.amr.corp.intel.com (10.18.124.203) with Microsoft SMTP Server (TLS) id 14.3.408.0; Sun, 17 Feb 2019 23:47:47 -0800 Received: from shsmsx154.ccr.corp.intel.com (10.239.6.54) by FMSMSX114.amr.corp.intel.com (10.18.116.8) with Microsoft SMTP Server (TLS) id 14.3.408.0; Sun, 17 Feb 2019 23:47:45 -0800 Received: from shsmsx102.ccr.corp.intel.com ([169.254.2.207]) by SHSMSX154.ccr.corp.intel.com ([169.254.7.232]) with mapi id 14.03.0415.000; Mon, 18 Feb 2019 15:47:43 +0800 From: "Dong, Eric" To: "Wu, Hao A" , "edk2-devel@lists.01.org" CC: "Ni, Ray" , "Zhang, Chao B" , "Yao, Jiewen" Thread-Topic: [PATCH v1 1/1] SecurityPkg/HddPassword: Add Security feature set support for ATA dev Thread-Index: AQHUxNkaiZmrzbpz+EOUeXT18Cqlq6XlMl+w Date: Mon, 18 Feb 2019 07:47:43 +0000 Message-ID: References: <20190215024911.7704-1-hao.a.wu@intel.com> <20190215024911.7704-2-hao.a.wu@intel.com> In-Reply-To: <20190215024911.7704-2-hao.a.wu@intel.com> Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [10.239.127.40] MIME-Version: 1.0 Subject: Re: [PATCH v1 1/1] SecurityPkg/HddPassword: Add Security feature set support for ATA dev X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 18 Feb 2019 07:47:48 -0000 Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Hi Hao, Only minor change request, remove below useless zero memory action. ZeroMem (S3InitDevices, S3InitDevicesLength); With this change, Reviewed-by: Eric Dong Thanks, Eric > -----Original Message----- > From: Wu, Hao A > Sent: Friday, February 15, 2019 10:49 AM > To: edk2-devel@lists.01.org > Cc: Wu, Hao A ; Dong, Eric ; Ni, > Ray ; Zhang, Chao B ; Yao, > Jiewen > Subject: [PATCH v1 1/1] SecurityPkg/HddPassword: Add Security feature set > support for ATA dev >=20 > REF:https://bugzilla.tianocore.org/show_bug.cgi?id=3D1529 >=20 > This commit will add the 'Security feature set' support for ATA devices. >=20 > According to the AT Attachment 8 - ATA/ATAPI Command Set (ATA8-ACS) > specification, the Security feature set is an optional feature. In > summary, the feature is a password system that restricts access to user > data stored on an ATA device. A more detailed introduction of this featur= e > can be referred from the ATA8-ACS spec. >=20 > The HddPassword driver is composed of 2 parts: > * A DXE driver and > * A PEI driver >=20 > The DXE driver consumes EFI_ATA_PASS_THRU_PROTOCOL instances and > installs > an HII GUI to manage the devices. If the managing device supports Securit= y > feature set, the HII page will provide the user with the ability to > set/update/disable the password for this device. Also, if a password is > being set via the Security feature set, a popup window will show during > boot requesting the user to input password. >=20 > Another feature supported by this driver is that for those managing > devices with password set, they will be automatically unlocked during the > S3 resume. This is done by the co-work of the DXE driver and the PEI > driver: >=20 > The DXE driver will save the password and the identication information fo= r > these devices into a LockBox, which is only allowed to restore during S3 > resume. >=20 > The PEI driver, during S3 resume, will restore the content in the LockBox > and will consume EDKII_PEI_ATA_PASS_THRU_PPI instances to unlock > devices. >=20 > Cc: Eric Dong > Cc: Ray Ni > Cc: Chao Zhang > Cc: Jiewen Yao > Contributed-under: TianoCore Contribution Agreement 1.1 > Signed-off-by: Hao Wu > --- > SecurityPkg/SecurityPkg.dsc | 6 + > SecurityPkg/HddPassword/HddPasswordDxe.inf | 75 + > SecurityPkg/HddPassword/HddPasswordPei.inf | 54 + > SecurityPkg/HddPassword/HddPasswordCommon.h | 61 + > SecurityPkg/HddPassword/HddPasswordDxe.h | 148 + > SecurityPkg/HddPassword/HddPasswordHiiDataStruc.h | 63 + > SecurityPkg/HddPassword/HddPasswordPei.h | 64 + > SecurityPkg/HddPassword/HddPassword.vfr | 188 ++ > SecurityPkg/HddPassword/HddPasswordDxe.c | 2816 > ++++++++++++++++++++ > SecurityPkg/HddPassword/HddPasswordPei.c | 461 ++++ > SecurityPkg/HddPassword/HddPasswordStrings.uni | 48 + > 11 files changed, 3984 insertions(+) >=20 > diff --git a/SecurityPkg/SecurityPkg.dsc b/SecurityPkg/SecurityPkg.dsc > index ab887e8c4d..5577ff0687 100644 > --- a/SecurityPkg/SecurityPkg.dsc > +++ b/SecurityPkg/SecurityPkg.dsc > @@ -287,6 +287,12 @@ > SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordDxe.inf > SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.inf >=20 > + # > + # HDD Password solution > + # > + SecurityPkg/HddPassword/HddPasswordDxe.inf > + SecurityPkg/HddPassword/HddPasswordPei.inf > + > [BuildOptions] > MSFT:*_*_IA32_DLINK_FLAGS =3D /ALIGN:256 > INTEL:*_*_IA32_DLINK_FLAGS =3D /ALIGN:256 > diff --git a/SecurityPkg/HddPassword/HddPasswordDxe.inf > b/SecurityPkg/HddPassword/HddPasswordDxe.inf > new file mode 100644 > index 0000000000..7a3fc2f88c > --- /dev/null > +++ b/SecurityPkg/HddPassword/HddPasswordDxe.inf > @@ -0,0 +1,75 @@ > +## @file > +# HddPasswordDxe driver which is used to set/clear hdd password at > attached harddisk > +# devices. > +# > +# Copyright (c) 2019, 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 ma= y 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 =3D 0x00010005 > + BASE_NAME =3D HddPasswordDxe > + FILE_GUID =3D 9BD549CD-86D1-4925-9F7D-3686DDD876F= C > + MODULE_TYPE =3D DXE_DRIVER > + VERSION_STRING =3D 1.0 > + ENTRY_POINT =3D HddPasswordDxeInit > + > +# > +# The following information is for reference only and not required by th= e > build tools. > +# > +# VALID_ARCHITECTURES =3D IA32 X64 IPF EBC > +# > + > +[Sources] > + HddPasswordDxe.c > + HddPasswordDxe.h > + HddPasswordHiiDataStruc.h > + HddPassword.vfr > + HddPasswordStrings.uni > + HddPasswordCommon.h > + > +[Packages] > + MdePkg/MdePkg.dec > + MdeModulePkg/MdeModulePkg.dec > + CryptoPkg/CryptoPkg.dec > + > +[LibraryClasses] > + BaseLib > + MemoryAllocationLib > + UefiBootServicesTableLib > + UefiDriverEntryPoint > + UefiHiiServicesLib > + UefiRuntimeServicesTableLib > + DxeServicesTableLib > + BaseMemoryLib > + DebugLib > + HiiLib > + PrintLib > + UefiLib > + LockBoxLib > + S3BootScriptLib > + PciLib > + BaseCryptLib > + > +[Guids] > + gEfiIfrTianoGuid ## CONSUMES ## GUID > + gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event > + gS3StorageDeviceInitListGuid ## SOMETIMES_PRODUCES ## > UNDEFINED > + > +[Protocols] > + gEfiHiiConfigAccessProtocolGuid ## PRODUCES > + gEfiAtaPassThruProtocolGuid ## CONSUMES > + gEfiPciIoProtocolGuid ## CONSUMES > + gEdkiiVariableLockProtocolGuid ## CONSUMES > + > +[Depex] > + gEfiVariableWriteArchProtocolGuid > + > diff --git a/SecurityPkg/HddPassword/HddPasswordPei.inf > b/SecurityPkg/HddPassword/HddPasswordPei.inf > new file mode 100644 > index 0000000000..d240cc1d07 > --- /dev/null > +++ b/SecurityPkg/HddPassword/HddPasswordPei.inf > @@ -0,0 +1,54 @@ > +## @file > +# HddPassword PEI module which is used to unlock HDD password for S3. > +# > +# Copyright (c) 2019, 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 ma= y 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 =3D 0x00010005 > + BASE_NAME =3D HddPasswordPei > + FILE_GUID =3D 91AD7375-8E8E-49D2-A343-68BC7827395= 5 > + MODULE_TYPE =3D PEIM > + VERSION_STRING =3D 1.0 > + ENTRY_POINT =3D HddPasswordPeiInit > + > +# > +# The following information is for reference only and not required by th= e > build tools. > +# > +# VALID_ARCHITECTURES =3D IA32 X64 IPF EBC > +# > + > +[Sources] > + HddPasswordPei.c > + HddPasswordPei.h > + HddPasswordCommon.h > + > +[Packages] > + MdePkg/MdePkg.dec > + MdeModulePkg/MdeModulePkg.dec > + > +[LibraryClasses] > + PeimEntryPoint > + PeiServicesLib > + DebugLib > + BaseLib > + BaseMemoryLib > + MemoryAllocationLib > + PciLib > + LockBoxLib > + > +[Ppis] > + gEdkiiPeiAtaPassThruPpiGuid ## NOTIFY > + > +[Depex] > + gEfiPeiMasterBootModePpiGuid > + > diff --git a/SecurityPkg/HddPassword/HddPasswordCommon.h > b/SecurityPkg/HddPassword/HddPasswordCommon.h > new file mode 100644 > index 0000000000..b904b7d39e > --- /dev/null > +++ b/SecurityPkg/HddPassword/HddPasswordCommon.h > @@ -0,0 +1,61 @@ > +/** @file > + HDD Password common header file. > + > + Copyright (c) 2019, 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 _HDD_PASSWORD_COMMON_H_ > +#define _HDD_PASSWORD_COMMON_H_ > + > +// > +// The payload length of HDD related ATA commands > +// > +#define HDD_PAYLOAD 512 > + > +#define ATA_SECURITY_SET_PASSWORD_CMD 0xF1 > +#define ATA_SECURITY_UNLOCK_CMD 0xF2 > +#define ATA_SECURITY_FREEZE_LOCK_CMD 0xF5 > +#define ATA_SECURITY_DIS_PASSWORD_CMD 0xF6 > + > +// > +// The max retry count specified in ATA 8 spec. > +// > +#define MAX_HDD_PASSWORD_RETRY_COUNT 5 > + > +// > +// According to ATA spec, the max length of hdd password is 32 bytes > +// > +#define HDD_PASSWORD_MAX_LENGTH 32 > + > +#define HDD_PASSWORD_DEVICE_INFO_GUID { 0x96d877ad, 0x48af, > 0x4b39, { 0x9b, 0x27, 0x4d, 0x97, 0x43, 0x9, 0xae, 0x47 } } > + > +typedef struct { > + UINT8 Bus; > + UINT8 Device; > + UINT8 Function; > + UINT8 Reserved; > + UINT16 Port; > + UINT16 PortMultiplierPort; > +} HDD_PASSWORD_DEVICE; > + > +// > +// It will be used to unlock HDD password for S3. > +// > +typedef struct { > + HDD_PASSWORD_DEVICE Device; > + CHAR8 Password[HDD_PASSWORD_MAX_LENGTH]; > + UINT32 DevicePathLength; > + EFI_DEVICE_PATH_PROTOCOL DevicePath[]; > +} HDD_PASSWORD_DEVICE_INFO; > + > +#endif // _HDD_PASSWORD_COMMON_H_ > diff --git a/SecurityPkg/HddPassword/HddPasswordDxe.h > b/SecurityPkg/HddPassword/HddPasswordDxe.h > new file mode 100644 > index 0000000000..41db0554d5 > --- /dev/null > +++ b/SecurityPkg/HddPassword/HddPasswordDxe.h > @@ -0,0 +1,148 @@ > +/** @file > + > + Copyright (c) 2019, 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 _HDD_PASSWORD_DXE_H_ > +#define _HDD_PASSWORD_DXE_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 "HddPasswordCommon.h" > +#include "HddPasswordHiiDataStruc.h" > + > +// > +// This is the generated IFR binary data for each formset defined in VFR= . > +// This data array is ready to be used as input of HiiAddPackages() to > +// create a packagelist (which contains Form packages, String packages, = etc). > +// > +extern UINT8 HddPasswordBin[]; > + > +// > +// This is the generated String package data for all .UNI files. > +// This data array is ready to be used as input of HiiAddPackages() to > +// create a packagelist (which contains Form packages, String packages, = etc). > +// > +extern UINT8 HddPasswordDxeStrings[]; > + > +#define HDD_PASSWORD_DXE_PRIVATE_SIGNATURE SIGNATURE_32 ('H', > 'D', 'D', 'P') > + > +typedef struct _HDD_PASSWORD_CONFIG_FORM_ENTRY { > + LIST_ENTRY Link; > + EFI_HANDLE Controller; > + UINTN Bus; > + UINTN Device; > + UINTN Function; > + UINT16 Port; > + UINT16 PortMultiplierPort; > + EFI_DEVICE_PATH_PROTOCOL *DevicePath; > + CHAR16 HddString[64]; > + CHAR8 Password[HDD_PASSWORD_MAX_LENGTH]; > + EFI_STRING_ID TitleToken; > + EFI_STRING_ID TitleHelpToken; > + > + HDD_PASSWORD_CONFIG IfrData; > + EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru; > +} HDD_PASSWORD_CONFIG_FORM_ENTRY; > + > +typedef struct _HDD_PASSWORD_DXE_PRIVATE_DATA { > + UINTN Signature; > + EFI_HANDLE DriverHandle; > + EFI_HII_HANDLE HiiHandle; > + EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess; > + HDD_PASSWORD_CONFIG_FORM_ENTRY *Current; > +} HDD_PASSWORD_DXE_PRIVATE_DATA; > + > +#define HDD_PASSWORD_DXE_PRIVATE_FROM_THIS(a) CR (a, > HDD_PASSWORD_DXE_PRIVATE_DATA, ConfigAccess, > HDD_PASSWORD_DXE_PRIVATE_SIGNATURE) > + > +// > +//Iterate through the doule linked list. NOT delete safe > +// > +#define EFI_LIST_FOR_EACH(Entry, ListHead) \ > + for (Entry =3D (ListHead)->ForwardLink; Entry !=3D (ListHead); Entry = =3D Entry- > >ForwardLink) > + > +#define PASSWORD_SALT_SIZE 32 > + > +#define HDD_PASSWORD_REQUEST_VARIABLE_NAME > L"HddPasswordRequest" > + > +// > +// It needs to be locked before EndOfDxe. > +// > +#define HDD_PASSWORD_VARIABLE_NAME L"HddPassword" > + > +#pragma pack(1) > + > +typedef struct { > + HDD_PASSWORD_DEVICE Device; > + HDD_PASSWORD_REQUEST Request; > +} HDD_PASSWORD_REQUEST_VARIABLE; > + > +// > +// It will be used to validate HDD password when the device is at frozen > state. > +// > +typedef struct { > + HDD_PASSWORD_DEVICE Device; > + UINT8 PasswordHash[SHA256_DIGEST_SIZE]; > + UINT8 PasswordSalt[PASSWORD_SALT_SIZE]; > +} HDD_PASSWORD_VARIABLE; > + > +/// > +/// HII specific Vendor Device Path definition. > +/// > +typedef struct { > + VENDOR_DEVICE_PATH VendorDevicePath; > + EFI_DEVICE_PATH_PROTOCOL End; > +} HII_VENDOR_DEVICE_PATH; > + > +#pragma pack() > + > +// > +// Time out value for ATA pass through protocol > +// > +#define ATA_TIMEOUT EFI_TIMER_PERIOD_SECONDS (3) > + > +typedef struct { > + UINT32 Address; > + S3_BOOT_SCRIPT_LIB_WIDTH Width; > +} HDD_HC_PCI_REGISTER_SAVE; > + > +#endif > diff --git a/SecurityPkg/HddPassword/HddPasswordHiiDataStruc.h > b/SecurityPkg/HddPassword/HddPasswordHiiDataStruc.h > new file mode 100644 > index 0000000000..608b92d797 > --- /dev/null > +++ b/SecurityPkg/HddPassword/HddPasswordHiiDataStruc.h > @@ -0,0 +1,63 @@ > +/** @file > + HddPassword HII data structure used by the driver. > + > + Copyright (c) 2019, 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 _HDD_PASSWORD_HII_DATASTRUC_H_ > +#define _HDD_PASSWORD_HII_DATASTRUC_H_ > + > +#include > + > +#define HDD_PASSWORD_CONFIG_GUID \ > + { \ > + 0x737cded7, 0x448b, 0x4801, { 0xb5, 0x7d, 0xb1, 0x94, 0x83, 0xec, 0x= 60, > 0x6f } \ > + } > + > +#define FORMID_HDD_MAIN_FORM 1 > +#define FORMID_HDD_DEVICE_FORM 2 > + > +#define HDD_DEVICE_ENTRY_LABEL 0x1234 > +#define HDD_DEVICE_LABEL_END 0xffff > + > +#define KEY_HDD_DEVICE_ENTRY_BASE 0x1000 > + > +#define KEY_HDD_USER_PASSWORD 0x101 > +#define KEY_HDD_MASTER_PASSWORD 0x102 > + > +#pragma pack(1) > + > +typedef struct { > + UINT8 Supported:1; > + UINT8 Enabled:1; > + UINT8 Locked:1; > + UINT8 Frozen:1; > + UINT8 UserPasswordStatus:1; > + UINT8 MasterPasswordStatus:1; > + UINT8 Reserved:2; > +} HDD_PASSWORD_SECURITY_STATUS; > + > +typedef struct { > + UINT8 UserPassword:1; > + UINT8 MasterPassword:1; > + UINT8 Reserved:6; > +} HDD_PASSWORD_REQUEST; > + > +typedef struct _HDD_PASSWORD_CONFIG { > + HDD_PASSWORD_SECURITY_STATUS SecurityStatus; > + HDD_PASSWORD_REQUEST Request; > +} HDD_PASSWORD_CONFIG; > + > +#pragma pack() > + > +#endif > diff --git a/SecurityPkg/HddPassword/HddPasswordPei.h > b/SecurityPkg/HddPassword/HddPasswordPei.h > new file mode 100644 > index 0000000000..be5402ecfc > --- /dev/null > +++ b/SecurityPkg/HddPassword/HddPasswordPei.h > @@ -0,0 +1,64 @@ > +/** @file > + HddPassword PEI module which is used to unlock HDD password for S3. > + > + Copyright (c) 2019, 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 _HDD_PASSWORD_PEI_H_ > +#define _HDD_PASSWORD_PEI_H_ > + > +#include > +#include > +//#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +#include "HddPasswordCommon.h" > + > +// > +// The maximum number of ATA PassThru PPI instances supported by the > driver > +// > +#define MAX_ATA_PASSTHRU_PPI 32 > + > +// > +// Time out value for ATA PassThru PPI > +// > +#define ATA_TIMEOUT 30000000 > + > +// > +// Private data structure for HddPassword PEI driver > +// > +#define HDD_PASSWORD_PEI_DRIVER_SIGNATURE SIGNATURE_32 ('h', > 'd', 'r', 'i') > + > +typedef struct { > + UINTN Signature; > + EFI_PEI_NOTIFY_DESCRIPTOR AtaPassThruPpiNotifyList; > + > + UINTN AtaPassThruPpiInstanceNum; > + UINTN AtaPassThruPpiInstances[MAX_ATA_PASSTHRU_= PPI]; > +} HDD_PASSWORD_PEI_DRIVER_PRIVATE_DATA; > + > +#define HDD_PASSWORD_PEI_PRIVATE_DATA_FROM_THIS_NOTIFY(a) \ > + CR (a, HDD_PASSWORD_PEI_DRIVER_PRIVATE_DATA, > AtaPassThruPpiNotifyList, HDD_PASSWORD_PEI_DRIVER_SIGNATURE) > + > +#endif > + > diff --git a/SecurityPkg/HddPassword/HddPassword.vfr > b/SecurityPkg/HddPassword/HddPassword.vfr > new file mode 100644 > index 0000000000..2cd39523c7 > --- /dev/null > +++ b/SecurityPkg/HddPassword/HddPassword.vfr > @@ -0,0 +1,188 @@ > +/** @file > + HDD Password Configuration Formset. > + > + Copyright (c) 2019, 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 "HddPasswordHiiDataStruc.h" > + > +formset > + guid =3D HDD_PASSWORD_CONFIG_GUID, > + title =3D STRING_TOKEN(STR_HDD_SECURITY_CONFIG), > + help =3D STRING_TOKEN(STR_HDD_SECURITY_CONFIG), > + classguid =3D EFI_HII_PLATFORM_SETUP_FORMSET_GUID, > + > + varstore HDD_PASSWORD_CONFIG, > + name =3D HDD_PASSWORD_CONFIG, > + guid =3D HDD_PASSWORD_CONFIG_GUID; > + > + form formid =3D FORMID_HDD_MAIN_FORM, > + title =3D STRING_TOKEN(STR_HDD_SECURITY_CONFIG); > + > + label HDD_DEVICE_ENTRY_LABEL; > + label HDD_DEVICE_LABEL_END; > + > + endform; > + > + form > + formid =3D FORMID_HDD_DEVICE_FORM, > + title =3D STRING_TOKEN(STR_HDD_SECURITY_HD); > + > + subtitle text =3D STRING_TOKEN(STR_SECURITY_HDD_PWD_DESC); > + > + subtitle text =3D STRING_TOKEN(STR_NULL); > + > + subtitle text =3D STRING_TOKEN(STR_SECURITY_HDD_BANNER_ONE); > + subtitle text =3D STRING_TOKEN(STR_SECURITY_HDD_BANNER_TWO); > + subtitle text =3D STRING_TOKEN(STR_SECURITY_HDD_BANNER_THREE); > + subtitle text =3D STRING_TOKEN(STR_SECURITY_HDD_BANNER_FOUR); > + subtitle text =3D STRING_TOKEN(STR_SECURITY_HDD_BANNER_FIVE); > + > + subtitle text =3D STRING_TOKEN(STR_NULL); > + > + subtitle text =3D STRING_TOKEN(STR_HDD_PASSWORD_CONFIG); > + > + subtitle text =3D STRING_TOKEN(STR_NULL); > + > + grayoutif TRUE; > + suppressif ideqvallist > HDD_PASSWORD_CONFIG.SecurityStatus.Supported =3D=3D 0; > + text > + help =3D STRING_TOKEN(STR_EMPTY), > + text =3D STRING_TOKEN(STR_SEC_SUPPORTED), > + text =3D STRING_TOKEN(STR_YES), > + flags =3D 0, > + key =3D 0; > + endif; > + > + suppressif ideqvallist > HDD_PASSWORD_CONFIG.SecurityStatus.Supported =3D=3D 1; > + text > + help =3D STRING_TOKEN(STR_EMPTY), > + text =3D STRING_TOKEN(STR_SEC_SUPPORTED), > + text =3D STRING_TOKEN(STR_NO), > + flags =3D 0, > + key =3D 0; > + endif; > + > + suppressif ideqvallist HDD_PASSWORD_CONFIG.SecurityStatus.Enabled > =3D=3D 0; > + text > + help =3D STRING_TOKEN(STR_EMPTY), > + text =3D STRING_TOKEN(STR_SEC_ENABLED), > + text =3D STRING_TOKEN(STR_YES), > + flags =3D 0, > + key =3D 0; > + endif; > + > + suppressif ideqvallist HDD_PASSWORD_CONFIG.SecurityStatus.Enabled > =3D=3D 1; > + text > + help =3D STRING_TOKEN(STR_EMPTY), > + text =3D STRING_TOKEN(STR_SEC_ENABLED), > + text =3D STRING_TOKEN(STR_NO), > + flags =3D 0, > + key =3D 0; > + endif; > + > + > + suppressif ideqvallist HDD_PASSWORD_CONFIG.SecurityStatus.Locked =3D= =3D > 0; > + text > + help =3D STRING_TOKEN(STR_EMPTY), > + text =3D STRING_TOKEN(STR_SEC_LOCKED), > + text =3D STRING_TOKEN(STR_YES), > + flags =3D 0, > + key =3D 0; > + endif; > + > + suppressif ideqvallist HDD_PASSWORD_CONFIG.SecurityStatus.Locked =3D= =3D > 1; > + text > + help =3D STRING_TOKEN(STR_EMPTY), > + text =3D STRING_TOKEN(STR_SEC_LOCKED), > + text =3D STRING_TOKEN(STR_NO), > + flags =3D 0, > + key =3D 0; > + endif; > + > + suppressif ideqvallist HDD_PASSWORD_CONFIG.SecurityStatus.Frozen =3D= =3D > 0; > + text > + help =3D STRING_TOKEN(STR_EMPTY), > + text =3D STRING_TOKEN(STR_SEC_FROZEN), > + text =3D STRING_TOKEN(STR_YES), > + flags =3D 0, > + key =3D 0; > + endif; > + > + suppressif ideqvallist HDD_PASSWORD_CONFIG.SecurityStatus.Frozen =3D= =3D > 1; > + text > + help =3D STRING_TOKEN(STR_EMPTY), > + text =3D STRING_TOKEN(STR_SEC_FROZEN), > + text =3D STRING_TOKEN(STR_NO), > + flags =3D 0, > + key =3D 0; > + endif; > + > + suppressif ideqvallist > HDD_PASSWORD_CONFIG.SecurityStatus.UserPasswordStatus =3D=3D 0; > + text > + help =3D STRING_TOKEN(STR_EMPTY), > + text =3D STRING_TOKEN(STR_HDD_USER_PASSWORD_STS), > + text =3D STRING_TOKEN(STR_INSTALLED), > + flags =3D 0, > + key =3D 0; > + endif; > + > + suppressif ideqvallist > HDD_PASSWORD_CONFIG.SecurityStatus.UserPasswordStatus =3D=3D 1; > + text > + help =3D STRING_TOKEN(STR_EMPTY), > + text =3D STRING_TOKEN(STR_HDD_USER_PASSWORD_STS), > + text =3D STRING_TOKEN(STR_NOT_INSTALLED), > + flags =3D 0, > + key =3D 0; > + endif; > + > + suppressif ideqvallist > HDD_PASSWORD_CONFIG.SecurityStatus.MasterPasswordStatus =3D=3D 0; > + text > + help =3D STRING_TOKEN(STR_EMPTY), > + text =3D STRING_TOKEN(STR_HDD_MASTER_PASSWORD_STS), > + text =3D STRING_TOKEN(STR_INSTALLED), > + flags =3D 0, > + key =3D 0; > + endif; > + > + suppressif ideqvallist > HDD_PASSWORD_CONFIG.SecurityStatus.MasterPasswordStatus =3D=3D 1; > + text > + help =3D STRING_TOKEN(STR_EMPTY), > + text =3D STRING_TOKEN(STR_HDD_MASTER_PASSWORD_STS), > + text =3D STRING_TOKEN(STR_NOT_INSTALLED), > + flags =3D 0, > + key =3D 0; > + endif; > + endif; > + > + subtitle text =3D STRING_TOKEN(STR_NULL); > + > + grayoutif ideqval HDD_PASSWORD_CONFIG.SecurityStatus.Supported =3D= =3D > 0; > + checkbox varid =3D HDD_PASSWORD_CONFIG.Request.UserPassword, > + prompt =3D STRING_TOKEN(STR_HDD_USER_PASSWORD), > + help =3D STRING_TOKEN(STR_HDD_USER_PASSWORD_HELP), > + flags =3D INTERACTIVE | RESET_REQUIRED, > + key =3D KEY_HDD_USER_PASSWORD, > + endcheckbox; > + endif; > + > + grayoutif ideqval HDD_PASSWORD_CONFIG.SecurityStatus.Supported =3D= =3D > 0; > + checkbox varid =3D HDD_PASSWORD_CONFIG.Request.MasterPassword, > + prompt =3D STRING_TOKEN(STR_HDD_MASTER_PASSWORD), > + help =3D STRING_TOKEN(STR_HDD_MASTER_PASSWORD_HELP), > + flags =3D INTERACTIVE | RESET_REQUIRED, > + key =3D KEY_HDD_MASTER_PASSWORD, > + endcheckbox; > + endif; > + endform; > + > +endformset; > diff --git a/SecurityPkg/HddPassword/HddPasswordDxe.c > b/SecurityPkg/HddPassword/HddPasswordDxe.c > new file mode 100644 > index 0000000000..c8198f9c78 > --- /dev/null > +++ b/SecurityPkg/HddPassword/HddPasswordDxe.c > @@ -0,0 +1,2816 @@ > +/** @file > + HDD password driver which is used to support HDD security feature. > + > + Copyright (c) 2019, 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 "HddPasswordDxe.h" > + > +EFI_GUID mHddPasswordVendorGuid =3D > HDD_PASSWORD_CONFIG_GUID; > +CHAR16 mHddPasswordVendorStorageName[] =3D > L"HDD_PASSWORD_CONFIG"; > +LIST_ENTRY mHddPasswordConfigFormList; > +UINT32 mNumberOfHddDevices =3D 0; > + > +EFI_GUID mHddPasswordDeviceInfoGuid =3D > HDD_PASSWORD_DEVICE_INFO_GUID; > +BOOLEAN mHddPasswordEndOfDxe =3D FALSE; > +HDD_PASSWORD_REQUEST_VARIABLE *mHddPasswordRequestVariable > =3D NULL; > +UINTN mHddPasswordRequestVariableSize =3D 0; > + > +HII_VENDOR_DEVICE_PATH mHddPasswordHiiVendorDevicePath =3D { > + { > + { > + HARDWARE_DEVICE_PATH, > + HW_VENDOR_DP, > + { > + (UINT8) (sizeof (VENDOR_DEVICE_PATH)), > + (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) > + } > + }, > + HDD_PASSWORD_CONFIG_GUID > + }, > + { > + END_DEVICE_PATH_TYPE, > + END_ENTIRE_DEVICE_PATH_SUBTYPE, > + { > + (UINT8) (END_DEVICE_PATH_LENGTH), > + (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8) > + } > + } > +}; > + > + > +/** > + Check if the password is full zero. > + > + @param[in] Password Points to the data buffer > + > + @retval TRUE This password string is full zero. > + @retval FALSE This password string is not full zero. > + > +**/ > +BOOLEAN > +PasswordIsFullZero ( > + IN CHAR8 *Password > + ) > +{ > + UINTN Index; > + > + for (Index =3D 0; Index < HDD_PASSWORD_MAX_LENGTH; Index++) { > + if (Password[Index] !=3D 0) { > + return FALSE; > + } > + } > + > + return TRUE; > +} > + > +/** > + Save device info. > + > + @param[in] ConfigFormEntry Points to > HDD_PASSWORD_CONFIG_FORM_ENTRY buffer > + @param[in,out] TempDevInfo Points to > HDD_PASSWORD_DEVICE_INFO buffer > + > +**/ > +VOID > +SaveDeviceInfo ( > + IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry, > + IN OUT HDD_PASSWORD_DEVICE_INFO *TempDevInfo > + ) > +{ > + TempDevInfo->Device.Bus =3D (UINT8) ConfigFormEntry->Bu= s; > + TempDevInfo->Device.Device =3D (UINT8) ConfigFormEntry->De= vice; > + TempDevInfo->Device.Function =3D (UINT8) ConfigFormEntry- > >Function; > + TempDevInfo->Device.Port =3D ConfigFormEntry->Port; > + TempDevInfo->Device.PortMultiplierPort =3D ConfigFormEntry- > >PortMultiplierPort; > + CopyMem (TempDevInfo->Password, ConfigFormEntry->Password, > HDD_PASSWORD_MAX_LENGTH); > + TempDevInfo->DevicePathLength =3D (UINT32) GetDevicePathSize > (ConfigFormEntry->DevicePath); > + CopyMem (TempDevInfo->DevicePath, ConfigFormEntry->DevicePath, > TempDevInfo->DevicePathLength); > +} > + > +/** > + Build HDD password device info and save them to LockBox. > + > + **/ > +VOID > +BuildHddPasswordDeviceInfo ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + LIST_ENTRY *Entry; > + HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry; > + HDD_PASSWORD_DEVICE_INFO *DevInfo; > + HDD_PASSWORD_DEVICE_INFO *TempDevInfo; > + UINTN DevInfoLength; > + UINT8 DummyData; > + BOOLEAN S3InitDevicesExist; > + UINTN S3InitDevicesLength; > + EFI_DEVICE_PATH_PROTOCOL *S3InitDevices; > + EFI_DEVICE_PATH_PROTOCOL *S3InitDevicesBak; > + > + // > + // Build HDD password device info and save them to LockBox. > + // > + DevInfoLength =3D 0; > + EFI_LIST_FOR_EACH (Entry, &mHddPasswordConfigFormList) { > + ConfigFormEntry =3D BASE_CR (Entry, > HDD_PASSWORD_CONFIG_FORM_ENTRY, Link); > + > + // > + // 1. Handle device which already set password. > + // 2. When request to send freeze comamnd, driver also needs to hand= le > device > + // which support security feature. > + // > + if ((!PasswordIsFullZero (ConfigFormEntry->Password)) || > + ((ConfigFormEntry->IfrData.SecurityStatus.Supported !=3D 0) && > + (ConfigFormEntry->IfrData.SecurityStatus.Enabled =3D=3D 0))) { > + DevInfoLength +=3D sizeof (HDD_PASSWORD_DEVICE_INFO) + > + GetDevicePathSize (ConfigFormEntry->DevicePath); > + } > + } > + > + if (DevInfoLength =3D=3D 0) { > + return; > + } > + > + S3InitDevicesLength =3D sizeof (DummyData); > + Status =3D RestoreLockBox ( > + &gS3StorageDeviceInitListGuid, > + &DummyData, > + &S3InitDevicesLength > + ); > + ASSERT ((Status =3D=3D EFI_NOT_FOUND) || (Status =3D=3D > EFI_BUFFER_TOO_SMALL)); > + if (Status =3D=3D EFI_NOT_FOUND) { > + S3InitDevices =3D NULL; > + S3InitDevicesExist =3D FALSE; > + } else if (Status =3D=3D EFI_BUFFER_TOO_SMALL) { > + S3InitDevices =3D AllocatePool (S3InitDevicesLength); > + ASSERT (S3InitDevices !=3D NULL); > + > + Status =3D RestoreLockBox ( > + &gS3StorageDeviceInitListGuid, > + S3InitDevices, > + &S3InitDevicesLength > + ); > + ASSERT_EFI_ERROR (Status); > + S3InitDevicesExist =3D TRUE; > + } else { > + return; > + } > + > + DevInfo =3D AllocateZeroPool (DevInfoLength); > + ASSERT (DevInfo !=3D NULL); > + > + TempDevInfo =3D DevInfo; > + EFI_LIST_FOR_EACH (Entry, &mHddPasswordConfigFormList) { > + ConfigFormEntry =3D BASE_CR (Entry, > HDD_PASSWORD_CONFIG_FORM_ENTRY, Link); > + > + if ((!PasswordIsFullZero (ConfigFormEntry->Password)) || > + ((ConfigFormEntry->IfrData.SecurityStatus.Supported !=3D 0) && > + (ConfigFormEntry->IfrData.SecurityStatus.Enabled =3D=3D 0))) { > + SaveDeviceInfo (ConfigFormEntry, TempDevInfo); > + > + S3InitDevicesBak =3D S3InitDevices; > + S3InitDevices =3D AppendDevicePathInstance ( > + S3InitDevicesBak, > + ConfigFormEntry->DevicePath > + ); > + if (S3InitDevicesBak !=3D NULL) { > + ZeroMem (S3InitDevicesBak, GetDevicePathSize (S3InitDevicesBak))= ; > + FreePool (S3InitDevicesBak); > + } > + ASSERT (S3InitDevices !=3D NULL); > + > + TempDevInfo =3D (HDD_PASSWORD_DEVICE_INFO *) > ((UINTN)TempDevInfo + > + sizeof (HDD_PASSWORD_D= EVICE_INFO) + > + TempDevInfo->DevicePat= hLength); > + } > + } > + > + Status =3D SaveLockBox ( > + &mHddPasswordDeviceInfoGuid, > + DevInfo, > + DevInfoLength > + ); > + ASSERT_EFI_ERROR (Status); > + > + Status =3D SetLockBoxAttributes ( > + &mHddPasswordDeviceInfoGuid, > + LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY > + ); > + ASSERT_EFI_ERROR (Status); > + > + S3InitDevicesLength =3D GetDevicePathSize (S3InitDevices); > + if (S3InitDevicesExist) { > + Status =3D UpdateLockBox ( > + &gS3StorageDeviceInitListGuid, > + 0, > + S3InitDevices, > + S3InitDevicesLength > + ); > + ASSERT_EFI_ERROR (Status); > + } else { > + Status =3D SaveLockBox ( > + &gS3StorageDeviceInitListGuid, > + S3InitDevices, > + S3InitDevicesLength > + ); > + ASSERT_EFI_ERROR (Status); > + > + Status =3D SetLockBoxAttributes ( > + &gS3StorageDeviceInitListGuid, > + LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY > + ); > + ASSERT_EFI_ERROR (Status); > + } > + > + ZeroMem (DevInfo, DevInfoLength); > + FreePool (DevInfo); > + ZeroMem (S3InitDevices, S3InitDevicesLength); > + FreePool (S3InitDevices); > +} > + > +/** > + Send freeze lock cmd through Ata Pass Thru Protocol. > + > + @param[in] AtaPassThru The pointer to the ATA_PASS_THRU protoc= ol. > + @param[in] Port The port number of the ATA device to se= nd the > command. > + @param[in] PortMultiplierPort The port multiplier port number of the = ATA > device to send the command. > + If there is no port multiplier, then sp= ecify 0xFFFF. > + > + @retval EFI_SUCCESS Successful to send freeze lock cmd. > + @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid. > + @retval EFI_OUT_OF_RESOURCES Not enough memory to send freeze > lock cmd. > + @retval EFI_DEVICE_ERROR Can not send freeze lock cmd. > + > +**/ > +EFI_STATUS > +FreezeLockDevice ( > + IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru, > + IN UINT16 Port, > + IN UINT16 PortMultiplierPort > + ) > +{ > + EFI_STATUS Status; > + EFI_ATA_COMMAND_BLOCK Acb; > + EFI_ATA_STATUS_BLOCK *Asb; > + EFI_ATA_PASS_THRU_COMMAND_PACKET Packet; > + > + if (AtaPassThru =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) i= n > + // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned > specified by > + // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. > Meanwhile, > + // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields= , > so it > + // may not be aligned when allocated on stack for some compilers. Henc= e, > we > + // use the API AllocateAlignedPages to ensure this structure is proper= ly > + // aligned. > + // > + Asb =3D AllocateAlignedPages ( > + EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)), > + AtaPassThru->Mode->IoAlign > + ); > + if (Asb =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + // > + // Prepare for ATA command block. > + // > + ZeroMem (&Acb, sizeof (Acb)); > + ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK)); > + Acb.AtaCommand =3D ATA_SECURITY_FREEZE_LOCK_CMD; > + Acb.AtaDeviceHead =3D (UINT8) (PortMultiplierPort =3D=3D 0xFFFF ? 0 : > (PortMultiplierPort << 4)); > + > + // > + // Prepare for ATA pass through packet. > + // > + ZeroMem (&Packet, sizeof (Packet)); > + Packet.Protocol =3D EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA; > + Packet.Length =3D EFI_ATA_PASS_THRU_LENGTH_NO_DATA_TRANSFER; > + Packet.Asb =3D Asb; > + Packet.Acb =3D &Acb; > + Packet.Timeout =3D ATA_TIMEOUT; > + > + Status =3D AtaPassThru->PassThru ( > + AtaPassThru, > + Port, > + PortMultiplierPort, > + &Packet, > + NULL > + ); > + if (!EFI_ERROR (Status) && > + ((Asb->AtaStatus & ATA_STSREG_ERR) !=3D 0) && > + ((Asb->AtaError & ATA_ERRREG_ABRT) !=3D 0)) { > + Status =3D EFI_DEVICE_ERROR; > + } > + > + FreeAlignedPages (Asb, EFI_SIZE_TO_PAGES (sizeof > (EFI_ATA_STATUS_BLOCK))); > + > + DEBUG ((DEBUG_INFO, "%a() - %r\n", __FUNCTION__, Status)); > + return Status; > +} > + > +/** > + Get attached harddisk identify data through Ata Pass Thru Protocol. > + > + @param[in] AtaPassThru The pointer to the ATA_PASS_THRU protoc= ol. > + @param[in] Port The port number of the ATA device to se= nd the > command. > + @param[in] PortMultiplierPort The port multiplier port number of the = ATA > device to send the command. > + If there is no port multiplier, then sp= ecify 0xFFFF. > + @param[in] IdentifyData The buffer to store identify data. > + > + @retval EFI_SUCCESS Successful to get identify data. > + @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid. > + @retval EFI_OUT_OF_RESOURCES Not enough memory to get identify > data. > + @retval EFI_DEVICE_ERROR Can not get identify data. > + > +**/ > +EFI_STATUS > +GetHddDeviceIdentifyData ( > + IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru, > + IN UINT16 Port, > + IN UINT16 PortMultiplierPort, > + IN ATA_IDENTIFY_DATA *IdentifyData > + ) > +{ > + EFI_STATUS Status; > + EFI_ATA_COMMAND_BLOCK Acb; > + EFI_ATA_STATUS_BLOCK *Asb; > + EFI_ATA_PASS_THRU_COMMAND_PACKET Packet; > + > + if ((AtaPassThru =3D=3D NULL) || (IdentifyData =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) i= n > + // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned > specified by > + // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. > Meanwhile, > + // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields= , > so it > + // may not be aligned when allocated on stack for some compilers. Henc= e, > we > + // use the API AllocateAlignedPages to ensure this structure is proper= ly > + // aligned. > + // > + Asb =3D AllocateAlignedPages ( > + EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)), > + AtaPassThru->Mode->IoAlign > + ); > + if (Asb =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + // > + // Prepare for ATA command block. > + // > + ZeroMem (&Acb, sizeof (Acb)); > + ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK)); > + Acb.AtaCommand =3D ATA_CMD_IDENTIFY_DRIVE; > + Acb.AtaDeviceHead =3D (UINT8) (BIT7 | BIT6 | BIT5 | (PortMultiplierPor= t =3D=3D > 0xFFFF ? 0 : (PortMultiplierPort << 4))); > + > + // > + // Prepare for ATA pass through packet. > + // > + ZeroMem (&Packet, sizeof (Packet)); > + Packet.Protocol =3D EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN; > + Packet.Length =3D EFI_ATA_PASS_THRU_LENGTH_BYTES | > EFI_ATA_PASS_THRU_LENGTH_SECTOR_COUNT; > + Packet.Asb =3D Asb; > + Packet.Acb =3D &Acb; > + Packet.InDataBuffer =3D IdentifyData; > + Packet.InTransferLength =3D sizeof (ATA_IDENTIFY_DATA); > + Packet.Timeout =3D ATA_TIMEOUT; > + > + Status =3D AtaPassThru->PassThru ( > + AtaPassThru, > + Port, > + PortMultiplierPort, > + &Packet, > + NULL > + ); > + > + FreeAlignedPages (Asb, EFI_SIZE_TO_PAGES (sizeof > (EFI_ATA_STATUS_BLOCK))); > + > + return Status; > +} > + > +/** > + Parse security status according to identify data. > + > + @param[in] IdentifyData The buffer to store identify data. > + @param[in, out] IfrData IFR data to hold security status. > + > +**/ > +VOID > +GetHddPasswordSecurityStatus ( > + IN ATA_IDENTIFY_DATA *IdentifyData, > + IN OUT HDD_PASSWORD_CONFIG *IfrData > + ) > +{ > + IfrData->SecurityStatus.Supported =3D (IdentifyData- > >command_set_supported_82 & BIT1) ? 1 : 0; > + IfrData->SecurityStatus.Enabled =3D (IdentifyData->security_status &= BIT1) ? > 1 : 0; > + IfrData->SecurityStatus.Locked =3D (IdentifyData->security_status &= BIT2) ? > 1 : 0; > + IfrData->SecurityStatus.Frozen =3D (IdentifyData->security_status &= BIT3) ? > 1 : 0; > + IfrData->SecurityStatus.UserPasswordStatus =3D IfrData- > >SecurityStatus.Enabled; > + IfrData->SecurityStatus.MasterPasswordStatus =3D IfrData- > >SecurityStatus.Supported; > + > + DEBUG ((DEBUG_INFO, "IfrData->SecurityStatus.Supported =3D = %x\n", > IfrData->SecurityStatus.Supported)); > + DEBUG ((DEBUG_INFO, "IfrData->SecurityStatus.Enabled =3D = %x\n", > IfrData->SecurityStatus.Enabled)); > + DEBUG ((DEBUG_INFO, "IfrData->SecurityStatus.Locked =3D = %x\n", > IfrData->SecurityStatus.Locked)); > + DEBUG ((DEBUG_INFO, "IfrData->SecurityStatus.Frozen =3D = %x\n", > IfrData->SecurityStatus.Frozen)); > + DEBUG ((DEBUG_INFO, "IfrData->SecurityStatus.UserPasswordStatus > =3D %x\n", IfrData->SecurityStatus.UserPasswordStatus)); > + DEBUG ((DEBUG_INFO, "IfrData->SecurityStatus.MasterPasswordStatus > =3D %x\n", IfrData->SecurityStatus.MasterPasswordStatus)); > +} > + > +/** > + Notification function of EFI_END_OF_DXE_EVENT_GROUP_GUID event > group. > + > + This is a notification function registered on > EFI_END_OF_DXE_EVENT_GROUP_GUID event group. > + > + @param Event Event whose notification function is being invoke= d. > + @param Context Pointer to the notification function's context. > + > +**/ > +VOID > +EFIAPI > +HddPasswordEndOfDxeEventNotify ( > + EFI_EVENT Event, > + VOID *Context > + ) > +{ > + LIST_ENTRY *Entry; > + HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry; > + EFI_STATUS Status; > + ATA_IDENTIFY_DATA IdentifyData; > + > + DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__)); > + > + mHddPasswordEndOfDxe =3D TRUE; > + > + if (mHddPasswordRequestVariable !=3D NULL) { > + // > + // Free the HDD password request variable buffer here > + // as the HDD password requests should have been processed. > + // > + FreePool (mHddPasswordRequestVariable); > + mHddPasswordRequestVariable =3D NULL; > + mHddPasswordRequestVariableSize =3D 0; > + } > + > + // > + // If no any device, return directly. > + // > + if (IsListEmpty (&mHddPasswordConfigFormList)) { > + gBS->CloseEvent (Event); > + return; > + } > + > + BuildHddPasswordDeviceInfo (); > + > + // > + // Zero passsword and freeze lock device. > + // > + EFI_LIST_FOR_EACH (Entry, &mHddPasswordConfigFormList) { > + ConfigFormEntry =3D BASE_CR (Entry, > HDD_PASSWORD_CONFIG_FORM_ENTRY, Link); > + > + ZeroMem (ConfigFormEntry->Password, > HDD_PASSWORD_MAX_LENGTH); > + > + // > + // Check whether need send freeze lock command. > + // Below device will be froze: > + // 1. Device not enable password. > + // 2. Device enable password and unlocked. > + // > + if ((ConfigFormEntry->IfrData.SecurityStatus.Supported !=3D 0) && > + (ConfigFormEntry->IfrData.SecurityStatus.Locked =3D=3D 0) && > + (ConfigFormEntry->IfrData.SecurityStatus.Frozen =3D=3D 0)) { > + Status =3D FreezeLockDevice (ConfigFormEntry->AtaPassThru, > ConfigFormEntry->Port, ConfigFormEntry->PortMultiplierPort); > + DEBUG ((DEBUG_INFO, "FreezeLockDevice return %r!\n", Status)); > + Status =3D GetHddDeviceIdentifyData ( > + ConfigFormEntry->AtaPassThru, > + ConfigFormEntry->Port, > + ConfigFormEntry->PortMultiplierPort, > + &IdentifyData > + ); > + GetHddPasswordSecurityStatus (&IdentifyData, &ConfigFormEntry- > >IfrData); > + } > + } > + > + DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__)); > + > + gBS->CloseEvent (Event); > +} > + > +/** > + Generate Salt value. > + > + @param[in, out] SaltValue Points to the salt buffer, 32 by= tes > + > +**/ > +VOID > +GenSalt ( > + IN OUT UINT8 *SaltValue > + ) > +{ > + RandomSeed (NULL, 0); > + RandomBytes (SaltValue, PASSWORD_SALT_SIZE); > +} > + > +/** > + Hash the data to get credential. > + > + @param[in] Buffer Points to the data buffer > + @param[in] BufferSize Buffer size > + @param[in] SaltValue Points to the salt buffer, 32 bytes > + @param[out] Credential Points to the hashed result > + > + @retval TRUE Hash the data successfully. > + @retval FALSE Failed to hash the data. > + > +**/ > +BOOLEAN > +GenerateCredential ( > + IN UINT8 *Buffer, > + IN UINTN BufferSize, > + IN UINT8 *SaltValue, > + OUT UINT8 *Credential > + ) > +{ > + BOOLEAN Status; > + UINTN HashSize; > + VOID *Hash; > + VOID *HashData; > + > + Hash =3D NULL; > + HashData =3D NULL; > + Status =3D FALSE; > + > + HashSize =3D Sha256GetContextSize (); > + Hash =3D AllocateZeroPool (HashSize); > + ASSERT (Hash !=3D NULL); > + if (Hash =3D=3D NULL) { > + goto Done; > + } > + > + Status =3D Sha256Init (Hash); > + if (!Status) { > + goto Done; > + } > + > + HashData =3D AllocateZeroPool (PASSWORD_SALT_SIZE + BufferSize); > + ASSERT (HashData !=3D NULL); > + if (HashData =3D=3D NULL) { > + goto Done; > + } > + > + CopyMem (HashData, SaltValue, PASSWORD_SALT_SIZE); > + CopyMem ((UINT8 *) HashData + PASSWORD_SALT_SIZE, Buffer, > BufferSize); > + > + Status =3D Sha256Update (Hash, HashData, PASSWORD_SALT_SIZE + > BufferSize); > + if (!Status) { > + goto Done; > + } > + > + Status =3D Sha256Final (Hash, Credential); > + > +Done: > + if (Hash !=3D NULL) { > + FreePool (Hash); > + } > + if (HashData !=3D NULL) { > + ZeroMem (HashData, PASSWORD_SALT_SIZE + BufferSize); > + FreePool (HashData); > + } > + return Status; > +} > + > +/** > + Save HDD password variable that will be used to validate HDD password > + when the device is at frozen state. > + > + @param[in] ConfigFormEntry The HDD Password configuration form > entry. > + @param[in] Password The hdd password of attached ATA dev= ice. > + > +**/ > +VOID > +SaveHddPasswordVariable ( > + IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry, > + IN CHAR8 *Password > + ) > +{ > + EFI_STATUS Status; > + HDD_PASSWORD_VARIABLE *TempVariable; > + UINTN TempVariableSize; > + HDD_PASSWORD_VARIABLE *NextNode; > + HDD_PASSWORD_VARIABLE *Variable; > + UINTN VariableSize; > + HDD_PASSWORD_VARIABLE *NewVariable; > + UINTN NewVariableSize; > + BOOLEAN Delete; > + BOOLEAN HashOk; > + UINT8 HashData[SHA256_DIGEST_SIZE]; > + UINT8 SaltData[PASSWORD_SALT_SIZE]; > + > + DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__)); > + > + Delete =3D FALSE; > + if (!PasswordIsFullZero (Password)) { > + // > + // It is Set/Update HDD Password. > + // > + ZeroMem (HashData, sizeof (HashData)); > + ZeroMem (SaltData, sizeof (SaltData)); > + GenSalt (SaltData); > + HashOk =3D GenerateCredential ((UINT8 *) Password, > HDD_PASSWORD_MAX_LENGTH, SaltData, HashData); > + if (!HashOk) { > + DEBUG ((DEBUG_INFO, "GenerateCredential failed\n")); > + return; > + } > + } else { > + // > + // It is Disable HDD Password. > + // Go to delete the variable node for the HDD password device. > + // > + Delete =3D TRUE; > + } > + > + Variable =3D NULL; > + VariableSize =3D 0; > + NewVariable =3D NULL; > + NewVariableSize =3D 0; > + > + Status =3D GetVariable2 ( > + HDD_PASSWORD_VARIABLE_NAME, > + &mHddPasswordVendorGuid, > + (VOID **) &Variable, > + &VariableSize > + ); > + if (Delete) { > + if (!EFI_ERROR (Status) && (Variable !=3D NULL)) { > + TempVariable =3D Variable; > + TempVariableSize =3D VariableSize; > + while (TempVariableSize >=3D sizeof (HDD_PASSWORD_VARIABLE)) { > + if ((TempVariable->Device.Bus =3D=3D ConfigFormEn= try->Bus) && > + (TempVariable->Device.Device =3D=3D ConfigFormEn= try->Device) > && > + (TempVariable->Device.Function =3D=3D ConfigFormEn= try->Function) > && > + (TempVariable->Device.Port =3D=3D ConfigFormEn= try->Port) && > + (TempVariable->Device.PortMultiplierPort =3D=3D ConfigFormEn= try- > >PortMultiplierPort)) { > + // > + // Found the node for the HDD password device. > + // Delete the node. > + // > + NextNode =3D TempVariable + 1; > + CopyMem (TempVariable, NextNode, (UINTN) Variable + VariableSi= ze > - (UINTN) NextNode); > + NewVariable =3D Variable; > + NewVariableSize =3D VariableSize - sizeof (HDD_PASSWORD_VARIAB= LE); > + break; > + } > + TempVariableSize -=3D sizeof (HDD_PASSWORD_VARIABLE); > + TempVariable +=3D 1; > + } > + if (NewVariable =3D=3D NULL) { > + DEBUG ((DEBUG_INFO, "The variable node for the HDD password > device is not found\n")); > + } > + } else { > + DEBUG ((DEBUG_INFO, "HddPassword variable get failed (%r)\n", > Status)); > + } > + } else { > + if (!EFI_ERROR (Status) && (Variable !=3D NULL)) { > + TempVariable =3D Variable; > + TempVariableSize =3D VariableSize; > + while (TempVariableSize >=3D sizeof (HDD_PASSWORD_VARIABLE)) { > + if ((TempVariable->Device.Bus =3D=3D ConfigFormEn= try->Bus) && > + (TempVariable->Device.Device =3D=3D ConfigFormEn= try->Device) > && > + (TempVariable->Device.Function =3D=3D ConfigFormEn= try->Function) > && > + (TempVariable->Device.Port =3D=3D ConfigFormEn= try->Port) && > + (TempVariable->Device.PortMultiplierPort =3D=3D ConfigFormEn= try- > >PortMultiplierPort)) { > + // > + // Found the node for the HDD password device. > + // Update the node. > + // > + CopyMem (TempVariable->PasswordHash, HashData, sizeof > (HashData)); > + CopyMem (TempVariable->PasswordSalt, SaltData, sizeof (SaltDat= a)); > + NewVariable =3D Variable; > + NewVariableSize =3D VariableSize; > + break; > + } > + TempVariableSize -=3D sizeof (HDD_PASSWORD_VARIABLE); > + TempVariable +=3D 1; > + } > + if (NewVariable =3D=3D NULL) { > + // > + // The node for the HDD password device is not found. > + // Create node for the HDD password device. > + // > + NewVariableSize =3D VariableSize + sizeof (HDD_PASSWORD_VARIABLE= ); > + NewVariable =3D AllocateZeroPool (NewVariableSize); > + ASSERT (NewVariable !=3D NULL); > + CopyMem (NewVariable, Variable, VariableSize); > + TempVariable =3D (HDD_PASSWORD_VARIABLE *) ((UINTN) NewVariable > + VariableSize); > + TempVariable->Device.Bus =3D (UINT8) ConfigFormEn= try->Bus; > + TempVariable->Device.Device =3D (UINT8) ConfigFormEn= try- > >Device; > + TempVariable->Device.Function =3D (UINT8) ConfigFormEn= try- > >Function; > + TempVariable->Device.Port =3D ConfigFormEntry->Por= t; > + TempVariable->Device.PortMultiplierPort =3D ConfigFormEntry- > >PortMultiplierPort; > + CopyMem (TempVariable->PasswordHash, HashData, sizeof > (HashData)); > + CopyMem (TempVariable->PasswordSalt, SaltData, sizeof (SaltData)= ); > + } > + } else { > + NewVariableSize =3D sizeof (HDD_PASSWORD_VARIABLE); > + NewVariable =3D AllocateZeroPool (NewVariableSize); > + ASSERT (NewVariable !=3D NULL); > + NewVariable->Device.Bus =3D (UINT8) ConfigFormEntry= ->Bus; > + NewVariable->Device.Device =3D (UINT8) ConfigFormEntry= ->Device; > + NewVariable->Device.Function =3D (UINT8) ConfigFormEntry= - > >Function; > + NewVariable->Device.Port =3D ConfigFormEntry->Port; > + NewVariable->Device.PortMultiplierPort =3D ConfigFormEntry- > >PortMultiplierPort; > + CopyMem (NewVariable->PasswordHash, HashData, sizeof (HashData)); > + CopyMem (NewVariable->PasswordSalt, SaltData, sizeof (SaltData)); > + } > + } > + > + if (NewVariable !=3D NULL) { > + Status =3D gRT->SetVariable ( > + HDD_PASSWORD_VARIABLE_NAME, > + &mHddPasswordVendorGuid, > + EFI_VARIABLE_NON_VOLATILE | > EFI_VARIABLE_BOOTSERVICE_ACCESS, > + NewVariableSize, > + NewVariable > + ); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_INFO, "HddPassword variable set failed (%r)\n", > Status)); > + } > + } > + > + if (NewVariable !=3D Variable) { > + FreePool (NewVariable); > + } > + if (Variable !=3D NULL) { > + FreePool (Variable); > + } > + > + DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__)); > +} > + > +/** > + Get saved HDD password variable that will be used to validate HDD > password > + when the device is at frozen state. > + > + @param[in] ConfigFormEntry The HDD Password configuration form > entry. > + @param[out] HddPasswordVariable The variable node for the HDD > password device. > + > + @retval TRUE The variable node for the HDD password device is fou= nd > and returned. > + @retval FALSE The variable node for the HDD password device is not > found. > + > +**/ > +BOOLEAN > +GetSavedHddPasswordVariable ( > + IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry, > + OUT HDD_PASSWORD_VARIABLE *HddPasswordVariable > + ) > +{ > + EFI_STATUS Status; > + HDD_PASSWORD_VARIABLE *TempVariable; > + HDD_PASSWORD_VARIABLE *Variable; > + UINTN VariableSize; > + BOOLEAN Found; > + > + DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__)); > + > + Variable =3D NULL; > + VariableSize =3D 0; > + > + Status =3D GetVariable2 ( > + HDD_PASSWORD_VARIABLE_NAME, > + &mHddPasswordVendorGuid, > + (VOID **) &Variable, > + &VariableSize > + ); > + if (EFI_ERROR (Status) || (Variable =3D=3D NULL)) { > + DEBUG ((DEBUG_INFO, "HddPassword variable get failed (%r)\n", > Status)); > + return FALSE; > + } > + > + Found =3D FALSE; > + TempVariable =3D Variable; > + while (VariableSize >=3D sizeof (HDD_PASSWORD_VARIABLE)) { > + if ((TempVariable->Device.Bus =3D=3D ConfigFormEntry-= >Bus) && > + (TempVariable->Device.Device =3D=3D ConfigFormEntry-= >Device) && > + (TempVariable->Device.Function =3D=3D ConfigFormEntry-= >Function) > && > + (TempVariable->Device.Port =3D=3D ConfigFormEntry-= >Port) && > + (TempVariable->Device.PortMultiplierPort =3D=3D ConfigFormEntry- > >PortMultiplierPort)) { > + // > + // Found the node for the HDD password device. > + // Get the node. > + // > + CopyMem (HddPasswordVariable, TempVariable, sizeof > (HDD_PASSWORD_VARIABLE)); > + Found =3D TRUE; > + break; > + } > + VariableSize -=3D sizeof (HDD_PASSWORD_VARIABLE); > + TempVariable +=3D 1; > + } > + > + FreePool (Variable); > + > + if (!Found) { > + DEBUG ((DEBUG_INFO, "The variable node for the HDD password device > is not found\n")); > + } > + > + DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__)); > + > + return Found; > +} > + > +/** > + Use saved HDD password variable to validate HDD password > + when the device is at frozen state. > + > + @param[in] ConfigFormEntry The HDD Password configuration form > entry. > + @param[in] Password The hdd password of attached ATA device. > + > + @retval EFI_SUCCESS Pass to validate the HDD password. > + @retval EFI_NOT_FOUND The variable node for the HDD password > device is not found. > + @retval EFI_DEVICE_ERROR Failed to generate credential for the HD= D > password. > + @retval EFI_INVALID_PARAMETER Failed to validate the HDD password. > + > +**/ > +EFI_STATUS > +ValidateHddPassword ( > + IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry, > + IN CHAR8 *Password > + ) > +{ > + EFI_STATUS Status; > + HDD_PASSWORD_VARIABLE HddPasswordVariable; > + BOOLEAN HashOk; > + UINT8 HashData[SHA256_DIGEST_SIZE]; > + > + DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__)); > + > + if (!GetSavedHddPasswordVariable (ConfigFormEntry, > &HddPasswordVariable)) { > + DEBUG ((DEBUG_INFO, "GetSavedHddPasswordVariable failed\n")); > + return EFI_NOT_FOUND; > + } > + > + ZeroMem (HashData, sizeof (HashData)); > + HashOk =3D GenerateCredential ((UINT8 *) Password, > HDD_PASSWORD_MAX_LENGTH, HddPasswordVariable.PasswordSalt, > HashData); > + if (!HashOk) { > + DEBUG ((DEBUG_INFO, "GenerateCredential failed\n")); > + return EFI_DEVICE_ERROR; > + } > + > + if (CompareMem (HddPasswordVariable.PasswordHash, HashData, sizeof > (HashData)) !=3D 0) { > + Status =3D EFI_INVALID_PARAMETER; > + } else { > + Status =3D EFI_SUCCESS; > + } > + > + DEBUG ((DEBUG_INFO, "%a() - exit (%r)\n", __FUNCTION__, Status)); > + return Status; > +} > + > +/** > + Send unlock hdd password cmd through Ata Pass Thru Protocol. > + > + @param[in] AtaPassThru The pointer to the ATA_PASS_THRU protoc= ol. > + @param[in] Port The port number of the ATA device to se= nd the > command. > + @param[in] PortMultiplierPort The port multiplier port number of the = ATA > device to send the command. > + If there is no port multiplier, then sp= ecify 0xFFFF. > + @param[in] Identifier The identifier to set user or master pa= ssword. > + @param[in] Password The hdd password of attached ATA device= . > + > + @retval EFI_SUCCESS Successful to send unlock hdd password = cmd. > + @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid. > + @retval EFI_OUT_OF_RESOURCES Not enough memory to send unlock > hdd password cmd. > + @retval EFI_DEVICE_ERROR Can not send unlock hdd password cmd. > + > +**/ > +EFI_STATUS > +UnlockHddPassword ( > + IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru, > + IN UINT16 Port, > + IN UINT16 PortMultiplierPort, > + IN CHAR8 Identifier, > + IN CHAR8 *Password > + ) > +{ > + EFI_STATUS Status; > + EFI_ATA_COMMAND_BLOCK Acb; > + EFI_ATA_STATUS_BLOCK *Asb; > + EFI_ATA_PASS_THRU_COMMAND_PACKET Packet; > + UINT8 Buffer[HDD_PAYLOAD]; > + > + if ((AtaPassThru =3D=3D NULL) || (Password =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) i= n > + // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned > specified by > + // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. > Meanwhile, > + // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields= , > so it > + // may not be aligned when allocated on stack for some compilers. Henc= e, > we > + // use the API AllocateAlignedPages to ensure this structure is proper= ly > + // aligned. > + // > + Asb =3D AllocateAlignedPages ( > + EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)), > + AtaPassThru->Mode->IoAlign > + ); > + if (Asb =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + // > + // Prepare for ATA command block. > + // > + ZeroMem (&Acb, sizeof (Acb)); > + ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK)); > + Acb.AtaCommand =3D ATA_SECURITY_UNLOCK_CMD; > + Acb.AtaDeviceHead =3D (UINT8) (PortMultiplierPort =3D=3D 0xFFFF ? 0 : > (PortMultiplierPort << 4)); > + > + // > + // Prepare for ATA pass through packet. > + // > + ZeroMem (&Packet, sizeof (Packet)); > + Packet.Protocol =3D EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT; > + Packet.Length =3D EFI_ATA_PASS_THRU_LENGTH_BYTES; > + Packet.Asb =3D Asb; > + Packet.Acb =3D &Acb; > + > + ((CHAR16 *) Buffer)[0] =3D Identifier & BIT0; > + CopyMem (&((CHAR16 *) Buffer)[1], Password, > HDD_PASSWORD_MAX_LENGTH); > + > + Packet.OutDataBuffer =3D Buffer; > + Packet.OutTransferLength =3D sizeof (Buffer); > + Packet.Timeout =3D ATA_TIMEOUT; > + > + Status =3D AtaPassThru->PassThru ( > + AtaPassThru, > + Port, > + PortMultiplierPort, > + &Packet, > + NULL > + ); > + if (!EFI_ERROR (Status) && > + ((Asb->AtaStatus & ATA_STSREG_ERR) !=3D 0) && > + ((Asb->AtaError & ATA_ERRREG_ABRT) !=3D 0)) { > + Status =3D EFI_DEVICE_ERROR; > + } > + > + FreeAlignedPages (Asb, EFI_SIZE_TO_PAGES (sizeof > (EFI_ATA_STATUS_BLOCK))); > + > + ZeroMem (Buffer, sizeof (Buffer)); > + > + DEBUG ((DEBUG_INFO, "%a() - %r\n", __FUNCTION__, Status)); > + return Status; > +} > + > +/** > + Send disable hdd password cmd through Ata Pass Thru Protocol. > + > + @param[in] AtaPassThru The pointer to the ATA_PASS_THRU protoc= ol. > + @param[in] Port The port number of the ATA device to se= nd the > command. > + @param[in] PortMultiplierPort The port multiplier port number of the = ATA > device to send the command. > + If there is no port multiplier, then sp= ecify 0xFFFF. > + @param[in] Identifier The identifier to set user or master pa= ssword. > + @param[in] Password The hdd password of attached ATA device= . > + > + @retval EFI_SUCCESS Successful to disable hdd password cmd. > + @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid. > + @retval EFI_OUT_OF_RESOURCES Not enough memory to disable hdd > password cmd. > + @retval EFI_DEVICE_ERROR Can not disable hdd password cmd. > + > +**/ > +EFI_STATUS > +DisableHddPassword ( > + IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru, > + IN UINT16 Port, > + IN UINT16 PortMultiplierPort, > + IN CHAR8 Identifier, > + IN CHAR8 *Password > + ) > +{ > + EFI_STATUS Status; > + EFI_ATA_COMMAND_BLOCK Acb; > + EFI_ATA_STATUS_BLOCK *Asb; > + EFI_ATA_PASS_THRU_COMMAND_PACKET Packet; > + UINT8 Buffer[HDD_PAYLOAD]; > + > + if ((AtaPassThru =3D=3D NULL) || (Password =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) i= n > + // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned > specified by > + // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. > Meanwhile, > + // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields= , > so it > + // may not be aligned when allocated on stack for some compilers. Henc= e, > we > + // use the API AllocateAlignedPages to ensure this structure is proper= ly > + // aligned. > + // > + Asb =3D AllocateAlignedPages ( > + EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)), > + AtaPassThru->Mode->IoAlign > + ); > + if (Asb =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + // > + // Prepare for ATA command block. > + // > + ZeroMem (&Acb, sizeof (Acb)); > + ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK)); > + Acb.AtaCommand =3D ATA_SECURITY_DIS_PASSWORD_CMD; > + Acb.AtaDeviceHead =3D (UINT8) (PortMultiplierPort =3D=3D 0xFFFF ? 0 : > (PortMultiplierPort << 4)); > + > + // > + // Prepare for ATA pass through packet. > + // > + ZeroMem (&Packet, sizeof (Packet)); > + Packet.Protocol =3D EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT; > + Packet.Length =3D EFI_ATA_PASS_THRU_LENGTH_BYTES; > + Packet.Asb =3D Asb; > + Packet.Acb =3D &Acb; > + > + ((CHAR16 *) Buffer)[0] =3D Identifier & BIT0; > + CopyMem (&((CHAR16 *) Buffer)[1], Password, > HDD_PASSWORD_MAX_LENGTH); > + > + Packet.OutDataBuffer =3D Buffer; > + Packet.OutTransferLength =3D sizeof (Buffer); > + Packet.Timeout =3D ATA_TIMEOUT; > + > + Status =3D AtaPassThru->PassThru ( > + AtaPassThru, > + Port, > + PortMultiplierPort, > + &Packet, > + NULL > + ); > + if (!EFI_ERROR (Status) && > + ((Asb->AtaStatus & ATA_STSREG_ERR) !=3D 0) && > + ((Asb->AtaError & ATA_ERRREG_ABRT) !=3D 0)) { > + Status =3D EFI_DEVICE_ERROR; > + } > + > + FreeAlignedPages (Asb, EFI_SIZE_TO_PAGES (sizeof > (EFI_ATA_STATUS_BLOCK))); > + > + ZeroMem (Buffer, sizeof (Buffer)); > + > + DEBUG ((DEBUG_INFO, "%a() - %r\n", __FUNCTION__, Status)); > + return Status; > +} > + > +/** > + Send set hdd password cmd through Ata Pass Thru Protocol. > + > + @param[in] AtaPassThru The pointer to the ATA_PASS_THRU > protocol. > + @param[in] Port The port number of the ATA devic= e to send > the command. > + @param[in] PortMultiplierPort The port multiplier port number = of the > ATA device to send the command. > + If there is no port multiplier, = then specify 0xFFFF. > + @param[in] Identifier The identifier to set user or ma= ster > password. > + @param[in] SecurityLevel The security level to be set to = device. > + @param[in] MasterPasswordIdentifier The master password identifier t= o > be set to device. > + @param[in] Password The hdd password of attached ATA= device. > + > + @retval EFI_SUCCESS Successful to set hdd password cmd. > + @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid. > + @retval EFI_OUT_OF_RESOURCES Not enough memory to set hdd > password cmd. > + @retval EFI_DEVICE_ERROR Can not set hdd password cmd. > + > +**/ > +EFI_STATUS > +SetHddPassword ( > + IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru, > + IN UINT16 Port, > + IN UINT16 PortMultiplierPort, > + IN CHAR8 Identifier, > + IN CHAR8 SecurityLevel, > + IN CHAR16 MasterPasswordIdentifier, > + IN CHAR8 *Password > + ) > +{ > + EFI_STATUS Status; > + EFI_ATA_COMMAND_BLOCK Acb; > + EFI_ATA_STATUS_BLOCK *Asb; > + EFI_ATA_PASS_THRU_COMMAND_PACKET Packet; > + UINT8 Buffer[HDD_PAYLOAD]; > + > + if ((AtaPassThru =3D=3D NULL) || (Password =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) i= n > + // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned > specified by > + // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. > Meanwhile, > + // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields= , > so it > + // may not be aligned when allocated on stack for some compilers. Henc= e, > we > + // use the API AllocateAlignedPages to ensure this structure is proper= ly > + // aligned. > + // > + Asb =3D AllocateAlignedPages ( > + EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)), > + AtaPassThru->Mode->IoAlign > + ); > + if (Asb =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + // > + // Prepare for ATA command block. > + // > + ZeroMem (&Acb, sizeof (Acb)); > + ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK)); > + Acb.AtaCommand =3D ATA_SECURITY_SET_PASSWORD_CMD; > + Acb.AtaDeviceHead =3D (UINT8) (PortMultiplierPort =3D=3D 0xFFFF ? 0 : > (PortMultiplierPort << 4)); > + > + // > + // Prepare for ATA pass through packet. > + // > + ZeroMem (&Packet, sizeof (Packet)); > + Packet.Protocol =3D EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT; > + Packet.Length =3D EFI_ATA_PASS_THRU_LENGTH_BYTES; > + Packet.Asb =3D Asb; > + Packet.Acb =3D &Acb; > + > + ((CHAR16 *) Buffer)[0] =3D (Identifier | (UINT16)(SecurityLevel << 8))= & (BIT0 > | BIT8); > + CopyMem (&((CHAR16 *) Buffer)[1], Password, > HDD_PASSWORD_MAX_LENGTH); > + if ((Identifier & BIT0) !=3D 0) { > + ((CHAR16 *) Buffer)[17] =3D MasterPasswordIdentifier; > + } > + > + Packet.OutDataBuffer =3D Buffer; > + Packet.OutTransferLength =3D sizeof (Buffer); > + Packet.Timeout =3D ATA_TIMEOUT; > + > + Status =3D AtaPassThru->PassThru ( > + AtaPassThru, > + Port, > + PortMultiplierPort, > + &Packet, > + NULL > + ); > + if (!EFI_ERROR (Status) && > + ((Asb->AtaStatus & ATA_STSREG_ERR) !=3D 0) && > + ((Asb->AtaError & ATA_ERRREG_ABRT) !=3D 0)) { > + Status =3D EFI_DEVICE_ERROR; > + } > + > + FreeAlignedPages (Asb, EFI_SIZE_TO_PAGES (sizeof > (EFI_ATA_STATUS_BLOCK))); > + > + ZeroMem (Buffer, sizeof (Buffer)); > + > + DEBUG ((DEBUG_INFO, "%a() - %r\n", __FUNCTION__, Status)); > + return Status; > +} > + > +/** > + Get attached harddisk model number from identify data buffer. > + > + @param[in] IdentifyData Pointer to identify data buffer. > + @param[in, out] String The buffer to store harddisk model number. > + > +**/ > +VOID > +GetHddDeviceModelNumber ( > + IN ATA_IDENTIFY_DATA *IdentifyData, > + IN OUT CHAR16 *String > + ) > +{ > + UINTN Index; > + > + // > + // Swap the byte order in the original module name. > + // From Ata spec, the maximum length is 40 bytes. > + // > + for (Index =3D 0; Index < 40; Index +=3D 2) { > + String[Index] =3D IdentifyData->ModelName[Index + 1]; > + String[Index + 1] =3D IdentifyData->ModelName[Index]; > + } > + > + // > + // Chap it off after 20 characters > + // > + String[20] =3D L'\0'; > + > + return ; > +} > + > +/** > + Get password input from the popup windows. > + > + @param[in] PopUpString1 Pop up string 1. > + @param[in] PopUpString2 Pop up string 2. > + @param[in, out] Password The buffer to hold the input password. > + > + @retval EFI_ABORTED It is given up by pressing 'ESC' key. > + @retval EFI_SUCCESS Get password input successfully. > + > +**/ > +EFI_STATUS > +PopupHddPasswordInputWindows ( > + IN CHAR16 *PopUpString1, > + IN CHAR16 *PopUpString2, > + IN OUT CHAR8 *Password > + ) > +{ > + EFI_INPUT_KEY Key; > + UINTN Length; > + CHAR16 Mask[HDD_PASSWORD_MAX_LENGTH + 1]; > + CHAR16 Unicode[HDD_PASSWORD_MAX_LENGTH + 1]; > + CHAR8 Ascii[HDD_PASSWORD_MAX_LENGTH + 1]; > + > + ZeroMem (Unicode, sizeof (Unicode)); > + ZeroMem (Ascii, sizeof (Ascii)); > + ZeroMem (Mask, sizeof (Mask)); > + > + gST->ConOut->ClearScreen(gST->ConOut); > + > + Length =3D 0; > + while (TRUE) { > + Mask[Length] =3D L'_'; > + if (PopUpString2 =3D=3D NULL) { > + CreatePopUp ( > + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, > + &Key, > + PopUpString1, > + L"---------------------", > + Mask, > + NULL > + ); > + } else { > + CreatePopUp ( > + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, > + &Key, > + PopUpString1, > + PopUpString2, > + L"---------------------", > + Mask, > + NULL > + ); > + } > + // > + // Check key. > + // > + if (Key.ScanCode =3D=3D SCAN_NULL) { > + if (Key.UnicodeChar =3D=3D CHAR_CARRIAGE_RETURN) { > + // > + // Add the null terminator. > + // > + Unicode[Length] =3D 0; > + break; > + } else if ((Key.UnicodeChar =3D=3D CHAR_NULL) || > + (Key.UnicodeChar =3D=3D CHAR_TAB) || > + (Key.UnicodeChar =3D=3D CHAR_LINEFEED) > + ) { > + continue; > + } else { > + if (Key.UnicodeChar =3D=3D CHAR_BACKSPACE) { > + if (Length > 0) { > + Unicode[Length] =3D 0; > + Mask[Length] =3D 0; > + Length--; > + } > + } else { > + Unicode[Length] =3D Key.UnicodeChar; > + Mask[Length] =3D L'*'; > + Length++; > + if (Length =3D=3D HDD_PASSWORD_MAX_LENGTH) { > + // > + // Add the null terminator. > + // > + Unicode[Length] =3D 0; > + Mask[Length] =3D 0; > + break; > + } > + } > + } > + } > + > + if (Key.ScanCode =3D=3D SCAN_ESC) { > + ZeroMem (Unicode, sizeof (Unicode)); > + ZeroMem (Ascii, sizeof (Ascii)); > + gST->ConOut->ClearScreen(gST->ConOut); > + return EFI_ABORTED; > + } > + } > + > + UnicodeStrToAsciiStrS (Unicode, Ascii, sizeof (Ascii)); > + CopyMem (Password, Ascii, HDD_PASSWORD_MAX_LENGTH); > + ZeroMem (Unicode, sizeof (Unicode)); > + ZeroMem (Ascii, sizeof (Ascii)); > + > + gST->ConOut->ClearScreen(gST->ConOut); > + return EFI_SUCCESS; > +} > + > +/** > + Check if disk is locked, show popup window and ask for password if it = is. > + > + @param[in] AtaPassThru Pointer to ATA_PASSTHRU instance. > + @param[in] Port The port number of attached ATA devi= ce. > + @param[in] PortMultiplierPort The port number of port multiplier o= f > attached ATA device. > + @param[in] ConfigFormEntry The HDD Password configuration form > entry. > + > +**/ > +VOID > +HddPasswordRequestPassword ( > + IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru, > + IN UINT16 Port, > + IN UINT16 PortMultiplierPort, > + IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry > + ) > +{ > + EFI_STATUS Status; > + CHAR16 PopUpString[100]; > + ATA_IDENTIFY_DATA IdentifyData; > + EFI_INPUT_KEY Key; > + UINT16 RetryCount; > + CHAR8 Password[HDD_PASSWORD_MAX_LENGTH]; > + > + RetryCount =3D 0; > + > + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__)); > + > + UnicodeSPrint (PopUpString, sizeof (PopUpString), L"Unlock: %s", > ConfigFormEntry->HddString); > + > + // > + // Check the device security status. > + // > + if ((ConfigFormEntry->IfrData.SecurityStatus.Supported) && > + (ConfigFormEntry->IfrData.SecurityStatus.Enabled)) { > + // > + // As soon as the HDD password is in enabled state, we pop up a wind= ow > to unlock hdd > + // no matter it's really in locked or unlocked state. > + // This way forces user to enter password every time to provide best > safety. > + // > + while (TRUE) { > + Status =3D PopupHddPasswordInputWindows (PopUpString, NULL, > Password); > + if (!EFI_ERROR (Status)) { > + // > + // The HDD is in locked state, unlock it by user input. > + // > + if (!PasswordIsFullZero (Password)) { > + if (!ConfigFormEntry->IfrData.SecurityStatus.Frozen) { > + Status =3D UnlockHddPassword (AtaPassThru, Port, PortMultipl= ierPort, > 0, Password); > + } else { > + // > + // Use saved HDD password variable to validate HDD password > + // when the device is at frozen state. > + // > + Status =3D ValidateHddPassword (ConfigFormEntry, Password); > + } > + } else { > + Status =3D EFI_INVALID_PARAMETER; > + } > + if (!EFI_ERROR (Status)) { > + CopyMem (ConfigFormEntry->Password, Password, > HDD_PASSWORD_MAX_LENGTH); > + if (!ConfigFormEntry->IfrData.SecurityStatus.Frozen) { > + SaveHddPasswordVariable (ConfigFormEntry, Password); > + } > + ZeroMem (Password, HDD_PASSWORD_MAX_LENGTH); > + Status =3D GetHddDeviceIdentifyData (AtaPassThru, Port, > PortMultiplierPort, &IdentifyData); > + ASSERT_EFI_ERROR (Status); > + > + // > + // Check the device security status again. > + // > + GetHddPasswordSecurityStatus (&IdentifyData, &ConfigFormEntry- > >IfrData); > + return; > + } > + > + ZeroMem (Password, HDD_PASSWORD_MAX_LENGTH); > + > + if (EFI_ERROR (Status)) { > + RetryCount ++; > + if (RetryCount < MAX_HDD_PASSWORD_RETRY_COUNT) { > + do { > + CreatePopUp ( > + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, > + &Key, > + L"Invalid password.", > + L"Press ENTER to retry", > + NULL > + ); > + } while (Key.UnicodeChar !=3D CHAR_CARRIAGE_RETURN); > + continue; > + } else { > + do { > + CreatePopUp ( > + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, > + &Key, > + L"Hdd password retry count is expired. Please shutdown t= he > machine.", > + L"Press ENTER to shutdown", > + NULL > + ); > + } while (Key.UnicodeChar !=3D CHAR_CARRIAGE_RETURN); > + gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL); > + break; > + } > + } > + } else if (Status =3D=3D EFI_ABORTED) { > + if (ConfigFormEntry->IfrData.SecurityStatus.Locked) { > + // > + // Current device in the lock status and > + // User not input password and press ESC, > + // keep device in lock status and continue boot. > + // > + do { > + CreatePopUp ( > + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, > + &Key, > + L"Press ENTER to skip the request and continue boot,", > + L"Press ESC to input password again", > + NULL > + ); > + } while ((Key.ScanCode !=3D SCAN_ESC) && (Key.UnicodeChar !=3D > CHAR_CARRIAGE_RETURN)); > + > + if (Key.UnicodeChar =3D=3D CHAR_CARRIAGE_RETURN) { > + gST->ConOut->ClearScreen(gST->ConOut); > + // > + // Keep lock and continue boot. > + // > + return; > + } else { > + // > + // Let user input password again. > + // > + continue; > + } > + } else { > + // > + // Current device in the unlock status and > + // User not input password and press ESC, > + // Shutdown the device. > + // > + do { > + CreatePopUp ( > + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, > + &Key, > + L"Press ENTER to shutdown, Press ESC to input password aga= in", > + NULL > + ); > + } while ((Key.ScanCode !=3D SCAN_ESC) && (Key.UnicodeChar !=3D > CHAR_CARRIAGE_RETURN)); > + > + if (Key.UnicodeChar =3D=3D CHAR_CARRIAGE_RETURN) { > + gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL); > + } else { > + // > + // Let user input password again. > + // > + continue; > + } > + } > + } > + } > + } > +} > + > +/** > + Process Set User Pwd HDD password request. > + > + @param[in] AtaPassThru Pointer to ATA_PASSTHRU instance. > + @param[in] Port The port number of attached ATA devi= ce. > + @param[in] PortMultiplierPort The port number of port multiplier o= f > attached ATA device. > + @param[in] ConfigFormEntry The HDD Password configuration form > entry. > + > +**/ > +VOID > +ProcessHddPasswordRequestSetUserPwd ( > + IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru, > + IN UINT16 Port, > + IN UINT16 PortMultiplierPort, > + IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry > + ) > +{ > + EFI_STATUS Status; > + CHAR16 PopUpString[100]; > + ATA_IDENTIFY_DATA IdentifyData; > + EFI_INPUT_KEY Key; > + UINT16 RetryCount; > + CHAR8 Password[HDD_PASSWORD_MAX_LENGTH]; > + CHAR8 PasswordConfirm[HDD_PASSWORD_MAX_LEN= GTH]; > + > + RetryCount =3D 0; > + > + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__)); > + > + if (ConfigFormEntry->IfrData.SecurityStatus.Frozen) { > + DEBUG ((DEBUG_INFO, "%s is frozen, do nothing\n", ConfigFormEntry- > >HddString)); > + return; > + } > + > + if (ConfigFormEntry->IfrData.SecurityStatus.Locked) { > + DEBUG ((DEBUG_INFO, "%s is locked, do nothing\n", ConfigFormEntry- > >HddString)); > + return; > + } > + > + UnicodeSPrint (PopUpString, sizeof (PopUpString), L"Set User Pwd: %s", > ConfigFormEntry->HddString); > + > + // > + // Check the device security status. > + // > + if (ConfigFormEntry->IfrData.SecurityStatus.Supported) { > + while (TRUE) { > + Status =3D PopupHddPasswordInputWindows (PopUpString, L"Please typ= e > in your new password", Password); > + if (!EFI_ERROR (Status)) { > + Status =3D PopupHddPasswordInputWindows (PopUpString, L"Please > confirm your new password", PasswordConfirm); > + if (!EFI_ERROR (Status)) { > + if (CompareMem (Password, PasswordConfirm, > HDD_PASSWORD_MAX_LENGTH) =3D=3D 0) { > + if (!PasswordIsFullZero (Password)) { > + Status =3D SetHddPassword (AtaPassThru, Port, PortMultipli= erPort, 0, 1, > 0, Password); > + } else { > + if (ConfigFormEntry->IfrData.SecurityStatus.Enabled) { > + Status =3D DisableHddPassword (AtaPassThru, Port, > PortMultiplierPort, 0, ConfigFormEntry->Password); > + } else { > + Status =3D EFI_INVALID_PARAMETER; > + } > + } > + if (!EFI_ERROR (Status)) { > + CopyMem (ConfigFormEntry->Password, Password, > HDD_PASSWORD_MAX_LENGTH); > + SaveHddPasswordVariable (ConfigFormEntry, Password); > + ZeroMem (Password, HDD_PASSWORD_MAX_LENGTH); > + ZeroMem (PasswordConfirm, HDD_PASSWORD_MAX_LENGTH); > + Status =3D GetHddDeviceIdentifyData (AtaPassThru, Port, > PortMultiplierPort, &IdentifyData); > + ASSERT_EFI_ERROR (Status); > + > + // > + // Check the device security status again. > + // > + GetHddPasswordSecurityStatus (&IdentifyData, &ConfigFormEn= try- > >IfrData); > + return; > + } else { > + do { > + CreatePopUp ( > + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, > + &Key, > + L"Set/Disable User Pwd failed or invalid password.", > + L"Press ENTER to retry", > + NULL > + ); > + } while (Key.UnicodeChar !=3D CHAR_CARRIAGE_RETURN); > + } > + } else { > + do { > + CreatePopUp ( > + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, > + &Key, > + L"Passwords are not the same.", > + L"Press ENTER to retry", > + NULL > + ); > + } while (Key.UnicodeChar !=3D CHAR_CARRIAGE_RETURN); > + Status =3D EFI_INVALID_PARAMETER; > + } > + } > + > + ZeroMem (Password, HDD_PASSWORD_MAX_LENGTH); > + ZeroMem (PasswordConfirm, HDD_PASSWORD_MAX_LENGTH); > + > + if (EFI_ERROR (Status)) { > + RetryCount ++; > + if (RetryCount >=3D MAX_HDD_PASSWORD_RETRY_COUNT) { > + do { > + CreatePopUp ( > + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, > + &Key, > + L"Hdd password retry count is expired.", > + L"Press ENTER to skip the request and continue boot", > + NULL > + ); > + } while (Key.UnicodeChar !=3D CHAR_CARRIAGE_RETURN); > + gST->ConOut->ClearScreen(gST->ConOut); > + return; > + } > + } > + } else if (Status =3D=3D EFI_ABORTED) { > + do { > + CreatePopUp ( > + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, > + &Key, > + L"Press ENTER to skip the request and continue boot,", > + L"Press ESC to input password again", > + NULL > + ); > + } while ((Key.ScanCode !=3D SCAN_ESC) && (Key.UnicodeChar !=3D > CHAR_CARRIAGE_RETURN)); > + > + if (Key.UnicodeChar =3D=3D CHAR_CARRIAGE_RETURN) { > + gST->ConOut->ClearScreen(gST->ConOut); > + return; > + } else { > + // > + // Let user input password again. > + // > + continue; > + } > + } > + } > + } > +} > + > +/** > + Process Set Master Pwd HDD password request. > + > + @param[in] AtaPassThru Pointer to ATA_PASSTHRU instance. > + @param[in] Port The port number of attached ATA devi= ce. > + @param[in] PortMultiplierPort The port number of port multiplier o= f > attached ATA device. > + @param[in] ConfigFormEntry The HDD Password configuration form > entry. > + > +**/ > +VOID > +ProcessHddPasswordRequestSetMasterPwd ( > + IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru, > + IN UINT16 Port, > + IN UINT16 PortMultiplierPort, > + IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry > + ) > +{ > + EFI_STATUS Status; > + CHAR16 PopUpString[100]; > + EFI_INPUT_KEY Key; > + UINT16 RetryCount; > + CHAR8 Password[HDD_PASSWORD_MAX_LENGTH]; > + CHAR8 PasswordConfirm[HDD_PASSWORD_MAX_LEN= GTH]; > + > + RetryCount =3D 0; > + > + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__)); > + > + if (ConfigFormEntry->IfrData.SecurityStatus.Frozen) { > + DEBUG ((DEBUG_INFO, "%s is frozen, do nothing\n", ConfigFormEntry- > >HddString)); > + return; > + } > + > + if (ConfigFormEntry->IfrData.SecurityStatus.Locked) { > + DEBUG ((DEBUG_INFO, "%s is locked, do nothing\n", ConfigFormEntry- > >HddString)); > + return; > + } > + > + UnicodeSPrint (PopUpString, sizeof (PopUpString), L"Set Master Pwd: %s= ", > ConfigFormEntry->HddString); > + > + // > + // Check the device security status. > + // > + if (ConfigFormEntry->IfrData.SecurityStatus.Supported) { > + while (TRUE) { > + Status =3D PopupHddPasswordInputWindows (PopUpString, L"Please typ= e > in your new password", Password); > + if (!EFI_ERROR (Status)) { > + Status =3D PopupHddPasswordInputWindows (PopUpString, L"Please > confirm your new password", PasswordConfirm); > + if (!EFI_ERROR (Status)) { > + if (CompareMem (Password, PasswordConfirm, > HDD_PASSWORD_MAX_LENGTH) =3D=3D 0) { > + if (!PasswordIsFullZero (Password)) { > + Status =3D SetHddPassword (AtaPassThru, Port, PortMultipli= erPort, 1, 1, > 1, Password); > + } else { > + Status =3D EFI_INVALID_PARAMETER; > + } > + if (!EFI_ERROR (Status)) { > + ZeroMem (Password, HDD_PASSWORD_MAX_LENGTH); > + ZeroMem (PasswordConfirm, HDD_PASSWORD_MAX_LENGTH); > + return; > + } else { > + do { > + CreatePopUp ( > + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, > + &Key, > + L"Set Master Pwd failed or invalid password.", > + L"Press ENTER to retry", > + NULL > + ); > + } while (Key.UnicodeChar !=3D CHAR_CARRIAGE_RETURN); > + } > + } else { > + do { > + CreatePopUp ( > + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, > + &Key, > + L"Passwords are not the same.", > + L"Press ENTER to retry", > + NULL > + ); > + } while (Key.UnicodeChar !=3D CHAR_CARRIAGE_RETURN); > + Status =3D EFI_INVALID_PARAMETER; > + } > + } > + > + ZeroMem (Password, HDD_PASSWORD_MAX_LENGTH); > + ZeroMem (PasswordConfirm, HDD_PASSWORD_MAX_LENGTH); > + > + if (EFI_ERROR (Status)) { > + RetryCount ++; > + if (RetryCount >=3D MAX_HDD_PASSWORD_RETRY_COUNT) { > + do { > + CreatePopUp ( > + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, > + &Key, > + L"Hdd password retry count is expired.", > + L"Press ENTER to skip the request and continue boot", > + NULL > + ); > + } while (Key.UnicodeChar !=3D CHAR_CARRIAGE_RETURN); > + gST->ConOut->ClearScreen(gST->ConOut); > + return; > + } > + } > + } else if (Status =3D=3D EFI_ABORTED) { > + do { > + CreatePopUp ( > + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, > + &Key, > + L"Press ENTER to skip the request and continue boot,", > + L"Press ESC to input password again", > + NULL > + ); > + } while ((Key.ScanCode !=3D SCAN_ESC) && (Key.UnicodeChar !=3D > CHAR_CARRIAGE_RETURN)); > + > + if (Key.UnicodeChar =3D=3D CHAR_CARRIAGE_RETURN) { > + gST->ConOut->ClearScreen(gST->ConOut); > + return; > + } else { > + // > + // Let user input password again. > + // > + continue; > + } > + } > + } > + } > +} > + > +/** > + Process HDD password request. > + > + @param[in] AtaPassThru Pointer to ATA_PASSTHRU instance. > + @param[in] Port The port number of attached ATA devi= ce. > + @param[in] PortMultiplierPort The port number of port multiplier o= f > attached ATA device. > + @param[in] ConfigFormEntry The HDD Password configuration form > entry. > + > +**/ > +VOID > +ProcessHddPasswordRequest ( > + IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru, > + IN UINT16 Port, > + IN UINT16 PortMultiplierPort, > + IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry > + ) > +{ > + EFI_STATUS Status; > + HDD_PASSWORD_REQUEST_VARIABLE *TempVariable; > + HDD_PASSWORD_REQUEST_VARIABLE *Variable; > + UINTN VariableSize; > + > + DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__)); > + > + if (mHddPasswordRequestVariable =3D=3D NULL) { > + Status =3D GetVariable2 ( > + HDD_PASSWORD_REQUEST_VARIABLE_NAME, > + &mHddPasswordVendorGuid, > + (VOID **) &Variable, > + &VariableSize > + ); > + if (EFI_ERROR (Status) || (Variable =3D=3D NULL)) { > + return; > + } > + mHddPasswordRequestVariable =3D Variable; > + mHddPasswordRequestVariableSize =3D VariableSize; > + > + // > + // Delete the HDD password request variable. > + // > + Status =3D gRT->SetVariable ( > + HDD_PASSWORD_REQUEST_VARIABLE_NAME, > + &mHddPasswordVendorGuid, > + 0, > + 0, > + NULL > + ); > + ASSERT_EFI_ERROR (Status); > + } else { > + Variable =3D mHddPasswordRequestVariable; > + VariableSize =3D mHddPasswordRequestVariableSize; > + } > + > + // > + // Process the HDD password requests. > + // > + TempVariable =3D Variable; > + while (VariableSize >=3D sizeof (HDD_PASSWORD_REQUEST_VARIABLE)) { > + if ((TempVariable->Device.Bus =3D=3D ConfigFormEntry-= >Bus) && > + (TempVariable->Device.Device =3D=3D ConfigFormEntry-= >Device) && > + (TempVariable->Device.Function =3D=3D ConfigFormEntry-= >Function) > && > + (TempVariable->Device.Port =3D=3D ConfigFormEntry-= >Port) && > + (TempVariable->Device.PortMultiplierPort =3D=3D ConfigFormEntry- > >PortMultiplierPort)) { > + // > + // Found the node for the HDD password device. > + // > + if (TempVariable->Request.UserPassword !=3D 0) { > + ProcessHddPasswordRequestSetUserPwd (AtaPassThru, Port, > PortMultiplierPort, ConfigFormEntry); > + } > + if (TempVariable->Request.MasterPassword !=3D 0) { > + ProcessHddPasswordRequestSetMasterPwd (AtaPassThru, Port, > PortMultiplierPort, ConfigFormEntry); > + } > + > + break; > + } > + > + VariableSize -=3D sizeof (HDD_PASSWORD_REQUEST_VARIABLE); > + TempVariable +=3D 1; > + } > + > + DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__)); > +} > + > +/** > + Get saved HDD password request. > + > + @param[in, out] ConfigFormEntry The HDD Password configuration > form entry. > + > +**/ > +VOID > +GetSavedHddPasswordRequest ( > + IN OUT HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry > + ) > +{ > + EFI_STATUS Status; > + HDD_PASSWORD_REQUEST_VARIABLE *TempVariable; > + HDD_PASSWORD_REQUEST_VARIABLE *Variable; > + UINTN VariableSize; > + > + DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__)); > + > + Variable =3D NULL; > + VariableSize =3D 0; > + > + Status =3D GetVariable2 ( > + HDD_PASSWORD_REQUEST_VARIABLE_NAME, > + &mHddPasswordVendorGuid, > + (VOID **) &Variable, > + &VariableSize > + ); > + if (EFI_ERROR (Status) || (Variable =3D=3D NULL)) { > + return; > + } > + > + TempVariable =3D Variable; > + while (VariableSize >=3D sizeof (HDD_PASSWORD_REQUEST_VARIABLE)) { > + if ((TempVariable->Device.Bus =3D=3D ConfigFormEntry-= >Bus) && > + (TempVariable->Device.Device =3D=3D ConfigFormEntry-= >Device) && > + (TempVariable->Device.Function =3D=3D ConfigFormEntry-= >Function) > && > + (TempVariable->Device.Port =3D=3D ConfigFormEntry-= >Port) && > + (TempVariable->Device.PortMultiplierPort =3D=3D ConfigFormEntry- > >PortMultiplierPort)) { > + // > + // Found the node for the HDD password device. > + // Get the HDD password request. > + // > + CopyMem (&ConfigFormEntry->IfrData.Request, &TempVariable- > >Request, sizeof (HDD_PASSWORD_REQUEST)); > + DEBUG (( > + DEBUG_INFO, > + "HddPasswordRequest got: 0x%x\n", > + ConfigFormEntry->IfrData.Request > + )); > + break; > + } > + VariableSize -=3D sizeof (HDD_PASSWORD_REQUEST_VARIABLE); > + TempVariable +=3D 1; > + } > + > + FreePool (Variable); > + > + DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__)); > +} > + > +/** > + Save HDD password request. > + > + @param[in] ConfigFormEntry The HDD Password configuration form > entry. > + > +**/ > +VOID > +SaveHddPasswordRequest ( > + IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry > + ) > +{ > + EFI_STATUS Status; > + HDD_PASSWORD_REQUEST_VARIABLE *TempVariable; > + UINTN TempVariableSize; > + HDD_PASSWORD_REQUEST_VARIABLE *Variable; > + UINTN VariableSize; > + HDD_PASSWORD_REQUEST_VARIABLE *NewVariable; > + UINTN NewVariableSize; > + > + DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__)); > + > + DEBUG (( > + DEBUG_INFO, > + "HddPasswordRequest to save: 0x%x\n", > + ConfigFormEntry->IfrData.Request > + )); > + > + Variable =3D NULL; > + VariableSize =3D 0; > + NewVariable =3D NULL; > + NewVariableSize =3D 0; > + > + Status =3D GetVariable2 ( > + HDD_PASSWORD_REQUEST_VARIABLE_NAME, > + &mHddPasswordVendorGuid, > + (VOID **) &Variable, > + &VariableSize > + ); > + if (!EFI_ERROR (Status) && (Variable !=3D NULL)) { > + TempVariable =3D Variable; > + TempVariableSize =3D VariableSize; > + while (TempVariableSize >=3D sizeof > (HDD_PASSWORD_REQUEST_VARIABLE)) { > + if ((TempVariable->Device.Bus =3D=3D ConfigFormEntr= y->Bus) && > + (TempVariable->Device.Device =3D=3D ConfigFormEntr= y->Device) && > + (TempVariable->Device.Function =3D=3D ConfigFormEntr= y->Function) > && > + (TempVariable->Device.Port =3D=3D ConfigFormEntr= y->Port) && > + (TempVariable->Device.PortMultiplierPort =3D=3D ConfigFormEntr= y- > >PortMultiplierPort)) { > + // > + // Found the node for the HDD password device. > + // Update the HDD password request. > + // > + CopyMem (&TempVariable->Request, &ConfigFormEntry- > >IfrData.Request, sizeof (HDD_PASSWORD_REQUEST)); > + NewVariable =3D Variable; > + NewVariableSize =3D VariableSize; > + break; > + } > + TempVariableSize -=3D sizeof (HDD_PASSWORD_REQUEST_VARIABLE); > + TempVariable +=3D 1; > + } > + if (NewVariable =3D=3D NULL) { > + // > + // The node for the HDD password device is not found. > + // Create node for the HDD password device. > + // > + NewVariableSize =3D VariableSize + sizeof > (HDD_PASSWORD_REQUEST_VARIABLE); > + NewVariable =3D AllocateZeroPool (NewVariableSize); > + ASSERT (NewVariable !=3D NULL); > + CopyMem (NewVariable, Variable, VariableSize); > + TempVariable =3D (HDD_PASSWORD_REQUEST_VARIABLE *) ((UINTN) > NewVariable + VariableSize); > + TempVariable->Device.Bus =3D (UINT8) ConfigFormEntr= y->Bus; > + TempVariable->Device.Device =3D (UINT8) ConfigFormEntr= y->Device; > + TempVariable->Device.Function =3D (UINT8) ConfigFormEntr= y- > >Function; > + TempVariable->Device.Port =3D ConfigFormEntry->Port; > + TempVariable->Device.PortMultiplierPort =3D ConfigFormEntry- > >PortMultiplierPort; > + CopyMem (&TempVariable->Request, &ConfigFormEntry- > >IfrData.Request, sizeof (HDD_PASSWORD_REQUEST)); > + } > + } else { > + NewVariableSize =3D sizeof (HDD_PASSWORD_REQUEST_VARIABLE); > + NewVariable =3D AllocateZeroPool (NewVariableSize); > + ASSERT (NewVariable !=3D NULL); > + NewVariable->Device.Bus =3D (UINT8) ConfigFormEntry->= Bus; > + NewVariable->Device.Device =3D (UINT8) ConfigFormEntry->= Device; > + NewVariable->Device.Function =3D (UINT8) ConfigFormEntry- > >Function; > + NewVariable->Device.Port =3D ConfigFormEntry->Port; > + NewVariable->Device.PortMultiplierPort =3D ConfigFormEntry- > >PortMultiplierPort; > + CopyMem (&NewVariable->Request, &ConfigFormEntry- > >IfrData.Request, sizeof (HDD_PASSWORD_REQUEST)); > + } > + Status =3D gRT->SetVariable ( > + HDD_PASSWORD_REQUEST_VARIABLE_NAME, > + &mHddPasswordVendorGuid, > + EFI_VARIABLE_NON_VOLATILE | > EFI_VARIABLE_BOOTSERVICE_ACCESS, > + NewVariableSize, > + NewVariable > + ); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_INFO, "HddPasswordRequest variable set failed (%r)\n", > Status)); > + } > + if (NewVariable !=3D Variable) { > + FreePool (NewVariable); > + } > + if (Variable !=3D NULL) { > + FreePool (Variable); > + } > + > + DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__)); > +} > + > +/** > + Get the HDD Password configuration form entry by the index of the goto > opcode actived. > + > + @param[in] Index The 0-based index of the goto opcode actived. > + > + @return The HDD Password configuration form entry found. > +**/ > +HDD_PASSWORD_CONFIG_FORM_ENTRY * > +HddPasswordGetConfigFormEntryByIndex ( > + IN UINT32 Index > + ) > +{ > + LIST_ENTRY *Entry; > + UINT32 CurrentIndex; > + HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry; > + > + CurrentIndex =3D 0; > + ConfigFormEntry =3D NULL; > + > + EFI_LIST_FOR_EACH (Entry, &mHddPasswordConfigFormList) { > + if (CurrentIndex =3D=3D Index) { > + ConfigFormEntry =3D BASE_CR (Entry, > HDD_PASSWORD_CONFIG_FORM_ENTRY, Link); > + break; > + } > + > + CurrentIndex++; > + } > + > + return ConfigFormEntry; > +} > + > +/** > + This function allows the caller to request the current > + configuration for one or more named elements. The resulting > + string is in format. Any and all alternative > + configuration strings shall also be appended to the end of the > + current configuration string. If they are, they must appear > + after the current configuration. They must contain the same > + routing (GUID, NAME, PATH) as the current configuration string. > + They must have an additional description indicating the type of > + alternative configuration the string represents, > + "ALTCFG=3D". That (when > + converted from Hex UNICODE to binary) is a reference to a > + string in the associated string pack. > + > + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. > + @param[in] Request A null-terminated Unicode string in > + format. Note that this > + includes the routing information as well as > + the configurable name / value pairs. It is > + invalid for this string to be in > + format. > + @param[out] 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[out] 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 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 Request parameter > + would result in this type of > + error. In this case, the > + Progress parameter would be > + set to NULL. > + @retval EFI_NOT_FOUND Routing data doesn't match any > + known driver. Progress set to the > + first character in the routing header. > + Note: There is no requirement that the > + driver validate the routing data. It > + must skip the in order to > + process the names. > + @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.Currently not implemented. > +**/ > +EFI_STATUS > +EFIAPI > +HddPasswordFormExtractConfig ( > + 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; > + HDD_PASSWORD_CONFIG *IfrData; > + HDD_PASSWORD_DXE_PRIVATE_DATA *Private; > + EFI_STRING ConfigRequestHdr; > + EFI_STRING ConfigRequest; > + BOOLEAN AllocatedRequest; > + UINTN Size; > + > + if (Progress =3D=3D NULL || Results =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + *Progress =3D Request; > + if ((Request !=3D NULL) && !HiiIsConfigHdrMatch (Request, > &mHddPasswordVendorGuid, mHddPasswordVendorStorageName)) { > + return EFI_NOT_FOUND; > + } > + > + ConfigRequestHdr =3D NULL; > + ConfigRequest =3D NULL; > + AllocatedRequest =3D FALSE; > + Size =3D 0; > + > + Private =3D HDD_PASSWORD_DXE_PRIVATE_FROM_THIS (This); > + IfrData =3D AllocateZeroPool (sizeof (HDD_PASSWORD_CONFIG)); > + ASSERT (IfrData !=3D NULL); > + if (Private->Current !=3D NULL) { > + CopyMem (IfrData, &Private->Current->IfrData, sizeof > (HDD_PASSWORD_CONFIG)); > + } > + > + // > + // Convert buffer data to by helper function BlockToConfi= g() > + // > + BufferSize =3D sizeof (HDD_PASSWORD_CONFIG); > + ConfigRequest =3D Request; > + if ((Request =3D=3D NULL) || (StrStr (Request, L"OFFSET") =3D=3D NULL)= ) { > + // > + // Request has no request element, construct full request string. > + // Allocate and fill a buffer large enough to hold the > template > + // followed by "&OFFSET=3D0&WIDTH=3DWWWWWWWWWWWWWWWW" > followed by a Null-terminator > + // > + ConfigRequestHdr =3D HiiConstructConfigHdr (&mHddPasswordVendorGuid, > mHddPasswordVendorStorageName, Private->DriverHandle); > + Size =3D (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16); > + ConfigRequest =3D AllocateZeroPool (Size); > + ASSERT (ConfigRequest !=3D NULL); > + AllocatedRequest =3D TRUE; > + UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=3D0&WIDTH=3D%016LX", > ConfigRequestHdr, (UINT64)BufferSize); > + FreePool (ConfigRequestHdr); > + } > + Status =3D gHiiConfigRouting->BlockToConfig ( > + gHiiConfigRouting, > + ConfigRequest, > + (UINT8 *) IfrData, > + BufferSize, > + Results, > + Progress > + ); > + FreePool (IfrData); > + // > + // Free the allocated config request string. > + // > + if (AllocatedRequest) { > + FreePool (ConfigRequest); > + ConfigRequest =3D NULL; > + } > + > + // > + // Set Progress string to the original request string. > + // > + if (Request =3D=3D NULL) { > + *Progress =3D NULL; > + } else if (StrStr (Request, L"OFFSET") =3D=3D NULL) { > + *Progress =3D Request + StrLen (Request); > + } > + > + return Status; > +} > + > +/** > + This function applies changes in a driver's configuration. > + Input is a Configuration, which has the routing data for this > + driver followed by name / value configuration pairs. The driver > + must apply those pairs to its configurable storage. If the > + driver's configuration is stored in a linear block of data > + and the driver's name / value pairs are in > + format, it may use the ConfigToBlock helper function (above) to > + simplify the job. Currently not implemented. > + > + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCO= L. > + @param[in] Configuration A null-terminated Unicode string in > + format. > + @param[out] Progress A pointer to a string filled in with the > + offset of the most recent '&' before the > + first failing name / value pair (or the > + beginn ing 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 a= re > + 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_PARAMETERS Passing in a NULL for the > + Results parameter would result > + in this type of error. > + @retval EFI_NOT_FOUND Target for the specified routing data > + was not found. > +**/ > +EFI_STATUS > +EFIAPI > +HddPasswordFormRouteConfig ( > + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, > + IN CONST EFI_STRING Configuration, > + OUT EFI_STRING *Progress > + ) > +{ > + if (Configuration =3D=3D NULL || Progress =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Check routing data in . > + // Note: if only one Storage is used, then this checking could be skip= ped. > + // > + if (!HiiIsConfigHdrMatch (Configuration, &mHddPasswordVendorGuid, > mHddPasswordVendorStorageName)) { > + *Progress =3D Configuration; > + return EFI_NOT_FOUND; > + } > + > + *Progress =3D Configuration + StrLen (Configuration); > + return EFI_SUCCESS; > +} > + > +/** > + This function is called to provide results data to the driver. > + This data consists of a unique key that is used to identify > + which data is either being passed back or being asked for. > + > + @param[in] This Points to the > EFI_HII_CONFIG_ACCESS_PROTOCOL. > + @param[in] Action Specifies the type of action taken by t= he browser. > + @param[in] QuestionId A unique value which is sent to the ori= ginal > + exporting driver so that it can identif= y the type > + of data to expect. The format of the da= ta tends to > + vary based on the opcode that enerated = the callback. > + @param[in] Type The type of value for the question. > + @param[in] Value A pointer to the data being sent to the= original > + exporting driver. > + @param[out] ActionRequest On return, points to the action request= ed > by the > + callback function. > + > + @retval EFI_SUCCESS The callback successfully handled the a= ction. > + @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 b= y > the > + callback.Currently not implemented. > + @retval EFI_INVALID_PARAMETERS Passing in wrong parameter. > + @retval Others Other errors as indicated. > +**/ > +EFI_STATUS > +EFIAPI > +HddPasswordFormCallback ( > + 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 > + ) > +{ > + HDD_PASSWORD_DXE_PRIVATE_DATA *Private; > + EFI_STRING_ID DeviceFormTitleToken; > + HDD_PASSWORD_CONFIG *IfrData; > + HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry; > + > + if (ActionRequest !=3D NULL) { > + *ActionRequest =3D EFI_BROWSER_ACTION_REQUEST_NONE; > + } else { > + return EFI_INVALID_PARAMETER; > + } > + > + if ((Action !=3D EFI_BROWSER_ACTION_CHANGING) && (Action !=3D > EFI_BROWSER_ACTION_CHANGED)) { > + // > + // Do nothing for other UEFI Action. Only do call back when data is > changing or changed. > + // > + return EFI_UNSUPPORTED; > + } > + > + Private =3D HDD_PASSWORD_DXE_PRIVATE_FROM_THIS (This); > + > + // > + // Retrive data from Browser > + // > + IfrData =3D AllocateZeroPool (sizeof (HDD_PASSWORD_CONFIG)); > + ASSERT (IfrData !=3D NULL); > + if (!HiiGetBrowserData (&mHddPasswordVendorGuid, > mHddPasswordVendorStorageName, sizeof (HDD_PASSWORD_CONFIG), > (UINT8 *) IfrData)) { > + FreePool (IfrData); > + return EFI_NOT_FOUND; > + } > + > + switch (QuestionId) { > + case KEY_HDD_USER_PASSWORD: > + if (Action =3D=3D EFI_BROWSER_ACTION_CHANGED) { > + DEBUG ((DEBUG_INFO, "KEY_HDD_USER_PASSWORD\n")); > + ConfigFormEntry =3D Private->Current; > + ConfigFormEntry->IfrData.Request.UserPassword =3D Value->b; > + SaveHddPasswordRequest (ConfigFormEntry); > + *ActionRequest =3D EFI_BROWSER_ACTION_REQUEST_FORM_APPLY; > + } > + break; > + case KEY_HDD_MASTER_PASSWORD: > + if (Action =3D=3D EFI_BROWSER_ACTION_CHANGED) { > + DEBUG ((DEBUG_INFO, "KEY_HDD_MASTER_PASSWORD\n")); > + ConfigFormEntry =3D Private->Current; > + ConfigFormEntry->IfrData.Request.MasterPassword =3D Value->b; > + SaveHddPasswordRequest (ConfigFormEntry); > + *ActionRequest =3D EFI_BROWSER_ACTION_REQUEST_FORM_APPLY; > + } > + break; > + > + default: > + if ((QuestionId >=3D KEY_HDD_DEVICE_ENTRY_BASE) && (QuestionId < > (mNumberOfHddDevices + KEY_HDD_DEVICE_ENTRY_BASE))) { > + if (Action =3D=3D EFI_BROWSER_ACTION_CHANGING) { > + // > + // In case goto the device configuration form, update the device= form > title. > + // > + ConfigFormEntry =3D HddPasswordGetConfigFormEntryByIndex ((UINT3= 2) > (QuestionId - KEY_HDD_DEVICE_ENTRY_BASE)); > + ASSERT (ConfigFormEntry !=3D NULL); > + > + DeviceFormTitleToken =3D (EFI_STRING_ID) STR_HDD_SECURITY_HD; > + HiiSetString (Private->HiiHandle, DeviceFormTitleToken, > ConfigFormEntry->HddString, NULL); > + > + Private->Current =3D ConfigFormEntry; > + CopyMem (IfrData, &ConfigFormEntry->IfrData, sizeof > (HDD_PASSWORD_CONFIG)); > + } > + } > + > + break; > + } > + > + // > + // Pass changed uncommitted data back to Form Browser > + // > + HiiSetBrowserData (&mHddPasswordVendorGuid, > mHddPasswordVendorStorageName, sizeof (HDD_PASSWORD_CONFIG), > (UINT8 *) IfrData, NULL); > + > + FreePool (IfrData); > + return EFI_SUCCESS; > +} > + > +/** > + Updates the HDD Password configuration form to add an entry for the > attached > + ata harddisk device specified by the Controller. > + > + @param[in] HiiHandle The HII Handle associated with the reg= istered > package list. > + @param[in] AtaPassThru Pointer to ATA_PASSTHRU instance. > + @param[in] PciIo Pointer to PCI_IO instance. > + @param[in] Controller The controller handle of the attached = ata > controller. > + @param[in] Bus The bus number of ATA controller. > + @param[in] Device The device number of ATA controller. > + @param[in] Function The function number of ATA controller. > + @param[in] Port The port number of attached ATA device= . > + @param[in] PortMultiplierPort The port number of port multiplier of > attached ATA device. > + > + @retval EFI_SUCCESS The Hdd Password configuration form is > updated. > + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. > + @retval Others Other errors as indicated. > + > +**/ > +EFI_STATUS > +HddPasswordConfigUpdateForm ( > + IN EFI_HII_HANDLE HiiHandle, > + IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru, > + IN EFI_PCI_IO_PROTOCOL *PciIo, > + IN EFI_HANDLE Controller, > + IN UINTN Bus, > + IN UINTN Device, > + IN UINTN Function, > + IN UINT16 Port, > + IN UINT16 PortMultiplierPort > + ) > +{ > + LIST_ENTRY *Entry; > + HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry; > + BOOLEAN EntryExisted; > + EFI_STATUS Status; > + VOID *StartOpCodeHandle; > + VOID *EndOpCodeHandle; > + EFI_IFR_GUID_LABEL *StartLabel; > + EFI_IFR_GUID_LABEL *EndLabel; > + CHAR16 HddString[40]; > + ATA_IDENTIFY_DATA IdentifyData; > + EFI_DEVICE_PATH_PROTOCOL *AtaDeviceNode; > + > + ConfigFormEntry =3D NULL; > + EntryExisted =3D FALSE; > + > + EFI_LIST_FOR_EACH (Entry, &mHddPasswordConfigFormList) { > + ConfigFormEntry =3D BASE_CR (Entry, > HDD_PASSWORD_CONFIG_FORM_ENTRY, Link); > + > + if ((ConfigFormEntry->Bus =3D=3D Bus) && > + (ConfigFormEntry->Device =3D=3D Device) && > + (ConfigFormEntry->Function =3D=3D Function) && > + (ConfigFormEntry->Port =3D=3D Port) && > + (ConfigFormEntry->PortMultiplierPort =3D=3D PortMultiplierPort))= { > + EntryExisted =3D TRUE; > + break; > + } > + } > + > + if (!EntryExisted) { > + // > + // Add a new form. > + // > + ConfigFormEntry =3D AllocateZeroPool (sizeof > (HDD_PASSWORD_CONFIG_FORM_ENTRY)); > + if (ConfigFormEntry =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + InitializeListHead (&ConfigFormEntry->Link); > + ConfigFormEntry->Controller =3D Controller; > + ConfigFormEntry->Bus =3D Bus; > + ConfigFormEntry->Device =3D Device; > + ConfigFormEntry->Function =3D Function; > + ConfigFormEntry->Port =3D Port; > + ConfigFormEntry->PortMultiplierPort =3D PortMultiplierPort; > + ConfigFormEntry->AtaPassThru =3D AtaPassThru; > + > + DEBUG ((DEBUG_INFO, "HddPasswordDxe: Create new form for > device[%d][%d] at Bus 0x%x Dev 0x%x Func 0x%x\n", Port, > PortMultiplierPort, Bus, Device, Function)); > + > + // > + // Construct the device path for the HDD password device > + // > + Status =3D AtaPassThru->BuildDevicePath ( > + AtaPassThru, > + Port, > + PortMultiplierPort, > + &AtaDeviceNode > + ); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + ConfigFormEntry->DevicePath =3D AppendDevicePathNode > (DevicePathFromHandle (Controller), AtaDeviceNode); > + FreePool (AtaDeviceNode); > + if (ConfigFormEntry->DevicePath =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + // > + // Get attached harddisk model number > + // > + Status =3D GetHddDeviceIdentifyData (AtaPassThru, Port, > PortMultiplierPort, &IdentifyData); > + ASSERT_EFI_ERROR (Status); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + GetHddDeviceModelNumber (&IdentifyData, HddString); > + // > + // Compose the HDD title string and help string of this port and cre= ate a > new EFI_STRING_ID. > + // > + UnicodeSPrint (ConfigFormEntry->HddString, sizeof (ConfigFormEntry- > >HddString), L"HDD %d:%s", mNumberOfHddDevices, HddString); > + ConfigFormEntry->TitleToken =3D HiiSetString (HiiHandle, 0, > ConfigFormEntry->HddString, NULL); > + ConfigFormEntry->TitleHelpToken =3D HiiSetString (HiiHandle, 0, L"Re= quest > to set HDD Password", NULL); > + > + GetHddPasswordSecurityStatus (&IdentifyData, &ConfigFormEntry- > >IfrData); > + > + InsertTailList (&mHddPasswordConfigFormList, &ConfigFormEntry->Link)= ; > + > + // > + // Init OpCode Handle > + // > + StartOpCodeHandle =3D HiiAllocateOpCodeHandle (); > + ASSERT (StartOpCodeHandle !=3D NULL); > + > + EndOpCodeHandle =3D HiiAllocateOpCodeHandle (); > + ASSERT (EndOpCodeHandle !=3D NULL); > + > + // > + // Create Hii Extend Label OpCode as the start opcode > + // > + StartLabel =3D (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode > (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof > (EFI_IFR_GUID_LABEL)); > + StartLabel->ExtendOpCode =3D EFI_IFR_EXTEND_OP_LABEL; > + StartLabel->Number =3D HDD_DEVICE_ENTRY_LABEL; > + > + // > + // Create Hii Extend Label OpCode as the end opcode > + // > + EndLabel =3D (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode > (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL)); > + EndLabel->ExtendOpCode =3D EFI_IFR_EXTEND_OP_LABEL; > + EndLabel->Number =3D HDD_DEVICE_LABEL_END; > + > + mNumberOfHddDevices =3D 0; > + EFI_LIST_FOR_EACH (Entry, &mHddPasswordConfigFormList) { > + ConfigFormEntry =3D BASE_CR (Entry, > HDD_PASSWORD_CONFIG_FORM_ENTRY, Link); > + > + HiiCreateGotoOpCode ( > + StartOpCodeHandle, // Container f= or dynamic created > opcodes > + FORMID_HDD_DEVICE_FORM, // Target Form= ID > + ConfigFormEntry->TitleToken, // Prompt text > + ConfigFormEntry->TitleHelpToken, // Help text > + EFI_IFR_FLAG_CALLBACK, // Question fl= ag > + (UINT16) (KEY_HDD_DEVICE_ENTRY_BASE + mNumberOfHddDevices) > // Question ID > + ); > + > + mNumberOfHddDevices++; > + } > + > + HiiUpdateForm ( > + HiiHandle, > + &mHddPasswordVendorGuid, > + FORMID_HDD_MAIN_FORM, > + StartOpCodeHandle, > + EndOpCodeHandle > + ); > + > + HiiFreeOpCodeHandle (StartOpCodeHandle); > + HiiFreeOpCodeHandle (EndOpCodeHandle); > + > + // > + // Check if device is locked and prompt for password. > + // > + HddPasswordRequestPassword (AtaPassThru, Port, PortMultiplierPort, > ConfigFormEntry); > + > + // > + // Process HDD password request from last boot. > + // > + ProcessHddPasswordRequest (AtaPassThru, Port, PortMultiplierPort, > ConfigFormEntry); > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Ata Pass Thru Protocol notification event handler. > + > + Check attached harddisk status to see if it's locked. If yes, then pop= up a > password windows to require user input. > + It also registers a form for user configuration on Hdd password > configuration. > + > + @param[in] Event Event whose notification function is being invoked= . > + @param[in] Context Pointer to the notification function's context. > + > +**/ > +VOID > +EFIAPI > +HddPasswordNotificationEvent ( > + IN EFI_EVENT Event, > + IN VOID *Context > + ) > +{ > + EFI_STATUS Status; > + HDD_PASSWORD_DXE_PRIVATE_DATA *Private; > + EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru; > + UINT16 Port; > + UINT16 PortMultiplierPort; > + EFI_HANDLE Controller; > + EFI_HANDLE *HandleBuffer; > + UINTN HandleCount; > + UINTN Index; > + EFI_PCI_IO_PROTOCOL *PciIo; > + UINTN SegNum; > + UINTN BusNum; > + UINTN DevNum; > + UINTN FuncNum; > + > + if (mHddPasswordEndOfDxe) { > + gBS->CloseEvent (Event); > + return; > + } > + > + Private =3D (HDD_PASSWORD_DXE_PRIVATE_DATA *)Context; > + > + // > + // Locate all handles of AtaPassThru protocol > + // > + Status =3D gBS->LocateHandleBuffer ( > + ByProtocol, > + &gEfiAtaPassThruProtocolGuid, > + NULL, > + &HandleCount, > + &HandleBuffer > + ); > + if (EFI_ERROR (Status)) { > + return ; > + } > + > + // > + // Check attached hard disk status to see if it's locked > + // > + for (Index =3D 0; Index < HandleCount; Index +=3D 1) { > + Controller =3D HandleBuffer[Index]; > + Status =3D gBS->HandleProtocol ( > + Controller, > + &gEfiAtaPassThruProtocolGuid, > + (VOID **) &AtaPassThru > + ); > + if (EFI_ERROR (Status)) { > + break; > + } > + > + // > + // Ignore those logical ATA_PASS_THRU instance. > + // > + if ((AtaPassThru->Mode->Attributes & > EFI_ATA_PASS_THRU_ATTRIBUTES_PHYSICAL) =3D=3D 0) { > + continue; > + } > + > + Status =3D gBS->HandleProtocol ( > + Controller, > + &gEfiPciIoProtocolGuid, > + (VOID **) &PciIo > + ); > + ASSERT_EFI_ERROR (Status); > + if (EFI_ERROR (Status)) { > + break; > + } > + > + Status =3D PciIo->GetLocation ( > + PciIo, > + &SegNum, > + &BusNum, > + &DevNum, > + &FuncNum > + ); > + ASSERT_EFI_ERROR (Status); > + if (EFI_ERROR (Status)) { > + break; > + } > + > + // > + // Assume and only support Segment =3D=3D 0. > + // > + ASSERT (SegNum =3D=3D 0); > + > + // > + // traverse all attached harddisk devices to update form and unlock = it > + // > + Port =3D 0xFFFF; > + > + while (TRUE) { > + Status =3D AtaPassThru->GetNextPort (AtaPassThru, &Port); > + if (EFI_ERROR (Status)) { > + // > + // We cannot find more legal port then we are done. > + // > + break; > + } > + > + PortMultiplierPort =3D 0xFFFF; > + while (TRUE) { > + Status =3D AtaPassThru->GetNextDevice (AtaPassThru, Port, > &PortMultiplierPort); > + if (EFI_ERROR (Status)) { > + // > + // We cannot find more legal port multiplier port number for A= TA > device > + // on the port, then we are done. > + // > + break; > + } > + // > + // Find out the attached harddisk devices. > + // Try to add a HDD Password configuration page for the attached > devices. > + // > + gBS->RestoreTPL (TPL_APPLICATION); > + Status =3D HddPasswordConfigUpdateForm (Private->HiiHandle, > AtaPassThru, PciIo, Controller, BusNum, DevNum, FuncNum, Port, > PortMultiplierPort); > + gBS->RaiseTPL (TPL_CALLBACK); > + if (EFI_ERROR (Status)) { > + break; > + } > + } > + } > + } > + > + FreePool (HandleBuffer); > + return ; > +} > + > +/** > + Initialize the HDD Password configuration form. > + > + @param[out] Instance Pointer to private instance. > + > + @retval EFI_SUCCESS The HDD Password configuration form i= s > initialized. > + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. > + @retval Others Other errors as indicated. > +**/ > +EFI_STATUS > +HddPasswordConfigFormInit ( > + OUT HDD_PASSWORD_DXE_PRIVATE_DATA **Instance > + ) > +{ > + EFI_STATUS Status; > + HDD_PASSWORD_DXE_PRIVATE_DATA *Private; > + > + InitializeListHead (&mHddPasswordConfigFormList); > + > + Private =3D AllocateZeroPool (sizeof > (HDD_PASSWORD_DXE_PRIVATE_DATA)); > + if (Private =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + Private->Signature =3D HDD_PASSWORD_DXE_PRIVATE_SIGNATURE; > + > + Private->ConfigAccess.ExtractConfig =3D HddPasswordFormExtractConfig; > + Private->ConfigAccess.RouteConfig =3D HddPasswordFormRouteConfig; > + Private->ConfigAccess.Callback =3D HddPasswordFormCallback; > + > + // > + // Install Device Path Protocol and Config Access protocol to driver h= andle > + // > + Status =3D gBS->InstallMultipleProtocolInterfaces ( > + &Private->DriverHandle, > + &gEfiDevicePathProtocolGuid, > + &mHddPasswordHiiVendorDevicePath, > + &gEfiHiiConfigAccessProtocolGuid, > + &Private->ConfigAccess, > + NULL > + ); > + ASSERT_EFI_ERROR (Status); > + if (EFI_ERROR (Status)) { > + FreePool(Private); > + return Status; > + } > + > + // > + // Publish our HII data > + // > + Private->HiiHandle =3D HiiAddPackages ( > + &mHddPasswordVendorGuid, > + Private->DriverHandle, > + HddPasswordDxeStrings, > + HddPasswordBin, > + NULL > + ); > + if (Private->HiiHandle =3D=3D NULL) { > + FreePool(Private); > + return EFI_OUT_OF_RESOURCES; > + } > + > + *Instance =3D Private; > + return Status; > +} > + > +/** > + Main entry for this driver. > + > + @param ImageHandle Image handle this driver. > + @param SystemTable Pointer to SystemTable. > + > + @retval EFI_SUCESS This function always complete successfully. > + > +**/ > +EFI_STATUS > +EFIAPI > +HddPasswordDxeInit ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_SYSTEM_TABLE *SystemTable > + ) > +{ > + EFI_STATUS Status; > + HDD_PASSWORD_DXE_PRIVATE_DATA *Private; > + EFI_EVENT Registration; > + EFI_EVENT EndOfDxeEvent; > + EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock; > + > + Private =3D NULL; > + > + // > + // Initialize the configuration form of HDD Password. > + // > + Status =3D HddPasswordConfigFormInit (&Private); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + // > + // Register HddPasswordNotificationEvent() notify function. > + // > + EfiCreateProtocolNotifyEvent ( > + &gEfiAtaPassThruProtocolGuid, > + TPL_CALLBACK, > + HddPasswordNotificationEvent, > + (VOID *)Private, > + &Registration > + ); > + > + Status =3D gBS->CreateEventEx ( > + EVT_NOTIFY_SIGNAL, > + TPL_CALLBACK, > + HddPasswordEndOfDxeEventNotify, > + NULL, > + &gEfiEndOfDxeEventGroupGuid, > + &EndOfDxeEvent > + ); > + ASSERT_EFI_ERROR (Status); > + > + // > + // Make HDD_PASSWORD_VARIABLE_NAME varible read-only. > + // > + Status =3D gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, > (VOID **) &VariableLock); > + if (!EFI_ERROR (Status)) { > + Status =3D VariableLock->RequestToLock ( > + VariableLock, > + HDD_PASSWORD_VARIABLE_NAME, > + &mHddPasswordVendorGuid > + ); > + DEBUG ((DEBUG_INFO, "%a(): Lock %s variable (%r)\n", __FUNCTION__, > HDD_PASSWORD_VARIABLE_NAME, Status)); > + ASSERT_EFI_ERROR (Status); > + } > + > + return Status; > +} > diff --git a/SecurityPkg/HddPassword/HddPasswordPei.c > b/SecurityPkg/HddPassword/HddPasswordPei.c > new file mode 100644 > index 0000000000..3f04f03d0b > --- /dev/null > +++ b/SecurityPkg/HddPassword/HddPasswordPei.c > @@ -0,0 +1,461 @@ > +/** @file > + HddPassword PEI module which is used to unlock HDD password for S3. > + > + Copyright (c) 2019, 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 "HddPasswordPei.h" > + > +EFI_GUID mHddPasswordDeviceInfoGuid =3D > HDD_PASSWORD_DEVICE_INFO_GUID; > + > +/** > + Tell whether the input EDKII_PEI_ATA_PASS_THRU_PPI instance has > already been > + handled by the HddPassword PEI driver. > + > + @param[in] Private Pointer to the HddPassword PEI driver p= rivate > data. > + @param[in] PassThruInstance Pointer to the > EDKII_PEI_ATA_PASS_THRU_PPI. > + > + @retval TRUE The PPI instance has already been handled. > + @retval FALSE The PPI instance has not been handled before. > + > +**/ > +BOOLEAN > +IsPassThruInstanceHandled ( > + IN HDD_PASSWORD_PEI_DRIVER_PRIVATE_DATA *Private, > + IN EDKII_PEI_ATA_PASS_THRU_PPI *PassThruInstance > + ) > +{ > + UINTN Index; > + > + for (Index =3D 0; Index < Private->AtaPassThruPpiInstanceNum; Index++)= { > + if ((UINTN)PassThruInstance =3D=3D Private->AtaPassThruPpiInstances[= Index]) > { > + return TRUE; > + } > + } > + > + return FALSE; > +} > + > +/** > + Send unlock hdd password cmd through ATA PassThru PPI. > + > + @param[in] AtaPassThru The pointer to the ATA PassThru PPI. > + @param[in] Port The port number of the ATA device. > + @param[in] PortMultiplierPort The port multiplier port number of th= e > ATA device. > + @param[in] Identifier The identifier to set user or master = password. > + @param[in] Password The hdd password of attached ATA devi= ce. > + > + @retval EFI_SUCCESS Successful to send unlock hdd passwor= d cmd. > + @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid. > + @retval EFI_OUT_OF_RESOURCES Not enough memory to send unlock > hdd password cmd. > + @retval EFI_DEVICE_ERROR Can not send unlock hdd password cmd. > + > +**/ > +EFI_STATUS > +UnlockDevice ( > + IN EDKII_PEI_ATA_PASS_THRU_PPI *AtaPassThru, > + IN UINT16 Port, > + IN UINT16 PortMultiplierPort, > + IN CHAR8 Identifier, > + IN CHAR8 *Password > + ) > +{ > + EFI_STATUS Status; > + EFI_ATA_COMMAND_BLOCK Acb; > + EFI_ATA_STATUS_BLOCK *Asb; > + EFI_ATA_PASS_THRU_COMMAND_PACKET Packet; > + UINT8 Buffer[HDD_PAYLOAD]; > + > + if ((AtaPassThru =3D=3D NULL) || (Password =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) i= n > + // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned > specified by > + // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. > Meanwhile, > + // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields= , > so it > + // may not be aligned when allocated on stack for some compilers. Henc= e, > we > + // use the API AllocateAlignedPages to ensure this structure is proper= ly > + // aligned. > + // > + Asb =3D AllocateAlignedPages ( > + EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)), > + AtaPassThru->Mode->IoAlign > + ); > + if (Asb =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + // > + // Prepare for ATA command block. > + // > + ZeroMem (&Acb, sizeof (Acb)); > + ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK)); > + Acb.AtaCommand =3D ATA_SECURITY_UNLOCK_CMD; > + Acb.AtaDeviceHead =3D (UINT8) (PortMultiplierPort =3D=3D 0xFFFF ? 0 : > (PortMultiplierPort << 4)); > + > + // > + // Prepare for ATA pass through packet. > + // > + ZeroMem (&Packet, sizeof (Packet)); > + Packet.Protocol =3D EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT; > + Packet.Length =3D EFI_ATA_PASS_THRU_LENGTH_BYTES; > + Packet.Asb =3D Asb; > + Packet.Acb =3D &Acb; > + > + ((CHAR16 *) Buffer)[0] =3D Identifier & BIT0; > + CopyMem (&((CHAR16 *) Buffer)[1], Password, > HDD_PASSWORD_MAX_LENGTH); > + > + Packet.OutDataBuffer =3D Buffer; > + Packet.OutTransferLength =3D sizeof (Buffer); > + Packet.Timeout =3D ATA_TIMEOUT; > + > + Status =3D AtaPassThru->PassThru ( > + AtaPassThru, > + Port, > + PortMultiplierPort, > + &Packet > + ); > + if (!EFI_ERROR (Status) && > + ((Asb->AtaStatus & ATA_STSREG_ERR) !=3D 0) && > + ((Asb->AtaError & ATA_ERRREG_ABRT) !=3D 0)) { > + Status =3D EFI_DEVICE_ERROR; > + } > + > + FreeAlignedPages (Asb, EFI_SIZE_TO_PAGES (sizeof > (EFI_ATA_STATUS_BLOCK))); > + > + ZeroMem (Buffer, sizeof (Buffer)); > + > + DEBUG ((DEBUG_INFO, "%a() - %r\n", __FUNCTION__, Status)); > + return Status; > +} > + > +/** > + Send security freeze lock cmd through ATA PassThru PPI. > + > + @param[in] AtaPassThru The pointer to the ATA PassThru PPI. > + @param[in] Port The port number of the ATA device. > + @param[in] PortMultiplierPort The port multiplier port number of th= e > ATA device. > + > + @retval EFI_SUCCESS Successful to send security freeze lo= ck cmd. > + @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid. > + @retval EFI_OUT_OF_RESOURCES Not enough memory to send unlock > hdd password cmd. > + @retval EFI_DEVICE_ERROR Can not send security freeze lock cmd= . > + > +**/ > +EFI_STATUS > +FreezeLockDevice ( > + IN EDKII_PEI_ATA_PASS_THRU_PPI *AtaPassThru, > + IN UINT16 Port, > + IN UINT16 PortMultiplierPort > + ) > +{ > + EFI_STATUS Status; > + EFI_ATA_COMMAND_BLOCK Acb; > + EFI_ATA_STATUS_BLOCK *Asb; > + EFI_ATA_PASS_THRU_COMMAND_PACKET Packet; > + > + if (AtaPassThru =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) i= n > + // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned > specified by > + // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. > Meanwhile, > + // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields= , > so it > + // may not be aligned when allocated on stack for some compilers. Henc= e, > we > + // use the API AllocateAlignedPages to ensure this structure is proper= ly > + // aligned. > + // > + Asb =3D AllocateAlignedPages ( > + EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)), > + AtaPassThru->Mode->IoAlign > + ); > + if (Asb =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + // > + // Prepare for ATA command block. > + // > + ZeroMem (&Acb, sizeof (Acb)); > + ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK)); > + Acb.AtaCommand =3D ATA_SECURITY_FREEZE_LOCK_CMD; > + Acb.AtaDeviceHead =3D (UINT8) (PortMultiplierPort =3D=3D 0xFFFF ? 0 : > (PortMultiplierPort << 4)); > + > + // > + // Prepare for ATA pass through packet. > + // > + ZeroMem (&Packet, sizeof (Packet)); > + Packet.Protocol =3D EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA; > + Packet.Length =3D EFI_ATA_PASS_THRU_LENGTH_NO_DATA_TRANSFER; > + Packet.Asb =3D Asb; > + Packet.Acb =3D &Acb; > + Packet.Timeout =3D ATA_TIMEOUT; > + > + Status =3D AtaPassThru->PassThru ( > + AtaPassThru, > + Port, > + PortMultiplierPort, > + &Packet > + ); > + if (!EFI_ERROR (Status) && > + ((Asb->AtaStatus & ATA_STSREG_ERR) !=3D 0) && > + ((Asb->AtaError & ATA_ERRREG_ABRT) !=3D 0)) { > + Status =3D EFI_DEVICE_ERROR; > + } > + > + FreeAlignedPages (Asb, EFI_SIZE_TO_PAGES (sizeof > (EFI_ATA_STATUS_BLOCK))); > + > + DEBUG ((DEBUG_INFO, "%a() - %r\n", __FUNCTION__, Status)); > + return Status; > +} > + > +/** > + Unlock HDD password for S3. > + > + @param[in] Private Pointer to the HddPassword PEI driver private da= ta. > + > +**/ > +VOID > +UnlockHddPassword ( > + IN HDD_PASSWORD_PEI_DRIVER_PRIVATE_DATA *Private > + ) > +{ > + EFI_STATUS Status; > + VOID *Buffer; > + UINTN Length; > + UINT8 DummyData; > + HDD_PASSWORD_DEVICE_INFO *DevInfo; > + UINTN AtaPassThruInstance; > + EDKII_PEI_ATA_PASS_THRU_PPI *AtaPassThruPpi; > + UINT16 Port; > + UINT16 PortMultiplierPort; > + EFI_DEVICE_PATH_PROTOCOL *DevicePath; > + UINTN DevicePathLength; > + > + // > + // Get HDD password device info from LockBox. > + // > + Buffer =3D (VOID *) &DummyData; > + Length =3D 1; > + Status =3D RestoreLockBox (&mHddPasswordDeviceInfoGuid, Buffer, > &Length); > + if (Status =3D=3D EFI_BUFFER_TOO_SMALL) { > + Buffer =3D AllocatePages (EFI_SIZE_TO_PAGES (Length)); > + if (Buffer !=3D NULL) { > + Status =3D RestoreLockBox (&mHddPasswordDeviceInfoGuid, Buffer, > &Length); > + } > + } > + if ((Buffer =3D=3D NULL) || (Buffer =3D=3D (VOID *) &DummyData)) { > + return; > + } else if (EFI_ERROR (Status)) { > + FreePages (Buffer, EFI_SIZE_TO_PAGES (Length)); > + return; > + } > + > + // > + // Go through the ATA PassThru PPI instances within system. > + // > + for (AtaPassThruInstance =3D 0; > + AtaPassThruInstance < MAX_ATA_PASSTHRU_PPI; > + AtaPassThruInstance++) { > + Status =3D PeiServicesLocatePpi ( > + &gEdkiiPeiAtaPassThruPpiGuid, > + AtaPassThruInstance, > + NULL, > + (VOID **) &AtaPassThruPpi > + ); > + if (EFI_ERROR (Status)) { > + // > + // No more EDKII_PEI_ATA_PASS_THRU_PPI instances. > + // > + break; > + } > + > + // > + // Check whether this PPI instance has been handled previously. > + // > + if (IsPassThruInstanceHandled (Private, AtaPassThruPpi)) { > + DEBUG (( > + DEBUG_INFO, "%a: ATA PassThru PPI instance (0x%p) already > handled.\n", > + __FUNCTION__, (UINTN)AtaPassThruPpi > + )); > + continue; > + } else { > + DEBUG (( > + DEBUG_INFO, "%a: New ATA PassThru PPI instance (0x%p) found.\n", > + __FUNCTION__, (UINTN)AtaPassThruPpi > + )); > + Private->AtaPassThruPpiInstances[Private- > >AtaPassThruPpiInstanceNum] =3D (UINTN)AtaPassThruPpi; > + Private->AtaPassThruPpiInstanceNum++; > + } > + > + Status =3D AtaPassThruPpi->GetDevicePath (AtaPassThruPpi, > &DevicePathLength, &DevicePath); > + if (EFI_ERROR (Status) || (DevicePathLength <=3D sizeof > (EFI_DEVICE_PATH_PROTOCOL))) { > + continue; > + } > + > + // > + // Go through all the devices managed by this PPI instance. > + // > + Port =3D 0xFFFF; > + while (TRUE) { > + Status =3D AtaPassThruPpi->GetNextPort (AtaPassThruPpi, &Port); > + if (EFI_ERROR (Status)) { > + // > + // We cannot find more legal port then we are done. > + // > + break; > + } > + > + PortMultiplierPort =3D 0xFFFF; > + while (TRUE) { > + Status =3D AtaPassThruPpi->GetNextDevice (AtaPassThruPpi, Port, > &PortMultiplierPort); > + if (EFI_ERROR (Status)) { > + // > + // We cannot find more legal port multiplier port number for A= TA > device > + // on the port, then we are done. > + // > + break; > + } > + > + // > + // Search the device in the restored LockBox. > + // > + DevInfo =3D (HDD_PASSWORD_DEVICE_INFO *) Buffer; > + while ((UINTN) DevInfo < ((UINTN) Buffer + Length)) { > + // > + // Find the matching device. > + // > + if ((DevInfo->Device.Port =3D=3D Port) && > + (DevInfo->Device.PortMultiplierPort =3D=3D PortMultiplierP= ort) && > + (DevInfo->DevicePathLength >=3D DevicePathLength) && > + (CompareMem ( > + DevInfo->DevicePath, > + DevicePath, > + DevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)) = =3D=3D 0)) { > + // > + // If device locked, unlock first. > + // > + if (!IsZeroBuffer (DevInfo->Password, > HDD_PASSWORD_MAX_LENGTH)) { > + UnlockDevice (AtaPassThruPpi, Port, PortMultiplierPort, 0,= DevInfo- > >Password); > + } > + // > + // Freeze lock the device. > + // > + FreezeLockDevice (AtaPassThruPpi, Port, PortMultiplierPort); > + break; > + } > + > + DevInfo =3D (HDD_PASSWORD_DEVICE_INFO *) > + ((UINTN) DevInfo + sizeof (HDD_PASSWORD_DEVICE_INFO)= + > DevInfo->DevicePathLength); > + } > + } > + } > + } > + > + ZeroMem (Buffer, Length); > + FreePages (Buffer, EFI_SIZE_TO_PAGES (Length)); > + > +} > + > +/** > + Entry point of the notification callback function itself within the PE= IM. > + It is to unlock HDD password for S3. > + > + @param PeiServices Indirect reference to the PEI Services Table. > + @param NotifyDescriptor Address of the notification descriptor data > structure. > + @param Ppi Address of the PPI that was installed. > + > + @return Status of the notification. > + The status code returned from this function is ignored. > +**/ > +EFI_STATUS > +EFIAPI > +HddPasswordAtaPassThruNotify ( > + IN EFI_PEI_SERVICES **PeiServices, > + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc, > + IN VOID *Ppi > + ) > +{ > + HDD_PASSWORD_PEI_DRIVER_PRIVATE_DATA *Private; > + > + DEBUG ((DEBUG_INFO, "%a() - enter at S3 resume\n", __FUNCTION__)); > + > + Private =3D HDD_PASSWORD_PEI_PRIVATE_DATA_FROM_THIS_NOTIFY > (NotifyDesc); > + UnlockHddPassword (Private); > + > + DEBUG ((DEBUG_INFO, "%a() - exit at S3 resume\n", __FUNCTION__)); > + > + return EFI_SUCCESS; > +} > + > +HDD_PASSWORD_PEI_DRIVER_PRIVATE_DATA > mHddPasswordPeiDriverPrivateTemplate =3D { > + HDD_PASSWORD_PEI_DRIVER_SIGNATURE, // Signature > + { // AtaPassThruPpiNotifyList > + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | > EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), > + &gEdkiiPeiAtaPassThruPpiGuid, > + HddPasswordAtaPassThruNotify > + }, > + 0, // AtaPassThruPpiInstanceNum > + {0} // AtaPassThruPpiInstances > +}; > + > +/** > + Main entry for this module. > + > + @param FileHandle Handle of the file being invoked. > + @param PeiServices Pointer to PEI Services table. > + > + @return Status from PeiServicesNotifyPpi. > + > +**/ > +EFI_STATUS > +EFIAPI > +HddPasswordPeiInit ( > + IN EFI_PEI_FILE_HANDLE FileHandle, > + IN CONST EFI_PEI_SERVICES **PeiServices > + ) > +{ > + EFI_STATUS Status; > + EFI_BOOT_MODE BootMode; > + HDD_PASSWORD_PEI_DRIVER_PRIVATE_DATA *Private; > + > + Status =3D PeiServicesGetBootMode (&BootMode); > + if ((EFI_ERROR (Status)) || (BootMode !=3D BOOT_ON_S3_RESUME)) { > + return EFI_UNSUPPORTED; > + } > + > + DEBUG ((DEBUG_INFO, "%a: Enters in S3 path.\n", __FUNCTION__)); > + > + Private =3D (HDD_PASSWORD_PEI_DRIVER_PRIVATE_DATA *) > + AllocateCopyPool ( > + sizeof (HDD_PASSWORD_PEI_DRIVER_PRIVATE_DATA), > + &mHddPasswordPeiDriverPrivateTemplate > + ); > + if (Private =3D=3D NULL) { > + DEBUG (( > + DEBUG_ERROR, > + "%a: Failed to allocate memory for > HDD_PASSWORD_PEI_DRIVER_PRIVATE_DATA.\n", > + __FUNCTION__ > + )); > + return EFI_OUT_OF_RESOURCES; > + } > + > + Status =3D PeiServicesNotifyPpi (&Private->AtaPassThruPpiNotifyList); > + ASSERT_EFI_ERROR (Status); > + return Status; > +} > + > diff --git a/SecurityPkg/HddPassword/HddPasswordStrings.uni > b/SecurityPkg/HddPassword/HddPasswordStrings.uni > new file mode 100644 > index 0000000000..455ecfcd02 > --- /dev/null > +++ b/SecurityPkg/HddPassword/HddPasswordStrings.uni > @@ -0,0 +1,48 @@ > +// /** @file > +// String definitions for HddPassword Setup Form. > +// > +// Copyright (c) 2019, 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. > +// > +// **/ > + > +#langdef en-US "English" > + > +#string STR_HDD_SECURITY_CONFIG #language en-US "HDD Secur= ity > Configuration" > + > +#string STR_SECURITY_HDD_PWD_DESC #language en-US "HDD > Password Description :" > + > +#string STR_SECURITY_HDD_BANNER_ONE #language en-US "Allows > Access to Set, Modify and Clear HardDisk User and" > +#string STR_SECURITY_HDD_BANNER_TWO #language en-US "Master > Passwords." > +#string STR_SECURITY_HDD_BANNER_THREE #language en-US "User > Password need to be installed for Enabling Security." > +#string STR_SECURITY_HDD_BANNER_FOUR #language en-US "Master > Password can be modified only when succesfully" > +#string STR_SECURITY_HDD_BANNER_FIVE #language en-US "unlocked > with User Password in POST." > + > +#string STR_HDD_SECURITY_HD #language en-US "HDD Passw= ord" > +#string STR_HDD_SECURITY_HELP #language en-US "Set HDD > Password" > +#string STR_HDD_PASSWORD_CONFIG #language en-US "HDD > PASSWORD CONFIGURATION:" > +#string STR_SEC_SUPPORTED #language en-US "Security > Supported :" > +#string STR_SEC_ENABLED #language en-US "Security > Enabled :" > +#string STR_SEC_LOCKED #language en-US "Security > Locked :" > +#string STR_SEC_FROZEN #language en-US "Security > Frozen :" > +#string STR_YES #language en-US "Yes" > +#string STR_NO #language en-US "No" > +#string STR_HDD_USER_PASSWORD #language en-US "Request t= o > set User Password" > +#string STR_HDD_USER_PASSWORD_HELP #language en-US "Request > to set HDD User Password. \n*** Reset is required for the request to be > processed in next boot *** \n*** G3 circle is required to disable freeze = state > when Security Frozen state is Yes, otherwise the request will be ignored.= *** > " > +#string STR_HDD_MASTER_PASSWORD #language en-US "Request > to set Master Password" > +#string STR_HDD_MASTER_PASSWORD_HELP #language en-US > "Request to set HDD Master Password. \n*** Reset is required for the > request to be processed in next boot *** \n*** G3 circle is required to > disable freeze state when Security Frozen state is Yes, otherwise the req= uest > will be ignored. *** " > + > +#string STR_INSTALLED #language en-US "INSTALLED= " > +#string STR_NOT_INSTALLED #language en-US "NOT INSTA= LLED" > +#string STR_HDD_USER_PASSWORD_STS #language en-US "HDD User > Password Status :" > +#string STR_HDD_MASTER_PASSWORD_STS #language en-US "HDD > Master Password Status:" > +#string STR_NULL #language en-US "" > +#string STR_EMPTY #language en-US "" > -- > 2.12.0.windows.1