]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.c
SecurityPkg/Tcg2Smm: Correct function parameter attribute
[mirror_edk2.git] / SecurityPkg / Tcg / Tcg2Smm / Tcg2Smm.c
... / ...
CommitLineData
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
12Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>\r
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
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
53 if (InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_TIS) {\r
54 return PtpInterfaceTis;\r
55 }\r
56\r
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
62\r
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
69\r
70 //\r
71 // No Ptp interface available\r
72 //\r
73 return PtpInterfaceMax;\r
74}\r
75\r
76EFI_TPM2_ACPI_TABLE mTpm2AcpiTemplate = {\r
77 {\r
78 EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE,\r
79 sizeof (mTpm2AcpiTemplate),\r
80 EFI_TPM2_ACPI_TABLE_REVISION,\r
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
86 0, // BIT0~15: PlatformClass\r
87 // BIT16~31: Reserved\r
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
123 UINT32 OperationRequest;\r
124 UINT32 RequestParameter;\r
125\r
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
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
143 );\r
144 mTcgNvs->PhysicalPresence.Request = OperationRequest;\r
145 mTcgNvs->PhysicalPresence.RequestParameter = RequestParameter;\r
146 } else if (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST) {\r
147 mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibGetUserConfirmationStatusFunction (mTcgNvs->PPRequestUserConfirm);\r
148 }\r
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
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
296 if (AsciiStrCmp((CHAR8 *)DataPtr, PHYSICAL_PRESENCE_VERSION_TAG) == 0) {\r
297 Status = AsciiStrCpyS((CHAR8 *)DataPtr, PHYSICAL_PRESENCE_VERSION_SIZE, PPVer);\r
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
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 @param[out] IsShortFormPkgLength If _PRS returns Short length Package(ACPI spec 20.2.4).\r
314\r
315 @return patch status.\r
316\r
317**/\r
318EFI_STATUS\r
319UpdatePossibleResource (\r
320 IN OUT EFI_ACPI_DESCRIPTION_HEADER *Table,\r
321 IN UINT32 *IrqBuffer,\r
322 IN UINT32 IrqBuffserSize,\r
323 OUT BOOLEAN *IsShortFormPkgLength\r
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
436 *IsShortFormPkgLength = TRUE;\r
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
508 *IsShortFormPkgLength = FALSE;\r
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
544 // 5. Jump over new ResourceTemplate. Stuff rest bytes to NOOP\r
545 //\r
546 DataPtr += 2;\r
547 if (DataPtr < DataEndPtr) {\r
548 SetMem(DataPtr, (UINTN)DataEndPtr - (UINTN)DataPtr, AML_NOOP_OP);\r
549 }\r
550\r
551 return EFI_SUCCESS;\r
552}\r
553\r
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
569 CHAR8 Hid[TPM_HID_ACPI_SIZE];\r
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
580 ZeroMem(Hid, TPM_HID_ACPI_SIZE);\r
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
589 // ManufacturerID defined in TCG Vendor ID Registry \r
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
597 CopyMem(Hid, &ManufacturerID, 3);\r
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
603 CopyMem(Hid, &ManufacturerID, 4);\r
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
620 AsciiSPrint(Hid + 3, TPM_HID_PNP_SIZE - 3, "%02d%02d", ((FirmwareVersion1 & 0xFFFF0000) >> 16), (FirmwareVersion1 & 0x0000FFFF));\r
621 } else {\r
622 AsciiSPrint(Hid + 4, TPM_HID_ACPI_SIZE - 4, "%02d%02d", ((FirmwareVersion1 & 0xFFFF0000) >> 16), (FirmwareVersion1 & 0x0000FFFF));\r
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
639 CopyMem(DataPtr, Hid, TPM_HID_PNP_SIZE);\r
640 //\r
641 // if HID is PNP ID, patch the last byte in HID TAG to Noop\r
642 //\r
643 *(DataPtr + TPM_HID_PNP_SIZE) = AML_NOOP_OP;\r
644 } else {\r
645\r
646 CopyMem(DataPtr, Hid, TPM_HID_ACPI_SIZE);\r
647 }\r
648 DEBUG((DEBUG_INFO, "TPM2 ACPI _HID is patched to %a\n", DataPtr));\r
649\r
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
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
675 UINT32 *PossibleIrqNumBuf;\r
676 UINT32 PossibleIrqNumBufSize;\r
677 BOOLEAN IsShortFormPkgLength;\r
678\r
679 IsShortFormPkgLength = FALSE;\r
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
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
695\r
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
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
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
718 Status = UpdatePossibleResource(Table, PossibleIrqNumBuf, PossibleIrqNumBufSize, &IsShortFormPkgLength);\r
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
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
750 mTcgNvs->TpmIrqNum = PcdGet32(PcdTpm2CurrentIrqNum);\r
751 mTcgNvs->IsShortFormPkgLength = IsShortFormPkgLength;\r
752\r
753 //\r
754 // Publish the TPM ACPI table. Table is re-checksumed.\r
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
787 EFI_TPM2_ACPI_CONTROL_AREA *ControlArea;\r
788 PTP_INTERFACE_TYPE InterfaceType;\r
789\r
790 mTpm2AcpiTemplate.Header.Revision = PcdGet8(PcdTpm2AcpiTableRev);\r
791 DEBUG((DEBUG_INFO, "Tpm2 ACPI table revision is %d\n", mTpm2AcpiTemplate.Header.Revision));\r
792\r
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
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
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
830 DEBUG((EFI_D_ERROR, "TPM2 InterfaceType get error! %d\n", InterfaceType));\r
831 break;\r
832 }\r
833\r
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