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