]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/Library/OpalPasswordSupportLib/OpalPasswordSupportLib.c
eead27fbe022831f2e72bb68ed9cf2ea12cb8ced
[mirror_edk2.git] / SecurityPkg / Library / OpalPasswordSupportLib / OpalPasswordSupportLib.c
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
405 Buffer = AllocateZeroPool (DataSize + OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + OFFSET_OF (OPAL_SMM_COMMUNICATE_HEADER, Data));
406 ASSERT (Buffer != NULL);
407
408 SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) Buffer;
409 CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gOpalPasswordNotifyProtocolGuid);
410 SmmCommunicateHeader->MessageLength = DataSize + OFFSET_OF (OPAL_SMM_COMMUNICATE_HEADER, Data);
411
412 SmmFunctionHeader = (OPAL_SMM_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;
413 SmmFunctionHeader->Function = Function;
414 if (DataPtr != NULL) {
415 *DataPtr = SmmFunctionHeader->Data;
416 }
417
418 return Buffer;
419 }
420
421 /**
422 Send the Data in communicate Buffer to SMM.
423
424 @param[in] Buffer Points to the Data in the communicate Buffer.
425 @param[in] DataSize This Size of the function Header and the Data.
426
427 @retval EFI_SUCCESS Success is returned from the functin in SMM.
428 @retval Others Failure is returned from the function in SMM.
429
430 **/
431 EFI_STATUS
432 OpalSendCommunicateBuffer (
433 IN VOID *Buffer,
434 IN UINTN DataSize
435 )
436 {
437 EFI_STATUS Status;
438 UINTN CommSize;
439 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
440 OPAL_SMM_COMMUNICATE_HEADER *SmmFunctionHeader;
441 EFI_SMM_COMMUNICATION_PROTOCOL *SmmCommunication;
442
443 Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &SmmCommunication);
444 if (EFI_ERROR (Status)) {
445 return Status;
446 }
447
448 CommSize = DataSize + OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + OFFSET_OF (OPAL_SMM_COMMUNICATE_HEADER, Data);
449 Status = SmmCommunication->Communicate (SmmCommunication, Buffer, &CommSize);
450 if (EFI_ERROR (Status)) {
451 return Status;
452 }
453
454 SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) Buffer;
455 SmmFunctionHeader = (OPAL_SMM_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data;
456
457 return SmmFunctionHeader->ReturnStatus;
458 }
459
460 /**
461 Transfer the password to the smm driver.
462
463 @param[in] DevicePath The device path for the opal devcie.
464 @param PasswordLen The input password length.
465 @param Password Input password buffer.
466
467 @retval EFI_SUCCESS Do the required action success.
468 @retval Others Error occured.
469
470 **/
471 EFI_STATUS
472 EFIAPI
473 OpalSupportSendPasword(
474 EFI_DEVICE_PATH_PROTOCOL *DevicePath,
475 UINTN PasswordLen,
476 VOID *Password
477 )
478 {
479 OPAL_COMM_DEVICE_LIST *Parameter;
480 VOID *Buffer;
481 UINTN Length;
482 EFI_STATUS Status;
483 UINTN DevicePathLen;
484
485 Parameter = NULL;
486 Buffer = NULL;
487
488 if (DevicePath == NULL) {
489 //
490 // Assume DevicePath == NULL only when library used by SMM driver
491 // and should not run to here, just return success.
492 //
493 return EFI_SUCCESS;
494 }
495
496 DevicePathLen = GetDevicePathSize (DevicePath);
497 Length = OFFSET_OF (OPAL_COMM_DEVICE_LIST, OpalDevicePath) + DevicePathLen;
498 Buffer = OpalInitCommunicateBuffer((VOID**)&Parameter, Length, SMM_FUNCTION_SET_OPAL_PASSWORD);
499 if (Buffer == NULL) {
500 return EFI_OUT_OF_RESOURCES;
501 }
502
503 if (Password != NULL) {
504 CopyMem((VOID*)Parameter->Password, Password, PasswordLen);
505 Parameter->PasswordLength = (UINT8)PasswordLen;
506 }
507 CopyMem (&Parameter->OpalDevicePath, DevicePath, DevicePathLen);
508
509 Status = OpalSendCommunicateBuffer(Buffer, Length);
510 if (EFI_ERROR(Status)) {
511 goto EXIT;
512 }
513
514 EXIT:
515 ZeroMem(Parameter, Length);
516 FreePool(Buffer);
517
518 return Status;
519 }
520
521 /**
522 Get saved Opal device list.
523
524 @retval return opal device list.
525
526 **/
527 LIST_ENTRY*
528 EFIAPI
529 OpalSupportGetOpalDeviceList (
530 VOID
531 )
532 {
533 return &mDeviceList;
534 }
535
536 /**
537 Check if the password is full zero.
538
539 @param[in] Password Points to the Data Buffer
540
541 @retval TRUE This password string is full zero.
542 @retval FALSE This password string is not full zero.
543
544 **/
545 BOOLEAN
546 OpalPasswordIsFullZero (
547 IN UINT8 *Password
548 )
549 {
550 UINTN Index;
551
552 for (Index = 0; Index < OPAL_PASSWORD_MAX_LENGTH; Index++) {
553 if (Password[Index] != 0) {
554 return FALSE;
555 }
556 }
557
558 return TRUE;
559 }
560
561 /**
562 Save hdd password to SMM.
563
564 @param[in] DevicePath Input device path info for the device.
565 @param[in] Password The hdd password of attached ATA device.
566 @param[in] PasswordLength The hdd password length.
567
568 @retval EFI_OUT_OF_RESOURCES Insufficient resources to create database record
569 @retval EFI_SUCCESS The function has been successfully executed.
570
571 **/
572 EFI_STATUS
573 OpalSavePasswordToSmm (
574 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
575 IN UINT8 *Password,
576 IN UINT8 PasswordLength
577 )
578 {
579 OPAL_DISK_AND_PASSWORD_INFO *List;
580 OPAL_DISK_AND_PASSWORD_INFO *Dev;
581 LIST_ENTRY *Entry;
582 UINTN DevicePathLen;
583
584 DevicePathLen = GetDevicePathSize (DevicePath);
585
586 for (Entry = mDeviceList.ForwardLink; Entry != &mDeviceList; Entry = Entry->ForwardLink) {
587 List = BASE_CR (Entry, OPAL_DISK_AND_PASSWORD_INFO, Link);
588 if (CompareMem (&List->OpalDevicePath, DevicePath, DevicePathLen) == 0) {
589 CopyMem(List->Password, Password, OPAL_PASSWORD_MAX_LENGTH);
590 return EFI_SUCCESS;
591 }
592 }
593
594 Dev = AllocateZeroPool (OFFSET_OF (OPAL_DISK_AND_PASSWORD_INFO, OpalDevicePath) + DevicePathLen);
595 if (Dev == NULL) {
596 return EFI_OUT_OF_RESOURCES;
597 }
598
599 Dev->PasswordLength = PasswordLength;
600 CopyMem(&(Dev->Password), Password, OPAL_PASSWORD_MAX_LENGTH);
601 CopyMem(&(Dev->OpalDevicePath), DevicePath, DevicePathLen);
602
603 InsertHeadList (&mDeviceList, &Dev->Link);
604
605 return EFI_SUCCESS;
606 }
607
608 /**
609 Communication service SMI Handler entry.
610
611 This SMI handler provides services for saving HDD password and saving S3 boot script when ready to boot.
612
613 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
614 @param[in] RegisterContext Points to an optional handler context which was specified when the
615 handler was registered.
616 @param[in, out] CommBuffer A pointer to a collection of Data in memory that will
617 be conveyed from a non-SMM environment into an SMM environment.
618 @param[in, out] CommBufferSize The Size of the CommBuffer.
619
620 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
621 should still be called.
622 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
623 still be called.
624 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
625 be called.
626 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
627 **/
628 EFI_STATUS
629 EFIAPI
630 SmmOpalPasswordHandler (
631 IN EFI_HANDLE DispatchHandle,
632 IN CONST VOID *RegisterContext,
633 IN OUT VOID *CommBuffer,
634 IN OUT UINTN *CommBufferSize
635 )
636 {
637 EFI_STATUS Status;
638 OPAL_SMM_COMMUNICATE_HEADER *SmmFunctionHeader;
639 UINTN TempCommBufferSize;
640 UINT8 *NewPassword;
641 UINT8 PasswordLength;
642 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
643
644 if (CommBuffer == NULL || CommBufferSize == NULL) {
645 return EFI_SUCCESS;
646 }
647
648 TempCommBufferSize = *CommBufferSize;
649 if (TempCommBufferSize < OFFSET_OF (OPAL_SMM_COMMUNICATE_HEADER, Data)) {
650 return EFI_SUCCESS;
651 }
652
653 Status = EFI_SUCCESS;
654 SmmFunctionHeader = (OPAL_SMM_COMMUNICATE_HEADER *)CommBuffer;
655
656 DevicePath = &((OPAL_COMM_DEVICE_LIST*)(SmmFunctionHeader->Data))->OpalDevicePath;
657 PasswordLength = ((OPAL_COMM_DEVICE_LIST*)(SmmFunctionHeader->Data))->PasswordLength;
658 NewPassword = ((OPAL_COMM_DEVICE_LIST*)(SmmFunctionHeader->Data))->Password;
659
660 switch (SmmFunctionHeader->Function) {
661 case SMM_FUNCTION_SET_OPAL_PASSWORD:
662 if (OpalPasswordIsFullZero (NewPassword) || PasswordLength == 0) {
663 Status = EFI_INVALID_PARAMETER;
664 goto EXIT;
665 }
666
667 Status = OpalSavePasswordToSmm (DevicePath, NewPassword, PasswordLength);
668 break;
669
670 default:
671 Status = EFI_UNSUPPORTED;
672 break;
673 }
674
675 EXIT:
676 SmmFunctionHeader->ReturnStatus = Status;
677
678 //
679 // Return EFI_SUCCESS cause only one handler can be trigged.
680 // so return EFI_WARN_INTERRUPT_SOURCE_PENDING to make all handler can be trigged.
681 //
682 return EFI_WARN_INTERRUPT_SOURCE_PENDING;
683 }
684
685 /**
686 The constructor function.
687
688 Register SMI handler when link to SMM driver.
689
690 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
691
692 **/
693 EFI_STATUS
694 EFIAPI
695 OpalPasswordSupportLibConstructor (
696 VOID
697 )
698 {
699 EFI_SMM_BASE2_PROTOCOL *SmmBase2;
700 EFI_SMM_SYSTEM_TABLE2 *Smst;
701 EFI_HANDLE SmmHandle;
702 EFI_STATUS Status;
703
704 Status = gBS->LocateProtocol (&gEfiSmmBase2ProtocolGuid, NULL, (VOID**) &SmmBase2);
705 if (EFI_ERROR (Status)) {
706 return RETURN_SUCCESS;
707 }
708 Status = SmmBase2->InSmm (SmmBase2, &gInSmm);
709 if (EFI_ERROR (Status)) {
710 return RETURN_SUCCESS;
711 }
712 if (!gInSmm) {
713 return RETURN_SUCCESS;
714 }
715
716 //
717 // Good, we are in SMM
718 //
719 Status = SmmBase2->GetSmstLocation (SmmBase2, &Smst);
720 if (EFI_ERROR (Status)) {
721 return RETURN_SUCCESS;
722 }
723
724 SmmHandle = NULL;
725 Status = Smst->SmiHandlerRegister (SmmOpalPasswordHandler, &gOpalPasswordNotifyProtocolGuid, &SmmHandle);
726 ASSERT_EFI_ERROR (Status);
727
728 return EFI_SUCCESS;
729 }
730
731 /**
732 The Destructor function.
733
734 Clean the saved opal device list.
735
736 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
737
738 **/
739 EFI_STATUS
740 EFIAPI
741 OpalPasswordSupportLibDestructor (
742 VOID
743 )
744 {
745 OPAL_DISK_AND_PASSWORD_INFO *Device;
746
747 while (!IsListEmpty (&mDeviceList)) {
748 Device = BASE_CR (mDeviceList.ForwardLink, OPAL_DISK_AND_PASSWORD_INFO, Link);
749
750 RemoveEntryList (&Device->Link);
751 FreePool (Device);
752 }
753
754 return EFI_SUCCESS;
755 }