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