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