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