From: "Ni, Ray" <ray.ni@intel.com>
To: "Wu, Hao A" <hao.a.wu@intel.com>,
"edk2-devel@lists.01.org" <edk2-devel@lists.01.org>
Cc: "Dong, Eric" <eric.dong@intel.com>,
"Zhang, Chao B" <chao.b.zhang@intel.com>,
"Yao, Jiewen" <jiewen.yao@intel.com>
Subject: Re: [PATCH v2 1/1] SecurityPkg/HddPassword: Add Security feature set support for ATA dev
Date: Thu, 21 Feb 2019 04:52:07 +0000 [thread overview]
Message-ID: <734D49CCEBEEF84792F5B80ED585239D5C0298C5@SHSMSX104.ccr.corp.intel.com> (raw)
In-Reply-To: <20190221003055.10320-2-hao.a.wu@intel.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
> -----Original Message-----
> From: Wu, Hao A <hao.a.wu@intel.com>
> Sent: Thursday, February 21, 2019 8:31 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 v2 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 identification 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 | 42 +
> SecurityPkg/HddPassword/HddPassword.vfr | 188 ++
> SecurityPkg/HddPassword/HddPasswordDxe.c | 2814
> ++++++++++++++++++++
> SecurityPkg/HddPassword/HddPasswordPei.c | 374 +++
> SecurityPkg/HddPassword/HddPasswordStrings.uni | 48 +
> 11 files changed, 3873 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..813b5422b4
> --- /dev/null
> +++ b/SecurityPkg/HddPassword/HddPasswordPei.h
> @@ -0,0 +1,42 @@
> +/** @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 <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"
> +
> +
> +//
> +// Time out value for ATA PassThru PPI
> +//
> +#define ATA_TIMEOUT 30000000
> +
> +#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..1247f856db
> --- /dev/null
> +++ b/SecurityPkg/HddPassword/HddPasswordDxe.c
> @@ -0,0 +1,2814 @@
> +/** @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) {
> + 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);
> + 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..1ea63b84bb
> --- /dev/null
> +++ b/SecurityPkg/HddPassword/HddPasswordPei.c
> @@ -0,0 +1,374 @@
> +/** @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;
> +
> +
> +/**
> + 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] AtaPassThruPpi Pointer to the
> EDKII_PEI_ATA_PASS_THRU_PPI instance.
> +
> +**/
> +VOID
> +UnlockHddPassword (
> + IN EDKII_PEI_ATA_PASS_THRU_PPI *AtaPassThruPpi
> + )
> +{
> + EFI_STATUS Status;
> + VOID *Buffer;
> + UINTN Length;
> + UINT8 DummyData;
> + HDD_PASSWORD_DEVICE_INFO *DevInfo;
> + UINT16 Port;
> + UINT16 PortMultiplierPort;
> + EFI_DEVICE_PATH_PROTOCOL *DevicePath;
> + UINTN DevicePathLength;
> +
> + //
> + // Get HDD password device info from LockBox.
> + //
> + Buffer = (VOID *) &DummyData;
> + Length = sizeof (DummyData);
> + 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;
> + }
> +
> + Status = AtaPassThruPpi->GetDevicePath (AtaPassThruPpi,
> &DevicePathLength, &DevicePath);
> + if (EFI_ERROR (Status) || (DevicePathLength <= sizeof
> (EFI_DEVICE_PATH_PROTOCOL))) {
> + goto Exit;
> + }
> +
> + //
> + // Go through all the devices managed by the AtaPassThru 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);
> + }
> + }
> + }
> +
> +Exit:
> + 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
> + )
> +{
> + DEBUG ((DEBUG_INFO, "%a() - enter at S3 resume\n", __FUNCTION__));
> +
> + UnlockHddPassword ((EDKII_PEI_ATA_PASS_THRU_PPI *) Ppi);
> +
> + DEBUG ((DEBUG_INFO, "%a() - exit at S3 resume\n", __FUNCTION__));
> +
> + return EFI_SUCCESS;
> +}
> +
> +
> +EFI_PEI_NOTIFY_DESCRIPTOR mHddPasswordAtaPassThruPpiNotifyDesc = {
> + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK |
> EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
> + &gEdkiiPeiAtaPassThruPpiGuid,
> + HddPasswordAtaPassThruNotify
> +};
> +
> +
> +/**
> + 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;
> +
> + 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__));
> +
> + Status = PeiServicesNotifyPpi
> (&mHddPasswordAtaPassThruPpiNotifyDesc);
> + 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
next prev parent reply other threads:[~2019-02-21 4:55 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-02-21 0:30 [PATCH v2 0/1] Add Security feature set support for ATA devices Hao Wu
2019-02-21 0:30 ` [PATCH v2 1/1] SecurityPkg/HddPassword: Add Security feature set support for ATA dev Hao Wu
2019-02-21 4:52 ` Ni, Ray [this message]
2019-02-21 5:56 ` Dong, Eric
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=734D49CCEBEEF84792F5B80ED585239D5C0298C5@SHSMSX104.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