REF:https://bugzilla.tianocore.org/show_bug.cgi?id=1959 Replaces usage of the linked list iteration macros defined in HddPasswordDxe.h with the common definition in BaseLib.h. Cc: Chao Zhang <chao.b.zhang@intel.com> Cc: Hao A Wu <hao.a.wu@intel.com> Cc: Jian J Wang <jian.j.wang@intel.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Sean Brogan <sean.brogan@microsoft.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Liming Gao <liming.gao@intel.com> Reviewed-by: Bret Barkelew <bret.barkelew@microsoft.com>
		
			
				
	
	
		
			2825 lines
		
	
	
		
			99 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2825 lines
		
	
	
		
			99 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   HDD password driver which is used to support HDD security feature.
 | |
| 
 | |
|   Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
 | |
|   Copyright (c) Microsoft Corporation.<BR>
 | |
| 
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #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;
 | |
|   BASE_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 command, 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;
 | |
|   BASE_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.
 | |
|   //
 | |
|   BASE_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)) {
 | |
| 
 | |
|      //
 | |
|      // Add PcdSkipHddPasswordPrompt to determin whether to skip password prompt.
 | |
|      // Due to board design, device may not power off during system warm boot, which result in
 | |
|      // security status remain unlocked status, hence we add device security status check here.
 | |
|      //
 | |
|      // If device is in the locked status, device keeps locked and system continues booting.
 | |
|      // If device is in the unlocked status, system is forced shutdown for security concern.
 | |
|      //
 | |
|      if (PcdGetBool (PcdSkipHddPasswordPrompt)) {
 | |
|        if (ConfigFormEntry->IfrData.SecurityStatus.Locked) {
 | |
|          return;
 | |
|        } else {
 | |
|          gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);
 | |
|        }
 | |
|     }
 | |
|     //
 | |
|     // 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 activated.
 | |
| 
 | |
|   @param[in]  Index The 0-based index of the goto opcode activated.
 | |
| 
 | |
|   @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;
 | |
| 
 | |
|   BASE_LIST_FOR_EACH (Entry, &mHddPasswordConfigFormList) {
 | |
|     if (CurrentIndex == Index) {
 | |
|       ConfigFormEntry = BASE_CR (Entry, HDD_PASSWORD_CONFIG_FORM_ENTRY, Link);
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     CurrentIndex++;
 | |
|   }
 | |
| 
 | |
|   return ConfigFormEntry;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function allows the caller to request the current
 | |
|   configuration for one or more named elements. The resulting
 | |
|   string is in <ConfigAltResp> format. Any and all alternative
 | |
|   configuration strings shall also be appended to the end of the
 | |
|   current configuration string. If they are, they must appear
 | |
|   after the current configuration. They must contain the same
 | |
|   routing (GUID, NAME, PATH) as the current configuration string.
 | |
|   They must have an additional description indicating the type of
 | |
|   alternative configuration the string represents,
 | |
|   "ALTCFG=<StringToken>". That <StringToken> (when
 | |
|   converted from Hex UNICODE to binary) is a reference to a
 | |
|   string in the associated string pack.
 | |
| 
 | |
|   @param[in] This       Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
 | |
|   @param[in] Request    A null-terminated Unicode string in
 | |
|                         <ConfigRequest> format. Note that this
 | |
|                         includes the routing information as well as
 | |
|                         the configurable name / value pairs. It is
 | |
|                         invalid for this string to be in
 | |
|                         <MultiConfigRequest> format.
 | |
|   @param[out] Progress  On return, points to a character in the
 | |
|                         Request string. Points to the string's null
 | |
|                         terminator if request was successful. Points
 | |
|                         to the most recent "&" before the first
 | |
|                         failing name / value pair (or the beginning
 | |
|                         of the string if the failure is in the first
 | |
|                         name / value pair) if the request was not
 | |
|                         successful.
 | |
|   @param[out] Results   A null-terminated Unicode string in
 | |
|                         <ConfigAltResp> format which has all values
 | |
|                         filled in for the names in the Request string.
 | |
|                         String to be allocated by the called function.
 | |
| 
 | |
|   @retval EFI_SUCCESS             The Results string is filled with the
 | |
|                                   values corresponding to all requested
 | |
|                                   names.
 | |
|   @retval EFI_OUT_OF_RESOURCES    Not enough memory to store the
 | |
|                                   parts of the results that must be
 | |
|                                   stored awaiting possible future
 | |
|                                   protocols.
 | |
|   @retval EFI_INVALID_PARAMETER   For example, passing in a NULL
 | |
|                                   for the Request parameter
 | |
|                                   would result in this type of
 | |
|                                   error. In this case, the
 | |
|                                   Progress parameter would be
 | |
|                                   set to NULL.
 | |
|   @retval EFI_NOT_FOUND           Routing data doesn't match any
 | |
|                                   known driver. Progress set to the
 | |
|                                   first character in the routing header.
 | |
|                                   Note: There is no requirement that the
 | |
|                                   driver validate the routing data. It
 | |
|                                   must skip the <ConfigHdr> in order to
 | |
|                                   process the names.
 | |
|   @retval EFI_INVALID_PARAMETER   Illegal syntax. Progress set
 | |
|                                   to most recent & before the
 | |
|                                   error or the beginning of the
 | |
|                                   string.
 | |
|   @retval EFI_INVALID_PARAMETER   Unknown name. Progress points
 | |
|                                   to the & before the name in
 | |
|                                   question.Currently not implemented.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| HddPasswordFormExtractConfig (
 | |
|   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
 | |
|   IN  CONST EFI_STRING                       Request,
 | |
|   OUT EFI_STRING                             *Progress,
 | |
|   OUT EFI_STRING                             *Results
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                       Status;
 | |
|   UINTN                            BufferSize;
 | |
|   HDD_PASSWORD_CONFIG              *IfrData;
 | |
|   HDD_PASSWORD_DXE_PRIVATE_DATA    *Private;
 | |
|   EFI_STRING                       ConfigRequestHdr;
 | |
|   EFI_STRING                       ConfigRequest;
 | |
|   BOOLEAN                          AllocatedRequest;
 | |
|   UINTN                            Size;
 | |
| 
 | |
|   if (Progress == NULL || Results == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   *Progress = Request;
 | |
|   if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &mHddPasswordVendorGuid, mHddPasswordVendorStorageName)) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   ConfigRequestHdr = NULL;
 | |
|   ConfigRequest    = NULL;
 | |
|   AllocatedRequest = FALSE;
 | |
|   Size             = 0;
 | |
| 
 | |
|   Private = HDD_PASSWORD_DXE_PRIVATE_FROM_THIS (This);
 | |
|   IfrData = AllocateZeroPool (sizeof (HDD_PASSWORD_CONFIG));
 | |
|   ASSERT (IfrData != NULL);
 | |
|   if (Private->Current != NULL) {
 | |
|     CopyMem (IfrData, &Private->Current->IfrData, sizeof (HDD_PASSWORD_CONFIG));
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
 | |
|   //
 | |
|   BufferSize = sizeof (HDD_PASSWORD_CONFIG);
 | |
|   ConfigRequest = Request;
 | |
|   if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
 | |
|     //
 | |
|     // Request has no request element, construct full request string.
 | |
|     // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
 | |
|     // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
 | |
|     //
 | |
|     ConfigRequestHdr = HiiConstructConfigHdr (&mHddPasswordVendorGuid, mHddPasswordVendorStorageName, Private->DriverHandle);
 | |
|     Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
 | |
|     ConfigRequest = AllocateZeroPool (Size);
 | |
|     ASSERT (ConfigRequest != NULL);
 | |
|     AllocatedRequest = TRUE;
 | |
|     UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);
 | |
|     FreePool (ConfigRequestHdr);
 | |
|   }
 | |
|   Status = gHiiConfigRouting->BlockToConfig (
 | |
|                                 gHiiConfigRouting,
 | |
|                                 ConfigRequest,
 | |
|                                 (UINT8 *) IfrData,
 | |
|                                 BufferSize,
 | |
|                                 Results,
 | |
|                                 Progress
 | |
|                                 );
 | |
|   FreePool (IfrData);
 | |
|   //
 | |
|   // Free the allocated config request string.
 | |
|   //
 | |
|   if (AllocatedRequest) {
 | |
|     FreePool (ConfigRequest);
 | |
|     ConfigRequest = NULL;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Set Progress string to the original request string.
 | |
|   //
 | |
|   if (Request == NULL) {
 | |
|     *Progress = NULL;
 | |
|   } else if (StrStr (Request, L"OFFSET") == NULL) {
 | |
|     *Progress = Request + StrLen (Request);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function applies changes in a driver's configuration.
 | |
|   Input is a Configuration, which has the routing data for this
 | |
|   driver followed by name / value configuration pairs. The driver
 | |
|   must apply those pairs to its configurable storage. If the
 | |
|   driver's configuration is stored in a linear block of data
 | |
|   and the driver's name / value pairs are in <BlockConfig>
 | |
|   format, it may use the ConfigToBlock helper function (above) to
 | |
|   simplify the job. Currently not implemented.
 | |
| 
 | |
|   @param[in]  This           Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
 | |
|   @param[in]  Configuration  A null-terminated Unicode string in
 | |
|                              <ConfigString> format.
 | |
|   @param[out] Progress       A pointer to a string filled in with the
 | |
|                              offset of the most recent '&' before the
 | |
|                              first failing name / value pair (or the
 | |
|                              beginn ing of the string if the failure
 | |
|                              is in the first name / value pair) or
 | |
|                              the terminating NULL if all was
 | |
|                              successful.
 | |
| 
 | |
|   @retval EFI_SUCCESS             The results have been distributed or are
 | |
|                                   awaiting distribution.
 | |
|   @retval EFI_OUT_OF_RESOURCES    Not enough memory to store the
 | |
|                                   parts of the results that must be
 | |
|                                   stored awaiting possible future
 | |
|                                   protocols.
 | |
|   @retval EFI_INVALID_PARAMETERS  Passing in a NULL for the
 | |
|                                   Results parameter would result
 | |
|                                   in this type of error.
 | |
|   @retval EFI_NOT_FOUND           Target for the specified routing data
 | |
|                                   was not found.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| HddPasswordFormRouteConfig (
 | |
|   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
 | |
|   IN  CONST EFI_STRING                       Configuration,
 | |
|   OUT EFI_STRING                             *Progress
 | |
|   )
 | |
| {
 | |
|   if (Configuration == NULL || Progress == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Check routing data in <ConfigHdr>.
 | |
|   // Note: if only one Storage is used, then this checking could be skipped.
 | |
|   //
 | |
|   if (!HiiIsConfigHdrMatch (Configuration, &mHddPasswordVendorGuid, mHddPasswordVendorStorageName)) {
 | |
|     *Progress = Configuration;
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   *Progress = Configuration + StrLen (Configuration);
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function is called to provide results data to the driver.
 | |
|   This data consists of a unique key that is used to identify
 | |
|   which data is either being passed back or being asked for.
 | |
| 
 | |
|   @param[in]  This               Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
 | |
|   @param[in]  Action             Specifies the type of action taken by the browser.
 | |
|   @param[in]  QuestionId         A unique value which is sent to the original
 | |
|                                  exporting driver so that it can identify the type
 | |
|                                  of data to expect. The format of the data tends to
 | |
|                                  vary based on the opcode that enerated the callback.
 | |
|   @param[in]  Type               The type of value for the question.
 | |
|   @param[in]  Value              A pointer to the data being sent to the original
 | |
|                                  exporting driver.
 | |
|   @param[out]  ActionRequest     On return, points to the action requested by the
 | |
|                                  callback function.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The callback successfully handled the action.
 | |
|   @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the
 | |
|                                  variable and its data.
 | |
|   @retval EFI_DEVICE_ERROR       The variable could not be saved.
 | |
|   @retval EFI_UNSUPPORTED        The specified Action is not supported by the
 | |
|                                  callback.Currently not implemented.
 | |
|   @retval EFI_INVALID_PARAMETERS Passing in wrong parameter.
 | |
|   @retval Others                 Other errors as indicated.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| HddPasswordFormCallback (
 | |
|   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
 | |
|   IN  EFI_BROWSER_ACTION                     Action,
 | |
|   IN  EFI_QUESTION_ID                        QuestionId,
 | |
|   IN  UINT8                                  Type,
 | |
|   IN  EFI_IFR_TYPE_VALUE                     *Value,
 | |
|   OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest
 | |
|   )
 | |
| {
 | |
|   HDD_PASSWORD_DXE_PRIVATE_DATA   *Private;
 | |
|   EFI_STRING_ID                    DeviceFormTitleToken;
 | |
|   HDD_PASSWORD_CONFIG              *IfrData;
 | |
|   HDD_PASSWORD_CONFIG_FORM_ENTRY   *ConfigFormEntry;
 | |
| 
 | |
|   if (ActionRequest != NULL) {
 | |
|     *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
 | |
|   } else {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if ((Action != EFI_BROWSER_ACTION_CHANGING) && (Action != EFI_BROWSER_ACTION_CHANGED)) {
 | |
|     //
 | |
|     // Do nothing for other UEFI Action. Only do call back when data is changing or changed.
 | |
|     //
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   Private = HDD_PASSWORD_DXE_PRIVATE_FROM_THIS (This);
 | |
| 
 | |
|   //
 | |
|   // Retrive data from Browser
 | |
|   //
 | |
|   IfrData = AllocateZeroPool (sizeof (HDD_PASSWORD_CONFIG));
 | |
|   ASSERT (IfrData != NULL);
 | |
|   if (!HiiGetBrowserData (&mHddPasswordVendorGuid, mHddPasswordVendorStorageName, sizeof (HDD_PASSWORD_CONFIG), (UINT8 *) IfrData)) {
 | |
|     FreePool (IfrData);
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   switch (QuestionId) {
 | |
|   case KEY_HDD_USER_PASSWORD:
 | |
|     if (Action == EFI_BROWSER_ACTION_CHANGED) {
 | |
|       DEBUG ((DEBUG_INFO, "KEY_HDD_USER_PASSWORD\n"));
 | |
|       ConfigFormEntry = Private->Current;
 | |
|       ConfigFormEntry->IfrData.Request.UserPassword = Value->b;
 | |
|       SaveHddPasswordRequest (ConfigFormEntry);
 | |
|       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
 | |
|     }
 | |
|     break;
 | |
|   case KEY_HDD_MASTER_PASSWORD:
 | |
|     if (Action == EFI_BROWSER_ACTION_CHANGED) {
 | |
|       DEBUG ((DEBUG_INFO, "KEY_HDD_MASTER_PASSWORD\n"));
 | |
|       ConfigFormEntry = Private->Current;
 | |
|       ConfigFormEntry->IfrData.Request.MasterPassword = Value->b;
 | |
|       SaveHddPasswordRequest (ConfigFormEntry);
 | |
|       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
 | |
|     }
 | |
|     break;
 | |
| 
 | |
|   default:
 | |
|     if ((QuestionId >= KEY_HDD_DEVICE_ENTRY_BASE) && (QuestionId < (mNumberOfHddDevices + KEY_HDD_DEVICE_ENTRY_BASE))) {
 | |
|       if (Action == EFI_BROWSER_ACTION_CHANGING) {
 | |
|         //
 | |
|         // In case goto the device configuration form, update the device form title.
 | |
|         //
 | |
|         ConfigFormEntry = HddPasswordGetConfigFormEntryByIndex ((UINT32) (QuestionId - KEY_HDD_DEVICE_ENTRY_BASE));
 | |
|         ASSERT (ConfigFormEntry != NULL);
 | |
| 
 | |
|         DeviceFormTitleToken = (EFI_STRING_ID) STR_HDD_SECURITY_HD;
 | |
|         HiiSetString (Private->HiiHandle, DeviceFormTitleToken, ConfigFormEntry->HddString, NULL);
 | |
| 
 | |
|         Private->Current = ConfigFormEntry;
 | |
|         CopyMem (IfrData, &ConfigFormEntry->IfrData, sizeof (HDD_PASSWORD_CONFIG));
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     break;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Pass changed uncommitted data back to Form Browser
 | |
|   //
 | |
|   HiiSetBrowserData (&mHddPasswordVendorGuid, mHddPasswordVendorStorageName, sizeof (HDD_PASSWORD_CONFIG), (UINT8 *) IfrData, NULL);
 | |
| 
 | |
|   FreePool (IfrData);
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Updates the HDD Password configuration form to add an entry for the attached
 | |
|   ata harddisk device specified by the Controller.
 | |
| 
 | |
|   @param[in] HiiHandle            The HII Handle associated with the registered package list.
 | |
|   @param[in] AtaPassThru          Pointer to ATA_PASSTHRU instance.
 | |
|   @param[in] PciIo                Pointer to PCI_IO instance.
 | |
|   @param[in] Controller           The controller handle of the attached ata controller.
 | |
|   @param[in] Bus                  The bus number of ATA controller.
 | |
|   @param[in] Device               The device number of ATA controller.
 | |
|   @param[in] Function             The function number of ATA controller.
 | |
|   @param[in] Port                 The port number of attached ATA device.
 | |
|   @param[in] PortMultiplierPort   The port number of port multiplier of attached ATA device.
 | |
| 
 | |
|   @retval EFI_SUCCESS             The Hdd Password configuration form is updated.
 | |
|   @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
 | |
|   @retval Others                  Other errors as indicated.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| HddPasswordConfigUpdateForm (
 | |
|   IN EFI_HII_HANDLE              HiiHandle,
 | |
|   IN EFI_ATA_PASS_THRU_PROTOCOL  *AtaPassThru,
 | |
|   IN EFI_PCI_IO_PROTOCOL         *PciIo,
 | |
|   IN EFI_HANDLE                  Controller,
 | |
|   IN UINTN                       Bus,
 | |
|   IN UINTN                       Device,
 | |
|   IN UINTN                       Function,
 | |
|   IN UINT16                      Port,
 | |
|   IN UINT16                      PortMultiplierPort
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY                       *Entry;
 | |
|   HDD_PASSWORD_CONFIG_FORM_ENTRY   *ConfigFormEntry;
 | |
|   BOOLEAN                          EntryExisted;
 | |
|   EFI_STATUS                       Status;
 | |
|   VOID                             *StartOpCodeHandle;
 | |
|   VOID                             *EndOpCodeHandle;
 | |
|   EFI_IFR_GUID_LABEL               *StartLabel;
 | |
|   EFI_IFR_GUID_LABEL               *EndLabel;
 | |
|   CHAR16                           HddString[40];
 | |
|   ATA_IDENTIFY_DATA                IdentifyData;
 | |
|   EFI_DEVICE_PATH_PROTOCOL         *AtaDeviceNode;
 | |
| 
 | |
|   ConfigFormEntry = NULL;
 | |
|   EntryExisted    = FALSE;
 | |
| 
 | |
|   BASE_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;
 | |
|     BASE_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_SUCCESS     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;
 | |
|   VOID                           *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 variable 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;
 | |
| }
 |