--- /dev/null
+/** @file\r
+ HDD password driver which is used to support HDD security feature.\r
+\r
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions\r
+ of the BSD License which accompanies this distribution. The\r
+ full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "HddPasswordDxe.h"\r
+\r
+EFI_GUID mHddPasswordVendorGuid = HDD_PASSWORD_CONFIG_GUID;\r
+CHAR16 mHddPasswordVendorStorageName[] = L"HDD_PASSWORD_CONFIG";\r
+LIST_ENTRY mHddPasswordConfigFormList;\r
+UINT32 mNumberOfHddDevices = 0;\r
+\r
+EFI_GUID mHddPasswordDeviceInfoGuid = HDD_PASSWORD_DEVICE_INFO_GUID;\r
+BOOLEAN mHddPasswordEndOfDxe = FALSE;\r
+HDD_PASSWORD_REQUEST_VARIABLE *mHddPasswordRequestVariable = NULL;\r
+UINTN mHddPasswordRequestVariableSize = 0;\r
+\r
+HII_VENDOR_DEVICE_PATH mHddPasswordHiiVendorDevicePath = {\r
+ {\r
+ {\r
+ HARDWARE_DEVICE_PATH,\r
+ HW_VENDOR_DP,\r
+ {\r
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),\r
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)\r
+ }\r
+ },\r
+ HDD_PASSWORD_CONFIG_GUID\r
+ },\r
+ {\r
+ END_DEVICE_PATH_TYPE,\r
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
+ {\r
+ (UINT8) (END_DEVICE_PATH_LENGTH),\r
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)\r
+ }\r
+ }\r
+};\r
+\r
+\r
+/**\r
+ Check if the password is full zero.\r
+\r
+ @param[in] Password Points to the data buffer\r
+\r
+ @retval TRUE This password string is full zero.\r
+ @retval FALSE This password string is not full zero.\r
+\r
+**/\r
+BOOLEAN\r
+PasswordIsFullZero (\r
+ IN CHAR8 *Password\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ for (Index = 0; Index < HDD_PASSWORD_MAX_LENGTH; Index++) {\r
+ if (Password[Index] != 0) {\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Save device info.\r
+\r
+ @param[in] ConfigFormEntry Points to HDD_PASSWORD_CONFIG_FORM_ENTRY buffer\r
+ @param[in,out] TempDevInfo Points to HDD_PASSWORD_DEVICE_INFO buffer\r
+\r
+**/\r
+VOID\r
+SaveDeviceInfo (\r
+ IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry,\r
+ IN OUT HDD_PASSWORD_DEVICE_INFO *TempDevInfo\r
+ )\r
+{\r
+ TempDevInfo->Device.Bus = (UINT8) ConfigFormEntry->Bus;\r
+ TempDevInfo->Device.Device = (UINT8) ConfigFormEntry->Device;\r
+ TempDevInfo->Device.Function = (UINT8) ConfigFormEntry->Function;\r
+ TempDevInfo->Device.Port = ConfigFormEntry->Port;\r
+ TempDevInfo->Device.PortMultiplierPort = ConfigFormEntry->PortMultiplierPort;\r
+ CopyMem (TempDevInfo->Password, ConfigFormEntry->Password, HDD_PASSWORD_MAX_LENGTH);\r
+ TempDevInfo->DevicePathLength = (UINT32) GetDevicePathSize (ConfigFormEntry->DevicePath);\r
+ CopyMem (TempDevInfo->DevicePath, ConfigFormEntry->DevicePath, TempDevInfo->DevicePathLength);\r
+}\r
+\r
+/**\r
+ Build HDD password device info and save them to LockBox.\r
+\r
+ **/\r
+VOID\r
+BuildHddPasswordDeviceInfo (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ LIST_ENTRY *Entry;\r
+ HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry;\r
+ HDD_PASSWORD_DEVICE_INFO *DevInfo;\r
+ HDD_PASSWORD_DEVICE_INFO *TempDevInfo;\r
+ UINTN DevInfoLength;\r
+ UINT8 DummyData;\r
+ BOOLEAN S3InitDevicesExist;\r
+ UINTN S3InitDevicesLength;\r
+ EFI_DEVICE_PATH_PROTOCOL *S3InitDevices;\r
+ EFI_DEVICE_PATH_PROTOCOL *S3InitDevicesBak;\r
+\r
+ //\r
+ // Build HDD password device info and save them to LockBox.\r
+ //\r
+ DevInfoLength = 0;\r
+ EFI_LIST_FOR_EACH (Entry, &mHddPasswordConfigFormList) {\r
+ ConfigFormEntry = BASE_CR (Entry, HDD_PASSWORD_CONFIG_FORM_ENTRY, Link);\r
+\r
+ //\r
+ // 1. Handle device which already set password.\r
+ // 2. When request to send freeze comamnd, driver also needs to handle device\r
+ // which support security feature.\r
+ //\r
+ if ((!PasswordIsFullZero (ConfigFormEntry->Password)) ||\r
+ ((ConfigFormEntry->IfrData.SecurityStatus.Supported != 0) &&\r
+ (ConfigFormEntry->IfrData.SecurityStatus.Enabled == 0))) {\r
+ DevInfoLength += sizeof (HDD_PASSWORD_DEVICE_INFO) +\r
+ GetDevicePathSize (ConfigFormEntry->DevicePath);\r
+ }\r
+ }\r
+\r
+ if (DevInfoLength == 0) {\r
+ return;\r
+ }\r
+\r
+ S3InitDevicesLength = sizeof (DummyData);\r
+ Status = RestoreLockBox (\r
+ &gS3StorageDeviceInitListGuid,\r
+ &DummyData,\r
+ &S3InitDevicesLength\r
+ );\r
+ ASSERT ((Status == EFI_NOT_FOUND) || (Status == EFI_BUFFER_TOO_SMALL));\r
+ if (Status == EFI_NOT_FOUND) {\r
+ S3InitDevices = NULL;\r
+ S3InitDevicesExist = FALSE;\r
+ } else if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ S3InitDevices = AllocatePool (S3InitDevicesLength);\r
+ ASSERT (S3InitDevices != NULL);\r
+\r
+ Status = RestoreLockBox (\r
+ &gS3StorageDeviceInitListGuid,\r
+ S3InitDevices,\r
+ &S3InitDevicesLength\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ S3InitDevicesExist = TRUE;\r
+ } else {\r
+ return;\r
+ }\r
+\r
+ DevInfo = AllocateZeroPool (DevInfoLength);\r
+ ASSERT (DevInfo != NULL);\r
+\r
+ TempDevInfo = DevInfo;\r
+ EFI_LIST_FOR_EACH (Entry, &mHddPasswordConfigFormList) {\r
+ ConfigFormEntry = BASE_CR (Entry, HDD_PASSWORD_CONFIG_FORM_ENTRY, Link);\r
+\r
+ if ((!PasswordIsFullZero (ConfigFormEntry->Password)) ||\r
+ ((ConfigFormEntry->IfrData.SecurityStatus.Supported != 0) &&\r
+ (ConfigFormEntry->IfrData.SecurityStatus.Enabled == 0))) {\r
+ SaveDeviceInfo (ConfigFormEntry, TempDevInfo);\r
+\r
+ S3InitDevicesBak = S3InitDevices;\r
+ S3InitDevices = AppendDevicePathInstance (\r
+ S3InitDevicesBak,\r
+ ConfigFormEntry->DevicePath\r
+ );\r
+ if (S3InitDevicesBak != NULL) {\r
+ FreePool (S3InitDevicesBak);\r
+ }\r
+ ASSERT (S3InitDevices != NULL);\r
+\r
+ TempDevInfo = (HDD_PASSWORD_DEVICE_INFO *) ((UINTN)TempDevInfo +\r
+ sizeof (HDD_PASSWORD_DEVICE_INFO) +\r
+ TempDevInfo->DevicePathLength);\r
+ }\r
+ }\r
+\r
+ Status = SaveLockBox (\r
+ &mHddPasswordDeviceInfoGuid,\r
+ DevInfo,\r
+ DevInfoLength\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Status = SetLockBoxAttributes (\r
+ &mHddPasswordDeviceInfoGuid,\r
+ LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ S3InitDevicesLength = GetDevicePathSize (S3InitDevices);\r
+ if (S3InitDevicesExist) {\r
+ Status = UpdateLockBox (\r
+ &gS3StorageDeviceInitListGuid,\r
+ 0,\r
+ S3InitDevices,\r
+ S3InitDevicesLength\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ } else {\r
+ Status = SaveLockBox (\r
+ &gS3StorageDeviceInitListGuid,\r
+ S3InitDevices,\r
+ S3InitDevicesLength\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Status = SetLockBoxAttributes (\r
+ &gS3StorageDeviceInitListGuid,\r
+ LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+ ZeroMem (DevInfo, DevInfoLength);\r
+ FreePool (DevInfo);\r
+ FreePool (S3InitDevices);\r
+}\r
+\r
+/**\r
+ Send freeze lock cmd through Ata Pass Thru Protocol.\r
+\r
+ @param[in] AtaPassThru The pointer to the ATA_PASS_THRU protocol.\r
+ @param[in] Port The port number of the ATA device to send the command.\r
+ @param[in] PortMultiplierPort The port multiplier port number of the ATA device to send the command.\r
+ If there is no port multiplier, then specify 0xFFFF.\r
+\r
+ @retval EFI_SUCCESS Successful to send freeze lock cmd.\r
+ @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to send freeze lock cmd.\r
+ @retval EFI_DEVICE_ERROR Can not send freeze lock cmd.\r
+\r
+**/\r
+EFI_STATUS\r
+FreezeLockDevice (\r
+ IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru,\r
+ IN UINT16 Port,\r
+ IN UINT16 PortMultiplierPort\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_ATA_COMMAND_BLOCK Acb;\r
+ EFI_ATA_STATUS_BLOCK *Asb;\r
+ EFI_ATA_PASS_THRU_COMMAND_PACKET Packet;\r
+\r
+ if (AtaPassThru == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in\r
+ // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned specified by\r
+ // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. Meanwhile,\r
+ // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields, so it\r
+ // may not be aligned when allocated on stack for some compilers. Hence, we\r
+ // use the API AllocateAlignedPages to ensure this structure is properly\r
+ // aligned.\r
+ //\r
+ Asb = AllocateAlignedPages (\r
+ EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)),\r
+ AtaPassThru->Mode->IoAlign\r
+ );\r
+ if (Asb == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Prepare for ATA command block.\r
+ //\r
+ ZeroMem (&Acb, sizeof (Acb));\r
+ ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK));\r
+ Acb.AtaCommand = ATA_SECURITY_FREEZE_LOCK_CMD;\r
+ Acb.AtaDeviceHead = (UINT8) (PortMultiplierPort == 0xFFFF ? 0 : (PortMultiplierPort << 4));\r
+\r
+ //\r
+ // Prepare for ATA pass through packet.\r
+ //\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+ Packet.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA;\r
+ Packet.Length = EFI_ATA_PASS_THRU_LENGTH_NO_DATA_TRANSFER;\r
+ Packet.Asb = Asb;\r
+ Packet.Acb = &Acb;\r
+ Packet.Timeout = ATA_TIMEOUT;\r
+\r
+ Status = AtaPassThru->PassThru (\r
+ AtaPassThru,\r
+ Port,\r
+ PortMultiplierPort,\r
+ &Packet,\r
+ NULL\r
+ );\r
+ if (!EFI_ERROR (Status) &&\r
+ ((Asb->AtaStatus & ATA_STSREG_ERR) != 0) &&\r
+ ((Asb->AtaError & ATA_ERRREG_ABRT) != 0)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ FreeAlignedPages (Asb, EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)));\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - %r\n", __FUNCTION__, Status));\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Get attached harddisk identify data through Ata Pass Thru Protocol.\r
+\r
+ @param[in] AtaPassThru The pointer to the ATA_PASS_THRU protocol.\r
+ @param[in] Port The port number of the ATA device to send the command.\r
+ @param[in] PortMultiplierPort The port multiplier port number of the ATA device to send the command.\r
+ If there is no port multiplier, then specify 0xFFFF.\r
+ @param[in] IdentifyData The buffer to store identify data.\r
+\r
+ @retval EFI_SUCCESS Successful to get identify data.\r
+ @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to get identify data.\r
+ @retval EFI_DEVICE_ERROR Can not get identify data.\r
+\r
+**/\r
+EFI_STATUS\r
+GetHddDeviceIdentifyData (\r
+ IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru,\r
+ IN UINT16 Port,\r
+ IN UINT16 PortMultiplierPort,\r
+ IN ATA_IDENTIFY_DATA *IdentifyData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_ATA_COMMAND_BLOCK Acb;\r
+ EFI_ATA_STATUS_BLOCK *Asb;\r
+ EFI_ATA_PASS_THRU_COMMAND_PACKET Packet;\r
+\r
+ if ((AtaPassThru == NULL) || (IdentifyData == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in\r
+ // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned specified by\r
+ // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. Meanwhile,\r
+ // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields, so it\r
+ // may not be aligned when allocated on stack for some compilers. Hence, we\r
+ // use the API AllocateAlignedPages to ensure this structure is properly\r
+ // aligned.\r
+ //\r
+ Asb = AllocateAlignedPages (\r
+ EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)),\r
+ AtaPassThru->Mode->IoAlign\r
+ );\r
+ if (Asb == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Prepare for ATA command block.\r
+ //\r
+ ZeroMem (&Acb, sizeof (Acb));\r
+ ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK));\r
+ Acb.AtaCommand = ATA_CMD_IDENTIFY_DRIVE;\r
+ Acb.AtaDeviceHead = (UINT8) (BIT7 | BIT6 | BIT5 | (PortMultiplierPort == 0xFFFF ? 0 : (PortMultiplierPort << 4)));\r
+\r
+ //\r
+ // Prepare for ATA pass through packet.\r
+ //\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+ Packet.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN;\r
+ Packet.Length = EFI_ATA_PASS_THRU_LENGTH_BYTES | EFI_ATA_PASS_THRU_LENGTH_SECTOR_COUNT;\r
+ Packet.Asb = Asb;\r
+ Packet.Acb = &Acb;\r
+ Packet.InDataBuffer = IdentifyData;\r
+ Packet.InTransferLength = sizeof (ATA_IDENTIFY_DATA);\r
+ Packet.Timeout = ATA_TIMEOUT;\r
+\r
+ Status = AtaPassThru->PassThru (\r
+ AtaPassThru,\r
+ Port,\r
+ PortMultiplierPort,\r
+ &Packet,\r
+ NULL\r
+ );\r
+\r
+ FreeAlignedPages (Asb, EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)));\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Parse security status according to identify data.\r
+\r
+ @param[in] IdentifyData The buffer to store identify data.\r
+ @param[in, out] IfrData IFR data to hold security status.\r
+\r
+**/\r
+VOID\r
+GetHddPasswordSecurityStatus (\r
+ IN ATA_IDENTIFY_DATA *IdentifyData,\r
+ IN OUT HDD_PASSWORD_CONFIG *IfrData\r
+ )\r
+{\r
+ IfrData->SecurityStatus.Supported = (IdentifyData->command_set_supported_82 & BIT1) ? 1 : 0;\r
+ IfrData->SecurityStatus.Enabled = (IdentifyData->security_status & BIT1) ? 1 : 0;\r
+ IfrData->SecurityStatus.Locked = (IdentifyData->security_status & BIT2) ? 1 : 0;\r
+ IfrData->SecurityStatus.Frozen = (IdentifyData->security_status & BIT3) ? 1 : 0;\r
+ IfrData->SecurityStatus.UserPasswordStatus = IfrData->SecurityStatus.Enabled;\r
+ IfrData->SecurityStatus.MasterPasswordStatus = IfrData->SecurityStatus.Supported;\r
+\r
+ DEBUG ((DEBUG_INFO, "IfrData->SecurityStatus.Supported = %x\n", IfrData->SecurityStatus.Supported));\r
+ DEBUG ((DEBUG_INFO, "IfrData->SecurityStatus.Enabled = %x\n", IfrData->SecurityStatus.Enabled));\r
+ DEBUG ((DEBUG_INFO, "IfrData->SecurityStatus.Locked = %x\n", IfrData->SecurityStatus.Locked));\r
+ DEBUG ((DEBUG_INFO, "IfrData->SecurityStatus.Frozen = %x\n", IfrData->SecurityStatus.Frozen));\r
+ DEBUG ((DEBUG_INFO, "IfrData->SecurityStatus.UserPasswordStatus = %x\n", IfrData->SecurityStatus.UserPasswordStatus));\r
+ DEBUG ((DEBUG_INFO, "IfrData->SecurityStatus.MasterPasswordStatus = %x\n", IfrData->SecurityStatus.MasterPasswordStatus));\r
+}\r
+\r
+/**\r
+ Notification function of EFI_END_OF_DXE_EVENT_GROUP_GUID event group.\r
+\r
+ This is a notification function registered on EFI_END_OF_DXE_EVENT_GROUP_GUID event group.\r
+\r
+ @param Event Event whose notification function is being invoked.\r
+ @param Context Pointer to the notification function's context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+HddPasswordEndOfDxeEventNotify (\r
+ EFI_EVENT Event,\r
+ VOID *Context\r
+ )\r
+{\r
+ LIST_ENTRY *Entry;\r
+ HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry;\r
+ EFI_STATUS Status;\r
+ ATA_IDENTIFY_DATA IdentifyData;\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));\r
+\r
+ mHddPasswordEndOfDxe = TRUE;\r
+\r
+ if (mHddPasswordRequestVariable != NULL) {\r
+ //\r
+ // Free the HDD password request variable buffer here\r
+ // as the HDD password requests should have been processed.\r
+ //\r
+ FreePool (mHddPasswordRequestVariable);\r
+ mHddPasswordRequestVariable = NULL;\r
+ mHddPasswordRequestVariableSize = 0;\r
+ }\r
+\r
+ //\r
+ // If no any device, return directly.\r
+ //\r
+ if (IsListEmpty (&mHddPasswordConfigFormList)) {\r
+ gBS->CloseEvent (Event);\r
+ return;\r
+ }\r
+\r
+ BuildHddPasswordDeviceInfo ();\r
+\r
+ //\r
+ // Zero passsword and freeze lock device.\r
+ //\r
+ EFI_LIST_FOR_EACH (Entry, &mHddPasswordConfigFormList) {\r
+ ConfigFormEntry = BASE_CR (Entry, HDD_PASSWORD_CONFIG_FORM_ENTRY, Link);\r
+\r
+ ZeroMem (ConfigFormEntry->Password, HDD_PASSWORD_MAX_LENGTH);\r
+\r
+ //\r
+ // Check whether need send freeze lock command.\r
+ // Below device will be froze:\r
+ // 1. Device not enable password.\r
+ // 2. Device enable password and unlocked.\r
+ //\r
+ if ((ConfigFormEntry->IfrData.SecurityStatus.Supported != 0) &&\r
+ (ConfigFormEntry->IfrData.SecurityStatus.Locked == 0) &&\r
+ (ConfigFormEntry->IfrData.SecurityStatus.Frozen == 0)) {\r
+ Status = FreezeLockDevice (ConfigFormEntry->AtaPassThru, ConfigFormEntry->Port, ConfigFormEntry->PortMultiplierPort);\r
+ DEBUG ((DEBUG_INFO, "FreezeLockDevice return %r!\n", Status));\r
+ Status = GetHddDeviceIdentifyData (\r
+ ConfigFormEntry->AtaPassThru,\r
+ ConfigFormEntry->Port,\r
+ ConfigFormEntry->PortMultiplierPort,\r
+ &IdentifyData\r
+ );\r
+ GetHddPasswordSecurityStatus (&IdentifyData, &ConfigFormEntry->IfrData);\r
+ }\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));\r
+\r
+ gBS->CloseEvent (Event);\r
+}\r
+\r
+/**\r
+ Generate Salt value.\r
+\r
+ @param[in, out] SaltValue Points to the salt buffer, 32 bytes\r
+\r
+**/\r
+VOID\r
+GenSalt (\r
+ IN OUT UINT8 *SaltValue\r
+ )\r
+{\r
+ RandomSeed (NULL, 0);\r
+ RandomBytes (SaltValue, PASSWORD_SALT_SIZE);\r
+}\r
+\r
+/**\r
+ Hash the data to get credential.\r
+\r
+ @param[in] Buffer Points to the data buffer\r
+ @param[in] BufferSize Buffer size\r
+ @param[in] SaltValue Points to the salt buffer, 32 bytes\r
+ @param[out] Credential Points to the hashed result\r
+\r
+ @retval TRUE Hash the data successfully.\r
+ @retval FALSE Failed to hash the data.\r
+\r
+**/\r
+BOOLEAN\r
+GenerateCredential (\r
+ IN UINT8 *Buffer,\r
+ IN UINTN BufferSize,\r
+ IN UINT8 *SaltValue,\r
+ OUT UINT8 *Credential\r
+ )\r
+{\r
+ BOOLEAN Status;\r
+ UINTN HashSize;\r
+ VOID *Hash;\r
+ VOID *HashData;\r
+\r
+ Hash = NULL;\r
+ HashData = NULL;\r
+ Status = FALSE;\r
+\r
+ HashSize = Sha256GetContextSize ();\r
+ Hash = AllocateZeroPool (HashSize);\r
+ ASSERT (Hash != NULL);\r
+ if (Hash == NULL) {\r
+ goto Done;\r
+ }\r
+\r
+ Status = Sha256Init (Hash);\r
+ if (!Status) {\r
+ goto Done;\r
+ }\r
+\r
+ HashData = AllocateZeroPool (PASSWORD_SALT_SIZE + BufferSize);\r
+ ASSERT (HashData != NULL);\r
+ if (HashData == NULL) {\r
+ goto Done;\r
+ }\r
+\r
+ CopyMem (HashData, SaltValue, PASSWORD_SALT_SIZE);\r
+ CopyMem ((UINT8 *) HashData + PASSWORD_SALT_SIZE, Buffer, BufferSize);\r
+\r
+ Status = Sha256Update (Hash, HashData, PASSWORD_SALT_SIZE + BufferSize);\r
+ if (!Status) {\r
+ goto Done;\r
+ }\r
+\r
+ Status = Sha256Final (Hash, Credential);\r
+\r
+Done:\r
+ if (Hash != NULL) {\r
+ FreePool (Hash);\r
+ }\r
+ if (HashData != NULL) {\r
+ ZeroMem (HashData, PASSWORD_SALT_SIZE + BufferSize);\r
+ FreePool (HashData);\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Save HDD password variable that will be used to validate HDD password\r
+ when the device is at frozen state.\r
+\r
+ @param[in] ConfigFormEntry The HDD Password configuration form entry.\r
+ @param[in] Password The hdd password of attached ATA device.\r
+\r
+**/\r
+VOID\r
+SaveHddPasswordVariable (\r
+ IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry,\r
+ IN CHAR8 *Password\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ HDD_PASSWORD_VARIABLE *TempVariable;\r
+ UINTN TempVariableSize;\r
+ HDD_PASSWORD_VARIABLE *NextNode;\r
+ HDD_PASSWORD_VARIABLE *Variable;\r
+ UINTN VariableSize;\r
+ HDD_PASSWORD_VARIABLE *NewVariable;\r
+ UINTN NewVariableSize;\r
+ BOOLEAN Delete;\r
+ BOOLEAN HashOk;\r
+ UINT8 HashData[SHA256_DIGEST_SIZE];\r
+ UINT8 SaltData[PASSWORD_SALT_SIZE];\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));\r
+\r
+ Delete = FALSE;\r
+ if (!PasswordIsFullZero (Password)) {\r
+ //\r
+ // It is Set/Update HDD Password.\r
+ //\r
+ ZeroMem (HashData, sizeof (HashData));\r
+ ZeroMem (SaltData, sizeof (SaltData));\r
+ GenSalt (SaltData);\r
+ HashOk = GenerateCredential ((UINT8 *) Password, HDD_PASSWORD_MAX_LENGTH, SaltData, HashData);\r
+ if (!HashOk) {\r
+ DEBUG ((DEBUG_INFO, "GenerateCredential failed\n"));\r
+ return;\r
+ }\r
+ } else {\r
+ //\r
+ // It is Disable HDD Password.\r
+ // Go to delete the variable node for the HDD password device.\r
+ //\r
+ Delete = TRUE;\r
+ }\r
+\r
+ Variable = NULL;\r
+ VariableSize = 0;\r
+ NewVariable = NULL;\r
+ NewVariableSize = 0;\r
+\r
+ Status = GetVariable2 (\r
+ HDD_PASSWORD_VARIABLE_NAME,\r
+ &mHddPasswordVendorGuid,\r
+ (VOID **) &Variable,\r
+ &VariableSize\r
+ );\r
+ if (Delete) {\r
+ if (!EFI_ERROR (Status) && (Variable != NULL)) {\r
+ TempVariable = Variable;\r
+ TempVariableSize = VariableSize;\r
+ while (TempVariableSize >= sizeof (HDD_PASSWORD_VARIABLE)) {\r
+ if ((TempVariable->Device.Bus == ConfigFormEntry->Bus) &&\r
+ (TempVariable->Device.Device == ConfigFormEntry->Device) &&\r
+ (TempVariable->Device.Function == ConfigFormEntry->Function) &&\r
+ (TempVariable->Device.Port == ConfigFormEntry->Port) &&\r
+ (TempVariable->Device.PortMultiplierPort == ConfigFormEntry->PortMultiplierPort)) {\r
+ //\r
+ // Found the node for the HDD password device.\r
+ // Delete the node.\r
+ //\r
+ NextNode = TempVariable + 1;\r
+ CopyMem (TempVariable, NextNode, (UINTN) Variable + VariableSize - (UINTN) NextNode);\r
+ NewVariable = Variable;\r
+ NewVariableSize = VariableSize - sizeof (HDD_PASSWORD_VARIABLE);\r
+ break;\r
+ }\r
+ TempVariableSize -= sizeof (HDD_PASSWORD_VARIABLE);\r
+ TempVariable += 1;\r
+ }\r
+ if (NewVariable == NULL) {\r
+ DEBUG ((DEBUG_INFO, "The variable node for the HDD password device is not found\n"));\r
+ }\r
+ } else {\r
+ DEBUG ((DEBUG_INFO, "HddPassword variable get failed (%r)\n", Status));\r
+ }\r
+ } else {\r
+ if (!EFI_ERROR (Status) && (Variable != NULL)) {\r
+ TempVariable = Variable;\r
+ TempVariableSize = VariableSize;\r
+ while (TempVariableSize >= sizeof (HDD_PASSWORD_VARIABLE)) {\r
+ if ((TempVariable->Device.Bus == ConfigFormEntry->Bus) &&\r
+ (TempVariable->Device.Device == ConfigFormEntry->Device) &&\r
+ (TempVariable->Device.Function == ConfigFormEntry->Function) &&\r
+ (TempVariable->Device.Port == ConfigFormEntry->Port) &&\r
+ (TempVariable->Device.PortMultiplierPort == ConfigFormEntry->PortMultiplierPort)) {\r
+ //\r
+ // Found the node for the HDD password device.\r
+ // Update the node.\r
+ //\r
+ CopyMem (TempVariable->PasswordHash, HashData, sizeof (HashData));\r
+ CopyMem (TempVariable->PasswordSalt, SaltData, sizeof (SaltData));\r
+ NewVariable = Variable;\r
+ NewVariableSize = VariableSize;\r
+ break;\r
+ }\r
+ TempVariableSize -= sizeof (HDD_PASSWORD_VARIABLE);\r
+ TempVariable += 1;\r
+ }\r
+ if (NewVariable == NULL) {\r
+ //\r
+ // The node for the HDD password device is not found.\r
+ // Create node for the HDD password device.\r
+ //\r
+ NewVariableSize = VariableSize + sizeof (HDD_PASSWORD_VARIABLE);\r
+ NewVariable = AllocateZeroPool (NewVariableSize);\r
+ ASSERT (NewVariable != NULL);\r
+ CopyMem (NewVariable, Variable, VariableSize);\r
+ TempVariable = (HDD_PASSWORD_VARIABLE *) ((UINTN) NewVariable + VariableSize);\r
+ TempVariable->Device.Bus = (UINT8) ConfigFormEntry->Bus;\r
+ TempVariable->Device.Device = (UINT8) ConfigFormEntry->Device;\r
+ TempVariable->Device.Function = (UINT8) ConfigFormEntry->Function;\r
+ TempVariable->Device.Port = ConfigFormEntry->Port;\r
+ TempVariable->Device.PortMultiplierPort = ConfigFormEntry->PortMultiplierPort;\r
+ CopyMem (TempVariable->PasswordHash, HashData, sizeof (HashData));\r
+ CopyMem (TempVariable->PasswordSalt, SaltData, sizeof (SaltData));\r
+ }\r
+ } else {\r
+ NewVariableSize = sizeof (HDD_PASSWORD_VARIABLE);\r
+ NewVariable = AllocateZeroPool (NewVariableSize);\r
+ ASSERT (NewVariable != NULL);\r
+ NewVariable->Device.Bus = (UINT8) ConfigFormEntry->Bus;\r
+ NewVariable->Device.Device = (UINT8) ConfigFormEntry->Device;\r
+ NewVariable->Device.Function = (UINT8) ConfigFormEntry->Function;\r
+ NewVariable->Device.Port = ConfigFormEntry->Port;\r
+ NewVariable->Device.PortMultiplierPort = ConfigFormEntry->PortMultiplierPort;\r
+ CopyMem (NewVariable->PasswordHash, HashData, sizeof (HashData));\r
+ CopyMem (NewVariable->PasswordSalt, SaltData, sizeof (SaltData));\r
+ }\r
+ }\r
+\r
+ if (NewVariable != NULL) {\r
+ Status = gRT->SetVariable (\r
+ HDD_PASSWORD_VARIABLE_NAME,\r
+ &mHddPasswordVendorGuid,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+ NewVariableSize,\r
+ NewVariable\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_INFO, "HddPassword variable set failed (%r)\n", Status));\r
+ }\r
+ }\r
+\r
+ if (NewVariable != Variable) {\r
+ FreePool (NewVariable);\r
+ }\r
+ if (Variable != NULL) {\r
+ FreePool (Variable);\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));\r
+}\r
+\r
+/**\r
+ Get saved HDD password variable that will be used to validate HDD password\r
+ when the device is at frozen state.\r
+\r
+ @param[in] ConfigFormEntry The HDD Password configuration form entry.\r
+ @param[out] HddPasswordVariable The variable node for the HDD password device.\r
+\r
+ @retval TRUE The variable node for the HDD password device is found and returned.\r
+ @retval FALSE The variable node for the HDD password device is not found.\r
+\r
+**/\r
+BOOLEAN\r
+GetSavedHddPasswordVariable (\r
+ IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry,\r
+ OUT HDD_PASSWORD_VARIABLE *HddPasswordVariable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ HDD_PASSWORD_VARIABLE *TempVariable;\r
+ HDD_PASSWORD_VARIABLE *Variable;\r
+ UINTN VariableSize;\r
+ BOOLEAN Found;\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));\r
+\r
+ Variable = NULL;\r
+ VariableSize = 0;\r
+\r
+ Status = GetVariable2 (\r
+ HDD_PASSWORD_VARIABLE_NAME,\r
+ &mHddPasswordVendorGuid,\r
+ (VOID **) &Variable,\r
+ &VariableSize\r
+ );\r
+ if (EFI_ERROR (Status) || (Variable == NULL)) {\r
+ DEBUG ((DEBUG_INFO, "HddPassword variable get failed (%r)\n", Status));\r
+ return FALSE;\r
+ }\r
+\r
+ Found = FALSE;\r
+ TempVariable = Variable;\r
+ while (VariableSize >= sizeof (HDD_PASSWORD_VARIABLE)) {\r
+ if ((TempVariable->Device.Bus == ConfigFormEntry->Bus) &&\r
+ (TempVariable->Device.Device == ConfigFormEntry->Device) &&\r
+ (TempVariable->Device.Function == ConfigFormEntry->Function) &&\r
+ (TempVariable->Device.Port == ConfigFormEntry->Port) &&\r
+ (TempVariable->Device.PortMultiplierPort == ConfigFormEntry->PortMultiplierPort)) {\r
+ //\r
+ // Found the node for the HDD password device.\r
+ // Get the node.\r
+ //\r
+ CopyMem (HddPasswordVariable, TempVariable, sizeof (HDD_PASSWORD_VARIABLE));\r
+ Found = TRUE;\r
+ break;\r
+ }\r
+ VariableSize -= sizeof (HDD_PASSWORD_VARIABLE);\r
+ TempVariable += 1;\r
+ }\r
+\r
+ FreePool (Variable);\r
+\r
+ if (!Found) {\r
+ DEBUG ((DEBUG_INFO, "The variable node for the HDD password device is not found\n"));\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));\r
+\r
+ return Found;\r
+}\r
+\r
+/**\r
+ Use saved HDD password variable to validate HDD password\r
+ when the device is at frozen state.\r
+\r
+ @param[in] ConfigFormEntry The HDD Password configuration form entry.\r
+ @param[in] Password The hdd password of attached ATA device.\r
+\r
+ @retval EFI_SUCCESS Pass to validate the HDD password.\r
+ @retval EFI_NOT_FOUND The variable node for the HDD password device is not found.\r
+ @retval EFI_DEVICE_ERROR Failed to generate credential for the HDD password.\r
+ @retval EFI_INVALID_PARAMETER Failed to validate the HDD password.\r
+\r
+**/\r
+EFI_STATUS\r
+ValidateHddPassword (\r
+ IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry,\r
+ IN CHAR8 *Password\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ HDD_PASSWORD_VARIABLE HddPasswordVariable;\r
+ BOOLEAN HashOk;\r
+ UINT8 HashData[SHA256_DIGEST_SIZE];\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));\r
+\r
+ if (!GetSavedHddPasswordVariable (ConfigFormEntry, &HddPasswordVariable)) {\r
+ DEBUG ((DEBUG_INFO, "GetSavedHddPasswordVariable failed\n"));\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ ZeroMem (HashData, sizeof (HashData));\r
+ HashOk = GenerateCredential ((UINT8 *) Password, HDD_PASSWORD_MAX_LENGTH, HddPasswordVariable.PasswordSalt, HashData);\r
+ if (!HashOk) {\r
+ DEBUG ((DEBUG_INFO, "GenerateCredential failed\n"));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if (CompareMem (HddPasswordVariable.PasswordHash, HashData, sizeof (HashData)) != 0) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ } else {\r
+ Status = EFI_SUCCESS;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - exit (%r)\n", __FUNCTION__, Status));\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send unlock hdd password cmd through Ata Pass Thru Protocol.\r
+\r
+ @param[in] AtaPassThru The pointer to the ATA_PASS_THRU protocol.\r
+ @param[in] Port The port number of the ATA device to send the command.\r
+ @param[in] PortMultiplierPort The port multiplier port number of the ATA device to send the command.\r
+ If there is no port multiplier, then specify 0xFFFF.\r
+ @param[in] Identifier The identifier to set user or master password.\r
+ @param[in] Password The hdd password of attached ATA device.\r
+\r
+ @retval EFI_SUCCESS Successful to send unlock hdd password cmd.\r
+ @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to send unlock hdd password cmd.\r
+ @retval EFI_DEVICE_ERROR Can not send unlock hdd password cmd.\r
+\r
+**/\r
+EFI_STATUS\r
+UnlockHddPassword (\r
+ IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru,\r
+ IN UINT16 Port,\r
+ IN UINT16 PortMultiplierPort,\r
+ IN CHAR8 Identifier,\r
+ IN CHAR8 *Password\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_ATA_COMMAND_BLOCK Acb;\r
+ EFI_ATA_STATUS_BLOCK *Asb;\r
+ EFI_ATA_PASS_THRU_COMMAND_PACKET Packet;\r
+ UINT8 Buffer[HDD_PAYLOAD];\r
+\r
+ if ((AtaPassThru == NULL) || (Password == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in\r
+ // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned specified by\r
+ // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. Meanwhile,\r
+ // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields, so it\r
+ // may not be aligned when allocated on stack for some compilers. Hence, we\r
+ // use the API AllocateAlignedPages to ensure this structure is properly\r
+ // aligned.\r
+ //\r
+ Asb = AllocateAlignedPages (\r
+ EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)),\r
+ AtaPassThru->Mode->IoAlign\r
+ );\r
+ if (Asb == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Prepare for ATA command block.\r
+ //\r
+ ZeroMem (&Acb, sizeof (Acb));\r
+ ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK));\r
+ Acb.AtaCommand = ATA_SECURITY_UNLOCK_CMD;\r
+ Acb.AtaDeviceHead = (UINT8) (PortMultiplierPort == 0xFFFF ? 0 : (PortMultiplierPort << 4));\r
+\r
+ //\r
+ // Prepare for ATA pass through packet.\r
+ //\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+ Packet.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT;\r
+ Packet.Length = EFI_ATA_PASS_THRU_LENGTH_BYTES;\r
+ Packet.Asb = Asb;\r
+ Packet.Acb = &Acb;\r
+\r
+ ((CHAR16 *) Buffer)[0] = Identifier & BIT0;\r
+ CopyMem (&((CHAR16 *) Buffer)[1], Password, HDD_PASSWORD_MAX_LENGTH);\r
+\r
+ Packet.OutDataBuffer = Buffer;\r
+ Packet.OutTransferLength = sizeof (Buffer);\r
+ Packet.Timeout = ATA_TIMEOUT;\r
+\r
+ Status = AtaPassThru->PassThru (\r
+ AtaPassThru,\r
+ Port,\r
+ PortMultiplierPort,\r
+ &Packet,\r
+ NULL\r
+ );\r
+ if (!EFI_ERROR (Status) &&\r
+ ((Asb->AtaStatus & ATA_STSREG_ERR) != 0) &&\r
+ ((Asb->AtaError & ATA_ERRREG_ABRT) != 0)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ FreeAlignedPages (Asb, EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)));\r
+\r
+ ZeroMem (Buffer, sizeof (Buffer));\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - %r\n", __FUNCTION__, Status));\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send disable hdd password cmd through Ata Pass Thru Protocol.\r
+\r
+ @param[in] AtaPassThru The pointer to the ATA_PASS_THRU protocol.\r
+ @param[in] Port The port number of the ATA device to send the command.\r
+ @param[in] PortMultiplierPort The port multiplier port number of the ATA device to send the command.\r
+ If there is no port multiplier, then specify 0xFFFF.\r
+ @param[in] Identifier The identifier to set user or master password.\r
+ @param[in] Password The hdd password of attached ATA device.\r
+\r
+ @retval EFI_SUCCESS Successful to disable hdd password cmd.\r
+ @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to disable hdd password cmd.\r
+ @retval EFI_DEVICE_ERROR Can not disable hdd password cmd.\r
+\r
+**/\r
+EFI_STATUS\r
+DisableHddPassword (\r
+ IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru,\r
+ IN UINT16 Port,\r
+ IN UINT16 PortMultiplierPort,\r
+ IN CHAR8 Identifier,\r
+ IN CHAR8 *Password\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_ATA_COMMAND_BLOCK Acb;\r
+ EFI_ATA_STATUS_BLOCK *Asb;\r
+ EFI_ATA_PASS_THRU_COMMAND_PACKET Packet;\r
+ UINT8 Buffer[HDD_PAYLOAD];\r
+\r
+ if ((AtaPassThru == NULL) || (Password == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in\r
+ // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned specified by\r
+ // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. Meanwhile,\r
+ // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields, so it\r
+ // may not be aligned when allocated on stack for some compilers. Hence, we\r
+ // use the API AllocateAlignedPages to ensure this structure is properly\r
+ // aligned.\r
+ //\r
+ Asb = AllocateAlignedPages (\r
+ EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)),\r
+ AtaPassThru->Mode->IoAlign\r
+ );\r
+ if (Asb == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Prepare for ATA command block.\r
+ //\r
+ ZeroMem (&Acb, sizeof (Acb));\r
+ ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK));\r
+ Acb.AtaCommand = ATA_SECURITY_DIS_PASSWORD_CMD;\r
+ Acb.AtaDeviceHead = (UINT8) (PortMultiplierPort == 0xFFFF ? 0 : (PortMultiplierPort << 4));\r
+\r
+ //\r
+ // Prepare for ATA pass through packet.\r
+ //\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+ Packet.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT;\r
+ Packet.Length = EFI_ATA_PASS_THRU_LENGTH_BYTES;\r
+ Packet.Asb = Asb;\r
+ Packet.Acb = &Acb;\r
+\r
+ ((CHAR16 *) Buffer)[0] = Identifier & BIT0;\r
+ CopyMem (&((CHAR16 *) Buffer)[1], Password, HDD_PASSWORD_MAX_LENGTH);\r
+\r
+ Packet.OutDataBuffer = Buffer;\r
+ Packet.OutTransferLength = sizeof (Buffer);\r
+ Packet.Timeout = ATA_TIMEOUT;\r
+\r
+ Status = AtaPassThru->PassThru (\r
+ AtaPassThru,\r
+ Port,\r
+ PortMultiplierPort,\r
+ &Packet,\r
+ NULL\r
+ );\r
+ if (!EFI_ERROR (Status) &&\r
+ ((Asb->AtaStatus & ATA_STSREG_ERR) != 0) &&\r
+ ((Asb->AtaError & ATA_ERRREG_ABRT) != 0)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ FreeAlignedPages (Asb, EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)));\r
+\r
+ ZeroMem (Buffer, sizeof (Buffer));\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - %r\n", __FUNCTION__, Status));\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send set hdd password cmd through Ata Pass Thru Protocol.\r
+\r
+ @param[in] AtaPassThru The pointer to the ATA_PASS_THRU protocol.\r
+ @param[in] Port The port number of the ATA device to send the command.\r
+ @param[in] PortMultiplierPort The port multiplier port number of the ATA device to send the command.\r
+ If there is no port multiplier, then specify 0xFFFF.\r
+ @param[in] Identifier The identifier to set user or master password.\r
+ @param[in] SecurityLevel The security level to be set to device.\r
+ @param[in] MasterPasswordIdentifier The master password identifier to be set to device.\r
+ @param[in] Password The hdd password of attached ATA device.\r
+\r
+ @retval EFI_SUCCESS Successful to set hdd password cmd.\r
+ @retval EFI_INVALID_PARAMETER The parameter passed-in is invalid.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to set hdd password cmd.\r
+ @retval EFI_DEVICE_ERROR Can not set hdd password cmd.\r
+\r
+**/\r
+EFI_STATUS\r
+SetHddPassword (\r
+ IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru,\r
+ IN UINT16 Port,\r
+ IN UINT16 PortMultiplierPort,\r
+ IN CHAR8 Identifier,\r
+ IN CHAR8 SecurityLevel,\r
+ IN CHAR16 MasterPasswordIdentifier,\r
+ IN CHAR8 *Password\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_ATA_COMMAND_BLOCK Acb;\r
+ EFI_ATA_STATUS_BLOCK *Asb;\r
+ EFI_ATA_PASS_THRU_COMMAND_PACKET Packet;\r
+ UINT8 Buffer[HDD_PAYLOAD];\r
+\r
+ if ((AtaPassThru == NULL) || (Password == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // The 'Asb' field (a pointer to the EFI_ATA_STATUS_BLOCK structure) in\r
+ // EFI_ATA_PASS_THRU_COMMAND_PACKET is required to be aligned specified by\r
+ // the 'IoAlign' field in the EFI_ATA_PASS_THRU_MODE structure. Meanwhile,\r
+ // the structure EFI_ATA_STATUS_BLOCK is composed of only UINT8 fields, so it\r
+ // may not be aligned when allocated on stack for some compilers. Hence, we\r
+ // use the API AllocateAlignedPages to ensure this structure is properly\r
+ // aligned.\r
+ //\r
+ Asb = AllocateAlignedPages (\r
+ EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)),\r
+ AtaPassThru->Mode->IoAlign\r
+ );\r
+ if (Asb == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Prepare for ATA command block.\r
+ //\r
+ ZeroMem (&Acb, sizeof (Acb));\r
+ ZeroMem (Asb, sizeof (EFI_ATA_STATUS_BLOCK));\r
+ Acb.AtaCommand = ATA_SECURITY_SET_PASSWORD_CMD;\r
+ Acb.AtaDeviceHead = (UINT8) (PortMultiplierPort == 0xFFFF ? 0 : (PortMultiplierPort << 4));\r
+\r
+ //\r
+ // Prepare for ATA pass through packet.\r
+ //\r
+ ZeroMem (&Packet, sizeof (Packet));\r
+ Packet.Protocol = EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT;\r
+ Packet.Length = EFI_ATA_PASS_THRU_LENGTH_BYTES;\r
+ Packet.Asb = Asb;\r
+ Packet.Acb = &Acb;\r
+\r
+ ((CHAR16 *) Buffer)[0] = (Identifier | (UINT16)(SecurityLevel << 8)) & (BIT0 | BIT8);\r
+ CopyMem (&((CHAR16 *) Buffer)[1], Password, HDD_PASSWORD_MAX_LENGTH);\r
+ if ((Identifier & BIT0) != 0) {\r
+ ((CHAR16 *) Buffer)[17] = MasterPasswordIdentifier;\r
+ }\r
+\r
+ Packet.OutDataBuffer = Buffer;\r
+ Packet.OutTransferLength = sizeof (Buffer);\r
+ Packet.Timeout = ATA_TIMEOUT;\r
+\r
+ Status = AtaPassThru->PassThru (\r
+ AtaPassThru,\r
+ Port,\r
+ PortMultiplierPort,\r
+ &Packet,\r
+ NULL\r
+ );\r
+ if (!EFI_ERROR (Status) &&\r
+ ((Asb->AtaStatus & ATA_STSREG_ERR) != 0) &&\r
+ ((Asb->AtaError & ATA_ERRREG_ABRT) != 0)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ FreeAlignedPages (Asb, EFI_SIZE_TO_PAGES (sizeof (EFI_ATA_STATUS_BLOCK)));\r
+\r
+ ZeroMem (Buffer, sizeof (Buffer));\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - %r\n", __FUNCTION__, Status));\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Get attached harddisk model number from identify data buffer.\r
+\r
+ @param[in] IdentifyData Pointer to identify data buffer.\r
+ @param[in, out] String The buffer to store harddisk model number.\r
+\r
+**/\r
+VOID\r
+GetHddDeviceModelNumber (\r
+ IN ATA_IDENTIFY_DATA *IdentifyData,\r
+ IN OUT CHAR16 *String\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ //\r
+ // Swap the byte order in the original module name.\r
+ // From Ata spec, the maximum length is 40 bytes.\r
+ //\r
+ for (Index = 0; Index < 40; Index += 2) {\r
+ String[Index] = IdentifyData->ModelName[Index + 1];\r
+ String[Index + 1] = IdentifyData->ModelName[Index];\r
+ }\r
+\r
+ //\r
+ // Chap it off after 20 characters\r
+ //\r
+ String[20] = L'\0';\r
+\r
+ return ;\r
+}\r
+\r
+/**\r
+ Get password input from the popup windows.\r
+\r
+ @param[in] PopUpString1 Pop up string 1.\r
+ @param[in] PopUpString2 Pop up string 2.\r
+ @param[in, out] Password The buffer to hold the input password.\r
+\r
+ @retval EFI_ABORTED It is given up by pressing 'ESC' key.\r
+ @retval EFI_SUCCESS Get password input successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+PopupHddPasswordInputWindows (\r
+ IN CHAR16 *PopUpString1,\r
+ IN CHAR16 *PopUpString2,\r
+ IN OUT CHAR8 *Password\r
+ )\r
+{\r
+ EFI_INPUT_KEY Key;\r
+ UINTN Length;\r
+ CHAR16 Mask[HDD_PASSWORD_MAX_LENGTH + 1];\r
+ CHAR16 Unicode[HDD_PASSWORD_MAX_LENGTH + 1];\r
+ CHAR8 Ascii[HDD_PASSWORD_MAX_LENGTH + 1];\r
+\r
+ ZeroMem (Unicode, sizeof (Unicode));\r
+ ZeroMem (Ascii, sizeof (Ascii));\r
+ ZeroMem (Mask, sizeof (Mask));\r
+\r
+ gST->ConOut->ClearScreen(gST->ConOut);\r
+\r
+ Length = 0;\r
+ while (TRUE) {\r
+ Mask[Length] = L'_';\r
+ if (PopUpString2 == NULL) {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ PopUpString1,\r
+ L"---------------------",\r
+ Mask,\r
+ NULL\r
+ );\r
+ } else {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ PopUpString1,\r
+ PopUpString2,\r
+ L"---------------------",\r
+ Mask,\r
+ NULL\r
+ );\r
+ }\r
+ //\r
+ // Check key.\r
+ //\r
+ if (Key.ScanCode == SCAN_NULL) {\r
+ if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
+ //\r
+ // Add the null terminator.\r
+ //\r
+ Unicode[Length] = 0;\r
+ break;\r
+ } else if ((Key.UnicodeChar == CHAR_NULL) ||\r
+ (Key.UnicodeChar == CHAR_TAB) ||\r
+ (Key.UnicodeChar == CHAR_LINEFEED)\r
+ ) {\r
+ continue;\r
+ } else {\r
+ if (Key.UnicodeChar == CHAR_BACKSPACE) {\r
+ if (Length > 0) {\r
+ Unicode[Length] = 0;\r
+ Mask[Length] = 0;\r
+ Length--;\r
+ }\r
+ } else {\r
+ Unicode[Length] = Key.UnicodeChar;\r
+ Mask[Length] = L'*';\r
+ Length++;\r
+ if (Length == HDD_PASSWORD_MAX_LENGTH) {\r
+ //\r
+ // Add the null terminator.\r
+ //\r
+ Unicode[Length] = 0;\r
+ Mask[Length] = 0;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ if (Key.ScanCode == SCAN_ESC) {\r
+ ZeroMem (Unicode, sizeof (Unicode));\r
+ ZeroMem (Ascii, sizeof (Ascii));\r
+ gST->ConOut->ClearScreen(gST->ConOut);\r
+ return EFI_ABORTED;\r
+ }\r
+ }\r
+\r
+ UnicodeStrToAsciiStrS (Unicode, Ascii, sizeof (Ascii));\r
+ CopyMem (Password, Ascii, HDD_PASSWORD_MAX_LENGTH);\r
+ ZeroMem (Unicode, sizeof (Unicode));\r
+ ZeroMem (Ascii, sizeof (Ascii));\r
+\r
+ gST->ConOut->ClearScreen(gST->ConOut);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Check if disk is locked, show popup window and ask for password if it is.\r
+\r
+ @param[in] AtaPassThru Pointer to ATA_PASSTHRU instance.\r
+ @param[in] Port The port number of attached ATA device.\r
+ @param[in] PortMultiplierPort The port number of port multiplier of attached ATA device.\r
+ @param[in] ConfigFormEntry The HDD Password configuration form entry.\r
+\r
+**/\r
+VOID\r
+HddPasswordRequestPassword (\r
+ IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru,\r
+ IN UINT16 Port,\r
+ IN UINT16 PortMultiplierPort,\r
+ IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ CHAR16 PopUpString[100];\r
+ ATA_IDENTIFY_DATA IdentifyData;\r
+ EFI_INPUT_KEY Key;\r
+ UINT16 RetryCount;\r
+ CHAR8 Password[HDD_PASSWORD_MAX_LENGTH];\r
+\r
+ RetryCount = 0;\r
+\r
+ DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
+\r
+ UnicodeSPrint (PopUpString, sizeof (PopUpString), L"Unlock: %s", ConfigFormEntry->HddString);\r
+\r
+ //\r
+ // Check the device security status.\r
+ //\r
+ if ((ConfigFormEntry->IfrData.SecurityStatus.Supported) &&\r
+ (ConfigFormEntry->IfrData.SecurityStatus.Enabled)) {\r
+ //\r
+ // As soon as the HDD password is in enabled state, we pop up a window to unlock hdd\r
+ // no matter it's really in locked or unlocked state.\r
+ // This way forces user to enter password every time to provide best safety.\r
+ //\r
+ while (TRUE) {\r
+ Status = PopupHddPasswordInputWindows (PopUpString, NULL, Password);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // The HDD is in locked state, unlock it by user input.\r
+ //\r
+ if (!PasswordIsFullZero (Password)) {\r
+ if (!ConfigFormEntry->IfrData.SecurityStatus.Frozen) {\r
+ Status = UnlockHddPassword (AtaPassThru, Port, PortMultiplierPort, 0, Password);\r
+ } else {\r
+ //\r
+ // Use saved HDD password variable to validate HDD password\r
+ // when the device is at frozen state.\r
+ //\r
+ Status = ValidateHddPassword (ConfigFormEntry, Password);\r
+ }\r
+ } else {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
+ if (!EFI_ERROR (Status)) {\r
+ CopyMem (ConfigFormEntry->Password, Password, HDD_PASSWORD_MAX_LENGTH);\r
+ if (!ConfigFormEntry->IfrData.SecurityStatus.Frozen) {\r
+ SaveHddPasswordVariable (ConfigFormEntry, Password);\r
+ }\r
+ ZeroMem (Password, HDD_PASSWORD_MAX_LENGTH);\r
+ Status = GetHddDeviceIdentifyData (AtaPassThru, Port, PortMultiplierPort, &IdentifyData);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Check the device security status again.\r
+ //\r
+ GetHddPasswordSecurityStatus (&IdentifyData, &ConfigFormEntry->IfrData);\r
+ return;\r
+ }\r
+\r
+ ZeroMem (Password, HDD_PASSWORD_MAX_LENGTH);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ RetryCount ++;\r
+ if (RetryCount < MAX_HDD_PASSWORD_RETRY_COUNT) {\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Invalid password.",\r
+ L"Press ENTER to retry",\r
+ NULL\r
+ );\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ continue;\r
+ } else {\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Hdd password retry count is expired. Please shutdown the machine.",\r
+ L"Press ENTER to shutdown",\r
+ NULL\r
+ );\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);\r
+ break;\r
+ }\r
+ }\r
+ } else if (Status == EFI_ABORTED) {\r
+ if (ConfigFormEntry->IfrData.SecurityStatus.Locked) {\r
+ //\r
+ // Current device in the lock status and\r
+ // User not input password and press ESC,\r
+ // keep device in lock status and continue boot.\r
+ //\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Press ENTER to skip the request and continue boot,",\r
+ L"Press ESC to input password again",\r
+ NULL\r
+ );\r
+ } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
+\r
+ if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
+ gST->ConOut->ClearScreen(gST->ConOut);\r
+ //\r
+ // Keep lock and continue boot.\r
+ //\r
+ return;\r
+ } else {\r
+ //\r
+ // Let user input password again.\r
+ //\r
+ continue;\r
+ }\r
+ } else {\r
+ //\r
+ // Current device in the unlock status and\r
+ // User not input password and press ESC,\r
+ // Shutdown the device.\r
+ //\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Press ENTER to shutdown, Press ESC to input password again",\r
+ NULL\r
+ );\r
+ } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
+\r
+ if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
+ gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);\r
+ } else {\r
+ //\r
+ // Let user input password again.\r
+ //\r
+ continue;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Process Set User Pwd HDD password request.\r
+\r
+ @param[in] AtaPassThru Pointer to ATA_PASSTHRU instance.\r
+ @param[in] Port The port number of attached ATA device.\r
+ @param[in] PortMultiplierPort The port number of port multiplier of attached ATA device.\r
+ @param[in] ConfigFormEntry The HDD Password configuration form entry.\r
+\r
+**/\r
+VOID\r
+ProcessHddPasswordRequestSetUserPwd (\r
+ IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru,\r
+ IN UINT16 Port,\r
+ IN UINT16 PortMultiplierPort,\r
+ IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ CHAR16 PopUpString[100];\r
+ ATA_IDENTIFY_DATA IdentifyData;\r
+ EFI_INPUT_KEY Key;\r
+ UINT16 RetryCount;\r
+ CHAR8 Password[HDD_PASSWORD_MAX_LENGTH];\r
+ CHAR8 PasswordConfirm[HDD_PASSWORD_MAX_LENGTH];\r
+\r
+ RetryCount = 0;\r
+\r
+ DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
+\r
+ if (ConfigFormEntry->IfrData.SecurityStatus.Frozen) {\r
+ DEBUG ((DEBUG_INFO, "%s is frozen, do nothing\n", ConfigFormEntry->HddString));\r
+ return;\r
+ }\r
+\r
+ if (ConfigFormEntry->IfrData.SecurityStatus.Locked) {\r
+ DEBUG ((DEBUG_INFO, "%s is locked, do nothing\n", ConfigFormEntry->HddString));\r
+ return;\r
+ }\r
+\r
+ UnicodeSPrint (PopUpString, sizeof (PopUpString), L"Set User Pwd: %s", ConfigFormEntry->HddString);\r
+\r
+ //\r
+ // Check the device security status.\r
+ //\r
+ if (ConfigFormEntry->IfrData.SecurityStatus.Supported) {\r
+ while (TRUE) {\r
+ Status = PopupHddPasswordInputWindows (PopUpString, L"Please type in your new password", Password);\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = PopupHddPasswordInputWindows (PopUpString, L"Please confirm your new password", PasswordConfirm);\r
+ if (!EFI_ERROR (Status)) {\r
+ if (CompareMem (Password, PasswordConfirm, HDD_PASSWORD_MAX_LENGTH) == 0) {\r
+ if (!PasswordIsFullZero (Password)) {\r
+ Status = SetHddPassword (AtaPassThru, Port, PortMultiplierPort, 0, 1, 0, Password);\r
+ } else {\r
+ if (ConfigFormEntry->IfrData.SecurityStatus.Enabled) {\r
+ Status = DisableHddPassword (AtaPassThru, Port, PortMultiplierPort, 0, ConfigFormEntry->Password);\r
+ } else {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ if (!EFI_ERROR (Status)) {\r
+ CopyMem (ConfigFormEntry->Password, Password, HDD_PASSWORD_MAX_LENGTH);\r
+ SaveHddPasswordVariable (ConfigFormEntry, Password);\r
+ ZeroMem (Password, HDD_PASSWORD_MAX_LENGTH);\r
+ ZeroMem (PasswordConfirm, HDD_PASSWORD_MAX_LENGTH);\r
+ Status = GetHddDeviceIdentifyData (AtaPassThru, Port, PortMultiplierPort, &IdentifyData);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Check the device security status again.\r
+ //\r
+ GetHddPasswordSecurityStatus (&IdentifyData, &ConfigFormEntry->IfrData);\r
+ return;\r
+ } else {\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Set/Disable User Pwd failed or invalid password.",\r
+ L"Press ENTER to retry",\r
+ NULL\r
+ );\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ }\r
+ } else {\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Passwords are not the same.",\r
+ L"Press ENTER to retry",\r
+ NULL\r
+ );\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ ZeroMem (Password, HDD_PASSWORD_MAX_LENGTH);\r
+ ZeroMem (PasswordConfirm, HDD_PASSWORD_MAX_LENGTH);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ RetryCount ++;\r
+ if (RetryCount >= MAX_HDD_PASSWORD_RETRY_COUNT) {\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Hdd password retry count is expired.",\r
+ L"Press ENTER to skip the request and continue boot",\r
+ NULL\r
+ );\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ gST->ConOut->ClearScreen(gST->ConOut);\r
+ return;\r
+ }\r
+ }\r
+ } else if (Status == EFI_ABORTED) {\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Press ENTER to skip the request and continue boot,",\r
+ L"Press ESC to input password again",\r
+ NULL\r
+ );\r
+ } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
+\r
+ if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
+ gST->ConOut->ClearScreen(gST->ConOut);\r
+ return;\r
+ } else {\r
+ //\r
+ // Let user input password again.\r
+ //\r
+ continue;\r
+ }\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Process Set Master Pwd HDD password request.\r
+\r
+ @param[in] AtaPassThru Pointer to ATA_PASSTHRU instance.\r
+ @param[in] Port The port number of attached ATA device.\r
+ @param[in] PortMultiplierPort The port number of port multiplier of attached ATA device.\r
+ @param[in] ConfigFormEntry The HDD Password configuration form entry.\r
+\r
+**/\r
+VOID\r
+ProcessHddPasswordRequestSetMasterPwd (\r
+ IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru,\r
+ IN UINT16 Port,\r
+ IN UINT16 PortMultiplierPort,\r
+ IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ CHAR16 PopUpString[100];\r
+ EFI_INPUT_KEY Key;\r
+ UINT16 RetryCount;\r
+ CHAR8 Password[HDD_PASSWORD_MAX_LENGTH];\r
+ CHAR8 PasswordConfirm[HDD_PASSWORD_MAX_LENGTH];\r
+\r
+ RetryCount = 0;\r
+\r
+ DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));\r
+\r
+ if (ConfigFormEntry->IfrData.SecurityStatus.Frozen) {\r
+ DEBUG ((DEBUG_INFO, "%s is frozen, do nothing\n", ConfigFormEntry->HddString));\r
+ return;\r
+ }\r
+\r
+ if (ConfigFormEntry->IfrData.SecurityStatus.Locked) {\r
+ DEBUG ((DEBUG_INFO, "%s is locked, do nothing\n", ConfigFormEntry->HddString));\r
+ return;\r
+ }\r
+\r
+ UnicodeSPrint (PopUpString, sizeof (PopUpString), L"Set Master Pwd: %s", ConfigFormEntry->HddString);\r
+\r
+ //\r
+ // Check the device security status.\r
+ //\r
+ if (ConfigFormEntry->IfrData.SecurityStatus.Supported) {\r
+ while (TRUE) {\r
+ Status = PopupHddPasswordInputWindows (PopUpString, L"Please type in your new password", Password);\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = PopupHddPasswordInputWindows (PopUpString, L"Please confirm your new password", PasswordConfirm);\r
+ if (!EFI_ERROR (Status)) {\r
+ if (CompareMem (Password, PasswordConfirm, HDD_PASSWORD_MAX_LENGTH) == 0) {\r
+ if (!PasswordIsFullZero (Password)) {\r
+ Status = SetHddPassword (AtaPassThru, Port, PortMultiplierPort, 1, 1, 1, Password);\r
+ } else {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
+ if (!EFI_ERROR (Status)) {\r
+ ZeroMem (Password, HDD_PASSWORD_MAX_LENGTH);\r
+ ZeroMem (PasswordConfirm, HDD_PASSWORD_MAX_LENGTH);\r
+ return;\r
+ } else {\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Set Master Pwd failed or invalid password.",\r
+ L"Press ENTER to retry",\r
+ NULL\r
+ );\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ }\r
+ } else {\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Passwords are not the same.",\r
+ L"Press ENTER to retry",\r
+ NULL\r
+ );\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ ZeroMem (Password, HDD_PASSWORD_MAX_LENGTH);\r
+ ZeroMem (PasswordConfirm, HDD_PASSWORD_MAX_LENGTH);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ RetryCount ++;\r
+ if (RetryCount >= MAX_HDD_PASSWORD_RETRY_COUNT) {\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Hdd password retry count is expired.",\r
+ L"Press ENTER to skip the request and continue boot",\r
+ NULL\r
+ );\r
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+ gST->ConOut->ClearScreen(gST->ConOut);\r
+ return;\r
+ }\r
+ }\r
+ } else if (Status == EFI_ABORTED) {\r
+ do {\r
+ CreatePopUp (\r
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+ &Key,\r
+ L"Press ENTER to skip the request and continue boot,",\r
+ L"Press ESC to input password again",\r
+ NULL\r
+ );\r
+ } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));\r
+\r
+ if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
+ gST->ConOut->ClearScreen(gST->ConOut);\r
+ return;\r
+ } else {\r
+ //\r
+ // Let user input password again.\r
+ //\r
+ continue;\r
+ }\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Process HDD password request.\r
+\r
+ @param[in] AtaPassThru Pointer to ATA_PASSTHRU instance.\r
+ @param[in] Port The port number of attached ATA device.\r
+ @param[in] PortMultiplierPort The port number of port multiplier of attached ATA device.\r
+ @param[in] ConfigFormEntry The HDD Password configuration form entry.\r
+\r
+**/\r
+VOID\r
+ProcessHddPasswordRequest (\r
+ IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru,\r
+ IN UINT16 Port,\r
+ IN UINT16 PortMultiplierPort,\r
+ IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ HDD_PASSWORD_REQUEST_VARIABLE *TempVariable;\r
+ HDD_PASSWORD_REQUEST_VARIABLE *Variable;\r
+ UINTN VariableSize;\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));\r
+\r
+ if (mHddPasswordRequestVariable == NULL) {\r
+ Status = GetVariable2 (\r
+ HDD_PASSWORD_REQUEST_VARIABLE_NAME,\r
+ &mHddPasswordVendorGuid,\r
+ (VOID **) &Variable,\r
+ &VariableSize\r
+ );\r
+ if (EFI_ERROR (Status) || (Variable == NULL)) {\r
+ return;\r
+ }\r
+ mHddPasswordRequestVariable = Variable;\r
+ mHddPasswordRequestVariableSize = VariableSize;\r
+\r
+ //\r
+ // Delete the HDD password request variable.\r
+ //\r
+ Status = gRT->SetVariable (\r
+ HDD_PASSWORD_REQUEST_VARIABLE_NAME,\r
+ &mHddPasswordVendorGuid,\r
+ 0,\r
+ 0,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ } else {\r
+ Variable = mHddPasswordRequestVariable;\r
+ VariableSize = mHddPasswordRequestVariableSize;\r
+ }\r
+\r
+ //\r
+ // Process the HDD password requests.\r
+ //\r
+ TempVariable = Variable;\r
+ while (VariableSize >= sizeof (HDD_PASSWORD_REQUEST_VARIABLE)) {\r
+ if ((TempVariable->Device.Bus == ConfigFormEntry->Bus) &&\r
+ (TempVariable->Device.Device == ConfigFormEntry->Device) &&\r
+ (TempVariable->Device.Function == ConfigFormEntry->Function) &&\r
+ (TempVariable->Device.Port == ConfigFormEntry->Port) &&\r
+ (TempVariable->Device.PortMultiplierPort == ConfigFormEntry->PortMultiplierPort)) {\r
+ //\r
+ // Found the node for the HDD password device.\r
+ //\r
+ if (TempVariable->Request.UserPassword != 0) {\r
+ ProcessHddPasswordRequestSetUserPwd (AtaPassThru, Port, PortMultiplierPort, ConfigFormEntry);\r
+ }\r
+ if (TempVariable->Request.MasterPassword != 0) {\r
+ ProcessHddPasswordRequestSetMasterPwd (AtaPassThru, Port, PortMultiplierPort, ConfigFormEntry);\r
+ }\r
+\r
+ break;\r
+ }\r
+\r
+ VariableSize -= sizeof (HDD_PASSWORD_REQUEST_VARIABLE);\r
+ TempVariable += 1;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));\r
+}\r
+\r
+/**\r
+ Get saved HDD password request.\r
+\r
+ @param[in, out] ConfigFormEntry The HDD Password configuration form entry.\r
+\r
+**/\r
+VOID\r
+GetSavedHddPasswordRequest (\r
+ IN OUT HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ HDD_PASSWORD_REQUEST_VARIABLE *TempVariable;\r
+ HDD_PASSWORD_REQUEST_VARIABLE *Variable;\r
+ UINTN VariableSize;\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));\r
+\r
+ Variable = NULL;\r
+ VariableSize = 0;\r
+\r
+ Status = GetVariable2 (\r
+ HDD_PASSWORD_REQUEST_VARIABLE_NAME,\r
+ &mHddPasswordVendorGuid,\r
+ (VOID **) &Variable,\r
+ &VariableSize\r
+ );\r
+ if (EFI_ERROR (Status) || (Variable == NULL)) {\r
+ return;\r
+ }\r
+\r
+ TempVariable = Variable;\r
+ while (VariableSize >= sizeof (HDD_PASSWORD_REQUEST_VARIABLE)) {\r
+ if ((TempVariable->Device.Bus == ConfigFormEntry->Bus) &&\r
+ (TempVariable->Device.Device == ConfigFormEntry->Device) &&\r
+ (TempVariable->Device.Function == ConfigFormEntry->Function) &&\r
+ (TempVariable->Device.Port == ConfigFormEntry->Port) &&\r
+ (TempVariable->Device.PortMultiplierPort == ConfigFormEntry->PortMultiplierPort)) {\r
+ //\r
+ // Found the node for the HDD password device.\r
+ // Get the HDD password request.\r
+ //\r
+ CopyMem (&ConfigFormEntry->IfrData.Request, &TempVariable->Request, sizeof (HDD_PASSWORD_REQUEST));\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "HddPasswordRequest got: 0x%x\n",\r
+ ConfigFormEntry->IfrData.Request\r
+ ));\r
+ break;\r
+ }\r
+ VariableSize -= sizeof (HDD_PASSWORD_REQUEST_VARIABLE);\r
+ TempVariable += 1;\r
+ }\r
+\r
+ FreePool (Variable);\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));\r
+}\r
+\r
+/**\r
+ Save HDD password request.\r
+\r
+ @param[in] ConfigFormEntry The HDD Password configuration form entry.\r
+\r
+**/\r
+VOID\r
+SaveHddPasswordRequest (\r
+ IN HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ HDD_PASSWORD_REQUEST_VARIABLE *TempVariable;\r
+ UINTN TempVariableSize;\r
+ HDD_PASSWORD_REQUEST_VARIABLE *Variable;\r
+ UINTN VariableSize;\r
+ HDD_PASSWORD_REQUEST_VARIABLE *NewVariable;\r
+ UINTN NewVariableSize;\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));\r
+\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "HddPasswordRequest to save: 0x%x\n",\r
+ ConfigFormEntry->IfrData.Request\r
+ ));\r
+\r
+ Variable = NULL;\r
+ VariableSize = 0;\r
+ NewVariable = NULL;\r
+ NewVariableSize = 0;\r
+\r
+ Status = GetVariable2 (\r
+ HDD_PASSWORD_REQUEST_VARIABLE_NAME,\r
+ &mHddPasswordVendorGuid,\r
+ (VOID **) &Variable,\r
+ &VariableSize\r
+ );\r
+ if (!EFI_ERROR (Status) && (Variable != NULL)) {\r
+ TempVariable = Variable;\r
+ TempVariableSize = VariableSize;\r
+ while (TempVariableSize >= sizeof (HDD_PASSWORD_REQUEST_VARIABLE)) {\r
+ if ((TempVariable->Device.Bus == ConfigFormEntry->Bus) &&\r
+ (TempVariable->Device.Device == ConfigFormEntry->Device) &&\r
+ (TempVariable->Device.Function == ConfigFormEntry->Function) &&\r
+ (TempVariable->Device.Port == ConfigFormEntry->Port) &&\r
+ (TempVariable->Device.PortMultiplierPort == ConfigFormEntry->PortMultiplierPort)) {\r
+ //\r
+ // Found the node for the HDD password device.\r
+ // Update the HDD password request.\r
+ //\r
+ CopyMem (&TempVariable->Request, &ConfigFormEntry->IfrData.Request, sizeof (HDD_PASSWORD_REQUEST));\r
+ NewVariable = Variable;\r
+ NewVariableSize = VariableSize;\r
+ break;\r
+ }\r
+ TempVariableSize -= sizeof (HDD_PASSWORD_REQUEST_VARIABLE);\r
+ TempVariable += 1;\r
+ }\r
+ if (NewVariable == NULL) {\r
+ //\r
+ // The node for the HDD password device is not found.\r
+ // Create node for the HDD password device.\r
+ //\r
+ NewVariableSize = VariableSize + sizeof (HDD_PASSWORD_REQUEST_VARIABLE);\r
+ NewVariable = AllocateZeroPool (NewVariableSize);\r
+ ASSERT (NewVariable != NULL);\r
+ CopyMem (NewVariable, Variable, VariableSize);\r
+ TempVariable = (HDD_PASSWORD_REQUEST_VARIABLE *) ((UINTN) NewVariable + VariableSize);\r
+ TempVariable->Device.Bus = (UINT8) ConfigFormEntry->Bus;\r
+ TempVariable->Device.Device = (UINT8) ConfigFormEntry->Device;\r
+ TempVariable->Device.Function = (UINT8) ConfigFormEntry->Function;\r
+ TempVariable->Device.Port = ConfigFormEntry->Port;\r
+ TempVariable->Device.PortMultiplierPort = ConfigFormEntry->PortMultiplierPort;\r
+ CopyMem (&TempVariable->Request, &ConfigFormEntry->IfrData.Request, sizeof (HDD_PASSWORD_REQUEST));\r
+ }\r
+ } else {\r
+ NewVariableSize = sizeof (HDD_PASSWORD_REQUEST_VARIABLE);\r
+ NewVariable = AllocateZeroPool (NewVariableSize);\r
+ ASSERT (NewVariable != NULL);\r
+ NewVariable->Device.Bus = (UINT8) ConfigFormEntry->Bus;\r
+ NewVariable->Device.Device = (UINT8) ConfigFormEntry->Device;\r
+ NewVariable->Device.Function = (UINT8) ConfigFormEntry->Function;\r
+ NewVariable->Device.Port = ConfigFormEntry->Port;\r
+ NewVariable->Device.PortMultiplierPort = ConfigFormEntry->PortMultiplierPort;\r
+ CopyMem (&NewVariable->Request, &ConfigFormEntry->IfrData.Request, sizeof (HDD_PASSWORD_REQUEST));\r
+ }\r
+ Status = gRT->SetVariable (\r
+ HDD_PASSWORD_REQUEST_VARIABLE_NAME,\r
+ &mHddPasswordVendorGuid,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+ NewVariableSize,\r
+ NewVariable\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_INFO, "HddPasswordRequest variable set failed (%r)\n", Status));\r
+ }\r
+ if (NewVariable != Variable) {\r
+ FreePool (NewVariable);\r
+ }\r
+ if (Variable != NULL) {\r
+ FreePool (Variable);\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));\r
+}\r
+\r
+/**\r
+ Get the HDD Password configuration form entry by the index of the goto opcode actived.\r
+\r
+ @param[in] Index The 0-based index of the goto opcode actived.\r
+\r
+ @return The HDD Password configuration form entry found.\r
+**/\r
+HDD_PASSWORD_CONFIG_FORM_ENTRY *\r
+HddPasswordGetConfigFormEntryByIndex (\r
+ IN UINT32 Index\r
+ )\r
+{\r
+ LIST_ENTRY *Entry;\r
+ UINT32 CurrentIndex;\r
+ HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry;\r
+\r
+ CurrentIndex = 0;\r
+ ConfigFormEntry = NULL;\r
+\r
+ EFI_LIST_FOR_EACH (Entry, &mHddPasswordConfigFormList) {\r
+ if (CurrentIndex == Index) {\r
+ ConfigFormEntry = BASE_CR (Entry, HDD_PASSWORD_CONFIG_FORM_ENTRY, Link);\r
+ break;\r
+ }\r
+\r
+ CurrentIndex++;\r
+ }\r
+\r
+ return ConfigFormEntry;\r
+}\r
+\r
+/**\r
+ This function allows the caller to request the current\r
+ configuration for one or more named elements. The resulting\r
+ string is in <ConfigAltResp> format. Any and all alternative\r
+ configuration strings shall also be appended to the end of the\r
+ current configuration string. If they are, they must appear\r
+ after the current configuration. They must contain the same\r
+ routing (GUID, NAME, PATH) as the current configuration string.\r
+ They must have an additional description indicating the type of\r
+ alternative configuration the string represents,\r
+ "ALTCFG=<StringToken>". That <StringToken> (when\r
+ converted from Hex UNICODE to binary) is a reference to a\r
+ string in the associated string pack.\r
+\r
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+ @param[in] Request A null-terminated Unicode string in\r
+ <ConfigRequest> format. Note that this\r
+ includes the routing information as well as\r
+ the configurable name / value pairs. It is\r
+ invalid for this string to be in\r
+ <MultiConfigRequest> format.\r
+ @param[out] Progress On return, points to a character in the\r
+ Request string. Points to the string's null\r
+ terminator if request was successful. Points\r
+ to the most recent "&" before the first\r
+ failing name / value pair (or the beginning\r
+ of the string if the failure is in the first\r
+ name / value pair) if the request was not\r
+ successful.\r
+ @param[out] Results A null-terminated Unicode string in\r
+ <ConfigAltResp> format which has all values\r
+ filled in for the names in the Request string.\r
+ String to be allocated by the called function.\r
+\r
+ @retval EFI_SUCCESS The Results string is filled with the\r
+ values corresponding to all requested\r
+ names.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the\r
+ parts of the results that must be\r
+ stored awaiting possible future\r
+ protocols.\r
+ @retval EFI_INVALID_PARAMETER For example, passing in a NULL\r
+ for the Request parameter\r
+ would result in this type of\r
+ error. In this case, the\r
+ Progress parameter would be\r
+ set to NULL.\r
+ @retval EFI_NOT_FOUND Routing data doesn't match any\r
+ known driver. Progress set to the\r
+ first character in the routing header.\r
+ Note: There is no requirement that the\r
+ driver validate the routing data. It\r
+ must skip the <ConfigHdr> in order to\r
+ process the names.\r
+ @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set\r
+ to most recent & before the\r
+ error or the beginning of the\r
+ string.\r
+ @retval EFI_INVALID_PARAMETER Unknown name. Progress points\r
+ to the & before the name in\r
+ question.Currently not implemented.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HddPasswordFormExtractConfig (\r
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
+ IN CONST EFI_STRING Request,\r
+ OUT EFI_STRING *Progress,\r
+ OUT EFI_STRING *Results\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN BufferSize;\r
+ HDD_PASSWORD_CONFIG *IfrData;\r
+ HDD_PASSWORD_DXE_PRIVATE_DATA *Private;\r
+ EFI_STRING ConfigRequestHdr;\r
+ EFI_STRING ConfigRequest;\r
+ BOOLEAN AllocatedRequest;\r
+ UINTN Size;\r
+\r
+ if (Progress == NULL || Results == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *Progress = Request;\r
+ if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &mHddPasswordVendorGuid, mHddPasswordVendorStorageName)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ ConfigRequestHdr = NULL;\r
+ ConfigRequest = NULL;\r
+ AllocatedRequest = FALSE;\r
+ Size = 0;\r
+\r
+ Private = HDD_PASSWORD_DXE_PRIVATE_FROM_THIS (This);\r
+ IfrData = AllocateZeroPool (sizeof (HDD_PASSWORD_CONFIG));\r
+ ASSERT (IfrData != NULL);\r
+ if (Private->Current != NULL) {\r
+ CopyMem (IfrData, &Private->Current->IfrData, sizeof (HDD_PASSWORD_CONFIG));\r
+ }\r
+\r
+ //\r
+ // Convert buffer data to <ConfigResp> by helper function BlockToConfig()\r
+ //\r
+ BufferSize = sizeof (HDD_PASSWORD_CONFIG);\r
+ ConfigRequest = Request;\r
+ if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {\r
+ //\r
+ // Request has no request element, construct full request string.\r
+ // Allocate and fill a buffer large enough to hold the <ConfigHdr> template\r
+ // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator\r
+ //\r
+ ConfigRequestHdr = HiiConstructConfigHdr (&mHddPasswordVendorGuid, mHddPasswordVendorStorageName, Private->DriverHandle);\r
+ Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);\r
+ ConfigRequest = AllocateZeroPool (Size);\r
+ ASSERT (ConfigRequest != NULL);\r
+ AllocatedRequest = TRUE;\r
+ UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);\r
+ FreePool (ConfigRequestHdr);\r
+ }\r
+ Status = gHiiConfigRouting->BlockToConfig (\r
+ gHiiConfigRouting,\r
+ ConfigRequest,\r
+ (UINT8 *) IfrData,\r
+ BufferSize,\r
+ Results,\r
+ Progress\r
+ );\r
+ FreePool (IfrData);\r
+ //\r
+ // Free the allocated config request string.\r
+ //\r
+ if (AllocatedRequest) {\r
+ FreePool (ConfigRequest);\r
+ ConfigRequest = NULL;\r
+ }\r
+\r
+ //\r
+ // Set Progress string to the original request string.\r
+ //\r
+ if (Request == NULL) {\r
+ *Progress = NULL;\r
+ } else if (StrStr (Request, L"OFFSET") == NULL) {\r
+ *Progress = Request + StrLen (Request);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ This function applies changes in a driver's configuration.\r
+ Input is a Configuration, which has the routing data for this\r
+ driver followed by name / value configuration pairs. The driver\r
+ must apply those pairs to its configurable storage. If the\r
+ driver's configuration is stored in a linear block of data\r
+ and the driver's name / value pairs are in <BlockConfig>\r
+ format, it may use the ConfigToBlock helper function (above) to\r
+ simplify the job. Currently not implemented.\r
+\r
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+ @param[in] Configuration A null-terminated Unicode string in\r
+ <ConfigString> format.\r
+ @param[out] Progress A pointer to a string filled in with the\r
+ offset of the most recent '&' before the\r
+ first failing name / value pair (or the\r
+ beginn ing of the string if the failure\r
+ is in the first name / value pair) or\r
+ the terminating NULL if all was\r
+ successful.\r
+\r
+ @retval EFI_SUCCESS The results have been distributed or are\r
+ awaiting distribution.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the\r
+ parts of the results that must be\r
+ stored awaiting possible future\r
+ protocols.\r
+ @retval EFI_INVALID_PARAMETERS Passing in a NULL for the\r
+ Results parameter would result\r
+ in this type of error.\r
+ @retval EFI_NOT_FOUND Target for the specified routing data\r
+ was not found.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HddPasswordFormRouteConfig (\r
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
+ IN CONST EFI_STRING Configuration,\r
+ OUT EFI_STRING *Progress\r
+ )\r
+{\r
+ if (Configuration == NULL || Progress == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Check routing data in <ConfigHdr>.\r
+ // Note: if only one Storage is used, then this checking could be skipped.\r
+ //\r
+ if (!HiiIsConfigHdrMatch (Configuration, &mHddPasswordVendorGuid, mHddPasswordVendorStorageName)) {\r
+ *Progress = Configuration;\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ *Progress = Configuration + StrLen (Configuration);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function is called to provide results data to the driver.\r
+ This data consists of a unique key that is used to identify\r
+ which data is either being passed back or being asked for.\r
+\r
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+ @param[in] Action Specifies the type of action taken by the browser.\r
+ @param[in] QuestionId A unique value which is sent to the original\r
+ exporting driver so that it can identify the type\r
+ of data to expect. The format of the data tends to\r
+ vary based on the opcode that enerated the callback.\r
+ @param[in] Type The type of value for the question.\r
+ @param[in] Value A pointer to the data being sent to the original\r
+ exporting driver.\r
+ @param[out] ActionRequest On return, points to the action requested by the\r
+ callback function.\r
+\r
+ @retval EFI_SUCCESS The callback successfully handled the action.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the\r
+ variable and its data.\r
+ @retval EFI_DEVICE_ERROR The variable could not be saved.\r
+ @retval EFI_UNSUPPORTED The specified Action is not supported by the\r
+ callback.Currently not implemented.\r
+ @retval EFI_INVALID_PARAMETERS Passing in wrong parameter.\r
+ @retval Others Other errors as indicated.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HddPasswordFormCallback (\r
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
+ IN EFI_BROWSER_ACTION Action,\r
+ IN EFI_QUESTION_ID QuestionId,\r
+ IN UINT8 Type,\r
+ IN EFI_IFR_TYPE_VALUE *Value,\r
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest\r
+ )\r
+{\r
+ HDD_PASSWORD_DXE_PRIVATE_DATA *Private;\r
+ EFI_STRING_ID DeviceFormTitleToken;\r
+ HDD_PASSWORD_CONFIG *IfrData;\r
+ HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry;\r
+\r
+ if (ActionRequest != NULL) {\r
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
+ } else {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Action != EFI_BROWSER_ACTION_CHANGING) && (Action != EFI_BROWSER_ACTION_CHANGED)) {\r
+ //\r
+ // Do nothing for other UEFI Action. Only do call back when data is changing or changed.\r
+ //\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Private = HDD_PASSWORD_DXE_PRIVATE_FROM_THIS (This);\r
+\r
+ //\r
+ // Retrive data from Browser\r
+ //\r
+ IfrData = AllocateZeroPool (sizeof (HDD_PASSWORD_CONFIG));\r
+ ASSERT (IfrData != NULL);\r
+ if (!HiiGetBrowserData (&mHddPasswordVendorGuid, mHddPasswordVendorStorageName, sizeof (HDD_PASSWORD_CONFIG), (UINT8 *) IfrData)) {\r
+ FreePool (IfrData);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ switch (QuestionId) {\r
+ case KEY_HDD_USER_PASSWORD:\r
+ if (Action == EFI_BROWSER_ACTION_CHANGED) {\r
+ DEBUG ((DEBUG_INFO, "KEY_HDD_USER_PASSWORD\n"));\r
+ ConfigFormEntry = Private->Current;\r
+ ConfigFormEntry->IfrData.Request.UserPassword = Value->b;\r
+ SaveHddPasswordRequest (ConfigFormEntry);\r
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;\r
+ }\r
+ break;\r
+ case KEY_HDD_MASTER_PASSWORD:\r
+ if (Action == EFI_BROWSER_ACTION_CHANGED) {\r
+ DEBUG ((DEBUG_INFO, "KEY_HDD_MASTER_PASSWORD\n"));\r
+ ConfigFormEntry = Private->Current;\r
+ ConfigFormEntry->IfrData.Request.MasterPassword = Value->b;\r
+ SaveHddPasswordRequest (ConfigFormEntry);\r
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;\r
+ }\r
+ break;\r
+\r
+ default:\r
+ if ((QuestionId >= KEY_HDD_DEVICE_ENTRY_BASE) && (QuestionId < (mNumberOfHddDevices + KEY_HDD_DEVICE_ENTRY_BASE))) {\r
+ if (Action == EFI_BROWSER_ACTION_CHANGING) {\r
+ //\r
+ // In case goto the device configuration form, update the device form title.\r
+ //\r
+ ConfigFormEntry = HddPasswordGetConfigFormEntryByIndex ((UINT32) (QuestionId - KEY_HDD_DEVICE_ENTRY_BASE));\r
+ ASSERT (ConfigFormEntry != NULL);\r
+\r
+ DeviceFormTitleToken = (EFI_STRING_ID) STR_HDD_SECURITY_HD;\r
+ HiiSetString (Private->HiiHandle, DeviceFormTitleToken, ConfigFormEntry->HddString, NULL);\r
+\r
+ Private->Current = ConfigFormEntry;\r
+ CopyMem (IfrData, &ConfigFormEntry->IfrData, sizeof (HDD_PASSWORD_CONFIG));\r
+ }\r
+ }\r
+\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Pass changed uncommitted data back to Form Browser\r
+ //\r
+ HiiSetBrowserData (&mHddPasswordVendorGuid, mHddPasswordVendorStorageName, sizeof (HDD_PASSWORD_CONFIG), (UINT8 *) IfrData, NULL);\r
+\r
+ FreePool (IfrData);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Updates the HDD Password configuration form to add an entry for the attached\r
+ ata harddisk device specified by the Controller.\r
+\r
+ @param[in] HiiHandle The HII Handle associated with the registered package list.\r
+ @param[in] AtaPassThru Pointer to ATA_PASSTHRU instance.\r
+ @param[in] PciIo Pointer to PCI_IO instance.\r
+ @param[in] Controller The controller handle of the attached ata controller.\r
+ @param[in] Bus The bus number of ATA controller.\r
+ @param[in] Device The device number of ATA controller.\r
+ @param[in] Function The function number of ATA controller.\r
+ @param[in] Port The port number of attached ATA device.\r
+ @param[in] PortMultiplierPort The port number of port multiplier of attached ATA device.\r
+\r
+ @retval EFI_SUCCESS The Hdd Password configuration form is updated.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+ @retval Others Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+HddPasswordConfigUpdateForm (\r
+ IN EFI_HII_HANDLE HiiHandle,\r
+ IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru,\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN EFI_HANDLE Controller,\r
+ IN UINTN Bus,\r
+ IN UINTN Device,\r
+ IN UINTN Function,\r
+ IN UINT16 Port,\r
+ IN UINT16 PortMultiplierPort\r
+ )\r
+{\r
+ LIST_ENTRY *Entry;\r
+ HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry;\r
+ BOOLEAN EntryExisted;\r
+ EFI_STATUS Status;\r
+ VOID *StartOpCodeHandle;\r
+ VOID *EndOpCodeHandle;\r
+ EFI_IFR_GUID_LABEL *StartLabel;\r
+ EFI_IFR_GUID_LABEL *EndLabel;\r
+ CHAR16 HddString[40];\r
+ ATA_IDENTIFY_DATA IdentifyData;\r
+ EFI_DEVICE_PATH_PROTOCOL *AtaDeviceNode;\r
+\r
+ ConfigFormEntry = NULL;\r
+ EntryExisted = FALSE;\r
+\r
+ EFI_LIST_FOR_EACH (Entry, &mHddPasswordConfigFormList) {\r
+ ConfigFormEntry = BASE_CR (Entry, HDD_PASSWORD_CONFIG_FORM_ENTRY, Link);\r
+\r
+ if ((ConfigFormEntry->Bus == Bus) &&\r
+ (ConfigFormEntry->Device == Device) &&\r
+ (ConfigFormEntry->Function == Function) &&\r
+ (ConfigFormEntry->Port == Port) &&\r
+ (ConfigFormEntry->PortMultiplierPort == PortMultiplierPort)) {\r
+ EntryExisted = TRUE;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (!EntryExisted) {\r
+ //\r
+ // Add a new form.\r
+ //\r
+ ConfigFormEntry = AllocateZeroPool (sizeof (HDD_PASSWORD_CONFIG_FORM_ENTRY));\r
+ if (ConfigFormEntry == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ InitializeListHead (&ConfigFormEntry->Link);\r
+ ConfigFormEntry->Controller = Controller;\r
+ ConfigFormEntry->Bus = Bus;\r
+ ConfigFormEntry->Device = Device;\r
+ ConfigFormEntry->Function = Function;\r
+ ConfigFormEntry->Port = Port;\r
+ ConfigFormEntry->PortMultiplierPort = PortMultiplierPort;\r
+ ConfigFormEntry->AtaPassThru = AtaPassThru;\r
+\r
+ 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));\r
+\r
+ //\r
+ // Construct the device path for the HDD password device\r
+ //\r
+ Status = AtaPassThru->BuildDevicePath (\r
+ AtaPassThru,\r
+ Port,\r
+ PortMultiplierPort,\r
+ &AtaDeviceNode\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ ConfigFormEntry->DevicePath = AppendDevicePathNode (DevicePathFromHandle (Controller), AtaDeviceNode);\r
+ FreePool (AtaDeviceNode);\r
+ if (ConfigFormEntry->DevicePath == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Get attached harddisk model number\r
+ //\r
+ Status = GetHddDeviceIdentifyData (AtaPassThru, Port, PortMultiplierPort, &IdentifyData);\r
+ ASSERT_EFI_ERROR (Status);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ GetHddDeviceModelNumber (&IdentifyData, HddString);\r
+ //\r
+ // Compose the HDD title string and help string of this port and create a new EFI_STRING_ID.\r
+ //\r
+ UnicodeSPrint (ConfigFormEntry->HddString, sizeof (ConfigFormEntry->HddString), L"HDD %d:%s", mNumberOfHddDevices, HddString);\r
+ ConfigFormEntry->TitleToken = HiiSetString (HiiHandle, 0, ConfigFormEntry->HddString, NULL);\r
+ ConfigFormEntry->TitleHelpToken = HiiSetString (HiiHandle, 0, L"Request to set HDD Password", NULL);\r
+\r
+ GetHddPasswordSecurityStatus (&IdentifyData, &ConfigFormEntry->IfrData);\r
+\r
+ InsertTailList (&mHddPasswordConfigFormList, &ConfigFormEntry->Link);\r
+\r
+ //\r
+ // Init OpCode Handle\r
+ //\r
+ StartOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+ ASSERT (StartOpCodeHandle != NULL);\r
+\r
+ EndOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+ ASSERT (EndOpCodeHandle != NULL);\r
+\r
+ //\r
+ // Create Hii Extend Label OpCode as the start opcode\r
+ //\r
+ StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));\r
+ StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
+ StartLabel->Number = HDD_DEVICE_ENTRY_LABEL;\r
+\r
+ //\r
+ // Create Hii Extend Label OpCode as the end opcode\r
+ //\r
+ EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));\r
+ EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
+ EndLabel->Number = HDD_DEVICE_LABEL_END;\r
+\r
+ mNumberOfHddDevices = 0;\r
+ EFI_LIST_FOR_EACH (Entry, &mHddPasswordConfigFormList) {\r
+ ConfigFormEntry = BASE_CR (Entry, HDD_PASSWORD_CONFIG_FORM_ENTRY, Link);\r
+\r
+ HiiCreateGotoOpCode (\r
+ StartOpCodeHandle, // Container for dynamic created opcodes\r
+ FORMID_HDD_DEVICE_FORM, // Target Form ID\r
+ ConfigFormEntry->TitleToken, // Prompt text\r
+ ConfigFormEntry->TitleHelpToken, // Help text\r
+ EFI_IFR_FLAG_CALLBACK, // Question flag\r
+ (UINT16) (KEY_HDD_DEVICE_ENTRY_BASE + mNumberOfHddDevices) // Question ID\r
+ );\r
+\r
+ mNumberOfHddDevices++;\r
+ }\r
+\r
+ HiiUpdateForm (\r
+ HiiHandle,\r
+ &mHddPasswordVendorGuid,\r
+ FORMID_HDD_MAIN_FORM,\r
+ StartOpCodeHandle,\r
+ EndOpCodeHandle\r
+ );\r
+\r
+ HiiFreeOpCodeHandle (StartOpCodeHandle);\r
+ HiiFreeOpCodeHandle (EndOpCodeHandle);\r
+\r
+ //\r
+ // Check if device is locked and prompt for password.\r
+ //\r
+ HddPasswordRequestPassword (AtaPassThru, Port, PortMultiplierPort, ConfigFormEntry);\r
+\r
+ //\r
+ // Process HDD password request from last boot.\r
+ //\r
+ ProcessHddPasswordRequest (AtaPassThru, Port, PortMultiplierPort, ConfigFormEntry);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Ata Pass Thru Protocol notification event handler.\r
+\r
+ Check attached harddisk status to see if it's locked. If yes, then pop up a password windows to require user input.\r
+ It also registers a form for user configuration on Hdd password configuration.\r
+\r
+ @param[in] Event Event whose notification function is being invoked.\r
+ @param[in] Context Pointer to the notification function's context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+HddPasswordNotificationEvent (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ HDD_PASSWORD_DXE_PRIVATE_DATA *Private;\r
+ EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru;\r
+ UINT16 Port;\r
+ UINT16 PortMultiplierPort;\r
+ EFI_HANDLE Controller;\r
+ EFI_HANDLE *HandleBuffer;\r
+ UINTN HandleCount;\r
+ UINTN Index;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINTN SegNum;\r
+ UINTN BusNum;\r
+ UINTN DevNum;\r
+ UINTN FuncNum;\r
+\r
+ if (mHddPasswordEndOfDxe) {\r
+ gBS->CloseEvent (Event);\r
+ return;\r
+ }\r
+\r
+ Private = (HDD_PASSWORD_DXE_PRIVATE_DATA *)Context;\r
+\r
+ //\r
+ // Locate all handles of AtaPassThru protocol\r
+ //\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiAtaPassThruProtocolGuid,\r
+ NULL,\r
+ &HandleCount,\r
+ &HandleBuffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return ;\r
+ }\r
+\r
+ //\r
+ // Check attached hard disk status to see if it's locked\r
+ //\r
+ for (Index = 0; Index < HandleCount; Index += 1) {\r
+ Controller = HandleBuffer[Index];\r
+ Status = gBS->HandleProtocol (\r
+ Controller,\r
+ &gEfiAtaPassThruProtocolGuid,\r
+ (VOID **) &AtaPassThru\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Ignore those logical ATA_PASS_THRU instance.\r
+ //\r
+ if ((AtaPassThru->Mode->Attributes & EFI_ATA_PASS_THRU_ATTRIBUTES_PHYSICAL) == 0) {\r
+ continue;\r
+ }\r
+\r
+ Status = gBS->HandleProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ (VOID **) &PciIo\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+\r
+ Status = PciIo->GetLocation (\r
+ PciIo,\r
+ &SegNum,\r
+ &BusNum,\r
+ &DevNum,\r
+ &FuncNum\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Assume and only support Segment == 0.\r
+ //\r
+ ASSERT (SegNum == 0);\r
+\r
+ //\r
+ // traverse all attached harddisk devices to update form and unlock it\r
+ //\r
+ Port = 0xFFFF;\r
+\r
+ while (TRUE) {\r
+ Status = AtaPassThru->GetNextPort (AtaPassThru, &Port);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // We cannot find more legal port then we are done.\r
+ //\r
+ break;\r
+ }\r
+\r
+ PortMultiplierPort = 0xFFFF;\r
+ while (TRUE) {\r
+ Status = AtaPassThru->GetNextDevice (AtaPassThru, Port, &PortMultiplierPort);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // We cannot find more legal port multiplier port number for ATA device\r
+ // on the port, then we are done.\r
+ //\r
+ break;\r
+ }\r
+ //\r
+ // Find out the attached harddisk devices.\r
+ // Try to add a HDD Password configuration page for the attached devices.\r
+ //\r
+ gBS->RestoreTPL (TPL_APPLICATION);\r
+ Status = HddPasswordConfigUpdateForm (Private->HiiHandle, AtaPassThru, PciIo, Controller, BusNum, DevNum, FuncNum, Port, PortMultiplierPort);\r
+ gBS->RaiseTPL (TPL_CALLBACK);\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ FreePool (HandleBuffer);\r
+ return ;\r
+}\r
+\r
+/**\r
+ Initialize the HDD Password configuration form.\r
+\r
+ @param[out] Instance Pointer to private instance.\r
+\r
+ @retval EFI_SUCCESS The HDD Password configuration form is initialized.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+ @retval Others Other errors as indicated.\r
+**/\r
+EFI_STATUS\r
+HddPasswordConfigFormInit (\r
+ OUT HDD_PASSWORD_DXE_PRIVATE_DATA **Instance\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ HDD_PASSWORD_DXE_PRIVATE_DATA *Private;\r
+\r
+ InitializeListHead (&mHddPasswordConfigFormList);\r
+\r
+ Private = AllocateZeroPool (sizeof (HDD_PASSWORD_DXE_PRIVATE_DATA));\r
+ if (Private == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Private->Signature = HDD_PASSWORD_DXE_PRIVATE_SIGNATURE;\r
+\r
+ Private->ConfigAccess.ExtractConfig = HddPasswordFormExtractConfig;\r
+ Private->ConfigAccess.RouteConfig = HddPasswordFormRouteConfig;\r
+ Private->ConfigAccess.Callback = HddPasswordFormCallback;\r
+\r
+ //\r
+ // Install Device Path Protocol and Config Access protocol to driver handle\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &Private->DriverHandle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ &mHddPasswordHiiVendorDevicePath,\r
+ &gEfiHiiConfigAccessProtocolGuid,\r
+ &Private->ConfigAccess,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool(Private);\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Publish our HII data\r
+ //\r
+ Private->HiiHandle = HiiAddPackages (\r
+ &mHddPasswordVendorGuid,\r
+ Private->DriverHandle,\r
+ HddPasswordDxeStrings,\r
+ HddPasswordBin,\r
+ NULL\r
+ );\r
+ if (Private->HiiHandle == NULL) {\r
+ FreePool(Private);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ *Instance = Private;\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Main entry for this driver.\r
+\r
+ @param ImageHandle Image handle this driver.\r
+ @param SystemTable Pointer to SystemTable.\r
+\r
+ @retval EFI_SUCESS This function always complete successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+HddPasswordDxeInit (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ HDD_PASSWORD_DXE_PRIVATE_DATA *Private;\r
+ EFI_EVENT Registration;\r
+ EFI_EVENT EndOfDxeEvent;\r
+ EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;\r
+\r
+ Private = NULL;\r
+\r
+ //\r
+ // Initialize the configuration form of HDD Password.\r
+ //\r
+ Status = HddPasswordConfigFormInit (&Private);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Register HddPasswordNotificationEvent() notify function.\r
+ //\r
+ EfiCreateProtocolNotifyEvent (\r
+ &gEfiAtaPassThruProtocolGuid,\r
+ TPL_CALLBACK,\r
+ HddPasswordNotificationEvent,\r
+ (VOID *)Private,\r
+ &Registration\r
+ );\r
+\r
+ Status = gBS->CreateEventEx (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ HddPasswordEndOfDxeEventNotify,\r
+ NULL,\r
+ &gEfiEndOfDxeEventGroupGuid,\r
+ &EndOfDxeEvent\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Make HDD_PASSWORD_VARIABLE_NAME varible read-only.\r
+ //\r
+ Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = VariableLock->RequestToLock (\r
+ VariableLock,\r
+ HDD_PASSWORD_VARIABLE_NAME,\r
+ &mHddPasswordVendorGuid\r
+ );\r
+ DEBUG ((DEBUG_INFO, "%a(): Lock %s variable (%r)\n", __FUNCTION__, HDD_PASSWORD_VARIABLE_NAME, Status));\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+ return Status;\r
+}\r