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