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