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