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