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