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