1 /** @file
2   It updates TPM2 items in ACPI table and registers SMI2 callback
3   functions for Tcg2 physical presence, ClearMemory, and sample
4   for dTPM StartMethod.
5 
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.
9 
10   PhysicalPresenceCallback() and MemoryClearCallback() will receive untrusted input and do some check.
11 
12 Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
13 SPDX-License-Identifier: BSD-2-Clause-Patent
14 
15 **/
16 
17 #include "Tcg2Smm.h"
18 
19 
20 EFI_TPM2_ACPI_TABLE  mTpm2AcpiTemplate = {
21   {
22     EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE,
23     sizeof (mTpm2AcpiTemplate),
24     EFI_TPM2_ACPI_TABLE_REVISION,
25     //
26     // Compiler initializes the remaining bytes to 0
27     // These fields should be filled in in production
28     //
29   },
30   0, // BIT0~15:  PlatformClass
31      // BIT16~31: Reserved
32   0, // Control Area
33   EFI_TPM2_ACPI_TABLE_START_METHOD_TIS, // StartMethod
34 };
35 
36 EFI_SMM_VARIABLE_PROTOCOL  *mSmmVariable;
37 TCG_NVS                    *mTcgNvs;
38 
39 /**
40   Software SMI callback for TPM physical presence which is called from ACPI method.
41 
42   Caution: This function may receive untrusted input.
43   Variable and ACPINvs are external input, so this function will validate
44   its data structure to be valid value.
45 
46   @param[in]      DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().
47   @param[in]      Context         Points to an optional handler context which was specified when the
48                                   handler was registered.
49   @param[in, out] CommBuffer      A pointer to a collection of data in memory that will
50                                   be conveyed from a non-SMM environment into an SMM environment.
51   @param[in, out] CommBufferSize  The size of the CommBuffer.
52 
53   @retval EFI_SUCCESS             The interrupt was handled successfully.
54 
55 **/
56 EFI_STATUS
57 EFIAPI
PhysicalPresenceCallback(IN EFI_HANDLE DispatchHandle,IN CONST VOID * Context,IN OUT VOID * CommBuffer,IN OUT UINTN * CommBufferSize)58 PhysicalPresenceCallback (
59   IN EFI_HANDLE                  DispatchHandle,
60   IN CONST VOID                  *Context,
61   IN OUT VOID                    *CommBuffer,
62   IN OUT UINTN                   *CommBufferSize
63   )
64 {
65   UINT32                MostRecentRequest;
66   UINT32                Response;
67   UINT32                OperationRequest;
68   UINT32                RequestParameter;
69 
70 
71   if (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS) {
72     mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibReturnOperationResponseToOsFunction (
73                                              &MostRecentRequest,
74                                              &Response
75                                              );
76     mTcgNvs->PhysicalPresence.LastRequest = MostRecentRequest;
77     mTcgNvs->PhysicalPresence.Response = Response;
78     return EFI_SUCCESS;
79   } else if ((mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS)
80           || (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2)) {
81 
82     OperationRequest = mTcgNvs->PhysicalPresence.Request;
83     RequestParameter = mTcgNvs->PhysicalPresence.RequestParameter;
84     mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunctionEx (
85                                              &OperationRequest,
86                                              &RequestParameter
87                                              );
88     mTcgNvs->PhysicalPresence.Request = OperationRequest;
89     mTcgNvs->PhysicalPresence.RequestParameter = RequestParameter;
90   } else if (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST) {
91     mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibGetUserConfirmationStatusFunction (mTcgNvs->PPRequestUserConfirm);
92   }
93 
94   return EFI_SUCCESS;
95 }
96 
97 
98 /**
99   Software SMI callback for MemoryClear which is called from ACPI method.
100 
101   Caution: This function may receive untrusted input.
102   Variable and ACPINvs are external input, so this function will validate
103   its data structure to be valid value.
104 
105   @param[in]      DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().
106   @param[in]      Context         Points to an optional handler context which was specified when the
107                                   handler was registered.
108   @param[in, out] CommBuffer      A pointer to a collection of data in memory that will
109                                   be conveyed from a non-SMM environment into an SMM environment.
110   @param[in, out] CommBufferSize  The size of the CommBuffer.
111 
112   @retval EFI_SUCCESS             The interrupt was handled successfully.
113 
114 **/
115 EFI_STATUS
116 EFIAPI
MemoryClearCallback(IN EFI_HANDLE DispatchHandle,IN CONST VOID * Context,IN OUT VOID * CommBuffer,IN OUT UINTN * CommBufferSize)117 MemoryClearCallback (
118   IN EFI_HANDLE                  DispatchHandle,
119   IN CONST VOID                  *Context,
120   IN OUT VOID                    *CommBuffer,
121   IN OUT UINTN                   *CommBufferSize
122   )
123 {
124   EFI_STATUS                     Status;
125   UINTN                          DataSize;
126   UINT8                          MorControl;
127 
128   mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_SUCCESS;
129   if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE) {
130     MorControl = (UINT8) mTcgNvs->MemoryClear.Request;
131   } else if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_PTS_CLEAR_MOR_BIT) {
132     DataSize = sizeof (UINT8);
133     Status = mSmmVariable->SmmGetVariable (
134                              MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
135                              &gEfiMemoryOverwriteControlDataGuid,
136                              NULL,
137                              &DataSize,
138                              &MorControl
139                              );
140     if (EFI_ERROR (Status)) {
141       mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;
142       DEBUG ((EFI_D_ERROR, "[TPM] Get MOR variable failure! Status = %r\n", Status));
143       return EFI_SUCCESS;
144     }
145 
146     if (MOR_CLEAR_MEMORY_VALUE (MorControl) == 0x0) {
147       return EFI_SUCCESS;
148     }
149     MorControl &= ~MOR_CLEAR_MEMORY_BIT_MASK;
150   } else {
151     mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;
152     DEBUG ((EFI_D_ERROR, "[TPM] MOR Parameter error! Parameter = %x\n", mTcgNvs->MemoryClear.Parameter));
153     return EFI_SUCCESS;
154   }
155 
156   DataSize = sizeof (UINT8);
157   Status = mSmmVariable->SmmSetVariable (
158                            MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
159                            &gEfiMemoryOverwriteControlDataGuid,
160                            EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
161                            DataSize,
162                            &MorControl
163                            );
164   if (EFI_ERROR (Status)) {
165     mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;
166     DEBUG ((EFI_D_ERROR, "[TPM] Set MOR variable failure! Status = %r\n", Status));
167   }
168 
169   return EFI_SUCCESS;
170 }
171 
172 /**
173   Find the operation region in TCG ACPI table by given Name and Size,
174   and initialize it if the region is found.
175 
176   @param[in, out] Table          The TPM item in ACPI table.
177   @param[in]      Name           The name string to find in TPM table.
178   @param[in]      Size           The size of the region to find.
179 
180   @return                        The allocated address for the found region.
181 
182 **/
183 VOID *
AssignOpRegion(EFI_ACPI_DESCRIPTION_HEADER * Table,UINT32 Name,UINT16 Size)184 AssignOpRegion (
185   EFI_ACPI_DESCRIPTION_HEADER    *Table,
186   UINT32                         Name,
187   UINT16                         Size
188   )
189 {
190   EFI_STATUS                     Status;
191   AML_OP_REGION_32_8             *OpRegion;
192   EFI_PHYSICAL_ADDRESS           MemoryAddress;
193 
194   MemoryAddress = SIZE_4GB - 1;
195 
196   //
197   // Patch some pointers for the ASL code before loading the SSDT.
198   //
199   for (OpRegion  = (AML_OP_REGION_32_8 *) (Table + 1);
200        OpRegion <= (AML_OP_REGION_32_8 *) ((UINT8 *) Table + Table->Length);
201        OpRegion  = (AML_OP_REGION_32_8 *) ((UINT8 *) OpRegion + 1)) {
202     if ((OpRegion->OpRegionOp  == AML_EXT_REGION_OP) &&
203         (OpRegion->NameString  == Name) &&
204         (OpRegion->DWordPrefix == AML_DWORD_PREFIX) &&
205         (OpRegion->BytePrefix  == AML_BYTE_PREFIX)) {
206 
207       Status = gBS->AllocatePages(AllocateMaxAddress, EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (Size), &MemoryAddress);
208       ASSERT_EFI_ERROR (Status);
209       ZeroMem ((VOID *)(UINTN)MemoryAddress, Size);
210       OpRegion->RegionOffset = (UINT32) (UINTN) MemoryAddress;
211       OpRegion->RegionLen    = (UINT8) Size;
212       break;
213     }
214   }
215 
216   return (VOID *) (UINTN) MemoryAddress;
217 }
218 
219 /**
220   Patch version string of Physical Presence interface supported by platform. The initial string tag in TPM
221 ACPI table is "$PV".
222 
223   @param[in, out] Table          The TPM item in ACPI table.
224   @param[in]      PPVer          Version string of Physical Presence interface supported by platform.
225 
226   @return                        The allocated address for the found region.
227 
228 **/
229 EFI_STATUS
UpdatePPVersion(EFI_ACPI_DESCRIPTION_HEADER * Table,CHAR8 * PPVer)230 UpdatePPVersion (
231   EFI_ACPI_DESCRIPTION_HEADER    *Table,
232   CHAR8                          *PPVer
233   )
234 {
235   EFI_STATUS  Status;
236   UINT8       *DataPtr;
237 
238   //
239   // Patch some pointers for the ASL code before loading the SSDT.
240   //
241   for (DataPtr  = (UINT8 *)(Table + 1);
242        DataPtr <= (UINT8 *) ((UINT8 *) Table + Table->Length - PHYSICAL_PRESENCE_VERSION_SIZE);
243        DataPtr += 1) {
244     if (AsciiStrCmp((CHAR8 *)DataPtr,  PHYSICAL_PRESENCE_VERSION_TAG) == 0) {
245       Status = AsciiStrCpyS((CHAR8 *)DataPtr, PHYSICAL_PRESENCE_VERSION_SIZE, PPVer);
246       DEBUG((EFI_D_INFO, "TPM2 Physical Presence Interface Version update status 0x%x\n", Status));
247       return Status;
248     }
249   }
250 
251   return EFI_NOT_FOUND;
252 }
253 
254 /**
255   Patch interrupt resources returned by TPM _PRS. ResourceTemplate to patch is determined by input
256   interrupt buffer size. BufferSize, PkgLength and interrupt descirptor in ByteList need to be patched
257 
258   @param[in, out] Table            The TPM item in ACPI table.
259   @param[in]      IrqBuffer        Input new IRQ buffer.
260   @param[in]      IrqBuffserSize   Input new IRQ buffer size.
261   @param[out]     IsShortFormPkgLength   If _PRS returns Short length Package(ACPI spec 20.2.4).
262 
263   @return                          patch status.
264 
265 **/
266 EFI_STATUS
UpdatePossibleResource(IN OUT EFI_ACPI_DESCRIPTION_HEADER * Table,IN UINT32 * IrqBuffer,IN UINT32 IrqBuffserSize,OUT BOOLEAN * IsShortFormPkgLength)267 UpdatePossibleResource (
268   IN OUT  EFI_ACPI_DESCRIPTION_HEADER    *Table,
269   IN      UINT32                         *IrqBuffer,
270   IN      UINT32                         IrqBuffserSize,
271   OUT     BOOLEAN                        *IsShortFormPkgLength
272   )
273 {
274   UINT8       *DataPtr;
275   UINT8       *DataEndPtr;
276   UINT32      NewPkgLength;
277   UINT32      OrignalPkgLength;
278 
279   NewPkgLength     = 0;
280   OrignalPkgLength = 0;
281   DataEndPtr       = NULL;
282 
283   //
284   // Follow ACPI spec
285   //           6.4.3   Extend Interrupt Descriptor.
286   //           19.3.3 ASL Resource Template
287   //           20      AML specification
288   // to patch TPM ACPI object _PRS returned ResourceTemplate() containing 2 resource descriptors and an auto appended End Tag
289   //
290   //  AML data is organized by following rule.
291   //  Code need to patch BufferSize and PkgLength and interrupt descirptor in ByteList
292   //
293   // =============  Buffer ====================
294   //           DefBuffer := BufferOp PkgLength BufferSize ByteList
295   //            BufferOp := 0x11
296   //
297   // ==============PkgLength==================
298   //          PkgLength := PkgLeadByte |
299   //                              <PkgLeadByte ByteData> |
300   //                              <PkgLeadByte ByteData ByteData> |
301   //                              <PkgLeadByte ByteData ByteData ByteData>
302   //
303   //       PkgLeadByte := <bit 7-6: ByteData count that follows (0-3)>
304   //                               <bit 5-4: Only used if PkgLength <= 63 >
305   //                               <bit 3-0: Least significant package length nybble>
306   //
307   //==============BufferSize==================
308   //        BufferSize := Integar
309   //           Integar := ByteConst|WordConst|DwordConst....
310   //
311   //           ByteConst := BytePrefix ByteData
312   //
313   //==============ByteList===================
314   //          ByteList := ByteData ByteList
315   //
316   //=========================================
317 
318   //
319   // 1. Check TPM_PRS_RESS with PkgLength <=63 can hold the input interrupt number buffer for patching
320   //
321   for (DataPtr  = (UINT8 *)(Table + 1);
322        DataPtr < (UINT8 *) ((UINT8 *) Table + Table->Length - (TPM_PRS_RES_NAME_SIZE + TPM_POS_RES_TEMPLATE_MIN_SIZE));
323        DataPtr += 1) {
324     if (CompareMem(DataPtr, TPM_PRS_RESS, TPM_PRS_RES_NAME_SIZE) == 0) {
325       //
326       // Jump over object name & BufferOp
327       //
328       DataPtr += TPM_PRS_RES_NAME_SIZE + 1;
329 
330       if ((*DataPtr & (BIT7|BIT6)) == 0) {
331         OrignalPkgLength = (UINT32)*DataPtr;
332         DataEndPtr       = DataPtr + OrignalPkgLength;
333 
334         //
335         // Jump over PkgLength = PkgLeadByte only
336         //
337         NewPkgLength++;
338 
339         //
340         // Jump over BufferSize
341         //
342         if (*(DataPtr + 1) == AML_BYTE_PREFIX) {
343           NewPkgLength += 2;
344         } else if (*(DataPtr + 1) == AML_WORD_PREFIX) {
345           NewPkgLength += 3;
346         } else if (*(DataPtr + 1) == AML_DWORD_PREFIX) {
347           NewPkgLength += 5;
348         } else {
349           ASSERT(FALSE);
350           return EFI_UNSUPPORTED;
351         }
352       } else {
353         ASSERT(FALSE);
354         return EFI_UNSUPPORTED;
355       }
356 
357       //
358       // Include Memory32Fixed Descritor (12 Bytes) + Interrupt Descriptor header(5 Bytes) + End Tag(2 Bytes)
359       //
360       NewPkgLength += 19 + IrqBuffserSize;
361       if (NewPkgLength > 63) {
362         break;
363       }
364 
365       if (NewPkgLength > OrignalPkgLength) {
366         ASSERT(FALSE);
367         return EFI_INVALID_PARAMETER;
368       }
369 
370       //
371       // 1.1 Patch PkgLength
372       //
373       *DataPtr = (UINT8)NewPkgLength;
374 
375       //
376       // 1.2 Patch BufferSize = sizeof(Memory32Fixed Descritor + Interrupt Descriptor + End Tag).
377       //      It is Little endian. So only patch lowest byte of BufferSize due to current interrupt number limit.
378       //
379       *(DataPtr + 2) = (UINT8)(IrqBuffserSize + 19);
380 
381       //
382       // Notify _PRS to report short formed ResourceTemplate
383       //
384       *IsShortFormPkgLength = TRUE;
385 
386       break;
387     }
388   }
389 
390   //
391   // 2. Use TPM_PRS_RESL with PkgLength > 63 to hold longer input interrupt number buffer for patching
392   //
393   if (NewPkgLength > 63) {
394     NewPkgLength     = 0;
395     OrignalPkgLength = 0;
396     for (DataPtr  = (UINT8 *)(Table + 1);
397          DataPtr < (UINT8 *) ((UINT8 *) Table + Table->Length - (TPM_PRS_RES_NAME_SIZE + TPM_POS_RES_TEMPLATE_MIN_SIZE));
398          DataPtr += 1) {
399       if (CompareMem(DataPtr, TPM_PRS_RESL, TPM_PRS_RES_NAME_SIZE) == 0) {
400         //
401         // Jump over object name & BufferOp
402         //
403         DataPtr += TPM_PRS_RES_NAME_SIZE + 1;
404 
405         if ((*DataPtr & (BIT7|BIT6)) != 0) {
406           OrignalPkgLength = (UINT32)(*(DataPtr + 1) << 4) + (*DataPtr & 0x0F);
407           DataEndPtr       = DataPtr + OrignalPkgLength;
408           //
409           // Jump over PkgLength = PkgLeadByte + ByteData length
410           //
411           NewPkgLength += 1 + ((*DataPtr & (BIT7|BIT6)) >> 6);
412 
413           //
414           // Jump over BufferSize
415           //
416           if (*(DataPtr + NewPkgLength) == AML_BYTE_PREFIX) {
417             NewPkgLength += 2;
418           } else if (*(DataPtr + NewPkgLength) == AML_WORD_PREFIX) {
419             NewPkgLength += 3;
420           } else if (*(DataPtr + NewPkgLength) == AML_DWORD_PREFIX) {
421             NewPkgLength += 5;
422           } else {
423             ASSERT(FALSE);
424             return EFI_UNSUPPORTED;
425           }
426         } else {
427           ASSERT(FALSE);
428           return EFI_UNSUPPORTED;
429         }
430 
431         //
432         // Include Memory32Fixed Descritor (12 Bytes) + Interrupt Descriptor header(5 Bytes) + End Tag(2  Bytes)
433         //
434         NewPkgLength += 19 + IrqBuffserSize;
435 
436         if (NewPkgLength > OrignalPkgLength) {
437           ASSERT(FALSE);
438           return EFI_INVALID_PARAMETER;
439         }
440 
441         //
442         // 2.1 Patch PkgLength. Only patch PkgLeadByte and first ByteData
443         //
444         *DataPtr = (UINT8)((*DataPtr) & 0xF0) | (NewPkgLength & 0x0F);
445         *(DataPtr + 1) = (UINT8)((NewPkgLength & 0xFF0) >> 4);
446 
447         //
448         // 2.2 Patch BufferSize = sizeof(Memory32Fixed Descritor + Interrupt Descriptor + End Tag).
449         //     It is Little endian. Only patch lowest byte of BufferSize due to current interrupt number limit.
450         //
451         *(DataPtr + 2 + ((*DataPtr & (BIT7|BIT6)) >> 6)) = (UINT8)(IrqBuffserSize + 19);
452 
453         //
454         // Notify _PRS to report long formed ResourceTemplate
455         //
456         *IsShortFormPkgLength = FALSE;
457         break;
458       }
459     }
460   }
461 
462   if (DataPtr >= (UINT8 *) ((UINT8 *) Table + Table->Length - (TPM_PRS_RES_NAME_SIZE + TPM_POS_RES_TEMPLATE_MIN_SIZE))) {
463     return EFI_NOT_FOUND;
464   }
465 
466   //
467   // 3. Move DataPtr to Interrupt descriptor header and patch interrupt descriptor.
468   //     5 bytes for interrupt descriptor header, 2 bytes for End Tag
469   //
470   DataPtr += NewPkgLength - (5 + IrqBuffserSize + 2);
471   //
472   //   3.1 Patch Length bit[7:0] of Interrupt descirptor patch interrupt descriptor
473   //
474   *(DataPtr + 1) = (UINT8)(2 + IrqBuffserSize);
475   //
476   //   3.2 Patch Interrupt Table Length
477   //
478   *(DataPtr + 4) = (UINT8)(IrqBuffserSize / sizeof(UINT32));
479   //
480   //   3.3 Copy patched InterruptNumBuffer
481   //
482   CopyMem(DataPtr + 5, IrqBuffer, IrqBuffserSize);
483 
484   //
485   // 4. Jump over Interrupt descirptor and Patch END Tag, set Checksum field to 0
486   //
487   DataPtr       += 5 + IrqBuffserSize;
488   *DataPtr       = ACPI_END_TAG_DESCRIPTOR;
489   *(DataPtr + 1) = 0;
490 
491   //
492   // 5. Jump over new ResourceTemplate. Stuff rest bytes to NOOP
493   //
494   DataPtr += 2;
495   if (DataPtr < DataEndPtr) {
496     SetMem(DataPtr, (UINTN)DataEndPtr - (UINTN)DataPtr, AML_NOOP_OP);
497   }
498 
499   return EFI_SUCCESS;
500 }
501 
502 /**
503   Patch TPM2 device HID string.  The initial string tag in TPM2 ACPI table is "NNN0000".
504 
505   @param[in, out] Table          The TPM2 SSDT ACPI table.
506 
507   @return                               HID Update status.
508 
509 **/
510 EFI_STATUS
UpdateHID(EFI_ACPI_DESCRIPTION_HEADER * Table)511 UpdateHID (
512   EFI_ACPI_DESCRIPTION_HEADER    *Table
513   )
514 {
515   EFI_STATUS  Status;
516   UINT8       *DataPtr;
517   CHAR8       Hid[TPM_HID_ACPI_SIZE];
518   UINT32      ManufacturerID;
519   UINT32      FirmwareVersion1;
520   UINT32      FirmwareVersion2;
521   BOOLEAN     PnpHID;
522 
523   PnpHID = TRUE;
524 
525   //
526   // Initialize HID with Default PNP string
527   //
528   ZeroMem(Hid, TPM_HID_ACPI_SIZE);
529 
530   //
531   // Get Manufacturer ID
532   //
533   Status = Tpm2GetCapabilityManufactureID(&ManufacturerID);
534   if (!EFI_ERROR(Status)) {
535     DEBUG((EFI_D_INFO, "TPM_PT_MANUFACTURER 0x%08x\n", ManufacturerID));
536     //
537     // ManufacturerID defined in TCG Vendor ID Registry
538     // may tailed with 0x00 or 0x20
539     //
540     if ((ManufacturerID >> 24) == 0x00 || ((ManufacturerID >> 24) == 0x20)) {
541       //
542       //  HID containing PNP ID "NNN####"
543       //   NNN is uppercase letter for Vendor ID specified by manufacturer
544       //
545       CopyMem(Hid, &ManufacturerID, 3);
546     } else {
547       //
548       //  HID containing ACP ID "NNNN####"
549       //   NNNN is uppercase letter for Vendor ID specified by manufacturer
550       //
551       CopyMem(Hid, &ManufacturerID, 4);
552       PnpHID = FALSE;
553     }
554   } else {
555     DEBUG ((EFI_D_ERROR, "Get TPM_PT_MANUFACTURER failed %x!\n", Status));
556     ASSERT(FALSE);
557     return Status;
558   }
559 
560   Status = Tpm2GetCapabilityFirmwareVersion(&FirmwareVersion1, &FirmwareVersion2);
561   if (!EFI_ERROR(Status)) {
562     DEBUG((EFI_D_INFO, "TPM_PT_FIRMWARE_VERSION_1 0x%x\n", FirmwareVersion1));
563     DEBUG((EFI_D_INFO, "TPM_PT_FIRMWARE_VERSION_2 0x%x\n", FirmwareVersion2));
564     //
565     //   #### is Firmware Version 1
566     //
567     if (PnpHID) {
568       AsciiSPrint(Hid + 3, TPM_HID_PNP_SIZE - 3, "%02d%02d", ((FirmwareVersion1 & 0xFFFF0000) >> 16), (FirmwareVersion1 & 0x0000FFFF));
569     } else {
570       AsciiSPrint(Hid + 4, TPM_HID_ACPI_SIZE - 4, "%02d%02d", ((FirmwareVersion1 & 0xFFFF0000) >> 16), (FirmwareVersion1 & 0x0000FFFF));
571     }
572 
573   } else {
574     DEBUG ((EFI_D_ERROR, "Get TPM_PT_FIRMWARE_VERSION_X failed %x!\n", Status));
575     ASSERT(FALSE);
576     return Status;
577   }
578 
579   //
580   // Patch HID in ASL code before loading the SSDT.
581   //
582   for (DataPtr  = (UINT8 *)(Table + 1);
583        DataPtr <= (UINT8 *) ((UINT8 *) Table + Table->Length - TPM_HID_PNP_SIZE);
584        DataPtr += 1) {
585     if (AsciiStrCmp((CHAR8 *)DataPtr,  TPM_HID_TAG) == 0) {
586       if (PnpHID) {
587         CopyMem(DataPtr, Hid, TPM_HID_PNP_SIZE);
588         //
589         // if HID is PNP ID, patch the last byte in HID TAG to Noop
590         //
591         *(DataPtr + TPM_HID_PNP_SIZE) = AML_NOOP_OP;
592       } else {
593 
594         CopyMem(DataPtr, Hid, TPM_HID_ACPI_SIZE);
595       }
596       DEBUG((DEBUG_INFO, "TPM2 ACPI _HID is patched to %a\n", DataPtr));
597 
598       return Status;
599     }
600   }
601 
602   DEBUG((EFI_D_ERROR, "TPM2 ACPI HID TAG for patch not found!\n"));
603   return EFI_NOT_FOUND;
604 }
605 
606 /**
607   Initialize and publish TPM items in ACPI table.
608 
609   @retval   EFI_SUCCESS     The TCG ACPI table is published successfully.
610   @retval   Others          The TCG ACPI table is not published.
611 
612 **/
613 EFI_STATUS
PublishAcpiTable(VOID)614 PublishAcpiTable (
615   VOID
616   )
617 {
618   EFI_STATUS                     Status;
619   EFI_ACPI_TABLE_PROTOCOL        *AcpiTable;
620   UINTN                          TableKey;
621   EFI_ACPI_DESCRIPTION_HEADER    *Table;
622   UINTN                          TableSize;
623   UINT32                         *PossibleIrqNumBuf;
624   UINT32                         PossibleIrqNumBufSize;
625   BOOLEAN                        IsShortFormPkgLength;
626 
627   IsShortFormPkgLength = FALSE;
628 
629   Status = GetSectionFromFv (
630              &gEfiCallerIdGuid,
631              EFI_SECTION_RAW,
632              0,
633              (VOID **) &Table,
634              &TableSize
635              );
636   ASSERT_EFI_ERROR (Status);
637 
638   //
639   // Update Table version before measuring it to PCR
640   //
641   Status = UpdatePPVersion(Table, (CHAR8 *)PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer));
642   ASSERT_EFI_ERROR (Status);
643 
644   DEBUG ((
645     DEBUG_INFO,
646     "Current physical presence interface version - %a\n",
647     (CHAR8 *) PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer)
648     ));
649 
650   //
651   // Update TPM2 HID before measuring it to PCR
652   //
653   Status = UpdateHID(Table);
654   if (EFI_ERROR(Status)) {
655     return Status;
656   }
657 
658   if (PcdGet32(PcdTpm2CurrentIrqNum) != 0) {
659     //
660     // Patch _PRS interrupt resource only when TPM interrupt is supported
661     //
662     PossibleIrqNumBuf     = (UINT32 *)PcdGetPtr(PcdTpm2PossibleIrqNumBuf);
663     PossibleIrqNumBufSize = (UINT32)PcdGetSize(PcdTpm2PossibleIrqNumBuf);
664 
665     if (PossibleIrqNumBufSize <= MAX_PRS_INT_BUF_SIZE && (PossibleIrqNumBufSize % sizeof(UINT32)) == 0) {
666       Status = UpdatePossibleResource(Table, PossibleIrqNumBuf, PossibleIrqNumBufSize, &IsShortFormPkgLength);
667       DEBUG ((
668         DEBUG_INFO,
669         "UpdatePossibleResource status - %x. TPM2 service may not ready in OS.\n",
670         Status
671         ));
672     } else {
673       DEBUG ((
674         DEBUG_INFO,
675         "PcdTpm2PossibleIrqNumBuf size %x is not correct. TPM2 service may not ready in OS.\n",
676         PossibleIrqNumBufSize
677       ));
678     }
679   }
680 
681   //
682   // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
683   //
684   TpmMeasureAndLogData(
685     0,
686     EV_POST_CODE,
687     EV_POSTCODE_INFO_ACPI_DATA,
688     ACPI_DATA_LEN,
689     Table,
690     TableSize
691     );
692 
693 
694   ASSERT (Table->OemTableId == SIGNATURE_64 ('T', 'p', 'm', '2', 'T', 'a', 'b', 'l'));
695   CopyMem (Table->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (Table->OemId) );
696   mTcgNvs = AssignOpRegion (Table, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16) sizeof (TCG_NVS));
697   ASSERT (mTcgNvs != NULL);
698   mTcgNvs->TpmIrqNum            = PcdGet32(PcdTpm2CurrentIrqNum);
699   mTcgNvs->IsShortFormPkgLength = IsShortFormPkgLength;
700 
701   //
702   // Publish the TPM ACPI table. Table is re-checksumed.
703   //
704   Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
705   ASSERT_EFI_ERROR (Status);
706 
707   TableKey = 0;
708   Status = AcpiTable->InstallAcpiTable (
709                         AcpiTable,
710                         Table,
711                         TableSize,
712                         &TableKey
713                         );
714   ASSERT_EFI_ERROR (Status);
715 
716   return Status;
717 }
718 
719 /**
720   Publish TPM2 ACPI table
721 
722   @retval   EFI_SUCCESS     The TPM2 ACPI table is published successfully.
723   @retval   Others          The TPM2 ACPI table is not published.
724 
725 **/
726 EFI_STATUS
PublishTpm2(VOID)727 PublishTpm2 (
728   VOID
729   )
730 {
731   EFI_STATUS                     Status;
732   EFI_ACPI_TABLE_PROTOCOL        *AcpiTable;
733   UINTN                          TableKey;
734   UINT64                         OemTableId;
735   EFI_TPM2_ACPI_CONTROL_AREA     *ControlArea;
736   TPM2_PTP_INTERFACE_TYPE        InterfaceType;
737 
738   mTpm2AcpiTemplate.Header.Revision = PcdGet8(PcdTpm2AcpiTableRev);
739   DEBUG((DEBUG_INFO, "Tpm2 ACPI table revision is %d\n", mTpm2AcpiTemplate.Header.Revision));
740 
741   //
742   // PlatformClass is only valid for version 4 and above
743   //    BIT0~15:  PlatformClass
744   //    BIT16~31: Reserved
745   //
746   if (mTpm2AcpiTemplate.Header.Revision >= EFI_TPM2_ACPI_TABLE_REVISION_4) {
747     mTpm2AcpiTemplate.Flags = (mTpm2AcpiTemplate.Flags & 0xFFFF0000) | PcdGet8(PcdTpmPlatformClass);
748     DEBUG((DEBUG_INFO, "Tpm2 ACPI table PlatformClass is %d\n", (mTpm2AcpiTemplate.Flags & 0x0000FFFF)));
749   }
750 
751   //
752   // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
753   //
754   TpmMeasureAndLogData(
755     0,
756     EV_POST_CODE,
757     EV_POSTCODE_INFO_ACPI_DATA,
758     ACPI_DATA_LEN,
759     &mTpm2AcpiTemplate,
760     sizeof(mTpm2AcpiTemplate)
761     );
762 
763   InterfaceType = PcdGet8(PcdActiveTpmInterfaceType);
764   switch (InterfaceType) {
765   case Tpm2PtpInterfaceCrb:
766     mTpm2AcpiTemplate.StartMethod = EFI_TPM2_ACPI_TABLE_START_METHOD_COMMAND_RESPONSE_BUFFER_INTERFACE;
767     mTpm2AcpiTemplate.AddressOfControlArea = PcdGet64 (PcdTpmBaseAddress) + 0x40;
768     ControlArea = (EFI_TPM2_ACPI_CONTROL_AREA *)(UINTN)mTpm2AcpiTemplate.AddressOfControlArea;
769     ControlArea->CommandSize  = 0xF80;
770     ControlArea->ResponseSize = 0xF80;
771     ControlArea->Command      = PcdGet64 (PcdTpmBaseAddress) + 0x80;
772     ControlArea->Response     = PcdGet64 (PcdTpmBaseAddress) + 0x80;
773     break;
774   case Tpm2PtpInterfaceFifo:
775   case Tpm2PtpInterfaceTis:
776     break;
777   default:
778     DEBUG((EFI_D_ERROR, "TPM2 InterfaceType get error! %d\n", InterfaceType));
779     break;
780   }
781 
782   CopyMem (mTpm2AcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mTpm2AcpiTemplate.Header.OemId));
783   OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
784   CopyMem (&mTpm2AcpiTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64));
785   mTpm2AcpiTemplate.Header.OemRevision      = PcdGet32 (PcdAcpiDefaultOemRevision);
786   mTpm2AcpiTemplate.Header.CreatorId        = PcdGet32 (PcdAcpiDefaultCreatorId);
787   mTpm2AcpiTemplate.Header.CreatorRevision  = PcdGet32 (PcdAcpiDefaultCreatorRevision);
788 
789   //
790   // Construct ACPI table
791   //
792   Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
793   ASSERT_EFI_ERROR (Status);
794 
795   Status = AcpiTable->InstallAcpiTable (
796                         AcpiTable,
797                         &mTpm2AcpiTemplate,
798                         sizeof(mTpm2AcpiTemplate),
799                         &TableKey
800                         );
801   ASSERT_EFI_ERROR (Status);
802 
803   return Status;
804 }
805 
806 /**
807   The driver's entry point.
808 
809   It install callbacks for TPM physical presence and MemoryClear, and locate
810   SMM variable to be used in the callback function.
811 
812   @param[in] ImageHandle  The firmware allocated handle for the EFI image.
813   @param[in] SystemTable  A pointer to the EFI System Table.
814 
815   @retval EFI_SUCCESS     The entry point is executed successfully.
816   @retval Others          Some error occurs when executing this entry point.
817 
818 **/
819 EFI_STATUS
820 EFIAPI
InitializeTcgSmm(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)821 InitializeTcgSmm (
822   IN EFI_HANDLE                  ImageHandle,
823   IN EFI_SYSTEM_TABLE            *SystemTable
824   )
825 {
826   EFI_STATUS                     Status;
827   EFI_SMM_SW_DISPATCH2_PROTOCOL  *SwDispatch;
828   EFI_SMM_SW_REGISTER_CONTEXT    SwContext;
829   EFI_HANDLE                     SwHandle;
830 
831   if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm20DtpmGuid)){
832     DEBUG ((EFI_D_ERROR, "No TPM2 DTPM instance required!\n"));
833     return EFI_UNSUPPORTED;
834   }
835 
836   Status = PublishAcpiTable ();
837   ASSERT_EFI_ERROR (Status);
838 
839   //
840   // Get the Sw dispatch protocol and register SMI callback functions.
841   //
842   Status = gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID**)&SwDispatch);
843   ASSERT_EFI_ERROR (Status);
844   SwContext.SwSmiInputValue = (UINTN) -1;
845   Status = SwDispatch->Register (SwDispatch, PhysicalPresenceCallback, &SwContext, &SwHandle);
846   ASSERT_EFI_ERROR (Status);
847   if (EFI_ERROR (Status)) {
848     return Status;
849   }
850   mTcgNvs->PhysicalPresence.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;
851 
852   SwContext.SwSmiInputValue = (UINTN) -1;
853   Status = SwDispatch->Register (SwDispatch, MemoryClearCallback, &SwContext, &SwHandle);
854   ASSERT_EFI_ERROR (Status);
855   if (EFI_ERROR (Status)) {
856     return Status;
857   }
858   mTcgNvs->MemoryClear.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;
859 
860   //
861   // Locate SmmVariableProtocol.
862   //
863   Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mSmmVariable);
864   ASSERT_EFI_ERROR (Status);
865 
866   //
867   // Set TPM2 ACPI table
868   //
869   Status = PublishTpm2 ();
870   ASSERT_EFI_ERROR (Status);
871 
872 
873   return EFI_SUCCESS;
874 }
875 
876