public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Dong, Eric" <eric.dong@intel.com>
To: "Wu, Hao A" <hao.a.wu@intel.com>,
	"edk2-devel@lists.01.org" <edk2-devel@lists.01.org>
Cc: "Ni, Ray" <ray.ni@intel.com>,
	"Zhang, Chao B" <chao.b.zhang@intel.com>,
	"Yao, Jiewen" <jiewen.yao@intel.com>
Subject: Re: [PATCH v1 1/1] SecurityPkg/HddPassword: Add Security feature set support for ATA dev
Date: Mon, 18 Feb 2019 07:47:43 +0000	[thread overview]
Message-ID: <ED077930C258884BBCB450DB737E662259DB120E@shsmsx102.ccr.corp.intel.com> (raw)
In-Reply-To: <20190215024911.7704-2-hao.a.wu@intel.com>

Hi Hao,

Only minor change request, remove below useless zero memory action.
  ZeroMem (S3InitDevices, S3InitDevicesLength);

With this change, Reviewed-by: Eric Dong <eric.dong@intel.com>

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 <hao.a.wu@intel.com>; Dong, Eric <eric.dong@intel.com>; Ni,
> Ray <ray.ni@intel.com>; Zhang, Chao B <chao.b.zhang@intel.com>; Yao,
> Jiewen <jiewen.yao@intel.com>
> Subject: [PATCH v1 1/1] SecurityPkg/HddPassword: Add Security feature set
> support for ATA dev
> 
> REF:https://bugzilla.tianocore.org/show_bug.cgi?id=1529
> 
> This commit will add the 'Security feature set' support for ATA devices.
> 
> 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 feature
> can be referred from the ATA8-ACS spec.
> 
> The HddPassword driver is composed of 2 parts:
> * A DXE driver and
> * A PEI driver
> 
> The DXE driver consumes EFI_ATA_PASS_THRU_PROTOCOL instances and
> installs
> an HII GUI to manage the devices. If the managing device supports Security
> 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.
> 
> 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:
> 
> The DXE driver will save the password and the identication information for
> these devices into a LockBox, which is only allowed to restore during S3
> resume.
> 
> 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.
> 
> Cc: Eric Dong <eric.dong@intel.com>
> Cc: Ray Ni <ray.ni@intel.com>
> Cc: Chao Zhang <chao.b.zhang@intel.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Contributed-under: TianoCore Contribution Agreement 1.1
> Signed-off-by: Hao Wu <hao.a.wu@intel.com>
> ---
>  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(+)
> 
> 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
> 
> +  #
> +  # HDD Password solution
> +  #
> +  SecurityPkg/HddPassword/HddPasswordDxe.inf
> +  SecurityPkg/HddPassword/HddPasswordPei.inf
> +
>  [BuildOptions]
>     MSFT:*_*_IA32_DLINK_FLAGS = /ALIGN:256
>    INTEL:*_*_IA32_DLINK_FLAGS = /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.<BR>
> +#
> +#  This program and the accompanying materials
> +#  are licensed and made available under the terms and conditions of the
> BSD License
> +#  which accompanies this distribution.  The full text of the license may be
> found at
> +#  http://opensource.org/licenses/bsd-license.php
> +#
> +#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = HddPasswordDxe
> +  FILE_GUID                      = 9BD549CD-86D1-4925-9F7D-3686DDD876FC
> +  MODULE_TYPE                    = DXE_DRIVER
> +  VERSION_STRING                 = 1.0
> +  ENTRY_POINT                    = HddPasswordDxeInit
> +
> +#
> +# The following information is for reference only and not required by the
> build tools.
> +#
> +#  VALID_ARCHITECTURES           = 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.<BR>
> +#
> +#  This program and the accompanying materials
> +#  are licensed and made available under the terms and conditions of the
> BSD License
> +#  which accompanies this distribution.  The full text of the license may be
> found at
> +#  http://opensource.org/licenses/bsd-license.php
> +#
> +#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = HddPasswordPei
> +  FILE_GUID                      = 91AD7375-8E8E-49D2-A343-68BC78273955
> +  MODULE_TYPE                    = PEIM
> +  VERSION_STRING                 = 1.0
> +  ENTRY_POINT                    = HddPasswordPeiInit
> +
> +#
> +# The following information is for reference only and not required by the
> build tools.
> +#
> +#  VALID_ARCHITECTURES           = 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.<BR>
> +
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions
> +  of the BSD License which accompanies this distribution.  The
> +  full text of the license may be found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#ifndef _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.<BR>
> +
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions
> +  of the BSD License which accompanies this distribution.  The
> +  full text of the license may be found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#ifndef _HDD_PASSWORD_DXE_H_
> +#define _HDD_PASSWORD_DXE_H_
> +
> +#include <Uefi.h>
> +
> +#include <IndustryStandard/Atapi.h>
> +#include <IndustryStandard/Pci.h>
> +#include <Protocol/AtaPassThru.h>
> +#include <Protocol/PciIo.h>
> +#include <Protocol/HiiConfigAccess.h>
> +#include <Protocol/VariableLock.h>
> +
> +#include <Guid/MdeModuleHii.h>
> +#include <Guid/EventGroup.h>
> +#include <Guid/S3StorageDeviceInitList.h>
> +
> +#include <Library/DebugLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/UefiRuntimeServicesTableLib.h>
> +#include <Library/UefiDriverEntryPoint.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/DxeServicesTableLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/UefiHiiServicesLib.h>
> +#include <Library/HiiLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/PrintLib.h>
> +#include <Library/UefiLib.h>
> +#include <Library/LockBoxLib.h>
> +#include <Library/S3BootScriptLib.h>
> +#include <Library/PciLib.h>
> +#include <Library/BaseCryptLib.h>
> +
> +#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 = (ListHead)->ForwardLink; Entry != (ListHead); Entry = 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.<BR>
> +
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions
> +  of the BSD License which accompanies this distribution.  The
> +  full text of the license may be found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#ifndef _HDD_PASSWORD_HII_DATASTRUC_H_
> +#define _HDD_PASSWORD_HII_DATASTRUC_H_
> +
> +#include <Guid/HiiPlatformSetupFormset.h>
> +
> +#define HDD_PASSWORD_CONFIG_GUID \
> +  { \
> +    0x737cded7, 0x448b, 0x4801, { 0xb5, 0x7d, 0xb1, 0x94, 0x83, 0xec, 0x60,
> 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.<BR>
> +
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions
> +  of the BSD License which accompanies this distribution.  The
> +  full text of the license may be found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#ifndef _HDD_PASSWORD_PEI_H_
> +#define _HDD_PASSWORD_PEI_H_
> +
> +#include <PiPei.h>
> +#include <IndustryStandard/Atapi.h>
> +//#include <IndustryStandard/Pci.h>
> +
> +#include <Library/DebugLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/PeimEntryPoint.h>
> +#include <Library/PeiServicesLib.h>
> +#include <Library/PciLib.h>
> +#include <Library/LockBoxLib.h>
> +
> +#include <Ppi/AtaPassThru.h>
> +
> +#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.<BR>
> +
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions
> +  of the BSD License which accompanies this distribution.  The
> +  full text of the license may be found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +**/
> +
> +#include "HddPasswordHiiDataStruc.h"
> +
> +formset
> +  guid      = HDD_PASSWORD_CONFIG_GUID,
> +  title     = STRING_TOKEN(STR_HDD_SECURITY_CONFIG),
> +  help      = STRING_TOKEN(STR_HDD_SECURITY_CONFIG),
> +  classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID,
> +
> +  varstore HDD_PASSWORD_CONFIG,
> +  name = HDD_PASSWORD_CONFIG,
> +  guid = HDD_PASSWORD_CONFIG_GUID;
> +
> +  form formid = FORMID_HDD_MAIN_FORM,
> +    title  = STRING_TOKEN(STR_HDD_SECURITY_CONFIG);
> +
> +    label HDD_DEVICE_ENTRY_LABEL;
> +    label HDD_DEVICE_LABEL_END;
> +
> +  endform;
> +
> +  form
> +    formid = FORMID_HDD_DEVICE_FORM,
> +    title = STRING_TOKEN(STR_HDD_SECURITY_HD);
> +
> +    subtitle text = STRING_TOKEN(STR_SECURITY_HDD_PWD_DESC);
> +
> +    subtitle text = STRING_TOKEN(STR_NULL);
> +
> +        subtitle text = STRING_TOKEN(STR_SECURITY_HDD_BANNER_ONE);
> +        subtitle text = STRING_TOKEN(STR_SECURITY_HDD_BANNER_TWO);
> +        subtitle text = STRING_TOKEN(STR_SECURITY_HDD_BANNER_THREE);
> +        subtitle text = STRING_TOKEN(STR_SECURITY_HDD_BANNER_FOUR);
> +        subtitle text = STRING_TOKEN(STR_SECURITY_HDD_BANNER_FIVE);
> +
> +    subtitle text = STRING_TOKEN(STR_NULL);
> +
> +    subtitle text = STRING_TOKEN(STR_HDD_PASSWORD_CONFIG);
> +
> +    subtitle text = STRING_TOKEN(STR_NULL);
> +
> +    grayoutif  TRUE;
> +    suppressif ideqvallist
> HDD_PASSWORD_CONFIG.SecurityStatus.Supported == 0;
> +        text
> +            help   = STRING_TOKEN(STR_EMPTY),
> +            text   = STRING_TOKEN(STR_SEC_SUPPORTED),
> +            text   = STRING_TOKEN(STR_YES),
> +            flags  = 0,
> +            key    = 0;
> +    endif;
> +
> +    suppressif ideqvallist
> HDD_PASSWORD_CONFIG.SecurityStatus.Supported == 1;
> +        text
> +            help   = STRING_TOKEN(STR_EMPTY),
> +            text   = STRING_TOKEN(STR_SEC_SUPPORTED),
> +            text   = STRING_TOKEN(STR_NO),
> +            flags  = 0,
> +            key    = 0;
> +    endif;
> +
> +    suppressif ideqvallist HDD_PASSWORD_CONFIG.SecurityStatus.Enabled
> == 0;
> +        text
> +            help   = STRING_TOKEN(STR_EMPTY),
> +            text   = STRING_TOKEN(STR_SEC_ENABLED),
> +            text   = STRING_TOKEN(STR_YES),
> +            flags  = 0,
> +            key    = 0;
> +    endif;
> +
> +    suppressif ideqvallist HDD_PASSWORD_CONFIG.SecurityStatus.Enabled
> == 1;
> +        text
> +            help   = STRING_TOKEN(STR_EMPTY),
> +            text   = STRING_TOKEN(STR_SEC_ENABLED),
> +            text   = STRING_TOKEN(STR_NO),
> +            flags  = 0,
> +            key    = 0;
> +    endif;
> +
> +
> +    suppressif ideqvallist HDD_PASSWORD_CONFIG.SecurityStatus.Locked ==
> 0;
> +        text
> +            help   = STRING_TOKEN(STR_EMPTY),
> +            text   = STRING_TOKEN(STR_SEC_LOCKED),
> +            text   = STRING_TOKEN(STR_YES),
> +            flags  = 0,
> +            key    = 0;
> +    endif;
> +
> +    suppressif ideqvallist HDD_PASSWORD_CONFIG.SecurityStatus.Locked ==
> 1;
> +        text
> +            help   = STRING_TOKEN(STR_EMPTY),
> +            text   = STRING_TOKEN(STR_SEC_LOCKED),
> +            text   = STRING_TOKEN(STR_NO),
> +            flags  = 0,
> +            key    = 0;
> +    endif;
> +
> +    suppressif ideqvallist HDD_PASSWORD_CONFIG.SecurityStatus.Frozen ==
> 0;
> +        text
> +            help   = STRING_TOKEN(STR_EMPTY),
> +            text   = STRING_TOKEN(STR_SEC_FROZEN),
> +            text   = STRING_TOKEN(STR_YES),
> +            flags  = 0,
> +            key    = 0;
> +    endif;
> +
> +    suppressif ideqvallist HDD_PASSWORD_CONFIG.SecurityStatus.Frozen ==
> 1;
> +        text
> +            help   = STRING_TOKEN(STR_EMPTY),
> +            text   = STRING_TOKEN(STR_SEC_FROZEN),
> +            text   = STRING_TOKEN(STR_NO),
> +            flags  = 0,
> +            key    = 0;
> +    endif;
> +
> +    suppressif ideqvallist
> HDD_PASSWORD_CONFIG.SecurityStatus.UserPasswordStatus == 0;
> +        text
> +            help   = STRING_TOKEN(STR_EMPTY),
> +            text   = STRING_TOKEN(STR_HDD_USER_PASSWORD_STS),
> +            text   = STRING_TOKEN(STR_INSTALLED),
> +            flags  = 0,
> +            key    = 0;
> +    endif;
> +
> +    suppressif ideqvallist
> HDD_PASSWORD_CONFIG.SecurityStatus.UserPasswordStatus == 1;
> +        text
> +            help   = STRING_TOKEN(STR_EMPTY),
> +            text   = STRING_TOKEN(STR_HDD_USER_PASSWORD_STS),
> +            text   = STRING_TOKEN(STR_NOT_INSTALLED),
> +            flags  = 0,
> +            key    = 0;
> +    endif;
> +
> +    suppressif ideqvallist
> HDD_PASSWORD_CONFIG.SecurityStatus.MasterPasswordStatus == 0;
> +        text
> +            help   = STRING_TOKEN(STR_EMPTY),
> +            text   = STRING_TOKEN(STR_HDD_MASTER_PASSWORD_STS),
> +            text   = STRING_TOKEN(STR_INSTALLED),
> +            flags  = 0,
> +            key    = 0;
> +    endif;
> +
> +    suppressif ideqvallist
> HDD_PASSWORD_CONFIG.SecurityStatus.MasterPasswordStatus == 1;
> +        text
> +            help   = STRING_TOKEN(STR_EMPTY),
> +            text   = STRING_TOKEN(STR_HDD_MASTER_PASSWORD_STS),
> +            text   = STRING_TOKEN(STR_NOT_INSTALLED),
> +            flags  = 0,
> +            key    = 0;
> +    endif;
> +    endif;
> +
> +    subtitle text = STRING_TOKEN(STR_NULL);
> +
> +    grayoutif ideqval HDD_PASSWORD_CONFIG.SecurityStatus.Supported ==
> 0;
> +      checkbox varid  = HDD_PASSWORD_CONFIG.Request.UserPassword,
> +            prompt      = STRING_TOKEN(STR_HDD_USER_PASSWORD),
> +            help        = STRING_TOKEN(STR_HDD_USER_PASSWORD_HELP),
> +            flags       = INTERACTIVE | RESET_REQUIRED,
> +            key         = KEY_HDD_USER_PASSWORD,
> +      endcheckbox;
> +    endif;
> +
> +    grayoutif ideqval HDD_PASSWORD_CONFIG.SecurityStatus.Supported ==
> 0;
> +      checkbox varid  = HDD_PASSWORD_CONFIG.Request.MasterPassword,
> +            prompt      = STRING_TOKEN(STR_HDD_MASTER_PASSWORD),
> +            help        = STRING_TOKEN(STR_HDD_MASTER_PASSWORD_HELP),
> +            flags       = INTERACTIVE | RESET_REQUIRED,
> +            key         = 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.<BR>
> +
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions
> +  of the BSD License which accompanies this distribution.  The
> +  full text of the license may be found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#include "HddPasswordDxe.h"
> +
> +EFI_GUID   mHddPasswordVendorGuid          =
> HDD_PASSWORD_CONFIG_GUID;
> +CHAR16     mHddPasswordVendorStorageName[] =
> L"HDD_PASSWORD_CONFIG";
> +LIST_ENTRY mHddPasswordConfigFormList;
> +UINT32     mNumberOfHddDevices = 0;
> +
> +EFI_GUID mHddPasswordDeviceInfoGuid =
> HDD_PASSWORD_DEVICE_INFO_GUID;
> +BOOLEAN                         mHddPasswordEndOfDxe = FALSE;
> +HDD_PASSWORD_REQUEST_VARIABLE   *mHddPasswordRequestVariable
> = NULL;
> +UINTN                           mHddPasswordRequestVariableSize = 0;
> +
> +HII_VENDOR_DEVICE_PATH          mHddPasswordHiiVendorDevicePath = {
> +  {
> +    {
> +      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 = 0; Index < HDD_PASSWORD_MAX_LENGTH; Index++) {
> +    if (Password[Index] != 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                = (UINT8) ConfigFormEntry->Bus;
> +  TempDevInfo->Device.Device             = (UINT8) ConfigFormEntry->Device;
> +  TempDevInfo->Device.Function           = (UINT8) ConfigFormEntry-
> >Function;
> +  TempDevInfo->Device.Port               = ConfigFormEntry->Port;
> +  TempDevInfo->Device.PortMultiplierPort = ConfigFormEntry-
> >PortMultiplierPort;
> +  CopyMem (TempDevInfo->Password, ConfigFormEntry->Password,
> HDD_PASSWORD_MAX_LENGTH);
> +  TempDevInfo->DevicePathLength          = (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 = 0;
> +  EFI_LIST_FOR_EACH (Entry, &mHddPasswordConfigFormList) {
> +    ConfigFormEntry = 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 handle
> device
> +    //    which support security feature.
> +    //
> +    if ((!PasswordIsFullZero (ConfigFormEntry->Password)) ||
> +        ((ConfigFormEntry->IfrData.SecurityStatus.Supported != 0) &&
> +         (ConfigFormEntry->IfrData.SecurityStatus.Enabled == 0))) {
> +      DevInfoLength += sizeof (HDD_PASSWORD_DEVICE_INFO) +
> +                       GetDevicePathSize (ConfigFormEntry->DevicePath);
> +    }
> +  }
> +
> +  if (DevInfoLength == 0) {
> +    return;
> +  }
> +
> +  S3InitDevicesLength = sizeof (DummyData);
> +  Status = RestoreLockBox (
> +             &gS3StorageDeviceInitListGuid,
> +             &DummyData,
> +             &S3InitDevicesLength
> +             );
> +  ASSERT ((Status == EFI_NOT_FOUND) || (Status ==
> EFI_BUFFER_TOO_SMALL));
> +  if (Status == EFI_NOT_FOUND) {
> +    S3InitDevices      = NULL;
> +    S3InitDevicesExist = FALSE;
> +  } else if (Status == EFI_BUFFER_TOO_SMALL) {
> +    S3InitDevices = AllocatePool (S3InitDevicesLength);
> +    ASSERT (S3InitDevices != NULL);
> +
> +    Status = RestoreLockBox (
> +               &gS3StorageDeviceInitListGuid,
> +               S3InitDevices,
> +               &S3InitDevicesLength
> +               );
> +    ASSERT_EFI_ERROR (Status);
> +    S3InitDevicesExist = TRUE;
> +  } else {
> +    return;
> +  }
> +
> +  DevInfo = AllocateZeroPool (DevInfoLength);
> +  ASSERT (DevInfo != NULL);
> +
> +  TempDevInfo = DevInfo;
> +  EFI_LIST_FOR_EACH (Entry, &mHddPasswordConfigFormList) {
> +    ConfigFormEntry = BASE_CR (Entry,
> HDD_PASSWORD_CONFIG_FORM_ENTRY, Link);
> +
> +    if ((!PasswordIsFullZero (ConfigFormEntry->Password)) ||
> +        ((ConfigFormEntry->IfrData.SecurityStatus.Supported != 0) &&
> +         (ConfigFormEntry->IfrData.SecurityStatus.Enabled == 0))) {
> +      SaveDeviceInfo (ConfigFormEntry, TempDevInfo);
> +
> +      S3InitDevicesBak = S3InitDevices;
> +      S3InitDevices    = AppendDevicePathInstance (
> +                           S3InitDevicesBak,
> +                           ConfigFormEntry->DevicePath
> +                           );
> +      if (S3InitDevicesBak != NULL) {
> +        ZeroMem (S3InitDevicesBak, GetDevicePathSize (S3InitDevicesBak));
> +        FreePool (S3InitDevicesBak);
> +      }
> +      ASSERT (S3InitDevices != NULL);
> +
> +      TempDevInfo = (HDD_PASSWORD_DEVICE_INFO *)
> ((UINTN)TempDevInfo +
> +                                                  sizeof (HDD_PASSWORD_DEVICE_INFO) +
> +                                                  TempDevInfo->DevicePathLength);
> +    }
> +  }
> +
> +  Status = SaveLockBox (
> +             &mHddPasswordDeviceInfoGuid,
> +             DevInfo,
> +             DevInfoLength
> +             );
> +  ASSERT_EFI_ERROR (Status);
> +
> +  Status = SetLockBoxAttributes (
> +             &mHddPasswordDeviceInfoGuid,
> +             LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY
> +             );
> +  ASSERT_EFI_ERROR (Status);
> +
> +  S3InitDevicesLength = GetDevicePathSize (S3InitDevices);
> +  if (S3InitDevicesExist) {
> +    Status = UpdateLockBox (
> +               &gS3StorageDeviceInitListGuid,
> +               0,
> +               S3InitDevices,
> +               S3InitDevicesLength
> +               );
> +    ASSERT_EFI_ERROR (Status);
> +  } else {
> +    Status = SaveLockBox (
> +               &gS3StorageDeviceInitListGuid,
> +               S3InitDevices,
> +               S3InitDevicesLength
> +               );
> +    ASSERT_EFI_ERROR (Status);
> +
> +    Status = 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 protocol.
> +  @param[in] Port                The port number of the ATA device 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.
> +
> +  @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 == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in
> +  // 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. Hence,
> we
> +  // use the API AllocateAlignedPages to ensure this structure is properly
> +  // aligned.
> +  //
> +  Asb = AllocateAlignedPages (
> +          EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)),
> +          AtaPassThru->Mode->IoAlign
> +          );
> +  if (Asb == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  //
> +  // Prepare for ATA command block.
> +  //
> +  ZeroMem (&Acb, sizeof (Acb));
> +  ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK));
> +  Acb.AtaCommand    = ATA_SECURITY_FREEZE_LOCK_CMD;
> +  Acb.AtaDeviceHead = (UINT8) (PortMultiplierPort == 0xFFFF ? 0 :
> (PortMultiplierPort << 4));
> +
> +  //
> +  // Prepare for ATA pass through packet.
> +  //
> +  ZeroMem (&Packet, sizeof (Packet));
> +  Packet.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA;
> +  Packet.Length   = EFI_ATA_PASS_THRU_LENGTH_NO_DATA_TRANSFER;
> +  Packet.Asb      = Asb;
> +  Packet.Acb      = &Acb;
> +  Packet.Timeout  = ATA_TIMEOUT;
> +
> +  Status = AtaPassThru->PassThru (
> +                          AtaPassThru,
> +                          Port,
> +                          PortMultiplierPort,
> +                          &Packet,
> +                          NULL
> +                          );
> +  if (!EFI_ERROR (Status) &&
> +      ((Asb->AtaStatus & ATA_STSREG_ERR) != 0) &&
> +      ((Asb->AtaError & ATA_ERRREG_ABRT) != 0)) {
> +    Status = 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 protocol.
> +  @param[in] Port                The port number of the ATA device 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] 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 == NULL) || (IdentifyData == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in
> +  // 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. Hence,
> we
> +  // use the API AllocateAlignedPages to ensure this structure is properly
> +  // aligned.
> +  //
> +  Asb = AllocateAlignedPages (
> +          EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)),
> +          AtaPassThru->Mode->IoAlign
> +          );
> +  if (Asb == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  //
> +  // Prepare for ATA command block.
> +  //
> +  ZeroMem (&Acb, sizeof (Acb));
> +  ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK));
> +  Acb.AtaCommand    = ATA_CMD_IDENTIFY_DRIVE;
> +  Acb.AtaDeviceHead = (UINT8) (BIT7 | BIT6 | BIT5 | (PortMultiplierPort ==
> 0xFFFF ? 0 : (PortMultiplierPort << 4)));
> +
> +  //
> +  // Prepare for ATA pass through packet.
> +  //
> +  ZeroMem (&Packet, sizeof (Packet));
> +  Packet.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN;
> +  Packet.Length   = EFI_ATA_PASS_THRU_LENGTH_BYTES |
> EFI_ATA_PASS_THRU_LENGTH_SECTOR_COUNT;
> +  Packet.Asb      = Asb;
> +  Packet.Acb      = &Acb;
> +  Packet.InDataBuffer     = IdentifyData;
> +  Packet.InTransferLength = sizeof (ATA_IDENTIFY_DATA);
> +  Packet.Timeout          = ATA_TIMEOUT;
> +
> +  Status = 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 = (IdentifyData-
> >command_set_supported_82 & BIT1) ? 1 : 0;
> +  IfrData->SecurityStatus.Enabled   = (IdentifyData->security_status & BIT1) ?
> 1 : 0;
> +  IfrData->SecurityStatus.Locked    = (IdentifyData->security_status & BIT2) ?
> 1 : 0;
> +  IfrData->SecurityStatus.Frozen    = (IdentifyData->security_status & BIT3) ?
> 1 : 0;
> +  IfrData->SecurityStatus.UserPasswordStatus   = IfrData-
> >SecurityStatus.Enabled;
> +  IfrData->SecurityStatus.MasterPasswordStatus = IfrData-
> >SecurityStatus.Supported;
> +
> +  DEBUG ((DEBUG_INFO, "IfrData->SecurityStatus.Supported            = %x\n",
> IfrData->SecurityStatus.Supported));
> +  DEBUG ((DEBUG_INFO, "IfrData->SecurityStatus.Enabled              = %x\n",
> IfrData->SecurityStatus.Enabled));
> +  DEBUG ((DEBUG_INFO, "IfrData->SecurityStatus.Locked               = %x\n",
> IfrData->SecurityStatus.Locked));
> +  DEBUG ((DEBUG_INFO, "IfrData->SecurityStatus.Frozen               = %x\n",
> IfrData->SecurityStatus.Frozen));
> +  DEBUG ((DEBUG_INFO, "IfrData->SecurityStatus.UserPasswordStatus
> = %x\n", IfrData->SecurityStatus.UserPasswordStatus));
> +  DEBUG ((DEBUG_INFO, "IfrData->SecurityStatus.MasterPasswordStatus
> = %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 invoked.
> +  @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 = TRUE;
> +
> +  if (mHddPasswordRequestVariable != NULL) {
> +    //
> +    // Free the HDD password request variable buffer here
> +    // as the HDD password requests should have been processed.
> +    //
> +    FreePool (mHddPasswordRequestVariable);
> +    mHddPasswordRequestVariable = NULL;
> +    mHddPasswordRequestVariableSize = 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 = 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 != 0) &&
> +        (ConfigFormEntry->IfrData.SecurityStatus.Locked == 0) &&
> +        (ConfigFormEntry->IfrData.SecurityStatus.Frozen == 0)) {
> +      Status = FreezeLockDevice (ConfigFormEntry->AtaPassThru,
> ConfigFormEntry->Port, ConfigFormEntry->PortMultiplierPort);
> +      DEBUG ((DEBUG_INFO, "FreezeLockDevice return %r!\n", Status));
> +      Status = 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 bytes
> +
> +**/
> +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      = NULL;
> +  HashData  = NULL;
> +  Status    = FALSE;
> +
> +  HashSize = Sha256GetContextSize ();
> +  Hash     = AllocateZeroPool (HashSize);
> +  ASSERT (Hash != NULL);
> +  if (Hash == NULL) {
> +    goto Done;
> +  }
> +
> +  Status = Sha256Init (Hash);
> +  if (!Status) {
> +    goto Done;
> +  }
> +
> +  HashData = AllocateZeroPool (PASSWORD_SALT_SIZE + BufferSize);
> +  ASSERT (HashData != NULL);
> +  if (HashData == NULL) {
> +    goto Done;
> +  }
> +
> +  CopyMem (HashData, SaltValue, PASSWORD_SALT_SIZE);
> +  CopyMem ((UINT8 *) HashData + PASSWORD_SALT_SIZE, Buffer,
> BufferSize);
> +
> +  Status = Sha256Update (Hash, HashData, PASSWORD_SALT_SIZE +
> BufferSize);
> +  if (!Status) {
> +    goto Done;
> +  }
> +
> +  Status = Sha256Final (Hash, Credential);
> +
> +Done:
> +  if (Hash != NULL) {
> +    FreePool (Hash);
> +  }
> +  if (HashData != 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 device.
> +
> +**/
> +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 = FALSE;
> +  if (!PasswordIsFullZero (Password)) {
> +    //
> +    // It is Set/Update HDD Password.
> +    //
> +    ZeroMem (HashData, sizeof (HashData));
> +    ZeroMem (SaltData, sizeof (SaltData));
> +    GenSalt (SaltData);
> +    HashOk = 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 = TRUE;
> +  }
> +
> +  Variable = NULL;
> +  VariableSize = 0;
> +  NewVariable = NULL;
> +  NewVariableSize = 0;
> +
> +  Status = GetVariable2 (
> +             HDD_PASSWORD_VARIABLE_NAME,
> +             &mHddPasswordVendorGuid,
> +             (VOID **) &Variable,
> +             &VariableSize
> +             );
> +  if (Delete) {
> +    if (!EFI_ERROR (Status) && (Variable != NULL)) {
> +      TempVariable = Variable;
> +      TempVariableSize = VariableSize;
> +      while (TempVariableSize >= sizeof (HDD_PASSWORD_VARIABLE)) {
> +        if ((TempVariable->Device.Bus                == ConfigFormEntry->Bus) &&
> +            (TempVariable->Device.Device             == ConfigFormEntry->Device)
> &&
> +            (TempVariable->Device.Function           == ConfigFormEntry->Function)
> &&
> +            (TempVariable->Device.Port               == ConfigFormEntry->Port) &&
> +            (TempVariable->Device.PortMultiplierPort == ConfigFormEntry-
> >PortMultiplierPort)) {
> +          //
> +          // Found the node for the HDD password device.
> +          // Delete the node.
> +          //
> +          NextNode = TempVariable + 1;
> +          CopyMem (TempVariable, NextNode, (UINTN) Variable + VariableSize
> - (UINTN) NextNode);
> +          NewVariable = Variable;
> +          NewVariableSize = VariableSize - sizeof (HDD_PASSWORD_VARIABLE);
> +          break;
> +        }
> +        TempVariableSize -= sizeof (HDD_PASSWORD_VARIABLE);
> +        TempVariable += 1;
> +      }
> +      if (NewVariable == 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 != NULL)) {
> +      TempVariable = Variable;
> +      TempVariableSize = VariableSize;
> +      while (TempVariableSize >= sizeof (HDD_PASSWORD_VARIABLE)) {
> +        if ((TempVariable->Device.Bus                == ConfigFormEntry->Bus) &&
> +            (TempVariable->Device.Device             == ConfigFormEntry->Device)
> &&
> +            (TempVariable->Device.Function           == ConfigFormEntry->Function)
> &&
> +            (TempVariable->Device.Port               == ConfigFormEntry->Port) &&
> +            (TempVariable->Device.PortMultiplierPort == ConfigFormEntry-
> >PortMultiplierPort)) {
> +          //
> +          // Found the node for the HDD password device.
> +          // Update the node.
> +          //
> +          CopyMem (TempVariable->PasswordHash, HashData, sizeof
> (HashData));
> +          CopyMem (TempVariable->PasswordSalt, SaltData, sizeof (SaltData));
> +          NewVariable = Variable;
> +          NewVariableSize = VariableSize;
> +          break;
> +        }
> +        TempVariableSize -= sizeof (HDD_PASSWORD_VARIABLE);
> +        TempVariable += 1;
> +      }
> +      if (NewVariable == NULL) {
> +        //
> +        // The node for the HDD password device is not found.
> +        // Create node for the HDD password device.
> +        //
> +        NewVariableSize = VariableSize + sizeof (HDD_PASSWORD_VARIABLE);
> +        NewVariable = AllocateZeroPool (NewVariableSize);
> +        ASSERT (NewVariable != NULL);
> +        CopyMem (NewVariable, Variable, VariableSize);
> +        TempVariable = (HDD_PASSWORD_VARIABLE *) ((UINTN) NewVariable
> + VariableSize);
> +        TempVariable->Device.Bus                = (UINT8) ConfigFormEntry->Bus;
> +        TempVariable->Device.Device             = (UINT8) ConfigFormEntry-
> >Device;
> +        TempVariable->Device.Function           = (UINT8) ConfigFormEntry-
> >Function;
> +        TempVariable->Device.Port               = ConfigFormEntry->Port;
> +        TempVariable->Device.PortMultiplierPort = ConfigFormEntry-
> >PortMultiplierPort;
> +        CopyMem (TempVariable->PasswordHash, HashData, sizeof
> (HashData));
> +        CopyMem (TempVariable->PasswordSalt, SaltData, sizeof (SaltData));
> +      }
> +    } else {
> +      NewVariableSize = sizeof (HDD_PASSWORD_VARIABLE);
> +      NewVariable = AllocateZeroPool (NewVariableSize);
> +      ASSERT (NewVariable != NULL);
> +      NewVariable->Device.Bus                = (UINT8) ConfigFormEntry->Bus;
> +      NewVariable->Device.Device             = (UINT8) ConfigFormEntry->Device;
> +      NewVariable->Device.Function           = (UINT8) ConfigFormEntry-
> >Function;
> +      NewVariable->Device.Port               = ConfigFormEntry->Port;
> +      NewVariable->Device.PortMultiplierPort = ConfigFormEntry-
> >PortMultiplierPort;
> +      CopyMem (NewVariable->PasswordHash, HashData, sizeof (HashData));
> +      CopyMem (NewVariable->PasswordSalt, SaltData, sizeof (SaltData));
> +    }
> +  }
> +
> +  if (NewVariable != NULL) {
> +    Status = 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 != Variable) {
> +    FreePool (NewVariable);
> +  }
> +  if (Variable != 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 found
> 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 = NULL;
> +  VariableSize = 0;
> +
> +  Status = GetVariable2 (
> +             HDD_PASSWORD_VARIABLE_NAME,
> +             &mHddPasswordVendorGuid,
> +             (VOID **) &Variable,
> +             &VariableSize
> +             );
> +  if (EFI_ERROR (Status) || (Variable == NULL)) {
> +    DEBUG ((DEBUG_INFO, "HddPassword variable get failed (%r)\n",
> Status));
> +    return FALSE;
> +  }
> +
> +  Found = FALSE;
> +  TempVariable = Variable;
> +  while (VariableSize >= sizeof (HDD_PASSWORD_VARIABLE)) {
> +    if ((TempVariable->Device.Bus                == ConfigFormEntry->Bus) &&
> +        (TempVariable->Device.Device             == ConfigFormEntry->Device) &&
> +        (TempVariable->Device.Function           == ConfigFormEntry->Function)
> &&
> +        (TempVariable->Device.Port               == ConfigFormEntry->Port) &&
> +        (TempVariable->Device.PortMultiplierPort == ConfigFormEntry-
> >PortMultiplierPort)) {
> +      //
> +      // Found the node for the HDD password device.
> +      // Get the node.
> +      //
> +      CopyMem (HddPasswordVariable, TempVariable, sizeof
> (HDD_PASSWORD_VARIABLE));
> +      Found = TRUE;
> +      break;
> +    }
> +    VariableSize -= sizeof (HDD_PASSWORD_VARIABLE);
> +    TempVariable += 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 HDD
> 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 = 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)) != 0) {
> +    Status = EFI_INVALID_PARAMETER;
> +  } else {
> +    Status = 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 protocol.
> +  @param[in] Port                The port number of the ATA device 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 master password.
> +  @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 == NULL) || (Password == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in
> +  // 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. Hence,
> we
> +  // use the API AllocateAlignedPages to ensure this structure is properly
> +  // aligned.
> +  //
> +  Asb = AllocateAlignedPages (
> +          EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)),
> +          AtaPassThru->Mode->IoAlign
> +          );
> +  if (Asb == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  //
> +  // Prepare for ATA command block.
> +  //
> +  ZeroMem (&Acb, sizeof (Acb));
> +  ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK));
> +  Acb.AtaCommand    = ATA_SECURITY_UNLOCK_CMD;
> +  Acb.AtaDeviceHead = (UINT8) (PortMultiplierPort == 0xFFFF ? 0 :
> (PortMultiplierPort << 4));
> +
> +  //
> +  // Prepare for ATA pass through packet.
> +  //
> +  ZeroMem (&Packet, sizeof (Packet));
> +  Packet.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT;
> +  Packet.Length   = EFI_ATA_PASS_THRU_LENGTH_BYTES;
> +  Packet.Asb      = Asb;
> +  Packet.Acb      = &Acb;
> +
> +  ((CHAR16 *) Buffer)[0] = Identifier & BIT0;
> +  CopyMem (&((CHAR16 *) Buffer)[1], Password,
> HDD_PASSWORD_MAX_LENGTH);
> +
> +  Packet.OutDataBuffer     = Buffer;
> +  Packet.OutTransferLength = sizeof (Buffer);
> +  Packet.Timeout           = ATA_TIMEOUT;
> +
> +  Status = AtaPassThru->PassThru (
> +                          AtaPassThru,
> +                          Port,
> +                          PortMultiplierPort,
> +                          &Packet,
> +                          NULL
> +                          );
> +  if (!EFI_ERROR (Status) &&
> +      ((Asb->AtaStatus & ATA_STSREG_ERR) != 0) &&
> +      ((Asb->AtaError & ATA_ERRREG_ABRT) != 0)) {
> +    Status = 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 protocol.
> +  @param[in] Port                The port number of the ATA device 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 master password.
> +  @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 == NULL) || (Password == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in
> +  // 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. Hence,
> we
> +  // use the API AllocateAlignedPages to ensure this structure is properly
> +  // aligned.
> +  //
> +  Asb = AllocateAlignedPages (
> +          EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)),
> +          AtaPassThru->Mode->IoAlign
> +          );
> +  if (Asb == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  //
> +  // Prepare for ATA command block.
> +  //
> +  ZeroMem (&Acb, sizeof (Acb));
> +  ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK));
> +  Acb.AtaCommand    = ATA_SECURITY_DIS_PASSWORD_CMD;
> +  Acb.AtaDeviceHead = (UINT8) (PortMultiplierPort == 0xFFFF ? 0 :
> (PortMultiplierPort << 4));
> +
> +  //
> +  // Prepare for ATA pass through packet.
> +  //
> +  ZeroMem (&Packet, sizeof (Packet));
> +  Packet.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT;
> +  Packet.Length   = EFI_ATA_PASS_THRU_LENGTH_BYTES;
> +  Packet.Asb      = Asb;
> +  Packet.Acb      = &Acb;
> +
> +  ((CHAR16 *) Buffer)[0] = Identifier & BIT0;
> +  CopyMem (&((CHAR16 *) Buffer)[1], Password,
> HDD_PASSWORD_MAX_LENGTH);
> +
> +  Packet.OutDataBuffer     = Buffer;
> +  Packet.OutTransferLength = sizeof (Buffer);
> +  Packet.Timeout           = ATA_TIMEOUT;
> +
> +  Status = AtaPassThru->PassThru (
> +                          AtaPassThru,
> +                          Port,
> +                          PortMultiplierPort,
> +                          &Packet,
> +                          NULL
> +                          );
> +  if (!EFI_ERROR (Status) &&
> +      ((Asb->AtaStatus & ATA_STSREG_ERR) != 0) &&
> +      ((Asb->AtaError & ATA_ERRREG_ABRT) != 0)) {
> +    Status = 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 device 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 master
> password.
> +  @param[in] SecurityLevel              The security level to be set to device.
> +  @param[in] MasterPasswordIdentifier   The master password identifier to
> 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 == NULL) || (Password == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in
> +  // 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. Hence,
> we
> +  // use the API AllocateAlignedPages to ensure this structure is properly
> +  // aligned.
> +  //
> +  Asb = AllocateAlignedPages (
> +          EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)),
> +          AtaPassThru->Mode->IoAlign
> +          );
> +  if (Asb == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  //
> +  // Prepare for ATA command block.
> +  //
> +  ZeroMem (&Acb, sizeof (Acb));
> +  ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK));
> +  Acb.AtaCommand    = ATA_SECURITY_SET_PASSWORD_CMD;
> +  Acb.AtaDeviceHead = (UINT8) (PortMultiplierPort == 0xFFFF ? 0 :
> (PortMultiplierPort << 4));
> +
> +  //
> +  // Prepare for ATA pass through packet.
> +  //
> +  ZeroMem (&Packet, sizeof (Packet));
> +  Packet.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT;
> +  Packet.Length   = EFI_ATA_PASS_THRU_LENGTH_BYTES;
> +  Packet.Asb      = Asb;
> +  Packet.Acb      = &Acb;
> +
> +  ((CHAR16 *) Buffer)[0] = (Identifier | (UINT16)(SecurityLevel << 8)) & (BIT0
> | BIT8);
> +  CopyMem (&((CHAR16 *) Buffer)[1], Password,
> HDD_PASSWORD_MAX_LENGTH);
> +  if ((Identifier & BIT0) != 0) {
> +    ((CHAR16 *) Buffer)[17] = MasterPasswordIdentifier;
> +  }
> +
> +  Packet.OutDataBuffer     = Buffer;
> +  Packet.OutTransferLength = sizeof (Buffer);
> +  Packet.Timeout           = ATA_TIMEOUT;
> +
> +  Status = AtaPassThru->PassThru (
> +                          AtaPassThru,
> +                          Port,
> +                          PortMultiplierPort,
> +                          &Packet,
> +                          NULL
> +                          );
> +  if (!EFI_ERROR (Status) &&
> +      ((Asb->AtaStatus & ATA_STSREG_ERR) != 0) &&
> +      ((Asb->AtaError & ATA_ERRREG_ABRT) != 0)) {
> +    Status = 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 = 0; Index < 40; Index += 2) {
> +    String[Index]      = IdentifyData->ModelName[Index + 1];
> +    String[Index + 1]  = IdentifyData->ModelName[Index];
> +  }
> +
> +  //
> +  // Chap it off after 20 characters
> +  //
> +  String[20] = 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 = 0;
> +  while (TRUE) {
> +    Mask[Length] = L'_';
> +    if (PopUpString2 == 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 == SCAN_NULL) {
> +      if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
> +        //
> +        // Add the null terminator.
> +        //
> +        Unicode[Length] = 0;
> +        break;
> +      } else if ((Key.UnicodeChar == CHAR_NULL) ||
> +                 (Key.UnicodeChar == CHAR_TAB) ||
> +                 (Key.UnicodeChar == CHAR_LINEFEED)
> +                 ) {
> +        continue;
> +      } else {
> +        if (Key.UnicodeChar == CHAR_BACKSPACE) {
> +          if (Length > 0) {
> +            Unicode[Length] = 0;
> +            Mask[Length] = 0;
> +            Length--;
> +          }
> +        } else {
> +          Unicode[Length] = Key.UnicodeChar;
> +          Mask[Length] = L'*';
> +          Length++;
> +          if (Length == HDD_PASSWORD_MAX_LENGTH) {
> +            //
> +            // Add the null terminator.
> +            //
> +            Unicode[Length] = 0;
> +            Mask[Length] = 0;
> +            break;
> +          }
> +        }
> +      }
> +    }
> +
> +    if (Key.ScanCode == 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 device.
> +  @param[in] PortMultiplierPort     The port number of port multiplier of
> 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 = 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 window
> 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 = 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 = UnlockHddPassword (AtaPassThru, Port, PortMultiplierPort,
> 0, Password);
> +          } else {
> +            //
> +            // Use saved HDD password variable to validate HDD password
> +            // when the device is at frozen state.
> +            //
> +            Status = ValidateHddPassword (ConfigFormEntry, Password);
> +          }
> +        } else {
> +          Status = 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 = 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 != CHAR_CARRIAGE_RETURN);
> +            continue;
> +          } else {
> +            do {
> +              CreatePopUp (
> +                EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
> +                &Key,
> +                L"Hdd password retry count is expired. Please shutdown the
> machine.",
> +                L"Press ENTER to shutdown",
> +                NULL
> +                );
> +            } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
> +            gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);
> +            break;
> +          }
> +        }
> +      } else if (Status == 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 != SCAN_ESC) && (Key.UnicodeChar !=
> CHAR_CARRIAGE_RETURN));
> +
> +          if (Key.UnicodeChar == 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 again",
> +              NULL
> +              );
> +          } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar !=
> CHAR_CARRIAGE_RETURN));
> +
> +          if (Key.UnicodeChar == 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 device.
> +  @param[in] PortMultiplierPort     The port number of port multiplier of
> 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_LENGTH];
> +
> +  RetryCount = 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 = PopupHddPasswordInputWindows (PopUpString, L"Please type
> in your new password", Password);
> +      if (!EFI_ERROR (Status)) {
> +        Status = PopupHddPasswordInputWindows (PopUpString, L"Please
> confirm your new password", PasswordConfirm);
> +        if (!EFI_ERROR (Status)) {
> +          if (CompareMem (Password, PasswordConfirm,
> HDD_PASSWORD_MAX_LENGTH) == 0) {
> +            if (!PasswordIsFullZero (Password)) {
> +              Status = SetHddPassword (AtaPassThru, Port, PortMultiplierPort, 0, 1,
> 0, Password);
> +            } else {
> +              if (ConfigFormEntry->IfrData.SecurityStatus.Enabled) {
> +                Status = DisableHddPassword (AtaPassThru, Port,
> PortMultiplierPort, 0, ConfigFormEntry->Password);
> +              } else {
> +                Status = 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 = GetHddDeviceIdentifyData (AtaPassThru, Port,
> PortMultiplierPort, &IdentifyData);
> +              ASSERT_EFI_ERROR (Status);
> +
> +              //
> +              // Check the device security status again.
> +              //
> +              GetHddPasswordSecurityStatus (&IdentifyData, &ConfigFormEntry-
> >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 != 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 != CHAR_CARRIAGE_RETURN);
> +            Status = EFI_INVALID_PARAMETER;
> +          }
> +        }
> +
> +        ZeroMem (Password, HDD_PASSWORD_MAX_LENGTH);
> +        ZeroMem (PasswordConfirm, 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"Hdd password retry count is expired.",
> +                L"Press ENTER to skip the request and continue boot",
> +                NULL
> +                );
> +            } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
> +            gST->ConOut->ClearScreen(gST->ConOut);
> +            return;
> +          }
> +        }
> +      } else if (Status == 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 != SCAN_ESC) && (Key.UnicodeChar !=
> CHAR_CARRIAGE_RETURN));
> +
> +        if (Key.UnicodeChar == 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 device.
> +  @param[in] PortMultiplierPort     The port number of port multiplier of
> 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_LENGTH];
> +
> +  RetryCount = 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 = PopupHddPasswordInputWindows (PopUpString, L"Please type
> in your new password", Password);
> +      if (!EFI_ERROR (Status)) {
> +        Status = PopupHddPasswordInputWindows (PopUpString, L"Please
> confirm your new password", PasswordConfirm);
> +        if (!EFI_ERROR (Status)) {
> +          if (CompareMem (Password, PasswordConfirm,
> HDD_PASSWORD_MAX_LENGTH) == 0) {
> +            if (!PasswordIsFullZero (Password)) {
> +              Status = SetHddPassword (AtaPassThru, Port, PortMultiplierPort, 1, 1,
> 1, Password);
> +            } else {
> +              Status = 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 != 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 != CHAR_CARRIAGE_RETURN);
> +            Status = EFI_INVALID_PARAMETER;
> +          }
> +        }
> +
> +        ZeroMem (Password, HDD_PASSWORD_MAX_LENGTH);
> +        ZeroMem (PasswordConfirm, 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"Hdd password retry count is expired.",
> +                L"Press ENTER to skip the request and continue boot",
> +                NULL
> +                );
> +            } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
> +            gST->ConOut->ClearScreen(gST->ConOut);
> +            return;
> +          }
> +        }
> +      } else if (Status == 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 != SCAN_ESC) && (Key.UnicodeChar !=
> CHAR_CARRIAGE_RETURN));
> +
> +        if (Key.UnicodeChar == 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 device.
> +  @param[in] PortMultiplierPort     The port number of port multiplier of
> 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 == NULL) {
> +    Status = GetVariable2 (
> +               HDD_PASSWORD_REQUEST_VARIABLE_NAME,
> +               &mHddPasswordVendorGuid,
> +               (VOID **) &Variable,
> +               &VariableSize
> +               );
> +    if (EFI_ERROR (Status) || (Variable == NULL)) {
> +      return;
> +    }
> +    mHddPasswordRequestVariable = Variable;
> +    mHddPasswordRequestVariableSize = VariableSize;
> +
> +    //
> +    // Delete the HDD password request variable.
> +    //
> +    Status = gRT->SetVariable (
> +                    HDD_PASSWORD_REQUEST_VARIABLE_NAME,
> +                    &mHddPasswordVendorGuid,
> +                    0,
> +                    0,
> +                    NULL
> +                    );
> +    ASSERT_EFI_ERROR (Status);
> +  } else {
> +    Variable = mHddPasswordRequestVariable;
> +    VariableSize = mHddPasswordRequestVariableSize;
> +  }
> +
> +  //
> +  // Process the HDD password requests.
> +  //
> +  TempVariable = Variable;
> +  while (VariableSize >= sizeof (HDD_PASSWORD_REQUEST_VARIABLE)) {
> +    if ((TempVariable->Device.Bus                == ConfigFormEntry->Bus) &&
> +        (TempVariable->Device.Device             == ConfigFormEntry->Device) &&
> +        (TempVariable->Device.Function           == ConfigFormEntry->Function)
> &&
> +        (TempVariable->Device.Port               == ConfigFormEntry->Port) &&
> +        (TempVariable->Device.PortMultiplierPort == ConfigFormEntry-
> >PortMultiplierPort)) {
> +      //
> +      // Found the node for the HDD password device.
> +      //
> +      if (TempVariable->Request.UserPassword != 0) {
> +        ProcessHddPasswordRequestSetUserPwd (AtaPassThru, Port,
> PortMultiplierPort, ConfigFormEntry);
> +      }
> +      if (TempVariable->Request.MasterPassword != 0) {
> +        ProcessHddPasswordRequestSetMasterPwd (AtaPassThru, Port,
> PortMultiplierPort, ConfigFormEntry);
> +      }
> +
> +      break;
> +    }
> +
> +    VariableSize -= sizeof (HDD_PASSWORD_REQUEST_VARIABLE);
> +    TempVariable += 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 = NULL;
> +  VariableSize = 0;
> +
> +  Status = GetVariable2 (
> +             HDD_PASSWORD_REQUEST_VARIABLE_NAME,
> +             &mHddPasswordVendorGuid,
> +             (VOID **) &Variable,
> +             &VariableSize
> +             );
> +  if (EFI_ERROR (Status) || (Variable == NULL)) {
> +    return;
> +  }
> +
> +  TempVariable = Variable;
> +  while (VariableSize >= sizeof (HDD_PASSWORD_REQUEST_VARIABLE)) {
> +    if ((TempVariable->Device.Bus                == ConfigFormEntry->Bus) &&
> +        (TempVariable->Device.Device             == ConfigFormEntry->Device) &&
> +        (TempVariable->Device.Function           == ConfigFormEntry->Function)
> &&
> +        (TempVariable->Device.Port               == ConfigFormEntry->Port) &&
> +        (TempVariable->Device.PortMultiplierPort == 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 -= sizeof (HDD_PASSWORD_REQUEST_VARIABLE);
> +    TempVariable += 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 = NULL;
> +  VariableSize = 0;
> +  NewVariable = NULL;
> +  NewVariableSize = 0;
> +
> +  Status = GetVariable2 (
> +             HDD_PASSWORD_REQUEST_VARIABLE_NAME,
> +             &mHddPasswordVendorGuid,
> +             (VOID **) &Variable,
> +             &VariableSize
> +             );
> +  if (!EFI_ERROR (Status) && (Variable != NULL)) {
> +    TempVariable = Variable;
> +    TempVariableSize = VariableSize;
> +    while (TempVariableSize >= sizeof
> (HDD_PASSWORD_REQUEST_VARIABLE)) {
> +      if ((TempVariable->Device.Bus                == ConfigFormEntry->Bus) &&
> +          (TempVariable->Device.Device             == ConfigFormEntry->Device) &&
> +          (TempVariable->Device.Function           == ConfigFormEntry->Function)
> &&
> +          (TempVariable->Device.Port               == ConfigFormEntry->Port) &&
> +          (TempVariable->Device.PortMultiplierPort == ConfigFormEntry-
> >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 = Variable;
> +        NewVariableSize = VariableSize;
> +        break;
> +      }
> +      TempVariableSize -= sizeof (HDD_PASSWORD_REQUEST_VARIABLE);
> +      TempVariable += 1;
> +    }
> +    if (NewVariable == NULL) {
> +      //
> +      // The node for the HDD password device is not found.
> +      // Create node for the HDD password device.
> +      //
> +      NewVariableSize = VariableSize + sizeof
> (HDD_PASSWORD_REQUEST_VARIABLE);
> +      NewVariable = AllocateZeroPool (NewVariableSize);
> +      ASSERT (NewVariable != NULL);
> +      CopyMem (NewVariable, Variable, VariableSize);
> +      TempVariable = (HDD_PASSWORD_REQUEST_VARIABLE *) ((UINTN)
> NewVariable + VariableSize);
> +      TempVariable->Device.Bus                = (UINT8) ConfigFormEntry->Bus;
> +      TempVariable->Device.Device             = (UINT8) ConfigFormEntry->Device;
> +      TempVariable->Device.Function           = (UINT8) ConfigFormEntry-
> >Function;
> +      TempVariable->Device.Port               = ConfigFormEntry->Port;
> +      TempVariable->Device.PortMultiplierPort = ConfigFormEntry-
> >PortMultiplierPort;
> +      CopyMem (&TempVariable->Request, &ConfigFormEntry-
> >IfrData.Request, sizeof (HDD_PASSWORD_REQUEST));
> +    }
> +  } else {
> +    NewVariableSize = sizeof (HDD_PASSWORD_REQUEST_VARIABLE);
> +    NewVariable = AllocateZeroPool (NewVariableSize);
> +    ASSERT (NewVariable != NULL);
> +    NewVariable->Device.Bus                = (UINT8) ConfigFormEntry->Bus;
> +    NewVariable->Device.Device             = (UINT8) ConfigFormEntry->Device;
> +    NewVariable->Device.Function           = (UINT8) ConfigFormEntry-
> >Function;
> +    NewVariable->Device.Port               = ConfigFormEntry->Port;
> +    NewVariable->Device.PortMultiplierPort = ConfigFormEntry-
> >PortMultiplierPort;
> +    CopyMem (&NewVariable->Request, &ConfigFormEntry-
> >IfrData.Request, sizeof (HDD_PASSWORD_REQUEST));
> +  }
> +  Status = 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 != Variable) {
> +    FreePool (NewVariable);
> +  }
> +  if (Variable != 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    = 0;
> +  ConfigFormEntry = NULL;
> +
> +  EFI_LIST_FOR_EACH (Entry, &mHddPasswordConfigFormList) {
> +    if (CurrentIndex == Index) {
> +      ConfigFormEntry = 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 <ConfigAltResp> 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=<StringToken>". That <StringToken> (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
> +                        <ConfigRequest> 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
> +                        <MultiConfigRequest> 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
> +                        <ConfigAltResp> format which has all values
> +                        filled in for the names in the Request string.
> +                        String to be allocated by the called function.
> +
> +  @retval EFI_SUCCESS             The Results 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 <ConfigHdr> 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 == NULL || Results == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  *Progress = Request;
> +  if ((Request != NULL) && !HiiIsConfigHdrMatch (Request,
> &mHddPasswordVendorGuid, mHddPasswordVendorStorageName)) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  ConfigRequestHdr = NULL;
> +  ConfigRequest    = NULL;
> +  AllocatedRequest = FALSE;
> +  Size             = 0;
> +
> +  Private = HDD_PASSWORD_DXE_PRIVATE_FROM_THIS (This);
> +  IfrData = AllocateZeroPool (sizeof (HDD_PASSWORD_CONFIG));
> +  ASSERT (IfrData != NULL);
> +  if (Private->Current != NULL) {
> +    CopyMem (IfrData, &Private->Current->IfrData, sizeof
> (HDD_PASSWORD_CONFIG));
> +  }
> +
> +  //
> +  // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
> +  //
> +  BufferSize = sizeof (HDD_PASSWORD_CONFIG);
> +  ConfigRequest = Request;
> +  if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
> +    //
> +    // Request has no request element, construct full request string.
> +    // Allocate and fill a buffer large enough to hold the <ConfigHdr>
> template
> +    // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW"
> followed by a Null-terminator
> +    //
> +    ConfigRequestHdr = HiiConstructConfigHdr (&mHddPasswordVendorGuid,
> mHddPasswordVendorStorageName, Private->DriverHandle);
> +    Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
> +    ConfigRequest = AllocateZeroPool (Size);
> +    ASSERT (ConfigRequest != NULL);
> +    AllocatedRequest = TRUE;
> +    UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX",
> ConfigRequestHdr, (UINT64)BufferSize);
> +    FreePool (ConfigRequestHdr);
> +  }
> +  Status = gHiiConfigRouting->BlockToConfig (
> +                                gHiiConfigRouting,
> +                                ConfigRequest,
> +                                (UINT8 *) IfrData,
> +                                BufferSize,
> +                                Results,
> +                                Progress
> +                                );
> +  FreePool (IfrData);
> +  //
> +  // Free the allocated config request string.
> +  //
> +  if (AllocatedRequest) {
> +    FreePool (ConfigRequest);
> +    ConfigRequest = NULL;
> +  }
> +
> +  //
> +  // Set Progress string to the original request string.
> +  //
> +  if (Request == NULL) {
> +    *Progress = NULL;
> +  } else if (StrStr (Request, L"OFFSET") == NULL) {
> +    *Progress = 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 <BlockConfig>
> +  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_PROTOCOL.
> +  @param[in]  Configuration  A null-terminated Unicode string in
> +                             <ConfigString> 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 are
> +                                  awaiting distribution.
> +  @retval EFI_OUT_OF_RESOURCES    Not enough memory to store the
> +                                  parts of the results that must be
> +                                  stored awaiting possible future
> +                                  protocols.
> +  @retval EFI_INVALID_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 == NULL || Progress == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // Check routing data in <ConfigHdr>.
> +  // Note: if only one Storage is used, then this checking could be skipped.
> +  //
> +  if (!HiiIsConfigHdrMatch (Configuration, &mHddPasswordVendorGuid,
> mHddPasswordVendorStorageName)) {
> +    *Progress = Configuration;
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  *Progress = 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 the browser.
> +  @param[in]  QuestionId         A unique value which is sent to the original
> +                                 exporting driver so that it can identify the type
> +                                 of data to expect. The format of the data tends to
> +                                 vary based on the 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 requested
> by the
> +                                 callback function.
> +
> +  @retval EFI_SUCCESS            The callback successfully handled the action.
> +  @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold
> the
> +                                 variable and its data.
> +  @retval EFI_DEVICE_ERROR       The variable could not be saved.
> +  @retval EFI_UNSUPPORTED        The specified Action is not supported by
> the
> +                                 callback.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 != NULL) {
> +    *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
> +  } else {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if ((Action != EFI_BROWSER_ACTION_CHANGING) && (Action !=
> EFI_BROWSER_ACTION_CHANGED)) {
> +    //
> +    // Do nothing for other UEFI Action. Only do call back when data is
> changing or changed.
> +    //
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  Private = HDD_PASSWORD_DXE_PRIVATE_FROM_THIS (This);
> +
> +  //
> +  // Retrive data from Browser
> +  //
> +  IfrData = AllocateZeroPool (sizeof (HDD_PASSWORD_CONFIG));
> +  ASSERT (IfrData != 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 == EFI_BROWSER_ACTION_CHANGED) {
> +      DEBUG ((DEBUG_INFO, "KEY_HDD_USER_PASSWORD\n"));
> +      ConfigFormEntry = Private->Current;
> +      ConfigFormEntry->IfrData.Request.UserPassword = Value->b;
> +      SaveHddPasswordRequest (ConfigFormEntry);
> +      *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
> +    }
> +    break;
> +  case KEY_HDD_MASTER_PASSWORD:
> +    if (Action == EFI_BROWSER_ACTION_CHANGED) {
> +      DEBUG ((DEBUG_INFO, "KEY_HDD_MASTER_PASSWORD\n"));
> +      ConfigFormEntry = Private->Current;
> +      ConfigFormEntry->IfrData.Request.MasterPassword = Value->b;
> +      SaveHddPasswordRequest (ConfigFormEntry);
> +      *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
> +    }
> +    break;
> +
> +  default:
> +    if ((QuestionId >= KEY_HDD_DEVICE_ENTRY_BASE) && (QuestionId <
> (mNumberOfHddDevices + KEY_HDD_DEVICE_ENTRY_BASE))) {
> +      if (Action == EFI_BROWSER_ACTION_CHANGING) {
> +        //
> +        // In case goto the device configuration form, update the device form
> title.
> +        //
> +        ConfigFormEntry = HddPasswordGetConfigFormEntryByIndex ((UINT32)
> (QuestionId - KEY_HDD_DEVICE_ENTRY_BASE));
> +        ASSERT (ConfigFormEntry != NULL);
> +
> +        DeviceFormTitleToken = (EFI_STRING_ID) STR_HDD_SECURITY_HD;
> +        HiiSetString (Private->HiiHandle, DeviceFormTitleToken,
> ConfigFormEntry->HddString, NULL);
> +
> +        Private->Current = 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 registered
> 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 = NULL;
> +  EntryExisted    = FALSE;
> +
> +  EFI_LIST_FOR_EACH (Entry, &mHddPasswordConfigFormList) {
> +    ConfigFormEntry = BASE_CR (Entry,
> HDD_PASSWORD_CONFIG_FORM_ENTRY, Link);
> +
> +    if ((ConfigFormEntry->Bus == Bus) &&
> +        (ConfigFormEntry->Device == Device) &&
> +        (ConfigFormEntry->Function == Function) &&
> +        (ConfigFormEntry->Port == Port) &&
> +        (ConfigFormEntry->PortMultiplierPort == PortMultiplierPort)) {
> +      EntryExisted = TRUE;
> +      break;
> +    }
> +  }
> +
> +  if (!EntryExisted) {
> +    //
> +    // Add a new form.
> +    //
> +    ConfigFormEntry = AllocateZeroPool (sizeof
> (HDD_PASSWORD_CONFIG_FORM_ENTRY));
> +    if (ConfigFormEntry == NULL) {
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +
> +    InitializeListHead (&ConfigFormEntry->Link);
> +    ConfigFormEntry->Controller         = Controller;
> +    ConfigFormEntry->Bus                = Bus;
> +    ConfigFormEntry->Device             = Device;
> +    ConfigFormEntry->Function           = Function;
> +    ConfigFormEntry->Port               = Port;
> +    ConfigFormEntry->PortMultiplierPort = PortMultiplierPort;
> +    ConfigFormEntry->AtaPassThru        = 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 = AtaPassThru->BuildDevicePath (
> +                            AtaPassThru,
> +                            Port,
> +                            PortMultiplierPort,
> +                            &AtaDeviceNode
> +                            );
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +    ConfigFormEntry->DevicePath = AppendDevicePathNode
> (DevicePathFromHandle (Controller), AtaDeviceNode);
> +    FreePool (AtaDeviceNode);
> +    if (ConfigFormEntry->DevicePath == NULL) {
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +
> +    //
> +    // Get attached harddisk model number
> +    //
> +    Status = 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 create a
> new EFI_STRING_ID.
> +    //
> +    UnicodeSPrint (ConfigFormEntry->HddString, sizeof (ConfigFormEntry-
> >HddString), L"HDD %d:%s", mNumberOfHddDevices, HddString);
> +    ConfigFormEntry->TitleToken     = HiiSetString (HiiHandle, 0,
> ConfigFormEntry->HddString, NULL);
> +    ConfigFormEntry->TitleHelpToken = HiiSetString (HiiHandle, 0, L"Request
> to set HDD Password", NULL);
> +
> +    GetHddPasswordSecurityStatus (&IdentifyData, &ConfigFormEntry-
> >IfrData);
> +
> +    InsertTailList (&mHddPasswordConfigFormList, &ConfigFormEntry->Link);
> +
> +    //
> +    // Init OpCode Handle
> +    //
> +    StartOpCodeHandle = HiiAllocateOpCodeHandle ();
> +    ASSERT (StartOpCodeHandle != NULL);
> +
> +    EndOpCodeHandle = HiiAllocateOpCodeHandle ();
> +    ASSERT (EndOpCodeHandle != NULL);
> +
> +    //
> +    // Create Hii Extend Label OpCode as the start opcode
> +    //
> +    StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode
> (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof
> (EFI_IFR_GUID_LABEL));
> +    StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
> +    StartLabel->Number       = HDD_DEVICE_ENTRY_LABEL;
> +
> +    //
> +    // Create Hii Extend Label OpCode as the end opcode
> +    //
> +    EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode
> (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
> +    EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
> +    EndLabel->Number       = HDD_DEVICE_LABEL_END;
> +
> +    mNumberOfHddDevices = 0;
> +    EFI_LIST_FOR_EACH (Entry, &mHddPasswordConfigFormList) {
> +      ConfigFormEntry = BASE_CR (Entry,
> HDD_PASSWORD_CONFIG_FORM_ENTRY, Link);
> +
> +      HiiCreateGotoOpCode (
> +        StartOpCodeHandle,                                // Container for dynamic created
> opcodes
> +        FORMID_HDD_DEVICE_FORM,                           // Target Form ID
> +        ConfigFormEntry->TitleToken,                      // Prompt text
> +        ConfigFormEntry->TitleHelpToken,                  // Help text
> +        EFI_IFR_FLAG_CALLBACK,                            // Question flag
> +        (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 = (HDD_PASSWORD_DXE_PRIVATE_DATA *)Context;
> +
> +  //
> +  // Locate all handles of AtaPassThru protocol
> +  //
> +  Status = 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 = 0; Index < HandleCount; Index += 1) {
> +    Controller = HandleBuffer[Index];
> +    Status = 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) == 0) {
> +      continue;
> +    }
> +
> +    Status = gBS->HandleProtocol (
> +                    Controller,
> +                    &gEfiPciIoProtocolGuid,
> +                    (VOID **) &PciIo
> +                    );
> +    ASSERT_EFI_ERROR (Status);
> +    if (EFI_ERROR (Status)) {
> +      break;
> +    }
> +
> +    Status = PciIo->GetLocation (
> +                      PciIo,
> +                      &SegNum,
> +                      &BusNum,
> +                      &DevNum,
> +                      &FuncNum
> +                      );
> +    ASSERT_EFI_ERROR (Status);
> +    if (EFI_ERROR (Status)) {
> +      break;
> +    }
> +
> +    //
> +    // Assume and only support Segment == 0.
> +    //
> +    ASSERT (SegNum == 0);
> +
> +    //
> +    // traverse all attached harddisk devices to update form and unlock it
> +    //
> +    Port = 0xFFFF;
> +
> +    while (TRUE) {
> +      Status = AtaPassThru->GetNextPort (AtaPassThru, &Port);
> +      if (EFI_ERROR (Status)) {
> +        //
> +        // We cannot find more legal port then we are done.
> +        //
> +        break;
> +      }
> +
> +      PortMultiplierPort = 0xFFFF;
> +      while (TRUE) {
> +        Status = AtaPassThru->GetNextDevice (AtaPassThru, Port,
> &PortMultiplierPort);
> +        if (EFI_ERROR (Status)) {
> +          //
> +          // We cannot find more legal port multiplier port number for ATA
> 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 = 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 is
> 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 = AllocateZeroPool (sizeof
> (HDD_PASSWORD_DXE_PRIVATE_DATA));
> +  if (Private == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  Private->Signature   = HDD_PASSWORD_DXE_PRIVATE_SIGNATURE;
> +
> +  Private->ConfigAccess.ExtractConfig = HddPasswordFormExtractConfig;
> +  Private->ConfigAccess.RouteConfig   = HddPasswordFormRouteConfig;
> +  Private->ConfigAccess.Callback      = HddPasswordFormCallback;
> +
> +  //
> +  // Install Device Path Protocol and Config Access protocol to driver handle
> +  //
> +  Status = 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 = HiiAddPackages (
> +                         &mHddPasswordVendorGuid,
> +                         Private->DriverHandle,
> +                         HddPasswordDxeStrings,
> +                         HddPasswordBin,
> +                         NULL
> +                         );
> +  if (Private->HiiHandle == NULL) {
> +    FreePool(Private);
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  *Instance = 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 = NULL;
> +
> +  //
> +  // Initialize the configuration form of HDD Password.
> +  //
> +  Status = HddPasswordConfigFormInit (&Private);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  //
> +  // Register HddPasswordNotificationEvent() notify function.
> +  //
> +  EfiCreateProtocolNotifyEvent (
> +    &gEfiAtaPassThruProtocolGuid,
> +    TPL_CALLBACK,
> +    HddPasswordNotificationEvent,
> +    (VOID *)Private,
> +    &Registration
> +    );
> +
> +  Status = gBS->CreateEventEx (
> +                  EVT_NOTIFY_SIGNAL,
> +                  TPL_CALLBACK,
> +                  HddPasswordEndOfDxeEventNotify,
> +                  NULL,
> +                  &gEfiEndOfDxeEventGroupGuid,
> +                  &EndOfDxeEvent
> +                  );
> +  ASSERT_EFI_ERROR (Status);
> +
> +  //
> +  // Make HDD_PASSWORD_VARIABLE_NAME varible read-only.
> +  //
> +  Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL,
> (VOID **) &VariableLock);
> +  if (!EFI_ERROR (Status)) {
> +    Status = 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.<BR>
> +
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions
> +  of the BSD License which accompanies this distribution.  The
> +  full text of the license may be found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#include "HddPasswordPei.h"
> +
> +EFI_GUID mHddPasswordDeviceInfoGuid =
> 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 private
> 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 = 0; Index < Private->AtaPassThruPpiInstanceNum; Index++) {
> +    if ((UINTN)PassThruInstance == 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 the
> ATA device.
> +  @param[in] Identifier            The identifier to set user or master password.
> +  @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
> +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 == NULL) || (Password == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in
> +  // 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. Hence,
> we
> +  // use the API AllocateAlignedPages to ensure this structure is properly
> +  // aligned.
> +  //
> +  Asb = AllocateAlignedPages (
> +          EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)),
> +          AtaPassThru->Mode->IoAlign
> +          );
> +  if (Asb == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  //
> +  // Prepare for ATA command block.
> +  //
> +  ZeroMem (&Acb, sizeof (Acb));
> +  ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK));
> +  Acb.AtaCommand    = ATA_SECURITY_UNLOCK_CMD;
> +  Acb.AtaDeviceHead = (UINT8) (PortMultiplierPort == 0xFFFF ? 0 :
> (PortMultiplierPort << 4));
> +
> +  //
> +  // Prepare for ATA pass through packet.
> +  //
> +  ZeroMem (&Packet, sizeof (Packet));
> +  Packet.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT;
> +  Packet.Length   = EFI_ATA_PASS_THRU_LENGTH_BYTES;
> +  Packet.Asb      = Asb;
> +  Packet.Acb      = &Acb;
> +
> +  ((CHAR16 *) Buffer)[0] = Identifier & BIT0;
> +  CopyMem (&((CHAR16 *) Buffer)[1], Password,
> HDD_PASSWORD_MAX_LENGTH);
> +
> +  Packet.OutDataBuffer     = Buffer;
> +  Packet.OutTransferLength = sizeof (Buffer);
> +  Packet.Timeout           = ATA_TIMEOUT;
> +
> +  Status = AtaPassThru->PassThru (
> +                          AtaPassThru,
> +                          Port,
> +                          PortMultiplierPort,
> +                          &Packet
> +                          );
> +  if (!EFI_ERROR (Status) &&
> +      ((Asb->AtaStatus & ATA_STSREG_ERR) != 0) &&
> +      ((Asb->AtaError & ATA_ERRREG_ABRT) != 0)) {
> +    Status = 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 the
> ATA device.
> +
> +  @retval EFI_SUCCESS              Successful to send security freeze lock 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 == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in
> +  // 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. Hence,
> we
> +  // use the API AllocateAlignedPages to ensure this structure is properly
> +  // aligned.
> +  //
> +  Asb = AllocateAlignedPages (
> +          EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)),
> +          AtaPassThru->Mode->IoAlign
> +          );
> +  if (Asb == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  //
> +  // Prepare for ATA command block.
> +  //
> +  ZeroMem (&Acb, sizeof (Acb));
> +  ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK));
> +  Acb.AtaCommand    = ATA_SECURITY_FREEZE_LOCK_CMD;
> +  Acb.AtaDeviceHead = (UINT8) (PortMultiplierPort == 0xFFFF ? 0 :
> (PortMultiplierPort << 4));
> +
> +  //
> +  // Prepare for ATA pass through packet.
> +  //
> +  ZeroMem (&Packet, sizeof (Packet));
> +  Packet.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA;
> +  Packet.Length   = EFI_ATA_PASS_THRU_LENGTH_NO_DATA_TRANSFER;
> +  Packet.Asb      = Asb;
> +  Packet.Acb      = &Acb;
> +  Packet.Timeout  = ATA_TIMEOUT;
> +
> +  Status = AtaPassThru->PassThru (
> +                          AtaPassThru,
> +                          Port,
> +                          PortMultiplierPort,
> +                          &Packet
> +                          );
> +  if (!EFI_ERROR (Status) &&
> +      ((Asb->AtaStatus & ATA_STSREG_ERR) != 0) &&
> +      ((Asb->AtaError & ATA_ERRREG_ABRT) != 0)) {
> +    Status = 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 data.
> +
> +**/
> +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 = (VOID *) &DummyData;
> +  Length = 1;
> +  Status = RestoreLockBox (&mHddPasswordDeviceInfoGuid, Buffer,
> &Length);
> +  if (Status == EFI_BUFFER_TOO_SMALL) {
> +    Buffer = AllocatePages (EFI_SIZE_TO_PAGES (Length));
> +    if (Buffer != NULL) {
> +      Status = RestoreLockBox (&mHddPasswordDeviceInfoGuid, Buffer,
> &Length);
> +    }
> +  }
> +  if ((Buffer == NULL) || (Buffer == (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 = 0;
> +       AtaPassThruInstance < MAX_ATA_PASSTHRU_PPI;
> +       AtaPassThruInstance++) {
> +    Status = 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] = (UINTN)AtaPassThruPpi;
> +      Private->AtaPassThruPpiInstanceNum++;
> +    }
> +
> +    Status = AtaPassThruPpi->GetDevicePath (AtaPassThruPpi,
> &DevicePathLength, &DevicePath);
> +    if (EFI_ERROR (Status) || (DevicePathLength <= sizeof
> (EFI_DEVICE_PATH_PROTOCOL))) {
> +      continue;
> +    }
> +
> +    //
> +    // Go through all the devices managed by this PPI instance.
> +    //
> +    Port = 0xFFFF;
> +    while (TRUE) {
> +      Status = AtaPassThruPpi->GetNextPort (AtaPassThruPpi, &Port);
> +      if (EFI_ERROR (Status)) {
> +        //
> +        // We cannot find more legal port then we are done.
> +        //
> +        break;
> +      }
> +
> +      PortMultiplierPort = 0xFFFF;
> +      while (TRUE) {
> +        Status = AtaPassThruPpi->GetNextDevice (AtaPassThruPpi, Port,
> &PortMultiplierPort);
> +        if (EFI_ERROR (Status)) {
> +          //
> +          // We cannot find more legal port multiplier port number for ATA
> device
> +          // on the port, then we are done.
> +          //
> +          break;
> +        }
> +
> +        //
> +        // Search the device in the restored LockBox.
> +        //
> +        DevInfo = (HDD_PASSWORD_DEVICE_INFO *) Buffer;
> +        while ((UINTN) DevInfo < ((UINTN) Buffer + Length)) {
> +          //
> +          // Find the matching device.
> +          //
> +          if ((DevInfo->Device.Port == Port) &&
> +              (DevInfo->Device.PortMultiplierPort == PortMultiplierPort) &&
> +              (DevInfo->DevicePathLength >= DevicePathLength) &&
> +              (CompareMem (
> +                DevInfo->DevicePath,
> +                DevicePath,
> +                DevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)) == 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 = (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 PEIM.
> +  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 = 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 = {
> +  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 = PeiServicesGetBootMode (&BootMode);
> +  if ((EFI_ERROR (Status)) || (BootMode != BOOT_ON_S3_RESUME)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  DEBUG ((DEBUG_INFO, "%a: Enters in S3 path.\n", __FUNCTION__));
> +
> +  Private = (HDD_PASSWORD_PEI_DRIVER_PRIVATE_DATA *)
> +              AllocateCopyPool (
> +                sizeof (HDD_PASSWORD_PEI_DRIVER_PRIVATE_DATA),
> +                &mHddPasswordPeiDriverPrivateTemplate
> +                );
> +  if (Private == NULL) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "%a: Failed to allocate memory for
> HDD_PASSWORD_PEI_DRIVER_PRIVATE_DATA.\n",
> +      __FUNCTION__
> +      ));
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  Status = 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.<BR>
> +//
> +// This program and the accompanying materials
> +// are licensed and made available under the terms and conditions
> +// of the BSD License which accompanies this distribution.  The
> +// full text of the license may be found at
> +// http://opensource.org/licenses/bsd-license.php
> +//
> +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +//
> +// **/
> +
> +#langdef en-US  "English"
> +
> +#string STR_HDD_SECURITY_CONFIG               #language en-US "HDD Security
> 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 Password"
> +#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 to
> 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 request
> will be ignored. *** "
> +
> +#string STR_INSTALLED                         #language en-US "INSTALLED"
> +#string STR_NOT_INSTALLED                     #language en-US "NOT INSTALLED"
> +#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



  reply	other threads:[~2019-02-18  7:47 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-02-15  2:49 [PATCH v1 0/1] Add Security feature set support for ATA devices Hao Wu
2019-02-15  2:49 ` [PATCH v1 1/1] SecurityPkg/HddPassword: Add Security feature set support for ATA dev Hao Wu
2019-02-18  7:47   ` Dong, Eric [this message]
2019-02-19  2:52     ` Wu, Hao A
2019-02-20 13:10   ` Ni, Ray

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ED077930C258884BBCB450DB737E662259DB120E@shsmsx102.ccr.corp.intel.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox