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