diff options
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.c')
-rw-r--r-- | src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.c | 2966 |
1 files changed, 2966 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.c new file mode 100644 index 00000000..e4987ba2 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.c @@ -0,0 +1,2966 @@ +/** @file + Entrypoint of Opal UEFI Driver and contains all the logic to + register for new Opal device instances. + +Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +// This UEFI driver consumes EFI_STORAGE_SECURITY_PROTOCOL instances and installs an +// HII GUI to manage Opal features if the device is Opal capable +// If the Opal device is being managed by the UEFI Driver, it shall provide a popup +// window during boot requesting a user password + +#include "OpalDriver.h" +#include "OpalHii.h" + +EFI_GUID mOpalDeviceLockBoxGuid = OPAL_DEVICE_LOCKBOX_GUID; + +BOOLEAN mOpalEndOfDxe = FALSE; +OPAL_REQUEST_VARIABLE *mOpalRequestVariable = NULL; +UINTN mOpalRequestVariableSize = 0; +CHAR16 mPopUpString[100]; + +OPAL_DRIVER mOpalDriver; + +// +// Globals +// +EFI_DRIVER_BINDING_PROTOCOL gOpalDriverBinding = { + OpalEfiDriverBindingSupported, + OpalEfiDriverBindingStart, + OpalEfiDriverBindingStop, + 0x1b, + NULL, + NULL +}; + +/** + + The function determines the available actions for the OPAL_DISK provided. + + @param[in] SupportedAttributes The supported attributes for the device. + @param[in] LockingFeature The locking status for the device. + @param[in] OwnerShip The ownership for the device. + @param[out] AvalDiskActions Pointer to fill-out with appropriate disk actions. + +**/ +TCG_RESULT +EFIAPI +OpalSupportGetAvailableActions( + IN OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes, + IN TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature, + IN UINT16 OwnerShip, + OUT OPAL_DISK_ACTIONS *AvalDiskActions + ) +{ + BOOLEAN ExistingPassword; + + NULL_CHECK(AvalDiskActions); + + AvalDiskActions->AdminPass = 1; + AvalDiskActions->UserPass = 0; + AvalDiskActions->DisableUser = 0; + AvalDiskActions->Unlock = 0; + + // + // Revert is performed on locking sp, so only allow if locking sp is enabled + // + if (LockingFeature->LockingEnabled) { + AvalDiskActions->Revert = 1; + } + + // + // Psid revert is available for any device with media encryption support or pyrite 2.0 type support. + // + if (SupportedAttributes->PyriteSscV2 || SupportedAttributes->MediaEncryption) { + + // + // Only allow psid revert if media encryption is enabled or pyrite 2.0 type support.. + // Otherwise, someone who steals a disk can psid revert the disk and the user Data is still + // intact and accessible + // + AvalDiskActions->PsidRevert = 1; + AvalDiskActions->RevertKeepDataForced = 0; + + // + // Secure erase is performed by generating a new encryption key + // this is only available if encryption is supported + // + AvalDiskActions->SecureErase = 1; + } else { + AvalDiskActions->PsidRevert = 0; + AvalDiskActions->SecureErase = 0; + + // + // If no media encryption is supported, then a revert (using password) will not + // erase the Data (since you can't generate a new encryption key) + // + AvalDiskActions->RevertKeepDataForced = 1; + } + + if (LockingFeature->Locked) { + AvalDiskActions->Unlock = 1; + } else { + AvalDiskActions->Unlock = 0; + } + + // + // Only allow user to set password if an admin password exists + // + ExistingPassword = OpalUtilAdminPasswordExists(OwnerShip, LockingFeature); + AvalDiskActions->UserPass = ExistingPassword; + + // + // This will still show up even if there isn't a user, which is fine + // + AvalDiskActions->DisableUser = ExistingPassword; + + return TcgResultSuccess; +} + +/** + Enable Opal Feature for the input device. + + @param[in] Session The opal session for the opal device. + @param[in] Msid Msid + @param[in] MsidLength Msid Length + @param[in] Password Admin password + @param[in] PassLength Length of password in bytes + +**/ +TCG_RESULT +EFIAPI +OpalSupportEnableOpalFeature ( + IN OPAL_SESSION *Session, + IN VOID *Msid, + IN UINT32 MsidLength, + IN VOID *Password, + IN UINT32 PassLength + ) +{ + TCG_RESULT Ret; + + NULL_CHECK(Session); + NULL_CHECK(Msid); + NULL_CHECK(Password); + + Ret = OpalUtilSetAdminPasswordAsSid( + Session, + Msid, + MsidLength, + Password, + PassLength + ); + if (Ret == TcgResultSuccess) { + // + // Enable global locking range + // + Ret = OpalUtilSetOpalLockingRange( + Session, + Password, + PassLength, + OPAL_LOCKING_SP_LOCKING_GLOBALRANGE, + 0, + 0, + TRUE, + TRUE, + FALSE, + FALSE + ); + } + + return Ret; +} + +/** + Update password for the Opal disk. + + @param[in, out] OpalDisk The disk to update password. + @param[in] Password The input password. + @param[in] PasswordLength The input password length. + +**/ +VOID +OpalSupportUpdatePassword ( + IN OUT OPAL_DISK *OpalDisk, + IN VOID *Password, + IN UINT32 PasswordLength + ) +{ + CopyMem (OpalDisk->Password, Password, PasswordLength); + OpalDisk->PasswordLength = (UINT8) PasswordLength; +} + +/** + Extract device info from the device path. + + @param[in] DevicePath Device path info for the device. + @param[out] DevInfoLength Device information length needed. + @param[out] DevInfo Device information extracted. + +**/ +VOID +ExtractDeviceInfoFromDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT UINT32 *DevInfoLength, + OUT OPAL_DEVICE_LOCKBOX_DATA *DevInfo OPTIONAL + ) +{ + EFI_DEVICE_PATH_PROTOCOL *TmpDevPath; + EFI_DEVICE_PATH_PROTOCOL *TmpDevPath2; + PCI_DEVICE_PATH *PciDevPath; + UINT8 DeviceType; + UINT8 BusNum; + OPAL_PCI_DEVICE *PciDevice; + + ASSERT (DevicePath != NULL); + ASSERT (DevInfoLength != NULL); + + DeviceType = OPAL_DEVICE_TYPE_UNKNOWN; + *DevInfoLength = 0; + + TmpDevPath = DevicePath; + + // + // Get device type. + // + while (!IsDevicePathEnd (TmpDevPath)) { + if ((TmpDevPath->Type == MESSAGING_DEVICE_PATH) && + (TmpDevPath->SubType == MSG_SATA_DP || TmpDevPath->SubType == MSG_NVME_NAMESPACE_DP)) { + if (DevInfo != NULL) { + DevInfo->DevicePathLength = (UINT32) GetDevicePathSize (DevicePath); + CopyMem (DevInfo->DevicePath, DevicePath, DevInfo->DevicePathLength); + } + + DeviceType = (TmpDevPath->SubType == MSG_SATA_DP) ? OPAL_DEVICE_TYPE_ATA : OPAL_DEVICE_TYPE_NVME; + *DevInfoLength = sizeof (OPAL_DEVICE_LOCKBOX_DATA) + (UINT32) GetDevicePathSize (DevicePath); + break; + } + TmpDevPath = NextDevicePathNode (TmpDevPath); + } + + // + // Get device info. + // + BusNum = 0; + TmpDevPath = DevicePath; + TmpDevPath2 = NextDevicePathNode (DevicePath); + while (!IsDevicePathEnd (TmpDevPath2)) { + if (TmpDevPath->Type == HARDWARE_DEVICE_PATH && TmpDevPath->SubType == HW_PCI_DP) { + PciDevPath = (PCI_DEVICE_PATH *) TmpDevPath; + if ((TmpDevPath2->Type == MESSAGING_DEVICE_PATH) && + (TmpDevPath2->SubType == MSG_SATA_DP || TmpDevPath2->SubType == MSG_NVME_NAMESPACE_DP)) { + if (DevInfo != NULL) { + PciDevice = &DevInfo->Device; + PciDevice->Segment = 0; + PciDevice->Bus = BusNum; + PciDevice->Device = PciDevPath->Device; + PciDevice->Function = PciDevPath->Function; + } + } else { + if (TmpDevPath2->Type == HARDWARE_DEVICE_PATH && TmpDevPath2->SubType == HW_PCI_DP) { + BusNum = PciRead8 (PCI_LIB_ADDRESS (BusNum, PciDevPath->Device, PciDevPath->Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET)); + } + } + } + + TmpDevPath = NextDevicePathNode (TmpDevPath); + TmpDevPath2 = NextDevicePathNode (TmpDevPath2); + } + + ASSERT (DeviceType != OPAL_DEVICE_TYPE_UNKNOWN); + return; +} + +/** + Build OPAL device info and save them to LockBox. + + **/ +VOID +BuildOpalDeviceInfo ( + VOID + ) +{ + EFI_STATUS Status; + OPAL_DEVICE_LOCKBOX_DATA *DevInfo; + OPAL_DEVICE_LOCKBOX_DATA *TempDevInfo; + UINTN TotalDevInfoLength; + UINT32 DevInfoLength; + OPAL_DRIVER_DEVICE *TmpDev; + UINT8 DummyData; + BOOLEAN S3InitDevicesExist; + UINTN S3InitDevicesLength; + EFI_DEVICE_PATH_PROTOCOL *S3InitDevices; + EFI_DEVICE_PATH_PROTOCOL *S3InitDevicesBak; + + // + // Build OPAL device info and save them to LockBox. + // + TotalDevInfoLength = 0; + TmpDev = mOpalDriver.DeviceList; + while (TmpDev != NULL) { + ExtractDeviceInfoFromDevicePath ( + TmpDev->OpalDisk.OpalDevicePath, + &DevInfoLength, + NULL + ); + TotalDevInfoLength += DevInfoLength; + TmpDev = TmpDev->Next; + } + + if (TotalDevInfoLength == 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); + if (S3InitDevices == NULL) { + return; + } + + Status = RestoreLockBox ( + &gS3StorageDeviceInitListGuid, + S3InitDevices, + &S3InitDevicesLength + ); + ASSERT_EFI_ERROR (Status); + S3InitDevicesExist = TRUE; + } else { + return; + } + + DevInfo = AllocateZeroPool (TotalDevInfoLength); + ASSERT (DevInfo != NULL); + if (DevInfo == NULL) { + return; + } + + TempDevInfo = DevInfo; + TmpDev = mOpalDriver.DeviceList; + while (TmpDev != NULL) { + ExtractDeviceInfoFromDevicePath ( + TmpDev->OpalDisk.OpalDevicePath, + &DevInfoLength, + TempDevInfo + ); + TempDevInfo->Length = DevInfoLength; + TempDevInfo->OpalBaseComId = TmpDev->OpalDisk.OpalBaseComId; + CopyMem ( + TempDevInfo->Password, + TmpDev->OpalDisk.Password, + TmpDev->OpalDisk.PasswordLength + ); + TempDevInfo->PasswordLength = TmpDev->OpalDisk.PasswordLength; + + S3InitDevicesBak = S3InitDevices; + S3InitDevices = AppendDevicePathInstance ( + S3InitDevicesBak, + TmpDev->OpalDisk.OpalDevicePath + ); + if (S3InitDevicesBak != NULL) { + FreePool (S3InitDevicesBak); + } + ASSERT (S3InitDevices != NULL); + if (S3InitDevices == NULL) { + return; + } + + TempDevInfo = (OPAL_DEVICE_LOCKBOX_DATA *) ((UINTN) TempDevInfo + DevInfoLength); + TmpDev = TmpDev->Next; + } + + Status = SaveLockBox ( + &mOpalDeviceLockBoxGuid, + DevInfo, + TotalDevInfoLength + ); + ASSERT_EFI_ERROR (Status); + + Status = SetLockBoxAttributes ( + &mOpalDeviceLockBoxGuid, + 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, TotalDevInfoLength); + FreePool (DevInfo); + FreePool (S3InitDevices); +} + +/** + + Send BlockSid command if needed. + +**/ +VOID +SendBlockSidCommand ( + VOID + ) +{ + OPAL_DRIVER_DEVICE *Itr; + TCG_RESULT Result; + OPAL_SESSION Session; + UINT32 PpStorageFlag; + + PpStorageFlag = Tcg2PhysicalPresenceLibGetManagementFlags (); + if ((PpStorageFlag & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_ENABLE_BLOCK_SID) != 0) { + // + // Send BlockSID command to each Opal disk + // + Itr = mOpalDriver.DeviceList; + while (Itr != NULL) { + if (Itr->OpalDisk.SupportedAttributes.BlockSid) { + ZeroMem(&Session, sizeof(Session)); + Session.Sscp = Itr->OpalDisk.Sscp; + Session.MediaId = Itr->OpalDisk.MediaId; + Session.OpalBaseComId = Itr->OpalDisk.OpalBaseComId; + + DEBUG ((DEBUG_INFO, "OpalPassword: EndOfDxe point, send BlockSid command to device!\n")); + Result = OpalBlockSid (&Session, TRUE); // HardwareReset must always be TRUE + if (Result != TcgResultSuccess) { + DEBUG ((DEBUG_ERROR, "OpalBlockSid fail\n")); + break; + } + + // + // Record BlockSID command has been sent. + // + Itr->OpalDisk.SentBlockSID = TRUE; + } + + Itr = Itr->Next; + } + } +} + +/** + 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 +OpalEndOfDxeEventNotify ( + EFI_EVENT Event, + VOID *Context + ) +{ + OPAL_DRIVER_DEVICE *TmpDev; + + DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__)); + + mOpalEndOfDxe = TRUE; + + if (mOpalRequestVariable != NULL) { + // + // Free the OPAL request variable buffer here + // as the OPAL requests should have been processed. + // + FreePool (mOpalRequestVariable); + mOpalRequestVariable = NULL; + mOpalRequestVariableSize = 0; + } + + // + // If no any device, return directly. + // + if (mOpalDriver.DeviceList == NULL) { + gBS->CloseEvent (Event); + return; + } + + BuildOpalDeviceInfo (); + + // + // Zero passsword. + // + TmpDev = mOpalDriver.DeviceList; + while (TmpDev != NULL) { + ZeroMem (TmpDev->OpalDisk.Password, TmpDev->OpalDisk.PasswordLength); + TmpDev = TmpDev->Next; + } + + // + // Send BlockSid command if needed. + // + SendBlockSidCommand (); + + DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__)); + + gBS->CloseEvent (Event); +} + +/** + Get Psid input from the popup window. + + @param[in] Dev The device which need Psid to process Psid Revert + OPAL request. + @param[in] PopUpString Pop up string. + @param[in] PopUpString2 Pop up string in line 2. + @param[in] PopUpString3 Pop up string in line 3. + + @param[out] PressEsc Whether user escape function through Press ESC. + + @retval Psid string if success. NULL if failed. + +**/ +CHAR8 * +OpalDriverPopUpPsidInput ( + IN OPAL_DRIVER_DEVICE *Dev, + IN CHAR16 *PopUpString, + IN CHAR16 *PopUpString2, + IN CHAR16 *PopUpString3, + OUT BOOLEAN *PressEsc + ) +{ + EFI_INPUT_KEY InputKey; + UINTN InputLength; + CHAR16 Mask[PSID_CHARACTER_LENGTH + 1]; + CHAR16 Unicode[PSID_CHARACTER_LENGTH + 1]; + CHAR8 *Ascii; + + ZeroMem(Unicode, sizeof(Unicode)); + ZeroMem(Mask, sizeof(Mask)); + + *PressEsc = FALSE; + + gST->ConOut->ClearScreen(gST->ConOut); + + InputLength = 0; + while (TRUE) { + Mask[InputLength] = L'_'; + if (PopUpString2 == NULL) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &InputKey, + PopUpString, + L"---------------------", + Mask, + NULL + ); + } else { + if (PopUpString3 == NULL) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &InputKey, + PopUpString, + PopUpString2, + L"---------------------", + Mask, + NULL + ); + } else { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &InputKey, + PopUpString, + PopUpString2, + PopUpString3, + L"---------------------", + Mask, + NULL + ); + } + } + + // + // Check key. + // + if (InputKey.ScanCode == SCAN_NULL) { + // + // password finished + // + if (InputKey.UnicodeChar == CHAR_CARRIAGE_RETURN) { + // + // Add the null terminator. + // + Unicode[InputLength] = 0; + Mask[InputLength] = 0; + break; + } else if ((InputKey.UnicodeChar == CHAR_NULL) || + (InputKey.UnicodeChar == CHAR_TAB) || + (InputKey.UnicodeChar == CHAR_LINEFEED) + ) { + continue; + } else { + // + // delete last key entered + // + if (InputKey.UnicodeChar == CHAR_BACKSPACE) { + if (InputLength > 0) { + Unicode[InputLength] = 0; + Mask[InputLength] = 0; + InputLength--; + } + } else { + // + // add Next key entry + // + Unicode[InputLength] = InputKey.UnicodeChar; + Mask[InputLength] = InputKey.UnicodeChar; + InputLength++; + if (InputLength == PSID_CHARACTER_LENGTH) { + // + // Add the null terminator. + // + Unicode[InputLength] = 0; + Mask[InputLength] = 0; + break; + } + } + } + } + + // + // exit on ESC + // + if (InputKey.ScanCode == SCAN_ESC) { + *PressEsc = TRUE; + break; + } + } + + gST->ConOut->ClearScreen(gST->ConOut); + + if (InputLength == 0 || InputKey.ScanCode == SCAN_ESC) { + ZeroMem (Unicode, sizeof (Unicode)); + ZeroMem (Mask, sizeof (Mask)); + return NULL; + } + + Ascii = AllocateZeroPool (PSID_CHARACTER_LENGTH + 1); + if (Ascii == NULL) { + ZeroMem (Unicode, sizeof (Unicode)); + ZeroMem (Mask, sizeof (Mask)); + return NULL; + } + + UnicodeStrToAsciiStrS (Unicode, Ascii, PSID_CHARACTER_LENGTH + 1); + ZeroMem (Unicode, sizeof (Unicode)); + ZeroMem (Mask, sizeof (Mask)); + + return Ascii; +} + + +/** + Get password input from the popup window. + + @param[in] Dev The device which need password to unlock or + process OPAL request. + @param[in] PopUpString1 Pop up string 1. + @param[in] PopUpString2 Pop up string 2. + @param[in] PopUpString3 Pop up string 3. + @param[out] PressEsc Whether user escape function through Press ESC. + + @retval Password string if success. NULL if failed. + +**/ +CHAR8 * +OpalDriverPopUpPasswordInput ( + IN OPAL_DRIVER_DEVICE *Dev, + IN CHAR16 *PopUpString1, + IN CHAR16 *PopUpString2, + IN CHAR16 *PopUpString3, + OUT BOOLEAN *PressEsc + ) +{ + EFI_INPUT_KEY InputKey; + UINTN InputLength; + CHAR16 Mask[OPAL_MAX_PASSWORD_SIZE + 1]; + CHAR16 Unicode[OPAL_MAX_PASSWORD_SIZE + 1]; + CHAR8 *Ascii; + + ZeroMem(Unicode, sizeof(Unicode)); + ZeroMem(Mask, sizeof(Mask)); + + *PressEsc = FALSE; + + gST->ConOut->ClearScreen(gST->ConOut); + + InputLength = 0; + while (TRUE) { + Mask[InputLength] = L'_'; + if (PopUpString2 == NULL) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &InputKey, + PopUpString1, + L"---------------------", + Mask, + NULL + ); + } else { + if (PopUpString3 == NULL) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &InputKey, + PopUpString1, + PopUpString2, + L"---------------------", + Mask, + NULL + ); + } else { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &InputKey, + PopUpString1, + PopUpString2, + PopUpString3, + L"---------------------", + Mask, + NULL + ); + } + } + + // + // Check key. + // + if (InputKey.ScanCode == SCAN_NULL) { + // + // password finished + // + if (InputKey.UnicodeChar == CHAR_CARRIAGE_RETURN) { + // + // Add the null terminator. + // + Unicode[InputLength] = 0; + Mask[InputLength] = 0; + break; + } else if ((InputKey.UnicodeChar == CHAR_NULL) || + (InputKey.UnicodeChar == CHAR_TAB) || + (InputKey.UnicodeChar == CHAR_LINEFEED) + ) { + continue; + } else { + // + // delete last key entered + // + if (InputKey.UnicodeChar == CHAR_BACKSPACE) { + if (InputLength > 0) { + Unicode[InputLength] = 0; + Mask[InputLength] = 0; + InputLength--; + } + } else { + // + // add Next key entry + // + Unicode[InputLength] = InputKey.UnicodeChar; + Mask[InputLength] = L'*'; + InputLength++; + if (InputLength == OPAL_MAX_PASSWORD_SIZE) { + // + // Add the null terminator. + // + Unicode[InputLength] = 0; + Mask[InputLength] = 0; + break; + } + } + } + } + + // + // exit on ESC + // + if (InputKey.ScanCode == SCAN_ESC) { + *PressEsc = TRUE; + break; + } + } + + gST->ConOut->ClearScreen(gST->ConOut); + + if (InputLength == 0 || InputKey.ScanCode == SCAN_ESC) { + ZeroMem (Unicode, sizeof (Unicode)); + return NULL; + } + + Ascii = AllocateZeroPool (OPAL_MAX_PASSWORD_SIZE + 1); + if (Ascii == NULL) { + ZeroMem (Unicode, sizeof (Unicode)); + return NULL; + } + + UnicodeStrToAsciiStrS (Unicode, Ascii, OPAL_MAX_PASSWORD_SIZE + 1); + ZeroMem (Unicode, sizeof (Unicode)); + + return Ascii; +} + +/** + Get pop up string. + + @param[in] Dev The OPAL device. + @param[in] RequestString Request string. + + @return Pop up string. + +**/ +CHAR16 * +OpalGetPopUpString ( + IN OPAL_DRIVER_DEVICE *Dev, + IN CHAR16 *RequestString + ) +{ + if (Dev->Name16 == NULL) { + UnicodeSPrint (mPopUpString, sizeof (mPopUpString), L"%s Disk", RequestString); + } else { + UnicodeSPrint (mPopUpString, sizeof (mPopUpString), L"%s %s", RequestString, Dev->Name16); + } + + return mPopUpString; +} + +/** + Check if disk is locked, show popup window and ask for password if it is. + + @param[in] Dev The device which need to be unlocked. + @param[in] RequestString Request string. + +**/ +VOID +OpalDriverRequestPassword ( + IN OPAL_DRIVER_DEVICE *Dev, + IN CHAR16 *RequestString + ) +{ + UINT8 Count; + BOOLEAN IsEnabled; + BOOLEAN IsLocked; + CHAR8 *Password; + UINT32 PasswordLen; + OPAL_SESSION Session; + BOOLEAN PressEsc; + EFI_INPUT_KEY Key; + TCG_RESULT Ret; + CHAR16 *PopUpString; + + if (Dev == NULL) { + return; + } + + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__)); + + PopUpString = OpalGetPopUpString (Dev, RequestString); + + Count = 0; + + IsEnabled = OpalFeatureEnabled (&Dev->OpalDisk.SupportedAttributes, &Dev->OpalDisk.LockingFeature); + if (IsEnabled) { + ZeroMem(&Session, sizeof(Session)); + Session.Sscp = Dev->OpalDisk.Sscp; + Session.MediaId = Dev->OpalDisk.MediaId; + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId; + + IsLocked = OpalDeviceLocked (&Dev->OpalDisk.SupportedAttributes, &Dev->OpalDisk.LockingFeature); + + // + // Add PcdSkipOpalPasswordPrompt 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 to support security requirement. + // + if (PcdGetBool (PcdSkipOpalPasswordPrompt)) { + if (IsLocked) { + return; + } else { + gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL); + } + } + + while (Count < MAX_PASSWORD_TRY_COUNT) { + Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, NULL, NULL, &PressEsc); + if (PressEsc) { + if (IsLocked) { + // + // 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; + } + } + } + + if (Password == NULL) { + Count ++; + continue; + } + PasswordLen = (UINT32) AsciiStrLen(Password); + + if (IsLocked) { + Ret = OpalUtilUpdateGlobalLockingRange(&Session, Password, PasswordLen, FALSE, FALSE); + } else { + Ret = OpalUtilUpdateGlobalLockingRange(&Session, Password, PasswordLen, TRUE, TRUE); + if (Ret == TcgResultSuccess) { + Ret = OpalUtilUpdateGlobalLockingRange(&Session, Password, PasswordLen, FALSE, FALSE); + } + } + + if (Ret == TcgResultSuccess) { + OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen); + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString)); + } else { + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString)); + } + + if (Password != NULL) { + ZeroMem (Password, PasswordLen); + FreePool (Password); + } + + if (Ret == TcgResultSuccess) { + break; + } + + // + // Check whether opal device's Tries value has reach the TryLimit value, if yes, force a shutdown + // before accept new password. + // + if (Ret == TcgResultFailureInvalidType) { + Count = MAX_PASSWORD_TRY_COUNT; + break; + } + + Count++; + + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid password.", + L"Press ENTER to retry", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + } + + if (Count >= MAX_PASSWORD_TRY_COUNT) { + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Opal password retry count exceeds the limit. Must shutdown!", + L"Press ENTER to shutdown", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + + gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL); + } + } +} + +/** + Process Enable Feature OPAL request. + + @param[in] Dev The device which has Enable Feature OPAL request. + @param[in] RequestString Request string. + +**/ +VOID +ProcessOpalRequestEnableFeature ( + IN OPAL_DRIVER_DEVICE *Dev, + IN CHAR16 *RequestString + ) +{ + UINT8 Count; + CHAR8 *Password; + UINT32 PasswordLen; + CHAR8 *PasswordConfirm; + UINT32 PasswordLenConfirm; + OPAL_SESSION Session; + BOOLEAN PressEsc; + EFI_INPUT_KEY Key; + TCG_RESULT Ret; + CHAR16 *PopUpString; + + if (Dev == NULL) { + return; + } + + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__)); + + PopUpString = OpalGetPopUpString (Dev, RequestString); + + Count = 0; + + ZeroMem(&Session, sizeof(Session)); + Session.Sscp = Dev->OpalDisk.Sscp; + Session.MediaId = Dev->OpalDisk.MediaId; + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId; + + while (Count < MAX_PASSWORD_TRY_COUNT) { + Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please type in your new password", NULL, &PressEsc); + if (PressEsc) { + 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; + } + } + + if (Password == NULL) { + Count ++; + continue; + } + PasswordLen = (UINT32) AsciiStrLen(Password); + + PasswordConfirm = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please confirm your new password", NULL, &PressEsc); + if (PasswordConfirm == NULL) { + ZeroMem (Password, PasswordLen); + FreePool (Password); + Count ++; + continue; + } + PasswordLenConfirm = (UINT32) AsciiStrLen(PasswordConfirm); + if ((PasswordLen != PasswordLenConfirm) || + (CompareMem (Password, PasswordConfirm, PasswordLen) != 0)) { + ZeroMem (Password, PasswordLen); + FreePool (Password); + ZeroMem (PasswordConfirm, PasswordLenConfirm); + FreePool (PasswordConfirm); + 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); + Count ++; + continue; + } + + if (PasswordConfirm != NULL) { + ZeroMem (PasswordConfirm, PasswordLenConfirm); + FreePool (PasswordConfirm); + } + + Ret = OpalSupportEnableOpalFeature (&Session, Dev->OpalDisk.Msid, Dev->OpalDisk.MsidLength, Password, PasswordLen); + if (Ret == TcgResultSuccess) { + OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen); + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString)); + } else { + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString)); + } + + if (Password != NULL) { + ZeroMem (Password, PasswordLen); + FreePool (Password); + } + + if (Ret == TcgResultSuccess) { + break; + } + + Count++; + + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Request failed.", + L"Press ENTER to retry", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + } + + if (Count >= MAX_PASSWORD_TRY_COUNT) { + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Opal password retry count exceeds the limit.", + L"Press ENTER to skip the request and continue boot", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + gST->ConOut->ClearScreen(gST->ConOut); + } +} + +/** + Process Disable User OPAL request. + + @param[in] Dev The device which has Disable User OPAL request. + @param[in] RequestString Request string. + +**/ +VOID +ProcessOpalRequestDisableUser ( + IN OPAL_DRIVER_DEVICE *Dev, + IN CHAR16 *RequestString + ) +{ + UINT8 Count; + CHAR8 *Password; + UINT32 PasswordLen; + OPAL_SESSION Session; + BOOLEAN PressEsc; + EFI_INPUT_KEY Key; + TCG_RESULT Ret; + BOOLEAN PasswordFailed; + CHAR16 *PopUpString; + + if (Dev == NULL) { + return; + } + + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__)); + + PopUpString = OpalGetPopUpString (Dev, RequestString); + + Count = 0; + + ZeroMem(&Session, sizeof(Session)); + Session.Sscp = Dev->OpalDisk.Sscp; + Session.MediaId = Dev->OpalDisk.MediaId; + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId; + + while (Count < MAX_PASSWORD_TRY_COUNT) { + Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, NULL, NULL, &PressEsc); + if (PressEsc) { + 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; + } + } + + if (Password == NULL) { + Count ++; + continue; + } + PasswordLen = (UINT32) AsciiStrLen(Password); + + Ret = OpalUtilDisableUser(&Session, Password, PasswordLen, &PasswordFailed); + if (Ret == TcgResultSuccess) { + OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen); + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString)); + } else { + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString)); + } + + if (Password != NULL) { + ZeroMem (Password, PasswordLen); + FreePool (Password); + } + + if (Ret == TcgResultSuccess) { + break; + } + + Count++; + + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid password, request failed.", + L"Press ENTER to retry", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + } + + if (Count >= MAX_PASSWORD_TRY_COUNT) { + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Opal password retry count exceeds the limit.", + L"Press ENTER to skip the request and continue boot", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + gST->ConOut->ClearScreen(gST->ConOut); + } +} + +/** + Process Psid Revert OPAL request. + + @param[in] Dev The device which has Psid Revert OPAL request. + @param[in] RequestString Request string. + +**/ +VOID +ProcessOpalRequestPsidRevert ( + IN OPAL_DRIVER_DEVICE *Dev, + IN CHAR16 *RequestString + ) +{ + UINT8 Count; + CHAR8 *Psid; + UINT32 PsidLen; + OPAL_SESSION Session; + BOOLEAN PressEsc; + EFI_INPUT_KEY Key; + TCG_RESULT Ret; + CHAR16 *PopUpString; + CHAR16 *PopUpString2; + CHAR16 *PopUpString3; + UINTN BufferSize; + + if (Dev == NULL) { + return; + } + + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__)); + + PopUpString = OpalGetPopUpString (Dev, RequestString); + + if (Dev->OpalDisk.EstimateTimeCost > MAX_ACCEPTABLE_REVERTING_TIME) { + BufferSize = StrSize (L"Warning: Revert action will take about ####### seconds"); + PopUpString2 = AllocateZeroPool (BufferSize); + ASSERT (PopUpString2 != NULL); + UnicodeSPrint ( + PopUpString2, + BufferSize, + L"WARNING: Revert action will take about %d seconds", + Dev->OpalDisk.EstimateTimeCost + ); + PopUpString3 = L"DO NOT power off system during the revert action!"; + } else { + PopUpString2 = NULL; + PopUpString3 = NULL; + } + + Count = 0; + + ZeroMem(&Session, sizeof(Session)); + Session.Sscp = Dev->OpalDisk.Sscp; + Session.MediaId = Dev->OpalDisk.MediaId; + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId; + + while (Count < MAX_PSID_TRY_COUNT) { + Psid = OpalDriverPopUpPsidInput (Dev, PopUpString, PopUpString2, PopUpString3, &PressEsc); + if (PressEsc) { + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Press ENTER to skip the request and continue boot,", + L"Press ESC to input Psid again", + NULL + ); + } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN)); + + if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) { + gST->ConOut->ClearScreen(gST->ConOut); + goto Done; + } else { + // + // Let user input Psid again. + // + continue; + } + } + + if (Psid == NULL) { + Count ++; + continue; + } + PsidLen = (UINT32) AsciiStrLen(Psid); + + Ret = OpalUtilPsidRevert(&Session, Psid, PsidLen); + if (Ret == TcgResultSuccess) { + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString)); + } else { + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString)); + } + + if (Psid != NULL) { + ZeroMem (Psid, PsidLen); + FreePool (Psid); + } + + if (Ret == TcgResultSuccess) { + break; + } + + Count++; + + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid Psid, request failed.", + L"Press ENTER to retry", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + } + + if (Count >= MAX_PSID_TRY_COUNT) { + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Opal Psid retry count exceeds the limit.", + L"Press ENTER to skip the request and continue boot", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + gST->ConOut->ClearScreen(gST->ConOut); + } + +Done: + if (PopUpString2 != NULL) { + FreePool (PopUpString2); + } +} + +/** + Process Admin Revert OPAL request. + + @param[in] Dev The device which has Revert OPAL request. + @param[in] KeepUserData Whether to keep user data or not. + @param[in] RequestString Request string. + +**/ +VOID +ProcessOpalRequestRevert ( + IN OPAL_DRIVER_DEVICE *Dev, + IN BOOLEAN KeepUserData, + IN CHAR16 *RequestString + ) +{ + UINT8 Count; + CHAR8 *Password; + UINT32 PasswordLen; + OPAL_SESSION Session; + BOOLEAN PressEsc; + EFI_INPUT_KEY Key; + TCG_RESULT Ret; + BOOLEAN PasswordFailed; + CHAR16 *PopUpString; + CHAR16 *PopUpString2; + CHAR16 *PopUpString3; + UINTN BufferSize; + + if (Dev == NULL) { + return; + } + + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__)); + + PopUpString = OpalGetPopUpString (Dev, RequestString); + + if ((!KeepUserData) && + (Dev->OpalDisk.EstimateTimeCost > MAX_ACCEPTABLE_REVERTING_TIME)) { + BufferSize = StrSize (L"Warning: Revert action will take about ####### seconds"); + PopUpString2 = AllocateZeroPool (BufferSize); + ASSERT (PopUpString2 != NULL); + UnicodeSPrint ( + PopUpString2, + BufferSize, + L"WARNING: Revert action will take about %d seconds", + Dev->OpalDisk.EstimateTimeCost + ); + PopUpString3 = L"DO NOT power off system during the revert action!"; + } else { + PopUpString2 = NULL; + PopUpString3 = NULL; + } + + Count = 0; + + ZeroMem(&Session, sizeof(Session)); + Session.Sscp = Dev->OpalDisk.Sscp; + Session.MediaId = Dev->OpalDisk.MediaId; + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId; + + while (Count < MAX_PASSWORD_TRY_COUNT) { + Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, PopUpString2, PopUpString3, &PressEsc); + if (PressEsc) { + 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); + goto Done; + } else { + // + // Let user input password again. + // + continue; + } + } + + if (Password == NULL) { + Count ++; + continue; + } + PasswordLen = (UINT32) AsciiStrLen(Password); + + if ((Dev->OpalDisk.SupportedAttributes.PyriteSsc == 1) && + (Dev->OpalDisk.LockingFeature.MediaEncryption == 0)) { + // + // For pyrite type device which does not support media encryption, + // it does not accept "Keep User Data" parameter. + // So here hardcode a FALSE for this case. + // + Ret = OpalUtilRevert( + &Session, + FALSE, + Password, + PasswordLen, + &PasswordFailed, + Dev->OpalDisk.Msid, + Dev->OpalDisk.MsidLength + ); + } else { + Ret = OpalUtilRevert( + &Session, + KeepUserData, + Password, + PasswordLen, + &PasswordFailed, + Dev->OpalDisk.Msid, + Dev->OpalDisk.MsidLength + ); + } + if (Ret == TcgResultSuccess) { + OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen); + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString)); + } else { + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString)); + } + + if (Password != NULL) { + ZeroMem (Password, PasswordLen); + FreePool (Password); + } + + if (Ret == TcgResultSuccess) { + break; + } + + Count++; + + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid password, request failed.", + L"Press ENTER to retry", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + } + + if (Count >= MAX_PASSWORD_TRY_COUNT) { + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Opal password retry count exceeds the limit.", + L"Press ENTER to skip the request and continue boot", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + gST->ConOut->ClearScreen(gST->ConOut); + } + +Done: + if (PopUpString2 != NULL) { + FreePool (PopUpString2); + } +} + +/** + Process Secure Erase OPAL request. + + @param[in] Dev The device which has Secure Erase OPAL request. + @param[in] RequestString Request string. + +**/ +VOID +ProcessOpalRequestSecureErase ( + IN OPAL_DRIVER_DEVICE *Dev, + IN CHAR16 *RequestString + ) +{ + UINT8 Count; + CHAR8 *Password; + UINT32 PasswordLen; + OPAL_SESSION Session; + BOOLEAN PressEsc; + EFI_INPUT_KEY Key; + TCG_RESULT Ret; + BOOLEAN PasswordFailed; + CHAR16 *PopUpString; + CHAR16 *PopUpString2; + CHAR16 *PopUpString3; + UINTN BufferSize; + + if (Dev == NULL) { + return; + } + + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__)); + + PopUpString = OpalGetPopUpString (Dev, RequestString); + + if (Dev->OpalDisk.EstimateTimeCost > MAX_ACCEPTABLE_REVERTING_TIME) { + BufferSize = StrSize (L"Warning: Secure erase action will take about ####### seconds"); + PopUpString2 = AllocateZeroPool (BufferSize); + ASSERT (PopUpString2 != NULL); + UnicodeSPrint ( + PopUpString2, + BufferSize, + L"WARNING: Secure erase action will take about %d seconds", + Dev->OpalDisk.EstimateTimeCost + ); + PopUpString3 = L"DO NOT power off system during the action!"; + } else { + PopUpString2 = NULL; + PopUpString3 = NULL; + } + Count = 0; + + ZeroMem(&Session, sizeof(Session)); + Session.Sscp = Dev->OpalDisk.Sscp; + Session.MediaId = Dev->OpalDisk.MediaId; + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId; + + while (Count < MAX_PASSWORD_TRY_COUNT) { + Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, PopUpString2, PopUpString3, &PressEsc); + if (PressEsc) { + 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); + goto Done; + } else { + // + // Let user input password again. + // + continue; + } + } + + if (Password == NULL) { + Count ++; + continue; + } + PasswordLen = (UINT32) AsciiStrLen(Password); + + Ret = OpalUtilSecureErase(&Session, Password, PasswordLen, &PasswordFailed); + if (Ret == TcgResultSuccess) { + OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen); + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString)); + } else { + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString)); + } + + if (Password != NULL) { + ZeroMem (Password, PasswordLen); + FreePool (Password); + } + + if (Ret == TcgResultSuccess) { + break; + } + + Count++; + + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid password, request failed.", + L"Press ENTER to retry", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + } + + if (Count >= MAX_PASSWORD_TRY_COUNT) { + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Opal password retry count exceeds the limit.", + L"Press ENTER to skip the request and continue boot", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + gST->ConOut->ClearScreen(gST->ConOut); + } + +Done: + if (PopUpString2 != NULL) { + FreePool (PopUpString2); + } +} + +/** + Process Set Admin Pwd OPAL request. + + @param[in] Dev The device which has Set Admin Pwd Feature OPAL request. + @param[in] RequestString Request string. + +**/ +VOID +ProcessOpalRequestSetUserPwd ( + IN OPAL_DRIVER_DEVICE *Dev, + IN CHAR16 *RequestString + ) +{ + UINT8 Count; + CHAR8 *OldPassword; + UINT32 OldPasswordLen; + CHAR8 *Password; + UINT32 PasswordLen; + CHAR8 *PasswordConfirm; + UINT32 PasswordLenConfirm; + OPAL_SESSION Session; + BOOLEAN PressEsc; + EFI_INPUT_KEY Key; + TCG_RESULT Ret; + CHAR16 *PopUpString; + + if (Dev == NULL) { + return; + } + + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__)); + + PopUpString = OpalGetPopUpString (Dev, RequestString); + + Count = 0; + + while (Count < MAX_PASSWORD_TRY_COUNT) { + OldPassword = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please type in your password", NULL, &PressEsc); + if (PressEsc) { + 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; + } + } + + if (OldPassword == NULL) { + Count ++; + continue; + } + OldPasswordLen = (UINT32) AsciiStrLen(OldPassword); + + ZeroMem(&Session, sizeof(Session)); + Session.Sscp = Dev->OpalDisk.Sscp; + Session.MediaId = Dev->OpalDisk.MediaId; + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId; + Ret = OpalUtilVerifyPassword (&Session, OldPassword, OldPasswordLen, OPAL_LOCKING_SP_USER1_AUTHORITY); + if (Ret == TcgResultSuccess) { + DEBUG ((DEBUG_INFO, "Verify with USER1 authority : Success\n")); + } else { + Ret = OpalUtilVerifyPassword (&Session, OldPassword, OldPasswordLen, OPAL_LOCKING_SP_ADMIN1_AUTHORITY); + if (Ret == TcgResultSuccess) { + DEBUG ((DEBUG_INFO, "Verify with ADMIN1 authority: Success\n")); + } else { + ZeroMem (OldPassword, OldPasswordLen); + FreePool (OldPassword); + DEBUG ((DEBUG_INFO, "Verify: Failure\n")); + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Incorrect password.", + L"Press ENTER to retry", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + Count ++; + continue; + } + } + + Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please type in your new password", NULL, &PressEsc); + if (Password == NULL) { + ZeroMem (OldPassword, OldPasswordLen); + FreePool (OldPassword); + Count ++; + continue; + } + PasswordLen = (UINT32) AsciiStrLen(Password); + + PasswordConfirm = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please confirm your new password", NULL, &PressEsc); + if (PasswordConfirm == NULL) { + ZeroMem (OldPassword, OldPasswordLen); + FreePool (OldPassword); + ZeroMem (Password, PasswordLen); + FreePool (Password); + Count ++; + continue; + } + PasswordLenConfirm = (UINT32) AsciiStrLen(PasswordConfirm); + if ((PasswordLen != PasswordLenConfirm) || + (CompareMem (Password, PasswordConfirm, PasswordLen) != 0)) { + ZeroMem (OldPassword, OldPasswordLen); + FreePool (OldPassword); + ZeroMem (Password, PasswordLen); + FreePool (Password); + ZeroMem (PasswordConfirm, PasswordLenConfirm); + FreePool (PasswordConfirm); + 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); + Count ++; + continue; + } + + if (PasswordConfirm != NULL) { + ZeroMem (PasswordConfirm, PasswordLenConfirm); + FreePool (PasswordConfirm); + } + + ZeroMem(&Session, sizeof(Session)); + Session.Sscp = Dev->OpalDisk.Sscp; + Session.MediaId = Dev->OpalDisk.MediaId; + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId; + Ret = OpalUtilSetUserPassword( + &Session, + OldPassword, + OldPasswordLen, + Password, + PasswordLen + ); + if (Ret == TcgResultSuccess) { + OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen); + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString)); + } else { + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString)); + } + + if (OldPassword != NULL) { + ZeroMem (OldPassword, OldPasswordLen); + FreePool (OldPassword); + } + + if (Password != NULL) { + ZeroMem (Password, PasswordLen); + FreePool (Password); + } + + if (Ret == TcgResultSuccess) { + break; + } + + Count++; + + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Request failed.", + L"Press ENTER to retry", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + } + + if (Count >= MAX_PASSWORD_TRY_COUNT) { + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Opal password retry count exceeds the limit.", + L"Press ENTER to skip the request and continue boot", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + gST->ConOut->ClearScreen(gST->ConOut); + } +} + +/** + Process Set Admin Pwd OPAL request. + + @param[in] Dev The device which has Set Admin Pwd Feature OPAL request. + @param[in] RequestString Request string. + +**/ +VOID +ProcessOpalRequestSetAdminPwd ( + IN OPAL_DRIVER_DEVICE *Dev, + IN CHAR16 *RequestString + ) +{ + UINT8 Count; + CHAR8 *OldPassword; + UINT32 OldPasswordLen; + CHAR8 *Password; + UINT32 PasswordLen; + CHAR8 *PasswordConfirm; + UINT32 PasswordLenConfirm; + OPAL_SESSION Session; + BOOLEAN PressEsc; + EFI_INPUT_KEY Key; + TCG_RESULT Ret; + CHAR16 *PopUpString; + + if (Dev == NULL) { + return; + } + + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__)); + + PopUpString = OpalGetPopUpString (Dev, RequestString); + + Count = 0; + + while (Count < MAX_PASSWORD_TRY_COUNT) { + OldPassword = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please type in your password", NULL, &PressEsc); + if (PressEsc) { + 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; + } + } + + if (OldPassword == NULL) { + Count ++; + continue; + } + OldPasswordLen = (UINT32) AsciiStrLen(OldPassword); + + ZeroMem(&Session, sizeof(Session)); + Session.Sscp = Dev->OpalDisk.Sscp; + Session.MediaId = Dev->OpalDisk.MediaId; + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId; + Ret = OpalUtilVerifyPassword (&Session, OldPassword, OldPasswordLen, OPAL_LOCKING_SP_ADMIN1_AUTHORITY); + if (Ret == TcgResultSuccess) { + DEBUG ((DEBUG_INFO, "Verify: Success\n")); + } else { + ZeroMem (OldPassword, OldPasswordLen); + FreePool (OldPassword); + DEBUG ((DEBUG_INFO, "Verify: Failure\n")); + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Incorrect password.", + L"Press ENTER to retry", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + Count ++; + continue; + } + + Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please type in your new password", NULL, &PressEsc); + if (Password == NULL) { + ZeroMem (OldPassword, OldPasswordLen); + FreePool (OldPassword); + Count ++; + continue; + } + PasswordLen = (UINT32) AsciiStrLen(Password); + + PasswordConfirm = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please confirm your new password", NULL, &PressEsc); + if (PasswordConfirm == NULL) { + ZeroMem (OldPassword, OldPasswordLen); + FreePool (OldPassword); + ZeroMem (Password, PasswordLen); + FreePool (Password); + Count ++; + continue; + } + PasswordLenConfirm = (UINT32) AsciiStrLen(PasswordConfirm); + if ((PasswordLen != PasswordLenConfirm) || + (CompareMem (Password, PasswordConfirm, PasswordLen) != 0)) { + ZeroMem (OldPassword, OldPasswordLen); + FreePool (OldPassword); + ZeroMem (Password, PasswordLen); + FreePool (Password); + ZeroMem (PasswordConfirm, PasswordLenConfirm); + FreePool (PasswordConfirm); + 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); + Count ++; + continue; + } + + if (PasswordConfirm != NULL) { + ZeroMem (PasswordConfirm, PasswordLenConfirm); + FreePool (PasswordConfirm); + } + + + ZeroMem(&Session, sizeof(Session)); + Session.Sscp = Dev->OpalDisk.Sscp; + Session.MediaId = Dev->OpalDisk.MediaId; + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId; + Ret = OpalUtilSetAdminPassword( + &Session, + OldPassword, + OldPasswordLen, + Password, + PasswordLen + ); + if (Ret == TcgResultSuccess) { + OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen); + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString)); + } else { + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString)); + } + + if (OldPassword != NULL) { + ZeroMem (OldPassword, OldPasswordLen); + FreePool (OldPassword); + } + + if (Password != NULL) { + ZeroMem (Password, PasswordLen); + FreePool (Password); + } + + if (Ret == TcgResultSuccess) { + break; + } + + Count++; + + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Request failed.", + L"Press ENTER to retry", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + } + + if (Count >= MAX_PASSWORD_TRY_COUNT) { + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Opal password retry count exceeds the limit.", + L"Press ENTER to skip the request and continue boot", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + gST->ConOut->ClearScreen(gST->ConOut); + } +} + +/** + Process OPAL request. + + @param[in] Dev The device which has OPAL request. + +**/ +VOID +ProcessOpalRequest ( + IN OPAL_DRIVER_DEVICE *Dev + ) +{ + EFI_STATUS Status; + OPAL_REQUEST_VARIABLE *TempVariable; + OPAL_REQUEST_VARIABLE *Variable; + UINTN VariableSize; + EFI_DEVICE_PATH_PROTOCOL *DevicePathInVariable; + UINTN DevicePathSizeInVariable; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + UINTN DevicePathSize; + BOOLEAN KeepUserData; + + DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__)); + + if (mOpalRequestVariable == NULL) { + Status = GetVariable2 ( + OPAL_REQUEST_VARIABLE_NAME, + &gHiiSetupVariableGuid, + (VOID **) &Variable, + &VariableSize + ); + if (EFI_ERROR (Status) || (Variable == NULL)) { + return; + } + mOpalRequestVariable = Variable; + mOpalRequestVariableSize = VariableSize; + + // + // Delete the OPAL request variable. + // + Status = gRT->SetVariable ( + OPAL_REQUEST_VARIABLE_NAME, + (EFI_GUID *) &gHiiSetupVariableGuid, + 0, + 0, + NULL + ); + ASSERT_EFI_ERROR (Status); + } else { + Variable = mOpalRequestVariable; + VariableSize = mOpalRequestVariableSize; + } + + // + // Process the OPAL requests. + // + TempVariable = Variable; + while ((VariableSize > sizeof (OPAL_REQUEST_VARIABLE)) && + (VariableSize >= TempVariable->Length) && + (TempVariable->Length > sizeof (OPAL_REQUEST_VARIABLE))) { + DevicePathInVariable = (EFI_DEVICE_PATH_PROTOCOL *) ((UINTN) TempVariable + sizeof (OPAL_REQUEST_VARIABLE)); + DevicePathSizeInVariable = GetDevicePathSize (DevicePathInVariable); + DevicePath = Dev->OpalDisk.OpalDevicePath; + DevicePathSize = GetDevicePathSize (DevicePath); + if ((DevicePathSize == DevicePathSizeInVariable) && + (CompareMem (DevicePath, DevicePathInVariable, DevicePathSize) == 0)) { + // + // Found the node for the OPAL device. + // + if (TempVariable->OpalRequest.SetAdminPwd != 0) { + ProcessOpalRequestSetAdminPwd (Dev, L"Update Admin Pwd:"); + } + if (TempVariable->OpalRequest.SetUserPwd != 0) { + ProcessOpalRequestSetUserPwd (Dev, L"Set User Pwd:"); + } + if (TempVariable->OpalRequest.SecureErase!= 0) { + ProcessOpalRequestSecureErase (Dev, L"Secure Erase:"); + } + if (TempVariable->OpalRequest.Revert != 0) { + KeepUserData = (BOOLEAN) TempVariable->OpalRequest.KeepUserData; + ProcessOpalRequestRevert ( + Dev, + KeepUserData, + KeepUserData ? L"Admin Revert(keep):" : L"Admin Revert:" + ); + } + if (TempVariable->OpalRequest.PsidRevert != 0) { + ProcessOpalRequestPsidRevert (Dev, L"Psid Revert:"); + } + if (TempVariable->OpalRequest.DisableUser != 0) { + ProcessOpalRequestDisableUser (Dev, L"Disable User:"); + } + if (TempVariable->OpalRequest.EnableFeature != 0) { + ProcessOpalRequestEnableFeature (Dev, L"Enable Feature:"); + } + + // + // Update Device ownership. + // Later BlockSID command may block the update. + // + OpalDiskUpdateOwnerShip (&Dev->OpalDisk); + + break; + } + + VariableSize -= TempVariable->Length; + TempVariable = (OPAL_REQUEST_VARIABLE *) ((UINTN) TempVariable + TempVariable->Length); + } + + DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__)); +} + +/** + Add new device to the global device list. + + @param Dev New create device. + +**/ +VOID +AddDeviceToTail( + IN OPAL_DRIVER_DEVICE *Dev + ) +{ + OPAL_DRIVER_DEVICE *TmpDev; + + if (mOpalDriver.DeviceList == NULL) { + mOpalDriver.DeviceList = Dev; + } else { + TmpDev = mOpalDriver.DeviceList; + while (TmpDev->Next != NULL) { + TmpDev = TmpDev->Next; + } + + TmpDev->Next = Dev; + } +} + +/** + Remove one device in the global device list. + + @param Dev The device need to be removed. + +**/ +VOID +RemoveDevice ( + IN OPAL_DRIVER_DEVICE *Dev + ) +{ + OPAL_DRIVER_DEVICE *TmpDev; + + if (mOpalDriver.DeviceList == NULL) { + return; + } + + if (mOpalDriver.DeviceList == Dev) { + mOpalDriver.DeviceList = NULL; + return; + } + + TmpDev = mOpalDriver.DeviceList; + while (TmpDev->Next != NULL) { + if (TmpDev->Next == Dev) { + TmpDev->Next = Dev->Next; + break; + } + } +} + +/** + Get current device count. + + @retval return the current created device count. + +**/ +UINT8 +GetDeviceCount ( + VOID + ) +{ + UINT8 Count; + OPAL_DRIVER_DEVICE *TmpDev; + + Count = 0; + TmpDev = mOpalDriver.DeviceList; + + while (TmpDev != NULL) { + Count++; + TmpDev = TmpDev->Next; + } + + return Count; +} + +/** + Get devcie list info. + + @retval return the device list pointer. +**/ +OPAL_DRIVER_DEVICE* +OpalDriverGetDeviceList( + VOID + ) +{ + return mOpalDriver.DeviceList; +} + +/** + Stop this Controller. + + @param Dev The device need to be stopped. + +**/ +VOID +OpalDriverStopDevice ( + OPAL_DRIVER_DEVICE *Dev + ) +{ + // + // free each name + // + FreePool(Dev->Name16); + + // + // remove OPAL_DRIVER_DEVICE from the list + // it updates the controllerList pointer + // + RemoveDevice(Dev); + + // + // close protocols that were opened + // + gBS->CloseProtocol( + Dev->Handle, + &gEfiStorageSecurityCommandProtocolGuid, + gOpalDriverBinding.DriverBindingHandle, + Dev->Handle + ); + + gBS->CloseProtocol( + Dev->Handle, + &gEfiBlockIoProtocolGuid, + gOpalDriverBinding.DriverBindingHandle, + Dev->Handle + ); + + FreePool(Dev); +} + +/** + Get devcie name through the component name protocol. + + @param[in] AllHandlesBuffer The handle buffer for current system. + @param[in] NumAllHandles The number of handles for the handle buffer. + @param[in] Dev The device which need to get name. + @param[in] UseComp1 Whether use component name or name2 protocol. + + @retval TRUE Find the name for this device. + @retval FALSE Not found the name for this device. +**/ +BOOLEAN +OpalDriverGetDeviceNameByProtocol( + EFI_HANDLE *AllHandlesBuffer, + UINTN NumAllHandles, + OPAL_DRIVER_DEVICE *Dev, + BOOLEAN UseComp1 + ) +{ + EFI_HANDLE* ProtocolHandlesBuffer; + UINTN NumProtocolHandles; + EFI_STATUS Status; + EFI_COMPONENT_NAME2_PROTOCOL* Cnp1_2; // efi component name and componentName2 have same layout + EFI_GUID Protocol; + UINTN StrLength; + EFI_DEVICE_PATH_PROTOCOL* TmpDevPath; + UINTN Index1; + UINTN Index2; + EFI_HANDLE TmpHandle; + CHAR16 *DevName; + + if (Dev == NULL || AllHandlesBuffer == NULL || NumAllHandles == 0) { + return FALSE; + } + + Protocol = UseComp1 ? gEfiComponentNameProtocolGuid : gEfiComponentName2ProtocolGuid; + + // + // Find all EFI_HANDLES with protocol + // + Status = gBS->LocateHandleBuffer( + ByProtocol, + &Protocol, + NULL, + &NumProtocolHandles, + &ProtocolHandlesBuffer + ); + if (EFI_ERROR(Status)) { + return FALSE; + } + + + // + // Exit early if no supported devices + // + if (NumProtocolHandles == 0) { + return FALSE; + } + + // + // Get printable name by iterating through all protocols + // using the handle as the child, and iterate through all handles for the controller + // exit loop early once found, if not found, then delete device + // storage security protocol instances already exist, add them to internal list + // + Status = EFI_DEVICE_ERROR; + for (Index1 = 0; Index1 < NumProtocolHandles; Index1++) { + DevName = NULL; + + if (Dev->Name16 != NULL) { + return TRUE; + } + + TmpHandle = ProtocolHandlesBuffer[Index1]; + + Status = gBS->OpenProtocol( + TmpHandle, + &Protocol, + (VOID**)&Cnp1_2, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR(Status) || Cnp1_2 == NULL) { + continue; + } + + // + // Use all handles array as controller handle + // + for (Index2 = 0; Index2 < NumAllHandles; Index2++) { + Status = Cnp1_2->GetControllerName( + Cnp1_2, + AllHandlesBuffer[Index2], + Dev->Handle, + LANGUAGE_ISO_639_2_ENGLISH, + &DevName + ); + if (EFI_ERROR(Status)) { + Status = Cnp1_2->GetControllerName( + Cnp1_2, + AllHandlesBuffer[Index2], + Dev->Handle, + LANGUAGE_RFC_3066_ENGLISH, + &DevName + ); + } + if (!EFI_ERROR(Status) && DevName != NULL) { + StrLength = StrLen(DevName) + 1; // Add one for NULL terminator + Dev->Name16 = AllocateZeroPool(StrLength * sizeof (CHAR16)); + ASSERT (Dev->Name16 != NULL); + StrCpyS (Dev->Name16, StrLength, DevName); + Dev->NameZ = (CHAR8*)AllocateZeroPool(StrLength); + UnicodeStrToAsciiStrS (DevName, Dev->NameZ, StrLength); + + // + // Retrieve bridge BDF info and port number or namespace depending on type + // + TmpDevPath = NULL; + Status = gBS->OpenProtocol( + Dev->Handle, + &gEfiDevicePathProtocolGuid, + (VOID**)&TmpDevPath, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR(Status)) { + Dev->OpalDevicePath = DuplicateDevicePath (TmpDevPath); + return TRUE; + } + + if (Dev->Name16 != NULL) { + FreePool(Dev->Name16); + Dev->Name16 = NULL; + } + if (Dev->NameZ != NULL) { + FreePool(Dev->NameZ); + Dev->NameZ = NULL; + } + } + } + } + + return FALSE; +} + +/** + Get devcie name through the component name protocol. + + @param[in] Dev The device which need to get name. + + @retval TRUE Find the name for this device. + @retval FALSE Not found the name for this device. +**/ +BOOLEAN +OpalDriverGetDriverDeviceName( + OPAL_DRIVER_DEVICE *Dev + ) +{ + EFI_HANDLE* AllHandlesBuffer; + UINTN NumAllHandles; + EFI_STATUS Status; + + if (Dev == NULL) { + DEBUG((DEBUG_ERROR | DEBUG_INIT, "OpalDriverGetDriverDeviceName Exiting, Dev=NULL\n")); + return FALSE; + } + + // + // Iterate through ComponentName2 handles to get name, if fails, try ComponentName + // + if (Dev->Name16 == NULL) { + DEBUG((DEBUG_ERROR | DEBUG_INIT, "Name is null, update it\n")); + // + // Find all EFI_HANDLES + // + Status = gBS->LocateHandleBuffer( + AllHandles, + NULL, + NULL, + &NumAllHandles, + &AllHandlesBuffer + ); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_INFO, "LocateHandleBuffer for AllHandles failed %r\n", Status )); + return FALSE; + } + + // + // Try component Name2 + // + if (!OpalDriverGetDeviceNameByProtocol(AllHandlesBuffer, NumAllHandles, Dev, FALSE)) { + DEBUG((DEBUG_ERROR | DEBUG_INIT, "ComponentName2 failed to get device name, try ComponentName\n")); + if (!OpalDriverGetDeviceNameByProtocol(AllHandlesBuffer, NumAllHandles, Dev, TRUE)) { + DEBUG((DEBUG_ERROR | DEBUG_INIT, "ComponentName failed to get device name, skip device\n")); + return FALSE; + } + } + } + + return TRUE; +} + +/** + 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 +EfiDriverEntryPoint( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE* SystemTable + ) +{ + EFI_STATUS Status; + EFI_EVENT EndOfDxeEvent; + + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gOpalDriverBinding, + ImageHandle, + &gOpalComponentName, + &gOpalComponentName2 + ); + + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "Install protocols to Opal driver Handle failed\n")); + return Status ; + } + + // + // Initialize Driver object + // + ZeroMem(&mOpalDriver, sizeof(mOpalDriver)); + mOpalDriver.Handle = ImageHandle; + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + OpalEndOfDxeEventNotify, + NULL, + &gEfiEndOfDxeEventGroupGuid, + &EndOfDxeEvent + ); + ASSERT_EFI_ERROR (Status); + + // + // Install Hii packages. + // + HiiInstall(); + + return Status; +} + +/** + Tests to see if this driver supports a given controller. + + This function checks to see if the controller contains an instance of the + EFI_STORAGE_SECURITY_COMMAND_PROTOCOL and the EFI_BLOCK_IO_PROTOCOL + and returns EFI_SUCCESS if it does. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The Handle of the controller to test. This Handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath This parameter is ignored. + + @retval EFI_SUCCESS The device contains required protocols + @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by the driver + specified by This. + @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by a different + driver or an application that requires exclusive access. + Currently not implemented. + @retval EFI_UNSUPPORTED The device does not contain requires protocols + +**/ +EFI_STATUS +EFIAPI +OpalEfiDriverBindingSupported( + IN EFI_DRIVER_BINDING_PROTOCOL* This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL* RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_STORAGE_SECURITY_COMMAND_PROTOCOL* SecurityCommand; + + if (mOpalEndOfDxe) { + return EFI_UNSUPPORTED; + } + + // + // Test EFI_STORAGE_SECURITY_COMMAND_PROTOCOL on controller Handle. + // + Status = gBS->OpenProtocol( + Controller, + &gEfiStorageSecurityCommandProtocolGuid, + ( VOID ** )&SecurityCommand, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (Status == EFI_ALREADY_STARTED) { + return EFI_SUCCESS; + } + + if (EFI_ERROR(Status)) { + return Status; + } + + // + // Close protocol and reopen in Start call + // + gBS->CloseProtocol( + Controller, + &gEfiStorageSecurityCommandProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + + return EFI_SUCCESS; +} + +/** + Enables Opal Management on a supported device if available. + + The start function is designed to be called after the Opal UEFI Driver has confirmed the + "controller", which is a child Handle, contains the EF_STORAGE_SECURITY_COMMAND protocols. + This function will complete the other necessary checks, such as verifying the device supports + the correct version of Opal. Upon verification, it will add the device to the + Opal HII list in order to expose Opal management options. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The Handle of the controller to start. This Handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For a bus driver, if this parameter is NULL, then handles + for all the children of Controller are created by this driver. + If this parameter is not NULL and the first Device Path Node is + not the End of Device Path Node, then only the Handle for the + child device specified by the first Device Path Node of + RemainingDevicePath is created by this driver. + If the first Device Path Node of RemainingDevicePath is + the End of Device Path Node, no child Handle is created by this + driver. + + @retval EFI_SUCCESS Opal management was enabled. + @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval Others The driver failed to start the device. + +**/ +EFI_STATUS +EFIAPI +OpalEfiDriverBindingStart( + IN EFI_DRIVER_BINDING_PROTOCOL* This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL* RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + OPAL_DRIVER_DEVICE *Dev; + OPAL_DRIVER_DEVICE *Itr; + BOOLEAN Result; + + Itr = mOpalDriver.DeviceList; + while (Itr != NULL) { + if (Controller == Itr->Handle) { + return EFI_SUCCESS; + } + Itr = Itr->Next; + } + + // + // Create internal device for tracking. This allows all disks to be tracked + // by same HII form + // + Dev = (OPAL_DRIVER_DEVICE*)AllocateZeroPool(sizeof(OPAL_DRIVER_DEVICE)); + if (Dev == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Dev->Handle = Controller; + + // + // Open EFI_STORAGE_SECURITY_COMMAND_PROTOCOL to perform Opal supported checks + // + Status = gBS->OpenProtocol( + Controller, + &gEfiStorageSecurityCommandProtocolGuid, + (VOID **)&Dev->Sscp, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR(Status)) { + FreePool(Dev); + return Status; + } + + // + // Open EFI_BLOCK_IO_PROTOCOL on controller Handle, required by EFI_STORAGE_SECURITY_COMMAND_PROTOCOL + // function APIs + // + Status = gBS->OpenProtocol( + Controller, + &gEfiBlockIoProtocolGuid, + (VOID **)&BlkIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR(Status)) { + // + // Block_IO not supported on handle + // + if(Status == EFI_UNSUPPORTED) { + BlkIo = NULL; + } else { + // + // Close storage security that was opened + // + gBS->CloseProtocol( + Controller, + &gEfiStorageSecurityCommandProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + FreePool(Dev); + return Status; + } + } + + // + // Save mediaId + // + if(BlkIo == NULL) { + // If no Block IO present, use defined MediaId value. + Dev->MediaId = 0x0; + } else { + Dev->MediaId = BlkIo->Media->MediaId; + + gBS->CloseProtocol( + Controller, + &gEfiBlockIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + } + + // + // Acquire Ascii printable name of child, if not found, then ignore device + // + Result = OpalDriverGetDriverDeviceName (Dev); + if (!Result) { + goto Done; + } + + Status = OpalDiskInitialize (Dev); + if (EFI_ERROR (Status)) { + goto Done; + } + + AddDeviceToTail(Dev); + + // + // Check if device is locked and prompt for password. + // + OpalDriverRequestPassword (Dev, L"Unlock:"); + + // + // Process OPAL request from last boot. + // + ProcessOpalRequest (Dev); + + return EFI_SUCCESS; + +Done: + // + // free device, close protocols and exit + // + gBS->CloseProtocol( + Controller, + &gEfiStorageSecurityCommandProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + FreePool(Dev); + + return EFI_DEVICE_ERROR; +} + +/** + Stop this driver on Controller. + + @param This Protocol instance pointer. + @param Controller Handle of device to stop driver on + @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of + children is zero stop the entire bus driver. + @param ChildHandleBuffer List of Child Handles to Stop. + + @retval EFI_SUCCESS This driver is removed Controller. + @retval other This driver could not be removed from this device. + +**/ +EFI_STATUS +EFIAPI +OpalEfiDriverBindingStop( + EFI_DRIVER_BINDING_PROTOCOL* This, + EFI_HANDLE Controller, + UINTN NumberOfChildren, + EFI_HANDLE* ChildHandleBuffer + ) +{ + OPAL_DRIVER_DEVICE* Itr; + + Itr = mOpalDriver.DeviceList; + + // + // does Controller match any of the devices we are managing for Opal + // + while (Itr != NULL) { + if (Itr->Handle == Controller) { + OpalDriverStopDevice (Itr); + return EFI_SUCCESS; + } + + Itr = Itr->Next; + } + + return EFI_NOT_FOUND; +} + + +/** + Unloads UEFI Driver. Very useful for debugging and testing. + + @param ImageHandle Image Handle this driver. + + @retval EFI_SUCCESS This function always complete successfully. + @retval EFI_INVALID_PARAMETER The input ImageHandle is not valid. +**/ +EFI_STATUS +EFIAPI +OpalEfiDriverUnload ( + IN EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + OPAL_DRIVER_DEVICE *Itr; + + Status = EFI_SUCCESS; + + if (ImageHandle != gImageHandle) { + return (EFI_INVALID_PARAMETER); + } + + // + // Uninstall any interface added to each device by us + // + while (mOpalDriver.DeviceList) { + Itr = mOpalDriver.DeviceList; + // + // Remove OPAL_DRIVER_DEVICE from the list + // it updates the controllerList pointer + // + OpalDriverStopDevice(Itr); + } + + // + // Uninstall the HII capability + // + Status = HiiUninstall(); + + return Status; +} + |