]> git.proxmox.com Git - mirror_edk2.git/commitdiff
SecurityPkg: TcgStorageOpalLib: Add TCG storage opal library.
authorEric Dong <eric.dong@intel.com>
Tue, 29 Mar 2016 06:42:13 +0000 (14:42 +0800)
committerFeng Tian <feng.tian@intel.com>
Tue, 29 Mar 2016 07:37:30 +0000 (15:37 +0800)
Library APIs used to create commands defined by TCG storage opal spec.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Eric Dong <eric.dong@intel.com>
Reviewed-by: Feng Tian <feng.tian@intel.com>
SecurityPkg/Include/Library/TcgStorageOpalLib.h [new file with mode: 0644]
SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalCore.c [new file with mode: 0644]
SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalLib.inf [new file with mode: 0644]
SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalUtil.c [new file with mode: 0644]

diff --git a/SecurityPkg/Include/Library/TcgStorageOpalLib.h b/SecurityPkg/Include/Library/TcgStorageOpalLib.h
new file mode 100644 (file)
index 0000000..a9b4f2f
--- /dev/null
@@ -0,0 +1,831 @@
+/** @file\r
+  Public API for Opal Core 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
+#ifndef _OPAL_CORE_H_\r
+#define _OPAL_CORE_H_\r
+\r
+#include <IndustryStandard/TcgStorageOpal.h>\r
+\r
+#include <Library/TcgStorageCoreLib.h>\r
+#include <Protocol/StorageSecurityCommand.h>\r
+\r
+#pragma pack(1)\r
+\r
+typedef struct {\r
+    //\r
+    // Opal SSC 1 support  (0 - not supported, 1 - supported)\r
+    //\r
+    UINT32 OpalSsc1 : 1;\r
+\r
+    //\r
+    // Opal SSC 2support  (0 - not supported, 1 - supported)\r
+    //\r
+    UINT32 OpalSsc2 : 1;\r
+\r
+    //\r
+    // Opal SSC Lite support  (0 - not supported, 1 - supported)\r
+    //\r
+    UINT32 OpalSscLite : 1;\r
+\r
+    //\r
+    // Pyrite SSC support  (0 - not supported, 1 - supported)\r
+    //\r
+    UINT32 PyriteSsc : 1;\r
+\r
+    //\r
+    // Security protocol 1 support  (0 - not supported, 1 - supported)\r
+    //\r
+    UINT32 Sp1 : 1;\r
+\r
+    //\r
+    // Security protocol 2 support  (0 - not supported, 1 - supported)\r
+    //\r
+    UINT32 Sp2 : 1;\r
+\r
+    //\r
+    // Security protocol IEEE1667 support  (0 - not supported, 1 - supported)\r
+    //\r
+    UINT32 SpIeee1667 : 1;\r
+\r
+    //\r
+    // Media encryption supported (0 - not supported, 1 - supported)\r
+    //\r
+    UINT32 MediaEncryption : 1;\r
+\r
+    //\r
+    // Initial C_PIN_SID PIN Indicator\r
+    //  0 - The initial C_PIN_SID PIN value is NOT equal to the C_PIN_MSID PIN value\r
+    //  1 - The initial C_PIN_SID PIN value is equal to the C_PIN_MSID PIN value\r
+    //\r
+    UINT32 InitCpinIndicator : 1;\r
+\r
+    //\r
+    // Behavior of C_PIN_SID PIN upon TPer Revert\r
+    //  0 - The initial C_PIN_SID PIN value is NOT equal to the C_PIN_MSID PIN value\r
+    //  1 - The initial C_PIN_SID PIN value is equal to the C_PIN_MSID PIN value\r
+    //\r
+    UINT32 CpinUponRevert : 1;\r
+} OPAL_DISK_SUPPORT_ATTRIBUTE;\r
+\r
+//\r
+// Opal device ownership type\r
+// The type indicates who was the determined owner of the device.\r
+//\r
+typedef enum {\r
+    //\r
+    // Represents the device ownership is unknown because starting a session as the SID authority with the ADMIN SP\r
+    //was unsuccessful with the provided PIN\r
+    //\r
+    OpalOwnershipUnknown,\r
+\r
+    //\r
+    // Represents that the ADMIN SP SID authority contains the same PIN as the MSID PIN\r
+    //\r
+    OpalOwnershipNobody,\r
+} OPAL_OWNER_SHIP;\r
+\r
+//\r
+// Structure that is used to represent an Opal session.\r
+// The structure must be initialized by calling OpalStartSession before being used as a parameter\r
+// for any other Opal function.\r
+// This structure should NOT be directly modified by the client of this library.\r
+//\r
+//\r
+typedef struct  {\r
+    UINT32                                 HostSessionId;\r
+    UINT32                                 TperSessionId;\r
+    UINT16                                 ComIdExtension;\r
+\r
+    UINT16                                 OpalBaseComId;\r
+\r
+    EFI_STORAGE_SECURITY_COMMAND_PROTOCOL  *Sscp;\r
+    UINT32                                 MediaId;\r
+} OPAL_SESSION;\r
+#pragma pack()\r
+\r
+/**\r
+\r
+  The function fills in the provided Buffer with the supported protocol list\r
+  of the device specified.\r
+\r
+  @param[in]        Session         OPAL_SESSION data.\r
+  @param[in]        BufferSize      Size of Buffer provided (in bytes)\r
+  @param[in]        BuffAddress     Buffer address to fill with security protocol list\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalRetrieveSupportedProtocolList(\r
+  OPAL_SESSION     *Session,\r
+  UINTN            BufferSize,\r
+  VOID             *BuffAddress\r
+  );\r
+\r
+/**\r
+\r
+  The function fills in the provided Buffer with the level 0 discovery Header\r
+  of the device specified.\r
+\r
+  @param[in]        Session         OPAL_SESSION data.\r
+  @param[in]        BufferSize      Size of Buffer provided (in bytes)\r
+  @param[in]        BuffAddress     Buffer address to fill with Level 0 Discovery response\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalRetrieveLevel0DiscoveryHeader(\r
+  OPAL_SESSION     *Session,\r
+  UINTN            BufferSize,\r
+  VOID             *BuffAddress\r
+  );\r
+\r
+/**\r
+  Starts a session with a security provider (SP).\r
+\r
+  If a session is started successfully, the caller must end the session with OpalEndSession when finished\r
+  performing Opal actions.\r
+\r
+  @param[in/out]  Session                 OPAL_SESSION to initialize.\r
+  @param[in]      SpId                    Security provider ID to start the session with.\r
+  @param[in]      Write                   Whether the session should be read-only (FALSE) or read/write (TRUE).\r
+  @param[in]      HostChallengeLength     Length of the host challenge.  Length should be 0 if hostChallenge is NULL\r
+  @param[in]      HostChallenge           Host challenge for Host Signing Authority.  If NULL, then no Host Challenge will be sent.\r
+  @param[in]      HostSigningAuthority    Host Signing Authority used for start session.  If NULL, then no Host Signing Authority will be sent.\r
+  @param[in/out]  MethodStatus            Status of the StartSession method; only valid if TcgResultSuccess is returned.\r
+\r
+  @return TcgResultSuccess indicates that the function completed without any internal errors.\r
+  The caller must inspect the MethodStatus field to determine whether the method completed successfully.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalStartSession(\r
+  OPAL_SESSION     *Session,\r
+  TCG_UID          SpId,\r
+  BOOLEAN          Write,\r
+  UINT32           HostChallengeLength,\r
+  const VOID       *HostChallenge,\r
+  TCG_UID          HostSigningAuthority,\r
+  UINT8            *MethodStatus\r
+  );\r
+\r
+/**\r
+  Close a session opened with OpalStartSession.\r
+\r
+  @param[in/out]  Session                 OPAL_SESSION to end.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalEndSession(\r
+  OPAL_SESSION     *Session\r
+  );\r
+\r
+/**\r
+\r
+  Reverts device using Admin SP Revert method.\r
+\r
+  @param[in]  AdminSpSession      OPAL_SESSION with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY to perform PSID revert.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalPsidRevert(\r
+  OPAL_SESSION              *AdminSpSession\r
+  );\r
+\r
+\r
+/**\r
+\r
+  The function retrieves the MSID from the device specified\r
+\r
+  @param[in]  AdminSpSession      OPAL_SESSION with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY to perform PSID revert.\r
+  @param[in]  MsidBufferSize      Allocated buffer size (in bytes) for MSID allocated by caller\r
+  @param[in]  Msid                Variable length byte sequence representing MSID of device\r
+  @param[in]  MsidLength          Actual length of MSID retrieved from device\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalGetMsid(\r
+  OPAL_SESSION    *AdminSpSession,\r
+  UINT32          MsidBufferSize,\r
+  UINT8           *Msid,\r
+  UINT32          *MsidLength\r
+  );\r
+\r
+/**\r
+\r
+  The function activates the Locking SP.\r
+  Once activated, per Opal spec, the ADMIN SP SID PIN is copied over to the ADMIN1 LOCKING SP PIN.\r
+  If the Locking SP is already enabled, then TcgResultSuccess is returned and no action occurs.\r
+\r
+  @param[in]      AdminSpSession      OPAL_SESSION with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_SID_AUTHORITY to activate Locking SP\r
+  @param[in/out]  MethodStatus        Method status of last action performed.  If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalActivateLockingSp(\r
+  OPAL_SESSION           *AdminSpSession,\r
+  UINT8                  *MethodStatus\r
+  );\r
+\r
+\r
+/**\r
+\r
+  The function sets the PIN column of the specified cpinRowUid (authority) with the newPin value.\r
+\r
+  @param[in/out]  Session                 OPAL_SESSION to set password\r
+  @param[in]      CpinRowUid              UID of row (authority) to update PIN column\r
+  @param[in]      NewPin                  New Pin to set for cpinRowUid specified\r
+  @param[in]      NewPinLength            Length in bytes of newPin\r
+  @param[in/out]  MethodStatus            Method status of last action performed.  If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalSetPassword(\r
+  OPAL_SESSION   *Session,\r
+  TCG_UID        CpinRowUid,\r
+  const VOID     *NewPin,\r
+  UINT32         NewPinLength,\r
+  UINT8          *MethodStatus\r
+  );\r
+\r
+/**\r
+\r
+  The function retrieves the active key of the global locking range\r
+  and calls the GenKey method on the active key retrieved.\r
+\r
+  @param[in]        LockingSpSession    OPAL_SESSION with OPAL_UID_LOCKING_SP to generate key\r
+  @param[in/out]    MethodStatus        Method status of last action performed.  If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalGlobalLockingRangeGenKey(\r
+  OPAL_SESSION   *LockingSpSession,\r
+  UINT8          *MethodStatus\r
+  );\r
+\r
+\r
+/**\r
+\r
+  The function updates the ReadLocked and WriteLocked columns of the Global Locking Range.\r
+  This funciton is required for a user1 authority, since a user1 authority shall only have access to ReadLocked and WriteLocked columns\r
+  (not ReadLockEnabled and WriteLockEnabled columns).\r
+\r
+  @param[in]      LockingSpSession    OPAL_SESSION with OPAL_UID_LOCKING_SP to generate key\r
+  @param[in]      ReadLocked          Value to set ReadLocked column for Global Locking Range\r
+  @param[in]      WriteLocked         Value to set WriteLocked column for Global Locking Range\r
+  @param[in/out]  MethodStatus        Method status of last action performed.  If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalUpdateGlobalLockingRange(\r
+  OPAL_SESSION             *LockingSpSession,\r
+  BOOLEAN                  ReadLocked,\r
+  BOOLEAN                  WriteLocked,\r
+  UINT8                    *MethodStatus\r
+  );\r
+\r
+\r
+/**\r
+\r
+  The function updates the RangeStart, RangeLength, ReadLockedEnabled, WriteLockedEnabled, ReadLocked and WriteLocked columns\r
+  of the specified Locking Range.  This function requires admin authority of a locking SP session.\r
+\r
+  @param[in]      LockingSpSession    OPAL_SESSION with OPAL_UID_LOCKING_SP to generate key\r
+  @param[in]      LockingRangeUid     Locking range UID to set values\r
+  @param[in]      RangeStart          Value to set RangeStart column for Locking Range\r
+  @param[in]      RangeLength         Value to set RangeLength column for Locking Range\r
+  @param[in]      ReadLockEnabled     Value to set readLockEnabled column for Locking Range\r
+  @param[in]      WriteLockEnabled    Value to set writeLockEnabled column for Locking Range\r
+  @param[in]      ReadLocked          Value to set ReadLocked column for Locking Range\r
+  @param[in]      WriteLocked         Value to set WriteLocked column for Locking Range\r
+  @param[in/out]  MethodStatus        Method status of last action performed.  If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalSetLockingRange(\r
+  OPAL_SESSION     *LockingSpSession,\r
+  TCG_UID          LockingRangeUid,\r
+  UINT64           RangeStart,\r
+  UINT64           RangeLength,\r
+  BOOLEAN          ReadLockEnabled,\r
+  BOOLEAN          WriteLockEnabled,\r
+  BOOLEAN          ReadLocked,\r
+  BOOLEAN          WriteLocked,\r
+  UINT8            *MethodStatus\r
+  );\r
+\r
+/**\r
+\r
+  The function sets the Enabled column to TRUE for the authorityUid provided and updates the PIN column for the cpinRowUid provided\r
+  using the newPin provided.  AuthorityUid and cpinRowUid should describe the same authority.\r
+\r
+  @param[in]      LockingSpSession    OPAL_SESSION with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY to update\r
+  @param[in]      CpinRowUid          Row UID of C_PIN table of Locking SP to update PIN\r
+  @param[in]      AuthorityUid        UID of Locking SP authority to update Pin column with\r
+  @param[in]      NewPin              New Password used to set Pin column\r
+  @param[in]      NewPinLength        Length in bytes of new password\r
+  @param[in/out]  MethodStatus        Method status of last action performed.  If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalSetLockingSpAuthorityEnabledAndPin(\r
+  OPAL_SESSION    *LockingSpSession,\r
+  TCG_UID         CpinRowUid,\r
+  TCG_UID         AuthorityUid,\r
+  const VOID      *NewPin,\r
+  UINT32          NewPinLength,\r
+  UINT8           *MethodStatus\r
+  );\r
+\r
+\r
+/**\r
+\r
+  The function sets the Enabled column to FALSE for the USER1 authority.\r
+\r
+  @param[in]      LockingSpSession    OPAL_SESSION with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY to disable User1\r
+  @param[in/out]  MethodStatus        Method status of last action performed.  If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalDisableUser(\r
+  OPAL_SESSION     *LockingSpSession,\r
+  UINT8            *MethodStatus\r
+  );\r
+\r
+\r
+/**\r
+\r
+  The function calls the Admin SP RevertSP method on the Locking SP.  If KeepUserData is True, then the optional parameter\r
+  to keep the user data is set to True, otherwise the optional parameter is not provided.\r
+\r
+  @param[in]      LockingSpSession    OPAL_SESSION with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY to revertSP\r
+  @param[in]      KeepUserData        Specifies whether or not to keep user data when performing RevertSP action. True = keeps user data.\r
+  @param[in/out]  MethodStatus        Method status of last action performed.  If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalAdminRevert(\r
+  OPAL_SESSION    *LockingSpSession,\r
+  BOOLEAN         KeepUserData,\r
+  UINT8           *MethodStatus\r
+  );\r
+\r
+\r
+/**\r
+\r
+  The function retrieves the TryLimit column for the specified rowUid (authority).\r
+\r
+  @param[in]      LockingSpSession    OPAL_SESSION with OPAL_UID_LOCKING_SP to retrieve try limit\r
+  @param[in]      RowUid              Row UID of the Locking SP C_PIN table to retrieve TryLimit column\r
+  @param[in/out]  TryLimit            Value from TryLimit column\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalGetTryLimit(\r
+  OPAL_SESSION   *LockingSpSession,\r
+  TCG_UID        RowUid,\r
+  UINT32         *TryLimit\r
+  );\r
+\r
+\r
+/**\r
+\r
+  The function populates the CreateStruct with a payload that will retrieve the global locking range active key.\r
+  It is intended to be called with a session that is already started with a valid credential.\r
+  The function does not send the payload.\r
+\r
+  @param[in]      Session        OPAL_SESSION to populate command for, needs comId\r
+  @param[in/out]  CreateStruct   Structure to populate with encoded TCG command\r
+  @param[in/out]  Size           Size in bytes of the command created.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalCreateRetrieveGlobalLockingRangeActiveKey(\r
+  const OPAL_SESSION    *Session,\r
+  TCG_CREATE_STRUCT     *CreateStruct,\r
+  UINT32                *Size\r
+  );\r
+\r
+\r
+/**\r
+\r
+  The function acquires the activeKey specified for the Global Locking Range from the parseStruct.\r
+\r
+  @param[in]      ParseStruct    Structure that contains the device's response with the activekey\r
+  @param[in/out]  ActiveKey      The UID of the active key retrieved\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalParseRetrieveGlobalLockingRangeActiveKey(\r
+  TCG_PARSE_STRUCT  *ParseStruct,\r
+  TCG_UID           *ActiveKey\r
+  );\r
+\r
+/**\r
+\r
+  Get the support attribute info.\r
+\r
+  @param[in]      Session             OPAL_SESSION with OPAL_UID_LOCKING_SP to retrieve info.\r
+  @param[in/out]  LockingFeature      Return the Locking info.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalGetLockingInfo(\r
+  OPAL_SESSION                     *Session,\r
+  TCG_LOCKING_FEATURE_DESCRIPTOR   *LockingFeature\r
+  );\r
+\r
+/**\r
+\r
+  The function determines whether or not all of the requirements for the Opal Feature (not full specification)\r
+  are met by the specified device.\r
+\r
+  @param[in]      SupportedAttributes     Opal device attribute.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+OpalFeatureSupported(\r
+  OPAL_DISK_SUPPORT_ATTRIBUTE      *SupportedAttributes\r
+  );\r
+\r
+/**\r
+\r
+  The function returns whether or not the device is Opal Enabled.\r
+  TRUE means that the device is partially or fully locked.\r
+  This will perform a Level 0 Discovery and parse the locking feature descriptor\r
+\r
+  @param[in]      SupportedAttributes     Opal device attribute.\r
+  @param[in]      LockingFeature          Opal device locking status.\r
+\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+OpalFeatureEnabled(\r
+  OPAL_DISK_SUPPORT_ATTRIBUTE      *SupportedAttributes,\r
+  TCG_LOCKING_FEATURE_DESCRIPTOR   *LockingFeature\r
+  );\r
+\r
+/**\r
+\r
+  The function returns whether or not the device is Opal Locked.\r
+  TRUE means that the device is partially or fully locked.\r
+  This will perform a Level 0 Discovery and parse the locking feature descriptor\r
+\r
+  @param[in]      SupportedAttributes     Opal device attribute.\r
+  @param[in]      LockingFeature          Opal device locking status.\r
+\r
+**/\r
+BOOLEAN\r
+OpalDeviceLocked(\r
+  OPAL_DISK_SUPPORT_ATTRIBUTE      *SupportedAttributes,\r
+  TCG_LOCKING_FEATURE_DESCRIPTOR   *LockingFeature\r
+  );\r
+\r
+/**\r
+  Trig the block sid action.\r
+\r
+  @param[in]      Session            OPAL_SESSION to populate command for, needs comId\r
+  @param[in]      HardwareReset      Whether need to do hardware reset.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalBlockSid(\r
+  OPAL_SESSION                           *Session,\r
+  BOOLEAN                                HardwareReset\r
+  );\r
+\r
+/**\r
+\r
+  Get the support attribute info.\r
+\r
+  @param[in]      Session             OPAL_SESSION with OPAL_UID_LOCKING_SP to retrieve info.\r
+  @param[in/out]  SupportedAttributes Return the support attribute info.\r
+  @param[out]     OpalBaseComId       Return the base com id info.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalGetSupportedAttributesInfo(\r
+  OPAL_SESSION                 *Session,\r
+  OPAL_DISK_SUPPORT_ATTRIBUTE  *SupportedAttributes,\r
+  UINT16                       *OpalBaseComId\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]      AdminSpSession     OPAL_SESSION to populate command for, needs comId\r
+  @param[in]      Psid               PSID of device to revert.\r
+  @param[in]      PsidLength         Length of PSID in bytes.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalUtilPsidRevert(\r
+  OPAL_SESSION   *AdminSpSession,\r
+  const VOID     *Psid,\r
+  UINT32         PsidLength\r
+  );\r
+\r
+/**\r
+  Opens a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_SID_AUTHORITY,\r
+  sets the OPAL_UID_ADMIN_SP_C_PIN_SID column with the new password,\r
+  and activates the locking SP to copy SID PIN to Admin1 Locking SP PIN.\r
+\r
+  @param[in]      AdminSpSession     OPAL_SESSION to populate command for, needs comId\r
+  @param[in]      GeneratedSid       Generated SID of disk\r
+  @param[in]      SidLength          Length of generatedSid in bytes\r
+  @param[in]      Password           New admin password to set\r
+  @param[in]      PassLength         Length of password in bytes\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalUtilSetAdminPasswordAsSid(\r
+  OPAL_SESSION      *AdminSpSession,\r
+  const VOID        *GeneratedSid,\r
+  UINT32            SidLength,\r
+  const VOID        *Password,\r
+  UINT32            PassLength\r
+  );\r
+\r
+/**\r
+\r
+  Opens a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY,\r
+  and updates the specified locking range with the provided column values.\r
+\r
+  @param[in]      LockingSpSession   OPAL_SESSION to populate command for, needs comId\r
+  @param[in]      Password           New admin password to set\r
+  @param[in]      PassLength         Length of password in bytes\r
+  @param[in]      LockingRangeUid    Locking range UID to set values\r
+  @param[in]      RangeStart         Value to set RangeStart column for Locking Range\r
+  @param[in]      RangeLength        Value to set RangeLength column for Locking Range\r
+  @param[in]      ReadLockEnabled    Value to set readLockEnabled column for Locking Range\r
+  @param[in]      WriteLockEnabled   Value to set writeLockEnabled column for Locking Range\r
+  @param[in]      ReadLocked         Value to set ReadLocked column for Locking Range\r
+  @param[in]      WriteLocked        Value to set WriteLocked column for Locking Range\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalUtilSetOpalLockingRange(\r
+  OPAL_SESSION   *LockingSpSession,\r
+  const VOID     *Password,\r
+  UINT32         PassLength,\r
+  TCG_UID        LockingRangeUid,\r
+  UINT64         RangeStart,\r
+  UINT64         RangeLength,\r
+  BOOLEAN        ReadLockEnabled,\r
+  BOOLEAN        WriteLockEnabled,\r
+  BOOLEAN        ReadLocked,\r
+  BOOLEAN        WriteLocked\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]      AdminSpSession     OPAL_SESSION to populate command for, needs comId\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
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalUtilSetAdminPassword(\r
+  OPAL_SESSION  *AdminSpSession,\r
+  const VOID    *OldPassword,\r
+  UINT32        OldPasswordLength,\r
+  const VOID    *NewPassword,\r
+  UINT32        NewPasswordLength\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 sets the User1 SP authority to enabled and sets the User1 password.\r
+\r
+  @param[in]      LockingSpSession   OPAL_SESSION to populate command for, needs comId\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
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalUtilSetUserPassword(\r
+  OPAL_SESSION    *LockingSpSession,\r
+  const VOID      *OldPassword,\r
+  UINT32          OldPasswordLength,\r
+  const VOID      *NewPassword,\r
+  UINT32          NewPasswordLength\r
+  );\r
+\r
+/**\r
+  Verify whether user input the correct password.\r
+\r
+  @param[in]      LockingSpSession            OPAL_SESSION to populate command for, needs comId\r
+  @param[in]      Password                    Admin password\r
+  @param[in]      PasswordLength              Length of password in bytes\r
+  @param[in/out]  HostSigningAuthority        Use the Host signing authority type.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalUtilVerifyPassword (\r
+  OPAL_SESSION   *LockingSpSession,\r
+  const VOID     *Password,\r
+  UINT32         PasswordLength,\r
+  TCG_UID        HostSigningAuthority\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 generates a new global locking range key to erase the Data.\r
+\r
+  @param[in]      LockingSpSession     OPAL_SESSION to populate command for, needs comId\r
+  @param[in]      Password             Admin or user password\r
+  @param[in]      PasswordLength       Length of password in bytes\r
+  @param[in/out]  PasswordFailed       indicates if password failed (start session didn't work)\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalUtilSecureErase(\r
+  OPAL_SESSION     *LockingSpSession,\r
+  const VOID       *Password,\r
+  UINT32           PasswordLength,\r
+  BOOLEAN          *PasswordFailed\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]      LockingSpSession      OPAL_SESSION to populate command for, needs comId\r
+  @param[in]      Password              Admin password\r
+  @param[in]      PasswordLength        Length of password in bytes\r
+  @param[in/out]  PasswordFailed        indicates if password failed (start session didn't work)\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalUtilDisableUser(\r
+  OPAL_SESSION   *LockingSpSession,\r
+  const VOID     *Password,\r
+  UINT32         PasswordLength,\r
+  BOOLEAN        *PasswordFailed\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]      LockingSpSession      OPAL_SESSION to populate command for, needs comId\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/out]  PasswordFailed     indicates if password failed (start session didn't work)\r
+  @param[in]      Msid               Input Msid info.\r
+  @param[in]      MsidLength         Input Msid info length.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalUtilRevert(\r
+  OPAL_SESSION     *LockingSpSession,\r
+  BOOLEAN          KeepUserData,\r
+  const VOID       *Password,\r
+  UINT32           PasswordLength,\r
+  BOOLEAN          *PasswordFailed,\r
+  UINT8            *Msid,\r
+  UINT32           MsidLength\r
+  );\r
+\r
+/**\r
+  After revert success, set SID to MSID.\r
+\r
+  @param[in]      AdminSpSession     OPAL_SESSION to populate command for, needs comId\r
+  @param          Password,          Input password info.\r
+  @param          PasswordLength,    Input password length.\r
+  @param[in]      Msid               Input Msid info.\r
+  @param[in]      MsidLength         Input Msid info length.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalUtilSetSIDtoMSID (\r
+  OPAL_SESSION     *AdminSpSession,\r
+  const VOID       *Password,\r
+  UINT32           PasswordLength,\r
+  UINT8            *Msid,\r
+  UINT32           MsidLength\r
+  );\r
+\r
+/**\r
+  Update global locking range.\r
+\r
+  @param[in]      LockingSpSession   OPAL_SESSION to populate command for, needs comId\r
+  @param          Password,          Input password info.\r
+  @param          PasswordLength,    Input password length.\r
+  @param          ReadLocked,        Read lock info.\r
+  @param          WriteLocked        write lock info.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalUtilUpdateGlobalLockingRange(\r
+  OPAL_SESSION    *LockingSpSession,\r
+  const VOID      *Password,\r
+  UINT32          PasswordLength,\r
+  BOOLEAN         ReadLocked,\r
+  BOOLEAN         WriteLocked\r
+  );\r
+\r
+/**\r
+  Update global locking range.\r
+\r
+  @param          Session,           The session info for one opal device.\r
+  @param          Msid,              The data buffer to save Msid info.\r
+  @param          MsidBufferLength,  The data buffer length for Msid.\r
+  @param          MsidLength,        The actual data length for Msid.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalUtilGetMsid(\r
+  OPAL_SESSION    *Session,\r
+  UINT8           *Msid,\r
+  UINT32          MsidBufferLength,\r
+  UINT32          *MsidLength\r
+  );\r
+\r
+/**\r
+\r
+  The function determines who owns the device by attempting to start a session with different credentials.\r
+  If the SID PIN matches the MSID PIN, the no one owns the device.\r
+  If the SID PIN matches the ourSidPin, then "Us" owns the device.  Otherwise it is unknown.\r
+\r
+\r
+  @param[in]      Session            The session info for one opal device.\r
+  @param          Msid,              The Msid info.\r
+  @param          MsidLength,        The data length for Msid.\r
+\r
+**/\r
+OPAL_OWNER_SHIP\r
+EFIAPI\r
+OpalUtilDetermineOwnership(\r
+  OPAL_SESSION       *Session,\r
+  UINT8              *Msid,\r
+  UINT32             MsidLength\r
+  );\r
+\r
+/**\r
+\r
+  The function returns if admin password exists.\r
+\r
+  @param[in]      OwnerShip         The owner ship of the opal device.\r
+  @param[in]      LockingFeature    The locking info of the opal device.\r
+\r
+  @retval         TRUE              Admin password existed.\r
+  @retval         FALSE             Admin password not existed.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+OpalUtilAdminPasswordExists(\r
+  IN  UINT16                           OwnerShip,\r
+  IN  TCG_LOCKING_FEATURE_DESCRIPTOR   *LockingFeature\r
+  );\r
+\r
+#endif // _OPAL_CORE_H_\r
diff --git a/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalCore.c b/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalCore.c
new file mode 100644 (file)
index 0000000..234909b
--- /dev/null
@@ -0,0 +1,1653 @@
+/** @file\r
+  Public API for Opal Core 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 <uefi.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/TcgStorageOpalLib.h>\r
+\r
+#pragma pack(1)\r
+typedef struct {\r
+    UINT8 HardwareReset : 1;\r
+    UINT8 Reserved : 7;\r
+} TCG_BLOCK_SID_CLEAR_EVENTS;\r
+#pragma pack()\r
+\r
+#define TRUSTED_COMMAND_TIMEOUT_NS      ((UINT64) 5 * ((UINT64)(1000000)) * 1000) // 5 seconds\r
+#define BUFFER_SIZE                      512\r
+\r
+/**\r
+  The function performs a Trusted Send of a Buffer containing a TCG_COM_PACKET.\r
+\r
+  @param[in]      Sscp                  The input Ssc Protocol.\r
+  @param[in]      MediaId               The input Media id info used by Ssc Protocol.\r
+  @param[in]      SecurityProtocol      Security Protocol\r
+  @param[in]      SpSpecific            Security Protocol Specific\r
+  @param[in]      TransferLength        Transfer Length of Buffer (in bytes) - always a multiple of 512\r
+  @param[in]      Buffer                Address of Data to transfer\r
+  @param[in]      BufferSize            Full Size of Buffer, including space that may be used for padding.\r
+\r
+**/\r
+TCG_RESULT\r
+OpalTrustedSend(\r
+  EFI_STORAGE_SECURITY_COMMAND_PROTOCOL  *Sscp,\r
+  UINT32                                 MediaId,\r
+  UINT8                                  SecurityProtocol,\r
+  UINT16                                 SpSpecific,\r
+  UINTN                                  TransferLength,\r
+  VOID                                   *Buffer,\r
+  UINTN                                  BufferSize\r
+  )\r
+{\r
+  UINTN       TransferLength512;\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // Round transferLength up to a 512-byte multiple\r
+  //\r
+  TransferLength512 = (TransferLength + 511) & ~(UINTN)511;\r
+\r
+  if (TransferLength512 > BufferSize) {\r
+    return TcgResultFailureBufferTooSmall;\r
+  }\r
+\r
+  ZeroMem((UINT8*)Buffer + TransferLength, TransferLength512 - TransferLength);\r
+\r
+  Status = Sscp->SendData(\r
+               Sscp,\r
+               MediaId,\r
+               TRUSTED_COMMAND_TIMEOUT_NS,\r
+               SecurityProtocol,\r
+               SwapBytes16(SpSpecific),\r
+               TransferLength512,\r
+               Buffer\r
+               );\r
+\r
+  return Status == EFI_SUCCESS ? TcgResultSuccess : TcgResultFailure;\r
+}\r
+\r
+/**\r
+\r
+  The function performs a Trusted Receive of a Buffer containing a TCG_COM_PACKET.\r
+\r
+  @param[in]      Sscp                  The input Ssc Protocol.\r
+  @param[in]      MediaId               The input Media id info used by Ssc Protocol.\r
+  @param[in]      SecurityProtocol      Security Protocol\r
+  @param[in]      SpSpecific            Security Protocol Specific\r
+  @param[in]      Buffer                Address of Data to transfer\r
+  @param[in]      BufferSize            Full Size of Buffer, including space that may be used for padding.\r
+\r
+**/\r
+TCG_RESULT\r
+OpalTrustedRecv(\r
+  EFI_STORAGE_SECURITY_COMMAND_PROTOCOL  *Sscp,\r
+  UINT32                                 MediaId,\r
+  UINT8                                  SecurityProtocol,\r
+  UINT16                                 SpSpecific,\r
+  VOID                                   *Buffer,\r
+  UINTN                                  BufferSize\r
+  )\r
+{\r
+\r
+  UINTN           TransferLength512;\r
+  UINT32          Tries;\r
+  TCG_COM_PACKET  *ComPacket;\r
+  UINT32          Length;\r
+  UINT32          OutstandingData;\r
+  EFI_STATUS      Status;\r
+  UINTN           TransferSize;\r
+\r
+  //\r
+  // Round Buffer Size down to a 512-byte multiple\r
+  //\r
+  TransferLength512 = BufferSize & ~(UINTN)511;\r
+  Tries = 0;\r
+  ComPacket = NULL;\r
+  Length = 0;\r
+  OutstandingData = 0;\r
+\r
+  if (TransferLength512 < sizeof(TCG_COM_PACKET)) {\r
+    DEBUG ((DEBUG_INFO, "transferLength %u too small for ComPacket\n", TransferLength512));\r
+    return TcgResultFailureBufferTooSmall;\r
+  }\r
+\r
+  //\r
+  // Some devices respond with Length = 0 and OutstandingData = 1 to indicate that processing is not yet completed,\r
+  // so we need to retry the IF-RECV to get the actual Data.\r
+  // See TCG Core Spec v2 Table 45 IF-RECV ComPacket Field Values Summary\r
+  // This is an arbitrary number of retries, not from the spec.\r
+  // have a max timeout of 10 seconds, 5000 tries * 2ms = 10s\r
+  //\r
+  Tries = 5000;\r
+  while ((Tries--) > 0) {\r
+    ZeroMem( Buffer, BufferSize );\r
+    TransferSize = 0;\r
+\r
+    Status = Sscp->ReceiveData(\r
+                 Sscp,\r
+                 MediaId,\r
+                 TRUSTED_COMMAND_TIMEOUT_NS,\r
+                 SecurityProtocol,\r
+                 SwapBytes16(SpSpecific),\r
+                 TransferLength512,\r
+                 Buffer,\r
+                 &TransferSize\r
+             );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      return TcgResultFailure;\r
+    }\r
+\r
+    if (SecurityProtocol != TCG_OPAL_SECURITY_PROTOCOL_1 && SecurityProtocol != TCG_OPAL_SECURITY_PROTOCOL_2) {\r
+      return TcgResultSuccess;\r
+    }\r
+\r
+    if (SpSpecific == TCG_SP_SPECIFIC_PROTOCOL_LEVEL0_DISCOVERY) {\r
+      return TcgResultSuccess;\r
+    }\r
+\r
+    ComPacket = (TCG_COM_PACKET*) Buffer;\r
+    Length = SwapBytes32(ComPacket->LengthBE);\r
+    OutstandingData = SwapBytes32( ComPacket->OutstandingDataBE );\r
+\r
+    if (Length != 0 && OutstandingData == 0) {\r
+      return TcgResultSuccess;\r
+    }\r
+\r
+    //\r
+    // Delay for 2 ms\r
+    //\r
+    MicroSecondDelay (2000);\r
+  }\r
+\r
+  return TcgResultFailure;\r
+}\r
+\r
+/**\r
+  The function performs send, recv, check comIDs, check method status action.\r
+\r
+  @param[in]      Session         OPAL_SESSION related to this method..\r
+  @param[in]      SendSize        Transfer Length of Buffer (in bytes) - always a multiple of 512\r
+  @param[in]      Buffer          Address of Data to transfer\r
+  @param[in]      BufferSize      Full Size of Buffer, including space that may be used for padding.\r
+  @param[in]      ParseStruct     Structure used to parse received TCG response.\r
+  @param[in]      MethodStatus    Method status of last action performed.  If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalPerformMethod(\r
+  OPAL_SESSION     *Session,\r
+  UINT32           SendSize,\r
+  VOID             *Buffer,\r
+  UINT32           BufferSize,\r
+  TCG_PARSE_STRUCT *ParseStruct,\r
+  UINT8            *MethodStatus\r
+  )\r
+{\r
+  NULL_CHECK(Session);\r
+  NULL_CHECK(MethodStatus);\r
+\r
+  ERROR_CHECK(OpalTrustedSend(\r
+                  Session->Sscp,\r
+                  Session->MediaId,\r
+                  TCG_OPAL_SECURITY_PROTOCOL_1,\r
+                  Session->OpalBaseComId,\r
+                  SendSize,\r
+                  Buffer,\r
+                  BufferSize\r
+              ));\r
+\r
+  ERROR_CHECK(OpalTrustedRecv(\r
+                  Session->Sscp,\r
+                  Session->MediaId,\r
+                  TCG_OPAL_SECURITY_PROTOCOL_1,\r
+                  Session->OpalBaseComId,\r
+                  Buffer,\r
+                  BufferSize\r
+              ));\r
+\r
+  ERROR_CHECK(TcgInitTcgParseStruct(ParseStruct, Buffer, BufferSize));\r
+  ERROR_CHECK(TcgCheckComIds(ParseStruct, Session->OpalBaseComId, Session->ComIdExtension));\r
+  ERROR_CHECK(TcgGetMethodStatus(ParseStruct, MethodStatus));\r
+\r
+  return TcgResultSuccess;\r
+}\r
+\r
+/**\r
+  Trig the block sid action.\r
+\r
+  @param[in]      Session            OPAL_SESSION related to this method..\r
+  @param[in]      HardwareReset      Whether need to do hardware reset.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalBlockSid(\r
+  OPAL_SESSION                           *Session,\r
+  BOOLEAN                                HardwareReset\r
+  )\r
+{\r
+  UINT8                      Buffer[BUFFER_SIZE];\r
+  TCG_BLOCK_SID_CLEAR_EVENTS *ClearEvents;\r
+\r
+  NULL_CHECK(Session);\r
+\r
+  //\r
+  // Set Hardware Reset bit\r
+  //\r
+  ClearEvents = (TCG_BLOCK_SID_CLEAR_EVENTS *) &Buffer[0];\r
+\r
+  ClearEvents->Reserved = 0;\r
+  ClearEvents->HardwareReset = HardwareReset;\r
+\r
+  return(OpalTrustedSend(\r
+                  Session->Sscp,\r
+                  Session->MediaId,\r
+                  TCG_OPAL_SECURITY_PROTOCOL_2,\r
+                  Session->OpalBaseComId,\r
+                  1,\r
+                  Buffer,\r
+                  BUFFER_SIZE\r
+              ));\r
+}\r
+\r
+/**\r
+\r
+  Reverts device using Admin SP Revert method.\r
+\r
+  @param[in]  AdminSpSession      OPAL_SESSION with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY to perform PSID revert.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalPsidRevert(\r
+  OPAL_SESSION              *AdminSpSession\r
+  )\r
+{\r
+  //\r
+  // Now that base comid is known, start Session\r
+  // we'll attempt to start Session as PSID authority\r
+  // verify PSID Authority is defined in ADMIN SP authority table... is this possible?\r
+  //\r
+  TCG_CREATE_STRUCT  CreateStruct;\r
+  TCG_PARSE_STRUCT   ParseStruct;\r
+  UINT32             Size;\r
+  UINT8              Buffer[BUFFER_SIZE];\r
+  UINT8              MethodStatus;\r
+\r
+  NULL_CHECK(AdminSpSession);\r
+\r
+  //\r
+  // Send Revert action on Admin SP\r
+  //\r
+  ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buffer, BUFFER_SIZE));\r
+  ERROR_CHECK(TcgStartComPacket(&CreateStruct, AdminSpSession->OpalBaseComId, AdminSpSession->ComIdExtension));\r
+  ERROR_CHECK(TcgStartPacket(&CreateStruct, AdminSpSession->TperSessionId, AdminSpSession->HostSessionId, 0x0, 0x0, 0x0));\r
+  ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0));\r
+  ERROR_CHECK(TcgStartMethodCall(&CreateStruct, OPAL_UID_ADMIN_SP, OPAL_ADMIN_SP_REVERT_METHOD));\r
+  ERROR_CHECK(TcgStartParameters(&CreateStruct));\r
+  ERROR_CHECK(TcgEndParameters(&CreateStruct));\r
+  ERROR_CHECK(TcgEndMethodCall(&CreateStruct));\r
+  ERROR_CHECK(TcgEndSubPacket(&CreateStruct));\r
+  ERROR_CHECK(TcgEndPacket(&CreateStruct));\r
+  ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size));\r
+\r
+  //\r
+  // Send Revert Method Call\r
+  //\r
+  ERROR_CHECK(OpalPerformMethod(AdminSpSession, Size, Buffer, BUFFER_SIZE, &ParseStruct, &MethodStatus));\r
+  METHOD_STATUS_ERROR_CHECK(MethodStatus, TcgResultFailure);\r
+\r
+  return TcgResultSuccess;\r
+}\r
+\r
+/**\r
+\r
+  The function fills in the provided Buffer with the level 0 discovery Header\r
+  of the device specified.\r
+\r
+  @param[in]        Session         OPAL_SESSION data.\r
+  @param[in]        BufferSize      Size of Buffer provided (in bytes)\r
+  @param[in]        BuffAddress     Buffer address to fill with Level 0 Discovery response\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalRetrieveLevel0DiscoveryHeader(\r
+  OPAL_SESSION     *Session,\r
+  UINTN            BufferSize,\r
+  VOID             *BuffAddress\r
+  )\r
+{\r
+  return (OpalTrustedRecv(\r
+              Session->Sscp,\r
+              Session->MediaId,\r
+              TCG_OPAL_SECURITY_PROTOCOL_1,   // SP\r
+              TCG_SP_SPECIFIC_PROTOCOL_LEVEL0_DISCOVERY, // SP_Specific\r
+              BuffAddress,\r
+              BufferSize\r
+            ));\r
+}\r
+\r
+/**\r
+\r
+  The function fills in the provided Buffer with the supported protocol list\r
+  of the device specified.\r
+\r
+  @param[in]        Session         OPAL_SESSION data.\r
+  @param[in]        BufferSize      Size of Buffer provided (in bytes)\r
+  @param[in]        BuffAddress     Buffer address to fill with security protocol list\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalRetrieveSupportedProtocolList(\r
+  OPAL_SESSION     *Session,\r
+  UINTN            BufferSize,\r
+  VOID             *BuffAddress\r
+  )\r
+{\r
+  return (OpalTrustedRecv(\r
+              Session->Sscp,\r
+              Session->MediaId,\r
+              TCG_SECURITY_PROTOCOL_INFO, // SP\r
+              TCG_SP_SPECIFIC_PROTOCOL_LIST, // SP_Specific\r
+              BuffAddress,\r
+              BufferSize\r
+          ));\r
+}\r
+\r
+/**\r
+  Starts a session with a security provider (SP).\r
+\r
+  If a session is started successfully, the caller must end the session with OpalEndSession when finished\r
+  performing Opal actions.\r
+\r
+  @param[in/out]  Session                 OPAL_SESSION to initialize.\r
+  @param[in]      SpId                    Security provider ID to start the session with.\r
+  @param[in]      Write                   Whether the session should be read-only (FALSE) or read/write (TRUE).\r
+  @param[in]      HostChallengeLength     Length of the host challenge.  Length should be 0 if hostChallenge is NULL\r
+  @param[in]      HostChallenge           Host challenge for Host Signing Authority.  If NULL, then no Host Challenge will be sent.\r
+  @param[in]      HostSigningAuthority    Host Signing Authority used for start session.  If NULL, then no Host Signing Authority will be sent.\r
+  @param[in/out]  MethodStatus            Status of the StartSession method; only valid if TcgResultSuccess is returned.\r
+\r
+  @return TcgResultSuccess indicates that the function completed without any internal errors.\r
+  The caller must inspect the MethodStatus field to determine whether the method completed successfully.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalStartSession(\r
+  OPAL_SESSION     *Session,\r
+  TCG_UID          SpId,\r
+  BOOLEAN          Write,\r
+  UINT32           HostChallengeLength,\r
+  const VOID       *HostChallenge,\r
+  TCG_UID          HostSigningAuthority,\r
+  UINT8            *MethodStatus\r
+  )\r
+{\r
+  TCG_CREATE_STRUCT CreateStruct;\r
+  TCG_PARSE_STRUCT  ParseStruct;\r
+  UINT32            Size;\r
+  UINT8             Buf[BUFFER_SIZE];\r
+  UINT16            ComIdExtension;\r
+  UINT32            HostSessionId;\r
+\r
+  ComIdExtension = 0;\r
+  HostSessionId  = 1;\r
+\r
+  NULL_CHECK(Session);\r
+  NULL_CHECK(MethodStatus);\r
+\r
+  Session->ComIdExtension = ComIdExtension;\r
+  Session->HostSessionId = HostSessionId;\r
+\r
+  ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));\r
+  ERROR_CHECK(TcgCreateStartSession(\r
+                    &CreateStruct,\r
+                    &Size,\r
+                    Session->OpalBaseComId,\r
+                    ComIdExtension,\r
+                    HostSessionId,\r
+                    SpId,\r
+                    Write,\r
+                    HostChallengeLength,\r
+                    HostChallenge,\r
+                    HostSigningAuthority\r
+                ));\r
+  ERROR_CHECK(OpalPerformMethod(Session, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));\r
+  if (*MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    return TcgResultSuccess; // return early if method failed - user must check MethodStatus\r
+  }\r
+\r
+  if (TcgParseSyncSession(&ParseStruct, Session->OpalBaseComId, ComIdExtension, HostSessionId, &Session->TperSessionId) != TcgResultSuccess) {\r
+    OpalEndSession(Session);\r
+    return TcgResultFailure;\r
+  }\r
+\r
+  return TcgResultSuccess;\r
+}\r
+\r
+/**\r
+  Close a session opened with OpalStartSession.\r
+\r
+  @param[in/out]  Session                 OPAL_SESSION to end.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalEndSession(\r
+  OPAL_SESSION     *Session\r
+  )\r
+{\r
+  UINT8             Buffer[BUFFER_SIZE];\r
+  TCG_CREATE_STRUCT CreateStruct;\r
+  UINT32            Size;\r
+  TCG_PARSE_STRUCT  ParseStruct;\r
+\r
+  NULL_CHECK(Session);\r
+  ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buffer, sizeof(Buffer)));\r
+  ERROR_CHECK(TcgCreateEndSession(\r
+                  &CreateStruct,\r
+                  &Size,\r
+                  Session->OpalBaseComId,\r
+                  Session->ComIdExtension,\r
+                  Session->HostSessionId,\r
+                  Session->TperSessionId\r
+                ));\r
+\r
+  ERROR_CHECK(OpalTrustedSend(\r
+                  Session->Sscp,\r
+                  Session->MediaId,\r
+                  TCG_OPAL_SECURITY_PROTOCOL_1,\r
+                  Session->OpalBaseComId,\r
+                  Size,\r
+                  Buffer,\r
+                  sizeof(Buffer)\r
+              ));\r
+\r
+  ERROR_CHECK(OpalTrustedRecv(\r
+                  Session->Sscp,\r
+                  Session->MediaId,\r
+                  TCG_OPAL_SECURITY_PROTOCOL_1,\r
+                  Session->OpalBaseComId,\r
+                  Buffer,\r
+                  sizeof(Buffer)\r
+              ));\r
+\r
+  ERROR_CHECK(TcgInitTcgParseStruct(&ParseStruct, Buffer, sizeof(Buffer)));\r
+  ERROR_CHECK(TcgCheckComIds(&ParseStruct, Session->OpalBaseComId, Session->ComIdExtension));\r
+\r
+  ERROR_CHECK(TcgGetNextEndOfSession(&ParseStruct));\r
+  return TcgResultSuccess;\r
+}\r
+\r
+/**\r
+\r
+  The function retrieves the MSID from the device specified\r
+\r
+  @param[in]  AdminSpSession      OPAL_SESSION with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY to perform PSID revert.\r
+  @param[in]  MsidBufferSize      Allocated Buffer Size (in bytes) for MSID allocated by caller\r
+  @param[in]  Msid                Variable Length byte sequence representing MSID of device\r
+  @param[in]  MsidLength          Actual Length of MSID retrieved from device\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalGetMsid(\r
+  OPAL_SESSION    *AdminSpSession,\r
+  UINT32          MsidBufferSize,\r
+  UINT8           *Msid,\r
+  UINT32          *MsidLength\r
+  )\r
+{\r
+  //\r
+  // now that base comid is known, start Session\r
+  // we'll attempt to start Session as PSID authority\r
+  // verify PSID Authority is defined in ADMIN SP authority table... is this possible?\r
+  //\r
+  TCG_CREATE_STRUCT CreateStruct;\r
+  TCG_PARSE_STRUCT  ParseStruct;\r
+  UINT32            Size;\r
+  UINT8             MethodStatus;\r
+  UINT32            Col;\r
+  const VOID        *RecvMsid;\r
+  UINT8             Buffer[BUFFER_SIZE];\r
+\r
+  NULL_CHECK(AdminSpSession);\r
+  NULL_CHECK(Msid);\r
+  NULL_CHECK(MsidLength);\r
+\r
+  ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buffer, BUFFER_SIZE));\r
+  ERROR_CHECK(TcgStartComPacket(&CreateStruct, AdminSpSession->OpalBaseComId, AdminSpSession->ComIdExtension));\r
+  ERROR_CHECK(TcgStartPacket(&CreateStruct, AdminSpSession->TperSessionId, AdminSpSession->HostSessionId, 0x0, 0x0, 0x0));\r
+  ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0));\r
+  ERROR_CHECK(TcgStartMethodCall(&CreateStruct, OPAL_UID_ADMIN_SP_C_PIN_MSID, TCG_UID_METHOD_GET));\r
+  ERROR_CHECK(TcgStartParameters(&CreateStruct));\r
+  ERROR_CHECK(TcgAddStartList(&CreateStruct));\r
+  ERROR_CHECK(TcgAddStartName(&CreateStruct));\r
+  ERROR_CHECK(TcgAddUINT8(&CreateStruct, TCG_CELL_BLOCK_START_COLUMN_NAME));\r
+  ERROR_CHECK(TcgAddUINT8(&CreateStruct, OPAL_ADMIN_SP_PIN_COL));\r
+  ERROR_CHECK(TcgAddEndName(&CreateStruct));\r
+  ERROR_CHECK(TcgAddStartName(&CreateStruct));\r
+  ERROR_CHECK(TcgAddUINT8(&CreateStruct, TCG_CELL_BLOCK_END_COLUMN_NAME));\r
+  ERROR_CHECK(TcgAddUINT8(&CreateStruct, OPAL_ADMIN_SP_PIN_COL));\r
+  ERROR_CHECK(TcgAddEndName(&CreateStruct));\r
+  ERROR_CHECK(TcgAddEndList(&CreateStruct));\r
+  ERROR_CHECK(TcgEndParameters(&CreateStruct));\r
+  ERROR_CHECK(TcgEndMethodCall(&CreateStruct));\r
+  ERROR_CHECK(TcgEndSubPacket(&CreateStruct));\r
+  ERROR_CHECK(TcgEndPacket(&CreateStruct));\r
+  ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size));\r
+\r
+  //\r
+  // Send MSID Method Call\r
+  //\r
+  ERROR_CHECK(OpalPerformMethod(AdminSpSession, Size, Buffer, BUFFER_SIZE, &ParseStruct, &MethodStatus));\r
+  METHOD_STATUS_ERROR_CHECK(MethodStatus, TcgResultFailure);\r
+\r
+  ERROR_CHECK(TcgGetNextStartList(&ParseStruct));\r
+  ERROR_CHECK(TcgGetNextStartList(&ParseStruct));\r
+  ERROR_CHECK(TcgGetNextStartName(&ParseStruct));\r
+  ERROR_CHECK(TcgGetNextUINT32(&ParseStruct, &Col));\r
+  ERROR_CHECK(TcgGetNextByteSequence(&ParseStruct, &RecvMsid, MsidLength));\r
+  ERROR_CHECK(TcgGetNextEndName(&ParseStruct));\r
+  ERROR_CHECK(TcgGetNextEndList(&ParseStruct));\r
+  ERROR_CHECK(TcgGetNextEndList(&ParseStruct));\r
+  ERROR_CHECK(TcgGetNextEndOfData(&ParseStruct));\r
+\r
+  if (Col != OPAL_ADMIN_SP_PIN_COL) {\r
+    DEBUG ((DEBUG_INFO, "ERROR: got col %u, expected %u\n", Col, OPAL_ADMIN_SP_PIN_COL));\r
+    return TcgResultFailure;\r
+  }\r
+\r
+  if (RecvMsid == NULL) {\r
+    return TcgResultFailure;\r
+  }\r
+\r
+  if (MsidBufferSize < *MsidLength) {\r
+    DEBUG ((DEBUG_INFO, "Buffer too small MsidBufferSize: %d MsidLength: %d\n", MsidBufferSize, *MsidLength));\r
+    return TcgResultFailureBufferTooSmall;\r
+  }\r
+\r
+  //\r
+  // copy msid into Buffer\r
+  //\r
+  CopyMem(Msid, RecvMsid, *MsidLength);\r
+  return TcgResultSuccess;\r
+}\r
+\r
+/**\r
+\r
+  The function calls the Admin SP RevertSP method on the Locking SP.  If KeepUserData is True, then the optional parameter\r
+  to keep the user Data is set to True, otherwise the optional parameter is not provided.\r
+\r
+  @param[in]      LockingSpSession    OPAL_SESSION with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY to revertSP\r
+  @param[in]      KeepUserData        Specifies whether or not to keep user Data when performing RevertSP action. True = keeps user Data.\r
+  @param[in/out]  MethodStatus        Method status of last action performed.  If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalAdminRevert(\r
+  OPAL_SESSION    *LockingSpSession,\r
+  BOOLEAN         KeepUserData,\r
+  UINT8           *MethodStatus\r
+  )\r
+{\r
+  UINT8             Buf[BUFFER_SIZE];\r
+  TCG_CREATE_STRUCT CreateStruct;\r
+  UINT32            Size;\r
+  TCG_PARSE_STRUCT  ParseStruct;\r
+  TCG_RESULT        Ret;\r
+\r
+  NULL_CHECK(LockingSpSession);\r
+  NULL_CHECK(MethodStatus);\r
+\r
+  //\r
+  // ReadLocked or WriteLocked must be False (per Opal spec) to guarantee revertSP can keep user Data\r
+  //\r
+  if (KeepUserData) {\r
+    //\r
+    // set readlocked and writelocked to false\r
+    //\r
+    Ret = OpalUpdateGlobalLockingRange(\r
+                        LockingSpSession,\r
+                        FALSE,\r
+                        FALSE,\r
+                        MethodStatus);\r
+\r
+    if (Ret != TcgResultSuccess || *MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+      //\r
+      // bail out\r
+      //\r
+      return Ret;\r
+    }\r
+  }\r
+\r
+  ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));\r
+  ERROR_CHECK(TcgStartComPacket(&CreateStruct, LockingSpSession->OpalBaseComId, LockingSpSession->ComIdExtension));\r
+  ERROR_CHECK(TcgStartPacket(&CreateStruct, LockingSpSession->TperSessionId, LockingSpSession->HostSessionId, 0x0, 0x0, 0x0));\r
+  ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0));\r
+  ERROR_CHECK(TcgStartMethodCall(&CreateStruct, TCG_UID_THIS_SP, OPAL_LOCKING_SP_REVERTSP_METHOD));\r
+  ERROR_CHECK(TcgStartParameters(&CreateStruct));\r
+\r
+  if (KeepUserData) {\r
+    //\r
+    // optional parameter to keep Data after revert\r
+    //\r
+    ERROR_CHECK(TcgAddStartName(&CreateStruct));\r
+    ERROR_CHECK(TcgAddUINT32(&CreateStruct, 0x060000));      // weird Value but that's what spec says\r
+    ERROR_CHECK(TcgAddBOOLEAN(&CreateStruct, KeepUserData));\r
+    ERROR_CHECK(TcgAddEndName(&CreateStruct));\r
+  }\r
+\r
+  ERROR_CHECK(TcgEndParameters(&CreateStruct));\r
+  ERROR_CHECK(TcgEndMethodCall(&CreateStruct));\r
+  ERROR_CHECK(TcgEndSubPacket(&CreateStruct));\r
+  ERROR_CHECK(TcgEndPacket(&CreateStruct));\r
+  ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size));\r
+\r
+  //\r
+  // Send RevertSP method call\r
+  //\r
+  ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));\r
+\r
+  //\r
+  // Session is immediately ended by device after successful revertsp, so no need to end Session\r
+  //\r
+  if (*MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    //\r
+    // Caller should take ownership again\r
+    //\r
+    return TcgResultSuccess;\r
+  } else {\r
+    //\r
+    // End Session\r
+    //\r
+    METHOD_STATUS_ERROR_CHECK(*MethodStatus, TcgResultSuccess);     // exit with success on method failure - user must inspect MethodStatus\r
+  }\r
+\r
+  return TcgResultSuccess;\r
+}\r
+\r
+/**\r
+\r
+  The function activates the Locking SP.\r
+  Once activated, per Opal spec, the ADMIN SP SID PIN is copied over to the ADMIN1 LOCKING SP PIN.\r
+  If the Locking SP is already enabled, then TcgResultSuccess is returned and no action occurs.\r
+\r
+  @param[in]      AdminSpSession      OPAL_SESSION with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_SID_AUTHORITY to activate Locking SP\r
+  @param[in/out]  MethodStatus        Method status of last action performed.  If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalActivateLockingSp(\r
+  OPAL_SESSION           *AdminSpSession,\r
+  UINT8                  *MethodStatus\r
+  )\r
+{\r
+  UINT8             Buf[BUFFER_SIZE];\r
+  TCG_CREATE_STRUCT CreateStruct;\r
+  UINT32            Size;\r
+  TCG_PARSE_STRUCT  ParseStruct;\r
+\r
+  NULL_CHECK(AdminSpSession);\r
+  NULL_CHECK(MethodStatus);\r
+\r
+  //\r
+  // Call Activate method on Locking SP\r
+  //\r
+  ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));\r
+  ERROR_CHECK(TcgStartComPacket(&CreateStruct, AdminSpSession->OpalBaseComId, AdminSpSession->ComIdExtension));\r
+  ERROR_CHECK(TcgStartPacket(&CreateStruct, AdminSpSession->TperSessionId, AdminSpSession->HostSessionId, 0x0, 0x0, 0x0));\r
+  ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0));\r
+  ERROR_CHECK(TcgStartMethodCall(&CreateStruct, OPAL_UID_LOCKING_SP, OPAL_ADMIN_SP_ACTIVATE_METHOD));\r
+  ERROR_CHECK(TcgStartParameters(&CreateStruct));\r
+  ERROR_CHECK(TcgEndParameters(&CreateStruct));\r
+  ERROR_CHECK(TcgEndMethodCall(&CreateStruct));\r
+  ERROR_CHECK(TcgEndSubPacket(&CreateStruct));\r
+  ERROR_CHECK(TcgEndPacket(&CreateStruct));\r
+  ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size));\r
+\r
+  //\r
+  // Send Activate method call\r
+  //\r
+  ERROR_CHECK(OpalPerformMethod(AdminSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));\r
+  METHOD_STATUS_ERROR_CHECK(*MethodStatus, TcgResultSuccess); // exit with success on method failure - user must inspect MethodStatus\r
+\r
+  return TcgResultSuccess;\r
+}\r
+\r
+/**\r
+\r
+  The function sets the PIN column of the specified cpinRowUid (authority) with the newPin Value.\r
+\r
+  @param[in/out]  Session                 OPAL_SESSION to set password\r
+  @param[in]      CpinRowUid              UID of row (authority) to update PIN column\r
+  @param[in]      NewPin                  New Pin to set for cpinRowUid specified\r
+  @param[in]      NewPinLength            Length in bytes of newPin\r
+  @param[in/out]  MethodStatus            Method status of last action performed.  If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalSetPassword(\r
+  OPAL_SESSION   *Session,\r
+  TCG_UID        CpinRowUid,\r
+  const VOID     *NewPin,\r
+  UINT32         NewPinLength,\r
+  UINT8          *MethodStatus\r
+  )\r
+{\r
+  UINT8             Buf[BUFFER_SIZE];\r
+  TCG_CREATE_STRUCT CreateStruct;\r
+  TCG_PARSE_STRUCT  ParseStruct;\r
+  UINT32            Size;\r
+\r
+  NULL_CHECK(Session);\r
+  NULL_CHECK(NewPin);\r
+  NULL_CHECK(MethodStatus);\r
+\r
+  ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));\r
+  ERROR_CHECK(TcgCreateSetCPin(\r
+                         &CreateStruct,\r
+                         &Size,\r
+                         Session->OpalBaseComId,\r
+                         Session->ComIdExtension,\r
+                         Session->TperSessionId,\r
+                         Session->HostSessionId,\r
+                         CpinRowUid,\r
+                         NewPin,\r
+                         NewPinLength\r
+                         ));\r
+\r
+  ERROR_CHECK(OpalPerformMethod(Session, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));\r
+  // exit with success on method failure - user must inspect MethodStatus\r
+  METHOD_STATUS_ERROR_CHECK(*MethodStatus, TcgResultSuccess);\r
+\r
+  return TcgResultSuccess;\r
+}\r
+\r
+/**\r
+\r
+  The function sets the Enabled column to TRUE for the authorityUid provided and updates the PIN column for the cpinRowUid provided\r
+  using the newPin provided.  AuthorityUid and cpinRowUid should describe the same authority.\r
+\r
+  @param[in]      LockingSpSession    OPAL_SESSION with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY to update\r
+  @param[in]      CpinRowUid          Row UID of C_PIN table of Locking SP to update PIN\r
+  @param[in]      AuthorityUid        UID of Locking SP authority to update Pin column with\r
+  @param[in]      NewPin              New Password used to set Pin column\r
+  @param[in]      NewPinLength        Length in bytes of new password\r
+  @param[in/out]  MethodStatus        Method status of last action performed.  If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalSetLockingSpAuthorityEnabledAndPin(\r
+  OPAL_SESSION    *LockingSpSession,\r
+  TCG_UID         CpinRowUid,\r
+  TCG_UID         AuthorityUid,\r
+  const VOID      *NewPin,\r
+  UINT32          NewPinLength,\r
+  UINT8           *MethodStatus\r
+  )\r
+{\r
+  UINT8             Buf[BUFFER_SIZE];\r
+  TCG_CREATE_STRUCT CreateStruct;\r
+  TCG_PARSE_STRUCT  ParseStruct;\r
+  UINT32            Size;\r
+  TCG_UID           ActiveKey;\r
+\r
+  NULL_CHECK(LockingSpSession);\r
+  NULL_CHECK(NewPin);\r
+  NULL_CHECK(MethodStatus);\r
+\r
+  ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));\r
+  ERROR_CHECK(TcgSetAuthorityEnabled(\r
+                  &CreateStruct,\r
+                  &Size,\r
+                  LockingSpSession->OpalBaseComId,\r
+                  LockingSpSession->ComIdExtension,\r
+                  LockingSpSession->TperSessionId,\r
+                  LockingSpSession->HostSessionId,\r
+                  AuthorityUid,\r
+                  TRUE));\r
+\r
+  ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));\r
+\r
+  if (*MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    DEBUG ((DEBUG_INFO, "Send Set Authority error\n"));\r
+    return TcgResultFailure;\r
+  }\r
+\r
+  ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));\r
+\r
+  ERROR_CHECK(TcgCreateSetCPin(\r
+                  &CreateStruct,\r
+                  &Size,\r
+                  LockingSpSession->OpalBaseComId,\r
+                  LockingSpSession->ComIdExtension,\r
+                  LockingSpSession->TperSessionId,\r
+                  LockingSpSession->HostSessionId,\r
+                  CpinRowUid,\r
+                  NewPin,\r
+                  NewPinLength));\r
+\r
+  ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));\r
+\r
+  //\r
+  // allow user1 to set global range to unlocked/locked by modifying ACE_Locking_GlobalRange_SetRdLocked/SetWrLocked\r
+  //\r
+  ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));\r
+  ERROR_CHECK(TcgCreateSetAce(\r
+                  &CreateStruct,\r
+                  &Size,\r
+                  LockingSpSession->OpalBaseComId,\r
+                  LockingSpSession->ComIdExtension,\r
+                  LockingSpSession->TperSessionId,\r
+                  LockingSpSession->HostSessionId,\r
+                  OPAL_LOCKING_SP_ACE_LOCKING_GLOBALRANGE_SET_RDLOCKED,\r
+                  OPAL_LOCKING_SP_USER1_AUTHORITY,\r
+                  TCG_ACE_EXPRESSION_OR,\r
+                  OPAL_LOCKING_SP_ADMINS_AUTHORITY\r
+              ));\r
+\r
+  ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));\r
+\r
+  if (*MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    DEBUG ((DEBUG_INFO, "Update ACE for RDLOCKED failed\n"));\r
+    return TcgResultFailure;\r
+  }\r
+\r
+  ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));\r
+  ERROR_CHECK(TcgCreateSetAce(\r
+                  &CreateStruct,\r
+                  &Size,\r
+                  LockingSpSession->OpalBaseComId,\r
+                  LockingSpSession->ComIdExtension,\r
+                  LockingSpSession->TperSessionId,\r
+                  LockingSpSession->HostSessionId,\r
+                  OPAL_LOCKING_SP_ACE_LOCKING_GLOBALRANGE_SET_WRLOCKED,\r
+                  OPAL_LOCKING_SP_USER1_AUTHORITY,\r
+                  TCG_ACE_EXPRESSION_OR,\r
+                  OPAL_LOCKING_SP_ADMINS_AUTHORITY\r
+              ));\r
+\r
+  ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));\r
+\r
+  if (*MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    DEBUG ((DEBUG_INFO, "Update ACE for WRLOCKED failed\n"));\r
+    return TcgResultFailure;\r
+  }\r
+\r
+  ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));\r
+  ERROR_CHECK(OpalCreateRetrieveGlobalLockingRangeActiveKey(LockingSpSession, &CreateStruct, &Size));\r
+  ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));\r
+\r
+  ERROR_CHECK(OpalParseRetrieveGlobalLockingRangeActiveKey(&ParseStruct, &ActiveKey));\r
+\r
+  ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));\r
+  ERROR_CHECK(TcgCreateSetAce(\r
+                  &CreateStruct,\r
+                  &Size,\r
+                  LockingSpSession->OpalBaseComId,\r
+                  LockingSpSession->ComIdExtension,\r
+                  LockingSpSession->TperSessionId,\r
+                  LockingSpSession->HostSessionId,\r
+                  (ActiveKey == OPAL_LOCKING_SP_K_AES_256_GLOBALRANGE_KEY) ? OPAL_LOCKING_SP_ACE_K_AES_256_GLOBALRANGE_GENKEY : OPAL_LOCKING_SP_ACE_K_AES_128_GLOBALRANGE_GENKEY,\r
+                  OPAL_LOCKING_SP_USER1_AUTHORITY,\r
+                  TCG_ACE_EXPRESSION_OR,\r
+                  OPAL_LOCKING_SP_ADMINS_AUTHORITY\r
+              ));\r
+\r
+  ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));\r
+\r
+  if (*MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    DEBUG ((DEBUG_INFO, "Update ACE for GLOBALRANGE_GENKEY failed\n"));\r
+    //\r
+    //TODO do we want to disable user1 if all permissions are not granted\r
+    //\r
+    return TcgResultFailure;\r
+  }\r
+\r
+  ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));\r
+  ERROR_CHECK(TcgCreateSetAce(\r
+                  &CreateStruct,\r
+                  &Size,\r
+                  LockingSpSession->OpalBaseComId,\r
+                  LockingSpSession->ComIdExtension,\r
+                  LockingSpSession->TperSessionId,\r
+                  LockingSpSession->HostSessionId,\r
+                  OPAL_LOCKING_SP_ACE_LOCKING_GLOBALRANGE_GET_ALL,\r
+                  OPAL_LOCKING_SP_USER1_AUTHORITY,\r
+                  TCG_ACE_EXPRESSION_OR,\r
+                  OPAL_LOCKING_SP_ADMINS_AUTHORITY\r
+              ));\r
+\r
+  ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));\r
+\r
+  if (*MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    DEBUG ((DEBUG_INFO, "Update ACE for OPAL_LOCKING_SP_ACE_LOCKING_GLOBALRANGE_GET_ALL failed\n"));\r
+    return TcgResultFailure;\r
+  }\r
+\r
+  return TcgResultSuccess;\r
+}\r
+\r
+/**\r
+\r
+  The function sets the Enabled column to FALSE for the USER1 authority.\r
+\r
+  @param[in]      LockingSpSession    OPAL_SESSION with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY to disable User1\r
+  @param[in/out]  MethodStatus        Method status of last action performed.  If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalDisableUser(\r
+  OPAL_SESSION     *LockingSpSession,\r
+  UINT8            *MethodStatus\r
+  )\r
+{\r
+  UINT8             Buf[BUFFER_SIZE];\r
+  TCG_CREATE_STRUCT CreateStruct;\r
+  TCG_PARSE_STRUCT  ParseStruct;\r
+  UINT32            Size;\r
+\r
+  NULL_CHECK(LockingSpSession);\r
+  NULL_CHECK(MethodStatus);\r
+\r
+  ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));\r
+  ERROR_CHECK(TcgSetAuthorityEnabled(\r
+                  &CreateStruct,\r
+                  &Size,\r
+                  LockingSpSession->OpalBaseComId,\r
+                  LockingSpSession->ComIdExtension,\r
+                  LockingSpSession->TperSessionId,\r
+                  LockingSpSession->HostSessionId,\r
+                  OPAL_LOCKING_SP_USER1_AUTHORITY,\r
+                  FALSE));\r
+\r
+  ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));\r
+\r
+  return TcgResultSuccess;\r
+}\r
+\r
+/**\r
+\r
+  The function retrieves the active key of the global locking range\r
+  and calls the GenKey method on the active key retrieved.\r
+\r
+  @param[in]      LockingSpSession    OPAL_SESSION with OPAL_UID_LOCKING_SP to generate key\r
+  @param[in/out]  MethodStatus        Method status of last action performed.  If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalGlobalLockingRangeGenKey(\r
+  OPAL_SESSION   *LockingSpSession,\r
+  UINT8          *MethodStatus\r
+  )\r
+{\r
+  UINT8             Buf[BUFFER_SIZE];\r
+  TCG_CREATE_STRUCT CreateStruct;\r
+  TCG_PARSE_STRUCT  ParseStruct;\r
+  UINT32            Size;\r
+  TCG_UID           ActiveKey;\r
+\r
+  NULL_CHECK(LockingSpSession);\r
+  NULL_CHECK(MethodStatus);\r
+\r
+  ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));\r
+  //\r
+  // retrieve the activekey in order to know which globalrange key to generate\r
+  //\r
+  ERROR_CHECK(OpalCreateRetrieveGlobalLockingRangeActiveKey(LockingSpSession, &CreateStruct, &Size));\r
+  ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));\r
+\r
+  METHOD_STATUS_ERROR_CHECK(*MethodStatus, TcgResultSuccess);\r
+\r
+  ERROR_CHECK(OpalParseRetrieveGlobalLockingRangeActiveKey(&ParseStruct, &ActiveKey));\r
+\r
+  //\r
+  // call genkey on ActiveKey UID\r
+  //\r
+  ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));\r
+  ERROR_CHECK(TcgStartComPacket(&CreateStruct, LockingSpSession->OpalBaseComId, LockingSpSession->ComIdExtension));\r
+  ERROR_CHECK(TcgStartPacket(&CreateStruct, LockingSpSession->TperSessionId, LockingSpSession->HostSessionId, 0x0, 0x0, 0x0));\r
+  ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0));\r
+  ERROR_CHECK(TcgStartMethodCall(&CreateStruct, ActiveKey, TCG_UID_METHOD_GEN_KEY));\r
+  ERROR_CHECK(TcgStartParameters(&CreateStruct));\r
+  ERROR_CHECK(TcgEndParameters(&CreateStruct));\r
+  ERROR_CHECK(TcgEndMethodCall(&CreateStruct));\r
+  ERROR_CHECK(TcgEndSubPacket(&CreateStruct));\r
+  ERROR_CHECK(TcgEndPacket(&CreateStruct));\r
+  ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size));\r
+\r
+  ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));\r
+\r
+  return TcgResultSuccess;\r
+}\r
+\r
+/**\r
+\r
+  The function updates the ReadLocked and WriteLocked columns of the Global Locking Range.\r
+  This funciton is required for a user1 authority, since a user1 authority shall only have access to ReadLocked and WriteLocked columns\r
+  (not ReadLockEnabled and WriteLockEnabled columns).\r
+\r
+  @param[in]      LockingSpSession    OPAL_SESSION with OPAL_UID_LOCKING_SP to generate key\r
+  @param[in]      ReadLocked          Value to set ReadLocked column for Global Locking Range\r
+  @param[in]      WriteLocked         Value to set WriteLocked column for Global Locking Range\r
+  @param[in/out]  MethodStatus        Method status of last action performed.  If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalUpdateGlobalLockingRange(\r
+  OPAL_SESSION             *LockingSpSession,\r
+  BOOLEAN                  ReadLocked,\r
+  BOOLEAN                  WriteLocked,\r
+  UINT8                    *MethodStatus\r
+  )\r
+{\r
+  UINT8             Buf[BUFFER_SIZE];\r
+  TCG_CREATE_STRUCT CreateStruct;\r
+  TCG_PARSE_STRUCT  ParseStruct;\r
+  UINT32            Size;\r
+\r
+  NULL_CHECK(LockingSpSession);\r
+  NULL_CHECK(MethodStatus);\r
+\r
+  ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));\r
+\r
+  //\r
+  // set global locking range values\r
+  //\r
+  ERROR_CHECK(TcgStartComPacket(&CreateStruct, LockingSpSession->OpalBaseComId, LockingSpSession->ComIdExtension));\r
+  ERROR_CHECK(TcgStartPacket(&CreateStruct, LockingSpSession->TperSessionId, LockingSpSession->HostSessionId, 0x0, 0x0, 0x0));\r
+  ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0));\r
+  ERROR_CHECK(TcgStartMethodCall(&CreateStruct, OPAL_LOCKING_SP_LOCKING_GLOBALRANGE, TCG_UID_METHOD_SET));\r
+  ERROR_CHECK(TcgStartParameters(&CreateStruct));\r
+  ERROR_CHECK(TcgAddStartName(&CreateStruct));\r
+  ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x01));                       // "Values"\r
+  ERROR_CHECK(TcgAddStartList(&CreateStruct));\r
+\r
+  ERROR_CHECK(TcgAddStartName(&CreateStruct));\r
+  ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x07));                       // "ReadLocked"\r
+  ERROR_CHECK(TcgAddBOOLEAN(&CreateStruct, ReadLocked));\r
+  ERROR_CHECK(TcgAddEndName(&CreateStruct));\r
+\r
+  ERROR_CHECK(TcgAddStartName(&CreateStruct));\r
+  ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x08));                       // "WriteLocked"\r
+  ERROR_CHECK(TcgAddBOOLEAN(&CreateStruct, WriteLocked));\r
+  ERROR_CHECK(TcgAddEndName(&CreateStruct));\r
+\r
+  ERROR_CHECK(TcgAddEndList(&CreateStruct));\r
+  ERROR_CHECK(TcgAddEndName(&CreateStruct));\r
+  ERROR_CHECK(TcgEndParameters(&CreateStruct));\r
+  ERROR_CHECK(TcgEndMethodCall(&CreateStruct));\r
+  ERROR_CHECK(TcgEndSubPacket(&CreateStruct));\r
+  ERROR_CHECK(TcgEndPacket(&CreateStruct));\r
+  ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size));\r
+\r
+  ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));\r
+  METHOD_STATUS_ERROR_CHECK(*MethodStatus, TcgResultSuccess);\r
+\r
+  return TcgResultSuccess;\r
+}\r
+\r
+/**\r
+\r
+  The function updates the RangeStart, RangeLength, ReadLockedEnabled, WriteLockedEnabled, ReadLocked and WriteLocked columns\r
+  of the specified Locking Range.  This function requires admin authority of a locking SP session.\r
+\r
+  @param[in]      LockingSpSession    OPAL_SESSION with OPAL_UID_LOCKING_SP to generate key\r
+  @param[in]      LockingRangeUid     Locking range UID to set values\r
+  @param[in]      RangeStart          Value to set RangeStart column for Locking Range\r
+  @param[in]      RangeLength         Value to set RangeLength column for Locking Range\r
+  @param[in]      ReadLockEnabled     Value to set readLockEnabled column for Locking Range\r
+  @param[in]      WriteLockEnabled    Value to set writeLockEnabled column for Locking Range\r
+  @param[in]      ReadLocked          Value to set ReadLocked column for Locking Range\r
+  @param[in]      WriteLocked         Value to set WriteLocked column for Locking Range\r
+  @param[in/out]  MethodStatus        Method status of last action performed.  If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalSetLockingRange(\r
+  OPAL_SESSION      *LockingSpSession,\r
+  TCG_UID           LockingRangeUid,\r
+  UINT64            RangeStart,\r
+  UINT64            RangeLength,\r
+  BOOLEAN           ReadLockEnabled,\r
+  BOOLEAN           WriteLockEnabled,\r
+  BOOLEAN           ReadLocked,\r
+  BOOLEAN           WriteLocked,\r
+  UINT8             *MethodStatus\r
+  )\r
+{\r
+  UINT8           Buf[BUFFER_SIZE];\r
+  TCG_CREATE_STRUCT CreateStruct;\r
+  TCG_PARSE_STRUCT  ParseStruct;\r
+  UINT32          Size;\r
+\r
+  NULL_CHECK(LockingSpSession);\r
+  NULL_CHECK(MethodStatus);\r
+\r
+  ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));\r
+\r
+  //\r
+  // set locking range values\r
+  //\r
+  ERROR_CHECK(TcgStartComPacket(&CreateStruct, LockingSpSession->OpalBaseComId, LockingSpSession->ComIdExtension));\r
+  ERROR_CHECK(TcgStartPacket(&CreateStruct, LockingSpSession->TperSessionId, LockingSpSession->HostSessionId, 0x0, 0x0, 0x0));\r
+  ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0));\r
+  ERROR_CHECK(TcgStartMethodCall(&CreateStruct, LockingRangeUid, TCG_UID_METHOD_SET));\r
+  ERROR_CHECK(TcgStartParameters(&CreateStruct));\r
+  ERROR_CHECK(TcgAddStartName(&CreateStruct));\r
+  ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x01));                        // "Values"\r
+  ERROR_CHECK(TcgAddStartList(&CreateStruct));\r
+\r
+  //\r
+  // range start and range Length only apply to non-global locking ranges\r
+  //\r
+  if (LockingRangeUid != OPAL_LOCKING_SP_LOCKING_GLOBALRANGE) {\r
+    ERROR_CHECK(TcgAddStartName(&CreateStruct));\r
+    ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x03));                       // "RangeStart"\r
+    ERROR_CHECK(TcgAddUINT64(&CreateStruct, RangeStart));\r
+    ERROR_CHECK(TcgAddEndName(&CreateStruct));\r
+\r
+    ERROR_CHECK(TcgAddStartName(&CreateStruct));\r
+    ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x04));                       // "RangeLength"\r
+    ERROR_CHECK(TcgAddUINT64(&CreateStruct, RangeLength));\r
+    ERROR_CHECK(TcgAddEndName(&CreateStruct));\r
+  }\r
+\r
+  ERROR_CHECK(TcgAddStartName(&CreateStruct));\r
+  ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x05));                       // "ReadLockEnabled"\r
+  ERROR_CHECK(TcgAddBOOLEAN(&CreateStruct, ReadLockEnabled));\r
+  ERROR_CHECK(TcgAddEndName(&CreateStruct));\r
+\r
+  ERROR_CHECK(TcgAddStartName(&CreateStruct));\r
+  ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x06));                       // "WriteLockEnabled"\r
+  ERROR_CHECK(TcgAddBOOLEAN(&CreateStruct, WriteLockEnabled));\r
+  ERROR_CHECK(TcgAddEndName(&CreateStruct));\r
+\r
+  ERROR_CHECK(TcgAddStartName(&CreateStruct));\r
+  ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x07));                       // "ReadLocked"\r
+  ERROR_CHECK(TcgAddBOOLEAN(&CreateStruct, ReadLocked));\r
+  ERROR_CHECK(TcgAddEndName(&CreateStruct));\r
+\r
+  ERROR_CHECK(TcgAddStartName(&CreateStruct));\r
+  ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x08));                       // "WriteLocked"\r
+  ERROR_CHECK(TcgAddBOOLEAN(&CreateStruct, WriteLocked));\r
+  ERROR_CHECK(TcgAddEndName(&CreateStruct));\r
+\r
+  ERROR_CHECK(TcgAddEndList(&CreateStruct));\r
+  ERROR_CHECK(TcgAddEndName(&CreateStruct));\r
+  ERROR_CHECK(TcgEndParameters(&CreateStruct));\r
+  ERROR_CHECK(TcgEndMethodCall(&CreateStruct));\r
+  ERROR_CHECK(TcgEndSubPacket(&CreateStruct));\r
+  ERROR_CHECK(TcgEndPacket(&CreateStruct));\r
+  ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size));\r
+\r
+  ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));\r
+  // Exit with success on method failure - user must inspect MethodStatus\r
+  METHOD_STATUS_ERROR_CHECK(*MethodStatus, TcgResultSuccess);\r
+\r
+  return TcgResultSuccess;\r
+}\r
+\r
+/**\r
+\r
+  The function populates the CreateStruct with a payload that will retrieve the global locking range active key.\r
+  It is intended to be called with a session that is already started with a valid credential.\r
+  The function does not send the payload.\r
+\r
+  @param[in]      Session        OPAL_SESSION to populate command for, needs ComId\r
+  @param[in/out]  CreateStruct   Structure to populate with encoded TCG command\r
+  @param[in/out]  Size           Size in bytes of the command created.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalCreateRetrieveGlobalLockingRangeActiveKey(\r
+  const OPAL_SESSION    *Session,\r
+  TCG_CREATE_STRUCT     *CreateStruct,\r
+  UINT32                *Size\r
+  )\r
+{\r
+  NULL_CHECK(Session);\r
+  NULL_CHECK(CreateStruct);\r
+  NULL_CHECK(Size);\r
+\r
+  // Retrieve the activekey in order to know which globalrange key to generate\r
+  ERROR_CHECK(TcgStartComPacket(CreateStruct, Session->OpalBaseComId, Session->ComIdExtension));\r
+  ERROR_CHECK(TcgStartPacket(CreateStruct, Session->TperSessionId, Session->HostSessionId, 0x0, 0x0, 0x0));\r
+  ERROR_CHECK(TcgStartSubPacket(CreateStruct, 0x0));\r
+  ERROR_CHECK(TcgStartMethodCall(CreateStruct, OPAL_LOCKING_SP_LOCKING_GLOBALRANGE, TCG_UID_METHOD_GET));\r
+  ERROR_CHECK(TcgStartParameters(CreateStruct));\r
+  ERROR_CHECK(TcgAddStartList(CreateStruct));\r
+  ERROR_CHECK(TcgAddStartName(CreateStruct));\r
+  ERROR_CHECK(TcgAddUINT8(CreateStruct, TCG_CELL_BLOCK_START_COLUMN_NAME));\r
+  ERROR_CHECK(TcgAddUINT8(CreateStruct, 0x0A));         // ActiveKey\r
+  ERROR_CHECK(TcgAddEndName(CreateStruct));\r
+  ERROR_CHECK(TcgAddStartName(CreateStruct));\r
+  ERROR_CHECK(TcgAddUINT8(CreateStruct, TCG_CELL_BLOCK_END_COLUMN_NAME));\r
+  ERROR_CHECK(TcgAddUINT8(CreateStruct, 0x0A));\r
+  ERROR_CHECK(TcgAddEndName(CreateStruct));\r
+  ERROR_CHECK(TcgAddEndList(CreateStruct));\r
+  ERROR_CHECK(TcgEndParameters(CreateStruct));\r
+  ERROR_CHECK(TcgEndMethodCall(CreateStruct));\r
+  ERROR_CHECK(TcgEndSubPacket(CreateStruct));\r
+  ERROR_CHECK(TcgEndPacket(CreateStruct));\r
+  ERROR_CHECK(TcgEndComPacket(CreateStruct, Size));\r
+\r
+  return TcgResultSuccess;\r
+}\r
+\r
+/**\r
+\r
+  The function acquires the activeKey specified for the Global Locking Range from the ParseStruct.\r
+\r
+  @param[in]      ParseStruct    Structure that contains the device's response with the activekey\r
+  @param[in/out]  ActiveKey      The UID of the active key retrieved\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalParseRetrieveGlobalLockingRangeActiveKey(\r
+  TCG_PARSE_STRUCT  *ParseStruct,\r
+  TCG_UID           *ActiveKey\r
+  )\r
+{\r
+  UINT32 ColumnName;\r
+\r
+  NULL_CHECK(ParseStruct);\r
+  NULL_CHECK(ActiveKey);\r
+\r
+  // parse response\r
+  ERROR_CHECK(TcgGetNextStartList(ParseStruct));\r
+  ERROR_CHECK(TcgGetNextStartList(ParseStruct));\r
+  ERROR_CHECK(TcgGetNextStartName(ParseStruct));\r
+  ERROR_CHECK(TcgGetNextUINT32(ParseStruct, &ColumnName));\r
+  ERROR_CHECK(TcgGetNextTcgUid(ParseStruct, ActiveKey));\r
+  ERROR_CHECK(TcgGetNextEndName(ParseStruct));\r
+  ERROR_CHECK(TcgGetNextEndList(ParseStruct));\r
+  ERROR_CHECK(TcgGetNextEndList(ParseStruct));\r
+  ERROR_CHECK(TcgGetNextEndOfData(ParseStruct));\r
+\r
+  if (ColumnName != 0x0A) {\r
+    DEBUG ((DEBUG_INFO, "Unexpected column name %u (exp 0x0A)\n", ColumnName));\r
+    return TcgResultFailure;\r
+  }\r
+\r
+  if (*ActiveKey != OPAL_LOCKING_SP_K_AES_256_GLOBALRANGE_KEY && *ActiveKey != OPAL_LOCKING_SP_K_AES_128_GLOBALRANGE_KEY) {\r
+    DEBUG ((DEBUG_INFO, "Unexpected gen key %u (exp %u or %u)\n", *ActiveKey, OPAL_LOCKING_SP_K_AES_256_GLOBALRANGE_KEY, OPAL_LOCKING_SP_K_AES_128_GLOBALRANGE_KEY));\r
+    return TcgResultFailure;\r
+  }\r
+\r
+  return TcgResultSuccess;\r
+}\r
+\r
+/**\r
+\r
+  The function retrieves the TryLimit column for the specified rowUid (authority).\r
+\r
+  @param[in]      LockingSpSession    OPAL_SESSION with OPAL_UID_LOCKING_SP to retrieve try limit\r
+  @param[in]      RowUid              Row UID of the Locking SP C_PIN table to retrieve TryLimit column\r
+  @param[in/out]  TryLimit            Value from TryLimit column\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalGetTryLimit(\r
+  OPAL_SESSION   *LockingSpSession,\r
+  TCG_UID        RowUid,\r
+  UINT32         *TryLimit\r
+  )\r
+{\r
+  TCG_CREATE_STRUCT CreateStruct;\r
+  TCG_PARSE_STRUCT  ParseStruct;\r
+  UINT32            Size;\r
+  UINT8             MethodStatus;\r
+  UINT8             Buf[BUFFER_SIZE];\r
+  UINT32            Col;\r
+\r
+  NULL_CHECK(LockingSpSession);\r
+  NULL_CHECK(TryLimit);\r
+\r
+  ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));\r
+  ERROR_CHECK(TcgStartComPacket(&CreateStruct, LockingSpSession->OpalBaseComId, LockingSpSession->ComIdExtension));\r
+  ERROR_CHECK(TcgStartPacket(&CreateStruct, LockingSpSession->TperSessionId, LockingSpSession->HostSessionId, 0x0, 0x0, 0x0));\r
+  ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0));\r
+  ERROR_CHECK(TcgStartMethodCall(&CreateStruct, RowUid, TCG_UID_METHOD_GET));\r
+  ERROR_CHECK(TcgStartParameters(&CreateStruct));\r
+  ERROR_CHECK(TcgAddStartList(&CreateStruct));\r
+  ERROR_CHECK(TcgAddStartName(&CreateStruct));\r
+  ERROR_CHECK(TcgAddUINT8(&CreateStruct, TCG_CELL_BLOCK_START_COLUMN_NAME));\r
+  ERROR_CHECK(TcgAddUINT8(&CreateStruct, OPAL_LOCKING_SP_C_PIN_TRYLIMIT_COL));\r
+  ERROR_CHECK(TcgAddEndName(&CreateStruct));\r
+  ERROR_CHECK(TcgAddStartName(&CreateStruct));\r
+  ERROR_CHECK(TcgAddUINT8(&CreateStruct, TCG_CELL_BLOCK_END_COLUMN_NAME));\r
+  ERROR_CHECK(TcgAddUINT8(&CreateStruct, OPAL_LOCKING_SP_C_PIN_TRYLIMIT_COL));\r
+  ERROR_CHECK(TcgAddEndName(&CreateStruct));\r
+  ERROR_CHECK(TcgAddEndList(&CreateStruct));\r
+  ERROR_CHECK(TcgEndParameters(&CreateStruct));\r
+  ERROR_CHECK(TcgEndMethodCall(&CreateStruct));\r
+  ERROR_CHECK(TcgEndSubPacket(&CreateStruct));\r
+  ERROR_CHECK(TcgEndPacket(&CreateStruct));\r
+  ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size));\r
+\r
+  ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, &MethodStatus));\r
+  METHOD_STATUS_ERROR_CHECK(MethodStatus, TcgResultFailure);\r
+\r
+  ERROR_CHECK(TcgGetNextStartList(&ParseStruct));\r
+  ERROR_CHECK(TcgGetNextStartList(&ParseStruct));\r
+  ERROR_CHECK(TcgGetNextStartName(&ParseStruct));\r
+  ERROR_CHECK(TcgGetNextUINT32(&ParseStruct, &Col));\r
+  ERROR_CHECK(TcgGetNextUINT32(&ParseStruct, TryLimit));\r
+  ERROR_CHECK(TcgGetNextEndName(&ParseStruct));\r
+  ERROR_CHECK(TcgGetNextEndList(&ParseStruct));\r
+  ERROR_CHECK(TcgGetNextEndList(&ParseStruct));\r
+  ERROR_CHECK(TcgGetNextEndOfData(&ParseStruct));\r
+\r
+  if (Col != OPAL_LOCKING_SP_C_PIN_TRYLIMIT_COL) {\r
+    DEBUG ((DEBUG_INFO, "ERROR: got col %u, expected %u\n", Col, OPAL_LOCKING_SP_C_PIN_TRYLIMIT_COL));\r
+    return TcgResultFailure;\r
+  }\r
+\r
+  return TcgResultSuccess;\r
+}\r
+\r
+/**\r
+\r
+  Get the support attribute info.\r
+\r
+  @param[in]      Session             OPAL_SESSION with OPAL_UID_LOCKING_SP to retrieve info.\r
+  @param[out]     SupportedAttributes Return the support attribute info.\r
+  @param[out]     OpalBaseComId       Return the base com id info.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalGetSupportedAttributesInfo(\r
+  IN  OPAL_SESSION                 *Session,\r
+  OUT OPAL_DISK_SUPPORT_ATTRIBUTE  *SupportedAttributes,\r
+  OUT UINT16                       *OpalBaseComId\r
+  )\r
+{\r
+  UINT8                              Buffer[BUFFER_SIZE];\r
+  TCG_SUPPORTED_SECURITY_PROTOCOLS   *SupportedProtocols;\r
+  TCG_LEVEL0_DISCOVERY_HEADER        *DiscoveryHeader;\r
+  OPAL_LEVEL0_FEATURE_DESCRIPTOR     *Feat;\r
+  UINTN                              Size;\r
+\r
+  NULL_CHECK(Session);\r
+  NULL_CHECK(SupportedAttributes);\r
+  NULL_CHECK(OpalBaseComId);\r
+\r
+  ZeroMem(Buffer, BUFFER_SIZE);\r
+  ASSERT(sizeof(Buffer) >= sizeof(TCG_SUPPORTED_SECURITY_PROTOCOLS));\r
+\r
+  //\r
+  // Retrieve supported protocols verify security protocol 1 is supported\r
+  //\r
+  SupportedProtocols = (TCG_SUPPORTED_SECURITY_PROTOCOLS*) Buffer;\r
+\r
+  //\r
+  // Get list of supported protocols\r
+  //\r
+  if (OpalRetrieveSupportedProtocolList (Session, sizeof(TCG_SUPPORTED_SECURITY_PROTOCOLS), SupportedProtocols) == TcgResultFailure) {\r
+    DEBUG ((DEBUG_INFO, "OpalRetrieveSupportedProtocolList failed\n"));\r
+    return TcgResultFailure;\r
+  }\r
+\r
+  SupportedAttributes->Sp1 = TcgIsProtocolSupported (SupportedProtocols, TCG_OPAL_SECURITY_PROTOCOL_1);\r
+  SupportedAttributes->Sp2 = TcgIsProtocolSupported (SupportedProtocols, TCG_OPAL_SECURITY_PROTOCOL_2);\r
+  SupportedAttributes->SpIeee1667 = TcgIsProtocolSupported (SupportedProtocols, TCG_SECURITY_PROTOCOL_IEEE_1667);\r
+\r
+  DEBUG ((DEBUG_INFO, "Supported Protocols: Sp1 %d Sp2: %d SpIeee1667 %d \n",\r
+              SupportedAttributes->Sp1,\r
+              SupportedAttributes->Sp2,\r
+              SupportedAttributes->SpIeee1667\r
+              ));\r
+\r
+  //\r
+  // Perform level 0 discovery and assign desired feature info to Opal Disk structure\r
+  //\r
+  ZeroMem (Buffer, BUFFER_SIZE);\r
+  if (OpalRetrieveLevel0DiscoveryHeader (Session, BUFFER_SIZE, Buffer) == TcgResultFailure) {\r
+    DEBUG ((DEBUG_INFO, "OpalRetrieveLevel0DiscoveryHeader failed\n"));\r
+    return TcgResultFailure;\r
+  }\r
+\r
+  //\r
+  // Check for required feature descriptors\r
+  //\r
+  DiscoveryHeader = (TCG_LEVEL0_DISCOVERY_HEADER*) Buffer;\r
+\r
+  Size = 0;\r
+  Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_OPAL_SSC_V2_0_0, &Size);\r
+  SupportedAttributes->OpalSsc2 = (Feat != NULL);\r
+\r
+  *OpalBaseComId = TCG_RESERVED_COMID;\r
+\r
+  //\r
+  // Check Opal SCC V2 has valid settings for SID C_PIN on revert\r
+  //\r
+  if (SupportedAttributes->OpalSsc2 && Size >= sizeof (OPAL_SSCV2_FEATURE_DESCRIPTOR)) {\r
+    //\r
+    // Want opposite polarity b/c Value is greater than a bit, but we only care about non-zero vs zero\r
+    //\r
+    SupportedAttributes->InitCpinIndicator = (Feat->OpalSscV2.InitialCPINSIDPIN == 0);\r
+    SupportedAttributes->CpinUponRevert = (Feat->OpalSscV2.CPINSIDPINRevertBehavior == 0);\r
+    DEBUG ((DEBUG_INFO, "Opal SSC V2 InitCpinIndicator %d  CpinUponRevert %d \n",\r
+             SupportedAttributes->InitCpinIndicator,\r
+             SupportedAttributes->CpinUponRevert\r
+            ));\r
+    *OpalBaseComId = SwapBytes16 (Feat->OpalSscV2.BaseComdIdBE);\r
+  }\r
+\r
+  Size = 0;\r
+  Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_OPAL_SSC_LITE, &Size);\r
+  SupportedAttributes->OpalSscLite = (Feat != NULL);\r
+\r
+  if (Feat != NULL && Size >= sizeof (OPAL_SSCLITE_FEATURE_DESCRIPTOR)) {\r
+    if (*OpalBaseComId == TCG_RESERVED_COMID) {\r
+      //\r
+      // Pin values used always match up with ComId used\r
+      //\r
+      *OpalBaseComId = SwapBytes16 (Feat->OpalSscLite.BaseComdIdBE);\r
+      SupportedAttributes->InitCpinIndicator = (Feat->OpalSscV2.InitialCPINSIDPIN == 0);\r
+      SupportedAttributes->CpinUponRevert = (Feat->OpalSscV2.CPINSIDPINRevertBehavior == 0);\r
+      DEBUG ((DEBUG_INFO, "Opal SSC Lite InitCpinIndicator %d  CpinUponRevert %d \n",\r
+               SupportedAttributes->InitCpinIndicator,\r
+               SupportedAttributes->CpinUponRevert\r
+              ));\r
+    }\r
+  }\r
+\r
+  Size = 0;\r
+  Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_PYRITE_SSC, &Size);\r
+  SupportedAttributes->PyriteSsc = (Feat != NULL);\r
+  if (Feat != NULL && Size >= sizeof (PYRITE_SSC_FEATURE_DESCRIPTOR)) {\r
+    if (*OpalBaseComId == TCG_RESERVED_COMID) {\r
+      *OpalBaseComId = SwapBytes16 (Feat->PyriteSsc.BaseComdIdBE);\r
+      SupportedAttributes->InitCpinIndicator = (Feat->PyriteSsc.InitialCPINSIDPIN == 0);\r
+      SupportedAttributes->CpinUponRevert = (Feat->PyriteSsc.CPINSIDPINRevertBehavior == 0);\r
+      DEBUG ((DEBUG_INFO, "Pyrite SSC InitCpinIndicator %d  CpinUponRevert %d \n",\r
+               SupportedAttributes->InitCpinIndicator,\r
+               SupportedAttributes->CpinUponRevert\r
+              ));\r
+    }\r
+  }\r
+\r
+  Size = 0;\r
+  Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_OPAL_SSC_V1_0_0, &Size);\r
+  SupportedAttributes->OpalSsc1 = (Feat != NULL);\r
+  if (Feat != NULL && Size >= sizeof (OPAL_SSCV1_FEATURE_DESCRIPTOR)) {\r
+    if (*OpalBaseComId == TCG_RESERVED_COMID) {\r
+      *OpalBaseComId = SwapBytes16 (Feat->OpalSscV1.BaseComdIdBE);\r
+    }\r
+  }\r
+\r
+  Size = 0;\r
+  Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_LOCKING, &Size);\r
+  if (Feat != NULL && Size >= sizeof (TCG_LOCKING_FEATURE_DESCRIPTOR)) {\r
+    SupportedAttributes->MediaEncryption = Feat->Locking.MediaEncryption;\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO, "Base COMID 0x%04X \n", *OpalBaseComId));\r
+\r
+\r
+  return TcgResultSuccess;\r
+}\r
+\r
+/**\r
+\r
+  Get the support attribute info.\r
+\r
+  @param[in]      Session             OPAL_SESSION with OPAL_UID_LOCKING_SP to retrieve info.\r
+  @param[in/out]  LockingFeature      Return the Locking info.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalGetLockingInfo(\r
+  OPAL_SESSION                     *Session,\r
+  TCG_LOCKING_FEATURE_DESCRIPTOR   *LockingFeature\r
+  )\r
+{\r
+  UINT8                              Buffer[BUFFER_SIZE];\r
+  TCG_LEVEL0_DISCOVERY_HEADER        *DiscoveryHeader;\r
+  OPAL_LEVEL0_FEATURE_DESCRIPTOR     *Feat;\r
+  UINTN                              Size;\r
+\r
+  NULL_CHECK(Session);\r
+  NULL_CHECK(LockingFeature);\r
+\r
+  ZeroMem(Buffer, BUFFER_SIZE);\r
+  ASSERT(sizeof(Buffer) >= sizeof(TCG_SUPPORTED_SECURITY_PROTOCOLS));\r
+\r
+  if (OpalRetrieveLevel0DiscoveryHeader (Session, BUFFER_SIZE, Buffer) == TcgResultFailure) {\r
+    DEBUG ((DEBUG_INFO, "OpalRetrieveLevel0DiscoveryHeader failed\n"));\r
+    return TcgResultFailure;\r
+  }\r
+  DiscoveryHeader = (TCG_LEVEL0_DISCOVERY_HEADER*) Buffer;\r
+\r
+  Size = 0;\r
+  Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_LOCKING, &Size);\r
+  if (Feat != NULL && Size >= sizeof (TCG_LOCKING_FEATURE_DESCRIPTOR)) {\r
+    CopyMem (LockingFeature, &Feat->Locking, sizeof (TCG_LOCKING_FEATURE_DESCRIPTOR));\r
+  }\r
+\r
+  return TcgResultSuccess;\r
+}\r
+\r
+/**\r
+\r
+  The function determines whether or not all of the requirements for the Opal Feature (not full specification)\r
+  are met by the specified device.\r
+\r
+  @param[in]      SupportedAttributes     Opal device attribute.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+OpalFeatureSupported(\r
+  OPAL_DISK_SUPPORT_ATTRIBUTE      *SupportedAttributes\r
+  )\r
+{\r
+  NULL_CHECK(SupportedAttributes);\r
+\r
+  if (SupportedAttributes->Sp1 == 0) {\r
+    return FALSE;\r
+  }\r
+\r
+  if (SupportedAttributes->OpalSscLite == 0 &&\r
+      SupportedAttributes->OpalSsc1 == 0 &&\r
+      SupportedAttributes->OpalSsc2 == 0 &&\r
+      SupportedAttributes->PyriteSsc == 0\r
+     ) {\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+\r
+  The function returns whether or not the device is Opal Enabled.\r
+  TRUE means that the device is partially or fully locked.\r
+  This will perform a Level 0 Discovery and parse the locking feature descriptor\r
+\r
+  @param[in]      SupportedAttributes     Opal device attribute.\r
+  @param[in]      LockingFeature          Opal device locking status.\r
+\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+OpalFeatureEnabled(\r
+  OPAL_DISK_SUPPORT_ATTRIBUTE      *SupportedAttributes,\r
+  TCG_LOCKING_FEATURE_DESCRIPTOR   *LockingFeature\r
+  )\r
+{\r
+  NULL_CHECK(SupportedAttributes);\r
+  NULL_CHECK(LockingFeature);\r
+\r
+  if (!OpalFeatureSupported (SupportedAttributes)) {\r
+    return FALSE;\r
+  }\r
+\r
+  if (LockingFeature->LockingSupported && LockingFeature->LockingEnabled) {\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+\r
+  The function returns whether or not the device is Opal Locked.\r
+  TRUE means that the device is partially or fully locked.\r
+  This will perform a Level 0 Discovery and parse the locking feature descriptor\r
+\r
+  @param[in]      SupportedAttributes     Opal device attribute.\r
+  @param[in]      LockingFeature          Opal device locking status.\r
+\r
+**/\r
+BOOLEAN\r
+OpalDeviceLocked(\r
+  OPAL_DISK_SUPPORT_ATTRIBUTE      *SupportedAttributes,\r
+  TCG_LOCKING_FEATURE_DESCRIPTOR   *LockingFeature\r
+  )\r
+{\r
+  NULL_CHECK(SupportedAttributes);\r
+  NULL_CHECK(LockingFeature);\r
+\r
+  if (!OpalFeatureEnabled (SupportedAttributes, LockingFeature)) {\r
+    return FALSE;\r
+  }\r
+\r
+  return LockingFeature->Locked;\r
+}\r
+\r
diff --git a/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalLib.inf b/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalLib.inf
new file mode 100644 (file)
index 0000000..b4589d9
--- /dev/null
@@ -0,0 +1,50 @@
+## @file\r
+#  This is a Tcg storage Opal library.\r
+#\r
+#  This module is used to provide API used by Opal password solution.\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
+# 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
+[Defines]\r
+  INF_VERSION                    = 0x00010017\r
+  BASE_NAME                      = TcgStorageOpalLib\r
+  FILE_GUID                      = F8B56221-FD5D-4215-B578-C3574AD1E253\r
+  VERSION_STRING                 = 1.0\r
+  MODULE_TYPE                    = BASE\r
+  LIBRARY_CLASS                  = TcgStorageOpalLib|DXE_DRIVER DXE_CORE DXE_SMM_DRIVER\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64\r
+#\r
+\r
+[Sources]\r
+  TcgStorageOpalCore.c\r
+  TcgStorageOpalUtil.c\r
+\r
+[LibraryClasses]\r
+  BaseLib\r
+  BaseMemoryLib\r
+  PrintLib\r
+  DebugLib\r
+  TimerLib\r
+  TcgStorageCoreLib\r
+  UefiLib\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  SecurityPkg/SecurityPkg.dec\r
+\r
+[Protocols]\r
+  gEfiStorageSecurityCommandProtocolGuid                         ## CONSUMES\r
+\r
+[BuildOptions]\r
+  MSFT:*_*_*_CC_FLAGS = /Od /GL-\r
diff --git a/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalUtil.c b/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalUtil.c
new file mode 100644 (file)
index 0000000..2d3ecb4
--- /dev/null
@@ -0,0 +1,913 @@
+/** @file\r
+  Public API for Opal Core 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
+#include <uefi.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/TcgStorageOpalLib.h>\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 session info for one opal device.\r
+  @param[in]      Psid               PSID of device to revert.\r
+  @param[in]      PsidLength         Length of PSID in bytes.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalUtilPsidRevert(\r
+  OPAL_SESSION   *Session,\r
+  const VOID     *Psid,\r
+  UINT32         PsidLength\r
+  )\r
+{\r
+  UINT8        MethodStatus;\r
+  TCG_RESULT   Ret;\r
+\r
+  NULL_CHECK(Session);\r
+  NULL_CHECK(Psid);\r
+\r
+  Ret = OpalStartSession(\r
+                      Session,\r
+                      OPAL_UID_ADMIN_SP,\r
+                      TRUE,\r
+                      PsidLength,\r
+                      Psid,\r
+                      OPAL_ADMIN_SP_PSID_AUTHORITY,\r
+                      &MethodStatus);\r
+  if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    Ret = OpalPsidRevert(Session);\r
+    if (Ret != TcgResultSuccess) {\r
+      //\r
+      // If revert was successful, session was already ended by TPer, so only end session on failure\r
+      //\r
+      OpalEndSession(Session);\r
+    }\r
+  }\r
+\r
+  if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    Ret = TcgResultFailure;\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 the OPAL_UID_ADMIN_SP_C_PIN_SID column with the new password,\r
+  and activates the locking SP to copy SID PIN to Admin1 Locking SP PIN\r
+\r
+  @param[in]      Session,           The session info for one opal device.\r
+  @param[in]      GeneratedSid       Generated SID of disk\r
+  @param[in]      SidLength          Length of generatedSid in bytes\r
+  @param[in]      Password           New admin password to set\r
+  @param[in]      PassLength         Length of password in bytes\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalUtilSetAdminPasswordAsSid(\r
+  OPAL_SESSION      *Session,\r
+  const VOID        *GeneratedSid,\r
+  UINT32            SidLength,\r
+  const VOID        *Password,\r
+  UINT32            PassLength\r
+  )\r
+{\r
+  UINT8        MethodStatus;\r
+  TCG_RESULT   Ret;\r
+\r
+  NULL_CHECK(Session);\r
+  NULL_CHECK(GeneratedSid);\r
+  NULL_CHECK(Password);\r
+\r
+  Ret = OpalStartSession(\r
+                    Session,\r
+                    OPAL_UID_ADMIN_SP,\r
+                    TRUE,\r
+                    SidLength,\r
+                    GeneratedSid,\r
+                    OPAL_ADMIN_SP_SID_AUTHORITY,\r
+                    &MethodStatus\r
+                    );\r
+  if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    DEBUG ((DEBUG_INFO, "start session with admin SP as SID authority failed: Ret=%d MethodStatus=%u\n", Ret, MethodStatus));\r
+    goto done;\r
+  }\r
+\r
+  //\r
+  // 1. Update SID = new Password\r
+  //\r
+  Ret = OpalSetPassword(\r
+                    Session,\r
+                    OPAL_UID_ADMIN_SP_C_PIN_SID,\r
+                    Password,\r
+                    PassLength,\r
+                    &MethodStatus\r
+                    );\r
+\r
+  if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    OpalEndSession(Session);\r
+    DEBUG ((DEBUG_INFO, "set Password failed: Ret=%d MethodStatus=%u\n", Ret, MethodStatus));\r
+    goto done;\r
+  }\r
+\r
+  //\r
+  // 2. Activate locking SP\r
+  //\r
+  Ret = OpalActivateLockingSp(Session, &MethodStatus);\r
+  OpalEndSession(Session);\r
+  if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    DEBUG ((DEBUG_INFO, "activate locking SP failed: Ret=%d MethodStatus=%u\n", Ret, MethodStatus));\r
+    goto done;\r
+  }\r
+\r
+done:\r
+  if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    Ret = TcgResultFailure;\r
+  }\r
+  return Ret;\r
+}\r
+\r
+/**\r
+\r
+  Opens a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY,\r
+  and updates the specified locking range with the provided column values\r
+\r
+  @param[in]      Session,               The session info for one opal device.\r
+  @param[in]      Password           New admin password to set\r
+  @param[in]      PassLength         Length of password in bytes\r
+  @param[in]      LockingRangeUid    Locking range UID to set values\r
+  @param[in]      RangeStart         Value to set RangeStart column for Locking Range\r
+  @param[in]      RangeLength        Value to set RangeLength column for Locking Range\r
+  @param[in]      ReadLockEnabled    Value to set readLockEnabled column for Locking Range\r
+  @param[in]      WriteLockEnabled   Value to set writeLockEnabled column for Locking Range\r
+  @param[in]      ReadLocked         Value to set ReadLocked column for Locking Range\r
+  @param[in]      WriteLocked        Value to set WriteLocked column for Locking Range\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalUtilSetOpalLockingRange(\r
+  OPAL_SESSION   *Session,\r
+  const VOID     *Password,\r
+  UINT32         PassLength,\r
+  TCG_UID        LockingRangeUid,\r
+  UINT64         RangeStart,\r
+  UINT64         RangeLength,\r
+  BOOLEAN        ReadLockEnabled,\r
+  BOOLEAN        WriteLockEnabled,\r
+  BOOLEAN        ReadLocked,\r
+  BOOLEAN        WriteLocked\r
+  )\r
+{\r
+  UINT8        MethodStatus;\r
+  TCG_RESULT   Ret;\r
+\r
+  NULL_CHECK(Session);\r
+  NULL_CHECK(Password);\r
+\r
+  //\r
+  // Start session with Locking SP using current admin Password\r
+  //\r
+  Ret = OpalStartSession(\r
+                      Session,\r
+                      OPAL_UID_LOCKING_SP,\r
+                      TRUE,\r
+                      PassLength,\r
+                      Password,\r
+                      OPAL_LOCKING_SP_ADMIN1_AUTHORITY,\r
+                      &MethodStatus);\r
+  if ((Ret != TcgResultSuccess) || (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS)) {\r
+    DEBUG ((DEBUG_INFO, "start session with locking SP failed: Ret=%d MethodStatus=%u\n", Ret, MethodStatus));\r
+    goto done;\r
+  }\r
+\r
+  //\r
+  // Enable locking range\r
+  //\r
+  Ret = OpalSetLockingRange(\r
+            Session,\r
+            LockingRangeUid,\r
+            RangeStart,\r
+            RangeLength,\r
+            ReadLockEnabled,\r
+            WriteLockEnabled,\r
+            ReadLocked,\r
+            WriteLocked,\r
+            &MethodStatus);\r
+\r
+  OpalEndSession(Session);\r
+  if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    DEBUG ((DEBUG_INFO, "set locking range failed: Ret=%d MethodStatus=0x%x\n", Ret, MethodStatus));\r
+  }\r
+\r
+done:\r
+  if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    Ret = TcgResultFailure;\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 session info for one 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
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalUtilSetAdminPassword(\r
+  OPAL_SESSION  *Session,\r
+  const VOID    *OldPassword,\r
+  UINT32        OldPasswordLength,\r
+  const VOID    *NewPassword,\r
+  UINT32        NewPasswordLength\r
+  )\r
+{\r
+  TCG_RESULT   Ret;\r
+  UINT8        MethodStatus;\r
+\r
+  NULL_CHECK(Session);\r
+  NULL_CHECK(OldPassword);\r
+  NULL_CHECK(NewPassword);\r
+\r
+  //\r
+  // Unknown ownership\r
+  //\r
+  Ret = OpalStartSession(\r
+                  Session,\r
+                  OPAL_UID_ADMIN_SP,\r
+                  TRUE,\r
+                  OldPasswordLength,\r
+                  OldPassword,\r
+                  OPAL_ADMIN_SP_SID_AUTHORITY,\r
+                  &MethodStatus\r
+                  );\r
+  if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    DEBUG ((DEBUG_INFO, "start session with admin SP using old Password failed\n"));\r
+    goto done;\r
+  }\r
+\r
+  //\r
+  // Update SID = new pw\r
+  //\r
+  Ret = OpalSetPassword(Session, OPAL_UID_ADMIN_SP_C_PIN_SID, NewPassword, NewPasswordLength, &MethodStatus);\r
+  OpalEndSession(Session);\r
+  if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    DEBUG ((DEBUG_INFO, "set new admin SP Password failed\n"));\r
+    goto done;\r
+  }\r
+\r
+  Ret = OpalStartSession(\r
+                  Session,\r
+                  OPAL_UID_LOCKING_SP,\r
+                  TRUE,\r
+                  OldPasswordLength,\r
+                  OldPassword,\r
+                  OPAL_LOCKING_SP_ADMIN1_AUTHORITY,\r
+                  &MethodStatus\r
+                  );\r
+  if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    DEBUG ((DEBUG_INFO, "start session with locking SP using old Password failed\n"));\r
+    goto done;\r
+  }\r
+\r
+  //\r
+  // Update admin locking SP to new pw\r
+  //\r
+  Ret = OpalSetPassword(Session, OPAL_LOCKING_SP_C_PIN_ADMIN1, NewPassword, NewPasswordLength, &MethodStatus);\r
+  OpalEndSession(Session);\r
+  if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    DEBUG ((DEBUG_INFO, "set new locking SP Password failed\n"));\r
+    goto done;\r
+  }\r
+\r
+done:\r
+  if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    Ret = TcgResultFailure;\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 sets the User1 SP authority to enabled and sets the User1 password.\r
+\r
+  @param[in]      Session,               The session info for one 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
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalUtilSetUserPassword(\r
+  OPAL_SESSION    *Session,\r
+  const VOID      *OldPassword,\r
+  UINT32          OldPasswordLength,\r
+  const VOID      *NewPassword,\r
+  UINT32          NewPasswordLength\r
+  )\r
+{\r
+  UINT8        MethodStatus;\r
+  TCG_RESULT   Ret;\r
+\r
+  NULL_CHECK(Session);\r
+  NULL_CHECK(OldPassword);\r
+  NULL_CHECK(NewPassword);\r
+\r
+  //\r
+  // See if updating user1 authority\r
+  //\r
+  Ret = OpalStartSession(\r
+                    Session,\r
+                    OPAL_UID_LOCKING_SP,\r
+                    TRUE,\r
+                    OldPasswordLength,\r
+                    OldPassword,\r
+                    OPAL_LOCKING_SP_USER1_AUTHORITY,\r
+                    &MethodStatus\r
+                    );\r
+  if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    Ret = OpalSetPassword(\r
+                      Session,\r
+                      OPAL_LOCKING_SP_C_PIN_USER1,\r
+                      NewPassword,\r
+                      NewPasswordLength,\r
+                      &MethodStatus\r
+                      );\r
+    OpalEndSession(Session);\r
+    if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+      return Ret;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Setting Password for first time or setting Password as admin\r
+  //\r
+\r
+  //\r
+  // Start session with Locking SP using current admin Password\r
+  //\r
+  Ret = OpalStartSession(\r
+                    Session,\r
+                    OPAL_UID_LOCKING_SP,\r
+                    TRUE,\r
+                    OldPasswordLength,\r
+                    OldPassword,\r
+                    OPAL_LOCKING_SP_ADMIN1_AUTHORITY,\r
+                    &MethodStatus\r
+                    );\r
+  if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    DEBUG ((DEBUG_INFO, "StartSession with locking SP as admin1 authority failed\n"));\r
+    goto done;\r
+  }\r
+\r
+  //\r
+  // Enable User1 and set its PIN\r
+  //\r
+  Ret = OpalSetLockingSpAuthorityEnabledAndPin(\r
+                                          Session,\r
+                                          OPAL_LOCKING_SP_C_PIN_USER1,\r
+                                          OPAL_LOCKING_SP_USER1_AUTHORITY,\r
+                                          NewPassword,\r
+                                          NewPasswordLength,\r
+                                          &MethodStatus\r
+                                          );\r
+  OpalEndSession(Session);\r
+  if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    DEBUG ((DEBUG_INFO, "OpalSetLockingSpAuthorityEnabledAndPin failed\n"));\r
+    goto done;\r
+  }\r
+\r
+done:\r
+  if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    Ret = TcgResultFailure;\r
+  }\r
+  return Ret;\r
+}\r
+\r
+/**\r
+  Verify whether user input the correct password.\r
+\r
+  @param[in]      Session,               The session info for one opal device.\r
+  @param[in]      Password                    Admin password\r
+  @param[in]      PasswordLength              Length of password in bytes\r
+  @param[in/out]  HostSigningAuthority        Use the Host signing authority type.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalUtilVerifyPassword (\r
+  OPAL_SESSION   *Session,\r
+  const VOID     *Password,\r
+  UINT32         PasswordLength,\r
+  TCG_UID        HostSigningAuthority\r
+  )\r
+{\r
+  TCG_RESULT                    Ret;\r
+  UINT8                         MethodStatus;\r
+\r
+  NULL_CHECK(Session);\r
+  NULL_CHECK(Password);\r
+\r
+  Ret = OpalStartSession(\r
+            Session,\r
+            OPAL_UID_LOCKING_SP,\r
+            TRUE,\r
+            PasswordLength,\r
+            Password,\r
+            HostSigningAuthority,\r
+            &MethodStatus);\r
+  if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    OpalEndSession(Session);\r
+    return TcgResultSuccess;\r
+  }\r
+\r
+  return TcgResultFailure;\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 generates a new global locking range key to erase the Data.\r
+\r
+  @param[in]      Session,               The session info for one opal device.\r
+  @param[in]      Password                   Admin or user password\r
+  @param[in]      PasswordLength         Length of password in bytes\r
+  @param[in/out]  PasswordFailed       indicates if password failed (start session didn't work)\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalUtilSecureErase(\r
+  OPAL_SESSION     *Session,\r
+  const VOID       *Password,\r
+  UINT32           PasswordLength,\r
+  BOOLEAN          *PasswordFailed\r
+  )\r
+{\r
+  UINT8        MethodStatus;\r
+  TCG_RESULT   Ret;\r
+\r
+  NULL_CHECK(Session);\r
+  NULL_CHECK(Password);\r
+  NULL_CHECK(PasswordFailed);\r
+\r
+  //\r
+  // Try to generate a new key with admin1\r
+  //\r
+  Ret = OpalStartSession(\r
+                      Session,\r
+                      OPAL_UID_LOCKING_SP,\r
+                      TRUE,\r
+                      PasswordLength,\r
+                      Password,\r
+                      OPAL_LOCKING_SP_ADMIN1_AUTHORITY,\r
+                      &MethodStatus\r
+                      );\r
+\r
+  if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    Ret = OpalGlobalLockingRangeGenKey(Session, &MethodStatus);\r
+    *PasswordFailed = FALSE;\r
+    OpalEndSession(Session);\r
+  } else {\r
+    //\r
+    // Try to generate a new key with user1\r
+    //\r
+    Ret = OpalStartSession(\r
+                      Session,\r
+                      OPAL_UID_LOCKING_SP,\r
+                      TRUE,\r
+                      PasswordLength,\r
+                      Password,\r
+                      OPAL_LOCKING_SP_USER1_AUTHORITY,\r
+                      &MethodStatus\r
+                      );\r
+\r
+    if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+      Ret = OpalGlobalLockingRangeGenKey(Session, &MethodStatus);\r
+      *PasswordFailed = FALSE;\r
+      OpalEndSession(Session);\r
+    } else {\r
+      *PasswordFailed = TRUE;\r
+    }\r
+  }\r
+\r
+  if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    Ret = TcgResultFailure;\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 session info for one opal device.\r
+  @param[in]      Password               Admin password\r
+  @param[in]      PasswordLength         Length of password in bytes\r
+  @param[in/out]  PasswordFailed         indicates if password failed (start session didn't work)\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalUtilDisableUser(\r
+  OPAL_SESSION   *Session,\r
+  const VOID     *Password,\r
+  UINT32         PasswordLength,\r
+  BOOLEAN        *PasswordFailed\r
+  )\r
+{\r
+  UINT8        MethodStatus;\r
+  TCG_RESULT   Ret;\r
+\r
+  NULL_CHECK(Session);\r
+  NULL_CHECK(Password);\r
+  NULL_CHECK(PasswordFailed);\r
+\r
+  //\r
+  // Start session with Locking SP using current admin Password\r
+  //\r
+  Ret = OpalStartSession(\r
+                    Session,\r
+                    OPAL_UID_LOCKING_SP,\r
+                    TRUE,\r
+                    PasswordLength,\r
+                    Password,\r
+                    OPAL_LOCKING_SP_ADMIN1_AUTHORITY,\r
+                    &MethodStatus\r
+                    );\r
+  if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    DEBUG ((DEBUG_INFO, "StartSession with Locking SP as Admin1 failed\n"));\r
+    *PasswordFailed = TRUE;\r
+    goto done;\r
+  }\r
+\r
+  *PasswordFailed = FALSE;\r
+  Ret = OpalDisableUser(Session, &MethodStatus);\r
+  OpalEndSession(Session);\r
+\r
+done:\r
+  if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    Ret = TcgResultFailure;\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 session info for one 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/out]  PasswordFailed     indicates if password failed (start session didn't work)\r
+  @param[in]      Msid               Msid info.\r
+  @param[in]      MsidLength         Msid data length.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalUtilRevert(\r
+  OPAL_SESSION     *Session,\r
+  BOOLEAN          KeepUserData,\r
+  const VOID       *Password,\r
+  UINT32           PasswordLength,\r
+  BOOLEAN          *PasswordFailed,\r
+  UINT8            *Msid,\r
+  UINT32           MsidLength\r
+  )\r
+{\r
+  UINT8        MethodStatus;\r
+  TCG_RESULT   Ret;\r
+\r
+  NULL_CHECK(Session);\r
+  NULL_CHECK(Msid);\r
+  NULL_CHECK(Password);\r
+  NULL_CHECK(PasswordFailed);\r
+\r
+  Ret = OpalStartSession(\r
+                   Session,\r
+                   OPAL_UID_LOCKING_SP,\r
+                   TRUE,\r
+                   PasswordLength,\r
+                   Password,\r
+                   OPAL_LOCKING_SP_ADMIN1_AUTHORITY,\r
+                   &MethodStatus\r
+                   );\r
+\r
+  if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    DEBUG ((DEBUG_INFO, "error starting session: Ret=%d, MethodStatus=%u\n", Ret, MethodStatus));\r
+    *PasswordFailed = TRUE;\r
+    goto done;\r
+  }\r
+\r
+  *PasswordFailed = FALSE;\r
+  //\r
+  // Try to revert with admin1\r
+  //\r
+  Ret = OpalAdminRevert(Session, KeepUserData, &MethodStatus);\r
+  if (Ret != TcgResultSuccess || MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    //\r
+    // Device ends the session on successful revert, so only call OpalEndSession when fail.\r
+    //\r
+    DEBUG ((DEBUG_INFO, "OpalAdminRevert as admin failed\n"));\r
+    OpalEndSession(Session);\r
+  }\r
+\r
+  Ret = OpalUtilSetSIDtoMSID (Session, Password, PasswordLength, Msid, MsidLength);\r
+\r
+done:\r
+  if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    Ret = TcgResultFailure;\r
+  }\r
+  return Ret;\r
+}\r
+\r
+/**\r
+  After revert success, set SID to MSID.\r
+\r
+  @param          Session,           The session info for one opal device.\r
+  @param          Password,          Input password info.\r
+  @param          PasswordLength,    Input password length.\r
+  @param          Msid               Msid info.\r
+  @param          MsidLength         Msid data length.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalUtilSetSIDtoMSID (\r
+  OPAL_SESSION     *Session,\r
+  const VOID       *Password,\r
+  UINT32           PasswordLength,\r
+  UINT8            *Msid,\r
+  UINT32           MsidLength\r
+  )\r
+{\r
+  TCG_RESULT                   Ret;\r
+  UINT8                        MethodStatus;\r
+\r
+  NULL_CHECK(Session);\r
+  NULL_CHECK(Msid);\r
+  NULL_CHECK(Password);\r
+\r
+  //\r
+  // Start session with admin sp to update SID to MSID\r
+  //\r
+  Ret = OpalStartSession(\r
+            Session,\r
+            OPAL_UID_ADMIN_SP,\r
+            TRUE,\r
+            PasswordLength,\r
+            Password,\r
+            OPAL_ADMIN_SP_SID_AUTHORITY,\r
+            &MethodStatus\r
+            );\r
+  if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    goto done;\r
+  }\r
+\r
+  //\r
+  // Update SID pin\r
+  //\r
+  Ret = OpalSetPassword(Session, OPAL_UID_ADMIN_SP_C_PIN_SID, Msid, MsidLength, &MethodStatus);\r
+  OpalEndSession(Session);\r
+\r
+done:\r
+  if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    Ret = TcgResultFailure;\r
+  }\r
+\r
+  return Ret;\r
+}\r
+\r
+/**\r
+  Update global locking range.\r
+\r
+  @param          Session,           The session info for one opal device.\r
+  @param          Password,          Input password info.\r
+  @param          PasswordLength,    Input password length.\r
+  @param          ReadLocked,        Read lock info.\r
+  @param          WriteLocked        write lock info.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalUtilUpdateGlobalLockingRange(\r
+  OPAL_SESSION    *Session,\r
+  const VOID      *Password,\r
+  UINT32          PasswordLength,\r
+  BOOLEAN         ReadLocked,\r
+  BOOLEAN         WriteLocked\r
+  )\r
+{\r
+  UINT8        MethodStatus;\r
+  TCG_RESULT   Ret;\r
+\r
+  NULL_CHECK(Session);\r
+  NULL_CHECK(Password);\r
+\r
+  //\r
+  // Try to start session with Locking SP as admin1 authority\r
+  //\r
+  Ret = OpalStartSession(\r
+                    Session,\r
+                    OPAL_UID_LOCKING_SP,\r
+                    TRUE,\r
+                    PasswordLength,\r
+                    Password,\r
+                    OPAL_LOCKING_SP_ADMIN1_AUTHORITY,\r
+                    &MethodStatus\r
+                    );\r
+  if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    Ret = OpalUpdateGlobalLockingRange(\r
+                                Session,\r
+                                ReadLocked,\r
+                                WriteLocked,\r
+                                &MethodStatus\r
+                                );\r
+    OpalEndSession(Session);\r
+    if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+      goto done;\r
+    }\r
+  }\r
+\r
+  if (MethodStatus == TCG_METHOD_STATUS_CODE_AUTHORITY_LOCKED_OUT) {\r
+    DEBUG ((DEBUG_INFO, "unlock as admin failed with AUTHORITY_LOCKED_OUT\n"));\r
+    goto done;\r
+  }\r
+\r
+  //\r
+  // Try user1 authority\r
+  //\r
+  Ret = OpalStartSession(\r
+                    Session,\r
+                    OPAL_UID_LOCKING_SP,\r
+                    TRUE,\r
+                    PasswordLength,\r
+                    Password,\r
+                    OPAL_LOCKING_SP_USER1_AUTHORITY,\r
+                    &MethodStatus\r
+                    );\r
+  if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    DEBUG ((DEBUG_INFO, "StartSession with Locking SP as User1 failed\n"));\r
+    goto done;\r
+  }\r
+\r
+  Ret = OpalUpdateGlobalLockingRange(Session, ReadLocked, WriteLocked, &MethodStatus);\r
+  OpalEndSession(Session);\r
+\r
+done:\r
+  if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    Ret = TcgResultFailure;\r
+  }\r
+  return Ret;\r
+}\r
+\r
+/**\r
+  Update global locking range.\r
+\r
+  @param          Session,           The session info for one opal device.\r
+  @param          Msid,              The data buffer to save Msid info.\r
+  @param          MsidBufferLength,  The data buffer length for Msid.\r
+  @param          MsidLength,        The actual data length for Msid.\r
+\r
+**/\r
+TCG_RESULT\r
+EFIAPI\r
+OpalUtilGetMsid(\r
+  OPAL_SESSION    *Session,\r
+  UINT8           *Msid,\r
+  UINT32          MsidBufferLength,\r
+  UINT32          *MsidLength\r
+  )\r
+{\r
+  UINT8        MethodStatus;\r
+  TCG_RESULT   Ret;\r
+\r
+  NULL_CHECK(Session);\r
+  NULL_CHECK(Msid);\r
+  NULL_CHECK(MsidLength);\r
+\r
+  Ret = OpalStartSession(\r
+                   Session,\r
+                   OPAL_UID_ADMIN_SP,\r
+                   TRUE,\r
+                   0,\r
+                   NULL,\r
+                   TCG_UID_NULL,\r
+                   &MethodStatus\r
+                   );\r
+  if ((Ret == TcgResultSuccess) && (MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS)) {\r
+    Ret = OpalGetMsid (Session, MsidBufferLength, Msid, MsidLength);\r
+    OpalEndSession (Session);\r
+  }\r
+\r
+  if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {\r
+    Ret = TcgResultFailure;\r
+  }\r
+\r
+  return Ret;\r
+}\r
+\r
+/**\r
+\r
+  The function determines who owns the device by attempting to start a session with different credentials.\r
+  If the SID PIN matches the MSID PIN, the no one owns the device.\r
+  If the SID PIN matches the ourSidPin, then "Us" owns the device.  Otherwise it is unknown.\r
+\r
+\r
+  @param[in]      Session            The session info for one opal device.\r
+  @param          Msid,              The Msid info.\r
+  @param          MsidLength,        The data length for Msid.\r
+\r
+**/\r
+OPAL_OWNER_SHIP\r
+EFIAPI\r
+OpalUtilDetermineOwnership(\r
+  OPAL_SESSION       *Session,\r
+  UINT8              *Msid,\r
+  UINT32             MsidLength\r
+  )\r
+{\r
+  UINT8            MethodStatus;\r
+  TCG_RESULT       Ret;\r
+  OPAL_OWNER_SHIP  Owner;\r
+\r
+  NULL_CHECK(Session);\r
+  NULL_CHECK(Msid);\r
+\r
+  Owner = OpalOwnershipUnknown;\r
+  //\r
+  // Start Session as SID_UID with ADMIN_SP using MSID PIN\r
+  //\r
+  Ret = OpalStartSession(\r
+                    Session,\r
+                    OPAL_UID_ADMIN_SP,\r
+                    TRUE,\r
+                    MsidLength,\r
+                    Msid,\r
+                    OPAL_ADMIN_SP_SID_AUTHORITY,\r
+                    &MethodStatus);\r
+  if ((Ret == TcgResultSuccess) && (MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS)) {\r
+    //\r
+    // now we know that SID PIN == MSID PIN\r
+    //\r
+    Owner = OpalOwnershipNobody;\r
+\r
+    OpalEndSession(Session);\r
+  }\r
+\r
+  return Owner;\r
+}\r
+\r
+/**\r
+\r
+  The function returns if admin password exists.\r
+\r
+  @param[in]      OwnerShip         The owner ship of the opal device.\r
+  @param[in]      LockingFeature    The locking info of the opal device.\r
+\r
+  @retval         TRUE              Admin password existed.\r
+  @retval         FALSE             Admin password not existed.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+OpalUtilAdminPasswordExists(\r
+  IN  UINT16                           OwnerShip,\r
+  IN  TCG_LOCKING_FEATURE_DESCRIPTOR   *LockingFeature\r
+  )\r
+{\r
+  NULL_CHECK(LockingFeature);\r
+\r
+  // if it is Unknown who owns the device\r
+  // then someone has set password previously through our UI\r
+  // because the SID would no longer match the generated SID (ownership us)\r
+  // or someone has set password using 3rd party software\r
+\r
+  //\r
+  // Locking sp enabled is checked b/c it must be enabled to change the PIN of the Admin1.\r
+  //\r
+  return (OwnerShip == OpalOwnershipUnknown && LockingFeature->LockingEnabled);\r
+}\r
+\r