]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/Tcg/TcgSmm/TcgSmm.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / SecurityPkg / Tcg / TcgSmm / TcgSmm.c
1 /** @file
2 It updates TPM items in ACPI table and registers SMI callback
3 functions for physical presence and ClearMemory.
4
5 Caution: This module requires additional review when modified.
6 This driver will have external input - variable and ACPINvs data in SMM mode.
7 This external input must be validated carefully to avoid security issue.
8
9 PhysicalPresenceCallback() and MemoryClearCallback() will receive untrusted input and do some check.
10
11 Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
12 SPDX-License-Identifier: BSD-2-Clause-Patent
13
14 **/
15
16 #include "TcgSmm.h"
17
18 EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable;
19 TCG_NVS *mTcgNvs;
20
21 /**
22 Software SMI callback for TPM physical presence which is called from ACPI method.
23
24 Caution: This function may receive untrusted input.
25 Variable and ACPINvs are external input, so this function will validate
26 its data structure to be valid value.
27
28 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
29 @param[in] Context Points to an optional handler context which was specified when the
30 handler was registered.
31 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
32 be conveyed from a non-SMM environment into an SMM environment.
33 @param[in, out] CommBufferSize The size of the CommBuffer.
34
35 @retval EFI_SUCCESS The interrupt was handled successfully.
36
37 **/
38 EFI_STATUS
39 EFIAPI
40 PhysicalPresenceCallback (
41 IN EFI_HANDLE DispatchHandle,
42 IN CONST VOID *Context,
43 IN OUT VOID *CommBuffer,
44 IN OUT UINTN *CommBufferSize
45 )
46 {
47 EFI_STATUS Status;
48 UINTN DataSize;
49 EFI_PHYSICAL_PRESENCE PpData;
50 EFI_PHYSICAL_PRESENCE_FLAGS Flags;
51 BOOLEAN RequestConfirmed;
52
53 //
54 // Get the Physical Presence variable
55 //
56 DataSize = sizeof (EFI_PHYSICAL_PRESENCE);
57 Status = mSmmVariable->SmmGetVariable (
58 PHYSICAL_PRESENCE_VARIABLE,
59 &gEfiPhysicalPresenceGuid,
60 NULL,
61 &DataSize,
62 &PpData
63 );
64
65 DEBUG ((DEBUG_INFO, "[TPM] PP callback, Parameter = %x\n", mTcgNvs->PhysicalPresence.Parameter));
66 if (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS) {
67 if (EFI_ERROR (Status)) {
68 mTcgNvs->PhysicalPresence.ReturnCode = PP_RETURN_TPM_OPERATION_RESPONSE_FAILURE;
69 mTcgNvs->PhysicalPresence.LastRequest = 0;
70 mTcgNvs->PhysicalPresence.Response = 0;
71 DEBUG ((DEBUG_ERROR, "[TPM] Get PP variable failure! Status = %r\n", Status));
72 return EFI_SUCCESS;
73 }
74
75 mTcgNvs->PhysicalPresence.ReturnCode = PP_RETURN_TPM_OPERATION_RESPONSE_SUCCESS;
76 mTcgNvs->PhysicalPresence.LastRequest = PpData.LastPPRequest;
77 mTcgNvs->PhysicalPresence.Response = PpData.PPResponse;
78 } else if ( (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS)
79 || (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2))
80 {
81 if (EFI_ERROR (Status)) {
82 mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE;
83 DEBUG ((DEBUG_ERROR, "[TPM] Get PP variable failure! Status = %r\n", Status));
84 return EFI_SUCCESS;
85 }
86
87 if (mTcgNvs->PhysicalPresence.Request == PHYSICAL_PRESENCE_SET_OPERATOR_AUTH) {
88 //
89 // This command requires UI to prompt user for Auth data.
90 //
91 mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED;
92 return EFI_SUCCESS;
93 }
94
95 if (PpData.PPRequest != mTcgNvs->PhysicalPresence.Request) {
96 PpData.PPRequest = (UINT8)mTcgNvs->PhysicalPresence.Request;
97 DataSize = sizeof (EFI_PHYSICAL_PRESENCE);
98 Status = mSmmVariable->SmmSetVariable (
99 PHYSICAL_PRESENCE_VARIABLE,
100 &gEfiPhysicalPresenceGuid,
101 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
102 DataSize,
103 &PpData
104 );
105 }
106
107 if (EFI_ERROR (Status)) {
108 mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE;
109 return EFI_SUCCESS;
110 }
111
112 mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS;
113
114 if (mTcgNvs->PhysicalPresence.Request >= TCG_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
115 DataSize = sizeof (EFI_PHYSICAL_PRESENCE_FLAGS);
116 Status = mSmmVariable->SmmGetVariable (
117 PHYSICAL_PRESENCE_FLAGS_VARIABLE,
118 &gEfiPhysicalPresenceGuid,
119 NULL,
120 &DataSize,
121 &Flags
122 );
123 if (EFI_ERROR (Status)) {
124 Flags.PPFlags = TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_PROVISION;
125 }
126
127 mTcgNvs->PhysicalPresence.ReturnCode = TcgPpVendorLibSubmitRequestToPreOSFunction (mTcgNvs->PhysicalPresence.Request, Flags.PPFlags);
128 }
129 } else if (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST) {
130 if (EFI_ERROR (Status)) {
131 mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_GET_USER_CONFIRMATION_BLOCKED_BY_BIOS_CONFIGURATION;
132 DEBUG ((DEBUG_ERROR, "[TPM] Get PP variable failure! Status = %r\n", Status));
133 return EFI_SUCCESS;
134 }
135
136 //
137 // Get the Physical Presence flags
138 //
139 DataSize = sizeof (EFI_PHYSICAL_PRESENCE_FLAGS);
140 Status = mSmmVariable->SmmGetVariable (
141 PHYSICAL_PRESENCE_FLAGS_VARIABLE,
142 &gEfiPhysicalPresenceGuid,
143 NULL,
144 &DataSize,
145 &Flags
146 );
147 if (EFI_ERROR (Status)) {
148 mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_GET_USER_CONFIRMATION_BLOCKED_BY_BIOS_CONFIGURATION;
149 DEBUG ((DEBUG_ERROR, "[TPM] Get PP flags failure! Status = %r\n", Status));
150 return EFI_SUCCESS;
151 }
152
153 RequestConfirmed = FALSE;
154
155 switch (mTcgNvs->PPRequestUserConfirm) {
156 case PHYSICAL_PRESENCE_ENABLE:
157 case PHYSICAL_PRESENCE_DISABLE:
158 case PHYSICAL_PRESENCE_ACTIVATE:
159 case PHYSICAL_PRESENCE_DEACTIVATE:
160 case PHYSICAL_PRESENCE_ENABLE_ACTIVATE:
161 case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE:
162 case PHYSICAL_PRESENCE_SET_OWNER_INSTALL_TRUE:
163 case PHYSICAL_PRESENCE_SET_OWNER_INSTALL_FALSE:
164 case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_OWNER_TRUE:
165 case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE_OWNER_FALSE:
166 if ((Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_PROVISION) != 0) {
167 RequestConfirmed = TRUE;
168 }
169
170 break;
171
172 case PHYSICAL_PRESENCE_CLEAR:
173 case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR:
174 if ((Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR) != 0) {
175 RequestConfirmed = TRUE;
176 }
177
178 break;
179
180 case PHYSICAL_PRESENCE_DEFERRED_PP_UNOWNERED_FIELD_UPGRADE:
181 if ((Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_MAINTENANCE) != 0) {
182 RequestConfirmed = TRUE;
183 }
184
185 break;
186
187 case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE:
188 case PHYSICAL_PRESENCE_CLEAR_ENABLE_ACTIVATE:
189 if (((Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR) != 0) && ((Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_PROVISION) != 0)) {
190 RequestConfirmed = TRUE;
191 }
192
193 break;
194
195 case PHYSICAL_PRESENCE_SET_NO_PPI_PROVISION_FALSE:
196 case PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_FALSE:
197 case PHYSICAL_PRESENCE_SET_NO_PPI_MAINTENANCE_FALSE:
198 case PHYSICAL_PRESENCE_NO_ACTION:
199 RequestConfirmed = TRUE;
200 break;
201
202 case PHYSICAL_PRESENCE_SET_OPERATOR_AUTH:
203 //
204 // This command requires UI to prompt user for Auth data
205 //
206 mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_GET_USER_CONFIRMATION_NOT_IMPLEMENTED;
207 return EFI_SUCCESS;
208 default:
209 break;
210 }
211
212 if (RequestConfirmed) {
213 mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_GET_USER_CONFIRMATION_ALLOWED_AND_PPUSER_NOT_REQUIRED;
214 } else {
215 mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_GET_USER_CONFIRMATION_ALLOWED_AND_PPUSER_REQUIRED;
216 }
217
218 if (mTcgNvs->PhysicalPresence.Request >= TCG_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
219 mTcgNvs->PhysicalPresence.ReturnCode = TcgPpVendorLibGetUserConfirmationStatusFunction (mTcgNvs->PhysicalPresence.Request, Flags.PPFlags);
220 }
221 }
222
223 return EFI_SUCCESS;
224 }
225
226 /**
227 Software SMI callback for MemoryClear which is called from ACPI method.
228
229 Caution: This function may receive untrusted input.
230 Variable and ACPINvs are external input, so this function will validate
231 its data structure to be valid value.
232
233 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
234 @param[in] Context Points to an optional handler context which was specified when the
235 handler was registered.
236 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
237 be conveyed from a non-SMM environment into an SMM environment.
238 @param[in, out] CommBufferSize The size of the CommBuffer.
239
240 @retval EFI_SUCCESS The interrupt was handled successfully.
241
242 **/
243 EFI_STATUS
244 EFIAPI
245 MemoryClearCallback (
246 IN EFI_HANDLE DispatchHandle,
247 IN CONST VOID *Context,
248 IN OUT VOID *CommBuffer,
249 IN OUT UINTN *CommBufferSize
250 )
251 {
252 EFI_STATUS Status;
253 UINTN DataSize;
254 UINT8 MorControl;
255
256 mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_SUCCESS;
257 if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE) {
258 MorControl = (UINT8)mTcgNvs->MemoryClear.Request;
259 } else if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_PTS_CLEAR_MOR_BIT) {
260 DataSize = sizeof (UINT8);
261 Status = mSmmVariable->SmmGetVariable (
262 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
263 &gEfiMemoryOverwriteControlDataGuid,
264 NULL,
265 &DataSize,
266 &MorControl
267 );
268 if (EFI_ERROR (Status)) {
269 mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;
270 DEBUG ((DEBUG_ERROR, "[TPM] Get MOR variable failure! Status = %r\n", Status));
271 return EFI_SUCCESS;
272 }
273
274 if (MOR_CLEAR_MEMORY_VALUE (MorControl) == 0x0) {
275 return EFI_SUCCESS;
276 }
277
278 MorControl &= ~MOR_CLEAR_MEMORY_BIT_MASK;
279 } else {
280 mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;
281 DEBUG ((DEBUG_ERROR, "[TPM] MOR Parameter error! Parameter = %x\n", mTcgNvs->MemoryClear.Parameter));
282 return EFI_SUCCESS;
283 }
284
285 DataSize = sizeof (UINT8);
286 Status = mSmmVariable->SmmSetVariable (
287 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
288 &gEfiMemoryOverwriteControlDataGuid,
289 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
290 DataSize,
291 &MorControl
292 );
293 if (EFI_ERROR (Status)) {
294 mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;
295 DEBUG ((DEBUG_ERROR, "[TPM] Set MOR variable failure! Status = %r\n", Status));
296 }
297
298 return EFI_SUCCESS;
299 }
300
301 /**
302 Find the operation region in TCG ACPI table by given Name and Size,
303 and initialize it if the region is found.
304
305 @param[in, out] Table The TPM item in ACPI table.
306 @param[in] Name The name string to find in TPM table.
307 @param[in] Size The size of the region to find.
308
309 @return The allocated address for the found region.
310
311 **/
312 VOID *
313 AssignOpRegion (
314 EFI_ACPI_DESCRIPTION_HEADER *Table,
315 UINT32 Name,
316 UINT16 Size
317 )
318 {
319 EFI_STATUS Status;
320 AML_OP_REGION_32_8 *OpRegion;
321 EFI_PHYSICAL_ADDRESS MemoryAddress;
322
323 MemoryAddress = SIZE_4GB - 1;
324
325 //
326 // Patch some pointers for the ASL code before loading the SSDT.
327 //
328 for (OpRegion = (AML_OP_REGION_32_8 *)(Table + 1);
329 OpRegion <= (AML_OP_REGION_32_8 *)((UINT8 *)Table + Table->Length);
330 OpRegion = (AML_OP_REGION_32_8 *)((UINT8 *)OpRegion + 1))
331 {
332 if ((OpRegion->OpRegionOp == AML_EXT_REGION_OP) &&
333 (OpRegion->NameString == Name) &&
334 (OpRegion->DWordPrefix == AML_DWORD_PREFIX) &&
335 (OpRegion->BytePrefix == AML_BYTE_PREFIX))
336 {
337 Status = gBS->AllocatePages (AllocateMaxAddress, EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (Size), &MemoryAddress);
338 ASSERT_EFI_ERROR (Status);
339 ZeroMem ((VOID *)(UINTN)MemoryAddress, Size);
340 OpRegion->RegionOffset = (UINT32)(UINTN)MemoryAddress;
341 OpRegion->RegionLen = (UINT8)Size;
342 break;
343 }
344 }
345
346 return (VOID *)(UINTN)MemoryAddress;
347 }
348
349 /**
350 Initialize and publish TPM items in ACPI table.
351
352 @retval EFI_SUCCESS The TCG ACPI table is published successfully.
353 @retval Others The TCG ACPI table is not published.
354
355 **/
356 EFI_STATUS
357 PublishAcpiTable (
358 VOID
359 )
360 {
361 EFI_STATUS Status;
362 EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
363 UINTN TableKey;
364 EFI_ACPI_DESCRIPTION_HEADER *Table;
365 UINTN TableSize;
366
367 Status = GetSectionFromFv (
368 &gEfiCallerIdGuid,
369 EFI_SECTION_RAW,
370 0,
371 (VOID **)&Table,
372 &TableSize
373 );
374 ASSERT_EFI_ERROR (Status);
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 Table,
385 TableSize
386 );
387
388 ASSERT (Table->OemTableId == SIGNATURE_64 ('T', 'c', 'g', 'T', 'a', 'b', 'l', 'e'));
389 CopyMem (Table->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (Table->OemId));
390 mTcgNvs = AssignOpRegion (Table, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16)sizeof (TCG_NVS));
391 ASSERT (mTcgNvs != NULL);
392
393 //
394 // Publish the TPM ACPI table
395 //
396 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **)&AcpiTable);
397 ASSERT_EFI_ERROR (Status);
398
399 TableKey = 0;
400 Status = AcpiTable->InstallAcpiTable (
401 AcpiTable,
402 Table,
403 TableSize,
404 &TableKey
405 );
406 ASSERT_EFI_ERROR (Status);
407
408 return Status;
409 }
410
411 /**
412 The driver's entry point.
413
414 It install callbacks for TPM physical presence and MemoryClear, and locate
415 SMM variable to be used in the callback function.
416
417 @param[in] ImageHandle The firmware allocated handle for the EFI image.
418 @param[in] SystemTable A pointer to the EFI System Table.
419
420 @retval EFI_SUCCESS The entry point is executed successfully.
421 @retval Others Some error occurs when executing this entry point.
422
423 **/
424 EFI_STATUS
425 EFIAPI
426 InitializeTcgSmm (
427 IN EFI_HANDLE ImageHandle,
428 IN EFI_SYSTEM_TABLE *SystemTable
429 )
430 {
431 EFI_STATUS Status;
432 EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;
433 EFI_SMM_SW_REGISTER_CONTEXT SwContext;
434 EFI_HANDLE SwHandle;
435
436 if (!CompareGuid (PcdGetPtr (PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)) {
437 DEBUG ((DEBUG_ERROR, "No TPM12 instance required!\n"));
438 return EFI_UNSUPPORTED;
439 }
440
441 Status = PublishAcpiTable ();
442 ASSERT_EFI_ERROR (Status);
443
444 //
445 // Get the Sw dispatch protocol and register SMI callback functions.
446 //
447 Status = gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID **)&SwDispatch);
448 ASSERT_EFI_ERROR (Status);
449 SwContext.SwSmiInputValue = (UINTN)-1;
450 Status = SwDispatch->Register (SwDispatch, PhysicalPresenceCallback, &SwContext, &SwHandle);
451 ASSERT_EFI_ERROR (Status);
452 if (EFI_ERROR (Status)) {
453 return Status;
454 }
455
456 mTcgNvs->PhysicalPresence.SoftwareSmi = (UINT8)SwContext.SwSmiInputValue;
457
458 SwContext.SwSmiInputValue = (UINTN)-1;
459 Status = SwDispatch->Register (SwDispatch, MemoryClearCallback, &SwContext, &SwHandle);
460 ASSERT_EFI_ERROR (Status);
461 if (EFI_ERROR (Status)) {
462 return Status;
463 }
464
465 mTcgNvs->MemoryClear.SoftwareSmi = (UINT8)SwContext.SwSmiInputValue;
466
467 //
468 // Locate SmmVariableProtocol.
469 //
470 Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **)&mSmmVariable);
471 ASSERT_EFI_ERROR (Status);
472
473 return EFI_SUCCESS;
474 }