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