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 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 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 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 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 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 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 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 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 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