]> git.proxmox.com Git - mirror_edk2.git/blame - SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.c
BaseTools: Separate HOST and PREFIX env for GCC tool chain
[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
313\r
314 @return patch status.\r
315\r
316**/\r
317EFI_STATUS\r
318UpdatePossibleResource (\r
319 EFI_ACPI_DESCRIPTION_HEADER *Table,\r
320 UINT32 *IrqBuffer,\r
321 UINT32 IrqBuffserSize\r
322 )\r
323{\r
324 UINT8 *DataPtr;\r
325 UINT8 *DataEndPtr;\r
326 UINT32 NewPkgLength;\r
327 UINT32 OrignalPkgLength;\r
328\r
329 NewPkgLength = 0;\r
330 OrignalPkgLength = 0;\r
331 DataEndPtr = NULL;\r
332\r
333 //\r
334 // Follow ACPI spec\r
335 // 6.4.3 Extend Interrupt Descriptor.\r
336 // 19.3.3 ASL Resource Template\r
337 // 20 AML specification\r
338 // to patch TPM ACPI object _PRS returned ResourceTemplate() containing 2 resource descriptors and an auto appended End Tag\r
339 //\r
340 // AML data is organized by following rule.\r
341 // Code need to patch BufferSize and PkgLength and interrupt descirptor in ByteList\r
342 //\r
343 // ============= Buffer ====================\r
344 // DefBuffer := BufferOp PkgLength BufferSize ByteList\r
345 // BufferOp := 0x11\r
346 //\r
347 // ==============PkgLength==================\r
348 // PkgLength := PkgLeadByte |\r
349 // <PkgLeadByte ByteData> |\r
350 // <PkgLeadByte ByteData ByteData> |\r
351 // <PkgLeadByte ByteData ByteData ByteData>\r
352 //\r
353 // PkgLeadByte := <bit 7-6: ByteData count that follows (0-3)>\r
354 // <bit 5-4: Only used if PkgLength <= 63 >\r
355 // <bit 3-0: Least significant package length nybble>\r
356 //\r
357 //==============BufferSize==================\r
358 // BufferSize := Integar\r
359 // Integar := ByteConst|WordConst|DwordConst....\r
360 //\r
361 // ByteConst := BytePrefix ByteData\r
362 //\r
363 //==============ByteList===================\r
364 // ByteList := ByteData ByteList\r
365 //\r
366 //=========================================\r
367\r
368 //\r
369 // 1. Check TPM_PRS_RESS with PkgLength <=63 can hold the input interrupt number buffer for patching\r
370 //\r
371 for (DataPtr = (UINT8 *)(Table + 1);\r
372 DataPtr < (UINT8 *) ((UINT8 *) Table + Table->Length - (TPM_PRS_RES_NAME_SIZE + TPM_POS_RES_TEMPLATE_MIN_SIZE));\r
373 DataPtr += 1) {\r
374 if (CompareMem(DataPtr, TPM_PRS_RESS, TPM_PRS_RES_NAME_SIZE) == 0) {\r
375 //\r
376 // Jump over object name & BufferOp\r
377 //\r
378 DataPtr += TPM_PRS_RES_NAME_SIZE + 1;\r
379\r
380 if ((*DataPtr & (BIT7|BIT6)) == 0) {\r
381 OrignalPkgLength = (UINT32)*DataPtr;\r
382 DataEndPtr = DataPtr + OrignalPkgLength;\r
383\r
384 //\r
385 // Jump over PkgLength = PkgLeadByte only\r
386 //\r
387 NewPkgLength++;\r
388\r
389 //\r
390 // Jump over BufferSize\r
391 //\r
392 if (*(DataPtr + 1) == AML_BYTE_PREFIX) {\r
393 NewPkgLength += 2;\r
394 } else if (*(DataPtr + 1) == AML_WORD_PREFIX) {\r
395 NewPkgLength += 3;\r
396 } else if (*(DataPtr + 1) == AML_DWORD_PREFIX) {\r
397 NewPkgLength += 5;\r
398 } else {\r
399 ASSERT(FALSE);\r
400 return EFI_UNSUPPORTED;\r
401 }\r
402 } else {\r
403 ASSERT(FALSE);\r
404 return EFI_UNSUPPORTED;\r
405 }\r
406\r
407 //\r
408 // Include Memory32Fixed Descritor (12 Bytes) + Interrupt Descriptor header(5 Bytes) + End Tag(2 Bytes)\r
409 //\r
410 NewPkgLength += 19 + IrqBuffserSize;\r
411 if (NewPkgLength > 63) {\r
412 break;\r
413 }\r
414\r
415 if (NewPkgLength > OrignalPkgLength) {\r
416 ASSERT(FALSE);\r
417 return EFI_INVALID_PARAMETER;\r
418 }\r
419\r
420 //\r
421 // 1.1 Patch PkgLength\r
422 //\r
423 *DataPtr = (UINT8)NewPkgLength;\r
424\r
425 //\r
426 // 1.2 Patch BufferSize = sizeof(Memory32Fixed Descritor + Interrupt Descriptor + End Tag).\r
427 // It is Little endian. So only patch lowest byte of BufferSize due to current interrupt number limit.\r
428 //\r
429 *(DataPtr + 2) = (UINT8)(IrqBuffserSize + 19);\r
430\r
431 //\r
432 // Notify _PRS to report short formed ResourceTemplate\r
433 //\r
434 mTcgNvs->IsShortFormPkgLength = TRUE;\r
435\r
436 break;\r
437 }\r
438 }\r
439\r
440 //\r
441 // 2. Use TPM_PRS_RESL with PkgLength > 63 to hold longer input interrupt number buffer for patching\r
442 //\r
443 if (NewPkgLength > 63) {\r
444 NewPkgLength = 0;\r
445 OrignalPkgLength = 0;\r
446 for (DataPtr = (UINT8 *)(Table + 1);\r
447 DataPtr < (UINT8 *) ((UINT8 *) Table + Table->Length - (TPM_PRS_RES_NAME_SIZE + TPM_POS_RES_TEMPLATE_MIN_SIZE));\r
448 DataPtr += 1) {\r
449 if (CompareMem(DataPtr, TPM_PRS_RESL, TPM_PRS_RES_NAME_SIZE) == 0) {\r
450 //\r
451 // Jump over object name & BufferOp\r
452 //\r
453 DataPtr += TPM_PRS_RES_NAME_SIZE + 1;\r
454\r
455 if ((*DataPtr & (BIT7|BIT6)) != 0) {\r
456 OrignalPkgLength = (UINT32)(*(DataPtr + 1) << 4) + (*DataPtr & 0x0F);\r
457 DataEndPtr = DataPtr + OrignalPkgLength;\r
458 //\r
459 // Jump over PkgLength = PkgLeadByte + ByteData length\r
460 //\r
461 NewPkgLength += 1 + ((*DataPtr & (BIT7|BIT6)) >> 6);\r
462\r
463 //\r
464 // Jump over BufferSize\r
465 //\r
466 if (*(DataPtr + NewPkgLength) == AML_BYTE_PREFIX) {\r
467 NewPkgLength += 2;\r
468 } else if (*(DataPtr + NewPkgLength) == AML_WORD_PREFIX) {\r
469 NewPkgLength += 3;\r
470 } else if (*(DataPtr + NewPkgLength) == AML_DWORD_PREFIX) {\r
471 NewPkgLength += 5;\r
472 } else {\r
473 ASSERT(FALSE);\r
474 return EFI_UNSUPPORTED;\r
475 }\r
476 } else {\r
477 ASSERT(FALSE);\r
478 return EFI_UNSUPPORTED;\r
479 }\r
480\r
481 //\r
482 // Include Memory32Fixed Descritor (12 Bytes) + Interrupt Descriptor header(5 Bytes) + End Tag(2 Bytes)\r
483 //\r
484 NewPkgLength += 19 + IrqBuffserSize;\r
485\r
486 if (NewPkgLength > OrignalPkgLength) {\r
487 ASSERT(FALSE);\r
488 return EFI_INVALID_PARAMETER;\r
489 }\r
490\r
491 //\r
492 // 2.1 Patch PkgLength. Only patch PkgLeadByte and first ByteData\r
493 //\r
494 *DataPtr = (UINT8)((*DataPtr) & 0xF0) | (NewPkgLength & 0x0F);\r
495 *(DataPtr + 1) = (UINT8)((NewPkgLength & 0xFF0) >> 4);\r
496\r
497 //\r
498 // 2.2 Patch BufferSize = sizeof(Memory32Fixed Descritor + Interrupt Descriptor + End Tag).\r
499 // It is Little endian. Only patch lowest byte of BufferSize due to current interrupt number limit.\r
500 //\r
501 *(DataPtr + 2 + ((*DataPtr & (BIT7|BIT6)) >> 6)) = (UINT8)(IrqBuffserSize + 19);\r
502\r
503 //\r
504 // Notify _PRS to report long formed ResourceTemplate\r
505 //\r
506 mTcgNvs->IsShortFormPkgLength = FALSE;\r
507 break;\r
508 }\r
509 }\r
510 }\r
511\r
512 if (DataPtr >= (UINT8 *) ((UINT8 *) Table + Table->Length - (TPM_PRS_RES_NAME_SIZE + TPM_POS_RES_TEMPLATE_MIN_SIZE))) {\r
513 return EFI_NOT_FOUND;\r
514 }\r
515\r
516 //\r
517 // 3. Move DataPtr to Interrupt descriptor header and patch interrupt descriptor.\r
518 // 5 bytes for interrupt descriptor header, 2 bytes for End Tag\r
519 //\r
520 DataPtr += NewPkgLength - (5 + IrqBuffserSize + 2);\r
521 //\r
522 // 3.1 Patch Length bit[7:0] of Interrupt descirptor patch interrupt descriptor\r
523 //\r
524 *(DataPtr + 1) = (UINT8)(2 + IrqBuffserSize);\r
525 //\r
526 // 3.2 Patch Interrupt Table Length\r
527 //\r
528 *(DataPtr + 4) = (UINT8)(IrqBuffserSize / sizeof(UINT32));\r
529 //\r
530 // 3.3 Copy patched InterruptNumBuffer\r
531 //\r
532 CopyMem(DataPtr + 5, IrqBuffer, IrqBuffserSize);\r
533\r
534 //\r
535 // 4. Jump over Interrupt descirptor and Patch END Tag, set Checksum field to 0\r
536 //\r
537 DataPtr += 5 + IrqBuffserSize;\r
538 *DataPtr = ACPI_END_TAG_DESCRIPTOR;\r
539 *(DataPtr + 1) = 0;\r
540\r
541 //\r
449083a3 542 // 5. Jump over new ResourceTemplate. Stuff rest bytes to NOOP\r
c4122dca 543 //\r
449083a3
ZC
544 DataPtr += 2;\r
545 if (DataPtr < DataEndPtr) {\r
28fd7b09 546 SetMem(DataPtr, (UINTN)DataEndPtr - (UINTN)DataPtr, AML_NOOP_OP);\r
c4122dca
ZC
547 }\r
548\r
549 return EFI_SUCCESS;\r
550}\r
551\r
73126ac2
ZC
552/**\r
553 Patch TPM2 device HID string. The initial string tag in TPM2 ACPI table is "NNN0000".\r
554\r
555 @param[in, out] Table The TPM2 SSDT ACPI table.\r
556\r
557 @return HID Update status.\r
558\r
559**/\r
560EFI_STATUS\r
561UpdateHID (\r
562 EFI_ACPI_DESCRIPTION_HEADER *Table\r
563 )\r
564{\r
565 EFI_STATUS Status;\r
566 UINT8 *DataPtr;\r
3304abc1 567 CHAR8 Hid[TPM_HID_ACPI_SIZE];\r
73126ac2
ZC
568 UINT32 ManufacturerID;\r
569 UINT32 FirmwareVersion1;\r
570 UINT32 FirmwareVersion2;\r
571 BOOLEAN PnpHID;\r
572\r
573 PnpHID = TRUE;\r
574\r
575 //\r
576 // Initialize HID with Default PNP string\r
577 //\r
3304abc1 578 ZeroMem(Hid, TPM_HID_ACPI_SIZE);\r
73126ac2
ZC
579\r
580 //\r
581 // Get Manufacturer ID\r
582 //\r
583 Status = Tpm2GetCapabilityManufactureID(&ManufacturerID);\r
584 if (!EFI_ERROR(Status)) {\r
585 DEBUG((EFI_D_INFO, "TPM_PT_MANUFACTURER 0x%08x\n", ManufacturerID));\r
586 //\r
a6e0e994 587 // ManufacturerID defined in TCG Vendor ID Registry \r
73126ac2
ZC
588 // may tailed with 0x00 or 0x20\r
589 //\r
590 if ((ManufacturerID >> 24) == 0x00 || ((ManufacturerID >> 24) == 0x20)) {\r
591 //\r
592 // HID containing PNP ID "NNN####"\r
593 // NNN is uppercase letter for Vendor ID specified by manufacturer\r
594 //\r
3304abc1 595 CopyMem(Hid, &ManufacturerID, 3);\r
73126ac2
ZC
596 } else {\r
597 //\r
598 // HID containing ACP ID "NNNN####"\r
599 // NNNN is uppercase letter for Vendor ID specified by manufacturer\r
600 //\r
3304abc1 601 CopyMem(Hid, &ManufacturerID, 4);\r
73126ac2
ZC
602 PnpHID = FALSE;\r
603 }\r
604 } else {\r
605 DEBUG ((EFI_D_ERROR, "Get TPM_PT_MANUFACTURER failed %x!\n", Status));\r
606 ASSERT(FALSE);\r
607 return Status;\r
608 }\r
609\r
610 Status = Tpm2GetCapabilityFirmwareVersion(&FirmwareVersion1, &FirmwareVersion2);\r
611 if (!EFI_ERROR(Status)) {\r
612 DEBUG((EFI_D_INFO, "TPM_PT_FIRMWARE_VERSION_1 0x%x\n", FirmwareVersion1));\r
613 DEBUG((EFI_D_INFO, "TPM_PT_FIRMWARE_VERSION_2 0x%x\n", FirmwareVersion2));\r
614 //\r
615 // #### is Firmware Version 1\r
616 //\r
617 if (PnpHID) {\r
363dc422 618 AsciiSPrint(Hid + 3, TPM_HID_PNP_SIZE - 3, "%02d%02d", ((FirmwareVersion1 & 0xFFFF0000) >> 16), (FirmwareVersion1 & 0x0000FFFF));\r
73126ac2 619 } else {\r
363dc422 620 AsciiSPrint(Hid + 4, TPM_HID_ACPI_SIZE - 4, "%02d%02d", ((FirmwareVersion1 & 0xFFFF0000) >> 16), (FirmwareVersion1 & 0x0000FFFF));\r
73126ac2
ZC
621 }\r
622 \r
623 } else {\r
624 DEBUG ((EFI_D_ERROR, "Get TPM_PT_FIRMWARE_VERSION_X failed %x!\n", Status));\r
625 ASSERT(FALSE);\r
626 return Status;\r
627 }\r
628\r
629 //\r
630 // Patch HID in ASL code before loading the SSDT.\r
631 //\r
632 for (DataPtr = (UINT8 *)(Table + 1);\r
633 DataPtr <= (UINT8 *) ((UINT8 *) Table + Table->Length - TPM_HID_PNP_SIZE);\r
634 DataPtr += 1) {\r
635 if (AsciiStrCmp((CHAR8 *)DataPtr, TPM_HID_TAG) == 0) {\r
636 if (PnpHID) {\r
3304abc1 637 CopyMem(DataPtr, Hid, TPM_HID_PNP_SIZE);\r
73126ac2 638 //\r
9a9fa14e 639 // if HID is PNP ID, patch the last byte in HID TAG to Noop\r
73126ac2 640 //\r
9a9fa14e
ZC
641 *(DataPtr + TPM_HID_PNP_SIZE) = AML_NOOP_OP;\r
642 } else {\r
643\r
3304abc1 644 CopyMem(DataPtr, Hid, TPM_HID_ACPI_SIZE);\r
73126ac2 645 }\r
a6e0e994
ZC
646 DEBUG((DEBUG_INFO, "TPM2 ACPI _HID is patched to %a\n", DataPtr));\r
647\r
73126ac2
ZC
648 return Status;\r
649 }\r
650 }\r
651\r
652 DEBUG((EFI_D_ERROR, "TPM2 ACPI HID TAG for patch not found!\n"));\r
653 return EFI_NOT_FOUND;\r
654}\r
655\r
1abfa4ce
JY
656/**\r
657 Initialize and publish TPM items in ACPI table.\r
658\r
659 @retval EFI_SUCCESS The TCG ACPI table is published successfully.\r
660 @retval Others The TCG ACPI table is not published.\r
661\r
662**/\r
663EFI_STATUS\r
664PublishAcpiTable (\r
665 VOID\r
666 )\r
667{\r
668 EFI_STATUS Status;\r
669 EFI_ACPI_TABLE_PROTOCOL *AcpiTable;\r
670 UINTN TableKey;\r
671 EFI_ACPI_DESCRIPTION_HEADER *Table;\r
672 UINTN TableSize;\r
c4122dca
ZC
673 UINT32 *PossibleIrqNumBuf;\r
674 UINT32 PossibleIrqNumBufSize;\r
1abfa4ce
JY
675\r
676 Status = GetSectionFromFv (\r
677 &gEfiCallerIdGuid,\r
678 EFI_SECTION_RAW,\r
679 0,\r
680 (VOID **) &Table,\r
681 &TableSize\r
682 );\r
683 ASSERT_EFI_ERROR (Status);\r
684\r
cd643013
ZC
685 //\r
686 // Update Table version before measuring it to PCR\r
687 //\r
688 Status = UpdatePPVersion(Table, (CHAR8 *)PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer));\r
689 ASSERT_EFI_ERROR (Status);\r
1abfa4ce 690\r
dd6d0a52
SZ
691 DEBUG ((\r
692 DEBUG_INFO,\r
693 "Current physical presence interface version - %a\n",\r
694 (CHAR8 *) PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer)\r
695 ));\r
696\r
73126ac2
ZC
697 //\r
698 // Update TPM2 HID before measuring it to PCR\r
699 //\r
700 Status = UpdateHID(Table);\r
701 if (EFI_ERROR(Status)) {\r
702 return Status;\r
703 }\r
704\r
c4122dca
ZC
705 if (PcdGet32(PcdTpm2CurrentIrqNum) != 0) {\r
706 //\r
707 // Patch _PRS interrupt resource only when TPM interrupt is supported\r
708 //\r
709 PossibleIrqNumBuf = (UINT32 *)PcdGetPtr(PcdTpm2PossibleIrqNumBuf);\r
710 PossibleIrqNumBufSize = (UINT32)PcdGetSize(PcdTpm2PossibleIrqNumBuf);\r
711\r
712 if (PossibleIrqNumBufSize <= MAX_PRS_INT_BUF_SIZE && (PossibleIrqNumBufSize % sizeof(UINT32)) == 0) {\r
713 Status = UpdatePossibleResource(Table, PossibleIrqNumBuf, PossibleIrqNumBufSize);\r
714 DEBUG ((\r
715 DEBUG_INFO,\r
716 "UpdatePossibleResource status - %x. TPM2 service may not ready in OS.\n",\r
717 Status\r
718 ));\r
719 } else {\r
720 DEBUG ((\r
721 DEBUG_INFO,\r
722 "PcdTpm2PossibleIrqNumBuf size %x is not correct. TPM2 service may not ready in OS.\n",\r
723 PossibleIrqNumBufSize\r
724 ));\r
725 }\r
726 }\r
727\r
1abfa4ce
JY
728 //\r
729 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA\r
730 //\r
731 TpmMeasureAndLogData(\r
732 0,\r
733 EV_POST_CODE,\r
734 EV_POSTCODE_INFO_ACPI_DATA,\r
735 ACPI_DATA_LEN,\r
736 Table,\r
737 TableSize\r
738 );\r
739\r
740\r
741 ASSERT (Table->OemTableId == SIGNATURE_64 ('T', 'p', 'm', '2', 'T', 'a', 'b', 'l'));\r
742 CopyMem (Table->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (Table->OemId) );\r
743 mTcgNvs = AssignOpRegion (Table, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16) sizeof (TCG_NVS));\r
744 ASSERT (mTcgNvs != NULL);\r
c4122dca
ZC
745 mTcgNvs->TpmIrqNum = PcdGet32(PcdTpm2CurrentIrqNum);\r
746 mTcgNvs->IsShortFormPkgLength = FALSE;\r
1abfa4ce
JY
747\r
748 //\r
cd643013 749 // Publish the TPM ACPI table. Table is re-checksumed.\r
1abfa4ce
JY
750 //\r
751 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);\r
752 ASSERT_EFI_ERROR (Status);\r
753\r
754 TableKey = 0;\r
755 Status = AcpiTable->InstallAcpiTable (\r
756 AcpiTable,\r
757 Table,\r
758 TableSize,\r
759 &TableKey\r
760 );\r
761 ASSERT_EFI_ERROR (Status);\r
762\r
763 return Status;\r
764}\r
765\r
766/**\r
767 Publish TPM2 ACPI table\r
768\r
769 @retval EFI_SUCCESS The TPM2 ACPI table is published successfully.\r
770 @retval Others The TPM2 ACPI table is not published.\r
771\r
772**/\r
773EFI_STATUS\r
774PublishTpm2 (\r
775 VOID\r
776 )\r
777{\r
778 EFI_STATUS Status;\r
779 EFI_ACPI_TABLE_PROTOCOL *AcpiTable;\r
780 UINTN TableKey;\r
781 UINT64 OemTableId;\r
d967d6d9
JY
782 EFI_TPM2_ACPI_CONTROL_AREA *ControlArea;\r
783 PTP_INTERFACE_TYPE InterfaceType;\r
1abfa4ce 784\r
fca42289
ZC
785 mTpm2AcpiTemplate.Header.Revision = PcdGet8(PcdTpm2AcpiTableRev);\r
786 DEBUG((DEBUG_INFO, "Tpm2 ACPI table revision is %d\n", mTpm2AcpiTemplate.Header.Revision));\r
787\r
bf3b7aae
ZC
788 //\r
789 // PlatformClass is only valid for version 4 and above\r
790 // BIT0~15: PlatformClass \r
791 // BIT16~31: Reserved\r
792 //\r
793 if (mTpm2AcpiTemplate.Header.Revision >= EFI_TPM2_ACPI_TABLE_REVISION_4) {\r
794 mTpm2AcpiTemplate.Flags = (mTpm2AcpiTemplate.Flags & 0xFFFF0000) | PcdGet8(PcdTpmPlatformClass);\r
795 DEBUG((DEBUG_INFO, "Tpm2 ACPI table PlatformClass is %d\n", (mTpm2AcpiTemplate.Flags & 0x0000FFFF)));\r
796 }\r
797\r
1abfa4ce
JY
798 //\r
799 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA\r
800 //\r
801 TpmMeasureAndLogData(\r
802 0,\r
803 EV_POST_CODE,\r
804 EV_POSTCODE_INFO_ACPI_DATA,\r
805 ACPI_DATA_LEN,\r
806 &mTpm2AcpiTemplate,\r
807 sizeof(mTpm2AcpiTemplate)\r
808 );\r
809\r
d967d6d9
JY
810 InterfaceType = GetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress));\r
811 switch (InterfaceType) {\r
812 case PtpInterfaceCrb:\r
813 mTpm2AcpiTemplate.StartMethod = EFI_TPM2_ACPI_TABLE_START_METHOD_COMMAND_RESPONSE_BUFFER_INTERFACE;\r
814 mTpm2AcpiTemplate.AddressOfControlArea = PcdGet64 (PcdTpmBaseAddress) + 0x40;\r
815 ControlArea = (EFI_TPM2_ACPI_CONTROL_AREA *)(UINTN)mTpm2AcpiTemplate.AddressOfControlArea;\r
816 ControlArea->CommandSize = 0xF80;\r
817 ControlArea->ResponseSize = 0xF80;\r
818 ControlArea->Command = PcdGet64 (PcdTpmBaseAddress) + 0x80;\r
819 ControlArea->Response = PcdGet64 (PcdTpmBaseAddress) + 0x80;\r
820 break;\r
821 case PtpInterfaceFifo:\r
822 case PtpInterfaceTis:\r
823 break;\r
824 default:\r
3b5624b0 825 DEBUG((EFI_D_ERROR, "TPM2 InterfaceType get error! %d\n", InterfaceType));\r
d967d6d9
JY
826 break;\r
827 }\r
828\r
1abfa4ce
JY
829 CopyMem (mTpm2AcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mTpm2AcpiTemplate.Header.OemId));\r
830 OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);\r
831 CopyMem (&mTpm2AcpiTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64));\r
832 mTpm2AcpiTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);\r
833 mTpm2AcpiTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);\r
834 mTpm2AcpiTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);\r
835\r
836 //\r
837 // Construct ACPI table\r
838 //\r
839 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);\r
840 ASSERT_EFI_ERROR (Status);\r
841\r
842 Status = AcpiTable->InstallAcpiTable (\r
843 AcpiTable,\r
844 &mTpm2AcpiTemplate,\r
845 sizeof(mTpm2AcpiTemplate),\r
846 &TableKey\r
847 );\r
848 ASSERT_EFI_ERROR (Status);\r
849\r
850 return Status;\r
851}\r
852\r
853/**\r
854 The driver's entry point.\r
855\r
856 It install callbacks for TPM physical presence and MemoryClear, and locate \r
857 SMM variable to be used in the callback function.\r
858\r
859 @param[in] ImageHandle The firmware allocated handle for the EFI image. \r
860 @param[in] SystemTable A pointer to the EFI System Table.\r
861 \r
862 @retval EFI_SUCCESS The entry point is executed successfully.\r
863 @retval Others Some error occurs when executing this entry point.\r
864\r
865**/\r
866EFI_STATUS\r
867EFIAPI\r
868InitializeTcgSmm (\r
869 IN EFI_HANDLE ImageHandle,\r
870 IN EFI_SYSTEM_TABLE *SystemTable\r
871 )\r
872{\r
873 EFI_STATUS Status;\r
874 EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;\r
875 EFI_SMM_SW_REGISTER_CONTEXT SwContext;\r
876 EFI_HANDLE SwHandle;\r
877\r
878 if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm20DtpmGuid)){\r
879 DEBUG ((EFI_D_ERROR, "No TPM2 DTPM instance required!\n"));\r
880 return EFI_UNSUPPORTED;\r
881 }\r
882\r
883 Status = PublishAcpiTable ();\r
884 ASSERT_EFI_ERROR (Status);\r
885\r
886 //\r
887 // Get the Sw dispatch protocol and register SMI callback functions.\r
888 //\r
889 Status = gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID**)&SwDispatch);\r
890 ASSERT_EFI_ERROR (Status);\r
891 SwContext.SwSmiInputValue = (UINTN) -1;\r
892 Status = SwDispatch->Register (SwDispatch, PhysicalPresenceCallback, &SwContext, &SwHandle);\r
893 ASSERT_EFI_ERROR (Status);\r
894 if (EFI_ERROR (Status)) {\r
895 return Status;\r
896 }\r
897 mTcgNvs->PhysicalPresence.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;\r
898\r
899 SwContext.SwSmiInputValue = (UINTN) -1;\r
900 Status = SwDispatch->Register (SwDispatch, MemoryClearCallback, &SwContext, &SwHandle);\r
901 ASSERT_EFI_ERROR (Status);\r
902 if (EFI_ERROR (Status)) {\r
903 return Status;\r
904 }\r
905 mTcgNvs->MemoryClear.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;\r
906 \r
907 //\r
908 // Locate SmmVariableProtocol.\r
909 //\r
910 Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mSmmVariable);\r
911 ASSERT_EFI_ERROR (Status);\r
912\r
913 //\r
914 // Set TPM2 ACPI table\r
915 //\r
916 Status = PublishTpm2 ();\r
917 ASSERT_EFI_ERROR (Status);\r
918\r
919\r
920 return EFI_SUCCESS;\r
921}\r
922\r