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