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