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