/** @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 | |
// | |
if (SupportedAttributes->MediaEncryption) { | |
AvalDiskActions->SecureErase = 1; | |
} else { | |
AvalDiskActions->SecureErase = 0; | |
} | |
} 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", __func__)); | |
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", __func__)); | |
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", __func__)); | |
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", __func__)); | |
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", __func__)); | |
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", __func__)); | |
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", __func__)); | |
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", __func__)); | |
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", __func__)); | |
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", __func__)); | |
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", __func__)); | |
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", __func__)); | |
} | |
/** | |
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; | |
} |