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, 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 EFI_TPM2_ACPI_TABLE mTpm2AcpiTemplate = {
26 {
27 EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE,
28 sizeof (mTpm2AcpiTemplate),
29 EFI_TPM2_ACPI_TABLE_REVISION,
30 //
31 // Compiler initializes the remaining bytes to 0
32 // These fields should be filled in in production
33 //
34 },
35 0, // Flags
36 0, // Control Area
37 EFI_TPM2_ACPI_TABLE_START_METHOD_TIS, // StartMethod
38 };
39
40 EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable;
41 TCG_NVS *mTcgNvs;
42
43 /**
44 Software SMI callback for TPM physical presence which is called from ACPI method.
45
46 Caution: This function may receive untrusted input.
47 Variable and ACPINvs are external input, so this function will validate
48 its data structure to be valid value.
49
50 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
51 @param[in] Context Points to an optional handler context which was specified when the
52 handler was registered.
53 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
54 be conveyed from a non-SMM environment into an SMM environment.
55 @param[in, out] CommBufferSize The size of the CommBuffer.
56
57 @retval EFI_SUCCESS The interrupt was handled successfully.
58
59 **/
60 EFI_STATUS
61 EFIAPI
PhysicalPresenceCallback(IN EFI_HANDLE DispatchHandle,IN CONST VOID * Context,IN OUT VOID * CommBuffer,IN OUT UINTN * CommBufferSize)62 PhysicalPresenceCallback (
63 IN EFI_HANDLE DispatchHandle,
64 IN CONST VOID *Context,
65 IN OUT VOID *CommBuffer,
66 IN OUT UINTN *CommBufferSize
67 )
68 {
69 UINT32 MostRecentRequest;
70 UINT32 Response;
71
72 if (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS) {
73 mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibReturnOperationResponseToOsFunction (
74 &MostRecentRequest,
75 &Response
76 );
77 mTcgNvs->PhysicalPresence.LastRequest = MostRecentRequest;
78 mTcgNvs->PhysicalPresence.Response = Response;
79 return EFI_SUCCESS;
80 } else if ((mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS)
81 || (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2)) {
82 mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction (
83 mTcgNvs->PhysicalPresence.Request,
84 mTcgNvs->PhysicalPresence.RequestParameter
85 );
86 } else if (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST) {
87 mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibGetUserConfirmationStatusFunction (mTcgNvs->PhysicalPresence.Request);
88 }
89
90 return EFI_SUCCESS;
91 }
92
93
94 /**
95 Software SMI callback for MemoryClear which is called from ACPI method.
96
97 Caution: This function may receive untrusted input.
98 Variable and ACPINvs are external input, so this function will validate
99 its data structure to be valid value.
100
101 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
102 @param[in] Context Points to an optional handler context which was specified when the
103 handler was registered.
104 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
105 be conveyed from a non-SMM environment into an SMM environment.
106 @param[in, out] CommBufferSize The size of the CommBuffer.
107
108 @retval EFI_SUCCESS The interrupt was handled successfully.
109
110 **/
111 EFI_STATUS
112 EFIAPI
MemoryClearCallback(IN EFI_HANDLE DispatchHandle,IN CONST VOID * Context,IN OUT VOID * CommBuffer,IN OUT UINTN * CommBufferSize)113 MemoryClearCallback (
114 IN EFI_HANDLE DispatchHandle,
115 IN CONST VOID *Context,
116 IN OUT VOID *CommBuffer,
117 IN OUT UINTN *CommBufferSize
118 )
119 {
120 EFI_STATUS Status;
121 UINTN DataSize;
122 UINT8 MorControl;
123
124 mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_SUCCESS;
125 if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE) {
126 MorControl = (UINT8) mTcgNvs->MemoryClear.Request;
127 } else if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_PTS_CLEAR_MOR_BIT) {
128 DataSize = sizeof (UINT8);
129 Status = mSmmVariable->SmmGetVariable (
130 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
131 &gEfiMemoryOverwriteControlDataGuid,
132 NULL,
133 &DataSize,
134 &MorControl
135 );
136 if (EFI_ERROR (Status)) {
137 mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;
138 DEBUG ((EFI_D_ERROR, "[TPM] Get MOR variable failure! Status = %r\n", Status));
139 return EFI_SUCCESS;
140 }
141
142 if (MOR_CLEAR_MEMORY_VALUE (MorControl) == 0x0) {
143 return EFI_SUCCESS;
144 }
145 MorControl &= ~MOR_CLEAR_MEMORY_BIT_MASK;
146 }
147
148 DataSize = sizeof (UINT8);
149 Status = mSmmVariable->SmmSetVariable (
150 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
151 &gEfiMemoryOverwriteControlDataGuid,
152 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
153 DataSize,
154 &MorControl
155 );
156 if (EFI_ERROR (Status)) {
157 mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;
158 DEBUG ((EFI_D_ERROR, "[TPM] Set MOR variable failure! Status = %r\n", Status));
159 }
160
161 return EFI_SUCCESS;
162 }
163
164 /**
165 Find the operation region in TCG ACPI table by given Name and Size,
166 and initialize it if the region is found.
167
168 @param[in, out] Table The TPM item in ACPI table.
169 @param[in] Name The name string to find in TPM table.
170 @param[in] Size The size of the region to find.
171
172 @return The allocated address for the found region.
173
174 **/
175 VOID *
AssignOpRegion(EFI_ACPI_DESCRIPTION_HEADER * Table,UINT32 Name,UINT16 Size)176 AssignOpRegion (
177 EFI_ACPI_DESCRIPTION_HEADER *Table,
178 UINT32 Name,
179 UINT16 Size
180 )
181 {
182 EFI_STATUS Status;
183 AML_OP_REGION_32_8 *OpRegion;
184 EFI_PHYSICAL_ADDRESS MemoryAddress;
185
186 MemoryAddress = SIZE_4GB - 1;
187
188 //
189 // Patch some pointers for the ASL code before loading the SSDT.
190 //
191 for (OpRegion = (AML_OP_REGION_32_8 *) (Table + 1);
192 OpRegion <= (AML_OP_REGION_32_8 *) ((UINT8 *) Table + Table->Length);
193 OpRegion = (AML_OP_REGION_32_8 *) ((UINT8 *) OpRegion + 1)) {
194 if ((OpRegion->OpRegionOp == AML_EXT_REGION_OP) &&
195 (OpRegion->NameString == Name) &&
196 (OpRegion->DWordPrefix == AML_DWORD_PREFIX) &&
197 (OpRegion->BytePrefix == AML_BYTE_PREFIX)) {
198
199 Status = gBS->AllocatePages(AllocateMaxAddress, EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (Size), &MemoryAddress);
200 ASSERT_EFI_ERROR (Status);
201 ZeroMem ((VOID *)(UINTN)MemoryAddress, Size);
202 OpRegion->RegionOffset = (UINT32) (UINTN) MemoryAddress;
203 OpRegion->RegionLen = (UINT8) Size;
204 break;
205 }
206 }
207
208 return (VOID *) (UINTN) MemoryAddress;
209 }
210
211 /**
212 Initialize and publish TPM items in ACPI table.
213
214 @retval EFI_SUCCESS The TCG ACPI table is published successfully.
215 @retval Others The TCG ACPI table is not published.
216
217 **/
218 EFI_STATUS
PublishAcpiTable(VOID)219 PublishAcpiTable (
220 VOID
221 )
222 {
223 EFI_STATUS Status;
224 EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
225 UINTN TableKey;
226 EFI_ACPI_DESCRIPTION_HEADER *Table;
227 UINTN TableSize;
228
229 Status = GetSectionFromFv (
230 &gEfiCallerIdGuid,
231 EFI_SECTION_RAW,
232 0,
233 (VOID **) &Table,
234 &TableSize
235 );
236 ASSERT_EFI_ERROR (Status);
237
238
239 //
240 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
241 //
242 TpmMeasureAndLogData(
243 0,
244 EV_POST_CODE,
245 EV_POSTCODE_INFO_ACPI_DATA,
246 ACPI_DATA_LEN,
247 Table,
248 TableSize
249 );
250
251
252 ASSERT (Table->OemTableId == SIGNATURE_64 ('T', 'p', 'm', '2', 'T', 'a', 'b', 'l'));
253 CopyMem (Table->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (Table->OemId) );
254 mTcgNvs = AssignOpRegion (Table, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16) sizeof (TCG_NVS));
255 ASSERT (mTcgNvs != NULL);
256
257 //
258 // Publish the TPM ACPI table
259 //
260 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
261 ASSERT_EFI_ERROR (Status);
262
263 TableKey = 0;
264 Status = AcpiTable->InstallAcpiTable (
265 AcpiTable,
266 Table,
267 TableSize,
268 &TableKey
269 );
270 ASSERT_EFI_ERROR (Status);
271
272 return Status;
273 }
274
275 /**
276 Publish TPM2 ACPI table
277
278 @retval EFI_SUCCESS The TPM2 ACPI table is published successfully.
279 @retval Others The TPM2 ACPI table is not published.
280
281 **/
282 EFI_STATUS
PublishTpm2(VOID)283 PublishTpm2 (
284 VOID
285 )
286 {
287 EFI_STATUS Status;
288 EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
289 UINTN TableKey;
290 UINT64 OemTableId;
291
292 //
293 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
294 //
295 TpmMeasureAndLogData(
296 0,
297 EV_POST_CODE,
298 EV_POSTCODE_INFO_ACPI_DATA,
299 ACPI_DATA_LEN,
300 &mTpm2AcpiTemplate,
301 sizeof(mTpm2AcpiTemplate)
302 );
303
304 CopyMem (mTpm2AcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mTpm2AcpiTemplate.Header.OemId));
305 OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
306 CopyMem (&mTpm2AcpiTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64));
307 mTpm2AcpiTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
308 mTpm2AcpiTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
309 mTpm2AcpiTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
310
311 //
312 // Construct ACPI table
313 //
314 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
315 ASSERT_EFI_ERROR (Status);
316
317 Status = AcpiTable->InstallAcpiTable (
318 AcpiTable,
319 &mTpm2AcpiTemplate,
320 sizeof(mTpm2AcpiTemplate),
321 &TableKey
322 );
323 ASSERT_EFI_ERROR (Status);
324
325 return Status;
326 }
327
328 /**
329 The driver's entry point.
330
331 It install callbacks for TPM physical presence and MemoryClear, and locate
332 SMM variable to be used in the callback function.
333
334 @param[in] ImageHandle The firmware allocated handle for the EFI image.
335 @param[in] SystemTable A pointer to the EFI System Table.
336
337 @retval EFI_SUCCESS The entry point is executed successfully.
338 @retval Others Some error occurs when executing this entry point.
339
340 **/
341 EFI_STATUS
342 EFIAPI
InitializeTcgSmm(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)343 InitializeTcgSmm (
344 IN EFI_HANDLE ImageHandle,
345 IN EFI_SYSTEM_TABLE *SystemTable
346 )
347 {
348 EFI_STATUS Status;
349 EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;
350 EFI_SMM_SW_REGISTER_CONTEXT SwContext;
351 EFI_HANDLE SwHandle;
352
353 if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm20DtpmGuid)){
354 DEBUG ((EFI_D_ERROR, "No TPM2 DTPM instance required!\n"));
355 return EFI_UNSUPPORTED;
356 }
357
358 Status = PublishAcpiTable ();
359 ASSERT_EFI_ERROR (Status);
360
361 //
362 // Get the Sw dispatch protocol and register SMI callback functions.
363 //
364 Status = gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID**)&SwDispatch);
365 ASSERT_EFI_ERROR (Status);
366 SwContext.SwSmiInputValue = (UINTN) -1;
367 Status = SwDispatch->Register (SwDispatch, PhysicalPresenceCallback, &SwContext, &SwHandle);
368 ASSERT_EFI_ERROR (Status);
369 if (EFI_ERROR (Status)) {
370 return Status;
371 }
372 mTcgNvs->PhysicalPresence.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;
373
374 SwContext.SwSmiInputValue = (UINTN) -1;
375 Status = SwDispatch->Register (SwDispatch, MemoryClearCallback, &SwContext, &SwHandle);
376 ASSERT_EFI_ERROR (Status);
377 if (EFI_ERROR (Status)) {
378 return Status;
379 }
380 mTcgNvs->MemoryClear.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;
381
382 //
383 // Locate SmmVariableProtocol.
384 //
385 Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mSmmVariable);
386 ASSERT_EFI_ERROR (Status);
387
388 //
389 // Set TPM2 ACPI table
390 //
391 Status = PublishTpm2 ();
392 ASSERT_EFI_ERROR (Status);
393
394
395 return EFI_SUCCESS;
396 }
397
398