2 Firmware Block Services to support emulating non-volatile variables
3 by pretending that a memory buffer is storage for the NV variables.
5 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include <Guid/EventGroup.h>
18 #include <Guid/SystemNvDataGuid.h>
19 #include <Guid/VariableFormat.h>
21 #include <Protocol/FirmwareVolumeBlock.h>
22 #include <Protocol/DevicePath.h>
24 #include <Library/UefiLib.h>
25 #include <Library/UefiDriverEntryPoint.h>
26 #include <Library/BaseLib.h>
27 #include <Library/UefiRuntimeLib.h>
28 #include <Library/DebugLib.h>
29 #include <Library/BaseMemoryLib.h>
30 #include <Library/MemoryAllocationLib.h>
31 #include <Library/UefiBootServicesTableLib.h>
32 #include <Library/DevicePathLib.h>
33 #include <Library/PcdLib.h>
34 #include <Library/PlatformFvbLib.h>
38 // Virtual Address Change Event
40 // This is needed for runtime variable access.
42 EFI_EVENT mEmuVarsFvbAddrChangeEvent
= NULL
;
45 // This is the single instance supported by this driver. It
46 // supports the FVB and Device Path protocols.
48 EFI_FW_VOL_BLOCK_DEVICE mEmuVarsFvb
= {
56 sizeof (MEMMAP_DEVICE_PATH
),
66 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
68 sizeof (EFI_DEVICE_PATH_PROTOCOL
),
74 FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize
), // BlockSize
75 2 * FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize
), // Size
76 { // FwVolBlockInstance
77 FvbProtocolGetAttributes
,
78 FvbProtocolSetAttributes
,
79 FvbProtocolGetPhysicalAddress
,
80 FvbProtocolGetBlockSize
,
83 FvbProtocolEraseBlocks
,
90 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
92 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
93 It converts pointer to new virtual address.
95 @param Event Event whose notification function is being invoked.
96 @param Context Pointer to the notification function's context.
101 FvbVirtualAddressChangeEvent (
106 EfiConvertPointer (0x0, &mEmuVarsFvb
.BufferPtr
);
115 The GetPhysicalAddress() function retrieves the base address of
116 a memory-mapped firmware volume. This function should be called
117 only for memory-mapped firmware volumes.
119 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
121 @param Address Pointer to a caller-allocated
122 EFI_PHYSICAL_ADDRESS that, on successful
123 return from GetPhysicalAddress(), contains the
124 base address of the firmware volume.
126 @retval EFI_SUCCESS The firmware volume base address is returned.
128 @retval EFI_NOT_SUPPORTED The firmware volume is not memory mapped.
133 FvbProtocolGetPhysicalAddress (
134 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
*This
,
135 OUT EFI_PHYSICAL_ADDRESS
*Address
138 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
140 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
142 *Address
= (EFI_PHYSICAL_ADDRESS
)(UINTN
) FvbDevice
->BufferPtr
;
149 The GetBlockSize() function retrieves the size of the requested
150 block. It also returns the number of additional blocks with
151 the identical size. The GetBlockSize() function is used to
152 retrieve the block map (see EFI_FIRMWARE_VOLUME_HEADER).
155 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
157 @param Lba Indicates the block for which to return the size.
159 @param BlockSize Pointer to a caller-allocated UINTN in which
160 the size of the block is returned.
162 @param NumberOfBlocks Pointer to a caller-allocated UINTN in
163 which the number of consecutive blocks,
164 starting with Lba, is returned. All
165 blocks in this range have a size of
169 @retval EFI_SUCCESS The firmware volume base address is returned.
171 @retval EFI_INVALID_PARAMETER The requested LBA is out of range.
176 FvbProtocolGetBlockSize (
177 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
*This
,
179 OUT UINTN
*BlockSize
,
180 OUT UINTN
*NumberOfBlocks
183 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
186 return EFI_INVALID_PARAMETER
;
189 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
191 *BlockSize
= FvbDevice
->BlockSize
;
192 *NumberOfBlocks
= (UINTN
) (2 - (UINTN
) Lba
);
199 The GetAttributes() function retrieves the attributes and
200 current settings of the block. Status Codes Returned
202 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
204 @param Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the
205 attributes and current settings are
206 returned. Type EFI_FVB_ATTRIBUTES_2 is defined
207 in EFI_FIRMWARE_VOLUME_HEADER.
209 @retval EFI_SUCCESS The firmware volume attributes were
215 FvbProtocolGetAttributes (
216 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
*This
,
217 OUT EFI_FVB_ATTRIBUTES_2
*Attributes
221 (EFI_FVB_ATTRIBUTES_2
) (
222 EFI_FVB2_READ_ENABLED_CAP
|
223 EFI_FVB2_READ_STATUS
|
224 EFI_FVB2_WRITE_ENABLED_CAP
|
225 EFI_FVB2_WRITE_STATUS
|
226 EFI_FVB2_ERASE_POLARITY
234 The SetAttributes() function sets configurable firmware volume
235 attributes and returns the new settings of the firmware volume.
237 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
239 @param Attributes On input, Attributes is a pointer to
240 EFI_FVB_ATTRIBUTES_2 that contains the
241 desired firmware volume settings. On
242 successful return, it contains the new
243 settings of the firmware volume. Type
244 EFI_FVB_ATTRIBUTES_2 is defined in
245 EFI_FIRMWARE_VOLUME_HEADER.
247 @retval EFI_SUCCESS The firmware volume attributes were returned.
249 @retval EFI_INVALID_PARAMETER The attributes requested are in
250 conflict with the capabilities
251 as declared in the firmware
257 FvbProtocolSetAttributes (
258 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
*This
,
259 IN OUT EFI_FVB_ATTRIBUTES_2
*Attributes
262 return EFI_ACCESS_DENIED
;
267 Erases and initializes a firmware volume block.
269 The EraseBlocks() function erases one or more blocks as denoted
270 by the variable argument list. The entire parameter list of
271 blocks must be verified before erasing any blocks. If a block is
272 requested that does not exist within the associated firmware
273 volume (it has a larger index than the last block of the
274 firmware volume), the EraseBlocks() function must return the
275 status code EFI_INVALID_PARAMETER without modifying the contents
276 of the firmware volume. Implementations should be mindful that
277 the firmware volume might be in the WriteDisabled state. If it
278 is in this state, the EraseBlocks() function must return the
279 status code EFI_ACCESS_DENIED without modifying the contents of
280 the firmware volume. All calls to EraseBlocks() must be fully
281 flushed to the hardware before the EraseBlocks() service
284 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
287 @param ... The variable argument list is a list of tuples.
288 Each tuple describes a range of LBAs to erase
289 and consists of the following:
290 - An EFI_LBA that indicates the starting LBA
291 - A UINTN that indicates the number of blocks to
294 The list is terminated with an
295 EFI_LBA_LIST_TERMINATOR. For example, the
296 following indicates that two ranges of blocks
297 (5-7 and 10-11) are to be erased: EraseBlocks
298 (This, 5, 3, 10, 2, EFI_LBA_LIST_TERMINATOR);
300 @retval EFI_SUCCESS The erase request was successfully
303 @retval EFI_ACCESS_DENIED The firmware volume is in the
305 @retval EFI_DEVICE_ERROR The block device is not functioning
306 correctly and could not be written.
307 The firmware device may have been
309 @retval EFI_INVALID_PARAMETER One or more of the LBAs listed
310 in the variable argument list do
311 not exist in the firmware volume.
316 FvbProtocolEraseBlocks (
317 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
*This
,
321 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
329 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
332 VA_START (args
, This
);
335 StartingLba
= VA_ARG (args
, EFI_LBA
);
336 if (StartingLba
== EFI_LBA_LIST_TERMINATOR
) {
340 NumOfLba
= VA_ARG (args
, UINT32
);
343 // Check input parameters
345 if ((NumOfLba
== 0) || (StartingLba
> 1) || ((StartingLba
+ NumOfLba
) > 2)) {
347 return EFI_INVALID_PARAMETER
;
350 if (StartingLba
== 0) {
351 Erase
= (UINT8
) (Erase
| BIT0
);
353 if ((StartingLba
+ NumOfLba
) == 2) {
354 Erase
= (UINT8
) (Erase
| BIT1
);
361 ErasePtr
= (UINT8
*) FvbDevice
->BufferPtr
;
364 if ((Erase
& BIT0
) != 0) {
365 EraseSize
= EraseSize
+ FvbDevice
->BlockSize
;
367 ErasePtr
= (VOID
*) ((UINT8
*)ErasePtr
+ FvbDevice
->BlockSize
);
370 if ((Erase
& BIT1
) != 0) {
371 EraseSize
= EraseSize
+ FvbDevice
->BlockSize
;
374 if (EraseSize
!= 0) {
380 VA_START (args
, This
);
381 PlatformFvbBlocksErased (This
, args
);
389 Writes the specified number of bytes from the input buffer to the block.
391 The Write() function writes the specified number of bytes from
392 the provided buffer to the specified block and offset. If the
393 firmware volume is sticky write, the caller must ensure that
394 all the bits of the specified range to write are in the
395 EFI_FVB_ERASE_POLARITY state before calling the Write()
396 function, or else the result will be unpredictable. This
397 unpredictability arises because, for a sticky-write firmware
398 volume, a write may negate a bit in the EFI_FVB_ERASE_POLARITY
399 state but cannot flip it back again. In general, before
400 calling the Write() function, the caller should call the
401 EraseBlocks() function first to erase the specified block to
402 write. A block erase cycle will transition bits from the
403 (NOT)EFI_FVB_ERASE_POLARITY state back to the
404 EFI_FVB_ERASE_POLARITY state. Implementations should be
405 mindful that the firmware volume might be in the WriteDisabled
406 state. If it is in this state, the Write() function must
407 return the status code EFI_ACCESS_DENIED without modifying the
408 contents of the firmware volume. The Write() function must
409 also prevent spanning block boundaries. If a write is
410 requested that spans a block boundary, the write must store up
411 to the boundary but not beyond. The output parameter NumBytes
412 must be set to correctly indicate the number of bytes actually
413 written. The caller must be aware that a write may be
414 partially completed. All writes, partial or otherwise, must be
415 fully flushed to the hardware before the Write() service
418 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
420 @param Lba The starting logical block index to write to.
422 @param Offset Offset into the block at which to begin writing.
424 @param NumBytes Pointer to a UINTN. At entry, *NumBytes
425 contains the total size of the buffer. At
426 exit, *NumBytes contains the total number of
427 bytes actually written.
429 @param Buffer Pointer to a caller-allocated buffer that
430 contains the source for the write.
432 @retval EFI_SUCCESS The firmware volume was written successfully.
434 @retval EFI_BAD_BUFFER_SIZE The write was attempted across an
435 LBA boundary. On output, NumBytes
436 contains the total number of bytes
439 @retval EFI_ACCESS_DENIED The firmware volume is in the
442 @retval EFI_DEVICE_ERROR The block device is malfunctioning
443 and could not be written.
450 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
*This
,
453 IN OUT UINTN
*NumBytes
,
458 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
461 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
463 if ((Lba
> 1) || (Offset
> FvbDevice
->BlockSize
)) {
464 return EFI_INVALID_PARAMETER
;
467 if ((Offset
+ *NumBytes
) > FvbDevice
->BlockSize
) {
468 *NumBytes
= FvbDevice
->BlockSize
- Offset
;
472 (UINT8
*) FvbDevice
->BufferPtr
+
473 MultU64x32 (Lba
, (UINT32
) FvbDevice
->BlockSize
) +
477 CopyMem (FvbDataPtr
, Buffer
, *NumBytes
);
478 PlatformFvbDataWritten (This
, Lba
, Offset
, *NumBytes
, Buffer
);
486 Reads the specified number of bytes into a buffer from the specified block.
488 The Read() function reads the requested number of bytes from the
489 requested block and stores them in the provided buffer.
490 Implementations should be mindful that the firmware volume
491 might be in the ReadDisabled state. If it is in this state,
492 the Read() function must return the status code
493 EFI_ACCESS_DENIED without modifying the contents of the
494 buffer. The Read() function must also prevent spanning block
495 boundaries. If a read is requested that would span a block
496 boundary, the read must read up to the boundary but not
497 beyond. The output parameter NumBytes must be set to correctly
498 indicate the number of bytes actually read. The caller must be
499 aware that a read may be partially completed.
501 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
503 @param Lba The starting logical block index
506 @param Offset Offset into the block at which to begin reading.
508 @param NumBytes Pointer to a UINTN. At entry, *NumBytes
509 contains the total size of the buffer. At
510 exit, *NumBytes contains the total number of
513 @param Buffer Pointer to a caller-allocated buffer that will
514 be used to hold the data that is read.
516 @retval EFI_SUCCESS The firmware volume was read successfully
517 and contents are in Buffer.
519 @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA
520 boundary. On output, NumBytes
521 contains the total number of bytes
524 @retval EFI_ACCESS_DENIED The firmware volume is in the
527 @retval EFI_DEVICE_ERROR The block device is not
528 functioning correctly and could
535 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
*This
,
538 IN OUT UINTN
*NumBytes
,
542 EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
;
545 FvbDevice
= FVB_DEVICE_FROM_THIS (This
);
547 if ((Lba
> 1) || (Offset
> FvbDevice
->BlockSize
)) {
548 return EFI_INVALID_PARAMETER
;
551 if ((Offset
+ *NumBytes
) > FvbDevice
->BlockSize
) {
552 *NumBytes
= FvbDevice
->BlockSize
- Offset
;
556 (UINT8
*) FvbDevice
->BufferPtr
+
557 MultU64x32 (Lba
, (UINT32
) FvbDevice
->BlockSize
) +
561 CopyMem (Buffer
, FvbDataPtr
, *NumBytes
);
562 PlatformFvbDataRead (This
, Lba
, Offset
, *NumBytes
, Buffer
);
570 Check the integrity of firmware volume header.
572 @param[in] FwVolHeader - A pointer to a firmware volume header
574 @retval EFI_SUCCESS - The firmware volume is consistent
575 @retval EFI_NOT_FOUND - The firmware volume has been corrupted.
580 IN EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
586 // Verify the header revision, header signature, length
587 // Length of FvBlock cannot be 2**64-1
588 // HeaderLength cannot be an odd number
590 if ((FwVolHeader
->Revision
!= EFI_FVH_REVISION
) ||
591 (FwVolHeader
->Signature
!= EFI_FVH_SIGNATURE
) ||
592 (FwVolHeader
->FvLength
!= EMU_FVB_SIZE
) ||
593 (FwVolHeader
->HeaderLength
!= EMU_FV_HEADER_LENGTH
)
595 DEBUG ((EFI_D_INFO
, "EMU Variable FVB: Basic FV headers were invalid\n"));
596 return EFI_NOT_FOUND
;
599 // Verify the header checksum
601 Checksum
= CalculateSum16((VOID
*) FwVolHeader
, FwVolHeader
->HeaderLength
);
604 DEBUG ((EFI_D_INFO
, "EMU Variable FVB: FV checksum was invalid\n"));
605 return EFI_NOT_FOUND
;
613 Initializes the FV Header and Variable Store Header
614 to support variable operations.
616 @param[in] Ptr - Location to initialize the headers
620 InitializeFvAndVariableStoreHeaders (
624 STATIC FVB_FV_HDR_AND_VARS_TEMPLATE FvAndVarTemplate
= {
625 { // EFI_FIRMWARE_VOLUME_HEADER FvHdr;
626 // UINT8 ZeroVector[16];
627 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
629 // EFI_GUID FileSystemGuid;
630 EFI_SYSTEM_NV_DATA_FV_GUID
,
638 // EFI_FVB_ATTRIBUTES_2 Attributes;
641 // UINT16 HeaderLength;
642 EMU_FV_HEADER_LENGTH
,
647 // UINT16 ExtHeaderOffset;
650 // UINT8 Reserved[1];
656 // EFI_FV_BLOCK_MAP_ENTRY BlockMap[1];
657 { 2, // UINT32 NumBlocks;
658 EMU_FVB_BLOCK_SIZE
// UINT32 Length;
661 // EFI_FV_BLOCK_MAP_ENTRY EndBlockMap;
662 { 0, 0 }, // End of block map
663 { // VARIABLE_STORE_HEADER VarHdr;
664 // EFI_GUID Signature;
669 FixedPcdGet32 (PcdVariableStoreSize
) -
670 OFFSET_OF (FVB_FV_HDR_AND_VARS_TEMPLATE
, VarHdr
)
674 VARIABLE_STORE_FORMATTED
,
677 VARIABLE_STORE_HEALTHY
,
686 EFI_FIRMWARE_VOLUME_HEADER
*Fv
;
689 // Copy the template structure into the location
691 CopyMem (Ptr
, (VOID
*)&FvAndVarTemplate
, sizeof (FvAndVarTemplate
));
694 // Update the checksum for the FV header
696 Fv
= (EFI_FIRMWARE_VOLUME_HEADER
*) Ptr
;
697 Fv
->Checksum
= CalculateCheckSum16 (Ptr
, Fv
->HeaderLength
);
702 Initializes the Fault Tolerant Write data structure
704 This data structure is used by the Fault Tolerant Write driver.
706 @param[in] Buffer - Location for the FTW data structure
714 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*Hdr
;
716 STATIC EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER DefaultFtw
= {
717 EFI_SYSTEM_NV_DATA_FV_GUID
, // EFI_GUID Signature;
718 ERASED_UINT32
, // UINT32 Crc;
719 ERASED_BIT
, // UINT8 WorkingBlockValid : 1;
720 ERASED_BIT
, // UINT8 WorkingBlockInvalid : 1;
721 0, // UINT8 Reserved : 6;
722 { 0, 0, 0 }, // UINT8 Reserved3[3];
723 FTW_WRITE_QUEUE_SIZE
// UINT64 WriteQueueSize;
726 CopyMem (Buffer
, (VOID
*) &DefaultFtw
, sizeof (DefaultFtw
));
728 Hdr
= (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
*) Buffer
;
731 // Calculate checksum.
733 // The Crc, WorkingBlockValid and WorkingBlockInvalid bits should
734 // be set to the erased state before computing the checksum.
736 gBS
->CalculateCrc32 (Buffer
, sizeof (DefaultFtw
), &TempCrc
);
742 Hdr
->WorkingBlockValid
= NOT_ERASED_BIT
;
749 @param[in] ImageHandle The firmware allocated handle for the EFI image.
750 @param[in] SystemTable A pointer to the EFI System Table.
752 @retval EFI_SUCCESS Successfully initialized.
758 IN EFI_HANDLE ImageHandle
,
759 IN EFI_SYSTEM_TABLE
*SystemTable
767 EFI_PHYSICAL_ADDRESS Address
;
769 DEBUG ((EFI_D_INFO
, "EMU Variable FVB Started\n"));
772 // Verify that the PCD's are set correctly.
775 (PcdGet32 (PcdVariableStoreSize
) +
776 PcdGet32 (PcdFlashNvStorageFtwWorkingSize
)
780 DEBUG ((EFI_D_ERROR
, "EMU Variable invalid PCD sizes\n"));
781 return EFI_INVALID_PARAMETER
;
785 // By default we will initialize the FV contents. But, if
786 // PcdEmuVariableNvStoreReserved is non-zero, then we will
787 // use this location for our buffer.
789 // If this location does not have a proper FV header, then
790 // we will initialize it.
793 if (PcdGet64 (PcdEmuVariableNvStoreReserved
) != 0) {
794 Ptr
= (VOID
*)(UINTN
) PcdGet64 (PcdEmuVariableNvStoreReserved
);
797 "EMU Variable FVB: Using pre-reserved block at %p\n",
800 Status
= ValidateFvHeader (Ptr
);
801 if (!EFI_ERROR (Status
)) {
802 DEBUG ((EFI_D_INFO
, "EMU Variable FVB: Found valid pre-existing FV\n"));
806 Ptr
= AllocateAlignedRuntimePages (
807 EFI_SIZE_TO_PAGES (EMU_FVB_SIZE
),
812 mEmuVarsFvb
.BufferPtr
= Ptr
;
815 // Initialize the main FV header and variable store header
818 SetMem (Ptr
, EMU_FVB_SIZE
, ERASED_UINT8
);
819 InitializeFvAndVariableStoreHeaders (Ptr
);
821 PcdSet64 (PcdFlashNvStorageVariableBase64
, (UINT32
)(UINTN
) Ptr
);
824 // Initialize the Fault Tolerant Write data area
826 SubPtr
= (VOID
*) ((UINT8
*) Ptr
+ PcdGet32 (PcdVariableStoreSize
));
828 InitializeFtwState (SubPtr
);
830 PcdSet32 (PcdFlashNvStorageFtwWorkingBase
, (UINT32
)(UINTN
) SubPtr
);
833 // Initialize the Fault Tolerant Write spare block
835 SubPtr
= (VOID
*) ((UINT8
*) Ptr
+ EMU_FVB_BLOCK_SIZE
);
836 PcdSet32 (PcdFlashNvStorageFtwSpareBase
, (UINT32
)(UINTN
) SubPtr
);
839 // Setup FVB device path
841 Address
= (EFI_PHYSICAL_ADDRESS
)(UINTN
) Ptr
;
842 mEmuVarsFvb
.DevicePath
.MemMapDevPath
.StartingAddress
= Address
;
843 mEmuVarsFvb
.DevicePath
.MemMapDevPath
.EndingAddress
= Address
+ EMU_FVB_SIZE
- 1;
846 // Install the protocols
848 DEBUG ((EFI_D_INFO
, "Installing FVB for EMU Variable support\n"));
850 Status
= gBS
->InstallMultipleProtocolInterfaces (
852 &gEfiFirmwareVolumeBlock2ProtocolGuid
,
853 &mEmuVarsFvb
.FwVolBlockInstance
,
854 &gEfiDevicePathProtocolGuid
,
855 &mEmuVarsFvb
.DevicePath
,
858 ASSERT_EFI_ERROR (Status
);
861 // Register for the virtual address change event
863 Status
= gBS
->CreateEventEx (
866 FvbVirtualAddressChangeEvent
,
868 &gEfiEventVirtualAddressChangeGuid
,
869 &mEmuVarsFvbAddrChangeEvent
871 ASSERT_EFI_ERROR (Status
);