diff options
author | jljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524> | 2009-09-26 07:15:45 +0000 |
---|---|---|
committer | jljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524> | 2009-09-26 07:15:45 +0000 |
commit | 670d495b19abebaed3ffde1e9293eb270a68ca3c (patch) | |
tree | 14d8b4400fbce1a1bdb895f186eb41188419678e /OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.c | |
parent | a876ae6f2f6e7fb66edd5ba26a4e140b40172831 (diff) | |
download | edk2-platforms-670d495b19abebaed3ffde1e9293eb270a68ca3c.tar.xz |
Add EmuVariableFvbRuntimeDxe driver.
This driver implements a firmware volume block protocol instance
which is stored in system memory.
The MdeModulePkg/Universal/Variable/RuntimeDxe and
MdeModulePkg/Universal/FaultTolerantWriteDxe drivers make use of
this FVB instance to provide variable services.
This driver links to a PlatformFvb library to allow for
platform specific processing to take place when data is written
to the FVB.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@9315 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.c')
-rw-r--r-- | OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.c | 873 |
1 files changed, 873 insertions, 0 deletions
diff --git a/OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.c b/OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.c new file mode 100644 index 0000000000..48d0555abc --- /dev/null +++ b/OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.c @@ -0,0 +1,873 @@ +/** @file
+ Firmware Block Services to support emulating non-volatile variables
+ by pretending that a memory buffer is storage for the NV variables.
+
+ Copyright (c) 2006 - 2009, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PiDxe.h"
+#include <Guid/EventGroup.h>
+#include <Guid/SystemNvDataGuid.h>
+#include <Guid/VariableFormat.h>
+
+#include <Protocol/FirmwareVolumeBlock.h>
+#include <Protocol/DevicePath.h>
+
+#include <Library/UefiLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PlatformFvbLib.h>
+#include "Fvb.h"
+
+//
+// Virtual Address Change Event
+//
+// This is needed for runtime variable access.
+//
+EFI_EVENT mEmuVarsFvbAddrChangeEvent = NULL;
+
+//
+// This is the single instance supported by this driver. It
+// supports the FVB and Device Path protocols.
+//
+EFI_FW_VOL_BLOCK_DEVICE mEmuVarsFvb = {
+ FVB_DEVICE_SIGNATURE,
+ { // DevicePath
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_MEMMAP_DP,
+ {
+ sizeof (MEMMAP_DEVICE_PATH),
+ 0
+ }
+ },
+ EfiMemoryMappedIO,
+ 0,
+ 0,
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ sizeof (EFI_DEVICE_PATH_PROTOCOL),
+ 0
+ }
+ }
+ },
+ NULL, // BufferPtr
+ FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize), // BlockSize
+ 2 * FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize), // Size
+ { // FwVolBlockInstance
+ FvbProtocolGetAttributes,
+ FvbProtocolSetAttributes,
+ FvbProtocolGetPhysicalAddress,
+ FvbProtocolGetBlockSize,
+ FvbProtocolRead,
+ FvbProtocolWrite,
+ FvbProtocolEraseBlocks,
+ NULL
+ },
+};
+
+
+/**
+ Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
+
+ This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
+ It converts pointer to new virtual address.
+
+ @param Event Event whose notification function is being invoked.
+ @param Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+FvbVirtualAddressChangeEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EfiConvertPointer (0x0, &mEmuVarsFvb.BufferPtr);
+}
+
+
+//
+// FVB protocol APIs
+//
+
+/**
+ The GetPhysicalAddress() function retrieves the base address of
+ a memory-mapped firmware volume. This function should be called
+ only for memory-mapped firmware volumes.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL instance.
+
+ @param Address Pointer to a caller-allocated
+ EFI_PHYSICAL_ADDRESS that, on successful
+ return from GetPhysicalAddress(), contains the
+ base address of the firmware volume.
+
+ @retval EFI_SUCCESS The firmware volume base address is returned.
+
+ @retval EFI_NOT_SUPPORTED The firmware volume is not memory mapped.
+
+**/
+EFI_STATUS
+EFIAPI
+FvbProtocolGetPhysicalAddress (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ OUT EFI_PHYSICAL_ADDRESS *Address
+ )
+{
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
+
+ FvbDevice = FVB_DEVICE_FROM_THIS (This);
+
+ *Address = (EFI_PHYSICAL_ADDRESS)(UINTN) FvbDevice->BufferPtr;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ The GetBlockSize() function retrieves the size of the requested
+ block. It also returns the number of additional blocks with
+ the identical size. The GetBlockSize() function is used to
+ retrieve the block map (see EFI_FIRMWARE_VOLUME_HEADER).
+
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL instance.
+
+ @param Lba Indicates the block for which to return the size.
+
+ @param BlockSize Pointer to a caller-allocated UINTN in which
+ the size of the block is returned.
+
+ @param NumberOfBlocks Pointer to a caller-allocated UINTN in
+ which the number of consecutive blocks,
+ starting with Lba, is returned. All
+ blocks in this range have a size of
+ BlockSize.
+
+
+ @retval EFI_SUCCESS The firmware volume base address is returned.
+
+ @retval EFI_INVALID_PARAMETER The requested LBA is out of range.
+
+**/
+EFI_STATUS
+EFIAPI
+FvbProtocolGetBlockSize (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ OUT UINTN *BlockSize,
+ OUT UINTN *NumberOfBlocks
+ )
+{
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
+
+ if (Lba > 1) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FvbDevice = FVB_DEVICE_FROM_THIS (This);
+
+ *BlockSize = FvbDevice->BlockSize;
+ *NumberOfBlocks = 2 - Lba;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ The GetAttributes() function retrieves the attributes and
+ current settings of the block. Status Codes Returned
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL instance.
+
+ @param Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the
+ attributes and current settings are
+ returned. Type EFI_FVB_ATTRIBUTES_2 is defined
+ in EFI_FIRMWARE_VOLUME_HEADER.
+
+ @retval EFI_SUCCESS The firmware volume attributes were
+ returned.
+
+**/
+EFI_STATUS
+EFIAPI
+FvbProtocolGetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ )
+{
+ *Attributes =
+ (EFI_FVB_ATTRIBUTES_2) (
+ EFI_FVB2_READ_ENABLED_CAP |
+ EFI_FVB2_READ_STATUS |
+ EFI_FVB2_WRITE_ENABLED_CAP |
+ EFI_FVB2_WRITE_STATUS |
+ EFI_FVB2_ERASE_POLARITY
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ The SetAttributes() function sets configurable firmware volume
+ attributes and returns the new settings of the firmware volume.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL instance.
+
+ @param Attributes On input, Attributes is a pointer to
+ EFI_FVB_ATTRIBUTES_2 that contains the
+ desired firmware volume settings. On
+ successful return, it contains the new
+ settings of the firmware volume. Type
+ EFI_FVB_ATTRIBUTES_2 is defined in
+ EFI_FIRMWARE_VOLUME_HEADER.
+
+ @retval EFI_SUCCESS The firmware volume attributes were returned.
+
+ @retval EFI_INVALID_PARAMETER The attributes requested are in
+ conflict with the capabilities
+ as declared in the firmware
+ volume header.
+
+**/
+EFI_STATUS
+EFIAPI
+FvbProtocolSetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ )
+{
+ return EFI_ACCESS_DENIED;
+}
+
+
+/**
+ Erases and initializes a firmware volume block.
+
+ The EraseBlocks() function erases one or more blocks as denoted
+ by the variable argument list. The entire parameter list of
+ blocks must be verified before erasing any blocks. If a block is
+ requested that does not exist within the associated firmware
+ volume (it has a larger index than the last block of the
+ firmware volume), the EraseBlocks() function must return the
+ status code EFI_INVALID_PARAMETER without modifying the contents
+ of the firmware volume. Implementations should be mindful that
+ the firmware volume might be in the WriteDisabled state. If it
+ is in this state, the EraseBlocks() function must return the
+ status code EFI_ACCESS_DENIED without modifying the contents of
+ the firmware volume. All calls to EraseBlocks() must be fully
+ flushed to the hardware before the EraseBlocks() service
+ returns.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
+ instance.
+
+ @param ... The variable argument list is a list of tuples.
+ Each tuple describes a range of LBAs to erase
+ and consists of the following:
+ - An EFI_LBA that indicates the starting LBA
+ - A UINTN that indicates the number of blocks to
+ erase
+
+ The list is terminated with an
+ EFI_LBA_LIST_TERMINATOR. For example, the
+ following indicates that two ranges of blocks
+ (5-7 and 10-11) are to be erased: EraseBlocks
+ (This, 5, 3, 10, 2, EFI_LBA_LIST_TERMINATOR);
+
+ @retval EFI_SUCCESS The erase request was successfully
+ completed.
+
+ @retval EFI_ACCESS_DENIED The firmware volume is in the
+ WriteDisabled state.
+ @retval EFI_DEVICE_ERROR The block device is not functioning
+ correctly and could not be written.
+ The firmware device may have been
+ partially erased.
+ @retval EFI_INVALID_PARAMETER One or more of the LBAs listed
+ in the variable argument list do
+ not exist in the firmware volume.
+
+**/
+EFI_STATUS
+EFIAPI
+FvbProtocolEraseBlocks (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ ...
+ )
+{
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
+ VA_LIST args;
+ EFI_LBA StartingLba;
+ UINTN NumOfLba;
+ UINT8 Erase;
+ VOID *ErasePtr;
+ UINTN EraseSize;
+
+ FvbDevice = FVB_DEVICE_FROM_THIS (This);
+ Erase = 0;
+
+ VA_START (args, This);
+
+ do {
+ StartingLba = VA_ARG (args, EFI_LBA);
+ if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
+ break;
+ }
+
+ NumOfLba = VA_ARG (args, UINT32);
+
+ //
+ // Check input parameters
+ //
+ if ((NumOfLba == 0) || (StartingLba > 1) || ((StartingLba + NumOfLba) > 2)) {
+ VA_END (args);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (StartingLba == 0) {
+ Erase = (UINT8) (Erase | BIT0);
+ }
+ if ((StartingLba + NumOfLba) == 2) {
+ Erase = (UINT8) (Erase | BIT1);
+ }
+
+ } while (1);
+
+ VA_END (args);
+
+ ErasePtr = (UINT8*) FvbDevice->BufferPtr;
+ EraseSize = 0;
+
+ if ((Erase & BIT0) != 0) {
+ EraseSize = EraseSize + FvbDevice->BlockSize;
+ } else {
+ ErasePtr = ErasePtr + FvbDevice->BlockSize;
+ }
+
+ if ((Erase & BIT1) != 0) {
+ EraseSize = EraseSize + FvbDevice->BlockSize;
+ }
+
+ if (EraseSize != 0) {
+ SetMem (
+ (VOID*) ErasePtr,
+ EraseSize,
+ ERASED_UINT8
+ );
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Writes the specified number of bytes from the input buffer to the block.
+
+ The Write() function writes the specified number of bytes from
+ the provided buffer to the specified block and offset. If the
+ firmware volume is sticky write, the caller must ensure that
+ all the bits of the specified range to write are in the
+ EFI_FVB_ERASE_POLARITY state before calling the Write()
+ function, or else the result will be unpredictable. This
+ unpredictability arises because, for a sticky-write firmware
+ volume, a write may negate a bit in the EFI_FVB_ERASE_POLARITY
+ state but cannot flip it back again. In general, before
+ calling the Write() function, the caller should call the
+ EraseBlocks() function first to erase the specified block to
+ write. A block erase cycle will transition bits from the
+ (NOT)EFI_FVB_ERASE_POLARITY state back to the
+ EFI_FVB_ERASE_POLARITY state. Implementations should be
+ mindful that the firmware volume might be in the WriteDisabled
+ state. If it is in this state, the Write() function must
+ return the status code EFI_ACCESS_DENIED without modifying the
+ contents of the firmware volume. The Write() function must
+ also prevent spanning block boundaries. If a write is
+ requested that spans a block boundary, the write must store up
+ to the boundary but not beyond. The output parameter NumBytes
+ must be set to correctly indicate the number of bytes actually
+ written. The caller must be aware that a write may be
+ partially completed. All writes, partial or otherwise, must be
+ fully flushed to the hardware before the Write() service
+ returns.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL instance.
+
+ @param Lba The starting logical block index to write to.
+
+ @param Offset Offset into the block at which to begin writing.
+
+ @param NumBytes Pointer to a UINTN. At entry, *NumBytes
+ contains the total size of the buffer. At
+ exit, *NumBytes contains the total number of
+ bytes actually written.
+
+ @param Buffer Pointer to a caller-allocated buffer that
+ contains the source for the write.
+
+ @retval EFI_SUCCESS The firmware volume was written successfully.
+
+ @retval EFI_BAD_BUFFER_SIZE The write was attempted across an
+ LBA boundary. On output, NumBytes
+ contains the total number of bytes
+ actually written.
+
+ @retval EFI_ACCESS_DENIED The firmware volume is in the
+ WriteDisabled state.
+
+ @retval EFI_DEVICE_ERROR The block device is malfunctioning
+ and could not be written.
+
+
+**/
+EFI_STATUS
+EFIAPI
+FvbProtocolWrite (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN UINT8 *Buffer
+ )
+{
+
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
+ UINT8 *FvbDataPtr;
+
+ FvbDevice = FVB_DEVICE_FROM_THIS (This);
+
+ if ((Lba > 1) || (Offset > FvbDevice->BlockSize)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Offset + *NumBytes) > FvbDevice->BlockSize) {
+ *NumBytes = FvbDevice->BlockSize - Offset;
+ }
+
+ FvbDataPtr =
+ (UINT8*) FvbDevice->BufferPtr +
+ MultU64x32 (Lba, FvbDevice->BlockSize) +
+ Offset;
+
+ if (*NumBytes > 0) {
+ CopyMem (FvbDataPtr, Buffer, *NumBytes);
+ PlatformFvbDataWritten (This, Lba);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Reads the specified number of bytes into a buffer from the specified block.
+
+ The Read() function reads the requested number of bytes from the
+ requested block and stores them in the provided buffer.
+ Implementations should be mindful that the firmware volume
+ might be in the ReadDisabled state. If it is in this state,
+ the Read() function must return the status code
+ EFI_ACCESS_DENIED without modifying the contents of the
+ buffer. The Read() function must also prevent spanning block
+ boundaries. If a read is requested that would span a block
+ boundary, the read must read up to the boundary but not
+ beyond. The output parameter NumBytes must be set to correctly
+ indicate the number of bytes actually read. The caller must be
+ aware that a read may be partially completed.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL instance.
+
+ @param Lba The starting logical block index
+ from which to read.
+
+ @param Offset Offset into the block at which to begin reading.
+
+ @param NumBytes Pointer to a UINTN. At entry, *NumBytes
+ contains the total size of the buffer. At
+ exit, *NumBytes contains the total number of
+ bytes read.
+
+ @param Buffer Pointer to a caller-allocated buffer that will
+ be used to hold the data that is read.
+
+ @retval EFI_SUCCESS The firmware volume was read successfully
+ and contents are in Buffer.
+
+ @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA
+ boundary. On output, NumBytes
+ contains the total number of bytes
+ returned in Buffer.
+
+ @retval EFI_ACCESS_DENIED The firmware volume is in the
+ ReadDisabled state.
+
+ @retval EFI_DEVICE_ERROR The block device is not
+ functioning correctly and could
+ not be read.
+
+**/
+EFI_STATUS
+EFIAPI
+FvbProtocolRead (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN OUT UINT8 *Buffer
+ )
+{
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
+ UINT8 *FvbDataPtr;
+
+ FvbDevice = FVB_DEVICE_FROM_THIS (This);
+
+ if ((Lba > 1) || (Offset > FvbDevice->BlockSize)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Offset + *NumBytes) > FvbDevice->BlockSize) {
+ *NumBytes = FvbDevice->BlockSize - Offset;
+ }
+
+ FvbDataPtr =
+ (UINT8*) FvbDevice->BufferPtr +
+ MultU64x32 (Lba, FvbDevice->BlockSize) +
+ Offset;
+
+ if (*NumBytes > 0) {
+ CopyMem (Buffer, FvbDataPtr, *NumBytes);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Check the integrity of firmware volume header.
+
+ @param[in] FwVolHeader - A pointer to a firmware volume header
+
+ @retval EFI_SUCCESS - The firmware volume is consistent
+ @retval EFI_NOT_FOUND - The firmware volume has been corrupted.
+
+**/
+EFI_STATUS
+ValidateFvHeader (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader
+ )
+{
+ UINT16 Checksum;
+
+ //
+ // Verify the header revision, header signature, length
+ // Length of FvBlock cannot be 2**64-1
+ // HeaderLength cannot be an odd number
+ //
+ if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||
+ (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||
+ (FwVolHeader->FvLength != EMU_FVB_SIZE) ||
+ (FwVolHeader->HeaderLength != EMU_FV_HEADER_LENGTH)
+ ) {
+ DEBUG ((EFI_D_INFO, "EMU Variable FVB: Basic FV headers were invalid\n"));
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Verify the header checksum
+ //
+ Checksum = CalculateSum16((VOID*) FwVolHeader, FwVolHeader->HeaderLength);
+
+ if (Checksum != 0) {
+ DEBUG ((EFI_D_INFO, "EMU Variable FVB: FV checksum was invalid\n"));
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Initializes the FV Header and Variable Store Header
+ to support variable operations.
+
+ @param[in] Ptr - Location to initialize the headers
+
+**/
+VOID
+InitializeFvAndVariableStoreHeaders (
+ IN VOID *Ptr
+ )
+{
+ STATIC FVB_FV_HDR_AND_VARS_TEMPLATE FvAndVarTemplate = {
+ { // EFI_FIRMWARE_VOLUME_HEADER FvHdr;
+ // UINT8 ZeroVector[16];
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+
+ // EFI_GUID FileSystemGuid;
+ EFI_SYSTEM_NV_DATA_FV_GUID,
+
+ // UINT64 FvLength;
+ EMU_FVB_SIZE,
+
+ // UINT32 Signature;
+ EFI_FVH_SIGNATURE,
+
+ // EFI_FVB_ATTRIBUTES_2 Attributes;
+ 0x4feff,
+
+ // UINT16 HeaderLength;
+ EMU_FV_HEADER_LENGTH,
+
+ // UINT16 Checksum;
+ 0,
+
+ // UINT16 ExtHeaderOffset;
+ 0,
+
+ // UINT8 Reserved[1];
+ 0,
+
+ // UINT8 Revision;
+ EFI_FVH_REVISION,
+
+ // EFI_FV_BLOCK_MAP_ENTRY BlockMap[1];
+ { 2, // UINT32 NumBlocks;
+ EMU_FVB_BLOCK_SIZE // UINT32 Length;
+ }
+ },
+ // EFI_FV_BLOCK_MAP_ENTRY EndBlockMap;
+ { 0, 0 }, // End of block map
+ { // VARIABLE_STORE_HEADER VarHdr;
+ // EFI_GUID Signature;
+ EFI_VARIABLE_GUID,
+
+ // UINT32 Size;
+ (
+ FixedPcdGet32 (PcdVariableStoreSize) -
+ OFFSET_OF (FVB_FV_HDR_AND_VARS_TEMPLATE, VarHdr)
+ ),
+
+ // UINT8 Format;
+ VARIABLE_STORE_FORMATTED,
+
+ // UINT8 State;
+ VARIABLE_STORE_HEALTHY,
+
+ // UINT16 Reserved;
+ 0,
+
+ // UINT32 Reserved1;
+ 0
+ }
+ };
+ EFI_FIRMWARE_VOLUME_HEADER *Fv;
+
+ //
+ // Copy the template structure into the location
+ //
+ CopyMem (Ptr, (VOID*)&FvAndVarTemplate, sizeof (FvAndVarTemplate));
+
+ //
+ // Update the checksum for the FV header
+ //
+ Fv = (EFI_FIRMWARE_VOLUME_HEADER*) Ptr;
+ Fv->Checksum = CalculateCheckSum16 (Ptr, Fv->HeaderLength);
+}
+
+
+/**
+ Initializes the Fault Tolerant Write data structure
+
+ This data structure is used by the Fault Tolerant Write driver.
+
+ @param[in] Buffer - Location for the FTW data structure
+
+**/
+VOID
+InitializeFtwState (
+ IN VOID *Buffer
+ )
+{
+ EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *Hdr;
+ UINT32 TempCrc;
+ STATIC EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER DefaultFtw = {
+ EFI_SYSTEM_NV_DATA_FV_GUID, // EFI_GUID Signature;
+ ERASED_UINT32, // UINT32 Crc;
+ ERASED_BIT, // UINT8 WorkingBlockValid : 1;
+ ERASED_BIT, // UINT8 WorkingBlockInvalid : 1;
+ 0, // UINT8 Reserved : 6;
+ { 0, 0, 0 }, // UINT8 Reserved3[3];
+ FTW_WRITE_QUEUE_SIZE // UINT64 WriteQueueSize;
+ };
+
+ CopyMem (Buffer, (VOID*) &DefaultFtw, sizeof (DefaultFtw));
+
+ Hdr = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER*) Buffer;
+
+ //
+ // Calculate checksum.
+ //
+ // The Crc, WorkingBlockValid and WorkingBlockInvalid bits should
+ // be set to the erased state before computing the checksum.
+ //
+ gBS->CalculateCrc32 (Buffer, sizeof (DefaultFtw), &TempCrc);
+ Hdr->Crc = TempCrc;
+
+ //
+ // Mark as valid.
+ //
+ Hdr->WorkingBlockValid = NOT_ERASED_BIT;
+}
+
+
+/**
+ Main entry point.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS Successfully initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+FvbInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ VOID *Ptr;
+ VOID *SubPtr;
+ BOOLEAN Initialize;
+ EFI_HANDLE Handle;
+ EFI_PHYSICAL_ADDRESS Address;
+
+ DEBUG ((EFI_D_INFO, "EMU Variable FVB Started\n"));
+
+ //
+ // Verify that the PCD's are set correctly.
+ //
+ if (
+ (FixedPcdGet32 (PcdVariableStoreSize) +
+ FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize)
+ ) >
+ EMU_FVB_BLOCK_SIZE
+ ) {
+ DEBUG ((EFI_D_ERROR, "EMU Variable invalid PCD sizes\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // By default we will initialize the FV contents. But, if
+ // PcdEmuVariableNvStoreReserved is non-zero, then we will
+ // use this location for our buffer.
+ //
+ // If this location does not have a proper FV header, then
+ // we will initialize it.
+ //
+ Initialize = TRUE;
+ if (PcdGet64 (PcdEmuVariableNvStoreReserved) != 0) {
+ Ptr = (VOID*)(UINTN) PcdGet64 (PcdEmuVariableNvStoreReserved);
+ DEBUG ((
+ EFI_D_INFO,
+ "EMU Variable FVB: Using pre-reserved block at %p\n",
+ Ptr
+ ));
+ Status = ValidateFvHeader (Ptr);
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "EMU Variable FVB: Found valid pre-existing FV\n"));
+ Initialize = FALSE;
+ }
+ } else {
+ Ptr = AllocateAlignedRuntimePages (
+ EFI_SIZE_TO_PAGES (EMU_FVB_SIZE),
+ SIZE_64KB
+ );
+ }
+
+ mEmuVarsFvb.BufferPtr = Ptr;
+
+ //
+ // Initialize the main FV header and variable store header
+ //
+ if (Initialize) {
+ SetMem (Ptr, EMU_FVB_SIZE, ERASED_UINT8);
+ InitializeFvAndVariableStoreHeaders (Ptr);
+ }
+ PcdSet32 (PcdFlashNvStorageVariableBase, (UINT32)(UINTN) Ptr);
+
+ //
+ // Initialize the Fault Tolerant Write data area
+ //
+ SubPtr = (VOID*) ((UINT8*) Ptr + FixedPcdGet32 (PcdVariableStoreSize));
+ if (Initialize) {
+ InitializeFtwState (SubPtr);
+ }
+ PcdSet32 (PcdFlashNvStorageFtwWorkingBase, (UINT32)(UINTN) SubPtr);
+
+ //
+ // Initialize the Fault Tolerant Write spare block
+ //
+ SubPtr = (VOID*) ((UINT8*) Ptr + EMU_FVB_BLOCK_SIZE);
+ PcdSet32 (PcdFlashNvStorageFtwSpareBase, (UINT32)(UINTN) SubPtr);
+
+ //
+ // Setup FVB device path
+ //
+ Address = (EFI_PHYSICAL_ADDRESS)(UINTN) Ptr;
+ mEmuVarsFvb.DevicePath.MemMapDevPath.StartingAddress = Address;
+ mEmuVarsFvb.DevicePath.MemMapDevPath.EndingAddress = Address + EMU_FVB_SIZE - 1;
+
+ //
+ // Install the protocols
+ //
+ DEBUG ((EFI_D_INFO, "Installing FVB for EMU Variable support\n"));
+ Handle = 0;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ &mEmuVarsFvb.FwVolBlockInstance,
+ &gEfiDevicePathProtocolGuid,
+ &mEmuVarsFvb.DevicePath,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register for the virtual address change event
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ FvbVirtualAddressChangeEvent,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &mEmuVarsFvbAddrChangeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+
|