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>
43 // Physical Presence Interface Version supported by Platform
45 #define PHYSICAL_PRESENCE_VERSION_TAG "$PV"
46 #define PHYSICAL_PRESENCE_VERSION_SIZE 4
49 // PNP _HID for TPM2 device
51 #define TPM_HID_TAG "NNNN0000"
52 #define TPM_HID_PNP_SIZE 8
53 #define TPM_HID_ACPI_SIZE 9
55 #define TPM_PRS_RESL "RESL"
56 #define TPM_PRS_RESS "RESS"
57 #define TPM_PRS_RES_NAME_SIZE 4
59 // Minimum PRS resource template size
60 // 1 byte for BufferOp
61 // 1 byte for PkgLength
62 // 2 bytes for BufferSize
63 // 12 bytes for Memory32Fixed descriptor
64 // 5 bytes for Interrupt descriptor
65 // 2 bytes for END Tag
67 #define TPM_POS_RES_TEMPLATE_MIN_SIZE (1 + 1 + 2 + 12 + 5 + 2)
70 // Max Interrupt buffer size for PRS interrupt resource
71 // Now support 15 interrupts in maxmum
73 #define MAX_PRS_INT_BUF_SIZE (15*4)
78 EFI_ACPI_DESCRIPTION_HEADER Header
;
79 // Flags field is replaced in version 4 and above
80 // BIT0~15: PlatformClass This field is only valid for version 4 and above
83 UINT64 AddressOfControlArea
;
85 UINT8 PlatformSpecificParameters
[12]; // size up to 12
86 UINT32 Laml
; // Optional
87 UINT64 Lasa
; // Optional
88 } EFI_TPM2_ACPI_TABLE_V4
;
92 EFI_TPM2_ACPI_TABLE_V4 mTpm2AcpiTemplate
= {
94 EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE
,
95 sizeof (mTpm2AcpiTemplate
),
96 EFI_TPM2_ACPI_TABLE_REVISION
,
98 // Compiler initializes the remaining bytes to 0
99 // These fields should be filled in in production
102 0, // BIT0~15: PlatformClass
103 // BIT16~31: Reserved
105 EFI_TPM2_ACPI_TABLE_START_METHOD_TIS
, // StartMethod
111 Find the operation region in TCG ACPI table by given Name and Size,
112 and initialize it if the region is found.
114 @param[in, out] Table The TPM item in ACPI table.
115 @param[in] Name The name string to find in TPM table.
116 @param[in] Size The size of the region to find.
118 @return The allocated address for the found region.
123 EFI_ACPI_DESCRIPTION_HEADER
*Table
,
129 AML_OP_REGION_32_8
*OpRegion
;
130 EFI_PHYSICAL_ADDRESS MemoryAddress
;
132 MemoryAddress
= SIZE_4GB
- 1;
135 // Patch some pointers for the ASL code before loading the SSDT.
137 for (OpRegion
= (AML_OP_REGION_32_8
*) (Table
+ 1);
138 OpRegion
<= (AML_OP_REGION_32_8
*) ((UINT8
*) Table
+ Table
->Length
);
139 OpRegion
= (AML_OP_REGION_32_8
*) ((UINT8
*) OpRegion
+ 1)) {
140 if ((OpRegion
->OpRegionOp
== AML_EXT_REGION_OP
) &&
141 (OpRegion
->NameString
== Name
) &&
142 (OpRegion
->DWordPrefix
== AML_DWORD_PREFIX
) &&
143 (OpRegion
->BytePrefix
== AML_BYTE_PREFIX
)) {
145 Status
= gBS
->AllocatePages(AllocateMaxAddress
, EfiACPIMemoryNVS
, EFI_SIZE_TO_PAGES (Size
), &MemoryAddress
);
146 ASSERT_EFI_ERROR (Status
);
147 ZeroMem ((VOID
*)(UINTN
)MemoryAddress
, Size
);
148 OpRegion
->RegionOffset
= (UINT32
) (UINTN
) MemoryAddress
;
149 OpRegion
->RegionLen
= (UINT8
) Size
;
154 return (VOID
*) (UINTN
) MemoryAddress
;
158 Locate the MM communication buffer and protocol, then use it to exchange information with
159 Tcg2StandaloneMmm on NVS address and SMI value.
161 @param[in, out] TcgNvs The NVS subject to send to MM environment.
163 @return The status for locating MM common buffer, communicate to MM, etc.
168 ExchangeCommonBuffer (
169 IN OUT TCG_NVS
*TcgNvs
173 EFI_MM_COMMUNICATION_PROTOCOL
*MmCommunication
;
174 EDKII_PI_SMM_COMMUNICATION_REGION_TABLE
*PiSmmCommunicationRegionTable
;
175 EFI_MEMORY_DESCRIPTOR
*MmCommMemRegion
;
176 EFI_MM_COMMUNICATE_HEADER
*CommHeader
;
177 TPM_NVS_MM_COMM_BUFFER
*CommBuffer
;
178 UINTN CommBufferSize
;
181 // Step 0: Sanity check for input argument
182 if (TcgNvs
== NULL
) {
183 DEBUG ((DEBUG_ERROR
, "%a - Input argument is NULL!\n", __FUNCTION__
));
184 return EFI_INVALID_PARAMETER
;
187 // Step 1: Grab the common buffer header
188 Status
= EfiGetSystemConfigurationTable (&gEdkiiPiSmmCommunicationRegionTableGuid
, (VOID
**) &PiSmmCommunicationRegionTable
);
189 if (EFI_ERROR (Status
)) {
190 DEBUG ((DEBUG_ERROR
, "%a - Failed to locate SMM communciation common buffer - %r!\n", __FUNCTION__
, Status
));
194 // Step 2: Grab one that is large enough to hold TPM_NVS_MM_COMM_BUFFER, the IPL one should be sufficient
196 MmCommMemRegion
= (EFI_MEMORY_DESCRIPTOR
*) (PiSmmCommunicationRegionTable
+ 1);
197 for (Index
= 0; Index
< PiSmmCommunicationRegionTable
->NumberOfEntries
; Index
++) {
198 if (MmCommMemRegion
->Type
== EfiConventionalMemory
) {
199 CommBufferSize
= EFI_PAGES_TO_SIZE ((UINTN
)MmCommMemRegion
->NumberOfPages
);
200 if (CommBufferSize
>= (sizeof (TPM_NVS_MM_COMM_BUFFER
) + OFFSET_OF (EFI_MM_COMMUNICATE_HEADER
, Data
))) {
204 MmCommMemRegion
= (EFI_MEMORY_DESCRIPTOR
*)((UINT8
*)MmCommMemRegion
+ PiSmmCommunicationRegionTable
->DescriptorSize
);
207 if (Index
>= PiSmmCommunicationRegionTable
->NumberOfEntries
) {
208 // Could not find one that meets our goal...
209 DEBUG ((DEBUG_ERROR
, "%a - Could not find a common buffer that is big enough for NVS!\n", __FUNCTION__
));
210 return EFI_OUT_OF_RESOURCES
;
213 // Step 3: Start to populate contents
214 // Step 3.1: MM Communication common header
215 CommHeader
= (EFI_MM_COMMUNICATE_HEADER
*) (UINTN
) MmCommMemRegion
->PhysicalStart
;
216 CommBufferSize
= sizeof (TPM_NVS_MM_COMM_BUFFER
) + OFFSET_OF (EFI_MM_COMMUNICATE_HEADER
, Data
);
217 ZeroMem (CommHeader
, CommBufferSize
);
218 CopyGuid (&CommHeader
->HeaderGuid
, &gTpmNvsMmGuid
);
219 CommHeader
->MessageLength
= sizeof (TPM_NVS_MM_COMM_BUFFER
);
221 // Step 3.2: TPM_NVS_MM_COMM_BUFFER content per our needs
222 CommBuffer
= (TPM_NVS_MM_COMM_BUFFER
*) (CommHeader
->Data
);
223 CommBuffer
->Function
= TpmNvsMmExchangeInfo
;
224 CommBuffer
->TargetAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) TcgNvs
;
226 // Step 4: Locate the protocol and signal Mmi.
227 Status
= gBS
->LocateProtocol (&gEfiMmCommunicationProtocolGuid
, NULL
, (VOID
**) &MmCommunication
);
228 if (!EFI_ERROR (Status
)) {
229 Status
= MmCommunication
->Communicate (MmCommunication
, CommHeader
, &CommBufferSize
);
230 DEBUG ((DEBUG_INFO
, "%a - Communicate() = %r\n", __FUNCTION__
, Status
));
233 DEBUG ((DEBUG_ERROR
, "%a - Failed to locate MmCommunication protocol - %r\n", __FUNCTION__
, Status
));
237 // Step 5: If everything goes well, populate the channel number
238 if (!EFI_ERROR (CommBuffer
->ReturnStatus
)) {
239 // Need to demote to UINT8 according to SMI value definition
240 TcgNvs
->PhysicalPresence
.SoftwareSmi
= (UINT8
) CommBuffer
->RegisteredPpSwiValue
;
241 TcgNvs
->MemoryClear
.SoftwareSmi
= (UINT8
) CommBuffer
->RegisteredMcSwiValue
;
244 "%a Communication returned software SMI value. PP: 0x%x; MC: 0x%x.\n",
246 TcgNvs
->PhysicalPresence
.SoftwareSmi
,
247 TcgNvs
->MemoryClear
.SoftwareSmi
251 return (EFI_STATUS
) CommBuffer
->ReturnStatus
;
255 Patch version string of Physical Presence interface supported by platform. The initial string tag in TPM
258 @param[in, out] Table The TPM item in ACPI table.
259 @param[in] PPVer Version string of Physical Presence interface supported by platform.
261 @return The allocated address for the found region.
266 EFI_ACPI_DESCRIPTION_HEADER
*Table
,
274 // Patch some pointers for the ASL code before loading the SSDT.
276 for (DataPtr
= (UINT8
*)(Table
+ 1);
277 DataPtr
<= (UINT8
*) ((UINT8
*) Table
+ Table
->Length
- PHYSICAL_PRESENCE_VERSION_SIZE
);
279 if (AsciiStrCmp((CHAR8
*)DataPtr
, PHYSICAL_PRESENCE_VERSION_TAG
) == 0) {
280 Status
= AsciiStrCpyS((CHAR8
*)DataPtr
, PHYSICAL_PRESENCE_VERSION_SIZE
, PPVer
);
281 DEBUG((DEBUG_INFO
, "TPM2 Physical Presence Interface Version update status 0x%x\n", Status
));
286 return EFI_NOT_FOUND
;
290 Patch interrupt resources returned by TPM _PRS. ResourceTemplate to patch is determined by input
291 interrupt buffer size. BufferSize, PkgLength and interrupt descriptor in ByteList need to be patched
293 @param[in, out] Table The TPM item in ACPI table.
294 @param[in] IrqBuffer Input new IRQ buffer.
295 @param[in] IrqBuffserSize Input new IRQ buffer size.
296 @param[out] IsShortFormPkgLength If _PRS returns Short length Package(ACPI spec 20.2.4).
298 @return patch status.
302 UpdatePossibleResource (
303 IN OUT EFI_ACPI_DESCRIPTION_HEADER
*Table
,
304 IN UINT32
*IrqBuffer
,
305 IN UINT32 IrqBuffserSize
,
306 OUT BOOLEAN
*IsShortFormPkgLength
312 UINT32 OrignalPkgLength
;
315 OrignalPkgLength
= 0;
320 // 6.4.3 Extend Interrupt Descriptor.
321 // 19.3.3 ASL Resource Template
322 // 20 AML specification
323 // to patch TPM ACPI object _PRS returned ResourceTemplate() containing 2 resource descriptors and an auto appended End Tag
325 // AML data is organized by following rule.
326 // Code need to patch BufferSize and PkgLength and interrupt descriptor in ByteList
328 // ============= Buffer ====================
329 // DefBuffer := BufferOp PkgLength BufferSize ByteList
332 // ==============PkgLength==================
333 // PkgLength := PkgLeadByte |
334 // <PkgLeadByte ByteData> |
335 // <PkgLeadByte ByteData ByteData> |
336 // <PkgLeadByte ByteData ByteData ByteData>
338 // PkgLeadByte := <bit 7-6: ByteData count that follows (0-3)>
339 // <bit 5-4: Only used if PkgLength <= 63 >
340 // <bit 3-0: Least significant package length nybble>
342 //==============BufferSize==================
343 // BufferSize := Integer
344 // Integer := ByteConst|WordConst|DwordConst....
346 // ByteConst := BytePrefix ByteData
348 //==============ByteList===================
349 // ByteList := ByteData ByteList
351 //=========================================
354 // 1. Check TPM_PRS_RESS with PkgLength <=63 can hold the input interrupt number buffer for patching
356 for (DataPtr
= (UINT8
*)(Table
+ 1);
357 DataPtr
< (UINT8
*) ((UINT8
*) Table
+ Table
->Length
- (TPM_PRS_RES_NAME_SIZE
+ TPM_POS_RES_TEMPLATE_MIN_SIZE
));
359 if (CompareMem(DataPtr
, TPM_PRS_RESS
, TPM_PRS_RES_NAME_SIZE
) == 0) {
361 // Jump over object name & BufferOp
363 DataPtr
+= TPM_PRS_RES_NAME_SIZE
+ 1;
365 if ((*DataPtr
& (BIT7
|BIT6
)) == 0) {
366 OrignalPkgLength
= (UINT32
)*DataPtr
;
367 DataEndPtr
= DataPtr
+ OrignalPkgLength
;
370 // Jump over PkgLength = PkgLeadByte only
375 // Jump over BufferSize
377 if (*(DataPtr
+ 1) == AML_BYTE_PREFIX
) {
379 } else if (*(DataPtr
+ 1) == AML_WORD_PREFIX
) {
381 } else if (*(DataPtr
+ 1) == AML_DWORD_PREFIX
) {
385 return EFI_UNSUPPORTED
;
389 return EFI_UNSUPPORTED
;
393 // Include Memory32Fixed Descriptor (12 Bytes) + Interrupt Descriptor header(5 Bytes) + End Tag(2 Bytes)
395 NewPkgLength
+= 19 + IrqBuffserSize
;
396 if (NewPkgLength
> 63) {
400 if (NewPkgLength
> OrignalPkgLength
) {
402 return EFI_INVALID_PARAMETER
;
406 // 1.1 Patch PkgLength
408 *DataPtr
= (UINT8
)NewPkgLength
;
411 // 1.2 Patch BufferSize = sizeof(Memory32Fixed Descriptor + Interrupt Descriptor + End Tag).
412 // It is Little endian. So only patch lowest byte of BufferSize due to current interrupt number limit.
414 *(DataPtr
+ 2) = (UINT8
)(IrqBuffserSize
+ 19);
417 // Notify _PRS to report short formed ResourceTemplate
419 *IsShortFormPkgLength
= TRUE
;
426 // 2. Use TPM_PRS_RESL with PkgLength > 63 to hold longer input interrupt number buffer for patching
428 if (NewPkgLength
> 63) {
430 OrignalPkgLength
= 0;
431 for (DataPtr
= (UINT8
*)(Table
+ 1);
432 DataPtr
< (UINT8
*) ((UINT8
*) Table
+ Table
->Length
- (TPM_PRS_RES_NAME_SIZE
+ TPM_POS_RES_TEMPLATE_MIN_SIZE
));
434 if (CompareMem(DataPtr
, TPM_PRS_RESL
, TPM_PRS_RES_NAME_SIZE
) == 0) {
436 // Jump over object name & BufferOp
438 DataPtr
+= TPM_PRS_RES_NAME_SIZE
+ 1;
440 if ((*DataPtr
& (BIT7
|BIT6
)) != 0) {
441 OrignalPkgLength
= (UINT32
)(*(DataPtr
+ 1) << 4) + (*DataPtr
& 0x0F);
442 DataEndPtr
= DataPtr
+ OrignalPkgLength
;
444 // Jump over PkgLength = PkgLeadByte + ByteData length
446 NewPkgLength
+= 1 + ((*DataPtr
& (BIT7
|BIT6
)) >> 6);
449 // Jump over BufferSize
451 if (*(DataPtr
+ NewPkgLength
) == AML_BYTE_PREFIX
) {
453 } else if (*(DataPtr
+ NewPkgLength
) == AML_WORD_PREFIX
) {
455 } else if (*(DataPtr
+ NewPkgLength
) == AML_DWORD_PREFIX
) {
459 return EFI_UNSUPPORTED
;
463 return EFI_UNSUPPORTED
;
467 // Include Memory32Fixed Descriptor (12 Bytes) + Interrupt Descriptor header(5 Bytes) + End Tag(2 Bytes)
469 NewPkgLength
+= 19 + IrqBuffserSize
;
471 if (NewPkgLength
> OrignalPkgLength
) {
473 return EFI_INVALID_PARAMETER
;
477 // 2.1 Patch PkgLength. Only patch PkgLeadByte and first ByteData
479 *DataPtr
= (UINT8
)((*DataPtr
) & 0xF0) | (NewPkgLength
& 0x0F);
480 *(DataPtr
+ 1) = (UINT8
)((NewPkgLength
& 0xFF0) >> 4);
483 // 2.2 Patch BufferSize = sizeof(Memory32Fixed Descriptor + Interrupt Descriptor + End Tag).
484 // It is Little endian. Only patch lowest byte of BufferSize due to current interrupt number limit.
486 *(DataPtr
+ 2 + ((*DataPtr
& (BIT7
|BIT6
)) >> 6)) = (UINT8
)(IrqBuffserSize
+ 19);
489 // Notify _PRS to report long formed ResourceTemplate
491 *IsShortFormPkgLength
= FALSE
;
497 if (DataPtr
>= (UINT8
*) ((UINT8
*) Table
+ Table
->Length
- (TPM_PRS_RES_NAME_SIZE
+ TPM_POS_RES_TEMPLATE_MIN_SIZE
))) {
498 return EFI_NOT_FOUND
;
502 // 3. Move DataPtr to Interrupt descriptor header and patch interrupt descriptor.
503 // 5 bytes for interrupt descriptor header, 2 bytes for End Tag
505 DataPtr
+= NewPkgLength
- (5 + IrqBuffserSize
+ 2);
507 // 3.1 Patch Length bit[7:0] of Interrupt descriptor patch interrupt descriptor
509 *(DataPtr
+ 1) = (UINT8
)(2 + IrqBuffserSize
);
511 // 3.2 Patch Interrupt Table Length
513 *(DataPtr
+ 4) = (UINT8
)(IrqBuffserSize
/ sizeof(UINT32
));
515 // 3.3 Copy patched InterruptNumBuffer
517 CopyMem(DataPtr
+ 5, IrqBuffer
, IrqBuffserSize
);
520 // 4. Jump over Interrupt descriptor and Patch END Tag, set Checksum field to 0
522 DataPtr
+= 5 + IrqBuffserSize
;
523 *DataPtr
= ACPI_END_TAG_DESCRIPTOR
;
527 // 5. Jump over new ResourceTemplate. Stuff rest bytes to NOOP
530 if (DataPtr
< DataEndPtr
) {
531 SetMem(DataPtr
, (UINTN
)DataEndPtr
- (UINTN
)DataPtr
, AML_NOOP_OP
);
538 Patch TPM2 device HID string. The initial string tag in TPM2 ACPI table is "NNN0000".
540 @param[in, out] Table The TPM2 SSDT ACPI table.
542 @return HID Update status.
547 EFI_ACPI_DESCRIPTION_HEADER
*Table
552 CHAR8 Hid
[TPM_HID_ACPI_SIZE
];
553 UINT32 ManufacturerID
;
554 UINT32 FirmwareVersion1
;
555 UINT32 FirmwareVersion2
;
561 // Initialize HID with Default PNP string
563 ZeroMem(Hid
, TPM_HID_ACPI_SIZE
);
566 // Get Manufacturer ID
568 Status
= Tpm2GetCapabilityManufactureID(&ManufacturerID
);
569 if (!EFI_ERROR(Status
)) {
570 DEBUG((DEBUG_INFO
, "TPM_PT_MANUFACTURER 0x%08x\n", ManufacturerID
));
572 // ManufacturerID defined in TCG Vendor ID Registry
573 // may tailed with 0x00 or 0x20
575 if ((ManufacturerID
>> 24) == 0x00 || ((ManufacturerID
>> 24) == 0x20)) {
577 // HID containing PNP ID "NNN####"
578 // NNN is uppercase letter for Vendor ID specified by manufacturer
580 CopyMem(Hid
, &ManufacturerID
, 3);
583 // HID containing ACP ID "NNNN####"
584 // NNNN is uppercase letter for Vendor ID specified by manufacturer
586 CopyMem(Hid
, &ManufacturerID
, 4);
590 DEBUG ((DEBUG_ERROR
, "Get TPM_PT_MANUFACTURER failed %x!\n", Status
));
595 Status
= Tpm2GetCapabilityFirmwareVersion(&FirmwareVersion1
, &FirmwareVersion2
);
596 if (!EFI_ERROR(Status
)) {
597 DEBUG((DEBUG_INFO
, "TPM_PT_FIRMWARE_VERSION_1 0x%x\n", FirmwareVersion1
));
598 DEBUG((DEBUG_INFO
, "TPM_PT_FIRMWARE_VERSION_2 0x%x\n", FirmwareVersion2
));
600 // #### is Firmware Version 1
603 AsciiSPrint(Hid
+ 3, TPM_HID_PNP_SIZE
- 3, "%02d%02d", ((FirmwareVersion1
& 0xFFFF0000) >> 16), (FirmwareVersion1
& 0x0000FFFF));
605 AsciiSPrint(Hid
+ 4, TPM_HID_ACPI_SIZE
- 4, "%02d%02d", ((FirmwareVersion1
& 0xFFFF0000) >> 16), (FirmwareVersion1
& 0x0000FFFF));
609 DEBUG ((DEBUG_ERROR
, "Get TPM_PT_FIRMWARE_VERSION_X failed %x!\n", Status
));
615 // Patch HID in ASL code before loading the SSDT.
617 for (DataPtr
= (UINT8
*)(Table
+ 1);
618 DataPtr
<= (UINT8
*) ((UINT8
*) Table
+ Table
->Length
- TPM_HID_PNP_SIZE
);
620 if (AsciiStrCmp((CHAR8
*)DataPtr
, TPM_HID_TAG
) == 0) {
622 CopyMem(DataPtr
, Hid
, TPM_HID_PNP_SIZE
);
624 // if HID is PNP ID, patch the last byte in HID TAG to Noop
626 *(DataPtr
+ TPM_HID_PNP_SIZE
) = AML_NOOP_OP
;
629 CopyMem(DataPtr
, Hid
, TPM_HID_ACPI_SIZE
);
631 DEBUG((DEBUG_INFO
, "TPM2 ACPI _HID is patched to %a\n", DataPtr
));
637 DEBUG((DEBUG_ERROR
, "TPM2 ACPI HID TAG for patch not found!\n"));
638 return EFI_NOT_FOUND
;
642 Initialize and publish TPM items in ACPI table.
644 @retval EFI_SUCCESS The TCG ACPI table is published successfully.
645 @retval Others The TCG ACPI table is not published.
654 EFI_ACPI_TABLE_PROTOCOL
*AcpiTable
;
656 EFI_ACPI_DESCRIPTION_HEADER
*Table
;
658 UINT32
*PossibleIrqNumBuf
;
659 UINT32 PossibleIrqNumBufSize
;
660 BOOLEAN IsShortFormPkgLength
;
662 IsShortFormPkgLength
= FALSE
;
664 Status
= GetSectionFromFv (
671 ASSERT_EFI_ERROR (Status
);
674 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA.
675 // The measurement has to be done before any update.
676 // Otherwise, the PCR record would be different after TPM FW update
677 // or the PCD configuration change.
679 TpmMeasureAndLogData(
682 EV_POSTCODE_INFO_ACPI_DATA
,
689 // Update Table version before measuring it to PCR
691 Status
= UpdatePPVersion(Table
, (CHAR8
*)PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer
));
692 ASSERT_EFI_ERROR (Status
);
696 "Current physical presence interface version - %a\n",
697 (CHAR8
*) PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer
)
701 // Update TPM2 HID after measuring it to PCR
703 Status
= UpdateHID(Table
);
704 if (EFI_ERROR(Status
)) {
708 if (PcdGet32(PcdTpm2CurrentIrqNum
) != 0) {
710 // Patch _PRS interrupt resource only when TPM interrupt is supported
712 PossibleIrqNumBuf
= (UINT32
*)PcdGetPtr(PcdTpm2PossibleIrqNumBuf
);
713 PossibleIrqNumBufSize
= (UINT32
)PcdGetSize(PcdTpm2PossibleIrqNumBuf
);
715 if (PossibleIrqNumBufSize
<= MAX_PRS_INT_BUF_SIZE
&& (PossibleIrqNumBufSize
% sizeof(UINT32
)) == 0) {
716 Status
= UpdatePossibleResource(Table
, PossibleIrqNumBuf
, PossibleIrqNumBufSize
, &IsShortFormPkgLength
);
719 "UpdatePossibleResource status - %x. TPM2 service may not ready in OS.\n",
725 "PcdTpm2PossibleIrqNumBuf size %x is not correct. TPM2 service may not ready in OS.\n",
726 PossibleIrqNumBufSize
731 ASSERT (Table
->OemTableId
== SIGNATURE_64 ('T', 'p', 'm', '2', 'T', 'a', 'b', 'l'));
732 CopyMem (Table
->OemId
, PcdGetPtr (PcdAcpiDefaultOemId
), sizeof (Table
->OemId
) );
733 mTcgNvs
= AssignOpRegion (Table
, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16
) sizeof (TCG_NVS
));
734 ASSERT (mTcgNvs
!= NULL
);
735 mTcgNvs
->TpmIrqNum
= PcdGet32(PcdTpm2CurrentIrqNum
);
736 mTcgNvs
->IsShortFormPkgLength
= IsShortFormPkgLength
;
738 Status
= ExchangeCommonBuffer (mTcgNvs
);
741 // Publish the TPM ACPI table. Table is re-checksummed.
743 Status
= gBS
->LocateProtocol (&gEfiAcpiTableProtocolGuid
, NULL
, (VOID
**) &AcpiTable
);
744 ASSERT_EFI_ERROR (Status
);
747 Status
= AcpiTable
->InstallAcpiTable (
753 ASSERT_EFI_ERROR (Status
);
759 Publish TPM2 ACPI table
761 @retval EFI_SUCCESS The TPM2 ACPI table is published successfully.
762 @retval Others The TPM2 ACPI table is not published.
771 EFI_ACPI_TABLE_PROTOCOL
*AcpiTable
;
774 EFI_TPM2_ACPI_CONTROL_AREA
*ControlArea
;
775 TPM2_PTP_INTERFACE_TYPE InterfaceType
;
778 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA.
779 // The measurement has to be done before any update.
780 // Otherwise, the PCR record would be different after event log update
781 // or the PCD configuration change.
783 TpmMeasureAndLogData(
786 EV_POSTCODE_INFO_ACPI_DATA
,
789 mTpm2AcpiTemplate
.Header
.Length
792 mTpm2AcpiTemplate
.Header
.Revision
= PcdGet8(PcdTpm2AcpiTableRev
);
793 DEBUG((DEBUG_INFO
, "Tpm2 ACPI table revision is %d\n", mTpm2AcpiTemplate
.Header
.Revision
));
796 // PlatformClass is only valid for version 4 and above
797 // BIT0~15: PlatformClass
798 // BIT16~31: Reserved
800 if (mTpm2AcpiTemplate
.Header
.Revision
>= EFI_TPM2_ACPI_TABLE_REVISION_4
) {
801 mTpm2AcpiTemplate
.Flags
= (mTpm2AcpiTemplate
.Flags
& 0xFFFF0000) | PcdGet8(PcdTpmPlatformClass
);
802 DEBUG((DEBUG_INFO
, "Tpm2 ACPI table PlatformClass is %d\n", (mTpm2AcpiTemplate
.Flags
& 0x0000FFFF)));
805 mTpm2AcpiTemplate
.Laml
= PcdGet32(PcdTpm2AcpiTableLaml
);
806 mTpm2AcpiTemplate
.Lasa
= PcdGet64(PcdTpm2AcpiTableLasa
);
807 if ((mTpm2AcpiTemplate
.Header
.Revision
< EFI_TPM2_ACPI_TABLE_REVISION_4
) ||
808 (mTpm2AcpiTemplate
.Laml
== 0) || (mTpm2AcpiTemplate
.Lasa
== 0)) {
810 // If version is smaller than 4 or Laml/Lasa is not valid, rollback to original Length.
812 mTpm2AcpiTemplate
.Header
.Length
= sizeof(EFI_TPM2_ACPI_TABLE
);
815 InterfaceType
= PcdGet8(PcdActiveTpmInterfaceType
);
816 switch (InterfaceType
) {
817 case Tpm2PtpInterfaceCrb
:
818 mTpm2AcpiTemplate
.StartMethod
= EFI_TPM2_ACPI_TABLE_START_METHOD_COMMAND_RESPONSE_BUFFER_INTERFACE
;
819 mTpm2AcpiTemplate
.AddressOfControlArea
= PcdGet64 (PcdTpmBaseAddress
) + 0x40;
820 ControlArea
= (EFI_TPM2_ACPI_CONTROL_AREA
*)(UINTN
)mTpm2AcpiTemplate
.AddressOfControlArea
;
821 ControlArea
->CommandSize
= 0xF80;
822 ControlArea
->ResponseSize
= 0xF80;
823 ControlArea
->Command
= PcdGet64 (PcdTpmBaseAddress
) + 0x80;
824 ControlArea
->Response
= PcdGet64 (PcdTpmBaseAddress
) + 0x80;
826 case Tpm2PtpInterfaceFifo
:
827 case Tpm2PtpInterfaceTis
:
830 DEBUG((DEBUG_ERROR
, "TPM2 InterfaceType get error! %d\n", InterfaceType
));
834 CopyMem (mTpm2AcpiTemplate
.Header
.OemId
, PcdGetPtr (PcdAcpiDefaultOemId
), sizeof (mTpm2AcpiTemplate
.Header
.OemId
));
835 OemTableId
= PcdGet64 (PcdAcpiDefaultOemTableId
);
836 CopyMem (&mTpm2AcpiTemplate
.Header
.OemTableId
, &OemTableId
, sizeof (UINT64
));
837 mTpm2AcpiTemplate
.Header
.OemRevision
= PcdGet32 (PcdAcpiDefaultOemRevision
);
838 mTpm2AcpiTemplate
.Header
.CreatorId
= PcdGet32 (PcdAcpiDefaultCreatorId
);
839 mTpm2AcpiTemplate
.Header
.CreatorRevision
= PcdGet32 (PcdAcpiDefaultCreatorRevision
);
842 // Construct ACPI table
844 Status
= gBS
->LocateProtocol (&gEfiAcpiTableProtocolGuid
, NULL
, (VOID
**) &AcpiTable
);
845 ASSERT_EFI_ERROR (Status
);
847 Status
= AcpiTable
->InstallAcpiTable (
850 mTpm2AcpiTemplate
.Header
.Length
,
853 ASSERT_EFI_ERROR (Status
);
859 The driver's entry point.
861 It patches and installs ACPI tables used for handling TPM physical presence
862 and Memory Clear requests through ACPI method.
864 @param[in] ImageHandle The firmware allocated handle for the EFI image.
865 @param[in] SystemTable A pointer to the EFI System Table.
867 @retval EFI_SUCCESS The entry point is executed successfully.
868 @retval Others Some error occurs when executing this entry point.
874 IN EFI_HANDLE ImageHandle
,
875 IN EFI_SYSTEM_TABLE
*SystemTable
880 if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid
), &gEfiTpmDeviceInstanceTpm20DtpmGuid
)){
881 DEBUG ((DEBUG_ERROR
, "No TPM2 DTPM instance required!\n"));
882 return EFI_UNSUPPORTED
;
885 Status
= PublishAcpiTable ();
886 ASSERT_EFI_ERROR (Status
);
889 // Set TPM2 ACPI table
891 Status
= PublishTpm2 ();
892 ASSERT_EFI_ERROR (Status
);