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.
33 Return PTP interface type.
35 @param[in] Register Pointer to PTP register.
37 @return PTP interface type.
44 PTP_CRB_INTERFACE_IDENTIFIER InterfaceId
;
45 PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability
;
50 InterfaceId
.Uint32
= MmioRead32 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->InterfaceId
);
51 InterfaceCapability
.Uint32
= MmioRead32 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->InterfaceCapability
);
53 if (InterfaceId
.Bits
.InterfaceType
== PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_TIS
) {
54 return PtpInterfaceTis
;
57 if ((InterfaceId
.Bits
.InterfaceType
== PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_CRB
) &&
58 (InterfaceId
.Bits
.InterfaceVersion
== PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_CRB
) &&
59 (InterfaceId
.Bits
.CapCRB
!= 0)) {
60 return PtpInterfaceCrb
;
63 if ((InterfaceId
.Bits
.InterfaceType
== PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO
) &&
64 (InterfaceId
.Bits
.InterfaceVersion
== PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_FIFO
) &&
65 (InterfaceId
.Bits
.CapFIFO
!= 0) &&
66 (InterfaceCapability
.Bits
.InterfaceVersion
== INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP
)) {
67 return PtpInterfaceFifo
;
71 // No Ptp interface available
73 return PtpInterfaceMax
;
76 EFI_TPM2_ACPI_TABLE mTpm2AcpiTemplate
= {
78 EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE
,
79 sizeof (mTpm2AcpiTemplate
),
80 EFI_TPM2_ACPI_TABLE_REVISION
,
82 // Compiler initializes the remaining bytes to 0
83 // These fields should be filled in in production
86 0, // BIT0~15: PlatformClass
89 EFI_TPM2_ACPI_TABLE_START_METHOD_TIS
, // StartMethod
92 EFI_SMM_VARIABLE_PROTOCOL
*mSmmVariable
;
96 Software SMI callback for TPM physical presence which is called from ACPI method.
98 Caution: This function may receive untrusted input.
99 Variable and ACPINvs are external input, so this function will validate
100 its data structure to be valid value.
102 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
103 @param[in] Context Points to an optional handler context which was specified when the
104 handler was registered.
105 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
106 be conveyed from a non-SMM environment into an SMM environment.
107 @param[in, out] CommBufferSize The size of the CommBuffer.
109 @retval EFI_SUCCESS The interrupt was handled successfully.
114 PhysicalPresenceCallback (
115 IN EFI_HANDLE DispatchHandle
,
116 IN CONST VOID
*Context
,
117 IN OUT VOID
*CommBuffer
,
118 IN OUT UINTN
*CommBufferSize
121 UINT32 MostRecentRequest
;
123 UINT32 OperationRequest
;
124 UINT32 RequestParameter
;
127 if (mTcgNvs
->PhysicalPresence
.Parameter
== TCG_ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS
) {
128 mTcgNvs
->PhysicalPresence
.ReturnCode
= Tcg2PhysicalPresenceLibReturnOperationResponseToOsFunction (
132 mTcgNvs
->PhysicalPresence
.LastRequest
= MostRecentRequest
;
133 mTcgNvs
->PhysicalPresence
.Response
= Response
;
135 } else if ((mTcgNvs
->PhysicalPresence
.Parameter
== TCG_ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS
)
136 || (mTcgNvs
->PhysicalPresence
.Parameter
== TCG_ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2
)) {
138 OperationRequest
= mTcgNvs
->PhysicalPresence
.Request
;
139 RequestParameter
= mTcgNvs
->PhysicalPresence
.RequestParameter
;
140 mTcgNvs
->PhysicalPresence
.ReturnCode
= Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunctionEx (
144 mTcgNvs
->PhysicalPresence
.Request
= OperationRequest
;
145 mTcgNvs
->PhysicalPresence
.RequestParameter
= RequestParameter
;
146 } else if (mTcgNvs
->PhysicalPresence
.Parameter
== TCG_ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST
) {
147 mTcgNvs
->PhysicalPresence
.ReturnCode
= Tcg2PhysicalPresenceLibGetUserConfirmationStatusFunction (mTcgNvs
->PPRequestUserConfirm
);
155 Software SMI callback for MemoryClear which is called from ACPI method.
157 Caution: This function may receive untrusted input.
158 Variable and ACPINvs are external input, so this function will validate
159 its data structure to be valid value.
161 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
162 @param[in] Context Points to an optional handler context which was specified when the
163 handler was registered.
164 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
165 be conveyed from a non-SMM environment into an SMM environment.
166 @param[in, out] CommBufferSize The size of the CommBuffer.
168 @retval EFI_SUCCESS The interrupt was handled successfully.
173 MemoryClearCallback (
174 IN EFI_HANDLE DispatchHandle
,
175 IN CONST VOID
*Context
,
176 IN OUT VOID
*CommBuffer
,
177 IN OUT UINTN
*CommBufferSize
184 mTcgNvs
->MemoryClear
.ReturnCode
= MOR_REQUEST_SUCCESS
;
185 if (mTcgNvs
->MemoryClear
.Parameter
== ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE
) {
186 MorControl
= (UINT8
) mTcgNvs
->MemoryClear
.Request
;
187 } else if (mTcgNvs
->MemoryClear
.Parameter
== ACPI_FUNCTION_PTS_CLEAR_MOR_BIT
) {
188 DataSize
= sizeof (UINT8
);
189 Status
= mSmmVariable
->SmmGetVariable (
190 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME
,
191 &gEfiMemoryOverwriteControlDataGuid
,
196 if (EFI_ERROR (Status
)) {
197 mTcgNvs
->MemoryClear
.ReturnCode
= MOR_REQUEST_GENERAL_FAILURE
;
198 DEBUG ((EFI_D_ERROR
, "[TPM] Get MOR variable failure! Status = %r\n", Status
));
202 if (MOR_CLEAR_MEMORY_VALUE (MorControl
) == 0x0) {
205 MorControl
&= ~MOR_CLEAR_MEMORY_BIT_MASK
;
208 DataSize
= sizeof (UINT8
);
209 Status
= mSmmVariable
->SmmSetVariable (
210 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME
,
211 &gEfiMemoryOverwriteControlDataGuid
,
212 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
216 if (EFI_ERROR (Status
)) {
217 mTcgNvs
->MemoryClear
.ReturnCode
= MOR_REQUEST_GENERAL_FAILURE
;
218 DEBUG ((EFI_D_ERROR
, "[TPM] Set MOR variable failure! Status = %r\n", Status
));
225 Find the operation region in TCG ACPI table by given Name and Size,
226 and initialize it if the region is found.
228 @param[in, out] Table The TPM item in ACPI table.
229 @param[in] Name The name string to find in TPM table.
230 @param[in] Size The size of the region to find.
232 @return The allocated address for the found region.
237 EFI_ACPI_DESCRIPTION_HEADER
*Table
,
243 AML_OP_REGION_32_8
*OpRegion
;
244 EFI_PHYSICAL_ADDRESS MemoryAddress
;
246 MemoryAddress
= SIZE_4GB
- 1;
249 // Patch some pointers for the ASL code before loading the SSDT.
251 for (OpRegion
= (AML_OP_REGION_32_8
*) (Table
+ 1);
252 OpRegion
<= (AML_OP_REGION_32_8
*) ((UINT8
*) Table
+ Table
->Length
);
253 OpRegion
= (AML_OP_REGION_32_8
*) ((UINT8
*) OpRegion
+ 1)) {
254 if ((OpRegion
->OpRegionOp
== AML_EXT_REGION_OP
) &&
255 (OpRegion
->NameString
== Name
) &&
256 (OpRegion
->DWordPrefix
== AML_DWORD_PREFIX
) &&
257 (OpRegion
->BytePrefix
== AML_BYTE_PREFIX
)) {
259 Status
= gBS
->AllocatePages(AllocateMaxAddress
, EfiACPIMemoryNVS
, EFI_SIZE_TO_PAGES (Size
), &MemoryAddress
);
260 ASSERT_EFI_ERROR (Status
);
261 ZeroMem ((VOID
*)(UINTN
)MemoryAddress
, Size
);
262 OpRegion
->RegionOffset
= (UINT32
) (UINTN
) MemoryAddress
;
263 OpRegion
->RegionLen
= (UINT8
) Size
;
268 return (VOID
*) (UINTN
) MemoryAddress
;
272 Patch version string of Physical Presence interface supported by platform. The initial string tag in TPM
275 @param[in, out] Table The TPM item in ACPI table.
276 @param[in] PPVer Version string of Physical Presence interface supported by platform.
278 @return The allocated address for the found region.
283 EFI_ACPI_DESCRIPTION_HEADER
*Table
,
291 // Patch some pointers for the ASL code before loading the SSDT.
293 for (DataPtr
= (UINT8
*)(Table
+ 1);
294 DataPtr
<= (UINT8
*) ((UINT8
*) Table
+ Table
->Length
- PHYSICAL_PRESENCE_VERSION_SIZE
);
296 if (AsciiStrCmp((CHAR8
*)DataPtr
, PHYSICAL_PRESENCE_VERSION_TAG
) == 0) {
297 Status
= AsciiStrCpyS((CHAR8
*)DataPtr
, PHYSICAL_PRESENCE_VERSION_SIZE
, PPVer
);
298 DEBUG((EFI_D_INFO
, "TPM2 Physical Presence Interface Version update status 0x%x\n", Status
));
303 return EFI_NOT_FOUND
;
307 Patch interrupt resources returned by TPM _PRS. ResourceTemplate to patch is determined by input
308 interrupt buffer size. BufferSize, PkgLength and interrupt descirptor in ByteList need to be patched
310 @param[in, out] Table The TPM item in ACPI table.
311 @param[in] IrqBuffer Input new IRQ buffer.
312 @param[in] IrqBuffserSize Input new IRQ buffer size.
313 @param[out] IsShortFormPkgLength If _PRS returns Short length Package(ACPI spec 20.2.4).
315 @return patch status.
319 UpdatePossibleResource (
320 IN OUT EFI_ACPI_DESCRIPTION_HEADER
*Table
,
321 IN UINT32
*IrqBuffer
,
322 IN UINT32 IrqBuffserSize
,
323 OUT BOOLEAN
*IsShortFormPkgLength
329 UINT32 OrignalPkgLength
;
332 OrignalPkgLength
= 0;
337 // 6.4.3 Extend Interrupt Descriptor.
338 // 19.3.3 ASL Resource Template
339 // 20 AML specification
340 // to patch TPM ACPI object _PRS returned ResourceTemplate() containing 2 resource descriptors and an auto appended End Tag
342 // AML data is organized by following rule.
343 // Code need to patch BufferSize and PkgLength and interrupt descirptor in ByteList
345 // ============= Buffer ====================
346 // DefBuffer := BufferOp PkgLength BufferSize ByteList
349 // ==============PkgLength==================
350 // PkgLength := PkgLeadByte |
351 // <PkgLeadByte ByteData> |
352 // <PkgLeadByte ByteData ByteData> |
353 // <PkgLeadByte ByteData ByteData ByteData>
355 // PkgLeadByte := <bit 7-6: ByteData count that follows (0-3)>
356 // <bit 5-4: Only used if PkgLength <= 63 >
357 // <bit 3-0: Least significant package length nybble>
359 //==============BufferSize==================
360 // BufferSize := Integar
361 // Integar := ByteConst|WordConst|DwordConst....
363 // ByteConst := BytePrefix ByteData
365 //==============ByteList===================
366 // ByteList := ByteData ByteList
368 //=========================================
371 // 1. Check TPM_PRS_RESS with PkgLength <=63 can hold the input interrupt number buffer for patching
373 for (DataPtr
= (UINT8
*)(Table
+ 1);
374 DataPtr
< (UINT8
*) ((UINT8
*) Table
+ Table
->Length
- (TPM_PRS_RES_NAME_SIZE
+ TPM_POS_RES_TEMPLATE_MIN_SIZE
));
376 if (CompareMem(DataPtr
, TPM_PRS_RESS
, TPM_PRS_RES_NAME_SIZE
) == 0) {
378 // Jump over object name & BufferOp
380 DataPtr
+= TPM_PRS_RES_NAME_SIZE
+ 1;
382 if ((*DataPtr
& (BIT7
|BIT6
)) == 0) {
383 OrignalPkgLength
= (UINT32
)*DataPtr
;
384 DataEndPtr
= DataPtr
+ OrignalPkgLength
;
387 // Jump over PkgLength = PkgLeadByte only
392 // Jump over BufferSize
394 if (*(DataPtr
+ 1) == AML_BYTE_PREFIX
) {
396 } else if (*(DataPtr
+ 1) == AML_WORD_PREFIX
) {
398 } else if (*(DataPtr
+ 1) == AML_DWORD_PREFIX
) {
402 return EFI_UNSUPPORTED
;
406 return EFI_UNSUPPORTED
;
410 // Include Memory32Fixed Descritor (12 Bytes) + Interrupt Descriptor header(5 Bytes) + End Tag(2 Bytes)
412 NewPkgLength
+= 19 + IrqBuffserSize
;
413 if (NewPkgLength
> 63) {
417 if (NewPkgLength
> OrignalPkgLength
) {
419 return EFI_INVALID_PARAMETER
;
423 // 1.1 Patch PkgLength
425 *DataPtr
= (UINT8
)NewPkgLength
;
428 // 1.2 Patch BufferSize = sizeof(Memory32Fixed Descritor + Interrupt Descriptor + End Tag).
429 // It is Little endian. So only patch lowest byte of BufferSize due to current interrupt number limit.
431 *(DataPtr
+ 2) = (UINT8
)(IrqBuffserSize
+ 19);
434 // Notify _PRS to report short formed ResourceTemplate
436 *IsShortFormPkgLength
= TRUE
;
443 // 2. Use TPM_PRS_RESL with PkgLength > 63 to hold longer input interrupt number buffer for patching
445 if (NewPkgLength
> 63) {
447 OrignalPkgLength
= 0;
448 for (DataPtr
= (UINT8
*)(Table
+ 1);
449 DataPtr
< (UINT8
*) ((UINT8
*) Table
+ Table
->Length
- (TPM_PRS_RES_NAME_SIZE
+ TPM_POS_RES_TEMPLATE_MIN_SIZE
));
451 if (CompareMem(DataPtr
, TPM_PRS_RESL
, TPM_PRS_RES_NAME_SIZE
) == 0) {
453 // Jump over object name & BufferOp
455 DataPtr
+= TPM_PRS_RES_NAME_SIZE
+ 1;
457 if ((*DataPtr
& (BIT7
|BIT6
)) != 0) {
458 OrignalPkgLength
= (UINT32
)(*(DataPtr
+ 1) << 4) + (*DataPtr
& 0x0F);
459 DataEndPtr
= DataPtr
+ OrignalPkgLength
;
461 // Jump over PkgLength = PkgLeadByte + ByteData length
463 NewPkgLength
+= 1 + ((*DataPtr
& (BIT7
|BIT6
)) >> 6);
466 // Jump over BufferSize
468 if (*(DataPtr
+ NewPkgLength
) == AML_BYTE_PREFIX
) {
470 } else if (*(DataPtr
+ NewPkgLength
) == AML_WORD_PREFIX
) {
472 } else if (*(DataPtr
+ NewPkgLength
) == AML_DWORD_PREFIX
) {
476 return EFI_UNSUPPORTED
;
480 return EFI_UNSUPPORTED
;
484 // Include Memory32Fixed Descritor (12 Bytes) + Interrupt Descriptor header(5 Bytes) + End Tag(2 Bytes)
486 NewPkgLength
+= 19 + IrqBuffserSize
;
488 if (NewPkgLength
> OrignalPkgLength
) {
490 return EFI_INVALID_PARAMETER
;
494 // 2.1 Patch PkgLength. Only patch PkgLeadByte and first ByteData
496 *DataPtr
= (UINT8
)((*DataPtr
) & 0xF0) | (NewPkgLength
& 0x0F);
497 *(DataPtr
+ 1) = (UINT8
)((NewPkgLength
& 0xFF0) >> 4);
500 // 2.2 Patch BufferSize = sizeof(Memory32Fixed Descritor + Interrupt Descriptor + End Tag).
501 // It is Little endian. Only patch lowest byte of BufferSize due to current interrupt number limit.
503 *(DataPtr
+ 2 + ((*DataPtr
& (BIT7
|BIT6
)) >> 6)) = (UINT8
)(IrqBuffserSize
+ 19);
506 // Notify _PRS to report long formed ResourceTemplate
508 *IsShortFormPkgLength
= FALSE
;
514 if (DataPtr
>= (UINT8
*) ((UINT8
*) Table
+ Table
->Length
- (TPM_PRS_RES_NAME_SIZE
+ TPM_POS_RES_TEMPLATE_MIN_SIZE
))) {
515 return EFI_NOT_FOUND
;
519 // 3. Move DataPtr to Interrupt descriptor header and patch interrupt descriptor.
520 // 5 bytes for interrupt descriptor header, 2 bytes for End Tag
522 DataPtr
+= NewPkgLength
- (5 + IrqBuffserSize
+ 2);
524 // 3.1 Patch Length bit[7:0] of Interrupt descirptor patch interrupt descriptor
526 *(DataPtr
+ 1) = (UINT8
)(2 + IrqBuffserSize
);
528 // 3.2 Patch Interrupt Table Length
530 *(DataPtr
+ 4) = (UINT8
)(IrqBuffserSize
/ sizeof(UINT32
));
532 // 3.3 Copy patched InterruptNumBuffer
534 CopyMem(DataPtr
+ 5, IrqBuffer
, IrqBuffserSize
);
537 // 4. Jump over Interrupt descirptor and Patch END Tag, set Checksum field to 0
539 DataPtr
+= 5 + IrqBuffserSize
;
540 *DataPtr
= ACPI_END_TAG_DESCRIPTOR
;
544 // 5. Jump over new ResourceTemplate. Stuff rest bytes to NOOP
547 if (DataPtr
< DataEndPtr
) {
548 SetMem(DataPtr
, (UINTN
)DataEndPtr
- (UINTN
)DataPtr
, AML_NOOP_OP
);
555 Patch TPM2 device HID string. The initial string tag in TPM2 ACPI table is "NNN0000".
557 @param[in, out] Table The TPM2 SSDT ACPI table.
559 @return HID Update status.
564 EFI_ACPI_DESCRIPTION_HEADER
*Table
569 CHAR8 Hid
[TPM_HID_ACPI_SIZE
];
570 UINT32 ManufacturerID
;
571 UINT32 FirmwareVersion1
;
572 UINT32 FirmwareVersion2
;
578 // Initialize HID with Default PNP string
580 ZeroMem(Hid
, TPM_HID_ACPI_SIZE
);
583 // Get Manufacturer ID
585 Status
= Tpm2GetCapabilityManufactureID(&ManufacturerID
);
586 if (!EFI_ERROR(Status
)) {
587 DEBUG((EFI_D_INFO
, "TPM_PT_MANUFACTURER 0x%08x\n", ManufacturerID
));
589 // ManufacturerID defined in TCG Vendor ID Registry
590 // may tailed with 0x00 or 0x20
592 if ((ManufacturerID
>> 24) == 0x00 || ((ManufacturerID
>> 24) == 0x20)) {
594 // HID containing PNP ID "NNN####"
595 // NNN is uppercase letter for Vendor ID specified by manufacturer
597 CopyMem(Hid
, &ManufacturerID
, 3);
600 // HID containing ACP ID "NNNN####"
601 // NNNN is uppercase letter for Vendor ID specified by manufacturer
603 CopyMem(Hid
, &ManufacturerID
, 4);
607 DEBUG ((EFI_D_ERROR
, "Get TPM_PT_MANUFACTURER failed %x!\n", Status
));
612 Status
= Tpm2GetCapabilityFirmwareVersion(&FirmwareVersion1
, &FirmwareVersion2
);
613 if (!EFI_ERROR(Status
)) {
614 DEBUG((EFI_D_INFO
, "TPM_PT_FIRMWARE_VERSION_1 0x%x\n", FirmwareVersion1
));
615 DEBUG((EFI_D_INFO
, "TPM_PT_FIRMWARE_VERSION_2 0x%x\n", FirmwareVersion2
));
617 // #### is Firmware Version 1
620 AsciiSPrint(Hid
+ 3, TPM_HID_PNP_SIZE
- 3, "%02d%02d", ((FirmwareVersion1
& 0xFFFF0000) >> 16), (FirmwareVersion1
& 0x0000FFFF));
622 AsciiSPrint(Hid
+ 4, TPM_HID_ACPI_SIZE
- 4, "%02d%02d", ((FirmwareVersion1
& 0xFFFF0000) >> 16), (FirmwareVersion1
& 0x0000FFFF));
626 DEBUG ((EFI_D_ERROR
, "Get TPM_PT_FIRMWARE_VERSION_X failed %x!\n", Status
));
632 // Patch HID in ASL code before loading the SSDT.
634 for (DataPtr
= (UINT8
*)(Table
+ 1);
635 DataPtr
<= (UINT8
*) ((UINT8
*) Table
+ Table
->Length
- TPM_HID_PNP_SIZE
);
637 if (AsciiStrCmp((CHAR8
*)DataPtr
, TPM_HID_TAG
) == 0) {
639 CopyMem(DataPtr
, Hid
, TPM_HID_PNP_SIZE
);
641 // if HID is PNP ID, patch the last byte in HID TAG to Noop
643 *(DataPtr
+ TPM_HID_PNP_SIZE
) = AML_NOOP_OP
;
646 CopyMem(DataPtr
, Hid
, TPM_HID_ACPI_SIZE
);
648 DEBUG((DEBUG_INFO
, "TPM2 ACPI _HID is patched to %a\n", DataPtr
));
654 DEBUG((EFI_D_ERROR
, "TPM2 ACPI HID TAG for patch not found!\n"));
655 return EFI_NOT_FOUND
;
659 Initialize and publish TPM items in ACPI table.
661 @retval EFI_SUCCESS The TCG ACPI table is published successfully.
662 @retval Others The TCG ACPI table is not published.
671 EFI_ACPI_TABLE_PROTOCOL
*AcpiTable
;
673 EFI_ACPI_DESCRIPTION_HEADER
*Table
;
675 UINT32
*PossibleIrqNumBuf
;
676 UINT32 PossibleIrqNumBufSize
;
677 BOOLEAN IsShortFormPkgLength
;
679 IsShortFormPkgLength
= FALSE
;
681 Status
= GetSectionFromFv (
688 ASSERT_EFI_ERROR (Status
);
691 // Update Table version before measuring it to PCR
693 Status
= UpdatePPVersion(Table
, (CHAR8
*)PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer
));
694 ASSERT_EFI_ERROR (Status
);
698 "Current physical presence interface version - %a\n",
699 (CHAR8
*) PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer
)
703 // Update TPM2 HID before measuring it to PCR
705 Status
= UpdateHID(Table
);
706 if (EFI_ERROR(Status
)) {
710 if (PcdGet32(PcdTpm2CurrentIrqNum
) != 0) {
712 // Patch _PRS interrupt resource only when TPM interrupt is supported
714 PossibleIrqNumBuf
= (UINT32
*)PcdGetPtr(PcdTpm2PossibleIrqNumBuf
);
715 PossibleIrqNumBufSize
= (UINT32
)PcdGetSize(PcdTpm2PossibleIrqNumBuf
);
717 if (PossibleIrqNumBufSize
<= MAX_PRS_INT_BUF_SIZE
&& (PossibleIrqNumBufSize
% sizeof(UINT32
)) == 0) {
718 Status
= UpdatePossibleResource(Table
, PossibleIrqNumBuf
, PossibleIrqNumBufSize
, &IsShortFormPkgLength
);
721 "UpdatePossibleResource status - %x. TPM2 service may not ready in OS.\n",
727 "PcdTpm2PossibleIrqNumBuf size %x is not correct. TPM2 service may not ready in OS.\n",
728 PossibleIrqNumBufSize
734 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
736 TpmMeasureAndLogData(
739 EV_POSTCODE_INFO_ACPI_DATA
,
746 ASSERT (Table
->OemTableId
== SIGNATURE_64 ('T', 'p', 'm', '2', 'T', 'a', 'b', 'l'));
747 CopyMem (Table
->OemId
, PcdGetPtr (PcdAcpiDefaultOemId
), sizeof (Table
->OemId
) );
748 mTcgNvs
= AssignOpRegion (Table
, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16
) sizeof (TCG_NVS
));
749 ASSERT (mTcgNvs
!= NULL
);
750 mTcgNvs
->TpmIrqNum
= PcdGet32(PcdTpm2CurrentIrqNum
);
751 mTcgNvs
->IsShortFormPkgLength
= IsShortFormPkgLength
;
754 // Publish the TPM ACPI table. Table is re-checksumed.
756 Status
= gBS
->LocateProtocol (&gEfiAcpiTableProtocolGuid
, NULL
, (VOID
**) &AcpiTable
);
757 ASSERT_EFI_ERROR (Status
);
760 Status
= AcpiTable
->InstallAcpiTable (
766 ASSERT_EFI_ERROR (Status
);
772 Publish TPM2 ACPI table
774 @retval EFI_SUCCESS The TPM2 ACPI table is published successfully.
775 @retval Others The TPM2 ACPI table is not published.
784 EFI_ACPI_TABLE_PROTOCOL
*AcpiTable
;
787 EFI_TPM2_ACPI_CONTROL_AREA
*ControlArea
;
788 PTP_INTERFACE_TYPE InterfaceType
;
790 mTpm2AcpiTemplate
.Header
.Revision
= PcdGet8(PcdTpm2AcpiTableRev
);
791 DEBUG((DEBUG_INFO
, "Tpm2 ACPI table revision is %d\n", mTpm2AcpiTemplate
.Header
.Revision
));
794 // PlatformClass is only valid for version 4 and above
795 // BIT0~15: PlatformClass
796 // BIT16~31: Reserved
798 if (mTpm2AcpiTemplate
.Header
.Revision
>= EFI_TPM2_ACPI_TABLE_REVISION_4
) {
799 mTpm2AcpiTemplate
.Flags
= (mTpm2AcpiTemplate
.Flags
& 0xFFFF0000) | PcdGet8(PcdTpmPlatformClass
);
800 DEBUG((DEBUG_INFO
, "Tpm2 ACPI table PlatformClass is %d\n", (mTpm2AcpiTemplate
.Flags
& 0x0000FFFF)));
804 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
806 TpmMeasureAndLogData(
809 EV_POSTCODE_INFO_ACPI_DATA
,
812 sizeof(mTpm2AcpiTemplate
)
815 InterfaceType
= GetPtpInterface ((VOID
*) (UINTN
) PcdGet64 (PcdTpmBaseAddress
));
816 switch (InterfaceType
) {
817 case PtpInterfaceCrb
:
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 PtpInterfaceFifo
:
827 case PtpInterfaceTis
:
830 DEBUG((EFI_D_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 sizeof(mTpm2AcpiTemplate
),
853 ASSERT_EFI_ERROR (Status
);
859 The driver's entry point.
861 It install callbacks for TPM physical presence and MemoryClear, and locate
862 SMM variable to be used in the callback function.
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
879 EFI_SMM_SW_DISPATCH2_PROTOCOL
*SwDispatch
;
880 EFI_SMM_SW_REGISTER_CONTEXT SwContext
;
883 if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid
), &gEfiTpmDeviceInstanceTpm20DtpmGuid
)){
884 DEBUG ((EFI_D_ERROR
, "No TPM2 DTPM instance required!\n"));
885 return EFI_UNSUPPORTED
;
888 Status
= PublishAcpiTable ();
889 ASSERT_EFI_ERROR (Status
);
892 // Get the Sw dispatch protocol and register SMI callback functions.
894 Status
= gSmst
->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid
, NULL
, (VOID
**)&SwDispatch
);
895 ASSERT_EFI_ERROR (Status
);
896 SwContext
.SwSmiInputValue
= (UINTN
) -1;
897 Status
= SwDispatch
->Register (SwDispatch
, PhysicalPresenceCallback
, &SwContext
, &SwHandle
);
898 ASSERT_EFI_ERROR (Status
);
899 if (EFI_ERROR (Status
)) {
902 mTcgNvs
->PhysicalPresence
.SoftwareSmi
= (UINT8
) SwContext
.SwSmiInputValue
;
904 SwContext
.SwSmiInputValue
= (UINTN
) -1;
905 Status
= SwDispatch
->Register (SwDispatch
, MemoryClearCallback
, &SwContext
, &SwHandle
);
906 ASSERT_EFI_ERROR (Status
);
907 if (EFI_ERROR (Status
)) {
910 mTcgNvs
->MemoryClear
.SoftwareSmi
= (UINT8
) SwContext
.SwSmiInputValue
;
913 // Locate SmmVariableProtocol.
915 Status
= gSmst
->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid
, NULL
, (VOID
**)&mSmmVariable
);
916 ASSERT_EFI_ERROR (Status
);
919 // Set TPM2 ACPI table
921 Status
= PublishTpm2 ();
922 ASSERT_EFI_ERROR (Status
);