2 This driver implements TPM 2.0 definition block in ACPI table and
3 populates registered SMI callback functions for Tcg2 physical presence
4 and MemoryClear to handle the requests for ACPI method. It needs to be
5 used together with Tcg2 MM drivers to exchange information on registered
6 SwSmiValue and allocated NVS region address.
8 Caution: This module requires additional review when modified.
9 This driver will have external input - variable and ACPINvs data in SMM mode.
10 This external input must be validated carefully to avoid security issue.
12 Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
13 Copyright (c) Microsoft Corporation.
14 SPDX-License-Identifier: BSD-2-Clause-Patent
20 #include <IndustryStandard/Tpm2Acpi.h>
22 #include <Guid/TpmInstance.h>
23 #include <Guid/TpmNvsMm.h>
24 #include <Guid/PiSmmCommunicationRegionTable.h>
26 #include <Protocol/AcpiTable.h>
27 #include <Protocol/Tcg2Protocol.h>
28 #include <Protocol/MmCommunication.h>
30 #include <Library/BaseLib.h>
31 #include <Library/BaseMemoryLib.h>
32 #include <Library/DxeServicesLib.h>
33 #include <Library/UefiBootServicesTableLib.h>
34 #include <Library/DebugLib.h>
35 #include <Library/PcdLib.h>
36 #include <Library/PrintLib.h>
37 #include <Library/TpmMeasurementLib.h>
38 #include <Library/Tpm2DeviceLib.h>
39 #include <Library/Tpm2CommandLib.h>
40 #include <Library/UefiLib.h>
41 #include <Library/MmUnblockMemoryLib.h>
44 // Physical Presence Interface Version supported by Platform
46 #define PHYSICAL_PRESENCE_VERSION_TAG "$PV"
47 #define PHYSICAL_PRESENCE_VERSION_SIZE 4
50 // PNP _HID for TPM2 device
52 #define TPM_HID_TAG "NNNN0000"
53 #define TPM_HID_PNP_SIZE 8
54 #define TPM_HID_ACPI_SIZE 9
56 #define TPM_PRS_RESL "RESL"
57 #define TPM_PRS_RESS "RESS"
58 #define TPM_PRS_RES_NAME_SIZE 4
60 // Minimum PRS resource template size
61 // 1 byte for BufferOp
62 // 1 byte for PkgLength
63 // 2 bytes for BufferSize
64 // 12 bytes for Memory32Fixed descriptor
65 // 5 bytes for Interrupt descriptor
66 // 2 bytes for END Tag
68 #define TPM_POS_RES_TEMPLATE_MIN_SIZE (1 + 1 + 2 + 12 + 5 + 2)
71 // Max Interrupt buffer size for PRS interrupt resource
72 // Now support 15 interrupts in maxmum
74 #define MAX_PRS_INT_BUF_SIZE (15*4)
79 EFI_ACPI_DESCRIPTION_HEADER Header
;
80 // Flags field is replaced in version 4 and above
81 // BIT0~15: PlatformClass This field is only valid for version 4 and above
84 UINT64 AddressOfControlArea
;
86 UINT8 PlatformSpecificParameters
[12]; // size up to 12
87 UINT32 Laml
; // Optional
88 UINT64 Lasa
; // Optional
89 } EFI_TPM2_ACPI_TABLE_V4
;
93 EFI_TPM2_ACPI_TABLE_V4 mTpm2AcpiTemplate
= {
95 EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE
,
96 sizeof (mTpm2AcpiTemplate
),
97 EFI_TPM2_ACPI_TABLE_REVISION
,
99 // Compiler initializes the remaining bytes to 0
100 // These fields should be filled in in production
103 0, // BIT0~15: PlatformClass
104 // BIT16~31: Reserved
106 EFI_TPM2_ACPI_TABLE_START_METHOD_TIS
, // StartMethod
112 Find the operation region in TCG ACPI table by given Name and Size,
113 and initialize it if the region is found.
115 @param[in, out] Table The TPM item in ACPI table.
116 @param[in] Name The name string to find in TPM table.
117 @param[in] Size The size of the region to find.
119 @return The allocated address for the found region.
124 EFI_ACPI_DESCRIPTION_HEADER
*Table
,
130 AML_OP_REGION_32_8
*OpRegion
;
131 EFI_PHYSICAL_ADDRESS MemoryAddress
;
133 MemoryAddress
= SIZE_4GB
- 1;
136 // Patch some pointers for the ASL code before loading the SSDT.
138 for (OpRegion
= (AML_OP_REGION_32_8
*)(Table
+ 1);
139 OpRegion
<= (AML_OP_REGION_32_8
*)((UINT8
*)Table
+ Table
->Length
);
140 OpRegion
= (AML_OP_REGION_32_8
*)((UINT8
*)OpRegion
+ 1))
142 if ((OpRegion
->OpRegionOp
== AML_EXT_REGION_OP
) &&
143 (OpRegion
->NameString
== Name
) &&
144 (OpRegion
->DWordPrefix
== AML_DWORD_PREFIX
) &&
145 (OpRegion
->BytePrefix
== AML_BYTE_PREFIX
))
147 Status
= gBS
->AllocatePages (AllocateMaxAddress
, EfiACPIMemoryNVS
, EFI_SIZE_TO_PAGES (Size
), &MemoryAddress
);
148 ASSERT_EFI_ERROR (Status
);
149 ZeroMem ((VOID
*)(UINTN
)MemoryAddress
, Size
);
150 OpRegion
->RegionOffset
= (UINT32
)(UINTN
)MemoryAddress
;
151 OpRegion
->RegionLen
= (UINT8
)Size
;
152 // Request to unblock this region from MM core
153 Status
= MmUnblockMemoryRequest (MemoryAddress
, EFI_SIZE_TO_PAGES (Size
));
154 if ((Status
!= EFI_UNSUPPORTED
) && EFI_ERROR (Status
)) {
155 ASSERT_EFI_ERROR (Status
);
162 return (VOID
*)(UINTN
)MemoryAddress
;
166 Locate the MM communication buffer and protocol, then use it to exchange information with
167 Tcg2StandaloneMmm on NVS address and SMI value.
169 @param[in, out] TcgNvs The NVS subject to send to MM environment.
171 @return The status for locating MM common buffer, communicate to MM, etc.
176 ExchangeCommonBuffer (
177 IN OUT TCG_NVS
*TcgNvs
181 EFI_MM_COMMUNICATION_PROTOCOL
*MmCommunication
;
182 EDKII_PI_SMM_COMMUNICATION_REGION_TABLE
*PiSmmCommunicationRegionTable
;
183 EFI_MEMORY_DESCRIPTOR
*MmCommMemRegion
;
184 EFI_MM_COMMUNICATE_HEADER
*CommHeader
;
185 TPM_NVS_MM_COMM_BUFFER
*CommBuffer
;
186 UINTN CommBufferSize
;
189 // Step 0: Sanity check for input argument
190 if (TcgNvs
== NULL
) {
191 DEBUG ((DEBUG_ERROR
, "%a - Input argument is NULL!\n", __FUNCTION__
));
192 return EFI_INVALID_PARAMETER
;
195 // Step 1: Grab the common buffer header
196 Status
= EfiGetSystemConfigurationTable (&gEdkiiPiSmmCommunicationRegionTableGuid
, (VOID
**)&PiSmmCommunicationRegionTable
);
197 if (EFI_ERROR (Status
)) {
198 DEBUG ((DEBUG_ERROR
, "%a - Failed to locate SMM communciation common buffer - %r!\n", __FUNCTION__
, Status
));
202 // Step 2: Grab one that is large enough to hold TPM_NVS_MM_COMM_BUFFER, the IPL one should be sufficient
204 MmCommMemRegion
= (EFI_MEMORY_DESCRIPTOR
*)(PiSmmCommunicationRegionTable
+ 1);
205 for (Index
= 0; Index
< PiSmmCommunicationRegionTable
->NumberOfEntries
; Index
++) {
206 if (MmCommMemRegion
->Type
== EfiConventionalMemory
) {
207 CommBufferSize
= EFI_PAGES_TO_SIZE ((UINTN
)MmCommMemRegion
->NumberOfPages
);
208 if (CommBufferSize
>= (sizeof (TPM_NVS_MM_COMM_BUFFER
) + OFFSET_OF (EFI_MM_COMMUNICATE_HEADER
, Data
))) {
213 MmCommMemRegion
= (EFI_MEMORY_DESCRIPTOR
*)((UINT8
*)MmCommMemRegion
+ PiSmmCommunicationRegionTable
->DescriptorSize
);
216 if (Index
>= PiSmmCommunicationRegionTable
->NumberOfEntries
) {
217 // Could not find one that meets our goal...
218 DEBUG ((DEBUG_ERROR
, "%a - Could not find a common buffer that is big enough for NVS!\n", __FUNCTION__
));
219 return EFI_OUT_OF_RESOURCES
;
222 // Step 3: Start to populate contents
223 // Step 3.1: MM Communication common header
224 CommHeader
= (EFI_MM_COMMUNICATE_HEADER
*)(UINTN
)MmCommMemRegion
->PhysicalStart
;
225 CommBufferSize
= sizeof (TPM_NVS_MM_COMM_BUFFER
) + OFFSET_OF (EFI_MM_COMMUNICATE_HEADER
, Data
);
226 ZeroMem (CommHeader
, CommBufferSize
);
227 CopyGuid (&CommHeader
->HeaderGuid
, &gTpmNvsMmGuid
);
228 CommHeader
->MessageLength
= sizeof (TPM_NVS_MM_COMM_BUFFER
);
230 // Step 3.2: TPM_NVS_MM_COMM_BUFFER content per our needs
231 CommBuffer
= (TPM_NVS_MM_COMM_BUFFER
*)(CommHeader
->Data
);
232 CommBuffer
->Function
= TpmNvsMmExchangeInfo
;
233 CommBuffer
->TargetAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)TcgNvs
;
235 // Step 4: Locate the protocol and signal Mmi.
236 Status
= gBS
->LocateProtocol (&gEfiMmCommunicationProtocolGuid
, NULL
, (VOID
**)&MmCommunication
);
237 if (!EFI_ERROR (Status
)) {
238 Status
= MmCommunication
->Communicate (MmCommunication
, CommHeader
, &CommBufferSize
);
239 DEBUG ((DEBUG_INFO
, "%a - Communicate() = %r\n", __FUNCTION__
, Status
));
241 DEBUG ((DEBUG_ERROR
, "%a - Failed to locate MmCommunication protocol - %r\n", __FUNCTION__
, Status
));
245 // Step 5: If everything goes well, populate the channel number
246 if (!EFI_ERROR (CommBuffer
->ReturnStatus
)) {
247 // Need to demote to UINT8 according to SMI value definition
248 TcgNvs
->PhysicalPresence
.SoftwareSmi
= (UINT8
)CommBuffer
->RegisteredPpSwiValue
;
249 TcgNvs
->MemoryClear
.SoftwareSmi
= (UINT8
)CommBuffer
->RegisteredMcSwiValue
;
252 "%a Communication returned software SMI value. PP: 0x%x; MC: 0x%x.\n",
254 TcgNvs
->PhysicalPresence
.SoftwareSmi
,
255 TcgNvs
->MemoryClear
.SoftwareSmi
259 return (EFI_STATUS
)CommBuffer
->ReturnStatus
;
263 Patch version string of Physical Presence interface supported by platform. The initial string tag in TPM
266 @param[in, out] Table The TPM item in ACPI table.
267 @param[in] PPVer Version string of Physical Presence interface supported by platform.
269 @return The allocated address for the found region.
274 EFI_ACPI_DESCRIPTION_HEADER
*Table
,
282 // Patch some pointers for the ASL code before loading the SSDT.
284 for (DataPtr
= (UINT8
*)(Table
+ 1);
285 DataPtr
<= (UINT8
*)((UINT8
*)Table
+ Table
->Length
- PHYSICAL_PRESENCE_VERSION_SIZE
);
288 if (AsciiStrCmp ((CHAR8
*)DataPtr
, PHYSICAL_PRESENCE_VERSION_TAG
) == 0) {
289 Status
= AsciiStrCpyS ((CHAR8
*)DataPtr
, PHYSICAL_PRESENCE_VERSION_SIZE
, PPVer
);
290 DEBUG ((DEBUG_INFO
, "TPM2 Physical Presence Interface Version update status 0x%x\n", Status
));
295 return EFI_NOT_FOUND
;
299 Patch interrupt resources returned by TPM _PRS. ResourceTemplate to patch is determined by input
300 interrupt buffer size. BufferSize, PkgLength and interrupt descriptor in ByteList need to be patched
302 @param[in, out] Table The TPM item in ACPI table.
303 @param[in] IrqBuffer Input new IRQ buffer.
304 @param[in] IrqBuffserSize Input new IRQ buffer size.
305 @param[out] IsShortFormPkgLength If _PRS returns Short length Package(ACPI spec 20.2.4).
307 @return patch status.
311 UpdatePossibleResource (
312 IN OUT EFI_ACPI_DESCRIPTION_HEADER
*Table
,
313 IN UINT32
*IrqBuffer
,
314 IN UINT32 IrqBuffserSize
,
315 OUT BOOLEAN
*IsShortFormPkgLength
321 UINT32 OrignalPkgLength
;
324 OrignalPkgLength
= 0;
329 // 6.4.3 Extend Interrupt Descriptor.
330 // 19.3.3 ASL Resource Template
331 // 20 AML specification
332 // to patch TPM ACPI object _PRS returned ResourceTemplate() containing 2 resource descriptors and an auto appended End Tag
334 // AML data is organized by following rule.
335 // Code need to patch BufferSize and PkgLength and interrupt descriptor in ByteList
337 // ============= Buffer ====================
338 // DefBuffer := BufferOp PkgLength BufferSize ByteList
341 // ==============PkgLength==================
342 // PkgLength := PkgLeadByte |
343 // <PkgLeadByte ByteData> |
344 // <PkgLeadByte ByteData ByteData> |
345 // <PkgLeadByte ByteData ByteData ByteData>
347 // PkgLeadByte := <bit 7-6: ByteData count that follows (0-3)>
348 // <bit 5-4: Only used if PkgLength <= 63 >
349 // <bit 3-0: Least significant package length nybble>
351 // ==============BufferSize==================
352 // BufferSize := Integer
353 // Integer := ByteConst|WordConst|DwordConst....
355 // ByteConst := BytePrefix ByteData
357 // ==============ByteList===================
358 // ByteList := ByteData ByteList
360 // =========================================
363 // 1. Check TPM_PRS_RESS with PkgLength <=63 can hold the input interrupt number buffer for patching
365 for (DataPtr
= (UINT8
*)(Table
+ 1);
366 DataPtr
< (UINT8
*)((UINT8
*)Table
+ Table
->Length
- (TPM_PRS_RES_NAME_SIZE
+ TPM_POS_RES_TEMPLATE_MIN_SIZE
));
369 if (CompareMem (DataPtr
, TPM_PRS_RESS
, TPM_PRS_RES_NAME_SIZE
) == 0) {
371 // Jump over object name & BufferOp
373 DataPtr
+= TPM_PRS_RES_NAME_SIZE
+ 1;
375 if ((*DataPtr
& (BIT7
|BIT6
)) == 0) {
376 OrignalPkgLength
= (UINT32
)*DataPtr
;
377 DataEndPtr
= DataPtr
+ OrignalPkgLength
;
380 // Jump over PkgLength = PkgLeadByte only
385 // Jump over BufferSize
387 if (*(DataPtr
+ 1) == AML_BYTE_PREFIX
) {
389 } else if (*(DataPtr
+ 1) == AML_WORD_PREFIX
) {
391 } else if (*(DataPtr
+ 1) == AML_DWORD_PREFIX
) {
395 return EFI_UNSUPPORTED
;
399 return EFI_UNSUPPORTED
;
403 // Include Memory32Fixed Descriptor (12 Bytes) + Interrupt Descriptor header(5 Bytes) + End Tag(2 Bytes)
405 NewPkgLength
+= 19 + IrqBuffserSize
;
406 if (NewPkgLength
> 63) {
410 if (NewPkgLength
> OrignalPkgLength
) {
412 return EFI_INVALID_PARAMETER
;
416 // 1.1 Patch PkgLength
418 *DataPtr
= (UINT8
)NewPkgLength
;
421 // 1.2 Patch BufferSize = sizeof(Memory32Fixed Descriptor + Interrupt Descriptor + End Tag).
422 // It is Little endian. So only patch lowest byte of BufferSize due to current interrupt number limit.
424 *(DataPtr
+ 2) = (UINT8
)(IrqBuffserSize
+ 19);
427 // Notify _PRS to report short formed ResourceTemplate
429 *IsShortFormPkgLength
= TRUE
;
436 // 2. Use TPM_PRS_RESL with PkgLength > 63 to hold longer input interrupt number buffer for patching
438 if (NewPkgLength
> 63) {
440 OrignalPkgLength
= 0;
441 for (DataPtr
= (UINT8
*)(Table
+ 1);
442 DataPtr
< (UINT8
*)((UINT8
*)Table
+ Table
->Length
- (TPM_PRS_RES_NAME_SIZE
+ TPM_POS_RES_TEMPLATE_MIN_SIZE
));
445 if (CompareMem (DataPtr
, TPM_PRS_RESL
, TPM_PRS_RES_NAME_SIZE
) == 0) {
447 // Jump over object name & BufferOp
449 DataPtr
+= TPM_PRS_RES_NAME_SIZE
+ 1;
451 if ((*DataPtr
& (BIT7
|BIT6
)) != 0) {
452 OrignalPkgLength
= (UINT32
)(*(DataPtr
+ 1) << 4) + (*DataPtr
& 0x0F);
453 DataEndPtr
= DataPtr
+ OrignalPkgLength
;
455 // Jump over PkgLength = PkgLeadByte + ByteData length
457 NewPkgLength
+= 1 + ((*DataPtr
& (BIT7
|BIT6
)) >> 6);
460 // Jump over BufferSize
462 if (*(DataPtr
+ NewPkgLength
) == AML_BYTE_PREFIX
) {
464 } else if (*(DataPtr
+ NewPkgLength
) == AML_WORD_PREFIX
) {
466 } else if (*(DataPtr
+ NewPkgLength
) == AML_DWORD_PREFIX
) {
470 return EFI_UNSUPPORTED
;
474 return EFI_UNSUPPORTED
;
478 // Include Memory32Fixed Descriptor (12 Bytes) + Interrupt Descriptor header(5 Bytes) + End Tag(2 Bytes)
480 NewPkgLength
+= 19 + IrqBuffserSize
;
482 if (NewPkgLength
> OrignalPkgLength
) {
484 return EFI_INVALID_PARAMETER
;
488 // 2.1 Patch PkgLength. Only patch PkgLeadByte and first ByteData
490 *DataPtr
= (UINT8
)((*DataPtr
) & 0xF0) | (NewPkgLength
& 0x0F);
491 *(DataPtr
+ 1) = (UINT8
)((NewPkgLength
& 0xFF0) >> 4);
494 // 2.2 Patch BufferSize = sizeof(Memory32Fixed Descriptor + Interrupt Descriptor + End Tag).
495 // It is Little endian. Only patch lowest byte of BufferSize due to current interrupt number limit.
497 *(DataPtr
+ 2 + ((*DataPtr
& (BIT7
|BIT6
)) >> 6)) = (UINT8
)(IrqBuffserSize
+ 19);
500 // Notify _PRS to report long formed ResourceTemplate
502 *IsShortFormPkgLength
= FALSE
;
508 if (DataPtr
>= (UINT8
*)((UINT8
*)Table
+ Table
->Length
- (TPM_PRS_RES_NAME_SIZE
+ TPM_POS_RES_TEMPLATE_MIN_SIZE
))) {
509 return EFI_NOT_FOUND
;
513 // 3. Move DataPtr to Interrupt descriptor header and patch interrupt descriptor.
514 // 5 bytes for interrupt descriptor header, 2 bytes for End Tag
516 DataPtr
+= NewPkgLength
- (5 + IrqBuffserSize
+ 2);
518 // 3.1 Patch Length bit[7:0] of Interrupt descriptor patch interrupt descriptor
520 *(DataPtr
+ 1) = (UINT8
)(2 + IrqBuffserSize
);
522 // 3.2 Patch Interrupt Table Length
524 *(DataPtr
+ 4) = (UINT8
)(IrqBuffserSize
/ sizeof (UINT32
));
526 // 3.3 Copy patched InterruptNumBuffer
528 CopyMem (DataPtr
+ 5, IrqBuffer
, IrqBuffserSize
);
531 // 4. Jump over Interrupt descriptor and Patch END Tag, set Checksum field to 0
533 DataPtr
+= 5 + IrqBuffserSize
;
534 *DataPtr
= ACPI_END_TAG_DESCRIPTOR
;
538 // 5. Jump over new ResourceTemplate. Stuff rest bytes to NOOP
541 if (DataPtr
< DataEndPtr
) {
542 SetMem (DataPtr
, (UINTN
)DataEndPtr
- (UINTN
)DataPtr
, AML_NOOP_OP
);
549 Patch TPM2 device HID string. The initial string tag in TPM2 ACPI table is "NNN0000".
551 @param[in, out] Table The TPM2 SSDT ACPI table.
553 @return HID Update status.
558 EFI_ACPI_DESCRIPTION_HEADER
*Table
563 CHAR8 Hid
[TPM_HID_ACPI_SIZE
];
564 UINT32 ManufacturerID
;
565 UINT32 FirmwareVersion1
;
566 UINT32 FirmwareVersion2
;
572 // Initialize HID with Default PNP string
574 ZeroMem (Hid
, TPM_HID_ACPI_SIZE
);
577 // Get Manufacturer ID
579 Status
= Tpm2GetCapabilityManufactureID (&ManufacturerID
);
580 if (!EFI_ERROR (Status
)) {
581 DEBUG ((DEBUG_INFO
, "TPM_PT_MANUFACTURER 0x%08x\n", ManufacturerID
));
583 // ManufacturerID defined in TCG Vendor ID Registry
584 // may tailed with 0x00 or 0x20
586 if (((ManufacturerID
>> 24) == 0x00) || ((ManufacturerID
>> 24) == 0x20)) {
588 // HID containing PNP ID "NNN####"
589 // NNN is uppercase letter for Vendor ID specified by manufacturer
591 CopyMem (Hid
, &ManufacturerID
, 3);
594 // HID containing ACP ID "NNNN####"
595 // NNNN is uppercase letter for Vendor ID specified by manufacturer
597 CopyMem (Hid
, &ManufacturerID
, 4);
601 DEBUG ((DEBUG_ERROR
, "Get TPM_PT_MANUFACTURER failed %x!\n", Status
));
606 Status
= Tpm2GetCapabilityFirmwareVersion (&FirmwareVersion1
, &FirmwareVersion2
);
607 if (!EFI_ERROR (Status
)) {
608 DEBUG ((DEBUG_INFO
, "TPM_PT_FIRMWARE_VERSION_1 0x%x\n", FirmwareVersion1
));
609 DEBUG ((DEBUG_INFO
, "TPM_PT_FIRMWARE_VERSION_2 0x%x\n", FirmwareVersion2
));
611 // #### is Firmware Version 1
614 AsciiSPrint (Hid
+ 3, TPM_HID_PNP_SIZE
- 3, "%02d%02d", ((FirmwareVersion1
& 0xFFFF0000) >> 16), (FirmwareVersion1
& 0x0000FFFF));
616 AsciiSPrint (Hid
+ 4, TPM_HID_ACPI_SIZE
- 4, "%02d%02d", ((FirmwareVersion1
& 0xFFFF0000) >> 16), (FirmwareVersion1
& 0x0000FFFF));
619 DEBUG ((DEBUG_ERROR
, "Get TPM_PT_FIRMWARE_VERSION_X failed %x!\n", Status
));
625 // Patch HID in ASL code before loading the SSDT.
627 for (DataPtr
= (UINT8
*)(Table
+ 1);
628 DataPtr
<= (UINT8
*)((UINT8
*)Table
+ Table
->Length
- TPM_HID_PNP_SIZE
);
631 if (AsciiStrCmp ((CHAR8
*)DataPtr
, TPM_HID_TAG
) == 0) {
633 CopyMem (DataPtr
, Hid
, TPM_HID_PNP_SIZE
);
635 // if HID is PNP ID, patch the last byte in HID TAG to Noop
637 *(DataPtr
+ TPM_HID_PNP_SIZE
) = AML_NOOP_OP
;
639 CopyMem (DataPtr
, Hid
, TPM_HID_ACPI_SIZE
);
642 DEBUG ((DEBUG_INFO
, "TPM2 ACPI _HID is patched to %a\n", DataPtr
));
648 DEBUG ((DEBUG_ERROR
, "TPM2 ACPI HID TAG for patch not found!\n"));
649 return EFI_NOT_FOUND
;
653 Initialize and publish TPM items in ACPI table.
655 @retval EFI_SUCCESS The TCG ACPI table is published successfully.
656 @retval Others The TCG ACPI table is not published.
665 EFI_ACPI_TABLE_PROTOCOL
*AcpiTable
;
667 EFI_ACPI_DESCRIPTION_HEADER
*Table
;
669 UINT32
*PossibleIrqNumBuf
;
670 UINT32 PossibleIrqNumBufSize
;
671 BOOLEAN IsShortFormPkgLength
;
673 IsShortFormPkgLength
= FALSE
;
675 Status
= GetSectionFromFv (
682 ASSERT_EFI_ERROR (Status
);
685 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA.
686 // The measurement has to be done before any update.
687 // Otherwise, the PCR record would be different after TPM FW update
688 // or the PCD configuration change.
690 TpmMeasureAndLogData (
693 EV_POSTCODE_INFO_ACPI_DATA
,
700 // Update Table version before measuring it to PCR
702 Status
= UpdatePPVersion (Table
, (CHAR8
*)PcdGetPtr (PcdTcgPhysicalPresenceInterfaceVer
));
703 ASSERT_EFI_ERROR (Status
);
707 "Current physical presence interface version - %a\n",
708 (CHAR8
*)PcdGetPtr (PcdTcgPhysicalPresenceInterfaceVer
)
712 // Update TPM2 HID after measuring it to PCR
714 Status
= UpdateHID (Table
);
715 if (EFI_ERROR (Status
)) {
719 if (PcdGet32 (PcdTpm2CurrentIrqNum
) != 0) {
721 // Patch _PRS interrupt resource only when TPM interrupt is supported
723 PossibleIrqNumBuf
= (UINT32
*)PcdGetPtr (PcdTpm2PossibleIrqNumBuf
);
724 PossibleIrqNumBufSize
= (UINT32
)PcdGetSize (PcdTpm2PossibleIrqNumBuf
);
726 if ((PossibleIrqNumBufSize
<= MAX_PRS_INT_BUF_SIZE
) && ((PossibleIrqNumBufSize
% sizeof (UINT32
)) == 0)) {
727 Status
= UpdatePossibleResource (Table
, PossibleIrqNumBuf
, PossibleIrqNumBufSize
, &IsShortFormPkgLength
);
730 "UpdatePossibleResource status - %x. TPM2 service may not ready in OS.\n",
736 "PcdTpm2PossibleIrqNumBuf size %x is not correct. TPM2 service may not ready in OS.\n",
737 PossibleIrqNumBufSize
742 ASSERT (Table
->OemTableId
== SIGNATURE_64 ('T', 'p', 'm', '2', 'T', 'a', 'b', 'l'));
743 CopyMem (Table
->OemId
, PcdGetPtr (PcdAcpiDefaultOemId
), sizeof (Table
->OemId
));
744 mTcgNvs
= AssignOpRegion (Table
, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16
)sizeof (TCG_NVS
));
745 ASSERT (mTcgNvs
!= NULL
);
746 mTcgNvs
->TpmIrqNum
= PcdGet32 (PcdTpm2CurrentIrqNum
);
747 mTcgNvs
->IsShortFormPkgLength
= IsShortFormPkgLength
;
749 Status
= ExchangeCommonBuffer (mTcgNvs
);
752 // Publish the TPM ACPI table. Table is re-checksummed.
754 Status
= gBS
->LocateProtocol (&gEfiAcpiTableProtocolGuid
, NULL
, (VOID
**)&AcpiTable
);
755 ASSERT_EFI_ERROR (Status
);
758 Status
= AcpiTable
->InstallAcpiTable (
764 ASSERT_EFI_ERROR (Status
);
770 Publish TPM2 ACPI table
772 @retval EFI_SUCCESS The TPM2 ACPI table is published successfully.
773 @retval Others The TPM2 ACPI table is not published.
782 EFI_ACPI_TABLE_PROTOCOL
*AcpiTable
;
785 EFI_TPM2_ACPI_CONTROL_AREA
*ControlArea
;
786 TPM2_PTP_INTERFACE_TYPE InterfaceType
;
789 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA.
790 // The measurement has to be done before any update.
791 // Otherwise, the PCR record would be different after event log update
792 // or the PCD configuration change.
794 TpmMeasureAndLogData (
797 EV_POSTCODE_INFO_ACPI_DATA
,
800 mTpm2AcpiTemplate
.Header
.Length
803 mTpm2AcpiTemplate
.Header
.Revision
= PcdGet8 (PcdTpm2AcpiTableRev
);
804 DEBUG ((DEBUG_INFO
, "Tpm2 ACPI table revision is %d\n", mTpm2AcpiTemplate
.Header
.Revision
));
807 // PlatformClass is only valid for version 4 and above
808 // BIT0~15: PlatformClass
809 // BIT16~31: Reserved
811 if (mTpm2AcpiTemplate
.Header
.Revision
>= EFI_TPM2_ACPI_TABLE_REVISION_4
) {
812 mTpm2AcpiTemplate
.Flags
= (mTpm2AcpiTemplate
.Flags
& 0xFFFF0000) | PcdGet8 (PcdTpmPlatformClass
);
813 DEBUG ((DEBUG_INFO
, "Tpm2 ACPI table PlatformClass is %d\n", (mTpm2AcpiTemplate
.Flags
& 0x0000FFFF)));
816 mTpm2AcpiTemplate
.Laml
= PcdGet32 (PcdTpm2AcpiTableLaml
);
817 mTpm2AcpiTemplate
.Lasa
= PcdGet64 (PcdTpm2AcpiTableLasa
);
818 if ((mTpm2AcpiTemplate
.Header
.Revision
< EFI_TPM2_ACPI_TABLE_REVISION_4
) ||
819 (mTpm2AcpiTemplate
.Laml
== 0) || (mTpm2AcpiTemplate
.Lasa
== 0))
822 // If version is smaller than 4 or Laml/Lasa is not valid, rollback to original Length.
824 mTpm2AcpiTemplate
.Header
.Length
= sizeof (EFI_TPM2_ACPI_TABLE
);
827 InterfaceType
= PcdGet8 (PcdActiveTpmInterfaceType
);
828 switch (InterfaceType
) {
829 case Tpm2PtpInterfaceCrb
:
830 mTpm2AcpiTemplate
.StartMethod
= EFI_TPM2_ACPI_TABLE_START_METHOD_COMMAND_RESPONSE_BUFFER_INTERFACE
;
831 mTpm2AcpiTemplate
.AddressOfControlArea
= PcdGet64 (PcdTpmBaseAddress
) + 0x40;
832 ControlArea
= (EFI_TPM2_ACPI_CONTROL_AREA
*)(UINTN
)mTpm2AcpiTemplate
.AddressOfControlArea
;
833 ControlArea
->CommandSize
= 0xF80;
834 ControlArea
->ResponseSize
= 0xF80;
835 ControlArea
->Command
= PcdGet64 (PcdTpmBaseAddress
) + 0x80;
836 ControlArea
->Response
= PcdGet64 (PcdTpmBaseAddress
) + 0x80;
838 case Tpm2PtpInterfaceFifo
:
839 case Tpm2PtpInterfaceTis
:
842 DEBUG ((DEBUG_ERROR
, "TPM2 InterfaceType get error! %d\n", InterfaceType
));
846 CopyMem (mTpm2AcpiTemplate
.Header
.OemId
, PcdGetPtr (PcdAcpiDefaultOemId
), sizeof (mTpm2AcpiTemplate
.Header
.OemId
));
847 OemTableId
= PcdGet64 (PcdAcpiDefaultOemTableId
);
848 CopyMem (&mTpm2AcpiTemplate
.Header
.OemTableId
, &OemTableId
, sizeof (UINT64
));
849 mTpm2AcpiTemplate
.Header
.OemRevision
= PcdGet32 (PcdAcpiDefaultOemRevision
);
850 mTpm2AcpiTemplate
.Header
.CreatorId
= PcdGet32 (PcdAcpiDefaultCreatorId
);
851 mTpm2AcpiTemplate
.Header
.CreatorRevision
= PcdGet32 (PcdAcpiDefaultCreatorRevision
);
854 // Construct ACPI table
856 Status
= gBS
->LocateProtocol (&gEfiAcpiTableProtocolGuid
, NULL
, (VOID
**)&AcpiTable
);
857 ASSERT_EFI_ERROR (Status
);
859 Status
= AcpiTable
->InstallAcpiTable (
862 mTpm2AcpiTemplate
.Header
.Length
,
865 ASSERT_EFI_ERROR (Status
);
871 The driver's entry point.
873 It patches and installs ACPI tables used for handling TPM physical presence
874 and Memory Clear requests through ACPI method.
876 @param[in] ImageHandle The firmware allocated handle for the EFI image.
877 @param[in] SystemTable A pointer to the EFI System Table.
879 @retval EFI_SUCCESS The entry point is executed successfully.
880 @retval Others Some error occurs when executing this entry point.
886 IN EFI_HANDLE ImageHandle
,
887 IN EFI_SYSTEM_TABLE
*SystemTable
892 if (!CompareGuid (PcdGetPtr (PcdTpmInstanceGuid
), &gEfiTpmDeviceInstanceTpm20DtpmGuid
)) {
893 DEBUG ((DEBUG_ERROR
, "No TPM2 DTPM instance required!\n"));
894 return EFI_UNSUPPORTED
;
897 Status
= PublishAcpiTable ();
898 ASSERT_EFI_ERROR (Status
);
901 // Set TPM2 ACPI table
903 Status
= PublishTpm2 ();
904 ASSERT_EFI_ERROR (Status
);