]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.c
b4974755b2bda32518e7af05ac619004124b840f
[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 - 2016, 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_CRB) &&
54 (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_CRB) &&
55 (InterfaceId.Bits.CapCRB != 0)) {
56 return PtpInterfaceCrb;
57 }
58 if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO) &&
59 (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_FIFO) &&
60 (InterfaceId.Bits.CapFIFO != 0) &&
61 (InterfaceCapability.Bits.InterfaceVersion == INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP)) {
62 return PtpInterfaceFifo;
63 }
64 return PtpInterfaceTis;
65 }
66
67 EFI_TPM2_ACPI_TABLE mTpm2AcpiTemplate = {
68 {
69 EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE,
70 sizeof (mTpm2AcpiTemplate),
71 EFI_TPM2_ACPI_TABLE_REVISION,
72 //
73 // Compiler initializes the remaining bytes to 0
74 // These fields should be filled in in production
75 //
76 },
77 0, // Flags
78 0, // Control Area
79 EFI_TPM2_ACPI_TABLE_START_METHOD_TIS, // StartMethod
80 };
81
82 EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable;
83 TCG_NVS *mTcgNvs;
84
85 /**
86 Software SMI callback for TPM physical presence which is called from ACPI method.
87
88 Caution: This function may receive untrusted input.
89 Variable and ACPINvs are external input, so this function will validate
90 its data structure to be valid value.
91
92 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
93 @param[in] Context Points to an optional handler context which was specified when the
94 handler was registered.
95 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
96 be conveyed from a non-SMM environment into an SMM environment.
97 @param[in, out] CommBufferSize The size of the CommBuffer.
98
99 @retval EFI_SUCCESS The interrupt was handled successfully.
100
101 **/
102 EFI_STATUS
103 EFIAPI
104 PhysicalPresenceCallback (
105 IN EFI_HANDLE DispatchHandle,
106 IN CONST VOID *Context,
107 IN OUT VOID *CommBuffer,
108 IN OUT UINTN *CommBufferSize
109 )
110 {
111 UINT32 MostRecentRequest;
112 UINT32 Response;
113
114 if (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS) {
115 mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibReturnOperationResponseToOsFunction (
116 &MostRecentRequest,
117 &Response
118 );
119 mTcgNvs->PhysicalPresence.LastRequest = MostRecentRequest;
120 mTcgNvs->PhysicalPresence.Response = Response;
121 return EFI_SUCCESS;
122 } else if ((mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS)
123 || (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2)) {
124 mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction (
125 mTcgNvs->PhysicalPresence.Request,
126 mTcgNvs->PhysicalPresence.RequestParameter
127 );
128 } else if (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST) {
129 mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibGetUserConfirmationStatusFunction (mTcgNvs->PhysicalPresence.Request);
130 }
131
132 return EFI_SUCCESS;
133 }
134
135
136 /**
137 Software SMI callback for MemoryClear which is called from ACPI method.
138
139 Caution: This function may receive untrusted input.
140 Variable and ACPINvs are external input, so this function will validate
141 its data structure to be valid value.
142
143 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
144 @param[in] Context Points to an optional handler context which was specified when the
145 handler was registered.
146 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
147 be conveyed from a non-SMM environment into an SMM environment.
148 @param[in, out] CommBufferSize The size of the CommBuffer.
149
150 @retval EFI_SUCCESS The interrupt was handled successfully.
151
152 **/
153 EFI_STATUS
154 EFIAPI
155 MemoryClearCallback (
156 IN EFI_HANDLE DispatchHandle,
157 IN CONST VOID *Context,
158 IN OUT VOID *CommBuffer,
159 IN OUT UINTN *CommBufferSize
160 )
161 {
162 EFI_STATUS Status;
163 UINTN DataSize;
164 UINT8 MorControl;
165
166 mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_SUCCESS;
167 if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE) {
168 MorControl = (UINT8) mTcgNvs->MemoryClear.Request;
169 } else if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_PTS_CLEAR_MOR_BIT) {
170 DataSize = sizeof (UINT8);
171 Status = mSmmVariable->SmmGetVariable (
172 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
173 &gEfiMemoryOverwriteControlDataGuid,
174 NULL,
175 &DataSize,
176 &MorControl
177 );
178 if (EFI_ERROR (Status)) {
179 mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;
180 DEBUG ((EFI_D_ERROR, "[TPM] Get MOR variable failure! Status = %r\n", Status));
181 return EFI_SUCCESS;
182 }
183
184 if (MOR_CLEAR_MEMORY_VALUE (MorControl) == 0x0) {
185 return EFI_SUCCESS;
186 }
187 MorControl &= ~MOR_CLEAR_MEMORY_BIT_MASK;
188 }
189
190 DataSize = sizeof (UINT8);
191 Status = mSmmVariable->SmmSetVariable (
192 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
193 &gEfiMemoryOverwriteControlDataGuid,
194 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
195 DataSize,
196 &MorControl
197 );
198 if (EFI_ERROR (Status)) {
199 mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;
200 DEBUG ((EFI_D_ERROR, "[TPM] Set MOR variable failure! Status = %r\n", Status));
201 }
202
203 return EFI_SUCCESS;
204 }
205
206 /**
207 Find the operation region in TCG ACPI table by given Name and Size,
208 and initialize it if the region is found.
209
210 @param[in, out] Table The TPM item in ACPI table.
211 @param[in] Name The name string to find in TPM table.
212 @param[in] Size The size of the region to find.
213
214 @return The allocated address for the found region.
215
216 **/
217 VOID *
218 AssignOpRegion (
219 EFI_ACPI_DESCRIPTION_HEADER *Table,
220 UINT32 Name,
221 UINT16 Size
222 )
223 {
224 EFI_STATUS Status;
225 AML_OP_REGION_32_8 *OpRegion;
226 EFI_PHYSICAL_ADDRESS MemoryAddress;
227
228 MemoryAddress = SIZE_4GB - 1;
229
230 //
231 // Patch some pointers for the ASL code before loading the SSDT.
232 //
233 for (OpRegion = (AML_OP_REGION_32_8 *) (Table + 1);
234 OpRegion <= (AML_OP_REGION_32_8 *) ((UINT8 *) Table + Table->Length);
235 OpRegion = (AML_OP_REGION_32_8 *) ((UINT8 *) OpRegion + 1)) {
236 if ((OpRegion->OpRegionOp == AML_EXT_REGION_OP) &&
237 (OpRegion->NameString == Name) &&
238 (OpRegion->DWordPrefix == AML_DWORD_PREFIX) &&
239 (OpRegion->BytePrefix == AML_BYTE_PREFIX)) {
240
241 Status = gBS->AllocatePages(AllocateMaxAddress, EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (Size), &MemoryAddress);
242 ASSERT_EFI_ERROR (Status);
243 ZeroMem ((VOID *)(UINTN)MemoryAddress, Size);
244 OpRegion->RegionOffset = (UINT32) (UINTN) MemoryAddress;
245 OpRegion->RegionLen = (UINT8) Size;
246 break;
247 }
248 }
249
250 return (VOID *) (UINTN) MemoryAddress;
251 }
252
253 /**
254 Patch version string of Physical Presence interface supported by platform. The initial string tag in TPM
255 ACPI table is "$PV".
256
257 @param[in, out] Table The TPM item in ACPI table.
258 @param[in] PPVer Version string of Physical Presence interface supported by platform.
259
260 @return The allocated address for the found region.
261
262 **/
263 EFI_STATUS
264 UpdatePPVersion (
265 EFI_ACPI_DESCRIPTION_HEADER *Table,
266 CHAR8 *PPVer
267 )
268 {
269 EFI_STATUS Status;
270 UINT8 *DataPtr;
271
272 //
273 // Patch some pointers for the ASL code before loading the SSDT.
274 //
275 for (DataPtr = (UINT8 *)(Table + 1);
276 DataPtr <= (UINT8 *) ((UINT8 *) Table + Table->Length - PHYSICAL_PRESENCE_VERSION_SIZE);
277 DataPtr += 1) {
278 if (AsciiStrCmp(DataPtr, PHYSICAL_PRESENCE_VERSION_TAG) == 0) {
279 Status = AsciiStrCpyS(DataPtr, PHYSICAL_PRESENCE_VERSION_SIZE, PPVer);
280 DEBUG((EFI_D_INFO, "TPM2 Physical Presence Interface Version update status 0x%x\n", Status));
281 return Status;
282 }
283 }
284
285 return EFI_NOT_FOUND;
286 }
287
288 /**
289 Initialize and publish TPM items in ACPI table.
290
291 @retval EFI_SUCCESS The TCG ACPI table is published successfully.
292 @retval Others The TCG ACPI table is not published.
293
294 **/
295 EFI_STATUS
296 PublishAcpiTable (
297 VOID
298 )
299 {
300 EFI_STATUS Status;
301 EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
302 UINTN TableKey;
303 EFI_ACPI_DESCRIPTION_HEADER *Table;
304 UINTN TableSize;
305
306 Status = GetSectionFromFv (
307 &gEfiCallerIdGuid,
308 EFI_SECTION_RAW,
309 0,
310 (VOID **) &Table,
311 &TableSize
312 );
313 ASSERT_EFI_ERROR (Status);
314
315 //
316 // Update Table version before measuring it to PCR
317 //
318 Status = UpdatePPVersion(Table, (CHAR8 *)PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer));
319 ASSERT_EFI_ERROR (Status);
320
321 //
322 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
323 //
324 TpmMeasureAndLogData(
325 0,
326 EV_POST_CODE,
327 EV_POSTCODE_INFO_ACPI_DATA,
328 ACPI_DATA_LEN,
329 Table,
330 TableSize
331 );
332
333
334 ASSERT (Table->OemTableId == SIGNATURE_64 ('T', 'p', 'm', '2', 'T', 'a', 'b', 'l'));
335 CopyMem (Table->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (Table->OemId) );
336 mTcgNvs = AssignOpRegion (Table, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16) sizeof (TCG_NVS));
337 ASSERT (mTcgNvs != NULL);
338
339 //
340 // Publish the TPM ACPI table. Table is re-checksumed.
341 //
342 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
343 ASSERT_EFI_ERROR (Status);
344
345 TableKey = 0;
346 Status = AcpiTable->InstallAcpiTable (
347 AcpiTable,
348 Table,
349 TableSize,
350 &TableKey
351 );
352 ASSERT_EFI_ERROR (Status);
353
354 return Status;
355 }
356
357 /**
358 Publish TPM2 ACPI table
359
360 @retval EFI_SUCCESS The TPM2 ACPI table is published successfully.
361 @retval Others The TPM2 ACPI table is not published.
362
363 **/
364 EFI_STATUS
365 PublishTpm2 (
366 VOID
367 )
368 {
369 EFI_STATUS Status;
370 EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
371 UINTN TableKey;
372 UINT64 OemTableId;
373 EFI_TPM2_ACPI_CONTROL_AREA *ControlArea;
374 PTP_INTERFACE_TYPE InterfaceType;
375
376 //
377 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
378 //
379 TpmMeasureAndLogData(
380 0,
381 EV_POST_CODE,
382 EV_POSTCODE_INFO_ACPI_DATA,
383 ACPI_DATA_LEN,
384 &mTpm2AcpiTemplate,
385 sizeof(mTpm2AcpiTemplate)
386 );
387
388 InterfaceType = GetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress));
389 switch (InterfaceType) {
390 case PtpInterfaceCrb:
391 mTpm2AcpiTemplate.StartMethod = EFI_TPM2_ACPI_TABLE_START_METHOD_COMMAND_RESPONSE_BUFFER_INTERFACE;
392 mTpm2AcpiTemplate.AddressOfControlArea = PcdGet64 (PcdTpmBaseAddress) + 0x40;
393 ControlArea = (EFI_TPM2_ACPI_CONTROL_AREA *)(UINTN)mTpm2AcpiTemplate.AddressOfControlArea;
394 ControlArea->CommandSize = 0xF80;
395 ControlArea->ResponseSize = 0xF80;
396 ControlArea->Command = PcdGet64 (PcdTpmBaseAddress) + 0x80;
397 ControlArea->Response = PcdGet64 (PcdTpmBaseAddress) + 0x80;
398 break;
399 case PtpInterfaceFifo:
400 case PtpInterfaceTis:
401 break;
402 default:
403 break;
404 }
405
406 CopyMem (mTpm2AcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mTpm2AcpiTemplate.Header.OemId));
407 OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
408 CopyMem (&mTpm2AcpiTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64));
409 mTpm2AcpiTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
410 mTpm2AcpiTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
411 mTpm2AcpiTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
412
413 //
414 // Construct ACPI table
415 //
416 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
417 ASSERT_EFI_ERROR (Status);
418
419 Status = AcpiTable->InstallAcpiTable (
420 AcpiTable,
421 &mTpm2AcpiTemplate,
422 sizeof(mTpm2AcpiTemplate),
423 &TableKey
424 );
425 ASSERT_EFI_ERROR (Status);
426
427 return Status;
428 }
429
430 /**
431 The driver's entry point.
432
433 It install callbacks for TPM physical presence and MemoryClear, and locate
434 SMM variable to be used in the callback function.
435
436 @param[in] ImageHandle The firmware allocated handle for the EFI image.
437 @param[in] SystemTable A pointer to the EFI System Table.
438
439 @retval EFI_SUCCESS The entry point is executed successfully.
440 @retval Others Some error occurs when executing this entry point.
441
442 **/
443 EFI_STATUS
444 EFIAPI
445 InitializeTcgSmm (
446 IN EFI_HANDLE ImageHandle,
447 IN EFI_SYSTEM_TABLE *SystemTable
448 )
449 {
450 EFI_STATUS Status;
451 EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;
452 EFI_SMM_SW_REGISTER_CONTEXT SwContext;
453 EFI_HANDLE SwHandle;
454
455 if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm20DtpmGuid)){
456 DEBUG ((EFI_D_ERROR, "No TPM2 DTPM instance required!\n"));
457 return EFI_UNSUPPORTED;
458 }
459
460 Status = PublishAcpiTable ();
461 ASSERT_EFI_ERROR (Status);
462
463 //
464 // Get the Sw dispatch protocol and register SMI callback functions.
465 //
466 Status = gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID**)&SwDispatch);
467 ASSERT_EFI_ERROR (Status);
468 SwContext.SwSmiInputValue = (UINTN) -1;
469 Status = SwDispatch->Register (SwDispatch, PhysicalPresenceCallback, &SwContext, &SwHandle);
470 ASSERT_EFI_ERROR (Status);
471 if (EFI_ERROR (Status)) {
472 return Status;
473 }
474 mTcgNvs->PhysicalPresence.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;
475
476 SwContext.SwSmiInputValue = (UINTN) -1;
477 Status = SwDispatch->Register (SwDispatch, MemoryClearCallback, &SwContext, &SwHandle);
478 ASSERT_EFI_ERROR (Status);
479 if (EFI_ERROR (Status)) {
480 return Status;
481 }
482 mTcgNvs->MemoryClear.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;
483
484 //
485 // Locate SmmVariableProtocol.
486 //
487 Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mSmmVariable);
488 ASSERT_EFI_ERROR (Status);
489
490 //
491 // Set TPM2 ACPI table
492 //
493 Status = PublishTpm2 ();
494 ASSERT_EFI_ERROR (Status);
495
496
497 return EFI_SUCCESS;
498 }
499