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