1 /** @file 2 It updates TPM items in ACPI table and registers SMI callback 3 functions for physical presence and ClearMemory. 4 5 Caution: This module requires additional review when modified. 6 This driver will have external input - variable and ACPINvs data in SMM mode. 7 This external input must be validated carefully to avoid security issue. 8 9 PhysicalPresenceCallback() and MemoryClearCallback() will receive untrusted input and do some check. 10 11 Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR> 12 This program and the accompanying materials 13 are licensed and made available under the terms and conditions of the BSD License 14 which accompanies this distribution. The full text of the license may be found at 15 http://opensource.org/licenses/bsd-license.php 16 17 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 18 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 19 20 **/ 21 22 #include "TcgSmm.h" 23 24 EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable; 25 TCG_NVS *mTcgNvs; 26 27 /** 28 Software SMI callback for TPM physical presence which is called from ACPI method. 29 30 Caution: This function may receive untrusted input. 31 Variable and ACPINvs are external input, so this function will validate 32 its data structure to be valid value. 33 34 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). 35 @param[in] Context Points to an optional handler context which was specified when the 36 handler was registered. 37 @param[in, out] CommBuffer A pointer to a collection of data in memory that will 38 be conveyed from a non-SMM environment into an SMM environment. 39 @param[in, out] CommBufferSize The size of the CommBuffer. 40 41 @retval EFI_SUCCESS The interrupt was handled successfully. 42 43 **/ 44 EFI_STATUS 45 EFIAPI 46 PhysicalPresenceCallback ( 47 IN EFI_HANDLE DispatchHandle, 48 IN CONST VOID *Context, 49 IN OUT VOID *CommBuffer, 50 IN OUT UINTN *CommBufferSize 51 ) 52 { 53 EFI_STATUS Status; 54 UINTN DataSize; 55 EFI_PHYSICAL_PRESENCE PpData; 56 EFI_PHYSICAL_PRESENCE_FLAGS Flags; 57 BOOLEAN RequestConfirmed; 58 59 // 60 // Get the Physical Presence variable 61 // 62 DataSize = sizeof (EFI_PHYSICAL_PRESENCE); 63 Status = mSmmVariable->SmmGetVariable ( 64 PHYSICAL_PRESENCE_VARIABLE, 65 &gEfiPhysicalPresenceGuid, 66 NULL, 67 &DataSize, 68 &PpData 69 ); 70 71 DEBUG ((EFI_D_INFO, "[TPM] PP callback, Parameter = %x\n", mTcgNvs->PhysicalPresence.Parameter)); 72 if (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS) { 73 if (EFI_ERROR (Status)) { 74 mTcgNvs->PhysicalPresence.ReturnCode = PP_RETURN_TPM_OPERATION_RESPONSE_FAILURE; 75 mTcgNvs->PhysicalPresence.LastRequest = 0; 76 mTcgNvs->PhysicalPresence.Response = 0; 77 DEBUG ((EFI_D_ERROR, "[TPM] Get PP variable failure! Status = %r\n", Status)); 78 return EFI_SUCCESS; 79 } 80 mTcgNvs->PhysicalPresence.ReturnCode = PP_RETURN_TPM_OPERATION_RESPONSE_SUCCESS; 81 mTcgNvs->PhysicalPresence.LastRequest = PpData.LastPPRequest; 82 mTcgNvs->PhysicalPresence.Response = PpData.PPResponse; 83 } else if ((mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS) 84 || (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2)) { 85 if (EFI_ERROR (Status)) { 86 mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE; 87 DEBUG ((EFI_D_ERROR, "[TPM] Get PP variable failure! Status = %r\n", Status)); 88 return EFI_SUCCESS; 89 } 90 if (mTcgNvs->PhysicalPresence.Request == PHYSICAL_PRESENCE_SET_OPERATOR_AUTH) { 91 // 92 // This command requires UI to prompt user for Auth data. 93 // 94 mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED; 95 return EFI_SUCCESS; 96 } 97 98 if (PpData.PPRequest != mTcgNvs->PhysicalPresence.Request) { 99 PpData.PPRequest = (UINT8) mTcgNvs->PhysicalPresence.Request; 100 DataSize = sizeof (EFI_PHYSICAL_PRESENCE); 101 Status = mSmmVariable->SmmSetVariable ( 102 PHYSICAL_PRESENCE_VARIABLE, 103 &gEfiPhysicalPresenceGuid, 104 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 105 DataSize, 106 &PpData 107 ); 108 } 109 110 if (EFI_ERROR (Status)) { 111 mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE; 112 return EFI_SUCCESS; 113 } 114 mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS; 115 116 if (mTcgNvs->PhysicalPresence.Request >= TCG_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) { 117 DataSize = sizeof (EFI_PHYSICAL_PRESENCE_FLAGS); 118 Status = mSmmVariable->SmmGetVariable ( 119 PHYSICAL_PRESENCE_FLAGS_VARIABLE, 120 &gEfiPhysicalPresenceGuid, 121 NULL, 122 &DataSize, 123 &Flags 124 ); 125 if (EFI_ERROR (Status)) { 126 Flags.PPFlags = TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_PROVISION; 127 } 128 mTcgNvs->PhysicalPresence.ReturnCode = TcgPpVendorLibSubmitRequestToPreOSFunction (mTcgNvs->PhysicalPresence.Request, Flags.PPFlags); 129 } 130 } else if (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST) { 131 if (EFI_ERROR (Status)) { 132 mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_GET_USER_CONFIRMATION_BLOCKED_BY_BIOS_CONFIGURATION; 133 DEBUG ((EFI_D_ERROR, "[TPM] Get PP variable failure! Status = %r\n", Status)); 134 return EFI_SUCCESS; 135 } 136 // 137 // Get the Physical Presence flags 138 // 139 DataSize = sizeof (EFI_PHYSICAL_PRESENCE_FLAGS); 140 Status = mSmmVariable->SmmGetVariable ( 141 PHYSICAL_PRESENCE_FLAGS_VARIABLE, 142 &gEfiPhysicalPresenceGuid, 143 NULL, 144 &DataSize, 145 &Flags 146 ); 147 if (EFI_ERROR (Status)) { 148 mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_GET_USER_CONFIRMATION_BLOCKED_BY_BIOS_CONFIGURATION; 149 DEBUG ((EFI_D_ERROR, "[TPM] Get PP flags failure! Status = %r\n", Status)); 150 return EFI_SUCCESS; 151 } 152 153 RequestConfirmed = FALSE; 154 155 switch (mTcgNvs->PhysicalPresence.Request) { 156 case PHYSICAL_PRESENCE_ENABLE: 157 case PHYSICAL_PRESENCE_DISABLE: 158 case PHYSICAL_PRESENCE_ACTIVATE: 159 case PHYSICAL_PRESENCE_DEACTIVATE: 160 case PHYSICAL_PRESENCE_ENABLE_ACTIVATE: 161 case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE: 162 case PHYSICAL_PRESENCE_SET_OWNER_INSTALL_TRUE: 163 case PHYSICAL_PRESENCE_SET_OWNER_INSTALL_FALSE: 164 case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_OWNER_TRUE: 165 case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE_OWNER_FALSE: 166 if ((Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_PROVISION) != 0) { 167 RequestConfirmed = TRUE; 168 } 169 break; 170 171 case PHYSICAL_PRESENCE_CLEAR: 172 case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR: 173 if ((Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR) != 0) { 174 RequestConfirmed = TRUE; 175 } 176 break; 177 178 case PHYSICAL_PRESENCE_DEFERRED_PP_UNOWNERED_FIELD_UPGRADE: 179 if ((Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_MAINTENANCE) != 0) { 180 RequestConfirmed = TRUE; 181 } 182 break; 183 184 case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE: 185 case PHYSICAL_PRESENCE_CLEAR_ENABLE_ACTIVATE: 186 if ((Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR) != 0 && (Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_PROVISION) != 0) { 187 RequestConfirmed = TRUE; 188 } 189 break; 190 191 case PHYSICAL_PRESENCE_SET_NO_PPI_PROVISION_FALSE: 192 case PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_FALSE: 193 case PHYSICAL_PRESENCE_SET_NO_PPI_MAINTENANCE_FALSE: 194 case PHYSICAL_PRESENCE_NO_ACTION: 195 RequestConfirmed = TRUE; 196 break; 197 198 case PHYSICAL_PRESENCE_SET_OPERATOR_AUTH: 199 // 200 // This command requires UI to prompt user for Auth data 201 // 202 mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_GET_USER_CONFIRMATION_NOT_IMPLEMENTED; 203 return EFI_SUCCESS; 204 default: 205 break; 206 } 207 208 if (RequestConfirmed) { 209 mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_GET_USER_CONFIRMATION_ALLOWED_AND_PPUSER_NOT_REQUIRED; 210 } else { 211 mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_GET_USER_CONFIRMATION_ALLOWED_AND_PPUSER_REQUIRED; 212 } 213 if (mTcgNvs->PhysicalPresence.Request >= TCG_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) { 214 mTcgNvs->PhysicalPresence.ReturnCode = TcgPpVendorLibGetUserConfirmationStatusFunction (mTcgNvs->PhysicalPresence.Request, Flags.PPFlags); 215 } 216 } 217 218 return EFI_SUCCESS; 219 } 220 221 222 /** 223 Software SMI callback for MemoryClear which is called from ACPI method. 224 225 Caution: This function may receive untrusted input. 226 Variable and ACPINvs are external input, so this function will validate 227 its data structure to be valid value. 228 229 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). 230 @param[in] Context Points to an optional handler context which was specified when the 231 handler was registered. 232 @param[in, out] CommBuffer A pointer to a collection of data in memory that will 233 be conveyed from a non-SMM environment into an SMM environment. 234 @param[in, out] CommBufferSize The size of the CommBuffer. 235 236 @retval EFI_SUCCESS The interrupt was handled successfully. 237 238 **/ 239 EFI_STATUS 240 EFIAPI 241 MemoryClearCallback ( 242 IN EFI_HANDLE DispatchHandle, 243 IN CONST VOID *Context, 244 IN OUT VOID *CommBuffer, 245 IN OUT UINTN *CommBufferSize 246 ) 247 { 248 EFI_STATUS Status; 249 UINTN DataSize; 250 UINT8 MorControl; 251 252 mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_SUCCESS; 253 if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE) { 254 MorControl = (UINT8) mTcgNvs->MemoryClear.Request; 255 } else if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_PTS_CLEAR_MOR_BIT) { 256 DataSize = sizeof (UINT8); 257 Status = mSmmVariable->SmmGetVariable ( 258 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, 259 &gEfiMemoryOverwriteControlDataGuid, 260 NULL, 261 &DataSize, 262 &MorControl 263 ); 264 if (EFI_ERROR (Status)) { 265 mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE; 266 DEBUG ((EFI_D_ERROR, "[TPM] Get MOR variable failure! Status = %r\n", Status)); 267 return EFI_SUCCESS; 268 } 269 270 if (MOR_CLEAR_MEMORY_VALUE (MorControl) == 0x0) { 271 return EFI_SUCCESS; 272 } 273 MorControl &= ~MOR_CLEAR_MEMORY_BIT_MASK; 274 } 275 276 DataSize = sizeof (UINT8); 277 Status = mSmmVariable->SmmSetVariable ( 278 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, 279 &gEfiMemoryOverwriteControlDataGuid, 280 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 281 DataSize, 282 &MorControl 283 ); 284 if (EFI_ERROR (Status)) { 285 mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE; 286 DEBUG ((EFI_D_ERROR, "[TPM] Set MOR variable failure! Status = %r\n", Status)); 287 } 288 289 return EFI_SUCCESS; 290 } 291 292 /** 293 Find the operation region in TCG ACPI table by given Name and Size, 294 and initialize it if the region is found. 295 296 @param[in, out] Table The TPM item in ACPI table. 297 @param[in] Name The name string to find in TPM table. 298 @param[in] Size The size of the region to find. 299 300 @return The allocated address for the found region. 301 302 **/ 303 VOID * 304 AssignOpRegion ( 305 EFI_ACPI_DESCRIPTION_HEADER *Table, 306 UINT32 Name, 307 UINT16 Size 308 ) 309 { 310 EFI_STATUS Status; 311 AML_OP_REGION_32_8 *OpRegion; 312 EFI_PHYSICAL_ADDRESS MemoryAddress; 313 314 MemoryAddress = SIZE_4GB - 1; 315 316 // 317 // Patch some pointers for the ASL code before loading the SSDT. 318 // 319 for (OpRegion = (AML_OP_REGION_32_8 *) (Table + 1); 320 OpRegion <= (AML_OP_REGION_32_8 *) ((UINT8 *) Table + Table->Length); 321 OpRegion = (AML_OP_REGION_32_8 *) ((UINT8 *) OpRegion + 1)) { 322 if ((OpRegion->OpRegionOp == AML_EXT_REGION_OP) && 323 (OpRegion->NameString == Name) && 324 (OpRegion->DWordPrefix == AML_DWORD_PREFIX) && 325 (OpRegion->BytePrefix == AML_BYTE_PREFIX)) { 326 327 Status = gBS->AllocatePages(AllocateMaxAddress, EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (Size), &MemoryAddress); 328 ASSERT_EFI_ERROR (Status); 329 ZeroMem ((VOID *)(UINTN)MemoryAddress, Size); 330 OpRegion->RegionOffset = (UINT32) (UINTN) MemoryAddress; 331 OpRegion->RegionLen = (UINT8) Size; 332 break; 333 } 334 } 335 336 return (VOID *) (UINTN) MemoryAddress; 337 } 338 339 /** 340 Initialize and publish TPM items in ACPI table. 341 342 @retval EFI_SUCCESS The TCG ACPI table is published successfully. 343 @retval Others The TCG ACPI table is not published. 344 345 **/ 346 EFI_STATUS 347 PublishAcpiTable ( 348 VOID 349 ) 350 { 351 EFI_STATUS Status; 352 EFI_ACPI_TABLE_PROTOCOL *AcpiTable; 353 UINTN TableKey; 354 EFI_ACPI_DESCRIPTION_HEADER *Table; 355 UINTN TableSize; 356 357 Status = GetSectionFromFv ( 358 &gEfiCallerIdGuid, 359 EFI_SECTION_RAW, 360 0, 361 (VOID **) &Table, 362 &TableSize 363 ); 364 ASSERT_EFI_ERROR (Status); 365 366 367 // 368 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA 369 // 370 TpmMeasureAndLogData( 371 0, 372 EV_POST_CODE, 373 EV_POSTCODE_INFO_ACPI_DATA, 374 ACPI_DATA_LEN, 375 Table, 376 TableSize 377 ); 378 379 380 ASSERT (Table->OemTableId == SIGNATURE_64 ('T', 'c', 'g', 'T', 'a', 'b', 'l', 'e')); 381 CopyMem (Table->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (Table->OemId) ); 382 mTcgNvs = AssignOpRegion (Table, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16) sizeof (TCG_NVS)); 383 ASSERT (mTcgNvs != NULL); 384 385 // 386 // Publish the TPM ACPI table 387 // 388 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable); 389 ASSERT_EFI_ERROR (Status); 390 391 TableKey = 0; 392 Status = AcpiTable->InstallAcpiTable ( 393 AcpiTable, 394 Table, 395 TableSize, 396 &TableKey 397 ); 398 ASSERT_EFI_ERROR (Status); 399 400 return Status; 401 } 402 403 /** 404 The driver's entry point. 405 406 It install callbacks for TPM physical presence and MemoryClear, and locate 407 SMM variable to be used in the callback function. 408 409 @param[in] ImageHandle The firmware allocated handle for the EFI image. 410 @param[in] SystemTable A pointer to the EFI System Table. 411 412 @retval EFI_SUCCESS The entry point is executed successfully. 413 @retval Others Some error occurs when executing this entry point. 414 415 **/ 416 EFI_STATUS 417 EFIAPI 418 InitializeTcgSmm ( 419 IN EFI_HANDLE ImageHandle, 420 IN EFI_SYSTEM_TABLE *SystemTable 421 ) 422 { 423 EFI_STATUS Status; 424 EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch; 425 EFI_SMM_SW_REGISTER_CONTEXT SwContext; 426 EFI_HANDLE SwHandle; 427 428 if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){ 429 DEBUG ((EFI_D_ERROR, "No TPM12 instance required!\n")); 430 return EFI_UNSUPPORTED; 431 } 432 433 Status = PublishAcpiTable (); 434 ASSERT_EFI_ERROR (Status); 435 436 // 437 // Get the Sw dispatch protocol and register SMI callback functions. 438 // 439 Status = gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID**)&SwDispatch); 440 ASSERT_EFI_ERROR (Status); 441 SwContext.SwSmiInputValue = (UINTN) -1; 442 Status = SwDispatch->Register (SwDispatch, PhysicalPresenceCallback, &SwContext, &SwHandle); 443 ASSERT_EFI_ERROR (Status); 444 if (EFI_ERROR (Status)) { 445 return Status; 446 } 447 mTcgNvs->PhysicalPresence.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue; 448 449 SwContext.SwSmiInputValue = (UINTN) -1; 450 Status = SwDispatch->Register (SwDispatch, MemoryClearCallback, &SwContext, &SwHandle); 451 ASSERT_EFI_ERROR (Status); 452 if (EFI_ERROR (Status)) { 453 return Status; 454 } 455 mTcgNvs->MemoryClear.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue; 456 457 // 458 // Locate SmmVariableProtocol. 459 // 460 Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mSmmVariable); 461 ASSERT_EFI_ERROR (Status); 462 463 return EFI_SUCCESS; 464 } 465 466