summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.c
diff options
context:
space:
mode:
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.c2966
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;
+}
+