1 /** @file 2 3 Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR> 4 5 This program and the accompanying materials 6 are licensed and made available under the terms and conditions 7 of the BSD License which accompanies this distribution. The 8 full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14 **/ 15 16 #include <PiSmm.h> 17 #include <Library/SmmServicesTableLib.h> 18 #include <Library/BaseLib.h> 19 #include <Library/BaseMemoryLib.h> 20 #include <Library/LockBoxLib.h> 21 #include <Library/DebugLib.h> 22 #include <Guid/SmmLockBox.h> 23 24 #include "SmmLockBoxLibPrivate.h" 25 26 /** 27 We need handle this library carefully. Only one library instance will construct the environment. 28 Below 2 global variable can only be used in constructor. They should NOT be used in any other library functions. 29 **/ 30 SMM_LOCK_BOX_CONTEXT mSmmLockBoxContext; 31 LIST_ENTRY mLockBoxQueue = INITIALIZE_LIST_HEAD_VARIABLE (mLockBoxQueue); 32 33 BOOLEAN mSmmConfigurationTableInstalled = FALSE; 34 35 /** 36 This function return SmmLockBox context from SMST. 37 38 @return SmmLockBox context from SMST. 39 **/ 40 SMM_LOCK_BOX_CONTEXT * 41 InternalGetSmmLockBoxContext ( 42 VOID 43 ) 44 { 45 UINTN Index; 46 47 // 48 // Check if gEfiSmmLockBoxCommunicationGuid is installed by someone 49 // 50 for (Index = 0; Index < gSmst->NumberOfTableEntries; Index++) { 51 if (CompareGuid (&gSmst->SmmConfigurationTable[Index].VendorGuid, &gEfiSmmLockBoxCommunicationGuid)) { 52 // 53 // Found. That means some other library instance is already run. 54 // No need to install again, just return. 55 // 56 return (SMM_LOCK_BOX_CONTEXT *)gSmst->SmmConfigurationTable[Index].VendorTable; 57 } 58 } 59 60 // 61 // Not found. 62 // 63 return NULL; 64 } 65 66 /** 67 Constructor for SmmLockBox library. 68 This is used to set SmmLockBox context, which will be used in PEI phase in S3 boot path later. 69 70 @param[in] ImageHandle Image handle of this driver. 71 @param[in] SystemTable A Pointer to the EFI System Table. 72 73 @retval EFI_SUCEESS 74 @return Others Some error occurs. 75 **/ 76 EFI_STATUS 77 EFIAPI 78 SmmLockBoxSmmConstructor ( 79 IN EFI_HANDLE ImageHandle, 80 IN EFI_SYSTEM_TABLE *SystemTable 81 ) 82 { 83 EFI_STATUS Status; 84 SMM_LOCK_BOX_CONTEXT *SmmLockBoxContext; 85 86 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SmmLockBoxSmmConstructor - Enter\n")); 87 88 // 89 // Check if gEfiSmmLockBoxCommunicationGuid is installed by someone 90 // 91 SmmLockBoxContext = InternalGetSmmLockBoxContext (); 92 if (SmmLockBoxContext != NULL) { 93 // 94 // Find it. That means some other library instance is already run. 95 // No need to install again, just return. 96 // 97 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SmmLockBoxContext - already installed\n")); 98 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SmmLockBoxSmmConstructor - Exit\n")); 99 return EFI_SUCCESS; 100 } 101 102 // 103 // If no one install this, it means this is first instance. Install it. 104 // 105 if (sizeof(UINTN) == sizeof(UINT64)) { 106 mSmmLockBoxContext.Signature = SMM_LOCK_BOX_SIGNATURE_64; 107 } else { 108 mSmmLockBoxContext.Signature = SMM_LOCK_BOX_SIGNATURE_32; 109 } 110 mSmmLockBoxContext.LockBoxDataAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)&mLockBoxQueue; 111 112 Status = gSmst->SmmInstallConfigurationTable ( 113 gSmst, 114 &gEfiSmmLockBoxCommunicationGuid, 115 &mSmmLockBoxContext, 116 sizeof(mSmmLockBoxContext) 117 ); 118 ASSERT_EFI_ERROR (Status); 119 mSmmConfigurationTableInstalled = TRUE; 120 121 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SmmLockBoxContext - %x\n", (UINTN)&mSmmLockBoxContext)); 122 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib LockBoxDataAddress - %x\n", (UINTN)&mLockBoxQueue)); 123 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SmmLockBoxSmmConstructor - Exit\n")); 124 125 return Status; 126 } 127 128 /** 129 Destructor for SmmLockBox library. 130 This is used to uninstall SmmLockBoxCommunication configuration table 131 if it has been installed in Constructor. 132 133 @param[in] ImageHandle Image handle of this driver. 134 @param[in] SystemTable A Pointer to the EFI System Table. 135 136 @retval EFI_SUCEESS The destructor always returns EFI_SUCCESS. 137 138 **/ 139 EFI_STATUS 140 EFIAPI 141 SmmLockBoxSmmDestructor ( 142 IN EFI_HANDLE ImageHandle, 143 IN EFI_SYSTEM_TABLE *SystemTable 144 ) 145 { 146 EFI_STATUS Status; 147 148 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SmmLockBoxSmmDestructor in %a module\n", gEfiCallerBaseName)); 149 150 if (mSmmConfigurationTableInstalled) { 151 Status = gSmst->SmmInstallConfigurationTable ( 152 gSmst, 153 &gEfiSmmLockBoxCommunicationGuid, 154 NULL, 155 0 156 ); 157 ASSERT_EFI_ERROR (Status); 158 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib uninstall SmmLockBoxCommunication configuration table\n")); 159 } 160 161 return EFI_SUCCESS; 162 } 163 164 /** 165 This function return SmmLockBox queue address. 166 167 @return SmmLockBox queue address. 168 **/ 169 LIST_ENTRY * 170 InternalGetLockBoxQueue ( 171 VOID 172 ) 173 { 174 SMM_LOCK_BOX_CONTEXT *SmmLockBoxContext; 175 176 SmmLockBoxContext = InternalGetSmmLockBoxContext (); 177 ASSERT (SmmLockBoxContext != NULL); 178 if (SmmLockBoxContext == NULL) { 179 return NULL; 180 } 181 return (LIST_ENTRY *)(UINTN)SmmLockBoxContext->LockBoxDataAddress; 182 } 183 184 /** 185 This function find LockBox by GUID. 186 187 @param Guid The guid to indentify the LockBox 188 189 @return LockBoxData 190 **/ 191 SMM_LOCK_BOX_DATA * 192 InternalFindLockBoxByGuid ( 193 IN EFI_GUID *Guid 194 ) 195 { 196 LIST_ENTRY *Link; 197 SMM_LOCK_BOX_DATA *LockBox; 198 LIST_ENTRY *LockBoxQueue; 199 200 LockBoxQueue = InternalGetLockBoxQueue (); 201 ASSERT (LockBoxQueue != NULL); 202 203 for (Link = LockBoxQueue->ForwardLink; 204 Link != LockBoxQueue; 205 Link = Link->ForwardLink) { 206 LockBox = BASE_CR ( 207 Link, 208 SMM_LOCK_BOX_DATA, 209 Link 210 ); 211 if (CompareGuid (&LockBox->Guid, Guid)) { 212 return LockBox; 213 } 214 } 215 return NULL; 216 } 217 218 /** 219 This function will save confidential information to lockbox. 220 221 @param Guid the guid to identify the confidential information 222 @param Buffer the address of the confidential information 223 @param Length the length of the confidential information 224 225 @retval RETURN_SUCCESS the information is saved successfully. 226 @retval RETURN_INVALID_PARAMETER the Guid is NULL, or Buffer is NULL, or Length is 0 227 @retval RETURN_ALREADY_STARTED the requested GUID already exist. 228 @retval RETURN_OUT_OF_RESOURCES no enough resource to save the information. 229 @retval RETURN_ACCESS_DENIED it is too late to invoke this interface 230 @retval RETURN_NOT_STARTED it is too early to invoke this interface 231 @retval RETURN_UNSUPPORTED the service is not supported by implementaion. 232 **/ 233 RETURN_STATUS 234 EFIAPI 235 SaveLockBox ( 236 IN GUID *Guid, 237 IN VOID *Buffer, 238 IN UINTN Length 239 ) 240 { 241 SMM_LOCK_BOX_DATA *LockBox; 242 EFI_PHYSICAL_ADDRESS SmramBuffer; 243 EFI_STATUS Status; 244 LIST_ENTRY *LockBoxQueue; 245 246 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SaveLockBox - Enter\n")); 247 248 // 249 // Basic check 250 // 251 if ((Guid == NULL) || (Buffer == NULL) || (Length == 0)) { 252 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_INVALID_PARAMETER)); 253 return EFI_INVALID_PARAMETER; 254 } 255 256 // 257 // Find LockBox 258 // 259 LockBox = InternalFindLockBoxByGuid (Guid); 260 if (LockBox != NULL) { 261 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_ALREADY_STARTED)); 262 return EFI_ALREADY_STARTED; 263 } 264 265 // 266 // Allocate SMRAM buffer 267 // 268 Status = gSmst->SmmAllocatePages ( 269 AllocateAnyPages, 270 EfiRuntimeServicesData, 271 EFI_SIZE_TO_PAGES (Length), 272 &SmramBuffer 273 ); 274 ASSERT_EFI_ERROR (Status); 275 if (EFI_ERROR (Status)) { 276 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_OUT_OF_RESOURCES)); 277 return EFI_OUT_OF_RESOURCES; 278 } 279 280 // 281 // Allocate LockBox 282 // 283 Status = gSmst->SmmAllocatePool ( 284 EfiRuntimeServicesData, 285 sizeof(*LockBox), 286 (VOID **)&LockBox 287 ); 288 ASSERT_EFI_ERROR (Status); 289 if (EFI_ERROR (Status)) { 290 gSmst->SmmFreePages (SmramBuffer, EFI_SIZE_TO_PAGES (Length)); 291 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_OUT_OF_RESOURCES)); 292 return EFI_OUT_OF_RESOURCES; 293 } 294 295 // 296 // Save data 297 // 298 CopyMem ((VOID *)(UINTN)SmramBuffer, (VOID *)(UINTN)Buffer, Length); 299 300 // 301 // Insert LockBox to queue 302 // 303 LockBox->Signature = SMM_LOCK_BOX_DATA_SIGNATURE; 304 CopyMem (&LockBox->Guid, Guid, sizeof(EFI_GUID)); 305 LockBox->Buffer = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer; 306 LockBox->Length = (UINT64)Length; 307 LockBox->Attributes = 0; 308 LockBox->SmramBuffer = SmramBuffer; 309 310 DEBUG (( 311 EFI_D_INFO, 312 "LockBoxGuid - %g, SmramBuffer - 0x%lx, Length - 0x%lx\n", 313 &LockBox->Guid, 314 LockBox->SmramBuffer, 315 LockBox->Length 316 )); 317 318 LockBoxQueue = InternalGetLockBoxQueue (); 319 ASSERT (LockBoxQueue != NULL); 320 InsertTailList (LockBoxQueue, &LockBox->Link); 321 322 // 323 // Done 324 // 325 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_SUCCESS)); 326 return EFI_SUCCESS; 327 } 328 329 /** 330 This function will set lockbox attributes. 331 332 @param Guid the guid to identify the confidential information 333 @param Attributes the attributes of the lockbox 334 335 @retval RETURN_SUCCESS the information is saved successfully. 336 @retval RETURN_INVALID_PARAMETER attributes is invalid. 337 @retval RETURN_NOT_FOUND the requested GUID not found. 338 @retval RETURN_ACCESS_DENIED it is too late to invoke this interface 339 @retval RETURN_NOT_STARTED it is too early to invoke this interface 340 @retval RETURN_UNSUPPORTED the service is not supported by implementaion. 341 **/ 342 RETURN_STATUS 343 EFIAPI 344 SetLockBoxAttributes ( 345 IN GUID *Guid, 346 IN UINT64 Attributes 347 ) 348 { 349 SMM_LOCK_BOX_DATA *LockBox; 350 351 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes - Enter\n")); 352 353 // 354 // Basic check 355 // 356 if ((Guid == NULL) || 357 ((Attributes & ~LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE) != 0)) { 358 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes - Exit (%r)\n", EFI_INVALID_PARAMETER)); 359 return EFI_INVALID_PARAMETER; 360 } 361 362 // 363 // Find LockBox 364 // 365 LockBox = InternalFindLockBoxByGuid (Guid); 366 if (LockBox == NULL) { 367 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes - Exit (%r)\n", EFI_NOT_FOUND)); 368 return EFI_NOT_FOUND; 369 } 370 371 // 372 // Update data 373 // 374 LockBox->Attributes = Attributes; 375 376 // 377 // Done 378 // 379 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes - Exit (%r)\n", EFI_SUCCESS)); 380 return EFI_SUCCESS; 381 } 382 383 /** 384 This function will update confidential information to lockbox. 385 386 @param Guid the guid to identify the original confidential information 387 @param Offset the offset of the original confidential information 388 @param Buffer the address of the updated confidential information 389 @param Length the length of the updated confidential information 390 391 @retval RETURN_SUCCESS the information is saved successfully. 392 @retval RETURN_INVALID_PARAMETER the Guid is NULL, or Buffer is NULL, or Length is 0. 393 @retval RETURN_NOT_FOUND the requested GUID not found. 394 @retval RETURN_BUFFER_TOO_SMALL the original buffer to too small to hold new information. 395 @retval RETURN_ACCESS_DENIED it is too late to invoke this interface 396 @retval RETURN_NOT_STARTED it is too early to invoke this interface 397 @retval RETURN_UNSUPPORTED the service is not supported by implementaion. 398 **/ 399 RETURN_STATUS 400 EFIAPI 401 UpdateLockBox ( 402 IN GUID *Guid, 403 IN UINTN Offset, 404 IN VOID *Buffer, 405 IN UINTN Length 406 ) 407 { 408 SMM_LOCK_BOX_DATA *LockBox; 409 410 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib UpdateLockBox - Enter\n")); 411 412 // 413 // Basic check 414 // 415 if ((Guid == NULL) || (Buffer == NULL) || (Length == 0)) { 416 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_INVALID_PARAMETER)); 417 return EFI_INVALID_PARAMETER; 418 } 419 420 // 421 // Find LockBox 422 // 423 LockBox = InternalFindLockBoxByGuid (Guid); 424 if (LockBox == NULL) { 425 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_NOT_FOUND)); 426 return EFI_NOT_FOUND; 427 } 428 429 // 430 // Update data 431 // 432 if (LockBox->Length < Offset + Length) { 433 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_BUFFER_TOO_SMALL)); 434 return EFI_BUFFER_TOO_SMALL; 435 } 436 ASSERT ((UINTN)LockBox->SmramBuffer <= (MAX_ADDRESS - Offset)); 437 CopyMem ((VOID *)((UINTN)LockBox->SmramBuffer + Offset), Buffer, Length); 438 439 // 440 // Done 441 // 442 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_SUCCESS)); 443 return EFI_SUCCESS; 444 } 445 446 /** 447 This function will restore confidential information from lockbox. 448 449 @param Guid the guid to identify the confidential information 450 @param Buffer the address of the restored confidential information 451 NULL means restored to original address, Length MUST be NULL at same time. 452 @param Length the length of the restored confidential information 453 454 @retval RETURN_SUCCESS the information is restored successfully. 455 @retval RETURN_INVALID_PARAMETER the Guid is NULL, or one of Buffer and Length is NULL. 456 @retval RETURN_WRITE_PROTECTED Buffer and Length are NULL, but the LockBox has no 457 LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE attribute. 458 @retval RETURN_BUFFER_TOO_SMALL the Length is too small to hold the confidential information. 459 @retval RETURN_NOT_FOUND the requested GUID not found. 460 @retval RETURN_NOT_STARTED it is too early to invoke this interface 461 @retval RETURN_ACCESS_DENIED not allow to restore to the address 462 @retval RETURN_UNSUPPORTED the service is not supported by implementaion. 463 **/ 464 RETURN_STATUS 465 EFIAPI 466 RestoreLockBox ( 467 IN GUID *Guid, 468 IN VOID *Buffer, OPTIONAL 469 IN OUT UINTN *Length OPTIONAL 470 ) 471 { 472 SMM_LOCK_BOX_DATA *LockBox; 473 VOID *RestoreBuffer; 474 475 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreLockBox - Enter\n")); 476 477 // 478 // Restore this, Buffer and Length MUST be both NULL or both non-NULL 479 // 480 if ((Guid == NULL) || 481 ((Buffer == NULL) && (Length != NULL)) || 482 ((Buffer != NULL) && (Length == NULL))) { 483 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_INVALID_PARAMETER)); 484 return EFI_INVALID_PARAMETER; 485 } 486 487 // 488 // Find LockBox 489 // 490 LockBox = InternalFindLockBoxByGuid (Guid); 491 if (LockBox == NULL) { 492 // 493 // Not found 494 // 495 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_NOT_FOUND)); 496 return EFI_NOT_FOUND; 497 } 498 499 // 500 // Set RestoreBuffer 501 // 502 if (Buffer != NULL) { 503 // 504 // restore to new buffer 505 // 506 RestoreBuffer = Buffer; 507 } else { 508 // 509 // restore to original buffer 510 // 511 if ((LockBox->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE) == 0) { 512 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_WRITE_PROTECTED)); 513 return EFI_WRITE_PROTECTED; 514 } 515 RestoreBuffer = (VOID *)(UINTN)LockBox->Buffer; 516 } 517 518 // 519 // Set RestoreLength 520 // 521 if (Length != NULL) { 522 if (*Length < (UINTN)LockBox->Length) { 523 // 524 // Input buffer is too small to hold all data. 525 // 526 *Length = (UINTN)LockBox->Length; 527 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_BUFFER_TOO_SMALL)); 528 return EFI_BUFFER_TOO_SMALL; 529 } 530 *Length = (UINTN)LockBox->Length; 531 } 532 533 // 534 // Restore data 535 // 536 CopyMem (RestoreBuffer, (VOID *)(UINTN)LockBox->SmramBuffer, (UINTN)LockBox->Length); 537 538 // 539 // Done 540 // 541 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_SUCCESS)); 542 return EFI_SUCCESS; 543 } 544 545 /** 546 This function will restore confidential information from all lockbox which have RestoreInPlace attribute. 547 548 @retval RETURN_SUCCESS the information is restored successfully. 549 @retval RETURN_NOT_STARTED it is too early to invoke this interface 550 @retval RETURN_UNSUPPORTED the service is not supported by implementaion. 551 **/ 552 RETURN_STATUS 553 EFIAPI 554 RestoreAllLockBoxInPlace ( 555 VOID 556 ) 557 { 558 SMM_LOCK_BOX_DATA *LockBox; 559 LIST_ENTRY *Link; 560 LIST_ENTRY *LockBoxQueue; 561 562 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreAllLockBoxInPlace - Enter\n")); 563 564 LockBoxQueue = InternalGetLockBoxQueue (); 565 ASSERT (LockBoxQueue != NULL); 566 567 // 568 // Restore all, Buffer and Length MUST be NULL 569 // 570 for (Link = LockBoxQueue->ForwardLink; 571 Link != LockBoxQueue; 572 Link = Link->ForwardLink) { 573 LockBox = BASE_CR ( 574 Link, 575 SMM_LOCK_BOX_DATA, 576 Link 577 ); 578 if ((LockBox->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE) != 0) { 579 // 580 // Restore data 581 // 582 CopyMem ((VOID *)(UINTN)LockBox->Buffer, (VOID *)(UINTN)LockBox->SmramBuffer, (UINTN)LockBox->Length); 583 } 584 } 585 // 586 // Done 587 // 588 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreAllLockBoxInPlace - Exit (%r)\n", EFI_SUCCESS)); 589 return EFI_SUCCESS; 590 } 591 592