/** @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.
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; }