]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
MdeModulePkg/Variable: Add RT GetVariable() cache support
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / VariableSmmRuntimeDxe.c
1 /** @file
2 Implement all four UEFI Runtime Variable services for the nonvolatile
3 and volatile storage space and install variable architecture protocol
4 based on SMM variable module.
5
6 Caution: This module requires additional review when modified.
7 This driver will have external input - variable data.
8 This external input must be validated carefully to avoid security issue like
9 buffer overflow, integer overflow.
10
11 RuntimeServiceGetVariable() and RuntimeServiceSetVariable() are external API
12 to receive data buffer. The size should be checked carefully.
13
14 InitCommunicateBuffer() is really function to check the variable data size.
15
16 Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
17 SPDX-License-Identifier: BSD-2-Clause-Patent
18
19 **/
20 #include <PiDxe.h>
21 #include <Protocol/VariableWrite.h>
22 #include <Protocol/Variable.h>
23 #include <Protocol/SmmCommunication.h>
24 #include <Protocol/SmmVariable.h>
25 #include <Protocol/VariableLock.h>
26 #include <Protocol/VarCheck.h>
27
28 #include <Library/UefiBootServicesTableLib.h>
29 #include <Library/UefiRuntimeServicesTableLib.h>
30 #include <Library/MemoryAllocationLib.h>
31 #include <Library/UefiDriverEntryPoint.h>
32 #include <Library/UefiRuntimeLib.h>
33 #include <Library/BaseMemoryLib.h>
34 #include <Library/DebugLib.h>
35 #include <Library/UefiLib.h>
36 #include <Library/BaseLib.h>
37
38 #include <Guid/EventGroup.h>
39 #include <Guid/SmmVariableCommon.h>
40
41 #include "PrivilegePolymorphic.h"
42 #include "VariableParsing.h"
43
44 EFI_HANDLE mHandle = NULL;
45 EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable = NULL;
46 EFI_EVENT mVirtualAddressChangeEvent = NULL;
47 EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL;
48 UINT8 *mVariableBuffer = NULL;
49 UINT8 *mVariableBufferPhysical = NULL;
50 VARIABLE_INFO_ENTRY *mVariableInfo = NULL;
51 VARIABLE_STORE_HEADER *mVariableRuntimeHobCacheBuffer = NULL;
52 VARIABLE_STORE_HEADER *mVariableRuntimeNvCacheBuffer = NULL;
53 VARIABLE_STORE_HEADER *mVariableRuntimeVolatileCacheBuffer = NULL;
54 UINTN mVariableBufferSize;
55 UINTN mVariableRuntimeHobCacheBufferSize;
56 UINTN mVariableRuntimeNvCacheBufferSize;
57 UINTN mVariableRuntimeVolatileCacheBufferSize;
58 UINTN mVariableBufferPayloadSize;
59 BOOLEAN mVariableRuntimeCachePendingUpdate;
60 BOOLEAN mVariableRuntimeCacheReadLock;
61 BOOLEAN mVariableAuthFormat;
62 BOOLEAN mHobFlushComplete;
63 EFI_LOCK mVariableServicesLock;
64 EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock;
65 EDKII_VAR_CHECK_PROTOCOL mVarCheck;
66
67 /**
68 Some Secure Boot Policy Variable may update following other variable changes(SecureBoot follows PK change, etc).
69 Record their initial State when variable write service is ready.
70
71 **/
72 VOID
73 EFIAPI
74 RecordSecureBootPolicyVarData(
75 VOID
76 );
77
78 /**
79 Acquires lock only at boot time. Simply returns at runtime.
80
81 This is a temperary function that will be removed when
82 EfiAcquireLock() in UefiLib can handle the call in UEFI
83 Runtimer driver in RT phase.
84 It calls EfiAcquireLock() at boot time, and simply returns
85 at runtime.
86
87 @param Lock A pointer to the lock to acquire.
88
89 **/
90 VOID
91 AcquireLockOnlyAtBootTime (
92 IN EFI_LOCK *Lock
93 )
94 {
95 if (!EfiAtRuntime ()) {
96 EfiAcquireLock (Lock);
97 }
98 }
99
100 /**
101 Releases lock only at boot time. Simply returns at runtime.
102
103 This is a temperary function which will be removed when
104 EfiReleaseLock() in UefiLib can handle the call in UEFI
105 Runtimer driver in RT phase.
106 It calls EfiReleaseLock() at boot time and simply returns
107 at runtime.
108
109 @param Lock A pointer to the lock to release.
110
111 **/
112 VOID
113 ReleaseLockOnlyAtBootTime (
114 IN EFI_LOCK *Lock
115 )
116 {
117 if (!EfiAtRuntime ()) {
118 EfiReleaseLock (Lock);
119 }
120 }
121
122 /**
123 Return TRUE if ExitBootServices () has been called.
124
125 @retval TRUE If ExitBootServices () has been called. FALSE if ExitBootServices () has not been called.
126 **/
127 BOOLEAN
128 AtRuntime (
129 VOID
130 )
131 {
132 return EfiAtRuntime ();
133 }
134
135 /**
136 Initialize the variable cache buffer as an empty variable store.
137
138 @param[out] VariableCacheBuffer A pointer to pointer of a cache variable store.
139 @param[in,out] TotalVariableCacheSize On input, the minimum size needed for the UEFI variable store cache
140 buffer that is allocated. On output, the actual size of the buffer allocated.
141 If TotalVariableCacheSize is zero, a buffer will not be allocated and the
142 function will return with EFI_SUCCESS.
143
144 @retval EFI_SUCCESS The variable cache was allocated and initialized successfully.
145 @retval EFI_INVALID_PARAMETER A given pointer is NULL or an invalid variable store size was specified.
146 @retval EFI_OUT_OF_RESOURCES Insufficient resources are available to allocate the variable store cache buffer.
147
148 **/
149 EFI_STATUS
150 InitVariableCache (
151 OUT VARIABLE_STORE_HEADER **VariableCacheBuffer,
152 IN OUT UINTN *TotalVariableCacheSize
153 )
154 {
155 VARIABLE_STORE_HEADER *VariableCacheStorePtr;
156
157 if (TotalVariableCacheSize == NULL) {
158 return EFI_INVALID_PARAMETER;
159 }
160 if (*TotalVariableCacheSize == 0) {
161 return EFI_SUCCESS;
162 }
163 if (VariableCacheBuffer == NULL || *TotalVariableCacheSize < sizeof (VARIABLE_STORE_HEADER)) {
164 return EFI_INVALID_PARAMETER;
165 }
166 *TotalVariableCacheSize = ALIGN_VALUE (*TotalVariableCacheSize, sizeof (UINT32));
167
168 //
169 // Allocate NV Storage Cache and initialize it to all 1's (like an erased FV)
170 //
171 *VariableCacheBuffer = (VARIABLE_STORE_HEADER *) AllocateRuntimePages (
172 EFI_SIZE_TO_PAGES (*TotalVariableCacheSize)
173 );
174 if (*VariableCacheBuffer == NULL) {
175 return EFI_OUT_OF_RESOURCES;
176 }
177 VariableCacheStorePtr = *VariableCacheBuffer;
178 SetMem32 ((VOID *) VariableCacheStorePtr, *TotalVariableCacheSize, (UINT32) 0xFFFFFFFF);
179
180 ZeroMem ((VOID *) VariableCacheStorePtr, sizeof (VARIABLE_STORE_HEADER));
181 VariableCacheStorePtr->Size = (UINT32) *TotalVariableCacheSize;
182 VariableCacheStorePtr->Format = VARIABLE_STORE_FORMATTED;
183 VariableCacheStorePtr->State = VARIABLE_STORE_HEALTHY;
184
185 return EFI_SUCCESS;
186 }
187
188 /**
189 Initialize the communicate buffer using DataSize and Function.
190
191 The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +
192 DataSize.
193
194 Caution: This function may receive untrusted input.
195 The data size external input, so this function will validate it carefully to avoid buffer overflow.
196
197 @param[out] DataPtr Points to the data in the communicate buffer.
198 @param[in] DataSize The data size to send to SMM.
199 @param[in] Function The function number to initialize the communicate header.
200
201 @retval EFI_INVALID_PARAMETER The data size is too big.
202 @retval EFI_SUCCESS Find the specified variable.
203
204 **/
205 EFI_STATUS
206 InitCommunicateBuffer (
207 OUT VOID **DataPtr OPTIONAL,
208 IN UINTN DataSize,
209 IN UINTN Function
210 )
211 {
212 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
213 SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
214
215
216 if (DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE > mVariableBufferSize) {
217 return EFI_INVALID_PARAMETER;
218 }
219
220 SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer;
221 CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);
222 SmmCommunicateHeader->MessageLength = DataSize + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
223
224 SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;
225 SmmVariableFunctionHeader->Function = Function;
226 if (DataPtr != NULL) {
227 *DataPtr = SmmVariableFunctionHeader->Data;
228 }
229
230 return EFI_SUCCESS;
231 }
232
233
234 /**
235 Send the data in communicate buffer to SMM.
236
237 @param[in] DataSize This size of the function header and the data.
238
239 @retval EFI_SUCCESS Success is returned from the functin in SMM.
240 @retval Others Failure is returned from the function in SMM.
241
242 **/
243 EFI_STATUS
244 SendCommunicateBuffer (
245 IN UINTN DataSize
246 )
247 {
248 EFI_STATUS Status;
249 UINTN CommSize;
250 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
251 SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
252
253 CommSize = DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
254 Status = mSmmCommunication->Communicate (mSmmCommunication, mVariableBufferPhysical, &CommSize);
255 ASSERT_EFI_ERROR (Status);
256
257 SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer;
258 SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data;
259 return SmmVariableFunctionHeader->ReturnStatus;
260 }
261
262 /**
263 Mark a variable that will become read-only after leaving the DXE phase of execution.
264
265 @param[in] This The VARIABLE_LOCK_PROTOCOL instance.
266 @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.
267 @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.
268
269 @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked
270 as pending to be read-only.
271 @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
272 Or VariableName is an empty string.
273 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
274 already been signaled.
275 @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.
276 **/
277 EFI_STATUS
278 EFIAPI
279 VariableLockRequestToLock (
280 IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,
281 IN CHAR16 *VariableName,
282 IN EFI_GUID *VendorGuid
283 )
284 {
285 EFI_STATUS Status;
286 UINTN VariableNameSize;
287 UINTN PayloadSize;
288 SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE *VariableToLock;
289
290 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
291 return EFI_INVALID_PARAMETER;
292 }
293
294 VariableNameSize = StrSize (VariableName);
295 VariableToLock = NULL;
296
297 //
298 // If VariableName exceeds SMM payload limit. Return failure
299 //
300 if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name)) {
301 return EFI_INVALID_PARAMETER;
302 }
303
304 AcquireLockOnlyAtBootTime(&mVariableServicesLock);
305
306 //
307 // Init the communicate buffer. The buffer data size is:
308 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
309 //
310 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name) + VariableNameSize;
311 Status = InitCommunicateBuffer ((VOID **) &VariableToLock, PayloadSize, SMM_VARIABLE_FUNCTION_LOCK_VARIABLE);
312 if (EFI_ERROR (Status)) {
313 goto Done;
314 }
315 ASSERT (VariableToLock != NULL);
316
317 CopyGuid (&VariableToLock->Guid, VendorGuid);
318 VariableToLock->NameSize = VariableNameSize;
319 CopyMem (VariableToLock->Name, VariableName, VariableToLock->NameSize);
320
321 //
322 // Send data to SMM.
323 //
324 Status = SendCommunicateBuffer (PayloadSize);
325
326 Done:
327 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
328 return Status;
329 }
330
331 /**
332 Register SetVariable check handler.
333
334 @param[in] Handler Pointer to check handler.
335
336 @retval EFI_SUCCESS The SetVariable check handler was registered successfully.
337 @retval EFI_INVALID_PARAMETER Handler is NULL.
338 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
339 already been signaled.
340 @retval EFI_OUT_OF_RESOURCES There is not enough resource for the SetVariable check handler register request.
341 @retval EFI_UNSUPPORTED This interface is not implemented.
342 For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
343
344 **/
345 EFI_STATUS
346 EFIAPI
347 VarCheckRegisterSetVariableCheckHandler (
348 IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler
349 )
350 {
351 return EFI_UNSUPPORTED;
352 }
353
354 /**
355 Variable property set.
356
357 @param[in] Name Pointer to the variable name.
358 @param[in] Guid Pointer to the vendor GUID.
359 @param[in] VariableProperty Pointer to the input variable property.
360
361 @retval EFI_SUCCESS The property of variable specified by the Name and Guid was set successfully.
362 @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,
363 or the fields of VariableProperty are not valid.
364 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
365 already been signaled.
366 @retval EFI_OUT_OF_RESOURCES There is not enough resource for the variable property set request.
367
368 **/
369 EFI_STATUS
370 EFIAPI
371 VarCheckVariablePropertySet (
372 IN CHAR16 *Name,
373 IN EFI_GUID *Guid,
374 IN VAR_CHECK_VARIABLE_PROPERTY *VariableProperty
375 )
376 {
377 EFI_STATUS Status;
378 UINTN VariableNameSize;
379 UINTN PayloadSize;
380 SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *CommVariableProperty;
381
382 if (Name == NULL || Name[0] == 0 || Guid == NULL) {
383 return EFI_INVALID_PARAMETER;
384 }
385
386 if (VariableProperty == NULL) {
387 return EFI_INVALID_PARAMETER;
388 }
389
390 if (VariableProperty->Revision != VAR_CHECK_VARIABLE_PROPERTY_REVISION) {
391 return EFI_INVALID_PARAMETER;
392 }
393
394 VariableNameSize = StrSize (Name);
395 CommVariableProperty = NULL;
396
397 //
398 // If VariableName exceeds SMM payload limit. Return failure
399 //
400 if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {
401 return EFI_INVALID_PARAMETER;
402 }
403
404 AcquireLockOnlyAtBootTime (&mVariableServicesLock);
405
406 //
407 // Init the communicate buffer. The buffer data size is:
408 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
409 //
410 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) + VariableNameSize;
411 Status = InitCommunicateBuffer ((VOID **) &CommVariableProperty, PayloadSize, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET);
412 if (EFI_ERROR (Status)) {
413 goto Done;
414 }
415 ASSERT (CommVariableProperty != NULL);
416
417 CopyGuid (&CommVariableProperty->Guid, Guid);
418 CopyMem (&CommVariableProperty->VariableProperty, VariableProperty, sizeof (*VariableProperty));
419 CommVariableProperty->NameSize = VariableNameSize;
420 CopyMem (CommVariableProperty->Name, Name, CommVariableProperty->NameSize);
421
422 //
423 // Send data to SMM.
424 //
425 Status = SendCommunicateBuffer (PayloadSize);
426
427 Done:
428 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
429 return Status;
430 }
431
432 /**
433 Variable property get.
434
435 @param[in] Name Pointer to the variable name.
436 @param[in] Guid Pointer to the vendor GUID.
437 @param[out] VariableProperty Pointer to the output variable property.
438
439 @retval EFI_SUCCESS The property of variable specified by the Name and Guid was got successfully.
440 @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
441 @retval EFI_NOT_FOUND The property of variable specified by the Name and Guid was not found.
442
443 **/
444 EFI_STATUS
445 EFIAPI
446 VarCheckVariablePropertyGet (
447 IN CHAR16 *Name,
448 IN EFI_GUID *Guid,
449 OUT VAR_CHECK_VARIABLE_PROPERTY *VariableProperty
450 )
451 {
452 EFI_STATUS Status;
453 UINTN VariableNameSize;
454 UINTN PayloadSize;
455 SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *CommVariableProperty;
456
457 if (Name == NULL || Name[0] == 0 || Guid == NULL) {
458 return EFI_INVALID_PARAMETER;
459 }
460
461 if (VariableProperty == NULL) {
462 return EFI_INVALID_PARAMETER;
463 }
464
465 VariableNameSize = StrSize (Name);
466 CommVariableProperty = NULL;
467
468 //
469 // If VariableName exceeds SMM payload limit. Return failure
470 //
471 if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {
472 return EFI_INVALID_PARAMETER;
473 }
474
475 AcquireLockOnlyAtBootTime (&mVariableServicesLock);
476
477 //
478 // Init the communicate buffer. The buffer data size is:
479 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
480 //
481 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) + VariableNameSize;
482 Status = InitCommunicateBuffer ((VOID **) &CommVariableProperty, PayloadSize, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET);
483 if (EFI_ERROR (Status)) {
484 goto Done;
485 }
486 ASSERT (CommVariableProperty != NULL);
487
488 CopyGuid (&CommVariableProperty->Guid, Guid);
489 CommVariableProperty->NameSize = VariableNameSize;
490 CopyMem (CommVariableProperty->Name, Name, CommVariableProperty->NameSize);
491
492 //
493 // Send data to SMM.
494 //
495 Status = SendCommunicateBuffer (PayloadSize);
496 if (Status == EFI_SUCCESS) {
497 CopyMem (VariableProperty, &CommVariableProperty->VariableProperty, sizeof (*VariableProperty));
498 }
499
500 Done:
501 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
502 return Status;
503 }
504
505 /**
506 Signals SMM to synchronize any pending variable updates with the runtime cache(s).
507
508 **/
509 VOID
510 SyncRuntimeCache (
511 VOID
512 )
513 {
514 //
515 // Init the communicate buffer. The buffer data size is:
516 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
517 //
518 InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE);
519
520 //
521 // Send data to SMM.
522 //
523 SendCommunicateBuffer (0);
524 }
525
526 /**
527 Check whether a SMI must be triggered to retrieve pending cache updates.
528
529 If the variable HOB was finished being flushed since the last check for a runtime cache update, this function
530 will prevent the HOB cache from being used for future runtime cache hits.
531
532 **/
533 VOID
534 CheckForRuntimeCacheSync (
535 VOID
536 )
537 {
538 if (mVariableRuntimeCachePendingUpdate) {
539 SyncRuntimeCache ();
540 }
541 ASSERT (!mVariableRuntimeCachePendingUpdate);
542
543 //
544 // The HOB variable data may have finished being flushed in the runtime cache sync update
545 //
546 if (mHobFlushComplete && mVariableRuntimeHobCacheBuffer != NULL) {
547 if (!EfiAtRuntime ()) {
548 FreePages (mVariableRuntimeHobCacheBuffer, EFI_SIZE_TO_PAGES (mVariableRuntimeHobCacheBufferSize));
549 }
550 mVariableRuntimeHobCacheBuffer = NULL;
551 }
552 }
553
554 /**
555 Finds the given variable in a runtime cache variable store.
556
557 Caution: This function may receive untrusted input.
558 The data size is external input, so this function will validate it carefully to avoid buffer overflow.
559
560 @param[in] VariableName Name of Variable to be found.
561 @param[in] VendorGuid Variable vendor GUID.
562 @param[out] Attributes Attribute value of the variable found.
563 @param[in, out] DataSize Size of Data found. If size is less than the
564 data, this value contains the required size.
565 @param[out] Data Data pointer.
566
567 @retval EFI_SUCCESS Found the specified variable.
568 @retval EFI_INVALID_PARAMETER Invalid parameter.
569 @retval EFI_NOT_FOUND The specified variable could not be found.
570
571 **/
572 EFI_STATUS
573 FindVariableInRuntimeCache (
574 IN CHAR16 *VariableName,
575 IN EFI_GUID *VendorGuid,
576 OUT UINT32 *Attributes OPTIONAL,
577 IN OUT UINTN *DataSize,
578 OUT VOID *Data OPTIONAL
579 )
580 {
581 EFI_STATUS Status;
582 UINTN TempDataSize;
583 VARIABLE_POINTER_TRACK RtPtrTrack;
584 VARIABLE_STORE_TYPE StoreType;
585 VARIABLE_STORE_HEADER *VariableStoreList[VariableStoreTypeMax];
586
587 Status = EFI_NOT_FOUND;
588
589 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
590 return EFI_INVALID_PARAMETER;
591 }
592
593 //
594 // The UEFI specification restricts Runtime Services callers from invoking the same or certain other Runtime Service
595 // functions prior to completion and return from a previous Runtime Service call. These restrictions prevent
596 // a GetVariable () or GetNextVariable () call from being issued until a prior call has returned. The runtime
597 // cache read lock should always be free when entering this function.
598 //
599 ASSERT (!mVariableRuntimeCacheReadLock);
600
601 mVariableRuntimeCacheReadLock = TRUE;
602 CheckForRuntimeCacheSync ();
603
604 if (!mVariableRuntimeCachePendingUpdate) {
605 //
606 // 0: Volatile, 1: HOB, 2: Non-Volatile.
607 // The index and attributes mapping must be kept in this order as FindVariable
608 // makes use of this mapping to implement search algorithm.
609 //
610 VariableStoreList[VariableStoreTypeVolatile] = mVariableRuntimeVolatileCacheBuffer;
611 VariableStoreList[VariableStoreTypeHob] = mVariableRuntimeHobCacheBuffer;
612 VariableStoreList[VariableStoreTypeNv] = mVariableRuntimeNvCacheBuffer;
613
614 for (StoreType = (VARIABLE_STORE_TYPE) 0; StoreType < VariableStoreTypeMax; StoreType++) {
615 if (VariableStoreList[StoreType] == NULL) {
616 continue;
617 }
618
619 RtPtrTrack.StartPtr = GetStartPointer (VariableStoreList[StoreType]);
620 RtPtrTrack.EndPtr = GetEndPointer (VariableStoreList[StoreType]);
621 RtPtrTrack.Volatile = (BOOLEAN) (StoreType == VariableStoreTypeVolatile);
622
623 Status = FindVariableEx (VariableName, VendorGuid, FALSE, &RtPtrTrack, mVariableAuthFormat);
624 if (!EFI_ERROR (Status)) {
625 break;
626 }
627 }
628
629 if (!EFI_ERROR (Status)) {
630 //
631 // Get data size
632 //
633 TempDataSize = DataSizeOfVariable (RtPtrTrack.CurrPtr, mVariableAuthFormat);
634 ASSERT (TempDataSize != 0);
635
636 if (*DataSize >= TempDataSize) {
637 if (Data == NULL) {
638 Status = EFI_INVALID_PARAMETER;
639 goto Done;
640 }
641
642 CopyMem (Data, GetVariableDataPtr (RtPtrTrack.CurrPtr, mVariableAuthFormat), TempDataSize);
643 if (Attributes != NULL) {
644 *Attributes = RtPtrTrack.CurrPtr->Attributes;
645 }
646
647 *DataSize = TempDataSize;
648
649 UpdateVariableInfo (VariableName, VendorGuid, RtPtrTrack.Volatile, TRUE, FALSE, FALSE, TRUE, &mVariableInfo);
650
651 Status = EFI_SUCCESS;
652 goto Done;
653 } else {
654 *DataSize = TempDataSize;
655 Status = EFI_BUFFER_TOO_SMALL;
656 goto Done;
657 }
658 }
659 }
660
661 Done:
662 mVariableRuntimeCacheReadLock = FALSE;
663
664 return Status;
665 }
666
667 /**
668 Finds the given variable in a variable store in SMM.
669
670 Caution: This function may receive untrusted input.
671 The data size is external input, so this function will validate it carefully to avoid buffer overflow.
672
673 @param[in] VariableName Name of Variable to be found.
674 @param[in] VendorGuid Variable vendor GUID.
675 @param[out] Attributes Attribute value of the variable found.
676 @param[in, out] DataSize Size of Data found. If size is less than the
677 data, this value contains the required size.
678 @param[out] Data Data pointer.
679
680 @retval EFI_SUCCESS Found the specified variable.
681 @retval EFI_INVALID_PARAMETER Invalid parameter.
682 @retval EFI_NOT_FOUND The specified variable could not be found.
683
684 **/
685 EFI_STATUS
686 FindVariableInSmm (
687 IN CHAR16 *VariableName,
688 IN EFI_GUID *VendorGuid,
689 OUT UINT32 *Attributes OPTIONAL,
690 IN OUT UINTN *DataSize,
691 OUT VOID *Data OPTIONAL
692 )
693 {
694 EFI_STATUS Status;
695 UINTN PayloadSize;
696 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;
697 UINTN TempDataSize;
698 UINTN VariableNameSize;
699
700 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
701 return EFI_INVALID_PARAMETER;
702 }
703
704 TempDataSize = *DataSize;
705 VariableNameSize = StrSize (VariableName);
706 SmmVariableHeader = NULL;
707
708 //
709 // If VariableName exceeds SMM payload limit. Return failure
710 //
711 if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {
712 return EFI_INVALID_PARAMETER;
713 }
714
715 //
716 // Init the communicate buffer. The buffer data size is:
717 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
718 //
719 if (TempDataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize) {
720 //
721 // If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size
722 //
723 TempDataSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize;
724 }
725 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + TempDataSize;
726
727 Status = InitCommunicateBuffer ((VOID **) &SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE);
728 if (EFI_ERROR (Status)) {
729 goto Done;
730 }
731 ASSERT (SmmVariableHeader != NULL);
732
733 CopyGuid (&SmmVariableHeader->Guid, VendorGuid);
734 SmmVariableHeader->DataSize = TempDataSize;
735 SmmVariableHeader->NameSize = VariableNameSize;
736 if (Attributes == NULL) {
737 SmmVariableHeader->Attributes = 0;
738 } else {
739 SmmVariableHeader->Attributes = *Attributes;
740 }
741 CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);
742
743 //
744 // Send data to SMM.
745 //
746 Status = SendCommunicateBuffer (PayloadSize);
747
748 //
749 // Get data from SMM.
750 //
751 if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {
752 //
753 // SMM CommBuffer DataSize can be a trimed value
754 // Only update DataSize when needed
755 //
756 *DataSize = SmmVariableHeader->DataSize;
757 }
758 if (Attributes != NULL) {
759 *Attributes = SmmVariableHeader->Attributes;
760 }
761
762 if (EFI_ERROR (Status)) {
763 goto Done;
764 }
765
766 if (Data != NULL) {
767 CopyMem (Data, (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize, SmmVariableHeader->DataSize);
768 } else {
769 Status = EFI_INVALID_PARAMETER;
770 }
771
772 Done:
773 return Status;
774 }
775
776 /**
777 This code finds variable in storage blocks (Volatile or Non-Volatile).
778
779 Caution: This function may receive untrusted input.
780 The data size is external input, so this function will validate it carefully to avoid buffer overflow.
781
782 @param[in] VariableName Name of Variable to be found.
783 @param[in] VendorGuid Variable vendor GUID.
784 @param[out] Attributes Attribute value of the variable found.
785 @param[in, out] DataSize Size of Data found. If size is less than the
786 data, this value contains the required size.
787 @param[out] Data Data pointer.
788
789 @retval EFI_INVALID_PARAMETER Invalid parameter.
790 @retval EFI_SUCCESS Find the specified variable.
791 @retval EFI_NOT_FOUND Not found.
792 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
793
794 **/
795 EFI_STATUS
796 EFIAPI
797 RuntimeServiceGetVariable (
798 IN CHAR16 *VariableName,
799 IN EFI_GUID *VendorGuid,
800 OUT UINT32 *Attributes OPTIONAL,
801 IN OUT UINTN *DataSize,
802 OUT VOID *Data
803 )
804 {
805 EFI_STATUS Status;
806
807 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
808 return EFI_INVALID_PARAMETER;
809 }
810 if (VariableName[0] == 0) {
811 return EFI_NOT_FOUND;
812 }
813
814 AcquireLockOnlyAtBootTime (&mVariableServicesLock);
815 if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) {
816 Status = FindVariableInRuntimeCache (VariableName, VendorGuid, Attributes, DataSize, Data);
817 } else {
818 Status = FindVariableInSmm (VariableName, VendorGuid, Attributes, DataSize, Data);
819 }
820 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
821
822 return Status;
823 }
824
825 /**
826 This code Finds the Next available variable.
827
828 @param[in, out] VariableNameSize Size of the variable name.
829 @param[in, out] VariableName Pointer to variable name.
830 @param[in, out] VendorGuid Variable Vendor Guid.
831
832 @retval EFI_INVALID_PARAMETER Invalid parameter.
833 @retval EFI_SUCCESS Find the specified variable.
834 @retval EFI_NOT_FOUND Not found.
835 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
836
837 **/
838 EFI_STATUS
839 EFIAPI
840 RuntimeServiceGetNextVariableName (
841 IN OUT UINTN *VariableNameSize,
842 IN OUT CHAR16 *VariableName,
843 IN OUT EFI_GUID *VendorGuid
844 )
845 {
846 EFI_STATUS Status;
847 UINTN PayloadSize;
848 SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *SmmGetNextVariableName;
849 UINTN OutVariableNameSize;
850 UINTN InVariableNameSize;
851
852 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
853 return EFI_INVALID_PARAMETER;
854 }
855
856 OutVariableNameSize = *VariableNameSize;
857 InVariableNameSize = StrSize (VariableName);
858 SmmGetNextVariableName = NULL;
859
860 //
861 // If input string exceeds SMM payload limit. Return failure
862 //
863 if (InVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
864 return EFI_INVALID_PARAMETER;
865 }
866
867 AcquireLockOnlyAtBootTime(&mVariableServicesLock);
868
869 //
870 // Init the communicate buffer. The buffer data size is:
871 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
872 //
873 if (OutVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
874 //
875 // If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size
876 //
877 OutVariableNameSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name);
878 }
879 //
880 // Payload should be Guid + NameSize + MAX of Input & Output buffer
881 //
882 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + MAX (OutVariableNameSize, InVariableNameSize);
883
884 Status = InitCommunicateBuffer ((VOID **)&SmmGetNextVariableName, PayloadSize, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME);
885 if (EFI_ERROR (Status)) {
886 goto Done;
887 }
888 ASSERT (SmmGetNextVariableName != NULL);
889
890 //
891 // SMM comm buffer->NameSize is buffer size for return string
892 //
893 SmmGetNextVariableName->NameSize = OutVariableNameSize;
894
895 CopyGuid (&SmmGetNextVariableName->Guid, VendorGuid);
896 //
897 // Copy whole string
898 //
899 CopyMem (SmmGetNextVariableName->Name, VariableName, InVariableNameSize);
900 if (OutVariableNameSize > InVariableNameSize) {
901 ZeroMem ((UINT8 *) SmmGetNextVariableName->Name + InVariableNameSize, OutVariableNameSize - InVariableNameSize);
902 }
903
904 //
905 // Send data to SMM
906 //
907 Status = SendCommunicateBuffer (PayloadSize);
908
909 //
910 // Get data from SMM.
911 //
912 if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {
913 //
914 // SMM CommBuffer NameSize can be a trimed value
915 // Only update VariableNameSize when needed
916 //
917 *VariableNameSize = SmmGetNextVariableName->NameSize;
918 }
919 if (EFI_ERROR (Status)) {
920 goto Done;
921 }
922
923 CopyGuid (VendorGuid, &SmmGetNextVariableName->Guid);
924 CopyMem (VariableName, SmmGetNextVariableName->Name, SmmGetNextVariableName->NameSize);
925
926 Done:
927 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
928 return Status;
929 }
930
931 /**
932 This code sets variable in storage blocks (Volatile or Non-Volatile).
933
934 Caution: This function may receive untrusted input.
935 The data size and data are external input, so this function will validate it carefully to avoid buffer overflow.
936
937 @param[in] VariableName Name of Variable to be found.
938 @param[in] VendorGuid Variable vendor GUID.
939 @param[in] Attributes Attribute value of the variable found
940 @param[in] DataSize Size of Data found. If size is less than the
941 data, this value contains the required size.
942 @param[in] Data Data pointer.
943
944 @retval EFI_INVALID_PARAMETER Invalid parameter.
945 @retval EFI_SUCCESS Set successfully.
946 @retval EFI_OUT_OF_RESOURCES Resource not enough to set variable.
947 @retval EFI_NOT_FOUND Not found.
948 @retval EFI_WRITE_PROTECTED Variable is read-only.
949
950 **/
951 EFI_STATUS
952 EFIAPI
953 RuntimeServiceSetVariable (
954 IN CHAR16 *VariableName,
955 IN EFI_GUID *VendorGuid,
956 IN UINT32 Attributes,
957 IN UINTN DataSize,
958 IN VOID *Data
959 )
960 {
961 EFI_STATUS Status;
962 UINTN PayloadSize;
963 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;
964 UINTN VariableNameSize;
965
966 //
967 // Check input parameters.
968 //
969 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
970 return EFI_INVALID_PARAMETER;
971 }
972
973 if (DataSize != 0 && Data == NULL) {
974 return EFI_INVALID_PARAMETER;
975 }
976
977 VariableNameSize = StrSize (VariableName);
978 SmmVariableHeader = NULL;
979
980 //
981 // If VariableName or DataSize exceeds SMM payload limit. Return failure
982 //
983 if ((VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||
984 (DataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize)){
985 return EFI_INVALID_PARAMETER;
986 }
987
988 AcquireLockOnlyAtBootTime(&mVariableServicesLock);
989
990 //
991 // Init the communicate buffer. The buffer data size is:
992 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
993 //
994 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + DataSize;
995 Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_SET_VARIABLE);
996 if (EFI_ERROR (Status)) {
997 goto Done;
998 }
999 ASSERT (SmmVariableHeader != NULL);
1000
1001 CopyGuid ((EFI_GUID *) &SmmVariableHeader->Guid, VendorGuid);
1002 SmmVariableHeader->DataSize = DataSize;
1003 SmmVariableHeader->NameSize = VariableNameSize;
1004 SmmVariableHeader->Attributes = Attributes;
1005 CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);
1006 CopyMem ((UINT8 *) SmmVariableHeader->Name + SmmVariableHeader->NameSize, Data, DataSize);
1007
1008 //
1009 // Send data to SMM.
1010 //
1011 Status = SendCommunicateBuffer (PayloadSize);
1012
1013 Done:
1014 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
1015
1016 if (!EfiAtRuntime ()) {
1017 if (!EFI_ERROR (Status)) {
1018 SecureBootHook (
1019 VariableName,
1020 VendorGuid
1021 );
1022 }
1023 }
1024 return Status;
1025 }
1026
1027
1028 /**
1029 This code returns information about the EFI variables.
1030
1031 @param[in] Attributes Attributes bitmask to specify the type of variables
1032 on which to return information.
1033 @param[out] MaximumVariableStorageSize Pointer to the maximum size of the storage space available
1034 for the EFI variables associated with the attributes specified.
1035 @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available
1036 for EFI variables associated with the attributes specified.
1037 @param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables
1038 associated with the attributes specified.
1039
1040 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
1041 @retval EFI_SUCCESS Query successfully.
1042 @retval EFI_UNSUPPORTED The attribute is not supported on this platform.
1043
1044 **/
1045 EFI_STATUS
1046 EFIAPI
1047 RuntimeServiceQueryVariableInfo (
1048 IN UINT32 Attributes,
1049 OUT UINT64 *MaximumVariableStorageSize,
1050 OUT UINT64 *RemainingVariableStorageSize,
1051 OUT UINT64 *MaximumVariableSize
1052 )
1053 {
1054 EFI_STATUS Status;
1055 UINTN PayloadSize;
1056 SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *SmmQueryVariableInfo;
1057
1058 SmmQueryVariableInfo = NULL;
1059
1060 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {
1061 return EFI_INVALID_PARAMETER;
1062 }
1063
1064 AcquireLockOnlyAtBootTime(&mVariableServicesLock);
1065
1066 //
1067 // Init the communicate buffer. The buffer data size is:
1068 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;
1069 //
1070 PayloadSize = sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO);
1071 Status = InitCommunicateBuffer ((VOID **)&SmmQueryVariableInfo, PayloadSize, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO);
1072 if (EFI_ERROR (Status)) {
1073 goto Done;
1074 }
1075 ASSERT (SmmQueryVariableInfo != NULL);
1076
1077 SmmQueryVariableInfo->Attributes = Attributes;
1078
1079 //
1080 // Send data to SMM.
1081 //
1082 Status = SendCommunicateBuffer (PayloadSize);
1083 if (EFI_ERROR (Status)) {
1084 goto Done;
1085 }
1086
1087 //
1088 // Get data from SMM.
1089 //
1090 *MaximumVariableSize = SmmQueryVariableInfo->MaximumVariableSize;
1091 *MaximumVariableStorageSize = SmmQueryVariableInfo->MaximumVariableStorageSize;
1092 *RemainingVariableStorageSize = SmmQueryVariableInfo->RemainingVariableStorageSize;
1093
1094 Done:
1095 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
1096 return Status;
1097 }
1098
1099
1100 /**
1101 Exit Boot Services Event notification handler.
1102
1103 Notify SMM variable driver about the event.
1104
1105 @param[in] Event Event whose notification function is being invoked.
1106 @param[in] Context Pointer to the notification function's context.
1107
1108 **/
1109 VOID
1110 EFIAPI
1111 OnExitBootServices (
1112 IN EFI_EVENT Event,
1113 IN VOID *Context
1114 )
1115 {
1116 //
1117 // Init the communicate buffer. The buffer data size is:
1118 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
1119 //
1120 InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE);
1121
1122 //
1123 // Send data to SMM.
1124 //
1125 SendCommunicateBuffer (0);
1126 }
1127
1128
1129 /**
1130 On Ready To Boot Services Event notification handler.
1131
1132 Notify SMM variable driver about the event.
1133
1134 @param[in] Event Event whose notification function is being invoked
1135 @param[in] Context Pointer to the notification function's context
1136
1137 **/
1138 VOID
1139 EFIAPI
1140 OnReadyToBoot (
1141 IN EFI_EVENT Event,
1142 IN VOID *Context
1143 )
1144 {
1145 //
1146 // Init the communicate buffer. The buffer data size is:
1147 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
1148 //
1149 InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT);
1150
1151 //
1152 // Send data to SMM.
1153 //
1154 SendCommunicateBuffer (0);
1155
1156 //
1157 // Install the system configuration table for variable info data captured
1158 //
1159 if (FeaturePcdGet (PcdEnableVariableRuntimeCache) && FeaturePcdGet (PcdVariableCollectStatistics)) {
1160 if (mVariableAuthFormat) {
1161 gBS->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid, mVariableInfo);
1162 } else {
1163 gBS->InstallConfigurationTable (&gEfiVariableGuid, mVariableInfo);
1164 }
1165 }
1166
1167 gBS->CloseEvent (Event);
1168 }
1169
1170
1171 /**
1172 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
1173
1174 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
1175 It convers pointer to new virtual address.
1176
1177 @param[in] Event Event whose notification function is being invoked.
1178 @param[in] Context Pointer to the notification function's context.
1179
1180 **/
1181 VOID
1182 EFIAPI
1183 VariableAddressChangeEvent (
1184 IN EFI_EVENT Event,
1185 IN VOID *Context
1186 )
1187 {
1188 EfiConvertPointer (0x0, (VOID **) &mVariableBuffer);
1189 EfiConvertPointer (0x0, (VOID **) &mSmmCommunication);
1190 EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **) &mVariableRuntimeHobCacheBuffer);
1191 EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **) &mVariableRuntimeNvCacheBuffer);
1192 EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **) &mVariableRuntimeVolatileCacheBuffer);
1193 }
1194
1195 /**
1196 This code gets variable payload size.
1197
1198 @param[out] VariablePayloadSize Output pointer to variable payload size.
1199
1200 @retval EFI_SUCCESS Get successfully.
1201 @retval Others Get unsuccessfully.
1202
1203 **/
1204 EFI_STATUS
1205 EFIAPI
1206 GetVariablePayloadSize (
1207 OUT UINTN *VariablePayloadSize
1208 )
1209 {
1210 EFI_STATUS Status;
1211 SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *SmmGetPayloadSize;
1212 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
1213 SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
1214 UINTN CommSize;
1215 UINT8 *CommBuffer;
1216
1217 SmmGetPayloadSize = NULL;
1218 CommBuffer = NULL;
1219
1220 if(VariablePayloadSize == NULL) {
1221 return EFI_INVALID_PARAMETER;
1222 }
1223
1224 AcquireLockOnlyAtBootTime(&mVariableServicesLock);
1225
1226 //
1227 // Init the communicate buffer. The buffer data size is:
1228 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
1229 //
1230 CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
1231 CommBuffer = AllocateZeroPool (CommSize);
1232 if (CommBuffer == NULL) {
1233 Status = EFI_OUT_OF_RESOURCES;
1234 goto Done;
1235 }
1236
1237 SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) CommBuffer;
1238 CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);
1239 SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
1240
1241 SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;
1242 SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE;
1243 SmmGetPayloadSize = (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *) SmmVariableFunctionHeader->Data;
1244
1245 //
1246 // Send data to SMM.
1247 //
1248 Status = mSmmCommunication->Communicate (mSmmCommunication, CommBuffer, &CommSize);
1249 ASSERT_EFI_ERROR (Status);
1250
1251 Status = SmmVariableFunctionHeader->ReturnStatus;
1252 if (EFI_ERROR (Status)) {
1253 goto Done;
1254 }
1255
1256 //
1257 // Get data from SMM.
1258 //
1259 *VariablePayloadSize = SmmGetPayloadSize->VariablePayloadSize;
1260
1261 Done:
1262 if (CommBuffer != NULL) {
1263 FreePool (CommBuffer);
1264 }
1265 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
1266 return Status;
1267 }
1268
1269 /**
1270 This code gets information needed from SMM for runtime cache initialization.
1271
1272 @param[out] TotalHobStorageSize Output pointer for the total HOB storage size in bytes.
1273 @param[out] TotalNvStorageSize Output pointer for the total non-volatile storage size in bytes.
1274 @param[out] TotalVolatileStorageSize Output pointer for the total volatile storage size in bytes.
1275 @param[out] AuthenticatedVariableUsage Output pointer that indicates if authenticated variables are to be used.
1276
1277 @retval EFI_SUCCESS Retrieved the size successfully.
1278 @retval EFI_INVALID_PARAMETER TotalNvStorageSize parameter is NULL.
1279 @retval EFI_OUT_OF_RESOURCES The memory resources needed for a CommBuffer are not available.
1280 @retval Others Could not retrieve the size successfully.
1281
1282 **/
1283 EFI_STATUS
1284 GetRuntimeCacheInfo (
1285 OUT UINTN *TotalHobStorageSize,
1286 OUT UINTN *TotalNvStorageSize,
1287 OUT UINTN *TotalVolatileStorageSize,
1288 OUT BOOLEAN *AuthenticatedVariableUsage
1289 )
1290 {
1291 EFI_STATUS Status;
1292 SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *SmmGetRuntimeCacheInfo;
1293 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
1294 SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
1295 UINTN CommSize;
1296 UINT8 *CommBuffer;
1297
1298 SmmGetRuntimeCacheInfo = NULL;
1299 CommBuffer = mVariableBuffer;
1300
1301 if (TotalHobStorageSize == NULL || TotalNvStorageSize == NULL || TotalVolatileStorageSize == NULL || AuthenticatedVariableUsage == NULL) {
1302 return EFI_INVALID_PARAMETER;
1303 }
1304
1305 if (CommBuffer == NULL) {
1306 return EFI_OUT_OF_RESOURCES;
1307 }
1308
1309 AcquireLockOnlyAtBootTime (&mVariableServicesLock);
1310
1311 CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO);
1312 ZeroMem (CommBuffer, CommSize);
1313
1314 SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) CommBuffer;
1315 CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);
1316 SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO);
1317
1318 SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;
1319 SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO;
1320 SmmGetRuntimeCacheInfo = (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *) SmmVariableFunctionHeader->Data;
1321
1322 //
1323 // Send data to SMM.
1324 //
1325 Status = mSmmCommunication->Communicate (mSmmCommunication, CommBuffer, &CommSize);
1326 ASSERT_EFI_ERROR (Status);
1327 if (CommSize <= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) {
1328 Status = EFI_BAD_BUFFER_SIZE;
1329 goto Done;
1330 }
1331
1332 Status = SmmVariableFunctionHeader->ReturnStatus;
1333 if (EFI_ERROR (Status)) {
1334 goto Done;
1335 }
1336
1337 //
1338 // Get data from SMM.
1339 //
1340 *TotalHobStorageSize = SmmGetRuntimeCacheInfo->TotalHobStorageSize;
1341 *TotalNvStorageSize = SmmGetRuntimeCacheInfo->TotalNvStorageSize;
1342 *TotalVolatileStorageSize = SmmGetRuntimeCacheInfo->TotalVolatileStorageSize;
1343 *AuthenticatedVariableUsage = SmmGetRuntimeCacheInfo->AuthenticatedVariableUsage;
1344
1345 Done:
1346 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
1347 return Status;
1348 }
1349
1350 /**
1351 Sends the runtime variable cache context information to SMM.
1352
1353 @retval EFI_SUCCESS Retrieved the size successfully.
1354 @retval EFI_INVALID_PARAMETER TotalNvStorageSize parameter is NULL.
1355 @retval EFI_OUT_OF_RESOURCES The memory resources needed for a CommBuffer are not available.
1356 @retval Others Could not retrieve the size successfully.;
1357
1358 **/
1359 EFI_STATUS
1360 SendRuntimeVariableCacheContextToSmm (
1361 VOID
1362 )
1363 {
1364 EFI_STATUS Status;
1365 SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT *SmmRuntimeVarCacheContext;
1366 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
1367 SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
1368 UINTN CommSize;
1369 UINT8 *CommBuffer;
1370
1371 SmmRuntimeVarCacheContext = NULL;
1372 CommBuffer = mVariableBuffer;
1373
1374 if (CommBuffer == NULL) {
1375 return EFI_OUT_OF_RESOURCES;
1376 }
1377
1378 AcquireLockOnlyAtBootTime (&mVariableServicesLock);
1379
1380 //
1381 // Init the communicate buffer. The buffer data size is:
1382 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);
1383 //
1384 CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);
1385 ZeroMem (CommBuffer, CommSize);
1386
1387 SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) CommBuffer;
1388 CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);
1389 SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);
1390
1391 SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;
1392 SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT;
1393 SmmRuntimeVarCacheContext = (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT *) SmmVariableFunctionHeader->Data;
1394
1395 SmmRuntimeVarCacheContext->RuntimeHobCache = mVariableRuntimeHobCacheBuffer;
1396 SmmRuntimeVarCacheContext->RuntimeVolatileCache = mVariableRuntimeVolatileCacheBuffer;
1397 SmmRuntimeVarCacheContext->RuntimeNvCache = mVariableRuntimeNvCacheBuffer;
1398 SmmRuntimeVarCacheContext->PendingUpdate = &mVariableRuntimeCachePendingUpdate;
1399 SmmRuntimeVarCacheContext->ReadLock = &mVariableRuntimeCacheReadLock;
1400 SmmRuntimeVarCacheContext->HobFlushComplete = &mHobFlushComplete;
1401
1402 //
1403 // Send data to SMM.
1404 //
1405 Status = mSmmCommunication->Communicate (mSmmCommunication, CommBuffer, &CommSize);
1406 ASSERT_EFI_ERROR (Status);
1407 if (CommSize <= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) {
1408 Status = EFI_BAD_BUFFER_SIZE;
1409 goto Done;
1410 }
1411
1412 Status = SmmVariableFunctionHeader->ReturnStatus;
1413 if (EFI_ERROR (Status)) {
1414 goto Done;
1415 }
1416
1417 Done:
1418 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
1419 return Status;
1420 }
1421
1422 /**
1423 Initialize variable service and install Variable Architectural protocol.
1424
1425 @param[in] Event Event whose notification function is being invoked.
1426 @param[in] Context Pointer to the notification function's context.
1427
1428 **/
1429 VOID
1430 EFIAPI
1431 SmmVariableReady (
1432 IN EFI_EVENT Event,
1433 IN VOID *Context
1434 )
1435 {
1436 EFI_STATUS Status;
1437
1438 Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **) &mSmmVariable);
1439 if (EFI_ERROR (Status)) {
1440 return;
1441 }
1442
1443 Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication);
1444 ASSERT_EFI_ERROR (Status);
1445
1446 //
1447 // Allocate memory for variable communicate buffer.
1448 //
1449 Status = GetVariablePayloadSize (&mVariableBufferPayloadSize);
1450 ASSERT_EFI_ERROR (Status);
1451 mVariableBufferSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + mVariableBufferPayloadSize;
1452 mVariableBuffer = AllocateRuntimePool (mVariableBufferSize);
1453 ASSERT (mVariableBuffer != NULL);
1454
1455 //
1456 // Save the buffer physical address used for SMM conmunication.
1457 //
1458 mVariableBufferPhysical = mVariableBuffer;
1459
1460 if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) {
1461 DEBUG ((DEBUG_INFO, "Variable driver runtime cache is enabled.\n"));
1462 //
1463 // Allocate runtime variable cache memory buffers.
1464 //
1465 Status = GetRuntimeCacheInfo (
1466 &mVariableRuntimeHobCacheBufferSize,
1467 &mVariableRuntimeNvCacheBufferSize,
1468 &mVariableRuntimeVolatileCacheBufferSize,
1469 &mVariableAuthFormat
1470 );
1471 if (!EFI_ERROR (Status)) {
1472 Status = InitVariableCache (&mVariableRuntimeHobCacheBuffer, &mVariableRuntimeHobCacheBufferSize);
1473 if (!EFI_ERROR (Status)) {
1474 Status = InitVariableCache (&mVariableRuntimeNvCacheBuffer, &mVariableRuntimeNvCacheBufferSize);
1475 if (!EFI_ERROR (Status)) {
1476 Status = InitVariableCache (&mVariableRuntimeVolatileCacheBuffer, &mVariableRuntimeVolatileCacheBufferSize);
1477 if (!EFI_ERROR (Status)) {
1478 Status = SendRuntimeVariableCacheContextToSmm ();
1479 if (!EFI_ERROR (Status)) {
1480 SyncRuntimeCache ();
1481 }
1482 }
1483 }
1484 }
1485 if (EFI_ERROR (Status)) {
1486 mVariableRuntimeHobCacheBuffer = NULL;
1487 mVariableRuntimeNvCacheBuffer = NULL;
1488 mVariableRuntimeVolatileCacheBuffer = NULL;
1489 }
1490 }
1491 ASSERT_EFI_ERROR (Status);
1492 } else {
1493 DEBUG ((DEBUG_INFO, "Variable driver runtime cache is disabled.\n"));
1494 }
1495
1496 gRT->GetVariable = RuntimeServiceGetVariable;
1497 gRT->GetNextVariableName = RuntimeServiceGetNextVariableName;
1498 gRT->SetVariable = RuntimeServiceSetVariable;
1499 gRT->QueryVariableInfo = RuntimeServiceQueryVariableInfo;
1500
1501 //
1502 // Install the Variable Architectural Protocol on a new handle.
1503 //
1504 Status = gBS->InstallProtocolInterface (
1505 &mHandle,
1506 &gEfiVariableArchProtocolGuid,
1507 EFI_NATIVE_INTERFACE,
1508 NULL
1509 );
1510 ASSERT_EFI_ERROR (Status);
1511
1512 mVariableLock.RequestToLock = VariableLockRequestToLock;
1513 Status = gBS->InstallMultipleProtocolInterfaces (
1514 &mHandle,
1515 &gEdkiiVariableLockProtocolGuid,
1516 &mVariableLock,
1517 NULL
1518 );
1519 ASSERT_EFI_ERROR (Status);
1520
1521 mVarCheck.RegisterSetVariableCheckHandler = VarCheckRegisterSetVariableCheckHandler;
1522 mVarCheck.VariablePropertySet = VarCheckVariablePropertySet;
1523 mVarCheck.VariablePropertyGet = VarCheckVariablePropertyGet;
1524 Status = gBS->InstallMultipleProtocolInterfaces (
1525 &mHandle,
1526 &gEdkiiVarCheckProtocolGuid,
1527 &mVarCheck,
1528 NULL
1529 );
1530 ASSERT_EFI_ERROR (Status);
1531
1532 gBS->CloseEvent (Event);
1533 }
1534
1535
1536 /**
1537 SMM Non-Volatile variable write service is ready notify event handler.
1538
1539 @param[in] Event Event whose notification function is being invoked.
1540 @param[in] Context Pointer to the notification function's context.
1541
1542 **/
1543 VOID
1544 EFIAPI
1545 SmmVariableWriteReady (
1546 IN EFI_EVENT Event,
1547 IN VOID *Context
1548 )
1549 {
1550 EFI_STATUS Status;
1551 VOID *ProtocolOps;
1552
1553 //
1554 // Check whether the protocol is installed or not.
1555 //
1556 Status = gBS->LocateProtocol (&gSmmVariableWriteGuid, NULL, (VOID **) &ProtocolOps);
1557 if (EFI_ERROR (Status)) {
1558 return;
1559 }
1560
1561 //
1562 // Some Secure Boot Policy Var (SecureBoot, etc) updates following other
1563 // Secure Boot Policy Variable change. Record their initial value.
1564 //
1565 RecordSecureBootPolicyVarData();
1566
1567 Status = gBS->InstallProtocolInterface (
1568 &mHandle,
1569 &gEfiVariableWriteArchProtocolGuid,
1570 EFI_NATIVE_INTERFACE,
1571 NULL
1572 );
1573 ASSERT_EFI_ERROR (Status);
1574
1575 gBS->CloseEvent (Event);
1576 }
1577
1578
1579 /**
1580 Variable Driver main entry point. The Variable driver places the 4 EFI
1581 runtime services in the EFI System Table and installs arch protocols
1582 for variable read and write services being available. It also registers
1583 a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
1584
1585 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1586 @param[in] SystemTable A pointer to the EFI System Table.
1587
1588 @retval EFI_SUCCESS Variable service successfully initialized.
1589
1590 **/
1591 EFI_STATUS
1592 EFIAPI
1593 VariableSmmRuntimeInitialize (
1594 IN EFI_HANDLE ImageHandle,
1595 IN EFI_SYSTEM_TABLE *SystemTable
1596 )
1597 {
1598 VOID *SmmVariableRegistration;
1599 VOID *SmmVariableWriteRegistration;
1600 EFI_EVENT OnReadyToBootEvent;
1601 EFI_EVENT ExitBootServiceEvent;
1602 EFI_EVENT LegacyBootEvent;
1603
1604 EfiInitializeLock (&mVariableServicesLock, TPL_NOTIFY);
1605
1606 //
1607 // Smm variable service is ready
1608 //
1609 EfiCreateProtocolNotifyEvent (
1610 &gEfiSmmVariableProtocolGuid,
1611 TPL_CALLBACK,
1612 SmmVariableReady,
1613 NULL,
1614 &SmmVariableRegistration
1615 );
1616
1617 //
1618 // Smm Non-Volatile variable write service is ready
1619 //
1620 EfiCreateProtocolNotifyEvent (
1621 &gSmmVariableWriteGuid,
1622 TPL_CALLBACK,
1623 SmmVariableWriteReady,
1624 NULL,
1625 &SmmVariableWriteRegistration
1626 );
1627
1628 //
1629 // Register the event to reclaim variable for OS usage.
1630 //
1631 EfiCreateEventReadyToBootEx (
1632 TPL_NOTIFY,
1633 OnReadyToBoot,
1634 NULL,
1635 &OnReadyToBootEvent
1636 );
1637
1638 //
1639 // Register the event to inform SMM variable that it is at runtime.
1640 //
1641 gBS->CreateEventEx (
1642 EVT_NOTIFY_SIGNAL,
1643 TPL_NOTIFY,
1644 OnExitBootServices,
1645 NULL,
1646 &gEfiEventExitBootServicesGuid,
1647 &ExitBootServiceEvent
1648 );
1649
1650 //
1651 // Register the event to inform SMM variable that it is at runtime for legacy boot.
1652 // Reuse OnExitBootServices() here.
1653 //
1654 EfiCreateEventLegacyBootEx(
1655 TPL_NOTIFY,
1656 OnExitBootServices,
1657 NULL,
1658 &LegacyBootEvent
1659 );
1660
1661 //
1662 // Register the event to convert the pointer for runtime.
1663 //
1664 gBS->CreateEventEx (
1665 EVT_NOTIFY_SIGNAL,
1666 TPL_NOTIFY,
1667 VariableAddressChangeEvent,
1668 NULL,
1669 &gEfiEventVirtualAddressChangeGuid,
1670 &mVirtualAddressChangeEvent
1671 );
1672
1673 return EFI_SUCCESS;
1674 }
1675