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