]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
MdeModulePkg: Change use of EFI_D_* to DEBUG_*
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / VariableSmm.c
1 /** @file
2 The sample implementation for SMM variable protocol. And this driver
3 implements an SMI handler to communicate with the DXE runtime driver
4 to provide variable services.
5
6 Caution: This module requires additional review when modified.
7 This driver will have external input - variable data and communicate buffer in SMM mode.
8 This external input must be validated carefully to avoid security issue like
9 buffer overflow, integer overflow.
10
11 SmmVariableHandler() will receive untrusted input and do basic validation.
12
13 Each sub function VariableServiceGetVariable(), VariableServiceGetNextVariableName(),
14 VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), ReclaimForOS(),
15 SmmVariableGetStatistics() should also do validation based on its own knowledge.
16
17 Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
18 Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>
19 SPDX-License-Identifier: BSD-2-Clause-Patent
20
21 **/
22
23 #include <Protocol/SmmVariable.h>
24 #include <Protocol/SmmFirmwareVolumeBlock.h>
25 #include <Protocol/SmmFaultTolerantWrite.h>
26 #include <Protocol/MmEndOfDxe.h>
27 #include <Protocol/SmmVarCheck.h>
28
29 #include <Library/MmServicesTableLib.h>
30 #include <Library/VariablePolicyLib.h>
31
32 #include <Guid/SmmVariableCommon.h>
33 #include "Variable.h"
34 #include "VariableParsing.h"
35 #include "VariableRuntimeCache.h"
36
37 extern VARIABLE_STORE_HEADER *mNvVariableCache;
38
39 BOOLEAN mAtRuntime = FALSE;
40 UINT8 *mVariableBufferPayload = NULL;
41 UINTN mVariableBufferPayloadSize;
42
43 /**
44 SecureBoot Hook for SetVariable.
45
46 @param[in] VariableName Name of Variable to be found.
47 @param[in] VendorGuid Variable vendor GUID.
48
49 **/
50 VOID
51 EFIAPI
52 SecureBootHook (
53 IN CHAR16 *VariableName,
54 IN EFI_GUID *VendorGuid
55 )
56 {
57 return ;
58 }
59
60 /**
61
62 This code sets variable in storage blocks (Volatile or Non-Volatile).
63
64 @param VariableName Name of Variable to be found.
65 @param VendorGuid Variable vendor GUID.
66 @param Attributes Attribute value of the variable found
67 @param DataSize Size of Data found. If size is less than the
68 data, this value contains the required size.
69 @param Data Data pointer.
70
71 @return EFI_INVALID_PARAMETER Invalid parameter.
72 @return EFI_SUCCESS Set successfully.
73 @return EFI_OUT_OF_RESOURCES Resource not enough to set variable.
74 @return EFI_NOT_FOUND Not found.
75 @return EFI_WRITE_PROTECTED Variable is read-only.
76
77 **/
78 EFI_STATUS
79 EFIAPI
80 SmmVariableSetVariable (
81 IN CHAR16 *VariableName,
82 IN EFI_GUID *VendorGuid,
83 IN UINT32 Attributes,
84 IN UINTN DataSize,
85 IN VOID *Data
86 )
87 {
88 EFI_STATUS Status;
89
90 //
91 // Disable write protection when the calling SetVariable() through EFI_SMM_VARIABLE_PROTOCOL.
92 //
93 mRequestSource = VarCheckFromTrusted;
94 Status = VariableServiceSetVariable (
95 VariableName,
96 VendorGuid,
97 Attributes,
98 DataSize,
99 Data
100 );
101 mRequestSource = VarCheckFromUntrusted;
102 return Status;
103 }
104
105 EFI_SMM_VARIABLE_PROTOCOL gSmmVariable = {
106 VariableServiceGetVariable,
107 VariableServiceGetNextVariableName,
108 SmmVariableSetVariable,
109 VariableServiceQueryVariableInfo
110 };
111
112 EDKII_SMM_VAR_CHECK_PROTOCOL mSmmVarCheck = { VarCheckRegisterSetVariableCheckHandler,
113 VarCheckVariablePropertySet,
114 VarCheckVariablePropertyGet };
115
116 /**
117 Return TRUE if ExitBootServices () has been called.
118
119 @retval TRUE If ExitBootServices () has been called.
120 **/
121 BOOLEAN
122 AtRuntime (
123 VOID
124 )
125 {
126 return mAtRuntime;
127 }
128
129 /**
130 Initializes a basic mutual exclusion lock.
131
132 This function initializes a basic mutual exclusion lock to the released state
133 and returns the lock. Each lock provides mutual exclusion access at its task
134 priority level. Since there is no preemption or multiprocessor support in EFI,
135 acquiring the lock only consists of raising to the locks TPL.
136 If Lock is NULL, then ASSERT().
137 If Priority is not a valid TPL value, then ASSERT().
138
139 @param Lock A pointer to the lock data structure to initialize.
140 @param Priority EFI TPL is associated with the lock.
141
142 @return The lock.
143
144 **/
145 EFI_LOCK *
146 InitializeLock (
147 IN OUT EFI_LOCK *Lock,
148 IN EFI_TPL Priority
149 )
150 {
151 return Lock;
152 }
153
154 /**
155 Acquires lock only at boot time. Simply returns at runtime.
156
157 This is a temperary function that will be removed when
158 EfiAcquireLock() in UefiLib can handle the call in UEFI
159 Runtimer driver in RT phase.
160 It calls EfiAcquireLock() at boot time, and simply returns
161 at runtime.
162
163 @param Lock A pointer to the lock to acquire.
164
165 **/
166 VOID
167 AcquireLockOnlyAtBootTime (
168 IN EFI_LOCK *Lock
169 )
170 {
171
172 }
173
174
175 /**
176 Releases lock only at boot time. Simply returns at runtime.
177
178 This is a temperary function which will be removed when
179 EfiReleaseLock() in UefiLib can handle the call in UEFI
180 Runtimer driver in RT phase.
181 It calls EfiReleaseLock() at boot time and simply returns
182 at runtime.
183
184 @param Lock A pointer to the lock to release.
185
186 **/
187 VOID
188 ReleaseLockOnlyAtBootTime (
189 IN EFI_LOCK *Lock
190 )
191 {
192
193 }
194
195 /**
196 Retrieve the SMM Fault Tolerent Write protocol interface.
197
198 @param[out] FtwProtocol The interface of SMM Ftw protocol
199
200 @retval EFI_SUCCESS The SMM FTW protocol instance was found and returned in FtwProtocol.
201 @retval EFI_NOT_FOUND The SMM FTW protocol instance was not found.
202 @retval EFI_INVALID_PARAMETER SarProtocol is NULL.
203
204 **/
205 EFI_STATUS
206 GetFtwProtocol (
207 OUT VOID **FtwProtocol
208 )
209 {
210 EFI_STATUS Status;
211
212 //
213 // Locate Smm Fault Tolerent Write protocol
214 //
215 Status = gMmst->MmLocateProtocol (
216 &gEfiSmmFaultTolerantWriteProtocolGuid,
217 NULL,
218 FtwProtocol
219 );
220 return Status;
221 }
222
223
224 /**
225 Retrieve the SMM FVB protocol interface by HANDLE.
226
227 @param[in] FvBlockHandle The handle of SMM FVB protocol that provides services for
228 reading, writing, and erasing the target block.
229 @param[out] FvBlock The interface of SMM FVB protocol
230
231 @retval EFI_SUCCESS The interface information for the specified protocol was returned.
232 @retval EFI_UNSUPPORTED The device does not support the SMM FVB protocol.
233 @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL.
234
235 **/
236 EFI_STATUS
237 GetFvbByHandle (
238 IN EFI_HANDLE FvBlockHandle,
239 OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock
240 )
241 {
242 //
243 // To get the SMM FVB protocol interface on the handle
244 //
245 return gMmst->MmHandleProtocol (
246 FvBlockHandle,
247 &gEfiSmmFirmwareVolumeBlockProtocolGuid,
248 (VOID **) FvBlock
249 );
250 }
251
252
253 /**
254 Function returns an array of handles that support the SMM FVB protocol
255 in a buffer allocated from pool.
256
257 @param[out] NumberHandles The number of handles returned in Buffer.
258 @param[out] Buffer A pointer to the buffer to return the requested
259 array of handles that support SMM FVB protocol.
260
261 @retval EFI_SUCCESS The array of handles was returned in Buffer, and the number of
262 handles in Buffer was returned in NumberHandles.
263 @retval EFI_NOT_FOUND No SMM FVB handle was found.
264 @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results.
265 @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL.
266
267 **/
268 EFI_STATUS
269 GetFvbCountAndBuffer (
270 OUT UINTN *NumberHandles,
271 OUT EFI_HANDLE **Buffer
272 )
273 {
274 EFI_STATUS Status;
275 UINTN BufferSize;
276
277 if ((NumberHandles == NULL) || (Buffer == NULL)) {
278 return EFI_INVALID_PARAMETER;
279 }
280
281 BufferSize = 0;
282 *NumberHandles = 0;
283 *Buffer = NULL;
284 Status = gMmst->MmLocateHandle (
285 ByProtocol,
286 &gEfiSmmFirmwareVolumeBlockProtocolGuid,
287 NULL,
288 &BufferSize,
289 *Buffer
290 );
291 if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) {
292 return EFI_NOT_FOUND;
293 }
294
295 *Buffer = AllocatePool (BufferSize);
296 if (*Buffer == NULL) {
297 return EFI_OUT_OF_RESOURCES;
298 }
299
300 Status = gMmst->MmLocateHandle (
301 ByProtocol,
302 &gEfiSmmFirmwareVolumeBlockProtocolGuid,
303 NULL,
304 &BufferSize,
305 *Buffer
306 );
307
308 *NumberHandles = BufferSize / sizeof(EFI_HANDLE);
309 if (EFI_ERROR(Status)) {
310 *NumberHandles = 0;
311 FreePool (*Buffer);
312 *Buffer = NULL;
313 }
314
315 return Status;
316 }
317
318
319 /**
320 Get the variable statistics information from the information buffer pointed by gVariableInfo.
321
322 Caution: This function may be invoked at SMM runtime.
323 InfoEntry and InfoSize are external input. Care must be taken to make sure not security issue at runtime.
324
325 @param[in, out] InfoEntry A pointer to the buffer of variable information entry.
326 On input, point to the variable information returned last time. if
327 InfoEntry->VendorGuid is zero, return the first information.
328 On output, point to the next variable information.
329 @param[in, out] InfoSize On input, the size of the variable information buffer.
330 On output, the returned variable information size.
331
332 @retval EFI_SUCCESS The variable information is found and returned successfully.
333 @retval EFI_UNSUPPORTED No variable inoformation exists in variable driver. The
334 PcdVariableCollectStatistics should be set TRUE to support it.
335 @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold the next variable information.
336 @retval EFI_INVALID_PARAMETER Input parameter is invalid.
337
338 **/
339 EFI_STATUS
340 SmmVariableGetStatistics (
341 IN OUT VARIABLE_INFO_ENTRY *InfoEntry,
342 IN OUT UINTN *InfoSize
343 )
344 {
345 VARIABLE_INFO_ENTRY *VariableInfo;
346 UINTN NameSize;
347 UINTN StatisticsInfoSize;
348 CHAR16 *InfoName;
349 UINTN InfoNameMaxSize;
350 EFI_GUID VendorGuid;
351
352 if (InfoEntry == NULL) {
353 return EFI_INVALID_PARAMETER;
354 }
355
356 VariableInfo = gVariableInfo;
357 if (VariableInfo == NULL) {
358 return EFI_UNSUPPORTED;
359 }
360
361 StatisticsInfoSize = sizeof (VARIABLE_INFO_ENTRY);
362 if (*InfoSize < StatisticsInfoSize) {
363 *InfoSize = StatisticsInfoSize;
364 return EFI_BUFFER_TOO_SMALL;
365 }
366 InfoName = (CHAR16 *)(InfoEntry + 1);
367 InfoNameMaxSize = (*InfoSize - sizeof (VARIABLE_INFO_ENTRY));
368
369 CopyGuid (&VendorGuid, &InfoEntry->VendorGuid);
370
371 if (IsZeroGuid (&VendorGuid)) {
372 //
373 // Return the first variable info
374 //
375 NameSize = StrSize (VariableInfo->Name);
376 StatisticsInfoSize = sizeof (VARIABLE_INFO_ENTRY) + NameSize;
377 if (*InfoSize < StatisticsInfoSize) {
378 *InfoSize = StatisticsInfoSize;
379 return EFI_BUFFER_TOO_SMALL;
380 }
381 CopyMem (InfoEntry, VariableInfo, sizeof (VARIABLE_INFO_ENTRY));
382 CopyMem (InfoName, VariableInfo->Name, NameSize);
383 *InfoSize = StatisticsInfoSize;
384 return EFI_SUCCESS;
385 }
386
387 //
388 // Get the next variable info
389 //
390 while (VariableInfo != NULL) {
391 if (CompareGuid (&VariableInfo->VendorGuid, &VendorGuid)) {
392 NameSize = StrSize (VariableInfo->Name);
393 if (NameSize <= InfoNameMaxSize) {
394 if (CompareMem (VariableInfo->Name, InfoName, NameSize) == 0) {
395 //
396 // Find the match one
397 //
398 VariableInfo = VariableInfo->Next;
399 break;
400 }
401 }
402 }
403 VariableInfo = VariableInfo->Next;
404 };
405
406 if (VariableInfo == NULL) {
407 *InfoSize = 0;
408 return EFI_SUCCESS;
409 }
410
411 //
412 // Output the new variable info
413 //
414 NameSize = StrSize (VariableInfo->Name);
415 StatisticsInfoSize = sizeof (VARIABLE_INFO_ENTRY) + NameSize;
416 if (*InfoSize < StatisticsInfoSize) {
417 *InfoSize = StatisticsInfoSize;
418 return EFI_BUFFER_TOO_SMALL;
419 }
420
421 CopyMem (InfoEntry, VariableInfo, sizeof (VARIABLE_INFO_ENTRY));
422 CopyMem (InfoName, VariableInfo->Name, NameSize);
423 *InfoSize = StatisticsInfoSize;
424
425 return EFI_SUCCESS;
426 }
427
428
429 /**
430 Communication service SMI Handler entry.
431
432 This SMI handler provides services for the variable wrapper driver.
433
434 Caution: This function may receive untrusted input.
435 This variable data and communicate buffer are external input, so this function will do basic validation.
436 Each sub function VariableServiceGetVariable(), VariableServiceGetNextVariableName(),
437 VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), ReclaimForOS(),
438 SmmVariableGetStatistics() should also do validation based on its own knowledge.
439
440 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
441 @param[in] RegisterContext Points to an optional handler context which was specified when the
442 handler was registered.
443 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
444 be conveyed from a non-SMM environment into an SMM environment.
445 @param[in, out] CommBufferSize The size of the CommBuffer.
446
447 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
448 should still be called.
449 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
450 still be called.
451 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
452 be called.
453 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
454 **/
455 EFI_STATUS
456 EFIAPI
457 SmmVariableHandler (
458 IN EFI_HANDLE DispatchHandle,
459 IN CONST VOID *RegisterContext,
460 IN OUT VOID *CommBuffer,
461 IN OUT UINTN *CommBufferSize
462 )
463 {
464 EFI_STATUS Status;
465 SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
466 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;
467 SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *GetNextVariableName;
468 SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *QueryVariableInfo;
469 SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *GetPayloadSize;
470 SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT *RuntimeVariableCacheContext;
471 SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *GetRuntimeCacheInfo;
472 SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE *VariableToLock;
473 SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *CommVariableProperty;
474 VARIABLE_INFO_ENTRY *VariableInfo;
475 VARIABLE_RUNTIME_CACHE_CONTEXT *VariableCacheContext;
476 VARIABLE_STORE_HEADER *VariableCache;
477 UINTN InfoSize;
478 UINTN NameBufferSize;
479 UINTN CommBufferPayloadSize;
480 UINTN TempCommBufferSize;
481
482 //
483 // If input is invalid, stop processing this SMI
484 //
485 if (CommBuffer == NULL || CommBufferSize == NULL) {
486 return EFI_SUCCESS;
487 }
488
489 TempCommBufferSize = *CommBufferSize;
490
491 if (TempCommBufferSize < SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) {
492 DEBUG ((DEBUG_ERROR, "SmmVariableHandler: SMM communication buffer size invalid!\n"));
493 return EFI_SUCCESS;
494 }
495 CommBufferPayloadSize = TempCommBufferSize - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
496 if (CommBufferPayloadSize > mVariableBufferPayloadSize) {
497 DEBUG ((DEBUG_ERROR, "SmmVariableHandler: SMM communication buffer payload size invalid!\n"));
498 return EFI_SUCCESS;
499 }
500
501 if (!VariableSmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {
502 DEBUG ((DEBUG_ERROR, "SmmVariableHandler: SMM communication buffer in SMRAM or overflow!\n"));
503 return EFI_SUCCESS;
504 }
505
506 SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)CommBuffer;
507 switch (SmmVariableFunctionHeader->Function) {
508 case SMM_VARIABLE_FUNCTION_GET_VARIABLE:
509 if (CommBufferPayloadSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {
510 DEBUG ((DEBUG_ERROR, "GetVariable: SMM communication buffer size invalid!\n"));
511 return EFI_SUCCESS;
512 }
513 //
514 // Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.
515 //
516 CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);
517 SmmVariableHeader = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *) mVariableBufferPayload;
518 if (((UINTN)(~0) - SmmVariableHeader->DataSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||
519 ((UINTN)(~0) - SmmVariableHeader->NameSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + SmmVariableHeader->DataSize)) {
520 //
521 // Prevent InfoSize overflow happen
522 //
523 Status = EFI_ACCESS_DENIED;
524 goto EXIT;
525 }
526 InfoSize = OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)
527 + SmmVariableHeader->DataSize + SmmVariableHeader->NameSize;
528
529 //
530 // SMRAM range check already covered before
531 //
532 if (InfoSize > CommBufferPayloadSize) {
533 DEBUG ((DEBUG_ERROR, "GetVariable: Data size exceed communication buffer size limit!\n"));
534 Status = EFI_ACCESS_DENIED;
535 goto EXIT;
536 }
537
538 //
539 // The VariableSpeculationBarrier() call here is to ensure the previous
540 // range/content checks for the CommBuffer have been completed before the
541 // subsequent consumption of the CommBuffer content.
542 //
543 VariableSpeculationBarrier ();
544 if (SmmVariableHeader->NameSize < sizeof (CHAR16) || SmmVariableHeader->Name[SmmVariableHeader->NameSize/sizeof (CHAR16) - 1] != L'\0') {
545 //
546 // Make sure VariableName is A Null-terminated string.
547 //
548 Status = EFI_ACCESS_DENIED;
549 goto EXIT;
550 }
551
552 Status = VariableServiceGetVariable (
553 SmmVariableHeader->Name,
554 &SmmVariableHeader->Guid,
555 &SmmVariableHeader->Attributes,
556 &SmmVariableHeader->DataSize,
557 (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize
558 );
559 CopyMem (SmmVariableFunctionHeader->Data, mVariableBufferPayload, CommBufferPayloadSize);
560 break;
561
562 case SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME:
563 if (CommBufferPayloadSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
564 DEBUG ((DEBUG_ERROR, "GetNextVariableName: SMM communication buffer size invalid!\n"));
565 return EFI_SUCCESS;
566 }
567 //
568 // Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.
569 //
570 CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);
571 GetNextVariableName = (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *) mVariableBufferPayload;
572 if ((UINTN)(~0) - GetNextVariableName->NameSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
573 //
574 // Prevent InfoSize overflow happen
575 //
576 Status = EFI_ACCESS_DENIED;
577 goto EXIT;
578 }
579 InfoSize = OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + GetNextVariableName->NameSize;
580
581 //
582 // SMRAM range check already covered before
583 //
584 if (InfoSize > CommBufferPayloadSize) {
585 DEBUG ((DEBUG_ERROR, "GetNextVariableName: Data size exceed communication buffer size limit!\n"));
586 Status = EFI_ACCESS_DENIED;
587 goto EXIT;
588 }
589
590 NameBufferSize = CommBufferPayloadSize - OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name);
591 if (NameBufferSize < sizeof (CHAR16) || GetNextVariableName->Name[NameBufferSize/sizeof (CHAR16) - 1] != L'\0') {
592 //
593 // Make sure input VariableName is A Null-terminated string.
594 //
595 Status = EFI_ACCESS_DENIED;
596 goto EXIT;
597 }
598
599 Status = VariableServiceGetNextVariableName (
600 &GetNextVariableName->NameSize,
601 GetNextVariableName->Name,
602 &GetNextVariableName->Guid
603 );
604 CopyMem (SmmVariableFunctionHeader->Data, mVariableBufferPayload, CommBufferPayloadSize);
605 break;
606
607 case SMM_VARIABLE_FUNCTION_SET_VARIABLE:
608 if (CommBufferPayloadSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {
609 DEBUG ((DEBUG_ERROR, "SetVariable: SMM communication buffer size invalid!\n"));
610 return EFI_SUCCESS;
611 }
612 //
613 // Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.
614 //
615 CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);
616 SmmVariableHeader = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *) mVariableBufferPayload;
617 if (((UINTN)(~0) - SmmVariableHeader->DataSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||
618 ((UINTN)(~0) - SmmVariableHeader->NameSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + SmmVariableHeader->DataSize)) {
619 //
620 // Prevent InfoSize overflow happen
621 //
622 Status = EFI_ACCESS_DENIED;
623 goto EXIT;
624 }
625 InfoSize = OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)
626 + SmmVariableHeader->DataSize + SmmVariableHeader->NameSize;
627
628 //
629 // SMRAM range check already covered before
630 // Data buffer should not contain SMM range
631 //
632 if (InfoSize > CommBufferPayloadSize) {
633 DEBUG ((DEBUG_ERROR, "SetVariable: Data size exceed communication buffer size limit!\n"));
634 Status = EFI_ACCESS_DENIED;
635 goto EXIT;
636 }
637
638 //
639 // The VariableSpeculationBarrier() call here is to ensure the previous
640 // range/content checks for the CommBuffer have been completed before the
641 // subsequent consumption of the CommBuffer content.
642 //
643 VariableSpeculationBarrier ();
644 if (SmmVariableHeader->NameSize < sizeof (CHAR16) || SmmVariableHeader->Name[SmmVariableHeader->NameSize/sizeof (CHAR16) - 1] != L'\0') {
645 //
646 // Make sure VariableName is A Null-terminated string.
647 //
648 Status = EFI_ACCESS_DENIED;
649 goto EXIT;
650 }
651
652 Status = VariableServiceSetVariable (
653 SmmVariableHeader->Name,
654 &SmmVariableHeader->Guid,
655 SmmVariableHeader->Attributes,
656 SmmVariableHeader->DataSize,
657 (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize
658 );
659 break;
660
661 case SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO:
662 if (CommBufferPayloadSize < sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO)) {
663 DEBUG ((DEBUG_ERROR, "QueryVariableInfo: SMM communication buffer size invalid!\n"));
664 return EFI_SUCCESS;
665 }
666 QueryVariableInfo = (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *) SmmVariableFunctionHeader->Data;
667
668 Status = VariableServiceQueryVariableInfo (
669 QueryVariableInfo->Attributes,
670 &QueryVariableInfo->MaximumVariableStorageSize,
671 &QueryVariableInfo->RemainingVariableStorageSize,
672 &QueryVariableInfo->MaximumVariableSize
673 );
674 break;
675
676 case SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE:
677 if (CommBufferPayloadSize < sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE)) {
678 DEBUG ((DEBUG_ERROR, "GetPayloadSize: SMM communication buffer size invalid!\n"));
679 return EFI_SUCCESS;
680 }
681 GetPayloadSize = (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *) SmmVariableFunctionHeader->Data;
682 GetPayloadSize->VariablePayloadSize = mVariableBufferPayloadSize;
683 Status = EFI_SUCCESS;
684 break;
685
686 case SMM_VARIABLE_FUNCTION_READY_TO_BOOT:
687 if (AtRuntime()) {
688 Status = EFI_UNSUPPORTED;
689 break;
690 }
691 if (!mEndOfDxe) {
692 MorLockInitAtEndOfDxe ();
693 Status = LockVariablePolicy ();
694 ASSERT_EFI_ERROR (Status);
695 mEndOfDxe = TRUE;
696 VarCheckLibInitializeAtEndOfDxe (NULL);
697 //
698 // The initialization for variable quota.
699 //
700 InitializeVariableQuota ();
701 }
702 ReclaimForOS ();
703 Status = EFI_SUCCESS;
704 break;
705
706 case SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE:
707 mAtRuntime = TRUE;
708 Status = EFI_SUCCESS;
709 break;
710
711 case SMM_VARIABLE_FUNCTION_GET_STATISTICS:
712 VariableInfo = (VARIABLE_INFO_ENTRY *) SmmVariableFunctionHeader->Data;
713 InfoSize = TempCommBufferSize - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
714
715 //
716 // Do not need to check SmmVariableFunctionHeader->Data in SMRAM here.
717 // It is covered by previous CommBuffer check
718 //
719
720 //
721 // Do not need to check CommBufferSize buffer as it should point to SMRAM
722 // that was used by SMM core to cache CommSize from SmmCommunication protocol.
723 //
724
725 Status = SmmVariableGetStatistics (VariableInfo, &InfoSize);
726 *CommBufferSize = InfoSize + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
727 break;
728
729 case SMM_VARIABLE_FUNCTION_LOCK_VARIABLE:
730 if (mEndOfDxe) {
731 Status = EFI_ACCESS_DENIED;
732 } else {
733 VariableToLock = (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE *) SmmVariableFunctionHeader->Data;
734 Status = VariableLockRequestToLock (
735 NULL,
736 VariableToLock->Name,
737 &VariableToLock->Guid
738 );
739 }
740 break;
741 case SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET:
742 if (mEndOfDxe) {
743 Status = EFI_ACCESS_DENIED;
744 } else {
745 CommVariableProperty = (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *) SmmVariableFunctionHeader->Data;
746 Status = VarCheckVariablePropertySet (
747 CommVariableProperty->Name,
748 &CommVariableProperty->Guid,
749 &CommVariableProperty->VariableProperty
750 );
751 }
752 break;
753 case SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET:
754 if (CommBufferPayloadSize < OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {
755 DEBUG ((DEBUG_ERROR, "VarCheckVariablePropertyGet: SMM communication buffer size invalid!\n"));
756 return EFI_SUCCESS;
757 }
758 //
759 // Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.
760 //
761 CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);
762 CommVariableProperty = (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *) mVariableBufferPayload;
763 if ((UINTN) (~0) - CommVariableProperty->NameSize < OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {
764 //
765 // Prevent InfoSize overflow happen
766 //
767 Status = EFI_ACCESS_DENIED;
768 goto EXIT;
769 }
770 InfoSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) + CommVariableProperty->NameSize;
771
772 //
773 // SMRAM range check already covered before
774 //
775 if (InfoSize > CommBufferPayloadSize) {
776 DEBUG ((DEBUG_ERROR, "VarCheckVariablePropertyGet: Data size exceed communication buffer size limit!\n"));
777 Status = EFI_ACCESS_DENIED;
778 goto EXIT;
779 }
780
781 //
782 // The VariableSpeculationBarrier() call here is to ensure the previous
783 // range/content checks for the CommBuffer have been completed before the
784 // subsequent consumption of the CommBuffer content.
785 //
786 VariableSpeculationBarrier ();
787 if (CommVariableProperty->NameSize < sizeof (CHAR16) || CommVariableProperty->Name[CommVariableProperty->NameSize/sizeof (CHAR16) - 1] != L'\0') {
788 //
789 // Make sure VariableName is A Null-terminated string.
790 //
791 Status = EFI_ACCESS_DENIED;
792 goto EXIT;
793 }
794
795 Status = VarCheckVariablePropertyGet (
796 CommVariableProperty->Name,
797 &CommVariableProperty->Guid,
798 &CommVariableProperty->VariableProperty
799 );
800 CopyMem (SmmVariableFunctionHeader->Data, mVariableBufferPayload, CommBufferPayloadSize);
801 break;
802 case SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT:
803 if (CommBufferPayloadSize < sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT)) {
804 DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: SMM communication buffer size invalid!\n"));
805 Status = EFI_ACCESS_DENIED;
806 goto EXIT;
807 }
808 if (mEndOfDxe) {
809 DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Cannot init context after end of DXE!\n"));
810 Status = EFI_ACCESS_DENIED;
811 goto EXIT;
812 }
813
814 //
815 // Copy the input communicate buffer payload to the pre-allocated SMM variable payload buffer.
816 //
817 CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);
818 RuntimeVariableCacheContext = (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT *) mVariableBufferPayload;
819
820 //
821 // Verify required runtime cache buffers are provided.
822 //
823 if (RuntimeVariableCacheContext->RuntimeVolatileCache == NULL ||
824 RuntimeVariableCacheContext->RuntimeNvCache == NULL ||
825 RuntimeVariableCacheContext->PendingUpdate == NULL ||
826 RuntimeVariableCacheContext->ReadLock == NULL ||
827 RuntimeVariableCacheContext->HobFlushComplete == NULL) {
828 DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Required runtime cache buffer is NULL!\n"));
829 Status = EFI_ACCESS_DENIED;
830 goto EXIT;
831 }
832
833 //
834 // Verify minimum size requirements for the runtime variable store buffers.
835 //
836 if ((RuntimeVariableCacheContext->RuntimeHobCache != NULL &&
837 RuntimeVariableCacheContext->RuntimeHobCache->Size < sizeof (VARIABLE_STORE_HEADER)) ||
838 RuntimeVariableCacheContext->RuntimeVolatileCache->Size < sizeof (VARIABLE_STORE_HEADER) ||
839 RuntimeVariableCacheContext->RuntimeNvCache->Size < sizeof (VARIABLE_STORE_HEADER)) {
840 DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: A runtime cache buffer size is invalid!\n"));
841 Status = EFI_ACCESS_DENIED;
842 goto EXIT;
843 }
844
845 //
846 // Verify runtime buffers do not overlap with SMRAM ranges.
847 //
848 if (RuntimeVariableCacheContext->RuntimeHobCache != NULL &&
849 !VariableSmmIsBufferOutsideSmmValid (
850 (UINTN) RuntimeVariableCacheContext->RuntimeHobCache,
851 (UINTN) RuntimeVariableCacheContext->RuntimeHobCache->Size)) {
852 DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime HOB cache buffer in SMRAM or overflow!\n"));
853 Status = EFI_ACCESS_DENIED;
854 goto EXIT;
855 }
856 if (!VariableSmmIsBufferOutsideSmmValid (
857 (UINTN) RuntimeVariableCacheContext->RuntimeVolatileCache,
858 (UINTN) RuntimeVariableCacheContext->RuntimeVolatileCache->Size)) {
859 DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime volatile cache buffer in SMRAM or overflow!\n"));
860 Status = EFI_ACCESS_DENIED;
861 goto EXIT;
862 }
863 if (!VariableSmmIsBufferOutsideSmmValid (
864 (UINTN) RuntimeVariableCacheContext->RuntimeNvCache,
865 (UINTN) RuntimeVariableCacheContext->RuntimeNvCache->Size)) {
866 DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime non-volatile cache buffer in SMRAM or overflow!\n"));
867 Status = EFI_ACCESS_DENIED;
868 goto EXIT;
869 }
870 if (!VariableSmmIsBufferOutsideSmmValid (
871 (UINTN) RuntimeVariableCacheContext->PendingUpdate,
872 sizeof (*(RuntimeVariableCacheContext->PendingUpdate)))) {
873 DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime cache pending update buffer in SMRAM or overflow!\n"));
874 Status = EFI_ACCESS_DENIED;
875 goto EXIT;
876 }
877 if (!VariableSmmIsBufferOutsideSmmValid (
878 (UINTN) RuntimeVariableCacheContext->ReadLock,
879 sizeof (*(RuntimeVariableCacheContext->ReadLock)))) {
880 DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime cache read lock buffer in SMRAM or overflow!\n"));
881 Status = EFI_ACCESS_DENIED;
882 goto EXIT;
883 }
884 if (!VariableSmmIsBufferOutsideSmmValid (
885 (UINTN) RuntimeVariableCacheContext->HobFlushComplete,
886 sizeof (*(RuntimeVariableCacheContext->HobFlushComplete)))) {
887 DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime cache HOB flush complete buffer in SMRAM or overflow!\n"));
888 Status = EFI_ACCESS_DENIED;
889 goto EXIT;
890 }
891
892 VariableCacheContext = &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext;
893 VariableCacheContext->VariableRuntimeHobCache.Store = RuntimeVariableCacheContext->RuntimeHobCache;
894 VariableCacheContext->VariableRuntimeVolatileCache.Store = RuntimeVariableCacheContext->RuntimeVolatileCache;
895 VariableCacheContext->VariableRuntimeNvCache.Store = RuntimeVariableCacheContext->RuntimeNvCache;
896 VariableCacheContext->PendingUpdate = RuntimeVariableCacheContext->PendingUpdate;
897 VariableCacheContext->ReadLock = RuntimeVariableCacheContext->ReadLock;
898 VariableCacheContext->HobFlushComplete = RuntimeVariableCacheContext->HobFlushComplete;
899
900 // Set up the intial pending request since the RT cache needs to be in sync with SMM cache
901 VariableCacheContext->VariableRuntimeHobCache.PendingUpdateOffset = 0;
902 VariableCacheContext->VariableRuntimeHobCache.PendingUpdateLength = 0;
903 if (mVariableModuleGlobal->VariableGlobal.HobVariableBase > 0 &&
904 VariableCacheContext->VariableRuntimeHobCache.Store != NULL) {
905 VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;
906 VariableCacheContext->VariableRuntimeHobCache.PendingUpdateLength = (UINT32) ((UINTN) GetEndPointer (VariableCache) - (UINTN) VariableCache);
907 CopyGuid (&(VariableCacheContext->VariableRuntimeHobCache.Store->Signature), &(VariableCache->Signature));
908 }
909 VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
910 VariableCacheContext->VariableRuntimeVolatileCache.PendingUpdateOffset = 0;
911 VariableCacheContext->VariableRuntimeVolatileCache.PendingUpdateLength = (UINT32) ((UINTN) GetEndPointer (VariableCache) - (UINTN) VariableCache);
912 CopyGuid (&(VariableCacheContext->VariableRuntimeVolatileCache.Store->Signature), &(VariableCache->Signature));
913
914 VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) mNvVariableCache;
915 VariableCacheContext->VariableRuntimeNvCache.PendingUpdateOffset = 0;
916 VariableCacheContext->VariableRuntimeNvCache.PendingUpdateLength = (UINT32) ((UINTN) GetEndPointer (VariableCache) - (UINTN) VariableCache);
917 CopyGuid (&(VariableCacheContext->VariableRuntimeNvCache.Store->Signature), &(VariableCache->Signature));
918
919 *(VariableCacheContext->PendingUpdate) = TRUE;
920 *(VariableCacheContext->ReadLock) = FALSE;
921 *(VariableCacheContext->HobFlushComplete) = FALSE;
922
923 Status = EFI_SUCCESS;
924 break;
925 case SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE:
926 Status = FlushPendingRuntimeVariableCacheUpdates ();
927 break;
928 case SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO:
929 if (CommBufferPayloadSize < sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO)) {
930 DEBUG ((DEBUG_ERROR, "GetRuntimeCacheInfo: SMM communication buffer size invalid!\n"));
931 return EFI_SUCCESS;
932 }
933 GetRuntimeCacheInfo = (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *) SmmVariableFunctionHeader->Data;
934
935 if (mVariableModuleGlobal->VariableGlobal.HobVariableBase > 0) {
936 VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;
937 GetRuntimeCacheInfo->TotalHobStorageSize = VariableCache->Size;
938 } else {
939 GetRuntimeCacheInfo->TotalHobStorageSize = 0;
940 }
941
942 VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
943 GetRuntimeCacheInfo->TotalVolatileStorageSize = VariableCache->Size;
944 VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) mNvVariableCache;
945 GetRuntimeCacheInfo->TotalNvStorageSize = (UINTN) VariableCache->Size;
946 GetRuntimeCacheInfo->AuthenticatedVariableUsage = mVariableModuleGlobal->VariableGlobal.AuthFormat;
947
948 Status = EFI_SUCCESS;
949 break;
950
951 default:
952 Status = EFI_UNSUPPORTED;
953 }
954
955 EXIT:
956
957 SmmVariableFunctionHeader->ReturnStatus = Status;
958
959 return EFI_SUCCESS;
960 }
961
962 /**
963 SMM END_OF_DXE protocol notification event handler.
964
965 @param Protocol Points to the protocol's unique identifier
966 @param Interface Points to the interface instance
967 @param Handle The handle on which the interface was installed
968
969 @retval EFI_SUCCESS SmmEndOfDxeCallback runs successfully
970
971 **/
972 EFI_STATUS
973 EFIAPI
974 SmmEndOfDxeCallback (
975 IN CONST EFI_GUID *Protocol,
976 IN VOID *Interface,
977 IN EFI_HANDLE Handle
978 )
979 {
980 EFI_STATUS Status;
981
982 DEBUG ((DEBUG_INFO, "[Variable]SMM_END_OF_DXE is signaled\n"));
983 MorLockInitAtEndOfDxe ();
984 Status = LockVariablePolicy ();
985 ASSERT_EFI_ERROR (Status);
986 mEndOfDxe = TRUE;
987 VarCheckLibInitializeAtEndOfDxe (NULL);
988 //
989 // The initialization for variable quota.
990 //
991 InitializeVariableQuota ();
992 if (PcdGetBool (PcdReclaimVariableSpaceAtEndOfDxe)) {
993 ReclaimForOS ();
994 }
995
996 return EFI_SUCCESS;
997 }
998
999 /**
1000 Initializes variable write service for SMM.
1001
1002 **/
1003 VOID
1004 VariableWriteServiceInitializeSmm (
1005 VOID
1006 )
1007 {
1008 EFI_STATUS Status;
1009
1010 Status = VariableWriteServiceInitialize ();
1011 if (EFI_ERROR (Status)) {
1012 DEBUG ((DEBUG_ERROR, "Variable write service initialization failed. Status = %r\n", Status));
1013 }
1014
1015 //
1016 // Notify the variable wrapper driver the variable write service is ready
1017 //
1018 VariableNotifySmmWriteReady ();
1019 }
1020
1021 /**
1022 SMM Fault Tolerant Write protocol notification event handler.
1023
1024 Non-Volatile variable write may needs FTW protocol to reclaim when
1025 writting variable.
1026
1027 @param Protocol Points to the protocol's unique identifier
1028 @param Interface Points to the interface instance
1029 @param Handle The handle on which the interface was installed
1030
1031 @retval EFI_SUCCESS SmmEventCallback runs successfully
1032 @retval EFI_NOT_FOUND The Fvb protocol for variable is not found.
1033
1034 **/
1035 EFI_STATUS
1036 EFIAPI
1037 SmmFtwNotificationEvent (
1038 IN CONST EFI_GUID *Protocol,
1039 IN VOID *Interface,
1040 IN EFI_HANDLE Handle
1041 )
1042 {
1043 EFI_STATUS Status;
1044 EFI_PHYSICAL_ADDRESS VariableStoreBase;
1045 EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol;
1046 EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol;
1047 EFI_PHYSICAL_ADDRESS NvStorageVariableBase;
1048 UINTN FtwMaxBlockSize;
1049
1050 if (mVariableModuleGlobal->FvbInstance != NULL) {
1051 return EFI_SUCCESS;
1052 }
1053
1054 //
1055 // Ensure SMM FTW protocol is installed.
1056 //
1057 Status = GetFtwProtocol ((VOID **)&FtwProtocol);
1058 if (EFI_ERROR (Status)) {
1059 return Status;
1060 }
1061
1062 Status = FtwProtocol->GetMaxBlockSize (FtwProtocol, &FtwMaxBlockSize);
1063 if (!EFI_ERROR (Status)) {
1064 ASSERT (PcdGet32 (PcdFlashNvStorageVariableSize) <= FtwMaxBlockSize);
1065 }
1066
1067 NvStorageVariableBase = NV_STORAGE_VARIABLE_BASE;
1068 VariableStoreBase = NvStorageVariableBase + mNvFvHeaderCache->HeaderLength;
1069
1070 //
1071 // Let NonVolatileVariableBase point to flash variable store base directly after FTW ready.
1072 //
1073 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;
1074
1075 //
1076 // Find the proper FVB protocol for variable.
1077 //
1078 Status = GetFvbInfoByAddress (NvStorageVariableBase, NULL, &FvbProtocol);
1079 if (EFI_ERROR (Status)) {
1080 return EFI_NOT_FOUND;
1081 }
1082
1083 mVariableModuleGlobal->FvbInstance = FvbProtocol;
1084
1085 //
1086 // Initializes variable write service after FTW was ready.
1087 //
1088 VariableWriteServiceInitializeSmm ();
1089
1090 return EFI_SUCCESS;
1091 }
1092
1093
1094 /**
1095 Variable Driver main entry point. The Variable driver places the 4 EFI
1096 runtime services in the EFI System Table and installs arch protocols
1097 for variable read and write services being available. It also registers
1098 a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
1099
1100 @retval EFI_SUCCESS Variable service successfully initialized.
1101
1102 **/
1103 EFI_STATUS
1104 EFIAPI
1105 MmVariableServiceInitialize (
1106 VOID
1107 )
1108 {
1109 EFI_STATUS Status;
1110 EFI_HANDLE VariableHandle;
1111 VOID *SmmFtwRegistration;
1112 VOID *SmmEndOfDxeRegistration;
1113
1114 //
1115 // Variable initialize.
1116 //
1117 Status = VariableCommonInitialize ();
1118 ASSERT_EFI_ERROR (Status);
1119
1120 //
1121 // Install the Smm Variable Protocol on a new handle.
1122 //
1123 VariableHandle = NULL;
1124 Status = gMmst->MmInstallProtocolInterface (
1125 &VariableHandle,
1126 &gEfiSmmVariableProtocolGuid,
1127 EFI_NATIVE_INTERFACE,
1128 &gSmmVariable
1129 );
1130 ASSERT_EFI_ERROR (Status);
1131
1132 Status = gMmst->MmInstallProtocolInterface (
1133 &VariableHandle,
1134 &gEdkiiSmmVarCheckProtocolGuid,
1135 EFI_NATIVE_INTERFACE,
1136 &mSmmVarCheck
1137 );
1138 ASSERT_EFI_ERROR (Status);
1139
1140 mVariableBufferPayloadSize = GetMaxVariableSize () +
1141 OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) -
1142 GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat);
1143
1144 Status = gMmst->MmAllocatePool (
1145 EfiRuntimeServicesData,
1146 mVariableBufferPayloadSize,
1147 (VOID **)&mVariableBufferPayload
1148 );
1149 ASSERT_EFI_ERROR (Status);
1150
1151 ///
1152 /// Register SMM variable SMI handler
1153 ///
1154 VariableHandle = NULL;
1155 Status = gMmst->MmiHandlerRegister (SmmVariableHandler, &gEfiSmmVariableProtocolGuid, &VariableHandle);
1156 ASSERT_EFI_ERROR (Status);
1157
1158 //
1159 // Notify the variable wrapper driver the variable service is ready
1160 //
1161 VariableNotifySmmReady ();
1162
1163 //
1164 // Register EFI_SMM_END_OF_DXE_PROTOCOL_GUID notify function.
1165 //
1166 Status = gMmst->MmRegisterProtocolNotify (
1167 &gEfiMmEndOfDxeProtocolGuid,
1168 SmmEndOfDxeCallback,
1169 &SmmEndOfDxeRegistration
1170 );
1171 ASSERT_EFI_ERROR (Status);
1172
1173 if (!PcdGetBool (PcdEmuVariableNvModeEnable)) {
1174 //
1175 // Register FtwNotificationEvent () notify function.
1176 //
1177 Status = gMmst->MmRegisterProtocolNotify (
1178 &gEfiSmmFaultTolerantWriteProtocolGuid,
1179 SmmFtwNotificationEvent,
1180 &SmmFtwRegistration
1181 );
1182 ASSERT_EFI_ERROR (Status);
1183
1184 SmmFtwNotificationEvent (NULL, NULL, NULL);
1185 } else {
1186 //
1187 // Emulated non-volatile variable mode does not depend on FVB and FTW.
1188 //
1189 VariableWriteServiceInitializeSmm ();
1190 }
1191
1192 return EFI_SUCCESS;
1193 }