]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/Tcg/TcgSmm/TcgSmm.c
Remove duplicated AML code definitions as they have been added to common header.
[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 Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16
17 #include <PiDxe.h>
18 #include <IndustryStandard/Acpi.h>
19 #include <Guid/PhysicalPresenceData.h>
20 #include <Guid/MemoryOverwriteControl.h>
21 #include <Protocol/SmmSwDispatch2.h>
22 #include <Protocol/AcpiTable.h>
23 #include <Protocol/SmmVariable.h>
24
25 #include <Library/BaseLib.h>
26 #include <Library/BaseMemoryLib.h>
27 #include <Library/DebugLib.h>
28 #include <Library/SmmServicesTableLib.h>
29 #include <Library/UefiDriverEntryPoint.h>
30 #include <Library/UefiBootServicesTableLib.h>
31 #include <Library/DxeServicesLib.h>
32
33 #pragma pack(1)
34 typedef struct {
35 UINT8 SoftwareSmi;
36 UINT32 Parameter;
37 UINT32 Response;
38 UINT32 Request;
39 UINT32 LastRequest;
40 UINT32 ReturnCode;
41 } PHYSICAL_PRESENCE_NVS;
42
43 typedef struct {
44 UINT8 SoftwareSmi;
45 UINT32 Parameter;
46 UINT32 Request;
47 } MEMORY_CLEAR_NVS;
48
49 typedef struct {
50 PHYSICAL_PRESENCE_NVS PhysicalPresence;
51 MEMORY_CLEAR_NVS MemoryClear;
52 } TCG_NVS;
53
54 typedef struct {
55 UINT8 OpRegionOp;
56 UINT32 NameString;
57 UINT8 RegionSpace;
58 UINT8 DWordPrefix;
59 UINT32 RegionOffset;
60 UINT8 BytePrefix;
61 UINT8 RegionLen;
62 } AML_OP_REGION_32_8;
63 #pragma pack()
64
65 EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable;
66 TCG_NVS *mTcgNvs;
67
68 /**
69 Software SMI callback for TPM physical presence which is called from ACPI method.
70
71 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
72 @param[in] Context Points to an optional handler context which was specified when the
73 handler was registered.
74 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
75 be conveyed from a non-SMM environment into an SMM environment.
76 @param[in, out] CommBufferSize The size of the CommBuffer.
77
78 @retval EFI_SUCCESS The interrupt was handled successfully.
79
80 **/
81 EFI_STATUS
82 EFIAPI
83 PhysicalPresenceCallback (
84 IN EFI_HANDLE DispatchHandle,
85 IN CONST VOID *Context,
86 IN OUT VOID *CommBuffer,
87 IN OUT UINTN *CommBufferSize
88 )
89 {
90 EFI_STATUS Status;
91 UINTN DataSize;
92 EFI_PHYSICAL_PRESENCE PpData;
93 UINT8 Flags;
94 BOOLEAN RequestConfirmed;
95
96 //
97 // Get the Physical Presence variable
98 //
99 DataSize = sizeof (EFI_PHYSICAL_PRESENCE);
100 Status = mSmmVariable->SmmGetVariable (
101 PHYSICAL_PRESENCE_VARIABLE,
102 &gEfiPhysicalPresenceGuid,
103 NULL,
104 &DataSize,
105 &PpData
106 );
107 if (EFI_ERROR (Status)) {
108 return EFI_SUCCESS;
109 }
110
111 DEBUG ((EFI_D_INFO, "[TPM] PP callback, Parameter = %x\n", mTcgNvs->PhysicalPresence.Parameter));
112 if (mTcgNvs->PhysicalPresence.Parameter == 5) {
113 //
114 // Return TPM Operation Response to OS Environment
115 //
116 mTcgNvs->PhysicalPresence.LastRequest = PpData.LastPPRequest;
117 mTcgNvs->PhysicalPresence.Response = PpData.PPResponse;
118
119 } else if ((mTcgNvs->PhysicalPresence.Parameter == 2) || (mTcgNvs->PhysicalPresence.Parameter == 7)) {
120 //
121 // Submit TPM Operation Request to Pre-OS Environment
122 //
123
124 if (mTcgNvs->PhysicalPresence.Request == PHYSICAL_PRESENCE_SET_OPERATOR_AUTH) {
125 //
126 // This command requires UI to prompt user for Auth data, NOT implemented.
127 //
128 mTcgNvs->PhysicalPresence.ReturnCode = 1;
129 return EFI_SUCCESS;
130 }
131
132 if (PpData.PPRequest != mTcgNvs->PhysicalPresence.Request) {
133 PpData.PPRequest = (UINT8) mTcgNvs->PhysicalPresence.Request;
134 DataSize = sizeof (EFI_PHYSICAL_PRESENCE);
135 Status = mSmmVariable->SmmSetVariable (
136 PHYSICAL_PRESENCE_VARIABLE,
137 &gEfiPhysicalPresenceGuid,
138 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
139 DataSize,
140 &PpData
141 );
142 }
143
144 if (EFI_ERROR (Status)) {
145 //
146 // General failure.
147 //
148 mTcgNvs->PhysicalPresence.ReturnCode = 2;
149 return EFI_SUCCESS;
150 }
151 mTcgNvs->PhysicalPresence.ReturnCode = 0;
152 } else if (mTcgNvs->PhysicalPresence.Parameter == 8) {
153 //
154 // Get User Confirmation Status for Operation
155 //
156 Flags = PpData.Flags;
157 RequestConfirmed = FALSE;
158
159 switch (mTcgNvs->PhysicalPresence.Request) {
160 case PHYSICAL_PRESENCE_ENABLE:
161 case PHYSICAL_PRESENCE_DISABLE:
162 case PHYSICAL_PRESENCE_ACTIVATE:
163 case PHYSICAL_PRESENCE_DEACTIVATE:
164 case PHYSICAL_PRESENCE_ENABLE_ACTIVATE:
165 case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE:
166 case PHYSICAL_PRESENCE_SET_OWNER_INSTALL_TRUE:
167 case PHYSICAL_PRESENCE_SET_OWNER_INSTALL_FALSE:
168 case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_OWNER_TRUE:
169 case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE_OWNER_FALSE:
170 if ((Flags & FLAG_NO_PPI_PROVISION) != 0) {
171 RequestConfirmed = TRUE;
172 }
173 break;
174
175 case PHYSICAL_PRESENCE_CLEAR:
176 case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR:
177 if ((Flags & FLAG_NO_PPI_CLEAR) != 0) {
178 RequestConfirmed = TRUE;
179 }
180 break;
181
182 case PHYSICAL_PRESENCE_DEFERRED_PP_UNOWNERED_FIELD_UPGRADE:
183 if ((Flags & FLAG_NO_PPI_MAINTENANCE) != 0) {
184 RequestConfirmed = TRUE;
185 }
186 break;
187
188 case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE:
189 case PHYSICAL_PRESENCE_CLEAR_ENABLE_ACTIVATE:
190 if ((Flags & FLAG_NO_PPI_CLEAR) != 0 && (Flags & FLAG_NO_PPI_PROVISION) != 0) {
191 RequestConfirmed = TRUE;
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 // Here it is NOT implemented
206 //
207 mTcgNvs->PhysicalPresence.ReturnCode = 0;
208 return EFI_SUCCESS;
209 }
210
211 if (RequestConfirmed) {
212 //
213 // Allowed and physically present user not required
214 //
215 mTcgNvs->PhysicalPresence.ReturnCode = 4;
216 } else {
217 //
218 // Allowed and physically present user required
219 //
220 mTcgNvs->PhysicalPresence.ReturnCode = 3;
221 }
222 }
223
224 return EFI_SUCCESS;
225 }
226
227
228 /**
229 Software SMI callback for MemoryClear which is called from ACPI method.
230
231 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
232 @param[in] Context Points to an optional handler context which was specified when the
233 handler was registered.
234 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
235 be conveyed from a non-SMM environment into an SMM environment.
236 @param[in, out] CommBufferSize The size of the CommBuffer.
237
238 @retval EFI_SUCCESS The interrupt was handled successfully.
239
240 **/
241 EFI_STATUS
242 EFIAPI
243 MemoryClearCallback (
244 IN EFI_HANDLE DispatchHandle,
245 IN CONST VOID *Context,
246 IN OUT VOID *CommBuffer,
247 IN OUT UINTN *CommBufferSize
248 )
249 {
250 EFI_STATUS Status;
251 UINTN DataSize;
252 UINT8 MorControl;
253
254 if (mTcgNvs->MemoryClear.Parameter == 1) {
255 //
256 // Called from ACPI _DSM method, save the MOR data to variable.
257 //
258 MorControl = (UINT8) mTcgNvs->MemoryClear.Request;
259 } else if (mTcgNvs->MemoryClear.Parameter == 2) {
260 //
261 // Called from ACPI _PTS method, setup ClearMemory flags if needed.
262 //
263 DataSize = sizeof (UINT8);
264 Status = mSmmVariable->SmmGetVariable (
265 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
266 &gEfiMemoryOverwriteControlDataGuid,
267 NULL,
268 &DataSize,
269 &MorControl
270 );
271 if (EFI_ERROR (Status)) {
272 ASSERT (Status == EFI_NOT_FOUND);
273 return EFI_SUCCESS;
274 }
275
276 if (MOR_CLEAR_MEMORY_VALUE (MorControl) == 0x0) {
277 return EFI_SUCCESS;
278 }
279 MorControl &= ~MOR_CLEAR_MEMORY_BIT_MASK;
280 }
281
282 DataSize = sizeof (UINT8);
283 Status = mSmmVariable->SmmSetVariable (
284 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
285 &gEfiMemoryOverwriteControlDataGuid,
286 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
287 DataSize,
288 &MorControl
289 );
290 ASSERT_EFI_ERROR (Status);
291
292 return EFI_SUCCESS;
293 }
294
295 /**
296 Find the operation region in TCG ACPI table by given Name and Size,
297 and initialize it if the region is found.
298
299 @param[in, out] Table The TPM item in ACPI table.
300 @param[in] Name The name string to find in TPM table.
301 @param[in] Size The size of the region to find.
302
303 @return The allocated address for the found region.
304
305 **/
306 VOID *
307 AssignOpRegion (
308 EFI_ACPI_DESCRIPTION_HEADER *Table,
309 UINT32 Name,
310 UINT16 Size
311 )
312 {
313 EFI_STATUS Status;
314 AML_OP_REGION_32_8 *OpRegion;
315 EFI_PHYSICAL_ADDRESS MemoryAddress;
316
317 MemoryAddress = SIZE_4GB - 1;
318
319 //
320 // Patch some pointers for the ASL code before loading the SSDT.
321 //
322 for (OpRegion = (AML_OP_REGION_32_8 *) (Table + 1);
323 OpRegion <= (AML_OP_REGION_32_8 *) ((UINT8 *) Table + Table->Length);
324 OpRegion = (AML_OP_REGION_32_8 *) ((UINT8 *) OpRegion + 1)) {
325 if ((OpRegion->OpRegionOp == AML_EXT_REGION_OP) &&
326 (OpRegion->NameString == Name) &&
327 (OpRegion->RegionLen == Size) &&
328 (OpRegion->DWordPrefix == AML_DWORD_PREFIX) &&
329 (OpRegion->BytePrefix == AML_BYTE_PREFIX)) {
330
331 Status = gBS->AllocatePages(AllocateMaxAddress, EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (Size), &MemoryAddress);
332 ASSERT_EFI_ERROR (Status);
333 ZeroMem ((VOID *)(UINTN)MemoryAddress, Size);
334 OpRegion->RegionOffset = (UINT32) (UINTN) MemoryAddress;
335 break;
336 }
337 }
338
339 return (VOID *) (UINTN) MemoryAddress;
340 }
341
342 /**
343 Initialize and publish TPM items in ACPI table.
344
345 @retval EFI_SUCCESS The TCG ACPI table is published successfully.
346 @retval Others The TCG ACPI table is not published.
347
348 **/
349 EFI_STATUS
350 PublishAcpiTable (
351 VOID
352 )
353 {
354 EFI_STATUS Status;
355 EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
356 UINTN TableKey;
357 EFI_ACPI_DESCRIPTION_HEADER *Table;
358 UINTN TableSize;
359
360 Status = GetSectionFromFv (
361 &gEfiCallerIdGuid,
362 EFI_SECTION_RAW,
363 0,
364 (VOID **) &Table,
365 &TableSize
366 );
367 ASSERT_EFI_ERROR (Status);
368
369 ASSERT (Table->OemTableId == SIGNATURE_64 ('T', 'c', 'g', 'T', 'a', 'b', 'l', 'e'));
370 mTcgNvs = AssignOpRegion (Table, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16) sizeof (TCG_NVS));
371 ASSERT (mTcgNvs != NULL);
372
373 //
374 // Publish the TPM ACPI table
375 //
376 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
377 ASSERT_EFI_ERROR (Status);
378
379 TableKey = 0;
380 Status = AcpiTable->InstallAcpiTable (
381 AcpiTable,
382 Table,
383 TableSize,
384 &TableKey
385 );
386 ASSERT_EFI_ERROR (Status);
387
388 return Status;
389 }
390
391 /**
392 The driver's entry point.
393
394 It install callbacks for TPM physical presence and MemoryClear, and locate
395 SMM variable to be used in the callback function.
396
397 @param[in] ImageHandle The firmware allocated handle for the EFI image.
398 @param[in] SystemTable A pointer to the EFI System Table.
399
400 @retval EFI_SUCCESS The entry point is executed successfully.
401 @retval Others Some error occurs when executing this entry point.
402
403 **/
404 EFI_STATUS
405 EFIAPI
406 InitializeTcgSmm (
407 IN EFI_HANDLE ImageHandle,
408 IN EFI_SYSTEM_TABLE *SystemTable
409 )
410 {
411 EFI_STATUS Status;
412 EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;
413 EFI_SMM_SW_REGISTER_CONTEXT SwContext;
414 EFI_HANDLE SwHandle;
415
416 Status = PublishAcpiTable ();
417 ASSERT_EFI_ERROR (Status);
418
419 //
420 // Get the Sw dispatch protocol and register SMI callback functions.
421 //
422 Status = gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID**)&SwDispatch);
423 ASSERT_EFI_ERROR (Status);
424 SwContext.SwSmiInputValue = (UINTN) -1;
425 Status = SwDispatch->Register (SwDispatch, PhysicalPresenceCallback, &SwContext, &SwHandle);
426 ASSERT_EFI_ERROR (Status);
427 if (EFI_ERROR (Status)) {
428 return Status;
429 }
430 mTcgNvs->PhysicalPresence.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;
431
432 SwContext.SwSmiInputValue = (UINTN) -1;
433 Status = SwDispatch->Register (SwDispatch, MemoryClearCallback, &SwContext, &SwHandle);
434 ASSERT_EFI_ERROR (Status);
435 if (EFI_ERROR (Status)) {
436 return Status;
437 }
438 mTcgNvs->MemoryClear.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;
439
440 //
441 // Locate SmmVariableProtocol.
442 //
443 Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mSmmVariable);
444 ASSERT_EFI_ERROR (Status);
445
446 return EFI_SUCCESS;
447 }
448