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