summaryrefslogtreecommitdiff
path: root/OvmfPkg
diff options
context:
space:
mode:
authorjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>2009-09-26 07:15:45 +0000
committerjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>2009-09-26 07:15:45 +0000
commit670d495b19abebaed3ffde1e9293eb270a68ca3c (patch)
tree14d8b4400fbce1a1bdb895f186eb41188419678e /OvmfPkg
parenta876ae6f2f6e7fb66edd5ba26a4e140b40172831 (diff)
downloadedk2-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')
-rw-r--r--OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.c873
-rw-r--r--OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.h140
-rw-r--r--OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf83
3 files changed, 1096 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;
+}
+
+
diff --git a/OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.h b/OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.h
new file mode 100644
index 0000000000..d4e0065202
--- /dev/null
+++ b/OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.h
@@ -0,0 +1,140 @@
+/*++
+
+Copyright (c) 2006, 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.
+
+Module Name:
+
+ FwBlockService.h
+
+Abstract:
+
+ Firmware volume block driver for Intel Firmware Hub (FWH) device
+
+--*/
+
+#ifndef _FW_BLOCK_SERVICE_H
+#define _FW_BLOCK_SERVICE_H
+
+//
+// Fvb Protocol instance data
+//
+#define FVB_DEVICE_FROM_THIS(a) CR (a, EFI_FW_VOL_BLOCK_DEVICE, FwVolBlockInstance, FVB_DEVICE_SIGNATURE)
+#define FVB_DEVICE_SIGNATURE SIGNATURE_32 ('F', 'V', 'B', 'N')
+
+#pragma pack (1)
+
+typedef struct {
+
+ EFI_FIRMWARE_VOLUME_HEADER FvHdr;
+ EFI_FV_BLOCK_MAP_ENTRY EndBlockMap;
+ VARIABLE_STORE_HEADER VarHdr;
+
+} FVB_FV_HDR_AND_VARS_TEMPLATE;
+
+typedef struct {
+ MEMMAP_DEVICE_PATH MemMapDevPath;
+ EFI_DEVICE_PATH_PROTOCOL EndDevPath;
+} FV_DEVICE_PATH;
+
+#pragma pack ()
+
+typedef struct {
+ UINTN Signature;
+ FV_DEVICE_PATH DevicePath;
+ VOID *BufferPtr;
+ UINTN BlockSize;
+ UINTN Size;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL FwVolBlockInstance;
+} EFI_FW_VOL_BLOCK_DEVICE;
+
+
+//
+// Constants
+//
+#define EMU_FVB_BLOCK_SIZE (FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize))
+#define EMU_FVB_SIZE (2 * FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize))
+#define FTW_WRITE_QUEUE_SIZE \
+ (FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) - \
+ sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER))
+#define EMU_FV_HEADER_LENGTH OFFSET_OF (FVB_FV_HDR_AND_VARS_TEMPLATE, VarHdr)
+
+#define NOT_ERASED_BIT 0
+#define ERASED_BIT 1
+#define ERASED_UINT8 0xff
+#define ERASED_UINT32 0xffffffff
+
+//
+// Protocol APIs
+//
+EFI_STATUS
+EFIAPI
+FvbProtocolGetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ )
+;
+
+EFI_STATUS
+EFIAPI
+FvbProtocolSetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ )
+;
+
+EFI_STATUS
+EFIAPI
+FvbProtocolGetPhysicalAddress (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ OUT EFI_PHYSICAL_ADDRESS *Address
+ )
+;
+
+EFI_STATUS
+EFIAPI
+FvbProtocolGetBlockSize (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ OUT UINTN *BlockSize,
+ OUT UINTN *NumberOfBlocks
+ )
+;
+
+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_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_STATUS
+EFIAPI
+FvbProtocolEraseBlocks (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ ...
+ )
+;
+
+#endif
diff --git a/OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf b/OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf
new file mode 100644
index 0000000000..c015116e8c
--- /dev/null
+++ b/OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf
@@ -0,0 +1,83 @@
+#/** @file
+# Firmware Block Services to support emulating non-volatile variables
+# by pretending that a memory buffer is storage for the NV variables.
+#
+# Copyright (c) 2008 - 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.
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = EmuVariableFvbRuntimeDxe
+ FILE_GUID = 22dc2b60-fe40-42ac-b01f-3ab1fad9aad8
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ EDK_RELEASE_VERSION = 0x00020000
+ EFI_SPECIFICATION_VERSION = 0x00020000
+
+ ENTRY_POINT = FvbInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+ Fvb.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ DxeServicesTableLib
+ HobLib
+ MemoryAllocationLib
+ PcdLib
+ PlatformFvbLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+ UefiRuntimeLib
+
+
+[Guids]
+ gEfiEventVirtualAddressChangeGuid # ALWAYS_CONSUMED Create Event: EVENT_GROUP_GUID
+
+
+[Protocols]
+ gEfiFirmwareVolumeBlockProtocolGuid # PROTOCOL ALWAYS_PRODUCED
+ gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_PRODUCED
+
+
+[FixedPcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
+
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase
+ gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved
+
+
+[Depex]
+ TRUE
+