1 /** @file
2
3 Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
4
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions
7 of the BSD License which accompanies this distribution. The
8 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 #include <PiSmm.h>
17 #include <Library/SmmServicesTableLib.h>
18 #include <Library/BaseLib.h>
19 #include <Library/BaseMemoryLib.h>
20 #include <Library/LockBoxLib.h>
21 #include <Library/DebugLib.h>
22 #include <Guid/SmmLockBox.h>
23
24 #include "SmmLockBoxLibPrivate.h"
25
26 /**
27 We need handle this library carefully. Only one library instance will construct the environment.
28 Below 2 global variable can only be used in constructor. They should NOT be used in any other library functions.
29 **/
30 SMM_LOCK_BOX_CONTEXT mSmmLockBoxContext;
31 LIST_ENTRY mLockBoxQueue = INITIALIZE_LIST_HEAD_VARIABLE (mLockBoxQueue);
32
33 BOOLEAN mSmmConfigurationTableInstalled = FALSE;
34
35 /**
36 This function return SmmLockBox context from SMST.
37
38 @return SmmLockBox context from SMST.
39 **/
40 SMM_LOCK_BOX_CONTEXT *
InternalGetSmmLockBoxContext(VOID)41 InternalGetSmmLockBoxContext (
42 VOID
43 )
44 {
45 UINTN Index;
46
47 //
48 // Check if gEfiSmmLockBoxCommunicationGuid is installed by someone
49 //
50 for (Index = 0; Index < gSmst->NumberOfTableEntries; Index++) {
51 if (CompareGuid (&gSmst->SmmConfigurationTable[Index].VendorGuid, &gEfiSmmLockBoxCommunicationGuid)) {
52 //
53 // Found. That means some other library instance is already run.
54 // No need to install again, just return.
55 //
56 return (SMM_LOCK_BOX_CONTEXT *)gSmst->SmmConfigurationTable[Index].VendorTable;
57 }
58 }
59
60 //
61 // Not found.
62 //
63 return NULL;
64 }
65
66 /**
67 Constructor for SmmLockBox library.
68 This is used to set SmmLockBox context, which will be used in PEI phase in S3 boot path later.
69
70 @param[in] ImageHandle Image handle of this driver.
71 @param[in] SystemTable A Pointer to the EFI System Table.
72
73 @retval EFI_SUCEESS
74 @return Others Some error occurs.
75 **/
76 EFI_STATUS
77 EFIAPI
SmmLockBoxSmmConstructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)78 SmmLockBoxSmmConstructor (
79 IN EFI_HANDLE ImageHandle,
80 IN EFI_SYSTEM_TABLE *SystemTable
81 )
82 {
83 EFI_STATUS Status;
84 SMM_LOCK_BOX_CONTEXT *SmmLockBoxContext;
85
86 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SmmLockBoxSmmConstructor - Enter\n"));
87
88 //
89 // Check if gEfiSmmLockBoxCommunicationGuid is installed by someone
90 //
91 SmmLockBoxContext = InternalGetSmmLockBoxContext ();
92 if (SmmLockBoxContext != NULL) {
93 //
94 // Find it. That means some other library instance is already run.
95 // No need to install again, just return.
96 //
97 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SmmLockBoxContext - already installed\n"));
98 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SmmLockBoxSmmConstructor - Exit\n"));
99 return EFI_SUCCESS;
100 }
101
102 //
103 // If no one install this, it means this is first instance. Install it.
104 //
105 if (sizeof(UINTN) == sizeof(UINT64)) {
106 mSmmLockBoxContext.Signature = SMM_LOCK_BOX_SIGNATURE_64;
107 } else {
108 mSmmLockBoxContext.Signature = SMM_LOCK_BOX_SIGNATURE_32;
109 }
110 mSmmLockBoxContext.LockBoxDataAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)&mLockBoxQueue;
111
112 Status = gSmst->SmmInstallConfigurationTable (
113 gSmst,
114 &gEfiSmmLockBoxCommunicationGuid,
115 &mSmmLockBoxContext,
116 sizeof(mSmmLockBoxContext)
117 );
118 ASSERT_EFI_ERROR (Status);
119 mSmmConfigurationTableInstalled = TRUE;
120
121 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SmmLockBoxContext - %x\n", (UINTN)&mSmmLockBoxContext));
122 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib LockBoxDataAddress - %x\n", (UINTN)&mLockBoxQueue));
123 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SmmLockBoxSmmConstructor - Exit\n"));
124
125 return Status;
126 }
127
128 /**
129 Destructor for SmmLockBox library.
130 This is used to uninstall SmmLockBoxCommunication configuration table
131 if it has been installed in Constructor.
132
133 @param[in] ImageHandle Image handle of this driver.
134 @param[in] SystemTable A Pointer to the EFI System Table.
135
136 @retval EFI_SUCEESS The destructor always returns EFI_SUCCESS.
137
138 **/
139 EFI_STATUS
140 EFIAPI
SmmLockBoxSmmDestructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)141 SmmLockBoxSmmDestructor (
142 IN EFI_HANDLE ImageHandle,
143 IN EFI_SYSTEM_TABLE *SystemTable
144 )
145 {
146 EFI_STATUS Status;
147
148 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SmmLockBoxSmmDestructor in %a module\n", gEfiCallerBaseName));
149
150 if (mSmmConfigurationTableInstalled) {
151 Status = gSmst->SmmInstallConfigurationTable (
152 gSmst,
153 &gEfiSmmLockBoxCommunicationGuid,
154 NULL,
155 0
156 );
157 ASSERT_EFI_ERROR (Status);
158 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib uninstall SmmLockBoxCommunication configuration table\n"));
159 }
160
161 return EFI_SUCCESS;
162 }
163
164 /**
165 This function return SmmLockBox queue address.
166
167 @return SmmLockBox queue address.
168 **/
169 LIST_ENTRY *
InternalGetLockBoxQueue(VOID)170 InternalGetLockBoxQueue (
171 VOID
172 )
173 {
174 SMM_LOCK_BOX_CONTEXT *SmmLockBoxContext;
175
176 SmmLockBoxContext = InternalGetSmmLockBoxContext ();
177 ASSERT (SmmLockBoxContext != NULL);
178 if (SmmLockBoxContext == NULL) {
179 return NULL;
180 }
181 return (LIST_ENTRY *)(UINTN)SmmLockBoxContext->LockBoxDataAddress;
182 }
183
184 /**
185 This function find LockBox by GUID.
186
187 @param Guid The guid to indentify the LockBox
188
189 @return LockBoxData
190 **/
191 SMM_LOCK_BOX_DATA *
InternalFindLockBoxByGuid(IN EFI_GUID * Guid)192 InternalFindLockBoxByGuid (
193 IN EFI_GUID *Guid
194 )
195 {
196 LIST_ENTRY *Link;
197 SMM_LOCK_BOX_DATA *LockBox;
198 LIST_ENTRY *LockBoxQueue;
199
200 LockBoxQueue = InternalGetLockBoxQueue ();
201 ASSERT (LockBoxQueue != NULL);
202
203 for (Link = LockBoxQueue->ForwardLink;
204 Link != LockBoxQueue;
205 Link = Link->ForwardLink) {
206 LockBox = BASE_CR (
207 Link,
208 SMM_LOCK_BOX_DATA,
209 Link
210 );
211 if (CompareGuid (&LockBox->Guid, Guid)) {
212 return LockBox;
213 }
214 }
215 return NULL;
216 }
217
218 /**
219 This function will save confidential information to lockbox.
220
221 @param Guid the guid to identify the confidential information
222 @param Buffer the address of the confidential information
223 @param Length the length of the confidential information
224
225 @retval RETURN_SUCCESS the information is saved successfully.
226 @retval RETURN_INVALID_PARAMETER the Guid is NULL, or Buffer is NULL, or Length is 0
227 @retval RETURN_ALREADY_STARTED the requested GUID already exist.
228 @retval RETURN_OUT_OF_RESOURCES no enough resource to save the information.
229 @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
230 @retval RETURN_NOT_STARTED it is too early to invoke this interface
231 @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
232 **/
233 RETURN_STATUS
234 EFIAPI
SaveLockBox(IN GUID * Guid,IN VOID * Buffer,IN UINTN Length)235 SaveLockBox (
236 IN GUID *Guid,
237 IN VOID *Buffer,
238 IN UINTN Length
239 )
240 {
241 SMM_LOCK_BOX_DATA *LockBox;
242 EFI_PHYSICAL_ADDRESS SmramBuffer;
243 EFI_STATUS Status;
244 LIST_ENTRY *LockBoxQueue;
245
246 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SaveLockBox - Enter\n"));
247
248 //
249 // Basic check
250 //
251 if ((Guid == NULL) || (Buffer == NULL) || (Length == 0)) {
252 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_INVALID_PARAMETER));
253 return EFI_INVALID_PARAMETER;
254 }
255
256 //
257 // Find LockBox
258 //
259 LockBox = InternalFindLockBoxByGuid (Guid);
260 if (LockBox != NULL) {
261 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_ALREADY_STARTED));
262 return EFI_ALREADY_STARTED;
263 }
264
265 //
266 // Allocate SMRAM buffer
267 //
268 Status = gSmst->SmmAllocatePages (
269 AllocateAnyPages,
270 EfiRuntimeServicesData,
271 EFI_SIZE_TO_PAGES (Length),
272 &SmramBuffer
273 );
274 ASSERT_EFI_ERROR (Status);
275 if (EFI_ERROR (Status)) {
276 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_OUT_OF_RESOURCES));
277 return EFI_OUT_OF_RESOURCES;
278 }
279
280 //
281 // Allocate LockBox
282 //
283 Status = gSmst->SmmAllocatePool (
284 EfiRuntimeServicesData,
285 sizeof(*LockBox),
286 (VOID **)&LockBox
287 );
288 ASSERT_EFI_ERROR (Status);
289 if (EFI_ERROR (Status)) {
290 gSmst->SmmFreePages (SmramBuffer, EFI_SIZE_TO_PAGES (Length));
291 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_OUT_OF_RESOURCES));
292 return EFI_OUT_OF_RESOURCES;
293 }
294
295 //
296 // Save data
297 //
298 CopyMem ((VOID *)(UINTN)SmramBuffer, (VOID *)(UINTN)Buffer, Length);
299
300 //
301 // Insert LockBox to queue
302 //
303 LockBox->Signature = SMM_LOCK_BOX_DATA_SIGNATURE;
304 CopyMem (&LockBox->Guid, Guid, sizeof(EFI_GUID));
305 LockBox->Buffer = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
306 LockBox->Length = (UINT64)Length;
307 LockBox->Attributes = 0;
308 LockBox->SmramBuffer = SmramBuffer;
309
310 DEBUG ((
311 EFI_D_INFO,
312 "LockBoxGuid - %g, SmramBuffer - 0x%lx, Length - 0x%lx\n",
313 &LockBox->Guid,
314 LockBox->SmramBuffer,
315 LockBox->Length
316 ));
317
318 LockBoxQueue = InternalGetLockBoxQueue ();
319 ASSERT (LockBoxQueue != NULL);
320 InsertTailList (LockBoxQueue, &LockBox->Link);
321
322 //
323 // Done
324 //
325 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_SUCCESS));
326 return EFI_SUCCESS;
327 }
328
329 /**
330 This function will set lockbox attributes.
331
332 @param Guid the guid to identify the confidential information
333 @param Attributes the attributes of the lockbox
334
335 @retval RETURN_SUCCESS the information is saved successfully.
336 @retval RETURN_INVALID_PARAMETER attributes is invalid.
337 @retval RETURN_NOT_FOUND the requested GUID not found.
338 @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
339 @retval RETURN_NOT_STARTED it is too early to invoke this interface
340 @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
341 **/
342 RETURN_STATUS
343 EFIAPI
SetLockBoxAttributes(IN GUID * Guid,IN UINT64 Attributes)344 SetLockBoxAttributes (
345 IN GUID *Guid,
346 IN UINT64 Attributes
347 )
348 {
349 SMM_LOCK_BOX_DATA *LockBox;
350
351 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes - Enter\n"));
352
353 //
354 // Basic check
355 //
356 if ((Guid == NULL) ||
357 ((Attributes & ~LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE) != 0)) {
358 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes - Exit (%r)\n", EFI_INVALID_PARAMETER));
359 return EFI_INVALID_PARAMETER;
360 }
361
362 //
363 // Find LockBox
364 //
365 LockBox = InternalFindLockBoxByGuid (Guid);
366 if (LockBox == NULL) {
367 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes - Exit (%r)\n", EFI_NOT_FOUND));
368 return EFI_NOT_FOUND;
369 }
370
371 //
372 // Update data
373 //
374 LockBox->Attributes = Attributes;
375
376 //
377 // Done
378 //
379 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes - Exit (%r)\n", EFI_SUCCESS));
380 return EFI_SUCCESS;
381 }
382
383 /**
384 This function will update confidential information to lockbox.
385
386 @param Guid the guid to identify the original confidential information
387 @param Offset the offset of the original confidential information
388 @param Buffer the address of the updated confidential information
389 @param Length the length of the updated confidential information
390
391 @retval RETURN_SUCCESS the information is saved successfully.
392 @retval RETURN_INVALID_PARAMETER the Guid is NULL, or Buffer is NULL, or Length is 0.
393 @retval RETURN_NOT_FOUND the requested GUID not found.
394 @retval RETURN_BUFFER_TOO_SMALL the original buffer to too small to hold new information.
395 @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
396 @retval RETURN_NOT_STARTED it is too early to invoke this interface
397 @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
398 **/
399 RETURN_STATUS
400 EFIAPI
UpdateLockBox(IN GUID * Guid,IN UINTN Offset,IN VOID * Buffer,IN UINTN Length)401 UpdateLockBox (
402 IN GUID *Guid,
403 IN UINTN Offset,
404 IN VOID *Buffer,
405 IN UINTN Length
406 )
407 {
408 SMM_LOCK_BOX_DATA *LockBox;
409
410 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib UpdateLockBox - Enter\n"));
411
412 //
413 // Basic check
414 //
415 if ((Guid == NULL) || (Buffer == NULL) || (Length == 0)) {
416 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_INVALID_PARAMETER));
417 return EFI_INVALID_PARAMETER;
418 }
419
420 //
421 // Find LockBox
422 //
423 LockBox = InternalFindLockBoxByGuid (Guid);
424 if (LockBox == NULL) {
425 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_NOT_FOUND));
426 return EFI_NOT_FOUND;
427 }
428
429 //
430 // Update data
431 //
432 if (LockBox->Length < Offset + Length) {
433 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_BUFFER_TOO_SMALL));
434 return EFI_BUFFER_TOO_SMALL;
435 }
436 ASSERT ((UINTN)LockBox->SmramBuffer <= (MAX_ADDRESS - Offset));
437 CopyMem ((VOID *)((UINTN)LockBox->SmramBuffer + Offset), Buffer, Length);
438
439 //
440 // Done
441 //
442 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_SUCCESS));
443 return EFI_SUCCESS;
444 }
445
446 /**
447 This function will restore confidential information from lockbox.
448
449 @param Guid the guid to identify the confidential information
450 @param Buffer the address of the restored confidential information
451 NULL means restored to original address, Length MUST be NULL at same time.
452 @param Length the length of the restored confidential information
453
454 @retval RETURN_SUCCESS the information is restored successfully.
455 @retval RETURN_INVALID_PARAMETER the Guid is NULL, or one of Buffer and Length is NULL.
456 @retval RETURN_WRITE_PROTECTED Buffer and Length are NULL, but the LockBox has no
457 LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE attribute.
458 @retval RETURN_BUFFER_TOO_SMALL the Length is too small to hold the confidential information.
459 @retval RETURN_NOT_FOUND the requested GUID not found.
460 @retval RETURN_NOT_STARTED it is too early to invoke this interface
461 @retval RETURN_ACCESS_DENIED not allow to restore to the address
462 @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
463 **/
464 RETURN_STATUS
465 EFIAPI
RestoreLockBox(IN GUID * Guid,IN VOID * Buffer,OPTIONAL IN OUT UINTN * Length OPTIONAL)466 RestoreLockBox (
467 IN GUID *Guid,
468 IN VOID *Buffer, OPTIONAL
469 IN OUT UINTN *Length OPTIONAL
470 )
471 {
472 SMM_LOCK_BOX_DATA *LockBox;
473 VOID *RestoreBuffer;
474
475 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreLockBox - Enter\n"));
476
477 //
478 // Restore this, Buffer and Length MUST be both NULL or both non-NULL
479 //
480 if ((Guid == NULL) ||
481 ((Buffer == NULL) && (Length != NULL)) ||
482 ((Buffer != NULL) && (Length == NULL))) {
483 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_INVALID_PARAMETER));
484 return EFI_INVALID_PARAMETER;
485 }
486
487 //
488 // Find LockBox
489 //
490 LockBox = InternalFindLockBoxByGuid (Guid);
491 if (LockBox == NULL) {
492 //
493 // Not found
494 //
495 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_NOT_FOUND));
496 return EFI_NOT_FOUND;
497 }
498
499 //
500 // Set RestoreBuffer
501 //
502 if (Buffer != NULL) {
503 //
504 // restore to new buffer
505 //
506 RestoreBuffer = Buffer;
507 } else {
508 //
509 // restore to original buffer
510 //
511 if ((LockBox->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE) == 0) {
512 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_WRITE_PROTECTED));
513 return EFI_WRITE_PROTECTED;
514 }
515 RestoreBuffer = (VOID *)(UINTN)LockBox->Buffer;
516 }
517
518 //
519 // Set RestoreLength
520 //
521 if (Length != NULL) {
522 if (*Length < (UINTN)LockBox->Length) {
523 //
524 // Input buffer is too small to hold all data.
525 //
526 *Length = (UINTN)LockBox->Length;
527 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_BUFFER_TOO_SMALL));
528 return EFI_BUFFER_TOO_SMALL;
529 }
530 *Length = (UINTN)LockBox->Length;
531 }
532
533 //
534 // Restore data
535 //
536 CopyMem (RestoreBuffer, (VOID *)(UINTN)LockBox->SmramBuffer, (UINTN)LockBox->Length);
537
538 //
539 // Done
540 //
541 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_SUCCESS));
542 return EFI_SUCCESS;
543 }
544
545 /**
546 This function will restore confidential information from all lockbox which have RestoreInPlace attribute.
547
548 @retval RETURN_SUCCESS the information is restored successfully.
549 @retval RETURN_NOT_STARTED it is too early to invoke this interface
550 @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
551 **/
552 RETURN_STATUS
553 EFIAPI
RestoreAllLockBoxInPlace(VOID)554 RestoreAllLockBoxInPlace (
555 VOID
556 )
557 {
558 SMM_LOCK_BOX_DATA *LockBox;
559 LIST_ENTRY *Link;
560 LIST_ENTRY *LockBoxQueue;
561
562 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreAllLockBoxInPlace - Enter\n"));
563
564 LockBoxQueue = InternalGetLockBoxQueue ();
565 ASSERT (LockBoxQueue != NULL);
566
567 //
568 // Restore all, Buffer and Length MUST be NULL
569 //
570 for (Link = LockBoxQueue->ForwardLink;
571 Link != LockBoxQueue;
572 Link = Link->ForwardLink) {
573 LockBox = BASE_CR (
574 Link,
575 SMM_LOCK_BOX_DATA,
576 Link
577 );
578 if ((LockBox->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE) != 0) {
579 //
580 // Restore data
581 //
582 CopyMem ((VOID *)(UINTN)LockBox->Buffer, (VOID *)(UINTN)LockBox->SmramBuffer, (UINTN)LockBox->Length);
583 }
584 }
585 //
586 // Done
587 //
588 DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreAllLockBoxInPlace - Exit (%r)\n", EFI_SUCCESS));
589 return EFI_SUCCESS;
590 }
591
592