]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.c
f0c92462cf921164a84b730471d5aadc7f1745b1
[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 @param[out] IsShortFormPkgLength If _PRS returns Short length Package(ACPI spec 20.2.4).
314
315 @return patch status.
316
317 **/
318 EFI_STATUS
319 UpdatePossibleResource (
320 IN OUT EFI_ACPI_DESCRIPTION_HEADER *Table,
321 IN UINT32 *IrqBuffer,
322 IN UINT32 IrqBuffserSize,
323 OUT BOOLEAN *IsShortFormPkgLength
324 )
325 {
326 UINT8 *DataPtr;
327 UINT8 *DataEndPtr;
328 UINT32 NewPkgLength;
329 UINT32 OrignalPkgLength;
330
331 NewPkgLength = 0;
332 OrignalPkgLength = 0;
333 DataEndPtr = NULL;
334
335 //
336 // Follow ACPI spec
337 // 6.4.3 Extend Interrupt Descriptor.
338 // 19.3.3 ASL Resource Template
339 // 20 AML specification
340 // to patch TPM ACPI object _PRS returned ResourceTemplate() containing 2 resource descriptors and an auto appended End Tag
341 //
342 // AML data is organized by following rule.
343 // Code need to patch BufferSize and PkgLength and interrupt descirptor in ByteList
344 //
345 // ============= Buffer ====================
346 // DefBuffer := BufferOp PkgLength BufferSize ByteList
347 // BufferOp := 0x11
348 //
349 // ==============PkgLength==================
350 // PkgLength := PkgLeadByte |
351 // <PkgLeadByte ByteData> |
352 // <PkgLeadByte ByteData ByteData> |
353 // <PkgLeadByte ByteData ByteData ByteData>
354 //
355 // PkgLeadByte := <bit 7-6: ByteData count that follows (0-3)>
356 // <bit 5-4: Only used if PkgLength <= 63 >
357 // <bit 3-0: Least significant package length nybble>
358 //
359 //==============BufferSize==================
360 // BufferSize := Integar
361 // Integar := ByteConst|WordConst|DwordConst....
362 //
363 // ByteConst := BytePrefix ByteData
364 //
365 //==============ByteList===================
366 // ByteList := ByteData ByteList
367 //
368 //=========================================
369
370 //
371 // 1. Check TPM_PRS_RESS with PkgLength <=63 can hold the input interrupt number buffer for patching
372 //
373 for (DataPtr = (UINT8 *)(Table + 1);
374 DataPtr < (UINT8 *) ((UINT8 *) Table + Table->Length - (TPM_PRS_RES_NAME_SIZE + TPM_POS_RES_TEMPLATE_MIN_SIZE));
375 DataPtr += 1) {
376 if (CompareMem(DataPtr, TPM_PRS_RESS, TPM_PRS_RES_NAME_SIZE) == 0) {
377 //
378 // Jump over object name & BufferOp
379 //
380 DataPtr += TPM_PRS_RES_NAME_SIZE + 1;
381
382 if ((*DataPtr & (BIT7|BIT6)) == 0) {
383 OrignalPkgLength = (UINT32)*DataPtr;
384 DataEndPtr = DataPtr + OrignalPkgLength;
385
386 //
387 // Jump over PkgLength = PkgLeadByte only
388 //
389 NewPkgLength++;
390
391 //
392 // Jump over BufferSize
393 //
394 if (*(DataPtr + 1) == AML_BYTE_PREFIX) {
395 NewPkgLength += 2;
396 } else if (*(DataPtr + 1) == AML_WORD_PREFIX) {
397 NewPkgLength += 3;
398 } else if (*(DataPtr + 1) == AML_DWORD_PREFIX) {
399 NewPkgLength += 5;
400 } else {
401 ASSERT(FALSE);
402 return EFI_UNSUPPORTED;
403 }
404 } else {
405 ASSERT(FALSE);
406 return EFI_UNSUPPORTED;
407 }
408
409 //
410 // Include Memory32Fixed Descritor (12 Bytes) + Interrupt Descriptor header(5 Bytes) + End Tag(2 Bytes)
411 //
412 NewPkgLength += 19 + IrqBuffserSize;
413 if (NewPkgLength > 63) {
414 break;
415 }
416
417 if (NewPkgLength > OrignalPkgLength) {
418 ASSERT(FALSE);
419 return EFI_INVALID_PARAMETER;
420 }
421
422 //
423 // 1.1 Patch PkgLength
424 //
425 *DataPtr = (UINT8)NewPkgLength;
426
427 //
428 // 1.2 Patch BufferSize = sizeof(Memory32Fixed Descritor + Interrupt Descriptor + End Tag).
429 // It is Little endian. So only patch lowest byte of BufferSize due to current interrupt number limit.
430 //
431 *(DataPtr + 2) = (UINT8)(IrqBuffserSize + 19);
432
433 //
434 // Notify _PRS to report short formed ResourceTemplate
435 //
436 *IsShortFormPkgLength = TRUE;
437
438 break;
439 }
440 }
441
442 //
443 // 2. Use TPM_PRS_RESL with PkgLength > 63 to hold longer input interrupt number buffer for patching
444 //
445 if (NewPkgLength > 63) {
446 NewPkgLength = 0;
447 OrignalPkgLength = 0;
448 for (DataPtr = (UINT8 *)(Table + 1);
449 DataPtr < (UINT8 *) ((UINT8 *) Table + Table->Length - (TPM_PRS_RES_NAME_SIZE + TPM_POS_RES_TEMPLATE_MIN_SIZE));
450 DataPtr += 1) {
451 if (CompareMem(DataPtr, TPM_PRS_RESL, TPM_PRS_RES_NAME_SIZE) == 0) {
452 //
453 // Jump over object name & BufferOp
454 //
455 DataPtr += TPM_PRS_RES_NAME_SIZE + 1;
456
457 if ((*DataPtr & (BIT7|BIT6)) != 0) {
458 OrignalPkgLength = (UINT32)(*(DataPtr + 1) << 4) + (*DataPtr & 0x0F);
459 DataEndPtr = DataPtr + OrignalPkgLength;
460 //
461 // Jump over PkgLength = PkgLeadByte + ByteData length
462 //
463 NewPkgLength += 1 + ((*DataPtr & (BIT7|BIT6)) >> 6);
464
465 //
466 // Jump over BufferSize
467 //
468 if (*(DataPtr + NewPkgLength) == AML_BYTE_PREFIX) {
469 NewPkgLength += 2;
470 } else if (*(DataPtr + NewPkgLength) == AML_WORD_PREFIX) {
471 NewPkgLength += 3;
472 } else if (*(DataPtr + NewPkgLength) == AML_DWORD_PREFIX) {
473 NewPkgLength += 5;
474 } else {
475 ASSERT(FALSE);
476 return EFI_UNSUPPORTED;
477 }
478 } else {
479 ASSERT(FALSE);
480 return EFI_UNSUPPORTED;
481 }
482
483 //
484 // Include Memory32Fixed Descritor (12 Bytes) + Interrupt Descriptor header(5 Bytes) + End Tag(2 Bytes)
485 //
486 NewPkgLength += 19 + IrqBuffserSize;
487
488 if (NewPkgLength > OrignalPkgLength) {
489 ASSERT(FALSE);
490 return EFI_INVALID_PARAMETER;
491 }
492
493 //
494 // 2.1 Patch PkgLength. Only patch PkgLeadByte and first ByteData
495 //
496 *DataPtr = (UINT8)((*DataPtr) & 0xF0) | (NewPkgLength & 0x0F);
497 *(DataPtr + 1) = (UINT8)((NewPkgLength & 0xFF0) >> 4);
498
499 //
500 // 2.2 Patch BufferSize = sizeof(Memory32Fixed Descritor + Interrupt Descriptor + End Tag).
501 // It is Little endian. Only patch lowest byte of BufferSize due to current interrupt number limit.
502 //
503 *(DataPtr + 2 + ((*DataPtr & (BIT7|BIT6)) >> 6)) = (UINT8)(IrqBuffserSize + 19);
504
505 //
506 // Notify _PRS to report long formed ResourceTemplate
507 //
508 *IsShortFormPkgLength = FALSE;
509 break;
510 }
511 }
512 }
513
514 if (DataPtr >= (UINT8 *) ((UINT8 *) Table + Table->Length - (TPM_PRS_RES_NAME_SIZE + TPM_POS_RES_TEMPLATE_MIN_SIZE))) {
515 return EFI_NOT_FOUND;
516 }
517
518 //
519 // 3. Move DataPtr to Interrupt descriptor header and patch interrupt descriptor.
520 // 5 bytes for interrupt descriptor header, 2 bytes for End Tag
521 //
522 DataPtr += NewPkgLength - (5 + IrqBuffserSize + 2);
523 //
524 // 3.1 Patch Length bit[7:0] of Interrupt descirptor patch interrupt descriptor
525 //
526 *(DataPtr + 1) = (UINT8)(2 + IrqBuffserSize);
527 //
528 // 3.2 Patch Interrupt Table Length
529 //
530 *(DataPtr + 4) = (UINT8)(IrqBuffserSize / sizeof(UINT32));
531 //
532 // 3.3 Copy patched InterruptNumBuffer
533 //
534 CopyMem(DataPtr + 5, IrqBuffer, IrqBuffserSize);
535
536 //
537 // 4. Jump over Interrupt descirptor and Patch END Tag, set Checksum field to 0
538 //
539 DataPtr += 5 + IrqBuffserSize;
540 *DataPtr = ACPI_END_TAG_DESCRIPTOR;
541 *(DataPtr + 1) = 0;
542
543 //
544 // 5. Jump over new ResourceTemplate. Stuff rest bytes to NOOP
545 //
546 DataPtr += 2;
547 if (DataPtr < DataEndPtr) {
548 SetMem(DataPtr, (UINTN)DataEndPtr - (UINTN)DataPtr, AML_NOOP_OP);
549 }
550
551 return EFI_SUCCESS;
552 }
553
554 /**
555 Patch TPM2 device HID string. The initial string tag in TPM2 ACPI table is "NNN0000".
556
557 @param[in, out] Table The TPM2 SSDT ACPI table.
558
559 @return HID Update status.
560
561 **/
562 EFI_STATUS
563 UpdateHID (
564 EFI_ACPI_DESCRIPTION_HEADER *Table
565 )
566 {
567 EFI_STATUS Status;
568 UINT8 *DataPtr;
569 CHAR8 Hid[TPM_HID_ACPI_SIZE];
570 UINT32 ManufacturerID;
571 UINT32 FirmwareVersion1;
572 UINT32 FirmwareVersion2;
573 BOOLEAN PnpHID;
574
575 PnpHID = TRUE;
576
577 //
578 // Initialize HID with Default PNP string
579 //
580 ZeroMem(Hid, TPM_HID_ACPI_SIZE);
581
582 //
583 // Get Manufacturer ID
584 //
585 Status = Tpm2GetCapabilityManufactureID(&ManufacturerID);
586 if (!EFI_ERROR(Status)) {
587 DEBUG((EFI_D_INFO, "TPM_PT_MANUFACTURER 0x%08x\n", ManufacturerID));
588 //
589 // ManufacturerID defined in TCG Vendor ID Registry
590 // may tailed with 0x00 or 0x20
591 //
592 if ((ManufacturerID >> 24) == 0x00 || ((ManufacturerID >> 24) == 0x20)) {
593 //
594 // HID containing PNP ID "NNN####"
595 // NNN is uppercase letter for Vendor ID specified by manufacturer
596 //
597 CopyMem(Hid, &ManufacturerID, 3);
598 } else {
599 //
600 // HID containing ACP ID "NNNN####"
601 // NNNN is uppercase letter for Vendor ID specified by manufacturer
602 //
603 CopyMem(Hid, &ManufacturerID, 4);
604 PnpHID = FALSE;
605 }
606 } else {
607 DEBUG ((EFI_D_ERROR, "Get TPM_PT_MANUFACTURER failed %x!\n", Status));
608 ASSERT(FALSE);
609 return Status;
610 }
611
612 Status = Tpm2GetCapabilityFirmwareVersion(&FirmwareVersion1, &FirmwareVersion2);
613 if (!EFI_ERROR(Status)) {
614 DEBUG((EFI_D_INFO, "TPM_PT_FIRMWARE_VERSION_1 0x%x\n", FirmwareVersion1));
615 DEBUG((EFI_D_INFO, "TPM_PT_FIRMWARE_VERSION_2 0x%x\n", FirmwareVersion2));
616 //
617 // #### is Firmware Version 1
618 //
619 if (PnpHID) {
620 AsciiSPrint(Hid + 3, TPM_HID_PNP_SIZE - 3, "%02d%02d", ((FirmwareVersion1 & 0xFFFF0000) >> 16), (FirmwareVersion1 & 0x0000FFFF));
621 } else {
622 AsciiSPrint(Hid + 4, TPM_HID_ACPI_SIZE - 4, "%02d%02d", ((FirmwareVersion1 & 0xFFFF0000) >> 16), (FirmwareVersion1 & 0x0000FFFF));
623 }
624
625 } else {
626 DEBUG ((EFI_D_ERROR, "Get TPM_PT_FIRMWARE_VERSION_X failed %x!\n", Status));
627 ASSERT(FALSE);
628 return Status;
629 }
630
631 //
632 // Patch HID in ASL code before loading the SSDT.
633 //
634 for (DataPtr = (UINT8 *)(Table + 1);
635 DataPtr <= (UINT8 *) ((UINT8 *) Table + Table->Length - TPM_HID_PNP_SIZE);
636 DataPtr += 1) {
637 if (AsciiStrCmp((CHAR8 *)DataPtr, TPM_HID_TAG) == 0) {
638 if (PnpHID) {
639 CopyMem(DataPtr, Hid, TPM_HID_PNP_SIZE);
640 //
641 // if HID is PNP ID, patch the last byte in HID TAG to Noop
642 //
643 *(DataPtr + TPM_HID_PNP_SIZE) = AML_NOOP_OP;
644 } else {
645
646 CopyMem(DataPtr, Hid, TPM_HID_ACPI_SIZE);
647 }
648 DEBUG((DEBUG_INFO, "TPM2 ACPI _HID is patched to %a\n", DataPtr));
649
650 return Status;
651 }
652 }
653
654 DEBUG((EFI_D_ERROR, "TPM2 ACPI HID TAG for patch not found!\n"));
655 return EFI_NOT_FOUND;
656 }
657
658 /**
659 Initialize and publish TPM items in ACPI table.
660
661 @retval EFI_SUCCESS The TCG ACPI table is published successfully.
662 @retval Others The TCG ACPI table is not published.
663
664 **/
665 EFI_STATUS
666 PublishAcpiTable (
667 VOID
668 )
669 {
670 EFI_STATUS Status;
671 EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
672 UINTN TableKey;
673 EFI_ACPI_DESCRIPTION_HEADER *Table;
674 UINTN TableSize;
675 UINT32 *PossibleIrqNumBuf;
676 UINT32 PossibleIrqNumBufSize;
677 BOOLEAN IsShortFormPkgLength;
678
679 IsShortFormPkgLength = FALSE;
680
681 Status = GetSectionFromFv (
682 &gEfiCallerIdGuid,
683 EFI_SECTION_RAW,
684 0,
685 (VOID **) &Table,
686 &TableSize
687 );
688 ASSERT_EFI_ERROR (Status);
689
690 //
691 // Update Table version before measuring it to PCR
692 //
693 Status = UpdatePPVersion(Table, (CHAR8 *)PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer));
694 ASSERT_EFI_ERROR (Status);
695
696 DEBUG ((
697 DEBUG_INFO,
698 "Current physical presence interface version - %a\n",
699 (CHAR8 *) PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer)
700 ));
701
702 //
703 // Update TPM2 HID before measuring it to PCR
704 //
705 Status = UpdateHID(Table);
706 if (EFI_ERROR(Status)) {
707 return Status;
708 }
709
710 if (PcdGet32(PcdTpm2CurrentIrqNum) != 0) {
711 //
712 // Patch _PRS interrupt resource only when TPM interrupt is supported
713 //
714 PossibleIrqNumBuf = (UINT32 *)PcdGetPtr(PcdTpm2PossibleIrqNumBuf);
715 PossibleIrqNumBufSize = (UINT32)PcdGetSize(PcdTpm2PossibleIrqNumBuf);
716
717 if (PossibleIrqNumBufSize <= MAX_PRS_INT_BUF_SIZE && (PossibleIrqNumBufSize % sizeof(UINT32)) == 0) {
718 Status = UpdatePossibleResource(Table, PossibleIrqNumBuf, PossibleIrqNumBufSize, &IsShortFormPkgLength);
719 DEBUG ((
720 DEBUG_INFO,
721 "UpdatePossibleResource status - %x. TPM2 service may not ready in OS.\n",
722 Status
723 ));
724 } else {
725 DEBUG ((
726 DEBUG_INFO,
727 "PcdTpm2PossibleIrqNumBuf size %x is not correct. TPM2 service may not ready in OS.\n",
728 PossibleIrqNumBufSize
729 ));
730 }
731 }
732
733 //
734 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
735 //
736 TpmMeasureAndLogData(
737 0,
738 EV_POST_CODE,
739 EV_POSTCODE_INFO_ACPI_DATA,
740 ACPI_DATA_LEN,
741 Table,
742 TableSize
743 );
744
745
746 ASSERT (Table->OemTableId == SIGNATURE_64 ('T', 'p', 'm', '2', 'T', 'a', 'b', 'l'));
747 CopyMem (Table->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (Table->OemId) );
748 mTcgNvs = AssignOpRegion (Table, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16) sizeof (TCG_NVS));
749 ASSERT (mTcgNvs != NULL);
750 mTcgNvs->TpmIrqNum = PcdGet32(PcdTpm2CurrentIrqNum);
751 mTcgNvs->IsShortFormPkgLength = IsShortFormPkgLength;
752
753 //
754 // Publish the TPM ACPI table. Table is re-checksumed.
755 //
756 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
757 ASSERT_EFI_ERROR (Status);
758
759 TableKey = 0;
760 Status = AcpiTable->InstallAcpiTable (
761 AcpiTable,
762 Table,
763 TableSize,
764 &TableKey
765 );
766 ASSERT_EFI_ERROR (Status);
767
768 return Status;
769 }
770
771 /**
772 Publish TPM2 ACPI table
773
774 @retval EFI_SUCCESS The TPM2 ACPI table is published successfully.
775 @retval Others The TPM2 ACPI table is not published.
776
777 **/
778 EFI_STATUS
779 PublishTpm2 (
780 VOID
781 )
782 {
783 EFI_STATUS Status;
784 EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
785 UINTN TableKey;
786 UINT64 OemTableId;
787 EFI_TPM2_ACPI_CONTROL_AREA *ControlArea;
788 PTP_INTERFACE_TYPE InterfaceType;
789
790 mTpm2AcpiTemplate.Header.Revision = PcdGet8(PcdTpm2AcpiTableRev);
791 DEBUG((DEBUG_INFO, "Tpm2 ACPI table revision is %d\n", mTpm2AcpiTemplate.Header.Revision));
792
793 //
794 // PlatformClass is only valid for version 4 and above
795 // BIT0~15: PlatformClass
796 // BIT16~31: Reserved
797 //
798 if (mTpm2AcpiTemplate.Header.Revision >= EFI_TPM2_ACPI_TABLE_REVISION_4) {
799 mTpm2AcpiTemplate.Flags = (mTpm2AcpiTemplate.Flags & 0xFFFF0000) | PcdGet8(PcdTpmPlatformClass);
800 DEBUG((DEBUG_INFO, "Tpm2 ACPI table PlatformClass is %d\n", (mTpm2AcpiTemplate.Flags & 0x0000FFFF)));
801 }
802
803 //
804 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
805 //
806 TpmMeasureAndLogData(
807 0,
808 EV_POST_CODE,
809 EV_POSTCODE_INFO_ACPI_DATA,
810 ACPI_DATA_LEN,
811 &mTpm2AcpiTemplate,
812 sizeof(mTpm2AcpiTemplate)
813 );
814
815 InterfaceType = GetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress));
816 switch (InterfaceType) {
817 case PtpInterfaceCrb:
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 PtpInterfaceFifo:
827 case PtpInterfaceTis:
828 break;
829 default:
830 DEBUG((EFI_D_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 sizeof(mTpm2AcpiTemplate),
851 &TableKey
852 );
853 ASSERT_EFI_ERROR (Status);
854
855 return Status;
856 }
857
858 /**
859 The driver's entry point.
860
861 It install callbacks for TPM physical presence and MemoryClear, and locate
862 SMM variable to be used in the callback function.
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 InitializeTcgSmm (
874 IN EFI_HANDLE ImageHandle,
875 IN EFI_SYSTEM_TABLE *SystemTable
876 )
877 {
878 EFI_STATUS Status;
879 EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;
880 EFI_SMM_SW_REGISTER_CONTEXT SwContext;
881 EFI_HANDLE SwHandle;
882
883 if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm20DtpmGuid)){
884 DEBUG ((EFI_D_ERROR, "No TPM2 DTPM instance required!\n"));
885 return EFI_UNSUPPORTED;
886 }
887
888 Status = PublishAcpiTable ();
889 ASSERT_EFI_ERROR (Status);
890
891 //
892 // Get the Sw dispatch protocol and register SMI callback functions.
893 //
894 Status = gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID**)&SwDispatch);
895 ASSERT_EFI_ERROR (Status);
896 SwContext.SwSmiInputValue = (UINTN) -1;
897 Status = SwDispatch->Register (SwDispatch, PhysicalPresenceCallback, &SwContext, &SwHandle);
898 ASSERT_EFI_ERROR (Status);
899 if (EFI_ERROR (Status)) {
900 return Status;
901 }
902 mTcgNvs->PhysicalPresence.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;
903
904 SwContext.SwSmiInputValue = (UINTN) -1;
905 Status = SwDispatch->Register (SwDispatch, MemoryClearCallback, &SwContext, &SwHandle);
906 ASSERT_EFI_ERROR (Status);
907 if (EFI_ERROR (Status)) {
908 return Status;
909 }
910 mTcgNvs->MemoryClear.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;
911
912 //
913 // Locate SmmVariableProtocol.
914 //
915 Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mSmmVariable);
916 ASSERT_EFI_ERROR (Status);
917
918 //
919 // Set TPM2 ACPI table
920 //
921 Status = PublishTpm2 ();
922 ASSERT_EFI_ERROR (Status);
923
924
925 return EFI_SUCCESS;
926 }
927