2 It updates TPM2 items in ACPI table and registers SMI2 callback
3 functions for TrEE physical presence, ClearMemory, and sample
6 Caution: This module requires additional review when modified.
7 This driver will have external input - variable and ACPINvs data in SMM mode.
8 This external input must be validated carefully to avoid security issue.
10 PhysicalPresenceCallback() and MemoryClearCallback() will receive untrusted input and do some check.
12 Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
13 This program and the accompanying materials
14 are licensed and made available under the terms and conditions of the BSD License
15 which accompanies this distribution. The full text of the license may be found at
16 http://opensource.org/licenses/bsd-license.php
18 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
19 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
25 EFI_TPM2_ACPI_TABLE mTpm2AcpiTemplate
= {
27 EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE
,
28 sizeof (mTpm2AcpiTemplate
),
29 EFI_TPM2_ACPI_TABLE_REVISION
,
31 // Compiler initializes the remaining bytes to 0
32 // These fields should be filled in in production
37 EFI_TPM2_ACPI_TABLE_START_METHOD_TIS
, // StartMethod
40 EFI_SMM_VARIABLE_PROTOCOL
*mSmmVariable
;
44 Software SMI callback for TPM physical presence which is called from ACPI method.
46 Caution: This function may receive untrusted input.
47 Variable and ACPINvs are external input, so this function will validate
48 its data structure to be valid value.
50 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
51 @param[in] Context Points to an optional handler context which was specified when the
52 handler was registered.
53 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
54 be conveyed from a non-SMM environment into an SMM environment.
55 @param[in, out] CommBufferSize The size of the CommBuffer.
57 @retval EFI_SUCCESS The interrupt was handled successfully.
62 PhysicalPresenceCallback (
63 IN EFI_HANDLE DispatchHandle
,
64 IN CONST VOID
*Context
,
65 IN OUT VOID
*CommBuffer
,
66 IN OUT UINTN
*CommBufferSize
71 EFI_TREE_PHYSICAL_PRESENCE PpData
;
72 EFI_TREE_PHYSICAL_PRESENCE_FLAGS Flags
;
73 BOOLEAN RequestConfirmed
;
76 // Get the Physical Presence variable
78 DataSize
= sizeof (EFI_TREE_PHYSICAL_PRESENCE
);
79 Status
= mSmmVariable
->SmmGetVariable (
80 TREE_PHYSICAL_PRESENCE_VARIABLE
,
81 &gEfiTrEEPhysicalPresenceGuid
,
87 DEBUG ((EFI_D_INFO
, "[TPM2] PP callback, Parameter = %x, Request = %x\n", mTcgNvs
->PhysicalPresence
.Parameter
, mTcgNvs
->PhysicalPresence
.Request
));
89 if (mTcgNvs
->PhysicalPresence
.Parameter
== ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS
) {
90 if (EFI_ERROR (Status
)) {
91 mTcgNvs
->PhysicalPresence
.ReturnCode
= PP_RETURN_TPM_OPERATION_RESPONSE_FAILURE
;
92 mTcgNvs
->PhysicalPresence
.LastRequest
= 0;
93 mTcgNvs
->PhysicalPresence
.Response
= 0;
94 DEBUG ((EFI_D_ERROR
, "[TPM2] Get PP variable failure! Status = %r\n", Status
));
97 mTcgNvs
->PhysicalPresence
.ReturnCode
= PP_RETURN_TPM_OPERATION_RESPONSE_SUCCESS
;
98 mTcgNvs
->PhysicalPresence
.LastRequest
= PpData
.LastPPRequest
;
99 mTcgNvs
->PhysicalPresence
.Response
= PpData
.PPResponse
;
100 } else if ((mTcgNvs
->PhysicalPresence
.Parameter
== ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS
)
101 || (mTcgNvs
->PhysicalPresence
.Parameter
== ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2
)) {
102 if (EFI_ERROR (Status
)) {
103 mTcgNvs
->PhysicalPresence
.ReturnCode
= TREE_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE
;
104 DEBUG ((EFI_D_ERROR
, "[TPM2] Get PP variable failure! Status = %r\n", Status
));
107 if ((mTcgNvs
->PhysicalPresence
.Request
> TREE_PHYSICAL_PRESENCE_NO_ACTION_MAX
) &&
108 (mTcgNvs
->PhysicalPresence
.Request
< TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION
) ) {
110 // This command requires UI to prompt user for Auth data.
112 mTcgNvs
->PhysicalPresence
.ReturnCode
= TREE_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED
;
116 if (PpData
.PPRequest
!= mTcgNvs
->PhysicalPresence
.Request
) {
117 PpData
.PPRequest
= (UINT8
) mTcgNvs
->PhysicalPresence
.Request
;
118 DataSize
= sizeof (EFI_TREE_PHYSICAL_PRESENCE
);
119 Status
= mSmmVariable
->SmmSetVariable (
120 TREE_PHYSICAL_PRESENCE_VARIABLE
,
121 &gEfiTrEEPhysicalPresenceGuid
,
122 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
128 if (EFI_ERROR (Status
)) {
129 mTcgNvs
->PhysicalPresence
.ReturnCode
= TREE_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE
;
130 DEBUG ((EFI_D_ERROR
, "[TPM2] Set PP variable failure! Status = %r\n", Status
));
133 mTcgNvs
->PhysicalPresence
.ReturnCode
= TREE_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS
;
135 if (mTcgNvs
->PhysicalPresence
.Request
>= TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION
) {
136 DataSize
= sizeof (EFI_TREE_PHYSICAL_PRESENCE_FLAGS
);
137 Status
= mSmmVariable
->SmmGetVariable (
138 TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE
,
139 &gEfiTrEEPhysicalPresenceGuid
,
144 if (EFI_ERROR (Status
)) {
147 mTcgNvs
->PhysicalPresence
.ReturnCode
= TrEEPpVendorLibSubmitRequestToPreOSFunction (mTcgNvs
->PhysicalPresence
.Request
, Flags
.PPFlags
);
149 } else if (mTcgNvs
->PhysicalPresence
.Parameter
== ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST
) {
150 if (EFI_ERROR (Status
)) {
151 mTcgNvs
->PhysicalPresence
.ReturnCode
= TREE_PP_GET_USER_CONFIRMATION_BLOCKED_BY_BIOS_CONFIGURATION
;
152 DEBUG ((EFI_D_ERROR
, "[TPM2] Get PP variable failure! Status = %r\n", Status
));
156 // Get the Physical Presence flags
158 DataSize
= sizeof (EFI_TREE_PHYSICAL_PRESENCE_FLAGS
);
159 Status
= mSmmVariable
->SmmGetVariable (
160 TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE
,
161 &gEfiTrEEPhysicalPresenceGuid
,
166 if (EFI_ERROR (Status
)) {
167 mTcgNvs
->PhysicalPresence
.ReturnCode
= TREE_PP_GET_USER_CONFIRMATION_BLOCKED_BY_BIOS_CONFIGURATION
;
168 DEBUG ((EFI_D_ERROR
, "[TPM2] Get PP flags failure! Status = %r\n", Status
));
172 RequestConfirmed
= FALSE
;
174 switch (mTcgNvs
->PhysicalPresence
.Request
) {
176 case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR
:
177 case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_2
:
178 case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_3
:
179 case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_4
:
180 if ((Flags
.PPFlags
& TREE_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR
) != 0) {
181 RequestConfirmed
= TRUE
;
185 case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_FALSE
:
186 RequestConfirmed
= TRUE
;
189 case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_TRUE
:
193 if (mTcgNvs
->PhysicalPresence
.Request
<= TREE_PHYSICAL_PRESENCE_NO_ACTION_MAX
) {
194 RequestConfirmed
= TRUE
;
196 if (mTcgNvs
->PhysicalPresence
.Request
< TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION
) {
197 mTcgNvs
->PhysicalPresence
.ReturnCode
= TREE_PP_GET_USER_CONFIRMATION_NOT_IMPLEMENTED
;
204 if (RequestConfirmed
) {
205 mTcgNvs
->PhysicalPresence
.ReturnCode
= TREE_PP_GET_USER_CONFIRMATION_ALLOWED_AND_PPUSER_NOT_REQUIRED
;
207 mTcgNvs
->PhysicalPresence
.ReturnCode
= TREE_PP_GET_USER_CONFIRMATION_ALLOWED_AND_PPUSER_REQUIRED
;
209 if (mTcgNvs
->PhysicalPresence
.Request
>= TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION
) {
210 mTcgNvs
->PhysicalPresence
.ReturnCode
= TrEEPpVendorLibGetUserConfirmationStatusFunction (mTcgNvs
->PhysicalPresence
.Request
, Flags
.PPFlags
);
219 Software SMI callback for MemoryClear which is called from ACPI method.
221 Caution: This function may receive untrusted input.
222 Variable and ACPINvs are external input, so this function will validate
223 its data structure to be valid value.
225 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
226 @param[in] Context Points to an optional handler context which was specified when the
227 handler was registered.
228 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
229 be conveyed from a non-SMM environment into an SMM environment.
230 @param[in, out] CommBufferSize The size of the CommBuffer.
232 @retval EFI_SUCCESS The interrupt was handled successfully.
237 MemoryClearCallback (
238 IN EFI_HANDLE DispatchHandle
,
239 IN CONST VOID
*Context
,
240 IN OUT VOID
*CommBuffer
,
241 IN OUT UINTN
*CommBufferSize
248 mTcgNvs
->MemoryClear
.ReturnCode
= MOR_REQUEST_SUCCESS
;
249 if (mTcgNvs
->MemoryClear
.Parameter
== ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE
) {
250 MorControl
= (UINT8
) mTcgNvs
->MemoryClear
.Request
;
251 } else if (mTcgNvs
->MemoryClear
.Parameter
== ACPI_FUNCTION_PTS_CLEAR_MOR_BIT
) {
252 DataSize
= sizeof (UINT8
);
253 Status
= mSmmVariable
->SmmGetVariable (
254 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME
,
255 &gEfiMemoryOverwriteControlDataGuid
,
260 if (EFI_ERROR (Status
)) {
261 mTcgNvs
->MemoryClear
.ReturnCode
= MOR_REQUEST_GENERAL_FAILURE
;
262 DEBUG ((EFI_D_ERROR
, "[TPM] Get MOR variable failure! Status = %r\n", Status
));
266 if (MOR_CLEAR_MEMORY_VALUE (MorControl
) == 0x0) {
269 MorControl
&= ~MOR_CLEAR_MEMORY_BIT_MASK
;
272 DataSize
= sizeof (UINT8
);
273 Status
= mSmmVariable
->SmmSetVariable (
274 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME
,
275 &gEfiMemoryOverwriteControlDataGuid
,
276 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
280 if (EFI_ERROR (Status
)) {
281 mTcgNvs
->MemoryClear
.ReturnCode
= MOR_REQUEST_GENERAL_FAILURE
;
282 DEBUG ((EFI_D_ERROR
, "[TPM] Set MOR variable failure! Status = %r\n", Status
));
289 Find the operation region in TCG ACPI table by given Name and Size,
290 and initialize it if the region is found.
292 @param[in, out] Table The TPM item in ACPI table.
293 @param[in] Name The name string to find in TPM table.
294 @param[in] Size The size of the region to find.
296 @return The allocated address for the found region.
301 EFI_ACPI_DESCRIPTION_HEADER
*Table
,
307 AML_OP_REGION_32_8
*OpRegion
;
308 EFI_PHYSICAL_ADDRESS MemoryAddress
;
310 MemoryAddress
= SIZE_4GB
- 1;
313 // Patch some pointers for the ASL code before loading the SSDT.
315 for (OpRegion
= (AML_OP_REGION_32_8
*) (Table
+ 1);
316 OpRegion
<= (AML_OP_REGION_32_8
*) ((UINT8
*) Table
+ Table
->Length
);
317 OpRegion
= (AML_OP_REGION_32_8
*) ((UINT8
*) OpRegion
+ 1)) {
318 if ((OpRegion
->OpRegionOp
== AML_EXT_REGION_OP
) &&
319 (OpRegion
->NameString
== Name
) &&
320 (OpRegion
->DWordPrefix
== AML_DWORD_PREFIX
) &&
321 (OpRegion
->BytePrefix
== AML_BYTE_PREFIX
)) {
323 Status
= gBS
->AllocatePages(AllocateMaxAddress
, EfiACPIMemoryNVS
, EFI_SIZE_TO_PAGES (Size
), &MemoryAddress
);
324 ASSERT_EFI_ERROR (Status
);
325 ZeroMem ((VOID
*)(UINTN
)MemoryAddress
, Size
);
326 OpRegion
->RegionOffset
= (UINT32
) (UINTN
) MemoryAddress
;
327 OpRegion
->RegionLen
= (UINT8
) Size
;
332 return (VOID
*) (UINTN
) MemoryAddress
;
336 Initialize and publish TPM items in ACPI table.
338 @retval EFI_SUCCESS The TCG ACPI table is published successfully.
339 @retval Others The TCG ACPI table is not published.
348 EFI_ACPI_TABLE_PROTOCOL
*AcpiTable
;
350 EFI_ACPI_DESCRIPTION_HEADER
*Table
;
353 Status
= GetSectionFromFv (
360 ASSERT_EFI_ERROR (Status
);
364 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
366 TpmMeasureAndLogData(
369 EV_POSTCODE_INFO_ACPI_DATA
,
376 ASSERT (Table
->OemTableId
== SIGNATURE_64 ('T', 'p', 'm', '2', 'T', 'a', 'b', 'l'));
377 CopyMem (Table
->OemId
, PcdGetPtr (PcdAcpiDefaultOemId
), sizeof (Table
->OemId
) );
378 mTcgNvs
= AssignOpRegion (Table
, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16
) sizeof (TCG_NVS
));
379 ASSERT (mTcgNvs
!= NULL
);
382 // Publish the TPM ACPI table
384 Status
= gBS
->LocateProtocol (&gEfiAcpiTableProtocolGuid
, NULL
, (VOID
**) &AcpiTable
);
385 ASSERT_EFI_ERROR (Status
);
388 Status
= AcpiTable
->InstallAcpiTable (
394 ASSERT_EFI_ERROR (Status
);
400 Publish TPM2 ACPI table
402 @retval EFI_SUCCESS The TPM2 ACPI table is published successfully.
403 @retval Others The TPM2 ACPI table is not published.
412 EFI_ACPI_TABLE_PROTOCOL
*AcpiTable
;
417 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
419 TpmMeasureAndLogData(
422 EV_POSTCODE_INFO_ACPI_DATA
,
425 sizeof(mTpm2AcpiTemplate
)
428 CopyMem (mTpm2AcpiTemplate
.Header
.OemId
, PcdGetPtr (PcdAcpiDefaultOemId
), sizeof (mTpm2AcpiTemplate
.Header
.OemId
));
429 OemTableId
= PcdGet64 (PcdAcpiDefaultOemTableId
);
430 CopyMem (&mTpm2AcpiTemplate
.Header
.OemTableId
, &OemTableId
, sizeof (UINT64
));
431 mTpm2AcpiTemplate
.Header
.OemRevision
= PcdGet32 (PcdAcpiDefaultOemRevision
);
432 mTpm2AcpiTemplate
.Header
.CreatorId
= PcdGet32 (PcdAcpiDefaultCreatorId
);
433 mTpm2AcpiTemplate
.Header
.CreatorRevision
= PcdGet32 (PcdAcpiDefaultCreatorRevision
);
436 // Construct ACPI table
438 Status
= gBS
->LocateProtocol (&gEfiAcpiTableProtocolGuid
, NULL
, (VOID
**) &AcpiTable
);
439 ASSERT_EFI_ERROR (Status
);
441 Status
= AcpiTable
->InstallAcpiTable (
444 sizeof(mTpm2AcpiTemplate
),
447 ASSERT_EFI_ERROR (Status
);
453 The driver's entry point.
455 It install callbacks for TPM physical presence and MemoryClear, and locate
456 SMM variable to be used in the callback function.
458 @param[in] ImageHandle The firmware allocated handle for the EFI image.
459 @param[in] SystemTable A pointer to the EFI System Table.
461 @retval EFI_SUCCESS The entry point is executed successfully.
462 @retval Others Some error occurs when executing this entry point.
468 IN EFI_HANDLE ImageHandle
,
469 IN EFI_SYSTEM_TABLE
*SystemTable
473 EFI_SMM_SW_DISPATCH2_PROTOCOL
*SwDispatch
;
474 EFI_SMM_SW_REGISTER_CONTEXT SwContext
;
477 if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid
), &gEfiTpmDeviceInstanceTpm20DtpmGuid
)){
478 DEBUG ((EFI_D_ERROR
, "No TPM2 DTPM instance required!\n"));
479 return EFI_UNSUPPORTED
;
482 Status
= PublishAcpiTable ();
483 ASSERT_EFI_ERROR (Status
);
486 // Get the Sw dispatch protocol and register SMI callback functions.
488 Status
= gSmst
->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid
, NULL
, (VOID
**)&SwDispatch
);
489 ASSERT_EFI_ERROR (Status
);
490 SwContext
.SwSmiInputValue
= (UINTN
) -1;
491 Status
= SwDispatch
->Register (SwDispatch
, PhysicalPresenceCallback
, &SwContext
, &SwHandle
);
492 ASSERT_EFI_ERROR (Status
);
493 if (EFI_ERROR (Status
)) {
496 mTcgNvs
->PhysicalPresence
.SoftwareSmi
= (UINT8
) SwContext
.SwSmiInputValue
;
498 SwContext
.SwSmiInputValue
= (UINTN
) -1;
499 Status
= SwDispatch
->Register (SwDispatch
, MemoryClearCallback
, &SwContext
, &SwHandle
);
500 ASSERT_EFI_ERROR (Status
);
501 if (EFI_ERROR (Status
)) {
504 mTcgNvs
->MemoryClear
.SoftwareSmi
= (UINT8
) SwContext
.SwSmiInputValue
;
507 // Locate SmmVariableProtocol.
509 Status
= gSmst
->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid
, NULL
, (VOID
**)&mSmmVariable
);
510 ASSERT_EFI_ERROR (Status
);
513 // Set TPM2 ACPI table
515 Status
= PublishTpm2 ();
516 ASSERT_EFI_ERROR (Status
);