From e8959f81003ccd80317b820f00287897191796ee Mon Sep 17 00:00:00 2001 From: Hao Wu Date: Tue, 15 Jan 2019 16:33:09 +0800 Subject: [PATCH] SecurityPkg/HddPassword: Add Security feature set support for ATA dev REF:https://bugzilla.tianocore.org/show_bug.cgi?id=1529 This commit will add the 'Security feature set' support for ATA devices. According to the AT Attachment 8 - ATA/ATAPI Command Set (ATA8-ACS) specification, the Security feature set is an optional feature. In summary, the feature is a password system that restricts access to user data stored on an ATA device. A more detailed introduction of this feature can be referred from the ATA8-ACS spec. The HddPassword driver is composed of 2 parts: * A DXE driver and * A PEI driver The DXE driver consumes EFI_ATA_PASS_THRU_PROTOCOL instances and installs an HII GUI to manage the devices. If the managing device supports Security feature set, the HII page will provide the user with the ability to set/update/disable the password for this device. Also, if a password is being set via the Security feature set, a popup window will show during boot requesting the user to input password. Another feature supported by this driver is that for those managing devices with password set, they will be automatically unlocked during the S3 resume. This is done by the co-work of the DXE driver and the PEI driver: The DXE driver will save the password and the identification information for these devices into a LockBox, which is only allowed to restore during S3 resume. The PEI driver, during S3 resume, will restore the content in the LockBox and will consume EDKII_PEI_ATA_PASS_THRU_PPI instances to unlock devices. Cc: Chao Zhang Cc: Jiewen Yao Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Hao Wu Reviewed-by: Ray Ni Reviewed-by: Eric Dong --- SecurityPkg/HddPassword/HddPassword.vfr | 188 ++ SecurityPkg/HddPassword/HddPasswordCommon.h | 61 + SecurityPkg/HddPassword/HddPasswordDxe.c | 2814 +++++++++++++++++ SecurityPkg/HddPassword/HddPasswordDxe.h | 148 + SecurityPkg/HddPassword/HddPasswordDxe.inf | 75 + .../HddPassword/HddPasswordHiiDataStruc.h | 63 + SecurityPkg/HddPassword/HddPasswordPei.c | 374 +++ SecurityPkg/HddPassword/HddPasswordPei.h | 42 + SecurityPkg/HddPassword/HddPasswordPei.inf | 54 + .../HddPassword/HddPasswordStrings.uni | 48 + SecurityPkg/SecurityPkg.dsc | 6 + 11 files changed, 3873 insertions(+) create mode 100644 SecurityPkg/HddPassword/HddPassword.vfr create mode 100644 SecurityPkg/HddPassword/HddPasswordCommon.h create mode 100644 SecurityPkg/HddPassword/HddPasswordDxe.c create mode 100644 SecurityPkg/HddPassword/HddPasswordDxe.h create mode 100644 SecurityPkg/HddPassword/HddPasswordDxe.inf create mode 100644 SecurityPkg/HddPassword/HddPasswordHiiDataStruc.h create mode 100644 SecurityPkg/HddPassword/HddPasswordPei.c create mode 100644 SecurityPkg/HddPassword/HddPasswordPei.h create mode 100644 SecurityPkg/HddPassword/HddPasswordPei.inf create mode 100644 SecurityPkg/HddPassword/HddPasswordStrings.uni 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 -- 2.39.2