• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
OpalSupportGetAvailableActions(IN OPAL_DISK_SUPPORT_ATTRIBUTE * SupportedAttributes,IN TCG_LOCKING_FEATURE_DESCRIPTOR * LockingFeature,IN UINT16 OwnerShip,OUT OPAL_DISK_ACTIONS * AvalDiskActions)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
OpalSupportPsidRevert(IN OPAL_SESSION * Session,IN VOID * Psid,IN UINT32 PsidLength,IN EFI_DEVICE_PATH_PROTOCOL * DevicePath)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
OpalSupportSetPassword(IN OPAL_SESSION * Session,IN VOID * OldPassword,IN UINT32 OldPasswordLength,IN VOID * NewPassword,IN UINT32 NewPasswordLength,IN EFI_DEVICE_PATH_PROTOCOL * DevicePath,IN BOOLEAN SetAdmin)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
OpalSupportDisableUser(IN OPAL_SESSION * Session,IN VOID * Password,IN UINT32 PasswordLength,OUT BOOLEAN * PasswordFailed,IN EFI_DEVICE_PATH_PROTOCOL * DevicePath)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
OpalSupportEnableOpalFeature(IN OPAL_SESSION * Session,IN VOID * Msid,IN UINT32 MsidLength,IN VOID * Password,IN UINT32 PassLength,IN EFI_DEVICE_PATH_PROTOCOL * DevicePath)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
OpalSupportRevert(IN OPAL_SESSION * Session,IN BOOLEAN KeepUserData,IN VOID * Password,IN UINT32 PasswordLength,IN VOID * Msid,IN UINT32 MsidLength,OUT BOOLEAN * PasswordFailed,IN EFI_DEVICE_PATH_PROTOCOL * DevicePath)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
OpalSupportUnlock(IN OPAL_SESSION * Session,IN VOID * Password,IN UINT32 PasswordLength,IN EFI_DEVICE_PATH_PROTOCOL * DevicePath)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
OpalSupportLock(IN OPAL_SESSION * Session,IN VOID * Password,IN UINT32 PasswordLength,IN EFI_DEVICE_PATH_PROTOCOL * DevicePath)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*
OpalInitCommunicateBuffer(OUT VOID ** DataPtr OPTIONAL,IN UINTN DataSize,IN UINTN Function)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
OpalSendCommunicateBuffer(IN VOID * Buffer,IN UINTN DataSize)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
OpalSupportSendPasword(EFI_DEVICE_PATH_PROTOCOL * DevicePath,UINTN PasswordLen,VOID * Password)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
OpalSupportGetOpalDeviceList(VOID)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
OpalPasswordIsFullZero(IN UINT8 * Password)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
OpalSavePasswordToSmm(IN EFI_DEVICE_PATH_PROTOCOL * DevicePath,IN UINT8 * Password,IN UINT8 PasswordLength)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
SmmOpalPasswordHandler(IN EFI_HANDLE DispatchHandle,IN CONST VOID * RegisterContext,IN OUT VOID * CommBuffer,IN OUT UINTN * CommBufferSize)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
OpalPasswordSupportLibConstructor(VOID)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
OpalPasswordSupportLibDestructor(VOID)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