/** @file HDD password driver which is used to support HDD security feature. Copyright (c) 2019, Intel Corporation. All rights reserved.
Copyright (c) Microsoft Corporation.
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 format. Any and all alternative configuration strings shall also be appended to the end of the current configuration string. If they are, they must appear after the current configuration. They must contain the same routing (GUID, NAME, PATH) as the current configuration string. They must have an additional description indicating the type of alternative configuration the string represents, "ALTCFG=". That (when converted from Hex UNICODE to binary) is a reference to a string in the associated string pack. @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. @param[in] Request A null-terminated Unicode string in format. Note that this includes the routing information as well as the configurable name / value pairs. It is invalid for this string to be in format. @param[out] Progress On return, points to a character in the Request string. Points to the string's null terminator if request was successful. Points to the most recent "&" before the first failing name / value pair (or the beginning of the string if the failure is in the first name / value pair) if the request was not successful. @param[out] Results A null-terminated Unicode string in format which has all values filled in for the names in the Request string. String to be allocated by the called function. @retval EFI_SUCCESS The Results string is filled with the values corresponding to all requested names. @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the results that must be stored awaiting possible future protocols. @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Request parameter would result in this type of error. In this case, the Progress parameter would be set to NULL. @retval EFI_NOT_FOUND Routing data doesn't match any known driver. Progress set to the first character in the routing header. Note: There is no requirement that the driver validate the routing data. It must skip the in order to process the names. @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set to most recent & before the error or the beginning of the string. @retval EFI_INVALID_PARAMETER Unknown name. Progress points to the & before the name in question.Currently not implemented. **/ EFI_STATUS EFIAPI HddPasswordFormExtractConfig ( IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, IN CONST EFI_STRING Request, OUT EFI_STRING *Progress, OUT EFI_STRING *Results ) { EFI_STATUS Status; UINTN BufferSize; HDD_PASSWORD_CONFIG *IfrData; HDD_PASSWORD_DXE_PRIVATE_DATA *Private; EFI_STRING ConfigRequestHdr; EFI_STRING ConfigRequest; BOOLEAN AllocatedRequest; UINTN Size; if (Progress == NULL || Results == NULL) { return EFI_INVALID_PARAMETER; } *Progress = Request; if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &mHddPasswordVendorGuid, mHddPasswordVendorStorageName)) { return EFI_NOT_FOUND; } ConfigRequestHdr = NULL; ConfigRequest = NULL; AllocatedRequest = FALSE; Size = 0; Private = HDD_PASSWORD_DXE_PRIVATE_FROM_THIS (This); IfrData = AllocateZeroPool (sizeof (HDD_PASSWORD_CONFIG)); ASSERT (IfrData != NULL); if (Private->Current != NULL) { CopyMem (IfrData, &Private->Current->IfrData, sizeof (HDD_PASSWORD_CONFIG)); } // // Convert buffer data to by helper function BlockToConfig() // BufferSize = sizeof (HDD_PASSWORD_CONFIG); ConfigRequest = Request; if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) { // // Request has no request element, construct full request string. // Allocate and fill a buffer large enough to hold the template // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator // ConfigRequestHdr = HiiConstructConfigHdr (&mHddPasswordVendorGuid, mHddPasswordVendorStorageName, Private->DriverHandle); Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16); ConfigRequest = AllocateZeroPool (Size); ASSERT (ConfigRequest != NULL); AllocatedRequest = TRUE; UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize); FreePool (ConfigRequestHdr); } Status = gHiiConfigRouting->BlockToConfig ( gHiiConfigRouting, ConfigRequest, (UINT8 *) IfrData, BufferSize, Results, Progress ); FreePool (IfrData); // // Free the allocated config request string. // if (AllocatedRequest) { FreePool (ConfigRequest); ConfigRequest = NULL; } // // Set Progress string to the original request string. // if (Request == NULL) { *Progress = NULL; } else if (StrStr (Request, L"OFFSET") == NULL) { *Progress = Request + StrLen (Request); } return Status; } /** This function applies changes in a driver's configuration. Input is a Configuration, which has the routing data for this driver followed by name / value configuration pairs. The driver must apply those pairs to its configurable storage. If the driver's configuration is stored in a linear block of data and the driver's name / value pairs are in format, it may use the ConfigToBlock helper function (above) to simplify the job. Currently not implemented. @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. @param[in] Configuration A null-terminated Unicode string in format. @param[out] Progress A pointer to a string filled in with the offset of the most recent '&' before the first failing name / value pair (or the beginn ing of the string if the failure is in the first name / value pair) or the terminating NULL if all was successful. @retval EFI_SUCCESS The results have been distributed or are awaiting distribution. @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the results that must be stored awaiting possible future protocols. @retval EFI_INVALID_PARAMETERS Passing in a NULL for the Results parameter would result in this type of error. @retval EFI_NOT_FOUND Target for the specified routing data was not found. **/ EFI_STATUS EFIAPI HddPasswordFormRouteConfig ( IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, IN CONST EFI_STRING Configuration, OUT EFI_STRING *Progress ) { if (Configuration == NULL || Progress == NULL) { return EFI_INVALID_PARAMETER; } // // Check routing data in . // Note: if only one Storage is used, then this checking could be skipped. // if (!HiiIsConfigHdrMatch (Configuration, &mHddPasswordVendorGuid, mHddPasswordVendorStorageName)) { *Progress = Configuration; return EFI_NOT_FOUND; } *Progress = Configuration + StrLen (Configuration); return EFI_SUCCESS; } /** This function is called to provide results data to the driver. This data consists of a unique key that is used to identify which data is either being passed back or being asked for. @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. @param[in] Action Specifies the type of action taken by the browser. @param[in] QuestionId A unique value which is sent to the original exporting driver so that it can identify the type of data to expect. The format of the data tends to vary based on the opcode that enerated the callback. @param[in] Type The type of value for the question. @param[in] Value A pointer to the data being sent to the original exporting driver. @param[out] ActionRequest On return, points to the action requested by the callback function. @retval EFI_SUCCESS The callback successfully handled the action. @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data. @retval EFI_DEVICE_ERROR The variable could not be saved. @retval EFI_UNSUPPORTED The specified Action is not supported by the callback.Currently not implemented. @retval EFI_INVALID_PARAMETERS Passing in wrong parameter. @retval Others Other errors as indicated. **/ EFI_STATUS EFIAPI HddPasswordFormCallback ( IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, IN EFI_BROWSER_ACTION Action, IN EFI_QUESTION_ID QuestionId, IN UINT8 Type, IN EFI_IFR_TYPE_VALUE *Value, OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest ) { HDD_PASSWORD_DXE_PRIVATE_DATA *Private; EFI_STRING_ID DeviceFormTitleToken; HDD_PASSWORD_CONFIG *IfrData; HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry; if (ActionRequest != NULL) { *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; } else { return EFI_INVALID_PARAMETER; } if ((Action != EFI_BROWSER_ACTION_CHANGING) && (Action != EFI_BROWSER_ACTION_CHANGED)) { // // Do nothing for other UEFI Action. Only do call back when data is changing or changed. // return EFI_UNSUPPORTED; } Private = HDD_PASSWORD_DXE_PRIVATE_FROM_THIS (This); // // Retrive data from Browser // IfrData = AllocateZeroPool (sizeof (HDD_PASSWORD_CONFIG)); ASSERT (IfrData != NULL); if (!HiiGetBrowserData (&mHddPasswordVendorGuid, mHddPasswordVendorStorageName, sizeof (HDD_PASSWORD_CONFIG), (UINT8 *) IfrData)) { FreePool (IfrData); return EFI_NOT_FOUND; } switch (QuestionId) { case KEY_HDD_USER_PASSWORD: if (Action == EFI_BROWSER_ACTION_CHANGED) { DEBUG ((DEBUG_INFO, "KEY_HDD_USER_PASSWORD\n")); ConfigFormEntry = Private->Current; ConfigFormEntry->IfrData.Request.UserPassword = Value->b; SaveHddPasswordRequest (ConfigFormEntry); *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY; } break; case KEY_HDD_MASTER_PASSWORD: if (Action == EFI_BROWSER_ACTION_CHANGED) { DEBUG ((DEBUG_INFO, "KEY_HDD_MASTER_PASSWORD\n")); ConfigFormEntry = Private->Current; ConfigFormEntry->IfrData.Request.MasterPassword = Value->b; SaveHddPasswordRequest (ConfigFormEntry); *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY; } break; default: if ((QuestionId >= KEY_HDD_DEVICE_ENTRY_BASE) && (QuestionId < (mNumberOfHddDevices + KEY_HDD_DEVICE_ENTRY_BASE))) { if (Action == EFI_BROWSER_ACTION_CHANGING) { // // In case goto the device configuration form, update the device form title. // ConfigFormEntry = HddPasswordGetConfigFormEntryByIndex ((UINT32) (QuestionId - KEY_HDD_DEVICE_ENTRY_BASE)); ASSERT (ConfigFormEntry != NULL); DeviceFormTitleToken = (EFI_STRING_ID) STR_HDD_SECURITY_HD; HiiSetString (Private->HiiHandle, DeviceFormTitleToken, ConfigFormEntry->HddString, NULL); Private->Current = ConfigFormEntry; CopyMem (IfrData, &ConfigFormEntry->IfrData, sizeof (HDD_PASSWORD_CONFIG)); } } break; } // // Pass changed uncommitted data back to Form Browser // HiiSetBrowserData (&mHddPasswordVendorGuid, mHddPasswordVendorStorageName, sizeof (HDD_PASSWORD_CONFIG), (UINT8 *) IfrData, NULL); FreePool (IfrData); return EFI_SUCCESS; } /** Updates the HDD Password configuration form to add an entry for the attached ata harddisk device specified by the Controller. @param[in] HiiHandle The HII Handle associated with the registered package list. @param[in] AtaPassThru Pointer to ATA_PASSTHRU instance. @param[in] PciIo Pointer to PCI_IO instance. @param[in] Controller The controller handle of the attached ata controller. @param[in] Bus The bus number of ATA controller. @param[in] Device The device number of ATA controller. @param[in] Function The function number of ATA controller. @param[in] Port The port number of attached ATA device. @param[in] PortMultiplierPort The port number of port multiplier of attached ATA device. @retval EFI_SUCCESS The Hdd Password configuration form is updated. @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. @retval Others Other errors as indicated. **/ EFI_STATUS HddPasswordConfigUpdateForm ( IN EFI_HII_HANDLE HiiHandle, IN EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru, IN EFI_PCI_IO_PROTOCOL *PciIo, IN EFI_HANDLE Controller, IN UINTN Bus, IN UINTN Device, IN UINTN Function, IN UINT16 Port, IN UINT16 PortMultiplierPort ) { LIST_ENTRY *Entry; HDD_PASSWORD_CONFIG_FORM_ENTRY *ConfigFormEntry; BOOLEAN EntryExisted; EFI_STATUS Status; VOID *StartOpCodeHandle; VOID *EndOpCodeHandle; EFI_IFR_GUID_LABEL *StartLabel; EFI_IFR_GUID_LABEL *EndLabel; CHAR16 HddString[40]; ATA_IDENTIFY_DATA IdentifyData; EFI_DEVICE_PATH_PROTOCOL *AtaDeviceNode; ConfigFormEntry = NULL; EntryExisted = FALSE; 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; }