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