Home | History | Annotate | Download | only in OpalPasswordSupportLib
      1 /** @file
      2   Implementation of Opal password support library.
      3 
      4 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "OpalPasswordSupportNotify.h"
     16 
     17 #define OPAL_PASSWORD_MAX_LENGTH         32
     18 
     19 LIST_ENTRY           mDeviceList = INITIALIZE_LIST_HEAD_VARIABLE (mDeviceList);
     20 BOOLEAN              gInSmm = FALSE;
     21 EFI_GUID             gOpalPasswordNotifyProtocolGuid = OPAL_PASSWORD_NOTIFY_PROTOCOL_GUID;
     22 
     23 /**
     24 
     25   The function performs determines the available actions for the OPAL_DISK provided.
     26 
     27   @param[in]   SupportedAttributes   The support attribute for the device.
     28   @param[in]   LockingFeature        The locking status for the device.
     29   @param[in]   OwnerShip             The ownership for the device.
     30   @param[out]  AvalDiskActions       Pointer to fill-out with appropriate disk actions.
     31 
     32 **/
     33 TCG_RESULT
     34 EFIAPI
     35 OpalSupportGetAvailableActions(
     36   IN  OPAL_DISK_SUPPORT_ATTRIBUTE      *SupportedAttributes,
     37   IN  TCG_LOCKING_FEATURE_DESCRIPTOR   *LockingFeature,
     38   IN  UINT16                           OwnerShip,
     39   OUT OPAL_DISK_ACTIONS                *AvalDiskActions
     40   )
     41 {
     42   BOOLEAN ExistingPassword;
     43 
     44   NULL_CHECK(AvalDiskActions);
     45 
     46   AvalDiskActions->AdminPass = 1;
     47   AvalDiskActions->UserPass = 0;
     48   AvalDiskActions->DisableUser = 0;
     49   AvalDiskActions->Unlock = 0;
     50 
     51   //
     52   // Revert is performed on locking sp, so only allow if locking sp is enabled
     53   //
     54   if (LockingFeature->LockingEnabled) {
     55     AvalDiskActions->Revert = 1;
     56   }
     57 
     58   //
     59   // Psid revert is available for any device with media encryption support
     60   // Revert is allowed for any device with media encryption support, however it requires
     61   //
     62   if (SupportedAttributes->MediaEncryption) {
     63 
     64     //
     65     // Only allow psid revert if media encryption is enabled.
     66     // Otherwise, someone who steals a disk can psid revert the disk and the user Data is still
     67     // intact and accessible
     68     //
     69     AvalDiskActions->PsidRevert = 1;
     70     AvalDiskActions->RevertKeepDataForced = 0;
     71 
     72     //
     73     // Secure erase is performed by generating a new encryption key
     74     // this is only available is encryption is supported
     75     //
     76     AvalDiskActions->SecureErase = 1;
     77   } else {
     78     AvalDiskActions->PsidRevert = 0;
     79     AvalDiskActions->SecureErase = 0;
     80 
     81     //
     82     // If no media encryption is supported, then a revert (using password) will not
     83     // erase the Data (since you can't generate a new encryption key)
     84     //
     85     AvalDiskActions->RevertKeepDataForced = 1;
     86   }
     87 
     88   if (LockingFeature->Locked) {
     89     AvalDiskActions->Unlock = 1;
     90   } else {
     91     AvalDiskActions->Unlock = 0;
     92   }
     93 
     94   //
     95   // Only allow user to set password if an admin password exists
     96   //
     97   ExistingPassword = OpalUtilAdminPasswordExists(OwnerShip, LockingFeature);
     98   AvalDiskActions->UserPass = ExistingPassword;
     99 
    100   //
    101   // This will still show up even if there isn't a user, which is fine
    102   //
    103   AvalDiskActions->DisableUser = ExistingPassword;
    104 
    105   return TcgResultSuccess;
    106 }
    107 
    108 /**
    109   Creates a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY, then reverts device using Admin SP Revert method.
    110 
    111   @param[in]      Session            The opal session for the opal device.
    112   @param[in]      Psid               PSID of device to revert.
    113   @param[in]      PsidLength         Length of PSID in bytes.
    114   @param[in]      DevicePath         The device path for the opal devcie.
    115 
    116 **/
    117 TCG_RESULT
    118 EFIAPI
    119 OpalSupportPsidRevert(
    120   IN OPAL_SESSION              *Session,
    121   IN VOID                      *Psid,
    122   IN UINT32                    PsidLength,
    123   IN EFI_DEVICE_PATH_PROTOCOL  *DevicePath
    124   )
    125 {
    126   TCG_RESULT   Ret;
    127 
    128   NULL_CHECK(Session);
    129   NULL_CHECK(Psid);
    130 
    131   Ret = OpalUtilPsidRevert (Session, Psid, PsidLength);
    132   if (Ret == TcgResultSuccess && !gInSmm) {
    133     OpalSupportSendPasword (DevicePath, 0, NULL);
    134   }
    135 
    136   return Ret;
    137 }
    138 
    139 /**
    140   Opens a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_SID_AUTHORITY,
    141   sets OPAL_UID_ADMIN_SP_C_PIN_SID with the new password,
    142   and sets OPAL_LOCKING_SP_C_PIN_ADMIN1 with the new password.
    143 
    144   @param[in]      Session            The opal session for the opal device.
    145   @param[in]      OldPassword        Current admin password
    146   @param[in]      OldPasswordLength  Length of current admin password in bytes
    147   @param[in]      NewPassword        New admin password to set
    148   @param[in]      NewPasswordLength  Length of new password in bytes
    149   @param[in]      DevicePath         The device path for the opal devcie.
    150   @param[in]      SetAdmin           Whether set admin password or user password.
    151                                      TRUE for admin, FALSE for user.
    152 
    153 **/
    154 TCG_RESULT
    155 EFIAPI
    156 OpalSupportSetPassword(
    157   IN OPAL_SESSION              *Session,
    158   IN VOID                      *OldPassword,
    159   IN UINT32                    OldPasswordLength,
    160   IN VOID                      *NewPassword,
    161   IN UINT32                    NewPasswordLength,
    162   IN EFI_DEVICE_PATH_PROTOCOL  *DevicePath,
    163   IN BOOLEAN                   SetAdmin
    164   )
    165 {
    166   TCG_RESULT   Ret;
    167 
    168   NULL_CHECK(Session);
    169   NULL_CHECK(OldPassword);
    170   NULL_CHECK(NewPassword);
    171 
    172   if (SetAdmin) {
    173     Ret = OpalUtilSetAdminPassword(Session, OldPassword, OldPasswordLength, NewPassword, NewPasswordLength);
    174   } else {
    175     Ret = OpalUtilSetUserPassword(Session, OldPassword, OldPasswordLength, NewPassword, NewPasswordLength);
    176   }
    177   if (Ret == TcgResultSuccess && !gInSmm) {
    178     OpalSupportSendPasword (DevicePath, NewPasswordLength, NewPassword);
    179   }
    180 
    181   return Ret;
    182 }
    183 
    184 /**
    185   Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY and disables the User1 authority.
    186 
    187   @param[in]      Session            The opal session for the opal device.
    188   @param[in]      Password           Admin password
    189   @param[in]      PasswordLength     Length of password in bytes
    190   @param[out]     PasswordFailed     Indicates if password failed (start session didn't work)
    191   @param[in]      DevicePath         The device path for the opal devcie.
    192 
    193 **/
    194 TCG_RESULT
    195 EFIAPI
    196 OpalSupportDisableUser(
    197   IN  OPAL_SESSION              *Session,
    198   IN  VOID                      *Password,
    199   IN  UINT32                    PasswordLength,
    200   OUT BOOLEAN                   *PasswordFailed,
    201   IN  EFI_DEVICE_PATH_PROTOCOL  *DevicePath
    202   )
    203 {
    204   TCG_RESULT   Ret;
    205 
    206   NULL_CHECK(Session);
    207   NULL_CHECK(Password);
    208   NULL_CHECK(PasswordFailed);
    209 
    210   Ret = OpalUtilDisableUser(Session, Password, PasswordLength, PasswordFailed);
    211   if (Ret == TcgResultSuccess && !gInSmm) {
    212     OpalSupportSendPasword (DevicePath, PasswordLength, Password);
    213   }
    214 
    215   return Ret;
    216 }
    217 
    218 /**
    219   Enable Opal Feature for the input device.
    220 
    221   @param[in]      Session            The opal session for the opal device.
    222   @param[in]      Msid               Msid
    223   @param[in]      MsidLength         Msid Length
    224   @param[in]      Password           Admin password
    225   @param[in]      PassLength         Length of password in bytes
    226   @param[in]      DevicePath         The device path for the opal devcie.
    227 
    228 **/
    229 TCG_RESULT
    230 EFIAPI
    231 OpalSupportEnableOpalFeature (
    232   IN OPAL_SESSION              *Session,
    233   IN VOID                      *Msid,
    234   IN UINT32                    MsidLength,
    235   IN VOID                      *Password,
    236   IN UINT32                    PassLength,
    237   IN EFI_DEVICE_PATH_PROTOCOL  *DevicePath
    238   )
    239 {
    240   TCG_RESULT   Ret;
    241 
    242   NULL_CHECK(Session);
    243   NULL_CHECK(Msid);
    244   NULL_CHECK(Password);
    245 
    246   Ret = OpalUtilSetAdminPasswordAsSid(
    247                           Session,
    248                           Msid,
    249                           MsidLength,
    250                           Password,
    251                           PassLength
    252                           );
    253   if (Ret == TcgResultSuccess) {
    254     //
    255     // Enable global locking range
    256     //
    257     Ret = OpalUtilSetOpalLockingRange(
    258                               Session,
    259                               Password,
    260                               PassLength,
    261                               OPAL_LOCKING_SP_LOCKING_GLOBALRANGE,
    262                               0,
    263                               0,
    264                               TRUE,
    265                               TRUE,
    266                               FALSE,
    267                               FALSE
    268                               );
    269   }
    270 
    271   if (Ret == TcgResultSuccess && !gInSmm) {
    272     OpalSupportSendPasword (DevicePath, PassLength, Password);
    273   }
    274 
    275   return Ret;
    276 }
    277 
    278 /**
    279   Opens a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY, then reverts the device using the RevertSP method.
    280 
    281   @param[in]      Session            The opal session for the opal device.
    282   @param[in]      KeepUserData       TRUE to keep existing Data on the disk, or FALSE to erase it
    283   @param[in]      Password           Admin password
    284   @param[in]      PasswordLength     Length of password in bytes
    285   @param[in]      Msid               Msid
    286   @param[in]      MsidLength         Msid Length
    287   @param[out]     PasswordFailed     indicates if password failed (start session didn't work)
    288   @param[in]      DevicePath         The device path for the opal devcie.
    289 
    290 **/
    291 TCG_RESULT
    292 EFIAPI
    293 OpalSupportRevert(
    294   IN  OPAL_SESSION              *Session,
    295   IN  BOOLEAN                   KeepUserData,
    296   IN  VOID                      *Password,
    297   IN  UINT32                    PasswordLength,
    298   IN  VOID                      *Msid,
    299   IN  UINT32                    MsidLength,
    300   OUT BOOLEAN                   *PasswordFailed,
    301   IN  EFI_DEVICE_PATH_PROTOCOL  *DevicePath
    302   )
    303 {
    304   TCG_RESULT   Ret;
    305 
    306   NULL_CHECK(Session);
    307   NULL_CHECK(Password);
    308   NULL_CHECK(Msid);
    309   NULL_CHECK(PasswordFailed);
    310 
    311   Ret = OpalUtilRevert(Session, KeepUserData, Password, PasswordLength, PasswordFailed, Msid, MsidLength);
    312   if (Ret == TcgResultSuccess && !gInSmm) {
    313     OpalSupportSendPasword (DevicePath, 0, NULL);
    314   }
    315 
    316   return Ret;
    317 }
    318 
    319 /**
    320   Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_USER1_AUTHORITY or OPAL_LOCKING_SP_ADMIN1_AUTHORITY
    321   and updates the global locking range ReadLocked and WriteLocked columns to FALSE.
    322 
    323   @param[in]      Session            The opal session for the opal device.
    324   @param[in]      Password           Admin or user password
    325   @param[in]      PasswordLength     Length of password in bytes
    326   @param[in]      DevicePath         The device path for the opal devcie.
    327 
    328 **/
    329 TCG_RESULT
    330 EFIAPI
    331 OpalSupportUnlock(
    332   IN OPAL_SESSION               *Session,
    333   IN VOID                       *Password,
    334   IN UINT32                     PasswordLength,
    335   IN EFI_DEVICE_PATH_PROTOCOL   *DevicePath
    336   )
    337 {
    338   TCG_RESULT   Ret;
    339 
    340   NULL_CHECK(Session);
    341   NULL_CHECK(Password);
    342 
    343   Ret = OpalUtilUpdateGlobalLockingRange(Session, Password, PasswordLength, FALSE, FALSE);
    344   if (Ret == TcgResultSuccess && !gInSmm) {
    345     OpalSupportSendPasword (DevicePath, PasswordLength, Password);
    346   }
    347 
    348   return Ret;
    349 }
    350 
    351 /**
    352   Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_USER1_AUTHORITY or OPAL_LOCKING_SP_ADMIN1_AUTHORITY
    353   and updates the global locking range ReadLocked and WriteLocked columns to TRUE.
    354 
    355   @param[in]      Session             The opal session for the opal device.
    356   @param[in]      Password            Admin or user password
    357   @param[in]      PasswordLength      Length of password in bytes
    358   @param[in]      DevicePath          The device path for the opal devcie.
    359 
    360 **/
    361 TCG_RESULT
    362 EFIAPI
    363 OpalSupportLock(
    364   IN OPAL_SESSION               *Session,
    365   IN VOID                       *Password,
    366   IN UINT32                     PasswordLength,
    367   IN EFI_DEVICE_PATH_PROTOCOL   *DevicePath
    368   )
    369 {
    370   TCG_RESULT  Ret;
    371 
    372   NULL_CHECK(Session);
    373   NULL_CHECK(Password);
    374 
    375   Ret = OpalUtilUpdateGlobalLockingRange(Session, Password, PasswordLength, TRUE, TRUE);
    376   if (Ret == TcgResultSuccess && !gInSmm) {
    377     OpalSupportSendPasword (DevicePath, PasswordLength, Password);
    378   }
    379 
    380   return Ret;
    381 }
    382 
    383 /**
    384   Initialize the communicate Buffer using DataSize and Function.
    385 
    386   @param[out]      DataPtr          Points to the Data in the communicate Buffer.
    387   @param[in]       DataSize         The Data Size to send to SMM.
    388   @param[in]       Function         The function number to initialize the communicate Header.
    389 
    390   @retval EFI_INVALID_PARAMETER     The Data Size is too big.
    391   @retval EFI_SUCCESS               Find the specified variable.
    392 
    393 **/
    394 VOID*
    395 OpalInitCommunicateBuffer (
    396   OUT     VOID                              **DataPtr OPTIONAL,
    397   IN      UINTN                             DataSize,
    398   IN      UINTN                             Function
    399   )
    400 {
    401   EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;
    402   OPAL_SMM_COMMUNICATE_HEADER               *SmmFunctionHeader;
    403   VOID                                      *Buffer;
    404   EDKII_PI_SMM_COMMUNICATION_REGION_TABLE   *SmmCommRegionTable;
    405   EFI_MEMORY_DESCRIPTOR                     *SmmCommMemRegion;
    406   UINTN                                     Index;
    407   UINTN                                     Size;
    408   EFI_STATUS                                Status;
    409 
    410   Buffer = NULL;
    411   Status = EfiGetSystemConfigurationTable (
    412              &gEdkiiPiSmmCommunicationRegionTableGuid,
    413              (VOID **) &SmmCommRegionTable
    414              );
    415   if (EFI_ERROR (Status)) {
    416     return NULL;
    417   }
    418 
    419   ASSERT (SmmCommRegionTable != NULL);
    420   SmmCommMemRegion = (EFI_MEMORY_DESCRIPTOR *) (SmmCommRegionTable + 1);
    421   Size = 0;
    422   for (Index = 0; Index < SmmCommRegionTable->NumberOfEntries; Index++) {
    423     if (SmmCommMemRegion->Type == EfiConventionalMemory) {
    424       Size = EFI_PAGES_TO_SIZE ((UINTN) SmmCommMemRegion->NumberOfPages);
    425       if (Size >= (DataSize + OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + OFFSET_OF (OPAL_SMM_COMMUNICATE_HEADER, Data))) {
    426         break;
    427       }
    428     }
    429     SmmCommMemRegion = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) SmmCommMemRegion + SmmCommRegionTable->DescriptorSize);
    430   }
    431   ASSERT (Index < SmmCommRegionTable->NumberOfEntries);
    432 
    433   Buffer = (VOID*)(UINTN)SmmCommMemRegion->PhysicalStart;
    434   ASSERT (Buffer != NULL);
    435 
    436   SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) Buffer;
    437   CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gOpalPasswordNotifyProtocolGuid);
    438   SmmCommunicateHeader->MessageLength = DataSize + OFFSET_OF (OPAL_SMM_COMMUNICATE_HEADER, Data);
    439 
    440   SmmFunctionHeader = (OPAL_SMM_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;
    441   SmmFunctionHeader->Function = Function;
    442   if (DataPtr != NULL) {
    443     *DataPtr = SmmFunctionHeader->Data;
    444   }
    445 
    446   return Buffer;
    447 }
    448 
    449 /**
    450   Send the Data in communicate Buffer to SMM.
    451 
    452   @param[in]   Buffer                 Points to the Data in the communicate Buffer.
    453   @param[in]   DataSize               This Size of the function Header and the Data.
    454 
    455   @retval      EFI_SUCCESS            Success is returned from the functin in SMM.
    456   @retval      Others                 Failure is returned from the function in SMM.
    457 
    458 **/
    459 EFI_STATUS
    460 OpalSendCommunicateBuffer (
    461   IN      VOID                              *Buffer,
    462   IN      UINTN                             DataSize
    463   )
    464 {
    465   EFI_STATUS                                Status;
    466   UINTN                                     CommSize;
    467   EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;
    468   OPAL_SMM_COMMUNICATE_HEADER               *SmmFunctionHeader;
    469   EFI_SMM_COMMUNICATION_PROTOCOL            *SmmCommunication;
    470 
    471   Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &SmmCommunication);
    472   if (EFI_ERROR (Status)) {
    473     return Status;
    474   }
    475 
    476   CommSize = DataSize + OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + OFFSET_OF (OPAL_SMM_COMMUNICATE_HEADER, Data);
    477   Status = SmmCommunication->Communicate (SmmCommunication, Buffer, &CommSize);
    478   if (EFI_ERROR (Status)) {
    479     return Status;
    480   }
    481 
    482   SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) Buffer;
    483   SmmFunctionHeader    = (OPAL_SMM_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data;
    484 
    485   return  SmmFunctionHeader->ReturnStatus;
    486 }
    487 
    488 /**
    489   Transfer the password to the smm driver.
    490 
    491   @param[in]  DevicePath     The device path for the opal devcie.
    492   @param      PasswordLen    The input password length.
    493   @param      Password       Input password buffer.
    494 
    495   @retval  EFI_SUCCESS       Do the required action success.
    496   @retval  Others            Error occured.
    497 
    498 **/
    499 EFI_STATUS
    500 EFIAPI
    501 OpalSupportSendPasword(
    502   EFI_DEVICE_PATH_PROTOCOL    *DevicePath,
    503   UINTN                       PasswordLen,
    504   VOID                        *Password
    505   )
    506 {
    507   OPAL_COMM_DEVICE_LIST   *Parameter;
    508   VOID                    *Buffer;
    509   UINTN                   Length;
    510   EFI_STATUS              Status;
    511   UINTN                   DevicePathLen;
    512 
    513   Parameter = NULL;
    514   Buffer = NULL;
    515 
    516   if (DevicePath == NULL) {
    517     //
    518     // Assume DevicePath == NULL only when library used by SMM driver
    519     // and should not run to here, just return success.
    520     //
    521     return EFI_SUCCESS;
    522   }
    523 
    524   DevicePathLen = GetDevicePathSize (DevicePath);
    525   Length = OFFSET_OF (OPAL_COMM_DEVICE_LIST, OpalDevicePath) + DevicePathLen;
    526   Buffer = OpalInitCommunicateBuffer((VOID**)&Parameter, Length, SMM_FUNCTION_SET_OPAL_PASSWORD);
    527   if (Buffer == NULL) {
    528     return EFI_OUT_OF_RESOURCES;
    529   }
    530 
    531   if (Password != NULL) {
    532     CopyMem((VOID*)Parameter->Password, Password, PasswordLen);
    533     Parameter->PasswordLength = (UINT8)PasswordLen;
    534   }
    535   CopyMem (&Parameter->OpalDevicePath, DevicePath, DevicePathLen);
    536 
    537   Status = OpalSendCommunicateBuffer(Buffer, Length);
    538   if (EFI_ERROR(Status)) {
    539     goto EXIT;
    540   }
    541 
    542 EXIT:
    543   ZeroMem(Parameter, Length);
    544   return Status;
    545 }
    546 
    547 /**
    548   Get saved Opal device list.
    549 
    550   @retval      return opal device list.
    551 
    552 **/
    553 LIST_ENTRY*
    554 EFIAPI
    555 OpalSupportGetOpalDeviceList (
    556   VOID
    557   )
    558 {
    559   return &mDeviceList;
    560 }
    561 
    562 /**
    563   Check if the password is full zero.
    564 
    565   @param[in]   Password       Points to the Data Buffer
    566 
    567   @retval      TRUE           This password string is full zero.
    568   @retval      FALSE          This password string is not full zero.
    569 
    570 **/
    571 BOOLEAN
    572 OpalPasswordIsFullZero (
    573   IN UINT8                    *Password
    574   )
    575 {
    576   UINTN                       Index;
    577 
    578   for (Index = 0; Index < OPAL_PASSWORD_MAX_LENGTH; Index++) {
    579     if (Password[Index] != 0) {
    580       return FALSE;
    581     }
    582   }
    583 
    584   return TRUE;
    585 }
    586 
    587 /**
    588   Save hdd password to SMM.
    589 
    590   @param[in] DevicePath                Input device path info for the device.
    591   @param[in] Password                  The hdd password of attached ATA device.
    592   @param[in] PasswordLength            The hdd password length.
    593 
    594   @retval EFI_OUT_OF_RESOURCES    Insufficient resources to create database record
    595   @retval EFI_SUCCESS             The function has been successfully executed.
    596 
    597 **/
    598 EFI_STATUS
    599 OpalSavePasswordToSmm (
    600   IN  EFI_DEVICE_PATH_PROTOCOL      *DevicePath,
    601   IN  UINT8                         *Password,
    602   IN  UINT8                         PasswordLength
    603   )
    604 {
    605   OPAL_DISK_AND_PASSWORD_INFO       *List;
    606   OPAL_DISK_AND_PASSWORD_INFO       *Dev;
    607   LIST_ENTRY                        *Entry;
    608   UINTN                             DevicePathLen;
    609 
    610   DevicePathLen = GetDevicePathSize (DevicePath);
    611 
    612   for (Entry = mDeviceList.ForwardLink; Entry != &mDeviceList; Entry = Entry->ForwardLink) {
    613     List = BASE_CR (Entry, OPAL_DISK_AND_PASSWORD_INFO, Link);
    614     if (CompareMem (&List->OpalDevicePath, DevicePath, DevicePathLen) == 0) {
    615       CopyMem(List->Password, Password, OPAL_PASSWORD_MAX_LENGTH);
    616       return EFI_SUCCESS;
    617     }
    618   }
    619 
    620   Dev = AllocateZeroPool (OFFSET_OF (OPAL_DISK_AND_PASSWORD_INFO, OpalDevicePath) + DevicePathLen);
    621   if (Dev == NULL) {
    622     return EFI_OUT_OF_RESOURCES;
    623   }
    624 
    625   Dev->PasswordLength = PasswordLength;
    626   CopyMem(&(Dev->Password), Password, OPAL_PASSWORD_MAX_LENGTH);
    627   CopyMem(&(Dev->OpalDevicePath), DevicePath, DevicePathLen);
    628 
    629   InsertHeadList (&mDeviceList, &Dev->Link);
    630 
    631   return EFI_SUCCESS;
    632 }
    633 
    634 /**
    635   Communication service SMI Handler entry.
    636 
    637   This SMI handler provides services for saving HDD password and saving S3 boot script when ready to boot.
    638 
    639   @param[in]     DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().
    640   @param[in]     RegisterContext Points to an optional handler context which was specified when the
    641                                  handler was registered.
    642   @param[in, out] CommBuffer     A pointer to a collection of Data in memory that will
    643                                  be conveyed from a non-SMM environment into an SMM environment.
    644   @param[in, out] CommBufferSize The Size of the CommBuffer.
    645 
    646   @retval EFI_SUCCESS                         The interrupt was handled and quiesced. No other handlers
    647                                               should still be called.
    648   @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED  The interrupt has been quiesced but other handlers should
    649                                               still be called.
    650   @retval EFI_WARN_INTERRUPT_SOURCE_PENDING   The interrupt is still pending and other handlers should still
    651                                               be called.
    652   @retval EFI_INTERRUPT_PENDING               The interrupt could not be quiesced.
    653 **/
    654 EFI_STATUS
    655 EFIAPI
    656 SmmOpalPasswordHandler (
    657   IN     EFI_HANDLE                 DispatchHandle,
    658   IN     CONST VOID                 *RegisterContext,
    659   IN OUT VOID                       *CommBuffer,
    660   IN OUT UINTN                      *CommBufferSize
    661   )
    662 {
    663   EFI_STATUS                        Status;
    664   OPAL_SMM_COMMUNICATE_HEADER       *SmmFunctionHeader;
    665   UINTN                             TempCommBufferSize;
    666   UINT8                             *NewPassword;
    667   UINT8                             PasswordLength;
    668   EFI_DEVICE_PATH_PROTOCOL          *DevicePath;
    669 
    670   if (CommBuffer == NULL || CommBufferSize == NULL) {
    671     return EFI_SUCCESS;
    672   }
    673 
    674   TempCommBufferSize = *CommBufferSize;
    675   if (TempCommBufferSize < OFFSET_OF (OPAL_SMM_COMMUNICATE_HEADER, Data)) {
    676     return EFI_SUCCESS;
    677   }
    678 
    679   Status   = EFI_SUCCESS;
    680   SmmFunctionHeader     = (OPAL_SMM_COMMUNICATE_HEADER *)CommBuffer;
    681 
    682   DevicePath = &((OPAL_COMM_DEVICE_LIST*)(SmmFunctionHeader->Data))->OpalDevicePath;
    683   PasswordLength = ((OPAL_COMM_DEVICE_LIST*)(SmmFunctionHeader->Data))->PasswordLength;
    684   NewPassword = ((OPAL_COMM_DEVICE_LIST*)(SmmFunctionHeader->Data))->Password;
    685 
    686   switch (SmmFunctionHeader->Function) {
    687     case SMM_FUNCTION_SET_OPAL_PASSWORD:
    688         if (OpalPasswordIsFullZero (NewPassword) || PasswordLength == 0) {
    689           Status = EFI_INVALID_PARAMETER;
    690           goto EXIT;
    691         }
    692 
    693         Status = OpalSavePasswordToSmm (DevicePath, NewPassword, PasswordLength);
    694       break;
    695 
    696     default:
    697       Status = EFI_UNSUPPORTED;
    698       break;
    699   }
    700 
    701 EXIT:
    702   SmmFunctionHeader->ReturnStatus = Status;
    703 
    704   //
    705   // Return EFI_SUCCESS cause only one handler can be trigged.
    706   // so return EFI_WARN_INTERRUPT_SOURCE_PENDING to make all handler can be trigged.
    707   //
    708   return EFI_WARN_INTERRUPT_SOURCE_PENDING;
    709 }
    710 
    711 /**
    712   The constructor function.
    713 
    714   Register SMI handler when link to SMM driver.
    715 
    716   @retval EFI_SUCCESS   The constructor always returns EFI_SUCCESS.
    717 
    718 **/
    719 EFI_STATUS
    720 EFIAPI
    721 OpalPasswordSupportLibConstructor (
    722   VOID
    723   )
    724 {
    725   EFI_SMM_BASE2_PROTOCOL         *SmmBase2;
    726   EFI_SMM_SYSTEM_TABLE2          *Smst;
    727   EFI_HANDLE                     SmmHandle;
    728   EFI_STATUS                     Status;
    729 
    730   Status = gBS->LocateProtocol (&gEfiSmmBase2ProtocolGuid, NULL, (VOID**) &SmmBase2);
    731   if (EFI_ERROR (Status)) {
    732     return RETURN_SUCCESS;
    733   }
    734   Status = SmmBase2->InSmm (SmmBase2, &gInSmm);
    735   if (EFI_ERROR (Status)) {
    736     return RETURN_SUCCESS;
    737   }
    738   if (!gInSmm) {
    739     return RETURN_SUCCESS;
    740   }
    741 
    742   //
    743   // Good, we are in SMM
    744   //
    745   Status = SmmBase2->GetSmstLocation (SmmBase2, &Smst);
    746   if (EFI_ERROR (Status)) {
    747     return RETURN_SUCCESS;
    748   }
    749 
    750   SmmHandle = NULL;
    751   Status    = Smst->SmiHandlerRegister (SmmOpalPasswordHandler, &gOpalPasswordNotifyProtocolGuid, &SmmHandle);
    752   ASSERT_EFI_ERROR (Status);
    753 
    754   return EFI_SUCCESS;
    755 }
    756 
    757 /**
    758   The Destructor function.
    759 
    760   Clean the saved opal device list.
    761 
    762   @retval EFI_SUCCESS   The constructor always returns EFI_SUCCESS.
    763 
    764 **/
    765 EFI_STATUS
    766 EFIAPI
    767 OpalPasswordSupportLibDestructor (
    768   VOID
    769   )
    770 {
    771   OPAL_DISK_AND_PASSWORD_INFO  *Device;
    772 
    773   while (!IsListEmpty (&mDeviceList)) {
    774     Device = BASE_CR (mDeviceList.ForwardLink, OPAL_DISK_AND_PASSWORD_INFO, Link);
    775 
    776     RemoveEntryList (&Device->Link);
    777     FreePool (Device);
    778   }
    779 
    780   return EFI_SUCCESS;
    781 }
    782