]> git.proxmox.com Git - mirror_edk2.git/blame - SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.c
SecurityPkg: Fix spelling errors
[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
cd643013
ZC
654 //\r
655 // Update Table version before measuring it to PCR\r
656 //\r
657 Status = UpdatePPVersion(Table, (CHAR8 *)PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer));\r
658 ASSERT_EFI_ERROR (Status);\r
1abfa4ce 659\r
dd6d0a52
SZ
660 DEBUG ((\r
661 DEBUG_INFO,\r
662 "Current physical presence interface version - %a\n",\r
663 (CHAR8 *) PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer)\r
664 ));\r
665\r
73126ac2
ZC
666 //\r
667 // Update TPM2 HID before measuring it to PCR\r
668 //\r
669 Status = UpdateHID(Table);\r
670 if (EFI_ERROR(Status)) {\r
671 return Status;\r
672 }\r
673\r
c4122dca
ZC
674 if (PcdGet32(PcdTpm2CurrentIrqNum) != 0) {\r
675 //\r
676 // Patch _PRS interrupt resource only when TPM interrupt is supported\r
677 //\r
678 PossibleIrqNumBuf = (UINT32 *)PcdGetPtr(PcdTpm2PossibleIrqNumBuf);\r
679 PossibleIrqNumBufSize = (UINT32)PcdGetSize(PcdTpm2PossibleIrqNumBuf);\r
680\r
681 if (PossibleIrqNumBufSize <= MAX_PRS_INT_BUF_SIZE && (PossibleIrqNumBufSize % sizeof(UINT32)) == 0) {\r
1ea08a3d 682 Status = UpdatePossibleResource(Table, PossibleIrqNumBuf, PossibleIrqNumBufSize, &IsShortFormPkgLength);\r
c4122dca
ZC
683 DEBUG ((\r
684 DEBUG_INFO,\r
685 "UpdatePossibleResource status - %x. TPM2 service may not ready in OS.\n",\r
686 Status\r
687 ));\r
688 } else {\r
689 DEBUG ((\r
690 DEBUG_INFO,\r
691 "PcdTpm2PossibleIrqNumBuf size %x is not correct. TPM2 service may not ready in OS.\n",\r
692 PossibleIrqNumBufSize\r
693 ));\r
694 }\r
695 }\r
696\r
1abfa4ce
JY
697 //\r
698 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA\r
699 //\r
700 TpmMeasureAndLogData(\r
701 0,\r
702 EV_POST_CODE,\r
703 EV_POSTCODE_INFO_ACPI_DATA,\r
704 ACPI_DATA_LEN,\r
705 Table,\r
706 TableSize\r
707 );\r
708\r
709\r
710 ASSERT (Table->OemTableId == SIGNATURE_64 ('T', 'p', 'm', '2', 'T', 'a', 'b', 'l'));\r
711 CopyMem (Table->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (Table->OemId) );\r
712 mTcgNvs = AssignOpRegion (Table, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16) sizeof (TCG_NVS));\r
713 ASSERT (mTcgNvs != NULL);\r
c4122dca 714 mTcgNvs->TpmIrqNum = PcdGet32(PcdTpm2CurrentIrqNum);\r
1ea08a3d 715 mTcgNvs->IsShortFormPkgLength = IsShortFormPkgLength;\r
1abfa4ce
JY
716\r
717 //\r
d6b926e7 718 // Publish the TPM ACPI table. Table is re-checksummed.\r
1abfa4ce
JY
719 //\r
720 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);\r
721 ASSERT_EFI_ERROR (Status);\r
722\r
723 TableKey = 0;\r
724 Status = AcpiTable->InstallAcpiTable (\r
725 AcpiTable,\r
726 Table,\r
727 TableSize,\r
728 &TableKey\r
729 );\r
730 ASSERT_EFI_ERROR (Status);\r
731\r
732 return Status;\r
733}\r
734\r
735/**\r
736 Publish TPM2 ACPI table\r
737\r
738 @retval EFI_SUCCESS The TPM2 ACPI table is published successfully.\r
739 @retval Others The TPM2 ACPI table is not published.\r
740\r
741**/\r
742EFI_STATUS\r
743PublishTpm2 (\r
744 VOID\r
745 )\r
746{\r
747 EFI_STATUS Status;\r
748 EFI_ACPI_TABLE_PROTOCOL *AcpiTable;\r
749 UINTN TableKey;\r
750 UINT64 OemTableId;\r
d967d6d9 751 EFI_TPM2_ACPI_CONTROL_AREA *ControlArea;\r
f15cb995 752 TPM2_PTP_INTERFACE_TYPE InterfaceType;\r
1abfa4ce 753\r
fca42289
ZC
754 mTpm2AcpiTemplate.Header.Revision = PcdGet8(PcdTpm2AcpiTableRev);\r
755 DEBUG((DEBUG_INFO, "Tpm2 ACPI table revision is %d\n", mTpm2AcpiTemplate.Header.Revision));\r
756\r
bf3b7aae
ZC
757 //\r
758 // PlatformClass is only valid for version 4 and above\r
b3548d32 759 // BIT0~15: PlatformClass\r
bf3b7aae
ZC
760 // BIT16~31: Reserved\r
761 //\r
762 if (mTpm2AcpiTemplate.Header.Revision >= EFI_TPM2_ACPI_TABLE_REVISION_4) {\r
763 mTpm2AcpiTemplate.Flags = (mTpm2AcpiTemplate.Flags & 0xFFFF0000) | PcdGet8(PcdTpmPlatformClass);\r
764 DEBUG((DEBUG_INFO, "Tpm2 ACPI table PlatformClass is %d\n", (mTpm2AcpiTemplate.Flags & 0x0000FFFF)));\r
765 }\r
766\r
a7e2d201
JY
767 mTpm2AcpiTemplate.Laml = PcdGet32(PcdTpm2AcpiTableLaml);\r
768 mTpm2AcpiTemplate.Lasa = PcdGet64(PcdTpm2AcpiTableLasa);\r
769 if ((mTpm2AcpiTemplate.Header.Revision < EFI_TPM2_ACPI_TABLE_REVISION_4) ||\r
770 (mTpm2AcpiTemplate.Laml == 0) || (mTpm2AcpiTemplate.Lasa == 0)) {\r
771 //\r
772 // If version is smaller than 4 or Laml/Lasa is not valid, rollback to original Length.\r
773 //\r
774 mTpm2AcpiTemplate.Header.Length = sizeof(EFI_TPM2_ACPI_TABLE);\r
775 }\r
776\r
1abfa4ce
JY
777 //\r
778 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA\r
779 //\r
780 TpmMeasureAndLogData(\r
781 0,\r
782 EV_POST_CODE,\r
783 EV_POSTCODE_INFO_ACPI_DATA,\r
784 ACPI_DATA_LEN,\r
785 &mTpm2AcpiTemplate,\r
a7e2d201 786 mTpm2AcpiTemplate.Header.Length\r
1abfa4ce
JY
787 );\r
788\r
f15cb995 789 InterfaceType = PcdGet8(PcdActiveTpmInterfaceType);\r
d967d6d9 790 switch (InterfaceType) {\r
f15cb995 791 case Tpm2PtpInterfaceCrb:\r
d967d6d9
JY
792 mTpm2AcpiTemplate.StartMethod = EFI_TPM2_ACPI_TABLE_START_METHOD_COMMAND_RESPONSE_BUFFER_INTERFACE;\r
793 mTpm2AcpiTemplate.AddressOfControlArea = PcdGet64 (PcdTpmBaseAddress) + 0x40;\r
794 ControlArea = (EFI_TPM2_ACPI_CONTROL_AREA *)(UINTN)mTpm2AcpiTemplate.AddressOfControlArea;\r
795 ControlArea->CommandSize = 0xF80;\r
796 ControlArea->ResponseSize = 0xF80;\r
797 ControlArea->Command = PcdGet64 (PcdTpmBaseAddress) + 0x80;\r
798 ControlArea->Response = PcdGet64 (PcdTpmBaseAddress) + 0x80;\r
799 break;\r
f15cb995
ZC
800 case Tpm2PtpInterfaceFifo:\r
801 case Tpm2PtpInterfaceTis:\r
d967d6d9
JY
802 break;\r
803 default:\r
3b5624b0 804 DEBUG((EFI_D_ERROR, "TPM2 InterfaceType get error! %d\n", InterfaceType));\r
d967d6d9
JY
805 break;\r
806 }\r
807\r
1abfa4ce
JY
808 CopyMem (mTpm2AcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mTpm2AcpiTemplate.Header.OemId));\r
809 OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);\r
810 CopyMem (&mTpm2AcpiTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64));\r
811 mTpm2AcpiTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);\r
812 mTpm2AcpiTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);\r
813 mTpm2AcpiTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);\r
814\r
815 //\r
816 // Construct ACPI table\r
817 //\r
818 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);\r
819 ASSERT_EFI_ERROR (Status);\r
820\r
821 Status = AcpiTable->InstallAcpiTable (\r
822 AcpiTable,\r
823 &mTpm2AcpiTemplate,\r
a7e2d201 824 mTpm2AcpiTemplate.Header.Length,\r
1abfa4ce
JY
825 &TableKey\r
826 );\r
827 ASSERT_EFI_ERROR (Status);\r
828\r
829 return Status;\r
830}\r
831\r
832/**\r
833 The driver's entry point.\r
834\r
b3548d32 835 It install callbacks for TPM physical presence and MemoryClear, and locate\r
1abfa4ce
JY
836 SMM variable to be used in the callback function.\r
837\r
b3548d32 838 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
1abfa4ce 839 @param[in] SystemTable A pointer to the EFI System Table.\r
b3548d32 840\r
1abfa4ce
JY
841 @retval EFI_SUCCESS The entry point is executed successfully.\r
842 @retval Others Some error occurs when executing this entry point.\r
843\r
844**/\r
845EFI_STATUS\r
846EFIAPI\r
847InitializeTcgSmm (\r
848 IN EFI_HANDLE ImageHandle,\r
849 IN EFI_SYSTEM_TABLE *SystemTable\r
850 )\r
851{\r
852 EFI_STATUS Status;\r
853 EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;\r
854 EFI_SMM_SW_REGISTER_CONTEXT SwContext;\r
855 EFI_HANDLE SwHandle;\r
856\r
857 if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm20DtpmGuid)){\r
858 DEBUG ((EFI_D_ERROR, "No TPM2 DTPM instance required!\n"));\r
859 return EFI_UNSUPPORTED;\r
860 }\r
861\r
862 Status = PublishAcpiTable ();\r
863 ASSERT_EFI_ERROR (Status);\r
864\r
865 //\r
866 // Get the Sw dispatch protocol and register SMI callback functions.\r
867 //\r
868 Status = gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID**)&SwDispatch);\r
869 ASSERT_EFI_ERROR (Status);\r
870 SwContext.SwSmiInputValue = (UINTN) -1;\r
871 Status = SwDispatch->Register (SwDispatch, PhysicalPresenceCallback, &SwContext, &SwHandle);\r
872 ASSERT_EFI_ERROR (Status);\r
873 if (EFI_ERROR (Status)) {\r
874 return Status;\r
875 }\r
876 mTcgNvs->PhysicalPresence.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;\r
877\r
878 SwContext.SwSmiInputValue = (UINTN) -1;\r
879 Status = SwDispatch->Register (SwDispatch, MemoryClearCallback, &SwContext, &SwHandle);\r
880 ASSERT_EFI_ERROR (Status);\r
881 if (EFI_ERROR (Status)) {\r
882 return Status;\r
883 }\r
884 mTcgNvs->MemoryClear.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;\r
b3548d32 885\r
1abfa4ce
JY
886 //\r
887 // Locate SmmVariableProtocol.\r
888 //\r
889 Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mSmmVariable);\r
890 ASSERT_EFI_ERROR (Status);\r
891\r
892 //\r
893 // Set TPM2 ACPI table\r
894 //\r
895 Status = PublishTpm2 ();\r
896 ASSERT_EFI_ERROR (Status);\r
897\r
898\r
899 return EFI_SUCCESS;\r
900}\r
901\r