--- /dev/null
+/** @file\r
+ Header file of Opal password support library.\r
+\r
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#ifndef _OPAL_PASSWORD_SUPPORT_LIB_H_\r
+#define _OPAL_PASSWORD_SUPPORT_LIB_H_\r
+\r
+#include <Protocol/DevicePath.h>\r
+#include <Library/TcgStorageOpalLib.h>\r
+\r
+\r
+#pragma pack(1)\r
+\r
+//\r
+// Structure that is used to represent the available actions for an OpalDisk.\r
+// The data can then be utilized to expose/hide certain actions available to an end user\r
+// by the consumer of this library.\r
+//\r
+typedef struct {\r
+ //\r
+ // Indicates if the disk can support PSID Revert action. should verify disk supports PSID authority\r
+ //\r
+ UINT16 PsidRevert : 1;\r
+\r
+ //\r
+ // Indicates if the disk can support Revert action\r
+ //\r
+ UINT16 Revert : 1;\r
+\r
+ //\r
+ // Indicates if the user must keep data for revert action. It is true if no media encryption is supported.\r
+ //\r
+ UINT16 RevertKeepDataForced : 1;\r
+\r
+ //\r
+ // Indicates if the disk can support set Admin password\r
+ //\r
+ UINT16 AdminPass : 1;\r
+\r
+ //\r
+ // Indicates if the disk can support set User password. This action requires that a user\r
+ // password is first enabled.\r
+ //\r
+ UINT16 UserPass : 1;\r
+\r
+ //\r
+ // Indicates if unlock action is available. Requires disk to be currently locked.\r
+ //\r
+ UINT16 Unlock : 1;\r
+\r
+ //\r
+ // Indicates if Secure Erase action is available. Action requires admin credentials and media encryption support.\r
+ //\r
+ UINT16 SecureErase : 1;\r
+\r
+ //\r
+ // Indicates if Disable User action is available. Action requires admin credentials.\r
+ //\r
+ UINT16 DisableUser : 1;\r
+} OPAL_DISK_ACTIONS;\r
+\r
+//\r
+// Structure that is used to represent the Opal device with password info.\r
+//\r
+typedef struct {\r
+ LIST_ENTRY Link;\r
+\r
+ UINT8 Password[32];\r
+ UINT8 PasswordLength;\r
+\r
+ EFI_DEVICE_PATH_PROTOCOL OpalDevicePath;\r
+} OPAL_DISK_AND_PASSWORD_INFO;\r
+\r
+#pragma pack()\r
+\r
+/**\r
+\r
+ The function performs determines the available actions for the OPAL_DISK provided.\r
+\r
+ @param[in] SupportedAttributes The support attribute for the device.\r
+ @param[in] LockingFeature The locking status for the device.\r
+ @param[in] OwnerShip The ownership for the device.\r
+ @param[out] AvalDiskActions Pointer to fill-out with appropriate disk actions.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalSupportGetAvailableActions(\r
+ IN OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes,\r
+ IN TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature,\r
+ IN UINT16 OwnerShip,\r
+ OUT OPAL_DISK_ACTIONS *AvalDiskActions\r
+ );\r
+\r
+/**\r
+ Enable Opal Feature for the input device.\r
+\r
+ @param[in] Session The opal session for the opal device.\r
+ @param[in] Msid Msid\r
+ @param[in] MsidLength Msid Length\r
+ @param[in] Password Admin password\r
+ @param[in] PassLength Length of password in bytes\r
+ @param[in] DevicePath The device path for the opal devcie.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalSupportEnableOpalFeature(\r
+ IN OPAL_SESSION *Session,\r
+ IN VOID *Msid,\r
+ IN UINT32 MsidLength,\r
+ IN VOID *Password,\r
+ IN UINT32 PassLength,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+ );\r
+\r
+/**\r
+ Creates a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY, then reverts device using Admin SP Revert method.\r
+\r
+ @param[in] Session The opal session for the opal device.\r
+ @param[in] Psid PSID of device to revert.\r
+ @param[in] PsidLength Length of PSID in bytes.\r
+ @param[in] DevicePath The device path for the opal devcie.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalSupportPsidRevert(\r
+ IN OPAL_SESSION *Session,\r
+ IN VOID *Psid,\r
+ IN UINT32 PsidLength,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+ );\r
+\r
+/**\r
+ Opens a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY, then reverts the device using the RevertSP method.\r
+\r
+ @param[in] Session The opal session for the opal device.\r
+ @param[in] KeepUserData TRUE to keep existing Data on the disk, or FALSE to erase it\r
+ @param[in] Password Admin password\r
+ @param[in] PasswordLength Length of password in bytes\r
+ @param[in] Msid Msid\r
+ @param[in] MsidLength Msid Length\r
+ @param[out] PasswordFailed indicates if password failed (start session didn't work)\r
+ @param[in] DevicePath The device path for the opal devcie.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalSupportRevert(\r
+ IN OPAL_SESSION *Session,\r
+ IN BOOLEAN KeepUserData,\r
+ IN VOID *Password,\r
+ IN UINT32 PasswordLength,\r
+ IN VOID *Msid,\r
+ IN UINT32 MsidLength,\r
+ OUT BOOLEAN *PasswordFailed,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+ );\r
+\r
+/**\r
+ Set new password.\r
+\r
+ @param[in] Session The opal session for the opal device.\r
+ @param[in] OldPassword Current admin password\r
+ @param[in] OldPasswordLength Length of current admin password in bytes\r
+ @param[in] NewPassword New admin password to set\r
+ @param[in] NewPasswordLength Length of new password in bytes\r
+ @param[in] DevicePath The device path for the opal devcie.\r
+ @param[in] SetAdmin Whether set admin password or user password.\r
+ TRUE for admin, FALSE for user.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalSupportSetPassword(\r
+ IN OPAL_SESSION *Session,\r
+ IN VOID *OldPassword,\r
+ IN UINT32 OldPasswordLength,\r
+ IN VOID *NewPassword,\r
+ IN UINT32 NewPasswordLength,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ IN BOOLEAN SetAdmin\r
+ );\r
+\r
+/**\r
+ Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY and disables the User1 authority.\r
+\r
+ @param[in] Session The opal session for the opal device.\r
+ @param[in] Password Admin password\r
+ @param[in] PasswordLength Length of password in bytes\r
+ @param[out] PasswordFailed Indicates if password failed (start session didn't work)\r
+ @param[in] DevicePath The device path for the opal devcie.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalSupportDisableUser(\r
+ IN OPAL_SESSION *Session,\r
+ IN VOID *Password,\r
+ IN UINT32 PasswordLength,\r
+ OUT BOOLEAN *PasswordFailed,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+ );\r
+\r
+/**\r
+ Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_USER1_AUTHORITY or OPAL_LOCKING_SP_ADMIN1_AUTHORITY\r
+ and updates the global locking range ReadLocked and WriteLocked columns to FALSE.\r
+\r
+ @param[in] Session The opal session for the opal device.\r
+ @param[in] Password Admin or user password\r
+ @param[in] PasswordLength Length of password in bytes\r
+ @param[in] DevicePath The device path for the opal devcie.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalSupportUnlock(\r
+ IN OPAL_SESSION *Session,\r
+ IN VOID *Password,\r
+ IN UINT32 PasswordLength,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+ );\r
+\r
+/**\r
+ Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_USER1_AUTHORITY or OPAL_LOCKING_SP_ADMIN1_AUTHORITY\r
+ and updates the global locking range ReadLocked and WriteLocked columns to TRUE.\r
+\r
+ @param[in] Session The opal session for the opal device.\r
+ @param[in] Password Admin or user password\r
+ @param[in] PasswordLength Length of password in bytes\r
+ @param[in] DevicePath The device path for the opal devcie.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalSupportLock(\r
+ IN OPAL_SESSION *Session,\r
+ IN VOID *Password,\r
+ IN UINT32 PasswordLength,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+ );\r
+\r
+/**\r
+ Check if the password is full zero.\r
+\r
+ @param[in] Password Points to the Data Buffer\r
+\r
+ @retval TRUE This password string is full zero.\r
+ @retval FALSE This password string is not full zero.\r
+\r
+**/\r
+LIST_ENTRY *\r
+EFIAPI\r
+OpalSupportGetOpalDeviceList (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Transfer the password to the smm driver.\r
+\r
+ @param[in] DevicePath The device path for the opal devcie.\r
+ @param PasswordLen The input password length.\r
+ @param Password Input password buffer.\r
+\r
+ @retval EFI_SUCCESS Do the required action success.\r
+ @retval Others Error occured.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalSupportSendPasword(\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ UINTN PasswordLen,\r
+ VOID *Password\r
+ );\r
+\r
+#endif // _OPAL_CORE_H_\r
--- /dev/null
+/** @file\r
+ Implementation of Opal password support library.\r
+\r
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "OpalPasswordSupportNotify.h"\r
+\r
+#define OPAL_PASSWORD_MAX_LENGTH 32\r
+\r
+LIST_ENTRY mDeviceList = INITIALIZE_LIST_HEAD_VARIABLE (mDeviceList);\r
+BOOLEAN gInSmm = FALSE;\r
+EFI_GUID gOpalPasswordNotifyProtocolGuid = OPAL_PASSWORD_NOTIFY_PROTOCOL_GUID;\r
+\r
+/**\r
+\r
+ The function performs determines the available actions for the OPAL_DISK provided.\r
+\r
+ @param[in] SupportedAttributes The support attribute for the device.\r
+ @param[in] LockingFeature The locking status for the device.\r
+ @param[in] OwnerShip The ownership for the device.\r
+ @param[out] AvalDiskActions Pointer to fill-out with appropriate disk actions.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalSupportGetAvailableActions(\r
+ IN OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes,\r
+ IN TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature,\r
+ IN UINT16 OwnerShip,\r
+ OUT OPAL_DISK_ACTIONS *AvalDiskActions\r
+ )\r
+{\r
+ BOOLEAN ExistingPassword;\r
+\r
+ NULL_CHECK(AvalDiskActions);\r
+\r
+ AvalDiskActions->AdminPass = 1;\r
+ AvalDiskActions->UserPass = 0;\r
+ AvalDiskActions->DisableUser = 0;\r
+ AvalDiskActions->Unlock = 0;\r
+\r
+ //\r
+ // Revert is performed on locking sp, so only allow if locking sp is enabled\r
+ //\r
+ if (LockingFeature->LockingEnabled) {\r
+ AvalDiskActions->Revert = 1;\r
+ }\r
+\r
+ //\r
+ // Psid revert is available for any device with media encryption support\r
+ // Revert is allowed for any device with media encryption support, however it requires\r
+ //\r
+ if (SupportedAttributes->MediaEncryption) {\r
+\r
+ //\r
+ // Only allow psid revert if media encryption is enabled.\r
+ // Otherwise, someone who steals a disk can psid revert the disk and the user Data is still\r
+ // intact and accessible\r
+ //\r
+ AvalDiskActions->PsidRevert = 1;\r
+ AvalDiskActions->RevertKeepDataForced = 0;\r
+\r
+ //\r
+ // Secure erase is performed by generating a new encryption key\r
+ // this is only available is encryption is supported\r
+ //\r
+ AvalDiskActions->SecureErase = 1;\r
+ } else {\r
+ AvalDiskActions->PsidRevert = 0;\r
+ AvalDiskActions->SecureErase = 0;\r
+\r
+ //\r
+ // If no media encryption is supported, then a revert (using password) will not\r
+ // erase the Data (since you can't generate a new encryption key)\r
+ //\r
+ AvalDiskActions->RevertKeepDataForced = 1;\r
+ }\r
+\r
+ if (LockingFeature->Locked) {\r
+ AvalDiskActions->Unlock = 1;\r
+ } else {\r
+ AvalDiskActions->Unlock = 0;\r
+ }\r
+\r
+ //\r
+ // Only allow user to set password if an admin password exists\r
+ //\r
+ ExistingPassword = OpalUtilAdminPasswordExists(OwnerShip, LockingFeature);\r
+ AvalDiskActions->UserPass = ExistingPassword;\r
+\r
+ //\r
+ // This will still show up even if there isn't a user, which is fine\r
+ //\r
+ AvalDiskActions->DisableUser = ExistingPassword;\r
+\r
+ return TcgResultSuccess;\r
+}\r
+\r
+/**\r
+ Creates a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY, then reverts device using Admin SP Revert method.\r
+\r
+ @param[in] Session The opal session for the opal device.\r
+ @param[in] Psid PSID of device to revert.\r
+ @param[in] PsidLength Length of PSID in bytes.\r
+ @param[in] DevicePath The device path for the opal devcie.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalSupportPsidRevert(\r
+ IN OPAL_SESSION *Session,\r
+ IN VOID *Psid,\r
+ IN UINT32 PsidLength,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+ )\r
+{\r
+ TCG_RESULT Ret;\r
+\r
+ NULL_CHECK(Session);\r
+ NULL_CHECK(Psid);\r
+\r
+ Ret = OpalUtilPsidRevert (Session, Psid, PsidLength);\r
+ if (Ret == TcgResultSuccess && !gInSmm) {\r
+ OpalSupportSendPasword (DevicePath, 0, NULL);\r
+ }\r
+\r
+ return Ret;\r
+}\r
+\r
+/**\r
+ Opens a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_SID_AUTHORITY,\r
+ sets OPAL_UID_ADMIN_SP_C_PIN_SID with the new password,\r
+ and sets OPAL_LOCKING_SP_C_PIN_ADMIN1 with the new password.\r
+\r
+ @param[in] Session The opal session for the opal device.\r
+ @param[in] OldPassword Current admin password\r
+ @param[in] OldPasswordLength Length of current admin password in bytes\r
+ @param[in] NewPassword New admin password to set\r
+ @param[in] NewPasswordLength Length of new password in bytes\r
+ @param[in] DevicePath The device path for the opal devcie.\r
+ @param[in] SetAdmin Whether set admin password or user password.\r
+ TRUE for admin, FALSE for user.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalSupportSetPassword(\r
+ IN OPAL_SESSION *Session,\r
+ IN VOID *OldPassword,\r
+ IN UINT32 OldPasswordLength,\r
+ IN VOID *NewPassword,\r
+ IN UINT32 NewPasswordLength,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ IN BOOLEAN SetAdmin\r
+ )\r
+{\r
+ TCG_RESULT Ret;\r
+\r
+ NULL_CHECK(Session);\r
+ NULL_CHECK(OldPassword);\r
+ NULL_CHECK(NewPassword);\r
+\r
+ if (SetAdmin) {\r
+ Ret = OpalUtilSetAdminPassword(Session, OldPassword, OldPasswordLength, NewPassword, NewPasswordLength);\r
+ } else {\r
+ Ret = OpalUtilSetUserPassword(Session, OldPassword, OldPasswordLength, NewPassword, NewPasswordLength);\r
+ }\r
+ if (Ret == TcgResultSuccess && !gInSmm) {\r
+ OpalSupportSendPasword (DevicePath, NewPasswordLength, NewPassword);\r
+ }\r
+\r
+ return Ret;\r
+}\r
+\r
+/**\r
+ Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY and disables the User1 authority.\r
+\r
+ @param[in] Session The opal session for the opal device.\r
+ @param[in] Password Admin password\r
+ @param[in] PasswordLength Length of password in bytes\r
+ @param[out] PasswordFailed Indicates if password failed (start session didn't work)\r
+ @param[in] DevicePath The device path for the opal devcie.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalSupportDisableUser(\r
+ IN OPAL_SESSION *Session,\r
+ IN VOID *Password,\r
+ IN UINT32 PasswordLength,\r
+ OUT BOOLEAN *PasswordFailed,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+ )\r
+{\r
+ TCG_RESULT Ret;\r
+\r
+ NULL_CHECK(Session);\r
+ NULL_CHECK(Password);\r
+ NULL_CHECK(PasswordFailed);\r
+\r
+ Ret = OpalUtilDisableUser(Session, Password, PasswordLength, PasswordFailed);\r
+ if (Ret == TcgResultSuccess && !gInSmm) {\r
+ OpalSupportSendPasword (DevicePath, PasswordLength, Password);\r
+ }\r
+\r
+ return Ret;\r
+}\r
+\r
+/**\r
+ Enable Opal Feature for the input device.\r
+\r
+ @param[in] Session The opal session for the opal device.\r
+ @param[in] Msid Msid\r
+ @param[in] MsidLength Msid Length\r
+ @param[in] Password Admin password\r
+ @param[in] PassLength Length of password in bytes\r
+ @param[in] DevicePath The device path for the opal devcie.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalSupportEnableOpalFeature (\r
+ IN OPAL_SESSION *Session,\r
+ IN VOID *Msid,\r
+ IN UINT32 MsidLength,\r
+ IN VOID *Password,\r
+ IN UINT32 PassLength,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+ )\r
+{\r
+ TCG_RESULT Ret;\r
+\r
+ NULL_CHECK(Session);\r
+ NULL_CHECK(Msid);\r
+ NULL_CHECK(Password);\r
+\r
+ Ret = OpalUtilSetAdminPasswordAsSid(\r
+ Session,\r
+ Msid,\r
+ MsidLength,\r
+ Password,\r
+ PassLength\r
+ );\r
+ if (Ret == TcgResultSuccess) {\r
+ //\r
+ // Enable global locking range\r
+ //\r
+ Ret = OpalUtilSetOpalLockingRange(\r
+ Session,\r
+ Password,\r
+ PassLength,\r
+ OPAL_LOCKING_SP_LOCKING_GLOBALRANGE,\r
+ 0,\r
+ 0,\r
+ TRUE,\r
+ TRUE,\r
+ FALSE,\r
+ FALSE\r
+ );\r
+ }\r
+\r
+ if (Ret == TcgResultSuccess && !gInSmm) {\r
+ OpalSupportSendPasword (DevicePath, PassLength, Password);\r
+ }\r
+\r
+ return Ret;\r
+}\r
+\r
+/**\r
+ Opens a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY, then reverts the device using the RevertSP method.\r
+\r
+ @param[in] Session The opal session for the opal device.\r
+ @param[in] KeepUserData TRUE to keep existing Data on the disk, or FALSE to erase it\r
+ @param[in] Password Admin password\r
+ @param[in] PasswordLength Length of password in bytes\r
+ @param[in] Msid Msid\r
+ @param[in] MsidLength Msid Length\r
+ @param[out] PasswordFailed indicates if password failed (start session didn't work)\r
+ @param[in] DevicePath The device path for the opal devcie.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalSupportRevert(\r
+ IN OPAL_SESSION *Session,\r
+ IN BOOLEAN KeepUserData,\r
+ IN VOID *Password,\r
+ IN UINT32 PasswordLength,\r
+ IN VOID *Msid,\r
+ IN UINT32 MsidLength,\r
+ OUT BOOLEAN *PasswordFailed,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+ )\r
+{\r
+ TCG_RESULT Ret;\r
+\r
+ NULL_CHECK(Session);\r
+ NULL_CHECK(Password);\r
+ NULL_CHECK(Msid);\r
+ NULL_CHECK(PasswordFailed);\r
+\r
+ Ret = OpalUtilRevert(Session, KeepUserData, Password, PasswordLength, PasswordFailed, Msid, MsidLength);\r
+ if (Ret == TcgResultSuccess && !gInSmm) {\r
+ OpalSupportSendPasword (DevicePath, 0, NULL);\r
+ }\r
+\r
+ return Ret;\r
+}\r
+\r
+/**\r
+ Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_USER1_AUTHORITY or OPAL_LOCKING_SP_ADMIN1_AUTHORITY\r
+ and updates the global locking range ReadLocked and WriteLocked columns to FALSE.\r
+\r
+ @param[in] Session The opal session for the opal device.\r
+ @param[in] Password Admin or user password\r
+ @param[in] PasswordLength Length of password in bytes\r
+ @param[in] DevicePath The device path for the opal devcie.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalSupportUnlock(\r
+ IN OPAL_SESSION *Session,\r
+ IN VOID *Password,\r
+ IN UINT32 PasswordLength,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+ )\r
+{\r
+ TCG_RESULT Ret;\r
+\r
+ NULL_CHECK(Session);\r
+ NULL_CHECK(Password);\r
+\r
+ Ret = OpalUtilUpdateGlobalLockingRange(Session, Password, PasswordLength, FALSE, FALSE);\r
+ if (Ret == TcgResultSuccess && !gInSmm) {\r
+ OpalSupportSendPasword (DevicePath, PasswordLength, Password);\r
+ }\r
+\r
+ return Ret;\r
+}\r
+\r
+/**\r
+ Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_USER1_AUTHORITY or OPAL_LOCKING_SP_ADMIN1_AUTHORITY\r
+ and updates the global locking range ReadLocked and WriteLocked columns to TRUE.\r
+\r
+ @param[in] Session The opal session for the opal device.\r
+ @param[in] Password Admin or user password\r
+ @param[in] PasswordLength Length of password in bytes\r
+ @param[in] DevicePath The device path for the opal devcie.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalSupportLock(\r
+ IN OPAL_SESSION *Session,\r
+ IN VOID *Password,\r
+ IN UINT32 PasswordLength,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+ )\r
+{\r
+ TCG_RESULT Ret;\r
+\r
+ NULL_CHECK(Session);\r
+ NULL_CHECK(Password);\r
+\r
+ Ret = OpalUtilUpdateGlobalLockingRange(Session, Password, PasswordLength, TRUE, TRUE);\r
+ if (Ret == TcgResultSuccess && !gInSmm) {\r
+ OpalSupportSendPasword (DevicePath, PasswordLength, Password);\r
+ }\r
+\r
+ return Ret;\r
+}\r
+\r
+/**\r
+ Initialize the communicate Buffer using DataSize and Function.\r
+\r
+ @param[out] DataPtr Points to the Data in the communicate Buffer.\r
+ @param[in] DataSize The Data Size to send to SMM.\r
+ @param[in] Function The function number to initialize the communicate Header.\r
+\r
+ @retval EFI_INVALID_PARAMETER The Data Size is too big.\r
+ @retval EFI_SUCCESS Find the specified variable.\r
+\r
+**/\r
+VOID*\r
+OpalInitCommunicateBuffer (\r
+ OUT VOID **DataPtr OPTIONAL,\r
+ IN UINTN DataSize,\r
+ IN UINTN Function\r
+ )\r
+{\r
+ EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;\r
+ OPAL_SMM_COMMUNICATE_HEADER *SmmFunctionHeader;\r
+ VOID *Buffer;\r
+\r
+ Buffer = AllocateZeroPool (DataSize + OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + OFFSET_OF (OPAL_SMM_COMMUNICATE_HEADER, Data));\r
+ ASSERT (Buffer != NULL);\r
+\r
+ SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) Buffer;\r
+ CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gOpalPasswordNotifyProtocolGuid);\r
+ SmmCommunicateHeader->MessageLength = DataSize + OFFSET_OF (OPAL_SMM_COMMUNICATE_HEADER, Data);\r
+\r
+ SmmFunctionHeader = (OPAL_SMM_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;\r
+ SmmFunctionHeader->Function = Function;\r
+ if (DataPtr != NULL) {\r
+ *DataPtr = SmmFunctionHeader->Data;\r
+ }\r
+\r
+ return Buffer;\r
+}\r
+\r
+/**\r
+ Send the Data in communicate Buffer to SMM.\r
+\r
+ @param[in] Buffer Points to the Data in the communicate Buffer.\r
+ @param[in] DataSize This Size of the function Header and the Data.\r
+\r
+ @retval EFI_SUCCESS Success is returned from the functin in SMM.\r
+ @retval Others Failure is returned from the function in SMM.\r
+\r
+**/\r
+EFI_STATUS\r
+OpalSendCommunicateBuffer (\r
+ IN VOID *Buffer,\r
+ IN UINTN DataSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN CommSize;\r
+ EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;\r
+ OPAL_SMM_COMMUNICATE_HEADER *SmmFunctionHeader;\r
+ EFI_SMM_COMMUNICATION_PROTOCOL *SmmCommunication;\r
+\r
+ Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &SmmCommunication);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ CommSize = DataSize + OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + OFFSET_OF (OPAL_SMM_COMMUNICATE_HEADER, Data);\r
+ Status = SmmCommunication->Communicate (SmmCommunication, Buffer, &CommSize);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) Buffer;\r
+ SmmFunctionHeader = (OPAL_SMM_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data;\r
+\r
+ return SmmFunctionHeader->ReturnStatus;\r
+}\r
+\r
+/**\r
+ Transfer the password to the smm driver.\r
+\r
+ @param[in] DevicePath The device path for the opal devcie.\r
+ @param PasswordLen The input password length.\r
+ @param Password Input password buffer.\r
+\r
+ @retval EFI_SUCCESS Do the required action success.\r
+ @retval Others Error occured.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalSupportSendPasword(\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ UINTN PasswordLen,\r
+ VOID *Password\r
+ )\r
+{\r
+ OPAL_COMM_DEVICE_LIST *Parameter;\r
+ VOID *Buffer;\r
+ UINTN Length;\r
+ EFI_STATUS Status;\r
+ UINTN DevicePathLen;\r
+\r
+ Parameter = NULL;\r
+ Buffer = NULL;\r
+\r
+ if (DevicePath == NULL) {\r
+ //\r
+ // Assume DevicePath == NULL only when library used by SMM driver\r
+ // and should not run to here, just return success.\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ DevicePathLen = GetDevicePathSize (DevicePath);\r
+ Length = OFFSET_OF (OPAL_COMM_DEVICE_LIST, OpalDevicePath) + DevicePathLen;\r
+ Buffer = OpalInitCommunicateBuffer((VOID**)&Parameter, Length, SMM_FUNCTION_SET_OPAL_PASSWORD);\r
+ if (Buffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ if (Password != NULL) {\r
+ CopyMem((VOID*)Parameter->Password, Password, PasswordLen);\r
+ Parameter->PasswordLength = (UINT8)PasswordLen;\r
+ }\r
+ CopyMem (&Parameter->OpalDevicePath, DevicePath, DevicePathLen);\r
+\r
+ Status = OpalSendCommunicateBuffer(Buffer, Length);\r
+ if (EFI_ERROR(Status)) {\r
+ goto EXIT;\r
+ }\r
+\r
+EXIT:\r
+ ZeroMem(Parameter, Length);\r
+ FreePool(Buffer);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Get saved Opal device list.\r
+\r
+ @retval return opal device list.\r
+\r
+**/\r
+LIST_ENTRY*\r
+EFIAPI\r
+OpalSupportGetOpalDeviceList (\r
+ VOID\r
+ )\r
+{\r
+ return &mDeviceList;\r
+}\r
+\r
+/**\r
+ Check if the password is full zero.\r
+\r
+ @param[in] Password Points to the Data Buffer\r
+\r
+ @retval TRUE This password string is full zero.\r
+ @retval FALSE This password string is not full zero.\r
+\r
+**/\r
+BOOLEAN\r
+OpalPasswordIsFullZero (\r
+ IN UINT8 *Password\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ for (Index = 0; Index < OPAL_PASSWORD_MAX_LENGTH; Index++) {\r
+ if (Password[Index] != 0) {\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Save hdd password to SMM.\r
+\r
+ @param[in] DevicePath Input device path info for the device.\r
+ @param[in] Password The hdd password of attached ATA device.\r
+ @param[in] PasswordLength The hdd password length.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Insufficient resources to create database record\r
+ @retval EFI_SUCCESS The function has been successfully executed.\r
+\r
+**/\r
+EFI_STATUS\r
+OpalSavePasswordToSmm (\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ IN UINT8 *Password,\r
+ IN UINT8 PasswordLength\r
+ )\r
+{\r
+ OPAL_DISK_AND_PASSWORD_INFO *List;\r
+ OPAL_DISK_AND_PASSWORD_INFO *Dev;\r
+ LIST_ENTRY *Entry;\r
+ UINTN DevicePathLen;\r
+\r
+ DevicePathLen = GetDevicePathSize (DevicePath);\r
+\r
+ for (Entry = mDeviceList.ForwardLink; Entry != &mDeviceList; Entry = Entry->ForwardLink) {\r
+ List = BASE_CR (Entry, OPAL_DISK_AND_PASSWORD_INFO, Link);\r
+ if (CompareMem (&List->OpalDevicePath, DevicePath, DevicePathLen) == 0) {\r
+ CopyMem(List->Password, Password, OPAL_PASSWORD_MAX_LENGTH);\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ Dev = AllocateZeroPool (OFFSET_OF (OPAL_DISK_AND_PASSWORD_INFO, OpalDevicePath) + DevicePathLen);\r
+ if (Dev == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Dev->PasswordLength = PasswordLength;\r
+ CopyMem(&(Dev->Password), Password, OPAL_PASSWORD_MAX_LENGTH);\r
+ CopyMem(&(Dev->OpalDevicePath), DevicePath, DevicePathLen);\r
+\r
+ InsertHeadList (&mDeviceList, &Dev->Link);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Communication service SMI Handler entry.\r
+\r
+ This SMI handler provides services for saving HDD password and saving S3 boot script when ready to boot.\r
+\r
+ @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
+ @param[in] RegisterContext Points to an optional handler context which was specified when the\r
+ handler was registered.\r
+ @param[in, out] CommBuffer A pointer to a collection of Data in memory that will\r
+ be conveyed from a non-SMM environment into an SMM environment.\r
+ @param[in, out] CommBufferSize The Size of the CommBuffer.\r
+\r
+ @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers\r
+ should still be called.\r
+ @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should\r
+ still be called.\r
+ @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still\r
+ be called.\r
+ @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.\r
+**/\r
+EFI_STATUS\r
+SmmOpalPasswordHandler (\r
+ IN EFI_HANDLE DispatchHandle,\r
+ IN CONST VOID *RegisterContext,\r
+ IN OUT VOID *CommBuffer,\r
+ IN OUT UINTN *CommBufferSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ OPAL_SMM_COMMUNICATE_HEADER *SmmFunctionHeader;\r
+ UINTN TempCommBufferSize;\r
+ UINT8 *NewPassword;\r
+ UINT8 PasswordLength;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+\r
+ if (CommBuffer == NULL || CommBufferSize == NULL) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ TempCommBufferSize = *CommBufferSize;\r
+ if (TempCommBufferSize < OFFSET_OF (OPAL_SMM_COMMUNICATE_HEADER, Data)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+ SmmFunctionHeader = (OPAL_SMM_COMMUNICATE_HEADER *)CommBuffer;\r
+\r
+ DevicePath = &((OPAL_COMM_DEVICE_LIST*)(SmmFunctionHeader->Data))->OpalDevicePath;\r
+ PasswordLength = ((OPAL_COMM_DEVICE_LIST*)(SmmFunctionHeader->Data))->PasswordLength;\r
+ NewPassword = ((OPAL_COMM_DEVICE_LIST*)(SmmFunctionHeader->Data))->Password;\r
+\r
+ switch (SmmFunctionHeader->Function) {\r
+ case SMM_FUNCTION_SET_OPAL_PASSWORD:\r
+ if (OpalPasswordIsFullZero (NewPassword) || PasswordLength == 0) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto EXIT;\r
+ }\r
+\r
+ Status = OpalSavePasswordToSmm (DevicePath, NewPassword, PasswordLength);\r
+ break;\r
+\r
+ default:\r
+ Status = EFI_UNSUPPORTED;\r
+ break;\r
+ }\r
+\r
+EXIT:\r
+ SmmFunctionHeader->ReturnStatus = Status;\r
+\r
+ //\r
+ // Return EFI_SUCCESS cause only one handler can be trigged.\r
+ // so return EFI_WARN_INTERRUPT_SOURCE_PENDING to make all handler can be trigged.\r
+ //\r
+ return EFI_WARN_INTERRUPT_SOURCE_PENDING;\r
+}\r
+\r
+/**\r
+ The constructor function.\r
+\r
+ Register SMI handler when link to SMM driver.\r
+\r
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalPasswordSupportLibConstructor (\r
+ VOID\r
+ )\r
+{\r
+ EFI_SMM_BASE2_PROTOCOL *SmmBase2;\r
+ EFI_SMM_SYSTEM_TABLE2 *Smst;\r
+ EFI_HANDLE SmmHandle;\r
+ EFI_STATUS Status;\r
+\r
+ Status = gBS->LocateProtocol (&gEfiSmmBase2ProtocolGuid, NULL, (VOID**) &SmmBase2);\r
+ if (EFI_ERROR (Status)) {\r
+ return RETURN_SUCCESS;\r
+ }\r
+ Status = SmmBase2->InSmm (SmmBase2, &gInSmm);\r
+ if (EFI_ERROR (Status)) {\r
+ return RETURN_SUCCESS;\r
+ }\r
+ if (!gInSmm) {\r
+ return RETURN_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Good, we are in SMM\r
+ //\r
+ Status = SmmBase2->GetSmstLocation (SmmBase2, &Smst);\r
+ if (EFI_ERROR (Status)) {\r
+ return RETURN_SUCCESS;\r
+ }\r
+\r
+ SmmHandle = NULL;\r
+ Status = Smst->SmiHandlerRegister (SmmOpalPasswordHandler, &gOpalPasswordNotifyProtocolGuid, &SmmHandle);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ The Destructor function.\r
+\r
+ Clean the saved opal device list.\r
+\r
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OpalPasswordSupportLibDestructor (\r
+ VOID\r
+ )\r
+{\r
+ OPAL_DISK_AND_PASSWORD_INFO *Device;\r
+\r
+ while (!IsListEmpty (&mDeviceList)) {\r
+ Device = BASE_CR (mDeviceList.ForwardLink, OPAL_DISK_AND_PASSWORD_INFO, Link);\r
+\r
+ RemoveEntryList (&Device->Link);\r
+ FreePool (Device);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r