From 670d495b19abebaed3ffde1e9293eb270a68ca3c Mon Sep 17 00:00:00 2001 From: jljusten Date: Sat, 26 Sep 2009 07:15:45 +0000 Subject: [PATCH] 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 --- OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.c | 873 +++++++++++++++++++++++ OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.h | 140 ++++ OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf | 83 +++ 3 files changed, 1096 insertions(+) create mode 100644 OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.c create mode 100644 OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.h create mode 100644 OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf 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 +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 +