diff --git a/SecurityPkg/HddPassword/HddPassword.vfr b/SecurityPkg/HddPassword/HddPassword.vfr
new file mode 100644
index 0000000000..2cd39523c7
--- /dev/null
+++ b/SecurityPkg/HddPassword/HddPassword.vfr
@@ -0,0 +1,188 @@
+/** @file
+ HDD Password Configuration Formset.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+**/
+
+#include "HddPasswordHiiDataStruc.h"
+
+formset
+ guid = 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/HddPasswordCommon.h b/SecurityPkg/HddPassword/HddPasswordCommon.h
new file mode 100644
index 0000000000..b904b7d39e
--- /dev/null
+++ b/SecurityPkg/HddPassword/HddPasswordCommon.h
@@ -0,0 +1,61 @@
+/** @file
+ HDD Password common header file.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _HDD_PASSWORD_COMMON_H_
+#define _HDD_PASSWORD_COMMON_H_
+
+//
+// The payload length of HDD related ATA commands
+//
+#define HDD_PAYLOAD 512
+
+#define ATA_SECURITY_SET_PASSWORD_CMD 0xF1
+#define ATA_SECURITY_UNLOCK_CMD 0xF2
+#define ATA_SECURITY_FREEZE_LOCK_CMD 0xF5
+#define ATA_SECURITY_DIS_PASSWORD_CMD 0xF6
+
+//
+// The max retry count specified in ATA 8 spec.
+//
+#define MAX_HDD_PASSWORD_RETRY_COUNT 5
+
+//
+// According to ATA spec, the max length of hdd password is 32 bytes
+//
+#define HDD_PASSWORD_MAX_LENGTH 32
+
+#define HDD_PASSWORD_DEVICE_INFO_GUID { 0x96d877ad, 0x48af, 0x4b39, { 0x9b, 0x27, 0x4d, 0x97, 0x43, 0x9, 0xae, 0x47 } }
+
+typedef struct {
+ UINT8 Bus;
+ UINT8 Device;
+ UINT8 Function;
+ UINT8 Reserved;
+ UINT16 Port;
+ UINT16 PortMultiplierPort;
+} HDD_PASSWORD_DEVICE;
+
+//
+// It will be used to unlock HDD password for S3.
+//
+typedef struct {
+ HDD_PASSWORD_DEVICE Device;
+ CHAR8 Password[HDD_PASSWORD_MAX_LENGTH];
+ UINT32 DevicePathLength;
+ EFI_DEVICE_PATH_PROTOCOL DevicePath[];
+} HDD_PASSWORD_DEVICE_INFO;
+
+#endif // _HDD_PASSWORD_COMMON_H_
diff --git a/SecurityPkg/HddPassword/HddPasswordDxe.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.
+
+ 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 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=". That (when
+ converted from Hex UNICODE to binary) is a reference to a
+ string in the associated string pack.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Request A null-terminated Unicode string in
+ format. Note that this
+ includes the routing information as well as
+ the configurable name / value pairs. It is
+ invalid for this string to be in
+ format.
+ @param[out] Progress On return, points to a character in the
+ Request string. Points to the string's null
+ terminator if request was successful. Points
+ to the most recent "&" before the first
+ failing name / value pair (or the beginning
+ of the string if the failure is in the first
+ name / value pair) if the request was not
+ successful.
+ @param[out] Results A null-terminated Unicode string in
+ format which has all values
+ filled in for the names in the Request string.
+ String to be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results string is filled with the
+ values corresponding to all requested
+ names.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the
+ parts of the results that must be
+ stored awaiting possible future
+ protocols.
+ @retval EFI_INVALID_PARAMETER For example, passing in a NULL
+ for the Request parameter
+ would result in this type of
+ error. In this case, the
+ Progress parameter would be
+ set to NULL.
+ @retval EFI_NOT_FOUND Routing data doesn't match any
+ known driver. Progress set to the
+ first character in the routing header.
+ Note: There is no requirement that the
+ driver validate the routing data. It
+ must skip the in order to
+ process the names.
+ @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set
+ to most recent & before the
+ error or the beginning of the
+ string.
+ @retval EFI_INVALID_PARAMETER Unknown name. Progress points
+ to the & before the name in
+ question.Currently not implemented.
+**/
+EFI_STATUS
+EFIAPI
+HddPasswordFormExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ HDD_PASSWORD_CONFIG *IfrData;
+ HDD_PASSWORD_DXE_PRIVATE_DATA *Private;
+ EFI_STRING ConfigRequestHdr;
+ EFI_STRING ConfigRequest;
+ BOOLEAN AllocatedRequest;
+ UINTN Size;
+
+ if (Progress == 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 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 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
+ 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
+ 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 .
+ // 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/HddPasswordDxe.h b/SecurityPkg/HddPassword/HddPasswordDxe.h
new file mode 100644
index 0000000000..41db0554d5
--- /dev/null
+++ b/SecurityPkg/HddPassword/HddPasswordDxe.h
@@ -0,0 +1,148 @@
+/** @file
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _HDD_PASSWORD_DXE_H_
+#define _HDD_PASSWORD_DXE_H_
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "HddPasswordCommon.h"
+#include "HddPasswordHiiDataStruc.h"
+
+//
+// This is the generated IFR binary data for each formset defined in VFR.
+// This data array is ready to be used as input of HiiAddPackages() to
+// create a packagelist (which contains Form packages, String packages, etc).
+//
+extern UINT8 HddPasswordBin[];
+
+//
+// This is the generated String package data for all .UNI files.
+// This data array is ready to be used as input of HiiAddPackages() to
+// create a packagelist (which contains Form packages, String packages, etc).
+//
+extern UINT8 HddPasswordDxeStrings[];
+
+#define HDD_PASSWORD_DXE_PRIVATE_SIGNATURE SIGNATURE_32 ('H', 'D', 'D', 'P')
+
+typedef struct _HDD_PASSWORD_CONFIG_FORM_ENTRY {
+ LIST_ENTRY Link;
+ EFI_HANDLE Controller;
+ UINTN Bus;
+ UINTN Device;
+ UINTN Function;
+ UINT16 Port;
+ UINT16 PortMultiplierPort;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ CHAR16 HddString[64];
+ CHAR8 Password[HDD_PASSWORD_MAX_LENGTH];
+ EFI_STRING_ID TitleToken;
+ EFI_STRING_ID TitleHelpToken;
+
+ HDD_PASSWORD_CONFIG IfrData;
+ EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru;
+} HDD_PASSWORD_CONFIG_FORM_ENTRY;
+
+typedef struct _HDD_PASSWORD_DXE_PRIVATE_DATA {
+ UINTN Signature;
+ EFI_HANDLE DriverHandle;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+ HDD_PASSWORD_CONFIG_FORM_ENTRY *Current;
+} HDD_PASSWORD_DXE_PRIVATE_DATA;
+
+#define HDD_PASSWORD_DXE_PRIVATE_FROM_THIS(a) CR (a, HDD_PASSWORD_DXE_PRIVATE_DATA, ConfigAccess, HDD_PASSWORD_DXE_PRIVATE_SIGNATURE)
+
+//
+//Iterate through the doule linked list. NOT delete safe
+//
+#define EFI_LIST_FOR_EACH(Entry, ListHead) \
+ for (Entry = (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/HddPasswordDxe.inf b/SecurityPkg/HddPassword/HddPasswordDxe.inf
new file mode 100644
index 0000000000..7a3fc2f88c
--- /dev/null
+++ b/SecurityPkg/HddPassword/HddPasswordDxe.inf
@@ -0,0 +1,75 @@
+## @file
+# HddPasswordDxe driver which is used to set/clear hdd password at attached harddisk
+# devices.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license 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/HddPasswordHiiDataStruc.h b/SecurityPkg/HddPassword/HddPasswordHiiDataStruc.h
new file mode 100644
index 0000000000..608b92d797
--- /dev/null
+++ b/SecurityPkg/HddPassword/HddPasswordHiiDataStruc.h
@@ -0,0 +1,63 @@
+/** @file
+ HddPassword HII data structure used by the driver.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _HDD_PASSWORD_HII_DATASTRUC_H_
+#define _HDD_PASSWORD_HII_DATASTRUC_H_
+
+#include
+
+#define HDD_PASSWORD_CONFIG_GUID \
+ { \
+ 0x737cded7, 0x448b, 0x4801, { 0xb5, 0x7d, 0xb1, 0x94, 0x83, 0xec, 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.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.
+
+ 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/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.
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _HDD_PASSWORD_PEI_H_
+#define _HDD_PASSWORD_PEI_H_
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include "HddPasswordCommon.h"
+
+
+//
+// Time out value for ATA PassThru PPI
+//
+#define ATA_TIMEOUT 30000000
+
+#endif
diff --git a/SecurityPkg/HddPassword/HddPasswordPei.inf b/SecurityPkg/HddPassword/HddPasswordPei.inf
new file mode 100644
index 0000000000..d240cc1d07
--- /dev/null
+++ b/SecurityPkg/HddPassword/HddPasswordPei.inf
@@ -0,0 +1,54 @@
+## @file
+# HddPassword PEI module which is used to unlock HDD password for S3.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license 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/HddPasswordStrings.uni b/SecurityPkg/HddPassword/HddPasswordStrings.uni
new file mode 100644
index 0000000000..455ecfcd02
--- /dev/null
+++ b/SecurityPkg/HddPassword/HddPasswordStrings.uni
@@ -0,0 +1,48 @@
+// /** @file
+// String definitions for HddPassword Setup Form.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions
+// of the BSD License which accompanies this distribution. The
+// full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#langdef en-US "English"
+
+#string STR_HDD_SECURITY_CONFIG #language en-US "HDD 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 ""
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