mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-11-04 02:40:26 +00:00 
			
		
		
		
	https://bugzilla.tianocore.org/show_bug.cgi?id=1373 Replace BSD 2-Clause License with BSD+Patent License. This change is based on the following emails: https://lists.01.org/pipermail/edk2-devel/2019-February/036260.html https://lists.01.org/pipermail/edk2-devel/2018-October/030385.html RFCs with detailed process for the license change: V3: https://lists.01.org/pipermail/edk2-devel/2019-March/038116.html V2: https://lists.01.org/pipermail/edk2-devel/2019-March/037669.html V1: https://lists.01.org/pipermail/edk2-devel/2019-March/037500.html Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Laszlo Ersek <lersek@redhat.com>
		
			
				
	
	
		
			838 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			838 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @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 - 2013, Intel Corporation. All rights reserved.<BR>
 | 
						|
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#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"
 | 
						|
 | 
						|
#define EFI_AUTHENTICATED_VARIABLE_GUID \
 | 
						|
{ 0xaaf32c78, 0x947b, 0x439a, { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 } }
 | 
						|
 | 
						|
//
 | 
						|
// 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
 | 
						|
  EMU_FVB_BLOCK_SIZE, // BlockSize
 | 
						|
  EMU_FVB_SIZE, // 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_BLOCK2_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_BLOCK2_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_BLOCK2_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_BLOCK2_PROTOCOL *This,
 | 
						|
  IN        EFI_LBA                             Lba,
 | 
						|
  OUT       UINTN                               *BlockSize,
 | 
						|
  OUT       UINTN                               *NumberOfBlocks
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
 | 
						|
 | 
						|
  if (Lba >= EMU_FVB_NUM_TOTAL_BLOCKS) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  FvbDevice = FVB_DEVICE_FROM_THIS (This);
 | 
						|
 | 
						|
  *BlockSize = FvbDevice->BlockSize;
 | 
						|
  *NumberOfBlocks = (UINTN)(EMU_FVB_NUM_TOTAL_BLOCKS - 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_BLOCK2_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_BLOCK2_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_BLOCK2_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_BLOCK2_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_BLOCK2_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_BLOCK2_PROTOCOL *This,
 | 
						|
  ...
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
 | 
						|
  VA_LIST                 Args;
 | 
						|
  EFI_LBA                 StartingLba;
 | 
						|
  UINTN                   NumOfLba;
 | 
						|
  UINT8                   *ErasePtr;
 | 
						|
  UINTN                   EraseSize;
 | 
						|
 | 
						|
  FvbDevice = FVB_DEVICE_FROM_THIS (This);
 | 
						|
 | 
						|
  //
 | 
						|
  // Check input parameters
 | 
						|
  //
 | 
						|
  VA_START (Args, This);
 | 
						|
  do {
 | 
						|
    StartingLba = VA_ARG (Args, EFI_LBA);
 | 
						|
    if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    NumOfLba = VA_ARG (Args, UINTN);
 | 
						|
 | 
						|
    if (StartingLba > EMU_FVB_NUM_TOTAL_BLOCKS ||
 | 
						|
        NumOfLba > EMU_FVB_NUM_TOTAL_BLOCKS - StartingLba) {
 | 
						|
      VA_END (Args);
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
  } while (1);
 | 
						|
  VA_END (Args);
 | 
						|
 | 
						|
  //
 | 
						|
  // Erase blocks
 | 
						|
  //
 | 
						|
  VA_START (Args, This);
 | 
						|
  do {
 | 
						|
    StartingLba = VA_ARG (Args, EFI_LBA);
 | 
						|
    if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    NumOfLba = VA_ARG (Args, UINTN);
 | 
						|
 | 
						|
    ErasePtr = FvbDevice->BufferPtr;
 | 
						|
    ErasePtr += (UINTN)StartingLba * FvbDevice->BlockSize;
 | 
						|
    EraseSize = NumOfLba * FvbDevice->BlockSize;
 | 
						|
 | 
						|
    SetMem (ErasePtr, EraseSize, ERASED_UINT8);
 | 
						|
  } while (1);
 | 
						|
  VA_END (Args);
 | 
						|
 | 
						|
  //
 | 
						|
  // Call platform hook
 | 
						|
  //
 | 
						|
  VA_START (Args, This);
 | 
						|
  PlatformFvbBlocksErased (This, Args);
 | 
						|
  VA_END (Args);
 | 
						|
 | 
						|
  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_BLOCK2_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_BLOCK2_PROTOCOL *This,
 | 
						|
  IN        EFI_LBA                             Lba,
 | 
						|
  IN        UINTN                               Offset,
 | 
						|
  IN OUT    UINTN                               *NumBytes,
 | 
						|
  IN        UINT8                               *Buffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
 | 
						|
  UINT8                   *FvbDataPtr;
 | 
						|
  EFI_STATUS              Status;
 | 
						|
 | 
						|
  FvbDevice = FVB_DEVICE_FROM_THIS (This);
 | 
						|
 | 
						|
  if (Lba >= EMU_FVB_NUM_TOTAL_BLOCKS ||
 | 
						|
      Offset > FvbDevice->BlockSize) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
  if (*NumBytes > FvbDevice->BlockSize - Offset) {
 | 
						|
    *NumBytes = FvbDevice->BlockSize - Offset;
 | 
						|
    Status = EFI_BAD_BUFFER_SIZE;
 | 
						|
  }
 | 
						|
 | 
						|
  FvbDataPtr = FvbDevice->BufferPtr;
 | 
						|
  FvbDataPtr += (UINTN)Lba * FvbDevice->BlockSize;
 | 
						|
  FvbDataPtr += Offset;
 | 
						|
 | 
						|
  CopyMem (FvbDataPtr, Buffer, *NumBytes);
 | 
						|
  PlatformFvbDataWritten (This, Lba, Offset, *NumBytes, Buffer);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  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_BLOCK2_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_BLOCK2_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;
 | 
						|
  EFI_STATUS              Status;
 | 
						|
 | 
						|
  FvbDevice = FVB_DEVICE_FROM_THIS (This);
 | 
						|
 | 
						|
  if (Lba >= EMU_FVB_NUM_TOTAL_BLOCKS ||
 | 
						|
      Offset > FvbDevice->BlockSize) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
  if (*NumBytes > FvbDevice->BlockSize - Offset) {
 | 
						|
    *NumBytes = FvbDevice->BlockSize - Offset;
 | 
						|
    Status = EFI_BAD_BUFFER_SIZE;
 | 
						|
  }
 | 
						|
 | 
						|
  FvbDataPtr = FvbDevice->BufferPtr;
 | 
						|
  FvbDataPtr += (UINTN)Lba * FvbDevice->BlockSize;
 | 
						|
  FvbDataPtr += Offset;
 | 
						|
 | 
						|
  CopyMem (Buffer, FvbDataPtr, *NumBytes);
 | 
						|
  PlatformFvbDataRead (This, Lba, Offset, *NumBytes, Buffer);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  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
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // Templates for authenticated variable FV header
 | 
						|
  //
 | 
						|
  STATIC FVB_FV_HDR_AND_VARS_TEMPLATE FvAndAuthenticatedVarTemplate = {
 | 
						|
    { // 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];
 | 
						|
      {
 | 
						|
        {
 | 
						|
          EMU_FVB_NUM_TOTAL_BLOCKS, // 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;     // need authenticated variables for secure boot
 | 
						|
        EFI_AUTHENTICATED_VARIABLE_GUID,
 | 
						|
 | 
						|
      // UINT32  Size;
 | 
						|
      (
 | 
						|
        FixedPcdGet32 (PcdFlashNvStorageVariableSize) -
 | 
						|
        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,
 | 
						|
    &FvAndAuthenticatedVarTemplate,
 | 
						|
    sizeof FvAndAuthenticatedVarTemplate
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  // Update the checksum for the FV header
 | 
						|
  //
 | 
						|
  Fv = (EFI_FIRMWARE_VOLUME_HEADER*) Ptr;
 | 
						|
  Fv->Checksum = CalculateCheckSum16 (Ptr, Fv->HeaderLength);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  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;
 | 
						|
  RETURN_STATUS                       PcdStatus;
 | 
						|
 | 
						|
  DEBUG ((EFI_D_INFO, "EMU Variable FVB Started\n"));
 | 
						|
 | 
						|
  //
 | 
						|
  // Verify that the PCD's are set correctly.
 | 
						|
  //
 | 
						|
  ASSERT (FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize) %
 | 
						|
          EMU_FVB_BLOCK_SIZE == 0);
 | 
						|
  if (
 | 
						|
       (PcdGet32 (PcdFlashNvStorageVariableSize) +
 | 
						|
        PcdGet32 (PcdFlashNvStorageFtwWorkingSize)
 | 
						|
       ) >
 | 
						|
       EMU_FVB_NUM_SPARE_BLOCKS * EMU_FVB_BLOCK_SIZE
 | 
						|
     ) {
 | 
						|
    DEBUG ((EFI_D_ERROR, "EMU Variable invalid PCD sizes\n"));
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0) {
 | 
						|
    DEBUG ((EFI_D_INFO, "Disabling EMU Variable FVB since "
 | 
						|
                        "flash variables appear to be supported.\n"));
 | 
						|
    return EFI_ABORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 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 = AllocateRuntimePages (EFI_SIZE_TO_PAGES (EMU_FVB_SIZE));
 | 
						|
  }
 | 
						|
 | 
						|
  mEmuVarsFvb.BufferPtr = Ptr;
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize the main FV header and variable store header
 | 
						|
  //
 | 
						|
  if (Initialize) {
 | 
						|
    SetMem (Ptr, EMU_FVB_SIZE, ERASED_UINT8);
 | 
						|
    InitializeFvAndVariableStoreHeaders (Ptr);
 | 
						|
  }
 | 
						|
  PcdStatus = PcdSet64S (PcdFlashNvStorageVariableBase64, (UINT32)(UINTN) Ptr);
 | 
						|
  ASSERT_RETURN_ERROR (PcdStatus);
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize the Fault Tolerant Write data area
 | 
						|
  //
 | 
						|
  SubPtr = (VOID*) ((UINT8*) Ptr + PcdGet32 (PcdFlashNvStorageVariableSize));
 | 
						|
  PcdStatus = PcdSet32S (PcdFlashNvStorageFtwWorkingBase,
 | 
						|
                (UINT32)(UINTN) SubPtr);
 | 
						|
  ASSERT_RETURN_ERROR (PcdStatus);
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize the Fault Tolerant Write spare block
 | 
						|
  //
 | 
						|
  SubPtr = (VOID*) ((UINT8*) Ptr +
 | 
						|
                    EMU_FVB_NUM_SPARE_BLOCKS * EMU_FVB_BLOCK_SIZE);
 | 
						|
  PcdStatus = PcdSet32S (PcdFlashNvStorageFtwSpareBase,
 | 
						|
                (UINT32)(UINTN) SubPtr);
 | 
						|
  ASSERT_RETURN_ERROR (PcdStatus);
 | 
						|
 | 
						|
  //
 | 
						|
  // 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,
 | 
						|
                  &gEfiFirmwareVolumeBlock2ProtocolGuid,
 | 
						|
                  &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;
 | 
						|
}
 | 
						|
 | 
						|
 |