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