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