2 It updates TPM2 items in ACPI table and registers SMI2 callback
3 functions for Tcg2 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) 2015 - 2018, 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.
26 EFI_TPM2_ACPI_TABLE mTpm2AcpiTemplate
= {
28 EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE
,
29 sizeof (mTpm2AcpiTemplate
),
30 EFI_TPM2_ACPI_TABLE_REVISION
,
32 // Compiler initializes the remaining bytes to 0
33 // These fields should be filled in in production
36 0, // BIT0~15: PlatformClass
39 EFI_TPM2_ACPI_TABLE_START_METHOD_TIS
, // StartMethod
42 EFI_SMM_VARIABLE_PROTOCOL
*mSmmVariable
;
46 Software SMI callback for TPM physical presence which is called from ACPI method.
48 Caution: This function may receive untrusted input.
49 Variable and ACPINvs are external input, so this function will validate
50 its data structure to be valid value.
52 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
53 @param[in] Context Points to an optional handler context which was specified when the
54 handler was registered.
55 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
56 be conveyed from a non-SMM environment into an SMM environment.
57 @param[in, out] CommBufferSize The size of the CommBuffer.
59 @retval EFI_SUCCESS The interrupt was handled successfully.
64 PhysicalPresenceCallback (
65 IN EFI_HANDLE DispatchHandle
,
66 IN CONST VOID
*Context
,
67 IN OUT VOID
*CommBuffer
,
68 IN OUT UINTN
*CommBufferSize
71 UINT32 MostRecentRequest
;
73 UINT32 OperationRequest
;
74 UINT32 RequestParameter
;
77 if (mTcgNvs
->PhysicalPresence
.Parameter
== TCG_ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS
) {
78 mTcgNvs
->PhysicalPresence
.ReturnCode
= Tcg2PhysicalPresenceLibReturnOperationResponseToOsFunction (
82 mTcgNvs
->PhysicalPresence
.LastRequest
= MostRecentRequest
;
83 mTcgNvs
->PhysicalPresence
.Response
= Response
;
85 } else if ((mTcgNvs
->PhysicalPresence
.Parameter
== TCG_ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS
)
86 || (mTcgNvs
->PhysicalPresence
.Parameter
== TCG_ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2
)) {
88 OperationRequest
= mTcgNvs
->PhysicalPresence
.Request
;
89 RequestParameter
= mTcgNvs
->PhysicalPresence
.RequestParameter
;
90 mTcgNvs
->PhysicalPresence
.ReturnCode
= Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunctionEx (
94 mTcgNvs
->PhysicalPresence
.Request
= OperationRequest
;
95 mTcgNvs
->PhysicalPresence
.RequestParameter
= RequestParameter
;
96 } else if (mTcgNvs
->PhysicalPresence
.Parameter
== TCG_ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST
) {
97 mTcgNvs
->PhysicalPresence
.ReturnCode
= Tcg2PhysicalPresenceLibGetUserConfirmationStatusFunction (mTcgNvs
->PPRequestUserConfirm
);
105 Software SMI callback for MemoryClear which is called from ACPI method.
107 Caution: This function may receive untrusted input.
108 Variable and ACPINvs are external input, so this function will validate
109 its data structure to be valid value.
111 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
112 @param[in] Context Points to an optional handler context which was specified when the
113 handler was registered.
114 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
115 be conveyed from a non-SMM environment into an SMM environment.
116 @param[in, out] CommBufferSize The size of the CommBuffer.
118 @retval EFI_SUCCESS The interrupt was handled successfully.
123 MemoryClearCallback (
124 IN EFI_HANDLE DispatchHandle
,
125 IN CONST VOID
*Context
,
126 IN OUT VOID
*CommBuffer
,
127 IN OUT UINTN
*CommBufferSize
134 mTcgNvs
->MemoryClear
.ReturnCode
= MOR_REQUEST_SUCCESS
;
135 if (mTcgNvs
->MemoryClear
.Parameter
== ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE
) {
136 MorControl
= (UINT8
) mTcgNvs
->MemoryClear
.Request
;
137 } else if (mTcgNvs
->MemoryClear
.Parameter
== ACPI_FUNCTION_PTS_CLEAR_MOR_BIT
) {
138 DataSize
= sizeof (UINT8
);
139 Status
= mSmmVariable
->SmmGetVariable (
140 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME
,
141 &gEfiMemoryOverwriteControlDataGuid
,
146 if (EFI_ERROR (Status
)) {
147 mTcgNvs
->MemoryClear
.ReturnCode
= MOR_REQUEST_GENERAL_FAILURE
;
148 DEBUG ((EFI_D_ERROR
, "[TPM] Get MOR variable failure! Status = %r\n", Status
));
152 if (MOR_CLEAR_MEMORY_VALUE (MorControl
) == 0x0) {
155 MorControl
&= ~MOR_CLEAR_MEMORY_BIT_MASK
;
157 mTcgNvs
->MemoryClear
.ReturnCode
= MOR_REQUEST_GENERAL_FAILURE
;
158 DEBUG ((EFI_D_ERROR
, "[TPM] MOR Parameter error! Parameter = %x\n", mTcgNvs
->MemoryClear
.Parameter
));
162 DataSize
= sizeof (UINT8
);
163 Status
= mSmmVariable
->SmmSetVariable (
164 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME
,
165 &gEfiMemoryOverwriteControlDataGuid
,
166 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
170 if (EFI_ERROR (Status
)) {
171 mTcgNvs
->MemoryClear
.ReturnCode
= MOR_REQUEST_GENERAL_FAILURE
;
172 DEBUG ((EFI_D_ERROR
, "[TPM] Set MOR variable failure! Status = %r\n", Status
));
179 Find the operation region in TCG ACPI table by given Name and Size,
180 and initialize it if the region is found.
182 @param[in, out] Table The TPM item in ACPI table.
183 @param[in] Name The name string to find in TPM table.
184 @param[in] Size The size of the region to find.
186 @return The allocated address for the found region.
191 EFI_ACPI_DESCRIPTION_HEADER
*Table
,
197 AML_OP_REGION_32_8
*OpRegion
;
198 EFI_PHYSICAL_ADDRESS MemoryAddress
;
200 MemoryAddress
= SIZE_4GB
- 1;
203 // Patch some pointers for the ASL code before loading the SSDT.
205 for (OpRegion
= (AML_OP_REGION_32_8
*) (Table
+ 1);
206 OpRegion
<= (AML_OP_REGION_32_8
*) ((UINT8
*) Table
+ Table
->Length
);
207 OpRegion
= (AML_OP_REGION_32_8
*) ((UINT8
*) OpRegion
+ 1)) {
208 if ((OpRegion
->OpRegionOp
== AML_EXT_REGION_OP
) &&
209 (OpRegion
->NameString
== Name
) &&
210 (OpRegion
->DWordPrefix
== AML_DWORD_PREFIX
) &&
211 (OpRegion
->BytePrefix
== AML_BYTE_PREFIX
)) {
213 Status
= gBS
->AllocatePages(AllocateMaxAddress
, EfiACPIMemoryNVS
, EFI_SIZE_TO_PAGES (Size
), &MemoryAddress
);
214 ASSERT_EFI_ERROR (Status
);
215 ZeroMem ((VOID
*)(UINTN
)MemoryAddress
, Size
);
216 OpRegion
->RegionOffset
= (UINT32
) (UINTN
) MemoryAddress
;
217 OpRegion
->RegionLen
= (UINT8
) Size
;
222 return (VOID
*) (UINTN
) MemoryAddress
;
226 Patch version string of Physical Presence interface supported by platform. The initial string tag in TPM
229 @param[in, out] Table The TPM item in ACPI table.
230 @param[in] PPVer Version string of Physical Presence interface supported by platform.
232 @return The allocated address for the found region.
237 EFI_ACPI_DESCRIPTION_HEADER
*Table
,
245 // Patch some pointers for the ASL code before loading the SSDT.
247 for (DataPtr
= (UINT8
*)(Table
+ 1);
248 DataPtr
<= (UINT8
*) ((UINT8
*) Table
+ Table
->Length
- PHYSICAL_PRESENCE_VERSION_SIZE
);
250 if (AsciiStrCmp((CHAR8
*)DataPtr
, PHYSICAL_PRESENCE_VERSION_TAG
) == 0) {
251 Status
= AsciiStrCpyS((CHAR8
*)DataPtr
, PHYSICAL_PRESENCE_VERSION_SIZE
, PPVer
);
252 DEBUG((EFI_D_INFO
, "TPM2 Physical Presence Interface Version update status 0x%x\n", Status
));
257 return EFI_NOT_FOUND
;
261 Patch interrupt resources returned by TPM _PRS. ResourceTemplate to patch is determined by input
262 interrupt buffer size. BufferSize, PkgLength and interrupt descirptor in ByteList need to be patched
264 @param[in, out] Table The TPM item in ACPI table.
265 @param[in] IrqBuffer Input new IRQ buffer.
266 @param[in] IrqBuffserSize Input new IRQ buffer size.
267 @param[out] IsShortFormPkgLength If _PRS returns Short length Package(ACPI spec 20.2.4).
269 @return patch status.
273 UpdatePossibleResource (
274 IN OUT EFI_ACPI_DESCRIPTION_HEADER
*Table
,
275 IN UINT32
*IrqBuffer
,
276 IN UINT32 IrqBuffserSize
,
277 OUT BOOLEAN
*IsShortFormPkgLength
283 UINT32 OrignalPkgLength
;
286 OrignalPkgLength
= 0;
291 // 6.4.3 Extend Interrupt Descriptor.
292 // 19.3.3 ASL Resource Template
293 // 20 AML specification
294 // to patch TPM ACPI object _PRS returned ResourceTemplate() containing 2 resource descriptors and an auto appended End Tag
296 // AML data is organized by following rule.
297 // Code need to patch BufferSize and PkgLength and interrupt descirptor in ByteList
299 // ============= Buffer ====================
300 // DefBuffer := BufferOp PkgLength BufferSize ByteList
303 // ==============PkgLength==================
304 // PkgLength := PkgLeadByte |
305 // <PkgLeadByte ByteData> |
306 // <PkgLeadByte ByteData ByteData> |
307 // <PkgLeadByte ByteData ByteData ByteData>
309 // PkgLeadByte := <bit 7-6: ByteData count that follows (0-3)>
310 // <bit 5-4: Only used if PkgLength <= 63 >
311 // <bit 3-0: Least significant package length nybble>
313 //==============BufferSize==================
314 // BufferSize := Integar
315 // Integar := ByteConst|WordConst|DwordConst....
317 // ByteConst := BytePrefix ByteData
319 //==============ByteList===================
320 // ByteList := ByteData ByteList
322 //=========================================
325 // 1. Check TPM_PRS_RESS with PkgLength <=63 can hold the input interrupt number buffer for patching
327 for (DataPtr
= (UINT8
*)(Table
+ 1);
328 DataPtr
< (UINT8
*) ((UINT8
*) Table
+ Table
->Length
- (TPM_PRS_RES_NAME_SIZE
+ TPM_POS_RES_TEMPLATE_MIN_SIZE
));
330 if (CompareMem(DataPtr
, TPM_PRS_RESS
, TPM_PRS_RES_NAME_SIZE
) == 0) {
332 // Jump over object name & BufferOp
334 DataPtr
+= TPM_PRS_RES_NAME_SIZE
+ 1;
336 if ((*DataPtr
& (BIT7
|BIT6
)) == 0) {
337 OrignalPkgLength
= (UINT32
)*DataPtr
;
338 DataEndPtr
= DataPtr
+ OrignalPkgLength
;
341 // Jump over PkgLength = PkgLeadByte only
346 // Jump over BufferSize
348 if (*(DataPtr
+ 1) == AML_BYTE_PREFIX
) {
350 } else if (*(DataPtr
+ 1) == AML_WORD_PREFIX
) {
352 } else if (*(DataPtr
+ 1) == AML_DWORD_PREFIX
) {
356 return EFI_UNSUPPORTED
;
360 return EFI_UNSUPPORTED
;
364 // Include Memory32Fixed Descritor (12 Bytes) + Interrupt Descriptor header(5 Bytes) + End Tag(2 Bytes)
366 NewPkgLength
+= 19 + IrqBuffserSize
;
367 if (NewPkgLength
> 63) {
371 if (NewPkgLength
> OrignalPkgLength
) {
373 return EFI_INVALID_PARAMETER
;
377 // 1.1 Patch PkgLength
379 *DataPtr
= (UINT8
)NewPkgLength
;
382 // 1.2 Patch BufferSize = sizeof(Memory32Fixed Descritor + Interrupt Descriptor + End Tag).
383 // It is Little endian. So only patch lowest byte of BufferSize due to current interrupt number limit.
385 *(DataPtr
+ 2) = (UINT8
)(IrqBuffserSize
+ 19);
388 // Notify _PRS to report short formed ResourceTemplate
390 *IsShortFormPkgLength
= TRUE
;
397 // 2. Use TPM_PRS_RESL with PkgLength > 63 to hold longer input interrupt number buffer for patching
399 if (NewPkgLength
> 63) {
401 OrignalPkgLength
= 0;
402 for (DataPtr
= (UINT8
*)(Table
+ 1);
403 DataPtr
< (UINT8
*) ((UINT8
*) Table
+ Table
->Length
- (TPM_PRS_RES_NAME_SIZE
+ TPM_POS_RES_TEMPLATE_MIN_SIZE
));
405 if (CompareMem(DataPtr
, TPM_PRS_RESL
, TPM_PRS_RES_NAME_SIZE
) == 0) {
407 // Jump over object name & BufferOp
409 DataPtr
+= TPM_PRS_RES_NAME_SIZE
+ 1;
411 if ((*DataPtr
& (BIT7
|BIT6
)) != 0) {
412 OrignalPkgLength
= (UINT32
)(*(DataPtr
+ 1) << 4) + (*DataPtr
& 0x0F);
413 DataEndPtr
= DataPtr
+ OrignalPkgLength
;
415 // Jump over PkgLength = PkgLeadByte + ByteData length
417 NewPkgLength
+= 1 + ((*DataPtr
& (BIT7
|BIT6
)) >> 6);
420 // Jump over BufferSize
422 if (*(DataPtr
+ NewPkgLength
) == AML_BYTE_PREFIX
) {
424 } else if (*(DataPtr
+ NewPkgLength
) == AML_WORD_PREFIX
) {
426 } else if (*(DataPtr
+ NewPkgLength
) == AML_DWORD_PREFIX
) {
430 return EFI_UNSUPPORTED
;
434 return EFI_UNSUPPORTED
;
438 // Include Memory32Fixed Descritor (12 Bytes) + Interrupt Descriptor header(5 Bytes) + End Tag(2 Bytes)
440 NewPkgLength
+= 19 + IrqBuffserSize
;
442 if (NewPkgLength
> OrignalPkgLength
) {
444 return EFI_INVALID_PARAMETER
;
448 // 2.1 Patch PkgLength. Only patch PkgLeadByte and first ByteData
450 *DataPtr
= (UINT8
)((*DataPtr
) & 0xF0) | (NewPkgLength
& 0x0F);
451 *(DataPtr
+ 1) = (UINT8
)((NewPkgLength
& 0xFF0) >> 4);
454 // 2.2 Patch BufferSize = sizeof(Memory32Fixed Descritor + Interrupt Descriptor + End Tag).
455 // It is Little endian. Only patch lowest byte of BufferSize due to current interrupt number limit.
457 *(DataPtr
+ 2 + ((*DataPtr
& (BIT7
|BIT6
)) >> 6)) = (UINT8
)(IrqBuffserSize
+ 19);
460 // Notify _PRS to report long formed ResourceTemplate
462 *IsShortFormPkgLength
= FALSE
;
468 if (DataPtr
>= (UINT8
*) ((UINT8
*) Table
+ Table
->Length
- (TPM_PRS_RES_NAME_SIZE
+ TPM_POS_RES_TEMPLATE_MIN_SIZE
))) {
469 return EFI_NOT_FOUND
;
473 // 3. Move DataPtr to Interrupt descriptor header and patch interrupt descriptor.
474 // 5 bytes for interrupt descriptor header, 2 bytes for End Tag
476 DataPtr
+= NewPkgLength
- (5 + IrqBuffserSize
+ 2);
478 // 3.1 Patch Length bit[7:0] of Interrupt descirptor patch interrupt descriptor
480 *(DataPtr
+ 1) = (UINT8
)(2 + IrqBuffserSize
);
482 // 3.2 Patch Interrupt Table Length
484 *(DataPtr
+ 4) = (UINT8
)(IrqBuffserSize
/ sizeof(UINT32
));
486 // 3.3 Copy patched InterruptNumBuffer
488 CopyMem(DataPtr
+ 5, IrqBuffer
, IrqBuffserSize
);
491 // 4. Jump over Interrupt descirptor and Patch END Tag, set Checksum field to 0
493 DataPtr
+= 5 + IrqBuffserSize
;
494 *DataPtr
= ACPI_END_TAG_DESCRIPTOR
;
498 // 5. Jump over new ResourceTemplate. Stuff rest bytes to NOOP
501 if (DataPtr
< DataEndPtr
) {
502 SetMem(DataPtr
, (UINTN
)DataEndPtr
- (UINTN
)DataPtr
, AML_NOOP_OP
);
509 Patch TPM2 device HID string. The initial string tag in TPM2 ACPI table is "NNN0000".
511 @param[in, out] Table The TPM2 SSDT ACPI table.
513 @return HID Update status.
518 EFI_ACPI_DESCRIPTION_HEADER
*Table
523 CHAR8 Hid
[TPM_HID_ACPI_SIZE
];
524 UINT32 ManufacturerID
;
525 UINT32 FirmwareVersion1
;
526 UINT32 FirmwareVersion2
;
532 // Initialize HID with Default PNP string
534 ZeroMem(Hid
, TPM_HID_ACPI_SIZE
);
537 // Get Manufacturer ID
539 Status
= Tpm2GetCapabilityManufactureID(&ManufacturerID
);
540 if (!EFI_ERROR(Status
)) {
541 DEBUG((EFI_D_INFO
, "TPM_PT_MANUFACTURER 0x%08x\n", ManufacturerID
));
543 // ManufacturerID defined in TCG Vendor ID Registry
544 // may tailed with 0x00 or 0x20
546 if ((ManufacturerID
>> 24) == 0x00 || ((ManufacturerID
>> 24) == 0x20)) {
548 // HID containing PNP ID "NNN####"
549 // NNN is uppercase letter for Vendor ID specified by manufacturer
551 CopyMem(Hid
, &ManufacturerID
, 3);
554 // HID containing ACP ID "NNNN####"
555 // NNNN is uppercase letter for Vendor ID specified by manufacturer
557 CopyMem(Hid
, &ManufacturerID
, 4);
561 DEBUG ((EFI_D_ERROR
, "Get TPM_PT_MANUFACTURER failed %x!\n", Status
));
566 Status
= Tpm2GetCapabilityFirmwareVersion(&FirmwareVersion1
, &FirmwareVersion2
);
567 if (!EFI_ERROR(Status
)) {
568 DEBUG((EFI_D_INFO
, "TPM_PT_FIRMWARE_VERSION_1 0x%x\n", FirmwareVersion1
));
569 DEBUG((EFI_D_INFO
, "TPM_PT_FIRMWARE_VERSION_2 0x%x\n", FirmwareVersion2
));
571 // #### is Firmware Version 1
574 AsciiSPrint(Hid
+ 3, TPM_HID_PNP_SIZE
- 3, "%02d%02d", ((FirmwareVersion1
& 0xFFFF0000) >> 16), (FirmwareVersion1
& 0x0000FFFF));
576 AsciiSPrint(Hid
+ 4, TPM_HID_ACPI_SIZE
- 4, "%02d%02d", ((FirmwareVersion1
& 0xFFFF0000) >> 16), (FirmwareVersion1
& 0x0000FFFF));
580 DEBUG ((EFI_D_ERROR
, "Get TPM_PT_FIRMWARE_VERSION_X failed %x!\n", Status
));
586 // Patch HID in ASL code before loading the SSDT.
588 for (DataPtr
= (UINT8
*)(Table
+ 1);
589 DataPtr
<= (UINT8
*) ((UINT8
*) Table
+ Table
->Length
- TPM_HID_PNP_SIZE
);
591 if (AsciiStrCmp((CHAR8
*)DataPtr
, TPM_HID_TAG
) == 0) {
593 CopyMem(DataPtr
, Hid
, TPM_HID_PNP_SIZE
);
595 // if HID is PNP ID, patch the last byte in HID TAG to Noop
597 *(DataPtr
+ TPM_HID_PNP_SIZE
) = AML_NOOP_OP
;
600 CopyMem(DataPtr
, Hid
, TPM_HID_ACPI_SIZE
);
602 DEBUG((DEBUG_INFO
, "TPM2 ACPI _HID is patched to %a\n", DataPtr
));
608 DEBUG((EFI_D_ERROR
, "TPM2 ACPI HID TAG for patch not found!\n"));
609 return EFI_NOT_FOUND
;
613 Initialize and publish TPM items in ACPI table.
615 @retval EFI_SUCCESS The TCG ACPI table is published successfully.
616 @retval Others The TCG ACPI table is not published.
625 EFI_ACPI_TABLE_PROTOCOL
*AcpiTable
;
627 EFI_ACPI_DESCRIPTION_HEADER
*Table
;
629 UINT32
*PossibleIrqNumBuf
;
630 UINT32 PossibleIrqNumBufSize
;
631 BOOLEAN IsShortFormPkgLength
;
633 IsShortFormPkgLength
= FALSE
;
635 Status
= GetSectionFromFv (
642 ASSERT_EFI_ERROR (Status
);
645 // Update Table version before measuring it to PCR
647 Status
= UpdatePPVersion(Table
, (CHAR8
*)PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer
));
648 ASSERT_EFI_ERROR (Status
);
652 "Current physical presence interface version - %a\n",
653 (CHAR8
*) PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer
)
657 // Update TPM2 HID before measuring it to PCR
659 Status
= UpdateHID(Table
);
660 if (EFI_ERROR(Status
)) {
664 if (PcdGet32(PcdTpm2CurrentIrqNum
) != 0) {
666 // Patch _PRS interrupt resource only when TPM interrupt is supported
668 PossibleIrqNumBuf
= (UINT32
*)PcdGetPtr(PcdTpm2PossibleIrqNumBuf
);
669 PossibleIrqNumBufSize
= (UINT32
)PcdGetSize(PcdTpm2PossibleIrqNumBuf
);
671 if (PossibleIrqNumBufSize
<= MAX_PRS_INT_BUF_SIZE
&& (PossibleIrqNumBufSize
% sizeof(UINT32
)) == 0) {
672 Status
= UpdatePossibleResource(Table
, PossibleIrqNumBuf
, PossibleIrqNumBufSize
, &IsShortFormPkgLength
);
675 "UpdatePossibleResource status - %x. TPM2 service may not ready in OS.\n",
681 "PcdTpm2PossibleIrqNumBuf size %x is not correct. TPM2 service may not ready in OS.\n",
682 PossibleIrqNumBufSize
688 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
690 TpmMeasureAndLogData(
693 EV_POSTCODE_INFO_ACPI_DATA
,
700 ASSERT (Table
->OemTableId
== SIGNATURE_64 ('T', 'p', 'm', '2', 'T', 'a', 'b', 'l'));
701 CopyMem (Table
->OemId
, PcdGetPtr (PcdAcpiDefaultOemId
), sizeof (Table
->OemId
) );
702 mTcgNvs
= AssignOpRegion (Table
, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16
) sizeof (TCG_NVS
));
703 ASSERT (mTcgNvs
!= NULL
);
704 mTcgNvs
->TpmIrqNum
= PcdGet32(PcdTpm2CurrentIrqNum
);
705 mTcgNvs
->IsShortFormPkgLength
= IsShortFormPkgLength
;
708 // Publish the TPM ACPI table. Table is re-checksumed.
710 Status
= gBS
->LocateProtocol (&gEfiAcpiTableProtocolGuid
, NULL
, (VOID
**) &AcpiTable
);
711 ASSERT_EFI_ERROR (Status
);
714 Status
= AcpiTable
->InstallAcpiTable (
720 ASSERT_EFI_ERROR (Status
);
726 Publish TPM2 ACPI table
728 @retval EFI_SUCCESS The TPM2 ACPI table is published successfully.
729 @retval Others The TPM2 ACPI table is not published.
738 EFI_ACPI_TABLE_PROTOCOL
*AcpiTable
;
741 EFI_TPM2_ACPI_CONTROL_AREA
*ControlArea
;
742 TPM2_PTP_INTERFACE_TYPE InterfaceType
;
744 mTpm2AcpiTemplate
.Header
.Revision
= PcdGet8(PcdTpm2AcpiTableRev
);
745 DEBUG((DEBUG_INFO
, "Tpm2 ACPI table revision is %d\n", mTpm2AcpiTemplate
.Header
.Revision
));
748 // PlatformClass is only valid for version 4 and above
749 // BIT0~15: PlatformClass
750 // BIT16~31: Reserved
752 if (mTpm2AcpiTemplate
.Header
.Revision
>= EFI_TPM2_ACPI_TABLE_REVISION_4
) {
753 mTpm2AcpiTemplate
.Flags
= (mTpm2AcpiTemplate
.Flags
& 0xFFFF0000) | PcdGet8(PcdTpmPlatformClass
);
754 DEBUG((DEBUG_INFO
, "Tpm2 ACPI table PlatformClass is %d\n", (mTpm2AcpiTemplate
.Flags
& 0x0000FFFF)));
758 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
760 TpmMeasureAndLogData(
763 EV_POSTCODE_INFO_ACPI_DATA
,
766 sizeof(mTpm2AcpiTemplate
)
769 InterfaceType
= PcdGet8(PcdActiveTpmInterfaceType
);
770 switch (InterfaceType
) {
771 case Tpm2PtpInterfaceCrb
:
772 mTpm2AcpiTemplate
.StartMethod
= EFI_TPM2_ACPI_TABLE_START_METHOD_COMMAND_RESPONSE_BUFFER_INTERFACE
;
773 mTpm2AcpiTemplate
.AddressOfControlArea
= PcdGet64 (PcdTpmBaseAddress
) + 0x40;
774 ControlArea
= (EFI_TPM2_ACPI_CONTROL_AREA
*)(UINTN
)mTpm2AcpiTemplate
.AddressOfControlArea
;
775 ControlArea
->CommandSize
= 0xF80;
776 ControlArea
->ResponseSize
= 0xF80;
777 ControlArea
->Command
= PcdGet64 (PcdTpmBaseAddress
) + 0x80;
778 ControlArea
->Response
= PcdGet64 (PcdTpmBaseAddress
) + 0x80;
780 case Tpm2PtpInterfaceFifo
:
781 case Tpm2PtpInterfaceTis
:
784 DEBUG((EFI_D_ERROR
, "TPM2 InterfaceType get error! %d\n", InterfaceType
));
788 CopyMem (mTpm2AcpiTemplate
.Header
.OemId
, PcdGetPtr (PcdAcpiDefaultOemId
), sizeof (mTpm2AcpiTemplate
.Header
.OemId
));
789 OemTableId
= PcdGet64 (PcdAcpiDefaultOemTableId
);
790 CopyMem (&mTpm2AcpiTemplate
.Header
.OemTableId
, &OemTableId
, sizeof (UINT64
));
791 mTpm2AcpiTemplate
.Header
.OemRevision
= PcdGet32 (PcdAcpiDefaultOemRevision
);
792 mTpm2AcpiTemplate
.Header
.CreatorId
= PcdGet32 (PcdAcpiDefaultCreatorId
);
793 mTpm2AcpiTemplate
.Header
.CreatorRevision
= PcdGet32 (PcdAcpiDefaultCreatorRevision
);
796 // Construct ACPI table
798 Status
= gBS
->LocateProtocol (&gEfiAcpiTableProtocolGuid
, NULL
, (VOID
**) &AcpiTable
);
799 ASSERT_EFI_ERROR (Status
);
801 Status
= AcpiTable
->InstallAcpiTable (
804 sizeof(mTpm2AcpiTemplate
),
807 ASSERT_EFI_ERROR (Status
);
813 The driver's entry point.
815 It install callbacks for TPM physical presence and MemoryClear, and locate
816 SMM variable to be used in the callback function.
818 @param[in] ImageHandle The firmware allocated handle for the EFI image.
819 @param[in] SystemTable A pointer to the EFI System Table.
821 @retval EFI_SUCCESS The entry point is executed successfully.
822 @retval Others Some error occurs when executing this entry point.
828 IN EFI_HANDLE ImageHandle
,
829 IN EFI_SYSTEM_TABLE
*SystemTable
833 EFI_SMM_SW_DISPATCH2_PROTOCOL
*SwDispatch
;
834 EFI_SMM_SW_REGISTER_CONTEXT SwContext
;
837 if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid
), &gEfiTpmDeviceInstanceTpm20DtpmGuid
)){
838 DEBUG ((EFI_D_ERROR
, "No TPM2 DTPM instance required!\n"));
839 return EFI_UNSUPPORTED
;
842 Status
= PublishAcpiTable ();
843 ASSERT_EFI_ERROR (Status
);
846 // Get the Sw dispatch protocol and register SMI callback functions.
848 Status
= gSmst
->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid
, NULL
, (VOID
**)&SwDispatch
);
849 ASSERT_EFI_ERROR (Status
);
850 SwContext
.SwSmiInputValue
= (UINTN
) -1;
851 Status
= SwDispatch
->Register (SwDispatch
, PhysicalPresenceCallback
, &SwContext
, &SwHandle
);
852 ASSERT_EFI_ERROR (Status
);
853 if (EFI_ERROR (Status
)) {
856 mTcgNvs
->PhysicalPresence
.SoftwareSmi
= (UINT8
) SwContext
.SwSmiInputValue
;
858 SwContext
.SwSmiInputValue
= (UINTN
) -1;
859 Status
= SwDispatch
->Register (SwDispatch
, MemoryClearCallback
, &SwContext
, &SwHandle
);
860 ASSERT_EFI_ERROR (Status
);
861 if (EFI_ERROR (Status
)) {
864 mTcgNvs
->MemoryClear
.SoftwareSmi
= (UINT8
) SwContext
.SwSmiInputValue
;
867 // Locate SmmVariableProtocol.
869 Status
= gSmst
->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid
, NULL
, (VOID
**)&mSmmVariable
);
870 ASSERT_EFI_ERROR (Status
);
873 // Set TPM2 ACPI table
875 Status
= PublishTpm2 ();
876 ASSERT_EFI_ERROR (Status
);