From: "xianglai" <lixianglai@loongson.cn>
To: Ard Biesheuvel <ardb@kernel.org>
Cc: devel@edk2.groups.io, quic_llindhol@quicinc.com,
michael.d.kinney@intel.com, kraxel@redhat.com,
maobibo@loongson.cn
Subject: Re: [edk2-platforms][PATCH V3 15/16] Platform/Loongson: Add QemuFlashFvbServicesRuntimeDxe driver.
Date: Mon, 17 Oct 2022 20:56:48 +0800 [thread overview]
Message-ID: <374be025-b836-b6fc-9214-8064e21997d4@loongson.cn> (raw)
In-Reply-To: <CAMj1kXEeVM8wa3wz_obqtU4oHWU-sNnZrqrQjiqawRzzKFEZgw@mail.gmail.com>
Hi Ard Biesheuvel :
In the function FvbInitialize, It validate the firmware volume
header.The firmware volume header address is PcdOvmfFdBaseAddress,
in Ovmf PcdOvmfFdBaseAddress is equal to
PcdOvmfFlashNvStorageVariableBase, so the checksum can pass.
When loongson is implemented, PcdOvmfFdBaseAddress and
PcdOvmfFlashNvStorageVariableBase are not equal,
the firmware checksum will fail and enter the exception branch.
In the exception branch, due to the existence of reserved space in the
layout of loongson's NORflash,
the exception branch will also fail to pass, which will eventually lead
to function call failure.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EFI_STATUS
EFIAPI
FvbInitialize (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
....
BaseAddress = (UINTN)PcdGet32 (PcdOvmfFdBaseAddress);
....
FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)BaseAddress;
Status = ValidateFvHeader (FwVolHeader);
if (EFI_ERROR (Status)) {
//
// Get FvbInfo
//
Status = GetFvbInfo (Length, &FwVolHeader);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "EFI_ERROR (GetFvbInfo (Length,
&FwVolHeader))\n"));
return EFI_WRITE_PROTECTED;
}
}
....
}
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
But I think the reserved space in NORflash is unnecessary,
maybe I can remove the reserved space in Norflash and go through the
exception branch to pass the firmware volume header checksum,
then I can just Using the flash library implementation in Ovmf.
I can try it like this.
Thanks
xianglai
On 2022/10/17 下午7:00, Ard Biesheuvel wrote:
> On Fri, 14 Oct 2022 at 06:01, xianglai li <lixianglai@loongson.cn> wrote:
>> This library provides flash read and write functionality
>> and supports writing variables to flash.
>>
>> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4054
>>
>> Signed-off-by: xianglai li <lixianglai@loongson.cn>
> Why do you need a new driver for this? We already have drivers to
> support QEMU's NOR flash emulation, and the NorFlashDxe driver is
> being migrated to OvmfPkg/ in a series that is on the list now for
> RISC-V
>
>> ---
>> .../QemuFlashFvbServicesRuntimeDxe/FvbInfo.c | 115 ++
>> .../FvbServicesRuntimeDxe.inf | 73 ++
>> .../FwBlockService.c | 1158 +++++++++++++++++
>> .../FwBlockService.h | 178 +++
>> .../FwBlockServiceDxe.c | 152 +++
>> .../QemuFlash.c | 251 ++++
>> .../QemuFlash.h | 86 ++
>> .../QemuFlashDxe.c | 21 +
>> .../Loongson/LoongArchQemuPkg/Loongson.dsc | 4 +-
>> 9 files changed, 2036 insertions(+), 2 deletions(-)
>> create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/FvbInfo.c
>> create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
>> create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c
>> create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/FwBlockService.h
>> create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c
>> create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c
>> create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/QemuFlash.h
>> create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/QemuFlashDxe.c
>>
>> diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/FvbInfo.c b/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/FvbInfo.c
>> new file mode 100644
>> index 0000000000..df772f72be
>> --- /dev/null
>> +++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/FvbInfo.c
>> @@ -0,0 +1,115 @@
>> +/** @file
>> + Defines data structure that is the volume header found.These data is intent
>> + to decouple FVB driver with FV header.
>> +
>> + Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
>> +
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +//
>> +// The package level header files this module uses
>> +//
>> +#include <Pi/PiFirmwareVolume.h>
>> +
>> +//
>> +// The protocols, PPI and GUID definitions for this module
>> +//
>> +#include <Guid/SystemNvDataGuid.h>
>> +//
>> +// The Library classes this module consumes
>> +//
>> +#include <Library/BaseLib.h>
>> +#include <Library/PcdLib.h>
>> +
>> +typedef struct {
>> + UINT64 FvLength;
>> + EFI_FIRMWARE_VOLUME_HEADER FvbInfo;
>> + //
>> + // EFI_FV_BLOCK_MAP_ENTRY ExtraBlockMap[n];//n=0
>> + //
>> + EFI_FV_BLOCK_MAP_ENTRY End[1];
>> +} EFI_FVB_MEDIA_INFO;
>> +
>> +EFI_FVB_MEDIA_INFO mPlatformFvbMediaInfo[] = {
>> + //
>> + // System NvStorage FVB
>> + //
>> + {
>> + FixedPcdGet32 (PcdAllVarSize),
>> + {
>> + {
>> + 0,
>> + }, // ZeroVector[16]
>> + EFI_SYSTEM_NV_DATA_FV_GUID,
>> + FixedPcdGet32 (PcdAllVarSize),
>> + EFI_FVH_SIGNATURE,
>> + EFI_FVB2_MEMORY_MAPPED |
>> + EFI_FVB2_READ_ENABLED_CAP |
>> + EFI_FVB2_READ_STATUS |
>> + EFI_FVB2_WRITE_ENABLED_CAP |
>> + EFI_FVB2_WRITE_STATUS |
>> + EFI_FVB2_ERASE_POLARITY |
>> + EFI_FVB2_ALIGNMENT_16,
>> + sizeof (EFI_FIRMWARE_VOLUME_HEADER) + sizeof (EFI_FV_BLOCK_MAP_ENTRY),
>> + 0, // CheckSum
>> + 0, // ExtHeaderOffset
>> + {
>> + 0,
>> + }, // Reserved[1]
>> + 2, // Revision
>> + {
>> + {
>> + (FixedPcdGet32 (PcdAllVarSize))/
>> + FixedPcdGet32 (PcdFlashBlockSize),
>> + FixedPcdGet32 (PcdFlashBlockSize),
>> + }
>> + } // BlockMap[1]
>> + },
>> + {
>> + {
>> + 0,
>> + 0
>> + }
>> + } // End[1]
>> + }
>> +};
>> +
>> +EFI_STATUS
>> +GetFvbInfo (
>> + IN UINT64 FvLength,
>> + OUT EFI_FIRMWARE_VOLUME_HEADER **FvbInfo
>> + )
>> +{
>> + STATIC BOOLEAN Checksummed = FALSE;
>> + UINTN Index;
>> +
>> + if (!Checksummed) {
>> + for (Index = 0;
>> + Index < sizeof (mPlatformFvbMediaInfo) / sizeof (EFI_FVB_MEDIA_INFO);
>> + Index += 1)
>> + {
>> + UINT16 Checksum;
>> + mPlatformFvbMediaInfo[Index].FvbInfo.Checksum = 0;
>> + Checksum = CalculateCheckSum16 (
>> + (UINT16 *)&mPlatformFvbMediaInfo[Index].FvbInfo,
>> + mPlatformFvbMediaInfo[Index].FvbInfo.HeaderLength
>> + );
>> + mPlatformFvbMediaInfo[Index].FvbInfo.Checksum = Checksum;
>> + }
>> + Checksummed = TRUE;
>> + }
>> +
>> + for (Index = 0;
>> + Index < sizeof (mPlatformFvbMediaInfo) / sizeof (EFI_FVB_MEDIA_INFO);
>> + Index += 1)
>> + {
>> + if (mPlatformFvbMediaInfo[Index].FvLength == FvLength) {
>> + *FvbInfo = &mPlatformFvbMediaInfo[Index].FvbInfo;
>> + return EFI_SUCCESS;
>> + }
>> + }
>> +
>> + return EFI_NOT_FOUND;
>> +}
>> diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf b/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
>> new file mode 100644
>> index 0000000000..4b0c42b075
>> --- /dev/null
>> +++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
>> @@ -0,0 +1,73 @@
>> +## @file
>> +# Component description file for Emu Fimware Volume Block DXE driver module.
>> +#
>> +# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
>> +#
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +#
>> +##
>> +
>> +
>> +[Defines]
>> + INF_VERSION = 0x00010005
>> + BASE_NAME = FvbServicesRuntimeDxe
>> + FILE_GUID = 733cbac2-b23f-4b92-bc8e-fb01ce5907b7
>> + MODULE_TYPE = DXE_RUNTIME_DRIVER
>> + VERSION_STRING = 1.0
>> + ENTRY_POINT = FvbInitialize
>> +
>> +#
>> +# The following information is for reference only and not required by the build
>> +# tools.
>> +#
>> +# VALID_ARCHITECTURES = IA32 X64
>> +#
>> +
>> +[Sources]
>> + FvbInfo.c
>> + FwBlockService.c
>> + FwBlockServiceDxe.c
>> + QemuFlash.c
>> + QemuFlashDxe.c
>> +
>> +[Packages]
>> + MdePkg/MdePkg.dec
>> + MdeModulePkg/MdeModulePkg.dec
>> + OvmfPkg/OvmfPkg.dec
>> + Platform/Loongson/LoongArchQemuPkg/Loongson.dec
>> +
>> +[LibraryClasses]
>> + BaseLib
>> + BaseMemoryLib
>> + DebugLib
>> + DevicePathLib
>> + DxeServicesTableLib
>> + MemoryAllocationLib
>> + PcdLib
>> + UefiBootServicesTableLib
>> + UefiDriverEntryPoint
>> + UefiRuntimeLib
>> +
>> +[Guids]
>> + gEfiEventVirtualAddressChangeGuid # ALWAYS_CONSUMED
>> + # gEfiEventVirtualAddressChangeGuid # Create Event: EVENT_GROUP_GUID
>> +
>> +[Protocols]
>> + gEfiFirmwareVolumeBlockProtocolGuid # PROTOCOL SOMETIMES_PRODUCED
>> + gEfiDevicePathProtocolGuid # PROTOCOL SOMETIMES_PRODUCED
>> +
>> +[FixedPcd]
>> + gLoongArchQemuPkgTokenSpaceGuid.PcdOvmfFlashNvStorageVariableBase
>> + gLoongArchQemuPkgTokenSpaceGuid.PcdOvmfFlashNvStorageFtwWorkingBase
>> + gLoongArchQemuPkgTokenSpaceGuid.PcdOvmfFlashNvStorageFtwSpareBase
>> + gLoongArchQemuPkgTokenSpaceGuid.PcdFlashFdBase
>> + gLoongArchQemuPkgTokenSpaceGuid.PcdAllVarSize
>> + gLoongArchQemuPkgTokenSpaceGuid.PcdFlashBlockSize
>> +[Pcd]
>> + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64
>> + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable
>> + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64
>> + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64
>> +
>> +[Depex]
>> + TRUE
>> diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c b/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c
>> new file mode 100644
>> index 0000000000..d44f2b460c
>> --- /dev/null
>> +++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c
>> @@ -0,0 +1,1158 @@
>> +/** @file
>> + Implementations for Firmware Volume Block protocol.
>> +
>> + Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
>> +
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +//
>> +// The protocols, PPI and GUID definitions for this module
>> +//
>> +#include <Protocol/DevicePath.h>
>> +#include <Protocol/FirmwareVolumeBlock.h>
>> +
>> +//
>> +// The Library classes this module consumes
>> +//
>> +#include <Library/BaseLib.h>
>> +#include <Library/BaseMemoryLib.h>
>> +#include <Library/DebugLib.h>
>> +#include <Library/DevicePathLib.h>
>> +#include <Library/DxeServicesTableLib.h>
>> +#include <Library/MemoryAllocationLib.h>
>> +#include <Library/UefiBootServicesTableLib.h>
>> +
>> +#include "FwBlockService.h"
>> +#include "QemuFlash.h"
>> +
>> +#define EFI_FVB2_STATUS \
>> + (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)
>> +
>> +ESAL_FWB_GLOBAL *mFvbModuleGlobal;
>> +
>> +FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate = {
>> + {
>> + {
>> + HARDWARE_DEVICE_PATH,
>> + HW_MEMMAP_DP,
>> + {
>> + (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),
>> + (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8)
>> + }
>> + },
>> + EfiMemoryMappedIO,
>> + (EFI_PHYSICAL_ADDRESS)0,
>> + (EFI_PHYSICAL_ADDRESS)0,
>> + },
>> + {
>> + END_DEVICE_PATH_TYPE,
>> + END_ENTIRE_DEVICE_PATH_SUBTYPE,
>> + {
>> + END_DEVICE_PATH_LENGTH,
>> + 0
>> + }
>> + }
>> +};
>> +
>> +FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate = {
>> + {
>> + {
>> + MEDIA_DEVICE_PATH,
>> + MEDIA_PIWG_FW_VOL_DP,
>> + {
>> + (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)),
>> + (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8)
>> + }
>> + },
>> + { 0 }
>> + },
>> + {
>> + END_DEVICE_PATH_TYPE,
>> + END_ENTIRE_DEVICE_PATH_SUBTYPE,
>> + {
>> + END_DEVICE_PATH_LENGTH,
>> + 0
>> + }
>> + }
>> +};
>> +
>> +EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = {
>> + FVB_DEVICE_SIGNATURE,
>> + NULL,
>> + 0,
>> + {
>> + FvbProtocolGetAttributes,
>> + FvbProtocolSetAttributes,
>> + FvbProtocolGetPhysicalAddress,
>> + FvbProtocolGetBlockSize,
>> + FvbProtocolRead,
>> + FvbProtocolWrite,
>> + FvbProtocolEraseBlocks,
>> + NULL
>> + }
>> +};
>> +
>> +
>> +EFI_STATUS
>> +GetFvbInstance (
>> + IN UINTN Instance,
>> + IN ESAL_FWB_GLOBAL *Global,
>> + OUT EFI_FW_VOL_INSTANCE **FwhInstance
>> + )
>> +/*++
>> +
>> + Routine Description:
>> + Retrieves the physical address of a memory mapped FV
>> +
>> + Arguments:
>> + Instance - The FV instance whose base address is going to be
>> + returned
>> + Global - Pointer to ESAL_FWB_GLOBAL that contains all
>> + instance data
>> + FwhInstance - The EFI_FW_VOL_INSTANCE firmware instance structure
>> +
>> + Returns:
>> + EFI_SUCCESS - Successfully returns
>> + EFI_INVALID_PARAMETER - Instance not found
>> +
>> +--*/
>> +{
>> + EFI_FW_VOL_INSTANCE *FwhRecord;
>> +
>> + *FwhInstance = NULL;
>> + if (Instance >= Global->NumFv) {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> + //
>> + // Find the right instance of the FVB private data
>> + //
>> + FwhRecord = Global->FvInstance;
>> + while (Instance > 0) {
>> + FwhRecord = (EFI_FW_VOL_INSTANCE *)
>> + (
>> + (UINTN)((UINT8 *)FwhRecord) + FwhRecord->VolumeHeader.HeaderLength +
>> + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
>> + );
>> + Instance--;
>> + }
>> +
>> + *FwhInstance = FwhRecord;
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +EFI_STATUS
>> +FvbGetPhysicalAddress (
>> + IN UINTN Instance,
>> + OUT EFI_PHYSICAL_ADDRESS *Address,
>> + IN ESAL_FWB_GLOBAL *Global
>> + )
>> +/*++
>> +
>> + Routine Description:
>> + Retrieves the physical address of a memory mapped FV
>> +
>> + Arguments:
>> + Instance - The FV instance whose base address is going to be
>> + returned
>> + Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
>> + that on successful return, contains the base
>> + address of the firmware volume.
>> + Global - Pointer to ESAL_FWB_GLOBAL that contains all
>> + instance data
>> +
>> + Returns:
>> + EFI_SUCCESS - Successfully returns
>> + EFI_INVALID_PARAMETER - Instance not found
>> +
>> +--*/
>> +{
>> + EFI_FW_VOL_INSTANCE *FwhInstance;
>> + EFI_STATUS Status;
>> +
>> + //
>> + // Find the right instance of the FVB private data
>> + //
>> + Status = GetFvbInstance (Instance, Global, &FwhInstance);
>> + ASSERT_EFI_ERROR (Status);
>> + *Address = FwhInstance->FvBase;
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +EFI_STATUS
>> +FvbGetVolumeAttributes (
>> + IN UINTN Instance,
>> + OUT EFI_FVB_ATTRIBUTES_2 *Attributes,
>> + IN ESAL_FWB_GLOBAL *Global
>> + )
>> +/*++
>> +
>> + Routine Description:
>> + Retrieves attributes, insures positive polarity of attribute bits, returns
>> + resulting attributes in output parameter
>> +
>> + Arguments:
>> + Instance - The FV instance whose attributes is going to be
>> + returned
>> + Attributes - Output buffer which contains attributes
>> + Global - Pointer to ESAL_FWB_GLOBAL that contains all
>> + instance data
>> +
>> + Returns:
>> + EFI_SUCCESS - Successfully returns
>> + EFI_INVALID_PARAMETER - Instance not found
>> +
>> +--*/
>> +{
>> + EFI_FW_VOL_INSTANCE *FwhInstance;
>> + EFI_STATUS Status;
>> +
>> + //
>> + // Find the right instance of the FVB private data
>> + //
>> + Status = GetFvbInstance (Instance, Global, &FwhInstance);
>> + ASSERT_EFI_ERROR (Status);
>> + *Attributes = FwhInstance->VolumeHeader.Attributes;
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +EFI_STATUS
>> +FvbGetLbaAddress (
>> + IN UINTN Instance,
>> + IN EFI_LBA Lba,
>> + OUT UINTN *LbaAddress,
>> + OUT UINTN *LbaLength,
>> + OUT UINTN *NumOfBlocks,
>> + IN ESAL_FWB_GLOBAL *Global
>> + )
>> +/*++
>> +
>> + Routine Description:
>> + Retrieves the starting address of an LBA in an FV
>> +
>> + Arguments:
>> + Instance - The FV instance which the Lba belongs to
>> + Lba - The logical block address
>> + LbaAddress - On output, contains the physical starting address
>> + of the Lba
>> + LbaLength - On output, contains the length of the block
>> + NumOfBlocks - A 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
>> + Global - Pointer to ESAL_FWB_GLOBAL that contains all
>> + instance data
>> +
>> + Returns:
>> + EFI_SUCCESS - Successfully returns
>> + EFI_INVALID_PARAMETER - Instance not found
>> +
>> +--*/
>> +{
>> + UINT32 NumBlocks;
>> + UINT32 BlockLength;
>> + UINTN Offset;
>> + EFI_LBA StartLba;
>> + EFI_LBA NextLba;
>> + EFI_FW_VOL_INSTANCE *FwhInstance;
>> + EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
>> + EFI_STATUS Status;
>> +
>> + //
>> + // Find the right instance of the FVB private data
>> + //
>> + Status = GetFvbInstance (Instance, Global, &FwhInstance);
>> + ASSERT_EFI_ERROR (Status);
>> +
>> + StartLba = 0;
>> + Offset = 0;
>> + BlockMap = &(FwhInstance->VolumeHeader.BlockMap[0]);
>> +
>> + //
>> + // Parse the blockmap of the FV to find which map entry the Lba belongs to
>> + //
>> + while (TRUE) {
>> + NumBlocks = BlockMap->NumBlocks;
>> + BlockLength = BlockMap->Length;
>> +
>> + if ((NumBlocks == 0) || (BlockLength == 0)) {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> +
>> + NextLba = StartLba + NumBlocks;
>> +
>> + //
>> + // The map entry found
>> + //
>> + if ((Lba >= StartLba) && (Lba < NextLba)) {
>> + Offset = Offset + (UINTN)MultU64x32 ((Lba - StartLba), BlockLength);
>> + if (LbaAddress != NULL) {
>> + *LbaAddress = FwhInstance->FvBase + Offset;
>> + }
>> +
>> + if (LbaLength != NULL) {
>> + *LbaLength = BlockLength;
>> + }
>> +
>> + if (NumOfBlocks != NULL) {
>> + *NumOfBlocks = (UINTN)(NextLba - Lba);
>> + }
>> +
>> + return EFI_SUCCESS;
>> + }
>> +
>> + StartLba = NextLba;
>> + Offset = Offset + NumBlocks * BlockLength;
>> + BlockMap++;
>> + }
>> +}
>> +
>> +EFI_STATUS
>> +FvbSetVolumeAttributes (
>> + IN UINTN Instance,
>> + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes,
>> + IN ESAL_FWB_GLOBAL *Global
>> + )
>> +/*++
>> +
>> + Routine Description:
>> + Modifies the current settings of the firmware volume according to the
>> + input parameter, and returns the new setting of the volume
>> +
>> + Arguments:
>> + Instance - The FV instance whose attributes is going to be
>> + modified
>> + Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
>> + containing the desired firmware volume settings.
>> + On successful return, it contains the new settings
>> + of the firmware volume
>> + Global - Pointer to ESAL_FWB_GLOBAL that contains all
>> + instance data
>> +
>> + Returns:
>> + EFI_SUCCESS - Successfully returns
>> + EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
>> + EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
>> + in conflict with the capabilities as declared in
>> + the firmware volume header
>> +
>> +--*/
>> +{
>> + EFI_FW_VOL_INSTANCE *FwhInstance;
>> + EFI_FVB_ATTRIBUTES_2 OldAttributes;
>> + EFI_FVB_ATTRIBUTES_2 *AttribPtr;
>> + UINT32 Capabilities;
>> + UINT32 OldStatus;
>> + UINT32 NewStatus;
>> + EFI_STATUS Status;
>> + EFI_FVB_ATTRIBUTES_2 UnchangedAttributes;
>> +
>> + //
>> + // Find the right instance of the FVB private data
>> + //
>> + Status = GetFvbInstance (Instance, Global, &FwhInstance);
>> + ASSERT_EFI_ERROR (Status);
>> +
>> + AttribPtr =
>> + (EFI_FVB_ATTRIBUTES_2 *)&(FwhInstance->VolumeHeader.Attributes);
>> + OldAttributes = *AttribPtr;
>> + Capabilities = OldAttributes & (EFI_FVB2_READ_DISABLED_CAP | \
>> + EFI_FVB2_READ_ENABLED_CAP | \
>> + EFI_FVB2_WRITE_DISABLED_CAP | \
>> + EFI_FVB2_WRITE_ENABLED_CAP | \
>> + EFI_FVB2_LOCK_CAP \
>> + );
>> + OldStatus = OldAttributes & EFI_FVB2_STATUS;
>> + NewStatus = *Attributes & EFI_FVB2_STATUS;
>> +
>> + UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP | \
>> + EFI_FVB2_READ_ENABLED_CAP | \
>> + EFI_FVB2_WRITE_DISABLED_CAP | \
>> + EFI_FVB2_WRITE_ENABLED_CAP | \
>> + EFI_FVB2_LOCK_CAP | \
>> + EFI_FVB2_STICKY_WRITE | \
>> + EFI_FVB2_MEMORY_MAPPED | \
>> + EFI_FVB2_ERASE_POLARITY | \
>> + EFI_FVB2_READ_LOCK_CAP | \
>> + EFI_FVB2_WRITE_LOCK_CAP | \
>> + EFI_FVB2_ALIGNMENT;
>> +
>> + //
>> + // Some attributes of FV is read only can *not* be set
>> + //
>> + if ((OldAttributes & UnchangedAttributes) ^
>> + (*Attributes & UnchangedAttributes))
>> + {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> + //
>> + // If firmware volume is locked, no status bit can be updated
>> + //
>> + if (OldAttributes & EFI_FVB2_LOCK_STATUS) {
>> + if (OldStatus ^ NewStatus) {
>> + return EFI_ACCESS_DENIED;
>> + }
>> + }
>> + //
>> + // Test read disable
>> + //
>> + if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
>> + if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> + }
>> + //
>> + // Test read enable
>> + //
>> + if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
>> + if (NewStatus & EFI_FVB2_READ_STATUS) {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> + }
>> + //
>> + // Test write disable
>> + //
>> + if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
>> + if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> + }
>> + //
>> + // Test write enable
>> + //
>> + if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
>> + if (NewStatus & EFI_FVB2_WRITE_STATUS) {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> + }
>> + //
>> + // Test lock
>> + //
>> + if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
>> + if (NewStatus & EFI_FVB2_LOCK_STATUS) {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> + }
>> +
>> + *AttribPtr = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
>> + *AttribPtr = (*AttribPtr) | NewStatus;
>> + *Attributes = *AttribPtr;
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +//
>> +// FVB protocol APIs
>> +//
>> +EFI_STATUS
>> +EFIAPI
>> +FvbProtocolGetPhysicalAddress (
>> + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
>> + OUT EFI_PHYSICAL_ADDRESS *Address
>> + )
>> +/*++
>> +
>> + Routine Description:
>> +
>> + Retrieves the physical address of the device.
>> +
>> + Arguments:
>> +
>> + This - Calling context
>> + Address - Output buffer containing the address.
>> +
>> + Returns:
>> + EFI_SUCCESS - Successfully returns
>> +
>> +--*/
>> +{
>> + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
>> +
>> + FvbDevice = FVB_DEVICE_FROM_THIS (This);
>> +
>> + return FvbGetPhysicalAddress (
>> + FvbDevice->Instance,
>> + Address,
>> + mFvbModuleGlobal
>> + );
>> +}
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +FvbProtocolGetBlockSize (
>> + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
>> + IN CONST EFI_LBA Lba,
>> + OUT UINTN *BlockSize,
>> + OUT UINTN *NumOfBlocks
>> + )
>> +/*++
>> +
>> + Routine Description:
>> + Retrieve the size of a logical block
>> +
>> + Arguments:
>> + This - Calling context
>> + Lba - Indicates which block to return the size for.
>> + BlockSize - A pointer to a caller allocated UINTN in which
>> + the size of the block is returned
>> + NumOfBlocks - a 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
>> +
>> + Returns:
>> + EFI_SUCCESS - The firmware volume was read successfully and
>> + contents are in Buffer
>> +
>> +--*/
>> +{
>> + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
>> +
>> + FvbDevice = FVB_DEVICE_FROM_THIS (This);
>> +
>> + return FvbGetLbaAddress (
>> + FvbDevice->Instance,
>> + Lba,
>> + NULL,
>> + BlockSize,
>> + NumOfBlocks,
>> + mFvbModuleGlobal
>> + );
>> +}
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +FvbProtocolGetAttributes (
>> + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
>> + OUT EFI_FVB_ATTRIBUTES_2 *Attributes
>> + )
>> +/*++
>> +
>> + Routine Description:
>> + Retrieves Volume attributes. No polarity translations are done.
>> +
>> + Arguments:
>> + This - Calling context
>> + Attributes - output buffer which contains attributes
>> +
>> + Returns:
>> + EFI_SUCCESS - Successfully returns
>> +
>> +--*/
>> +{
>> + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
>> +
>> + FvbDevice = FVB_DEVICE_FROM_THIS (This);
>> +
>> + return FvbGetVolumeAttributes (
>> + FvbDevice->Instance,
>> + Attributes,
>> + mFvbModuleGlobal
>> + );
>> +}
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +FvbProtocolSetAttributes (
>> + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
>> + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
>> + )
>> +/*++
>> +
>> + Routine Description:
>> + Sets Volume attributes. No polarity translations are done.
>> +
>> + Arguments:
>> + This - Calling context
>> + Attributes - output buffer which contains attributes
>> +
>> + Returns:
>> + EFI_SUCCESS - Successfully returns
>> +
>> +--*/
>> +{
>> + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
>> +
>> + FvbDevice = FVB_DEVICE_FROM_THIS (This);
>> +
>> + return FvbSetVolumeAttributes (
>> + FvbDevice->Instance,
>> + Attributes,
>> + mFvbModuleGlobal
>> + );
>> +}
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +FvbProtocolEraseBlocks (
>> + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
>> + ...
>> + )
>> +/*++
>> +
>> + Routine Description:
>> +
>> + The EraseBlock() function erases one or more blocks as denoted by the
>> + variable argument list. The entire parameter list of blocks must be
>> + verified prior to 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 EraseBlock() function must
>> + return EFI_INVALID_PARAMETER without modifying the contents of the firmware
>> + volume.
>> +
>> + Arguments:
>> + This - Calling context
>> + ... - Starting LBA followed by Number of Lba to erase.
>> + a -1 to terminate the list.
>> +
>> + Returns:
>> + EFI_SUCCESS - The erase request was successfully completed
>> + EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
>> + EFI_DEVICE_ERROR - The block device is not functioning correctly and
>> + could not be written. Firmware device may have been
>> + partially erased
>> +
>> +--*/
>> +{
>> + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
>> + EFI_FW_VOL_INSTANCE *FwhInstance;
>> + UINTN NumOfBlocks;
>> + VA_LIST args;
>> + EFI_LBA StartingLba;
>> + UINTN NumOfLba;
>> + EFI_STATUS Status;
>> +
>> + FvbDevice = FVB_DEVICE_FROM_THIS (This);
>> +
>> + Status = GetFvbInstance (
>> + FvbDevice->Instance,
>> + mFvbModuleGlobal,
>> + &FwhInstance
>> + );
>> + ASSERT_EFI_ERROR (Status);
>> +
>> + NumOfBlocks = FwhInstance->NumOfBlocks;
>> +
>> + VA_START (args, This);
>> +
>> + do {
>> + StartingLba = VA_ARG (args, EFI_LBA);
>> + if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
>> + break;
>> + }
>> +
>> + NumOfLba = VA_ARG (args, UINTN);
>> +
>> + //
>> + // Check input parameters
>> + //
>> + if ((NumOfLba == 0) || ((StartingLba + NumOfLba) > NumOfBlocks)) {
>> + VA_END (args);
>> + return EFI_INVALID_PARAMETER;
>> + }
>> + } while (1);
>> +
>> + VA_END (args);
>> +
>> + VA_START (args, This);
>> + do {
>> + StartingLba = VA_ARG (args, EFI_LBA);
>> + if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
>> + break;
>> + }
>> +
>> + NumOfLba = VA_ARG (args, UINTN);
>> +
>> + while (NumOfLba > 0) {
>> + Status = QemuFlashEraseBlock (StartingLba);
>> + if (EFI_ERROR (Status)) {
>> + VA_END (args);
>> + return Status;
>> + }
>> +
>> + StartingLba++;
>> + NumOfLba--;
>> + }
>> +
>> + } while (1);
>> +
>> + VA_END (args);
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +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
>> + )
>> +/*++
>> +
>> + Routine Description:
>> +
>> + Writes data beginning at Lba:Offset from FV. The write terminates either
>> + when *NumBytes of data have been written, or when a block boundary is
>> + reached. *NumBytes is updated to reflect the actual number of bytes
>> + written. The write operation does not include erase. This routine will
>> + attempt to write only the specified bytes. If the writes do not stick,
>> + it will return an error.
>> +
>> + Arguments:
>> + This - Calling context
>> + Lba - Block in which to begin write
>> + Offset - Offset in the block at which to begin write
>> + NumBytes - On input, indicates the requested write size. On
>> + output, indicates the actual number of bytes
>> + written
>> + Buffer - Buffer containing source data for the write.
>> +
>> + Returns:
>> + EFI_SUCCESS - The firmware volume was written successfully
>> + EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
>> + NumBytes contains the total number of bytes
>> + actually written
>> + EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
>> + EFI_DEVICE_ERROR - The block device is not functioning correctly and
>> + could not be written
>> + EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
>> +
>> +--*/
>> +{
>> + return QemuFlashWrite (
>> + (EFI_LBA)Lba,
>> + (UINTN)Offset,
>> + NumBytes,
>> + (UINT8 *)Buffer
>> + );
>> +}
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +FvbProtocolRead (
>> + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
>> + IN CONST EFI_LBA Lba,
>> + IN CONST UINTN Offset,
>> + IN OUT UINTN *NumBytes,
>> + IN UINT8 *Buffer
>> + )
>> +/*++
>> +
>> + Routine Description:
>> +
>> + Reads data beginning at Lba:Offset from FV. The Read terminates either
>> + when *NumBytes of data have been read, or when a block boundary is
>> + reached. *NumBytes is updated to reflect the actual number of bytes
>> + written. The write operation does not include erase. This routine will
>> + attempt to write only the specified bytes. If the writes do not stick,
>> + it will return an error.
>> +
>> + Arguments:
>> + This - Calling context
>> + Lba - Block in which to begin Read
>> + Offset - Offset in the block at which to begin Read
>> + NumBytes - On input, indicates the requested write size. On
>> + output, indicates the actual number of bytes Read
>> + Buffer - Buffer containing source data for the Read.
>> +
>> + Returns:
>> + EFI_SUCCESS - The firmware volume was read successfully and
>> + contents are in Buffer
>> + EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
>> + NumBytes contains the total number of bytes
>> + returned in Buffer
>> + EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
>> + EFI_DEVICE_ERROR - The block device is not functioning correctly and
>> + could not be read
>> + EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
>> +
>> +--*/
>> +{
>> + return QemuFlashRead (
>> + (EFI_LBA)Lba,
>> + (UINTN)Offset,
>> + NumBytes,
>> + (UINT8 *)Buffer
>> + );
>> +}
>> +
>> +EFI_STATUS
>> +ValidateFvHeader (
>> + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader
>> + )
>> +/*++
>> +
>> + Routine Description:
>> + Check the integrity of firmware volume header
>> +
>> + Arguments:
>> + FwVolHeader - A pointer to a firmware volume header
>> +
>> + Returns:
>> + EFI_SUCCESS - The firmware volume is consistent
>> + EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an
>> + FV
>> +
>> +--*/
>> +{
>> + 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 == ((UINTN)-1)) ||
>> + ((FwVolHeader->HeaderLength & 0x01) != 0)
>> + )
>> + {
>> + return EFI_NOT_FOUND;
>> + }
>> +
>> + //
>> + // Verify the header checksum
>> + //
>> +
>> + Checksum = CalculateSum16 (
>> + (UINT16 *)FwVolHeader,
>> + FwVolHeader->HeaderLength
>> + );
>> + if (Checksum != 0) {
>> + UINT16 Expected;
>> +
>> + Expected =
>> + (UINT16)(((UINTN)FwVolHeader->Checksum + 0x10000 - Checksum) & 0xffff);
>> +
>> + DEBUG ((
>> + DEBUG_INFO,
>> + "FV@%p Checksum is 0x%x, expected 0x%x\n",
>> + FwVolHeader,
>> + FwVolHeader->Checksum,
>> + Expected
>> + ));
>> + return EFI_NOT_FOUND;
>> + }
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +STATIC
>> +EFI_STATUS
>> +MarkMemoryRangeForRuntimeAccess (
>> + EFI_PHYSICAL_ADDRESS BaseAddress,
>> + UINTN Length
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + //
>> + // Mark flash region as runtime memory
>> + //
>> + Status = gDS->RemoveMemorySpace (
>> + BaseAddress,
>> + Length
>> + );
>> +
>> + Status = gDS->AddMemorySpace (
>> + EfiGcdMemoryTypeSystemMemory,
>> + BaseAddress,
>> + Length,
>> + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
>> + );
>> + ASSERT_EFI_ERROR (Status);
>> +
>> + Status = gBS->AllocatePages (
>> + AllocateAddress,
>> + EfiRuntimeServicesData,
>> + EFI_SIZE_TO_PAGES (Length),
>> + &BaseAddress
>> + );
>> + ASSERT_EFI_ERROR (Status);
>> +
>> + return Status;
>> +}
>> +
>> +STATIC
>> +EFI_STATUS
>> +InitializeVariableFvHeader (
>> + VOID
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EFI_FIRMWARE_VOLUME_HEADER *GoodFwVolHeader;
>> + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
>> + UINTN Length;
>> + UINTN WriteLength;
>> + UINTN BlockSize;
>> +
>> + FwVolHeader =
>> + (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)
>> + PcdGet64 (PcdOvmfFlashNvStorageVariableBase);
>> +
>> + Length = FixedPcdGet32 (PcdAllVarSize);
>> + BlockSize = PcdGet32 (PcdFlashBlockSize);
>> +
>> + Status = ValidateFvHeader (FwVolHeader);
>> + if (!EFI_ERROR (Status)) {
>> + if ((FwVolHeader->FvLength != Length) ||
>> + (FwVolHeader->BlockMap[0].Length != BlockSize))
>> + {
>> + Status = EFI_VOLUME_CORRUPTED;
>> + }
>> + }
>> + if (EFI_ERROR (Status)) {
>> + UINTN Offset;
>> + UINTN Start;
>> +
>> + DEBUG ((
>> + DEBUG_INFO,
>> + "Variable FV header is not valid. It will be reinitialized.\n"
>> + ));
>> +
>> + //
>> + // Get FvbInfo to provide in FwhInstance.
>> + //
>> + Status = GetFvbInfo (Length, &GoodFwVolHeader);
>> + ASSERT (!EFI_ERROR (Status));
>> +
>> + Start = (UINTN)(UINT8*) FwVolHeader - PcdGet64 (PcdFlashFdBase);
>> + ASSERT (Start % BlockSize == 0 && Length % BlockSize == 0);
>> + ASSERT (GoodFwVolHeader->HeaderLength <= BlockSize);
>> +
>> + //
>> + // Erase all the blocks
>> + //
>> + for (Offset = Start; Offset < Start + Length; Offset += BlockSize) {
>> + Status = QemuFlashEraseBlock (Offset / BlockSize);
>> + ASSERT_EFI_ERROR (Status);
>> + }
>> +
>> + //
>> + // Write good FV header
>> + //
>> + WriteLength = GoodFwVolHeader->HeaderLength;
>> + Status = QemuFlashWrite (
>> + Start / BlockSize,
>> + 0,
>> + &WriteLength,
>> + (UINT8 *)GoodFwVolHeader
>> + );
>> + ASSERT_EFI_ERROR (Status);
>> + ASSERT (WriteLength == GoodFwVolHeader->HeaderLength);
>> + }
>> +
>> + return Status;
>> +}
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +FvbInitialize (
>> + IN EFI_HANDLE ImageHandle,
>> + IN EFI_SYSTEM_TABLE *SystemTable
>> + )
>> +/*++
>> +
>> + Routine Description:
>> + This function does common initialization for FVB services
>> +
>> + Arguments:
>> +
>> + Returns:
>> +
>> +--*/
>> +{
>> + EFI_STATUS Status;
>> + EFI_FW_VOL_INSTANCE *FwhInstance;
>> + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
>> + UINT32 BufferSize;
>> + EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;
>> + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
>> + UINT32 MaxLbaSize;
>> + EFI_PHYSICAL_ADDRESS BaseAddress;
>> + UINTN Length;
>> + UINTN NumOfBlocks;
>> + RETURN_STATUS PcdStatus;
>> +
>> + if (EFI_ERROR (QemuFlashInitialize ())) {
>> + //
>> + // Return an error so image will be unloaded
>> + //
>> + DEBUG ((
>> + DEBUG_INFO,
>> + "QEMU flash was not detected. Writable FVB is not being installed.\n"
>> + ));
>> + return EFI_WRITE_PROTECTED;
>> + }
>> +
>> + //
>> + // Allocate runtime services data for global variable, which contains
>> + // the private data of all firmware volume block instances
>> + //
>> + mFvbModuleGlobal = AllocateRuntimePool (sizeof (ESAL_FWB_GLOBAL));
>> + ASSERT (mFvbModuleGlobal != NULL);
>> +
>> + BaseAddress = (UINTN) PcdGet64 (PcdOvmfFlashNvStorageVariableBase);
>> + Length = PcdGet32 (PcdAllVarSize);
>> +
>> + Status = InitializeVariableFvHeader ();
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((
>> + DEBUG_INFO,
>> + "QEMU Flash: Unable to initialize variable FV header\n"
>> + ));
>> + return EFI_WRITE_PROTECTED;
>> + }
>> +
>> + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)BaseAddress;
>> + Status = ValidateFvHeader (FwVolHeader);
>> + if (EFI_ERROR (Status)) {
>> + //
>> + // Get FvbInfo
>> + //
>> + Status = GetFvbInfo (Length, &FwVolHeader);
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_INFO, "EFI_ERROR (GetFvbInfo (Length, &FwVolHeader))\n"));
>> + return EFI_WRITE_PROTECTED;
>> + }
>> + }
>> +
>> + BufferSize = (sizeof (EFI_FW_VOL_INSTANCE) +
>> + FwVolHeader->HeaderLength -
>> + sizeof (EFI_FIRMWARE_VOLUME_HEADER)
>> + );
>> + mFvbModuleGlobal->FvInstance = AllocateRuntimePool (BufferSize);
>> + ASSERT (mFvbModuleGlobal->FvInstance != NULL);
>> +
>> + FwhInstance = mFvbModuleGlobal->FvInstance;
>> +
>> + mFvbModuleGlobal->NumFv = 0;
>> + MaxLbaSize = 0;
>> +
>> + FwVolHeader =
>> + (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)
>> + PcdGet64 (PcdOvmfFlashNvStorageVariableBase);
>> +
>> + FwhInstance->FvBase = (UINTN)BaseAddress;
>> +
>> + CopyMem (
>> + (UINTN *)&(FwhInstance->VolumeHeader),
>> + (UINTN *)FwVolHeader,
>> + FwVolHeader->HeaderLength
>> + );
>> + FwVolHeader = &(FwhInstance->VolumeHeader);
>> +
>> + NumOfBlocks = 0;
>> +
>> + for (PtrBlockMapEntry = FwVolHeader->BlockMap;
>> + PtrBlockMapEntry->NumBlocks != 0;
>> + PtrBlockMapEntry++)
>> + {
>> + //
>> + // Get the maximum size of a block.
>> + //
>> + if (MaxLbaSize < PtrBlockMapEntry->Length) {
>> + MaxLbaSize = PtrBlockMapEntry->Length;
>> + }
>> +
>> + NumOfBlocks = NumOfBlocks + PtrBlockMapEntry->NumBlocks;
>> + }
>> +
>> + //
>> + // The total number of blocks in the FV.
>> + //
>> + FwhInstance->NumOfBlocks = NumOfBlocks;
>> +
>> + //
>> + // Add a FVB Protocol Instance
>> + //
>> + FvbDevice = AllocateRuntimePool (sizeof (EFI_FW_VOL_BLOCK_DEVICE));
>> + ASSERT (FvbDevice != NULL);
>> +
>> + CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE));
>> +
>> + FvbDevice->Instance = mFvbModuleGlobal->NumFv;
>> + mFvbModuleGlobal->NumFv++;
>> +
>> + //
>> + // Set up the devicepath
>> + //
>> + if (FwVolHeader->ExtHeaderOffset == 0) {
>> + FV_MEMMAP_DEVICE_PATH *FvMemmapDevicePath;
>> +
>> + //
>> + // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH
>> + //
>> + FvMemmapDevicePath = AllocateCopyPool (
>> + sizeof (FV_MEMMAP_DEVICE_PATH),
>> + &mFvMemmapDevicePathTemplate
>> + );
>> + FvMemmapDevicePath->MemMapDevPath.StartingAddress = BaseAddress;
>> + FvMemmapDevicePath->MemMapDevPath.EndingAddress =
>> + BaseAddress + FwVolHeader->FvLength - 1;
>> + FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)FvMemmapDevicePath;
>> + } else {
>> + FV_PIWG_DEVICE_PATH *FvPiwgDevicePath;
>> +
>> + FvPiwgDevicePath = AllocateCopyPool (
>> + sizeof (FV_PIWG_DEVICE_PATH),
>> + &mFvPIWGDevicePathTemplate
>> + );
>> + CopyGuid (
>> + &FvPiwgDevicePath->FvDevPath.FvName,
>> + (GUID *)(UINTN)(BaseAddress + FwVolHeader->ExtHeaderOffset)
>> + );
>> + FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)FvPiwgDevicePath;
>> + }
>> +
>> + //
>> + // Module type specific hook.
>> + //
>> + InstallProtocolInterfaces (FvbDevice);
>> +
>> + MarkMemoryRangeForRuntimeAccess (BaseAddress, Length);
>> +
>> + //
>> + // Set several PCD values to point to flash
>> + //
>> +
>> +
>> + PcdStatus = PcdSet64S (
>> + PcdFlashNvStorageVariableBase64,
>> + (UINTN) PcdGet64 (PcdOvmfFlashNvStorageVariableBase)
>> + );
>> + ASSERT_RETURN_ERROR (PcdStatus);
>> + PcdStatus = PcdSet64S (
>> + PcdFlashNvStorageFtwWorkingBase64,
>> + PcdGet64 (PcdOvmfFlashNvStorageFtwWorkingBase)
>> + );
>> + ASSERT_RETURN_ERROR (PcdStatus);
>> + PcdStatus = PcdSet64S (
>> + PcdFlashNvStorageFtwSpareBase64,
>> + PcdGet64 (PcdOvmfFlashNvStorageFtwSpareBase)
>> + );
>> + ASSERT_RETURN_ERROR (PcdStatus);
>> +
>> + FwhInstance = (EFI_FW_VOL_INSTANCE *)
>> + (
>> + (UINTN)((UINT8 *)FwhInstance) + FwVolHeader->HeaderLength +
>> + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
>> + );
>> +
>> + //
>> + // Module type specific hook.
>> + //
>> + InstallVirtualAddressChangeHandler ();
>> +
>> + PcdStatus = PcdSetBoolS (PcdOvmfFlashVariablesEnable, TRUE);
>> + ASSERT_RETURN_ERROR (PcdStatus);
>> + return EFI_SUCCESS;
>> +}
>> diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/FwBlockService.h b/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/FwBlockService.h
>> new file mode 100644
>> index 0000000000..e7234a0c5e
>> --- /dev/null
>> +++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/FwBlockService.h
>> @@ -0,0 +1,178 @@
>> +/** @file
>> + Firmware volume block driver for Intel Firmware Hub (FWH) device
>> +
>> + Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
>> +
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +#ifndef _FW_BLOCK_SERVICE_H
>> +#define _FW_BLOCK_SERVICE_H
>> +
>> +typedef struct {
>> + UINTN FvBase;
>> + UINTN NumOfBlocks;
>> + EFI_FIRMWARE_VOLUME_HEADER VolumeHeader;
>> +} EFI_FW_VOL_INSTANCE;
>> +
>> +typedef struct {
>> + UINT32 NumFv;
>> + EFI_FW_VOL_INSTANCE *FvInstance;
>> +} ESAL_FWB_GLOBAL;
>> +
>> +extern ESAL_FWB_GLOBAL *mFvbModuleGlobal;
>> +
>> +//
>> +// Fvb Protocol instance data
>> +//
>> +#define FVB_DEVICE_FROM_THIS(a) CR (a, EFI_FW_VOL_BLOCK_DEVICE,\
>> + FwVolBlockInstance, FVB_DEVICE_SIGNATURE)
>> +
>> +#define FVB_EXTEND_DEVICE_FROM_THIS(a) CR (a, EFI_FW_VOL_BLOCK_DEVICE,\
>> + FvbExtension, FVB_DEVICE_SIGNATURE)
>> +
>> +#define FVB_DEVICE_SIGNATURE SIGNATURE_32 ('F', 'V', 'B', 'N')
>> +
>> +typedef struct {
>> + MEDIA_FW_VOL_DEVICE_PATH FvDevPath;
>> + EFI_DEVICE_PATH_PROTOCOL EndDevPath;
>> +} FV_PIWG_DEVICE_PATH;
>> +
>> +typedef struct {
>> + MEMMAP_DEVICE_PATH MemMapDevPath;
>> + EFI_DEVICE_PATH_PROTOCOL EndDevPath;
>> +} FV_MEMMAP_DEVICE_PATH;
>> +
>> +typedef struct {
>> + UINTN Signature;
>> + EFI_DEVICE_PATH_PROTOCOL *DevicePath;
>> + UINTN Instance;
>> + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL FwVolBlockInstance;
>> +} EFI_FW_VOL_BLOCK_DEVICE;
>> +
>> +EFI_STATUS
>> +GetFvbInfo (
>> + IN UINT64 FvLength,
>> + OUT EFI_FIRMWARE_VOLUME_HEADER **FvbInfo
>> + );
>> +
>> +EFI_STATUS
>> +FvbSetVolumeAttributes (
>> + IN UINTN Instance,
>> + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes,
>> + IN ESAL_FWB_GLOBAL *Global
>> + );
>> +
>> +EFI_STATUS
>> +FvbGetVolumeAttributes (
>> + IN UINTN Instance,
>> + OUT EFI_FVB_ATTRIBUTES_2 *Attributes,
>> + IN ESAL_FWB_GLOBAL *Global
>> + );
>> +
>> +EFI_STATUS
>> +FvbGetPhysicalAddress (
>> + IN UINTN Instance,
>> + OUT EFI_PHYSICAL_ADDRESS *Address,
>> + IN ESAL_FWB_GLOBAL *Global
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +FvbInitialize (
>> + IN EFI_HANDLE ImageHandle,
>> + IN EFI_SYSTEM_TABLE *SystemTable
>> + );
>> +
>> +
>> +VOID
>> +EFIAPI
>> +FvbClassAddressChangeEvent (
>> + IN EFI_EVENT Event,
>> + IN VOID *Context
>> + );
>> +
>> +EFI_STATUS
>> +FvbGetLbaAddress (
>> + IN UINTN Instance,
>> + IN EFI_LBA Lba,
>> + OUT UINTN *LbaAddress,
>> + OUT UINTN *LbaLength,
>> + OUT UINTN *NumOfBlocks,
>> + IN ESAL_FWB_GLOBAL *Global
>> + );
>> +
>> +//
>> +// 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 CONST EFI_LBA Lba,
>> + OUT UINTN *BlockSize,
>> + OUT UINTN *NumOfBlocks
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +FvbProtocolRead (
>> + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
>> + IN CONST EFI_LBA Lba,
>> + IN CONST UINTN Offset,
>> + IN OUT UINTN *NumBytes,
>> + IN 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,
>> + ...
>> + );
>> +
>> +//
>> +// The following functions have different implementations dependent on the
>> +// module type chosen for building this driver.
>> +//
>> +VOID
>> +InstallProtocolInterfaces (
>> + IN EFI_FW_VOL_BLOCK_DEVICE *FvbDevice
>> + );
>> +
>> +VOID
>> +InstallVirtualAddressChangeHandler (
>> + VOID
>> + );
>> +#endif
>> diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c b/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c
>> new file mode 100644
>> index 0000000000..cb85499539
>> --- /dev/null
>> +++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c
>> @@ -0,0 +1,152 @@
>> +/** @file
>> + Functions related to the Firmware Volume Block service whose
>> + implementation is specific to the runtime DXE driver build.
>> +
>> + Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
>> +
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#include <Guid/EventGroup.h>
>> +#include <Library/DebugLib.h>
>> +#include <Library/DevicePathLib.h>
>> +#include <Library/PcdLib.h>
>> +#include <Library/UefiBootServicesTableLib.h>
>> +#include <Library/UefiRuntimeLib.h>
>> +#include <Protocol/DevicePath.h>
>> +#include <Protocol/FirmwareVolumeBlock.h>
>> +
>> +#include "FwBlockService.h"
>> +#include "QemuFlash.h"
>> +
>> +VOID
>> +InstallProtocolInterfaces (
>> + IN EFI_FW_VOL_BLOCK_DEVICE *FvbDevice
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EFI_HANDLE FwbHandle;
>> + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFwbInterface;
>> +
>> + //
>> + // Find a handle with a matching device path that has supports FW Block
>> + // protocol
>> + //
>> + Status = gBS->LocateDevicePath (
>> + &gEfiFirmwareVolumeBlockProtocolGuid,
>> + &FvbDevice->DevicePath,
>> + &FwbHandle
>> + );
>> + if (EFI_ERROR (Status)) {
>> + //
>> + // LocateDevicePath fails so install a new interface and device path
>> + //
>> + FwbHandle = NULL;
>> + DEBUG ((DEBUG_INFO, "Installing QEMU flash FVB\n"));
>> + Status = gBS->InstallMultipleProtocolInterfaces (
>> + &FwbHandle,
>> + &gEfiFirmwareVolumeBlockProtocolGuid,
>> + &FvbDevice->FwVolBlockInstance,
>> + &gEfiDevicePathProtocolGuid,
>> + FvbDevice->DevicePath,
>> + NULL
>> + );
>> + ASSERT_EFI_ERROR (Status);
>> + } else if (IsDevicePathEnd (FvbDevice->DevicePath)) {
>> + //
>> + // Device already exists, so reinstall the FVB protocol
>> + //
>> + Status = gBS->HandleProtocol (
>> + FwbHandle,
>> + &gEfiFirmwareVolumeBlockProtocolGuid,
>> + (VOID **)&OldFwbInterface
>> + );
>> + ASSERT_EFI_ERROR (Status);
>> +
>> + DEBUG ((DEBUG_INFO, "Reinstalling FVB for QEMU flash region\n"));
>> + Status = gBS->ReinstallProtocolInterface (
>> + FwbHandle,
>> + &gEfiFirmwareVolumeBlockProtocolGuid,
>> + OldFwbInterface,
>> + &FvbDevice->FwVolBlockInstance
>> + );
>> + ASSERT_EFI_ERROR (Status);
>> + } else {
>> + //
>> + // There was a FVB protocol on an End Device Path node
>> + //
>> + ASSERT (FALSE);
>> + }
>> +}
>> +
>> +
>> +STATIC
>> +VOID
>> +EFIAPI
>> +FvbVirtualAddressChangeEvent (
>> + IN EFI_EVENT Event,
>> + IN VOID *Context
>> + )
>> +/*++
>> +
>> + Routine Description:
>> +
>> + Fixup internal data so that EFI and SAL can be call in virtual mode.
>> + Call the passed in Child Notify event and convert the mFvbModuleGlobal
>> + date items to there virtual address.
>> +
>> + Arguments:
>> +
>> + (Standard EFI notify event - EFI_EVENT_NOTIFY)
>> +
>> + Returns:
>> +
>> + None
>> +
>> +--*/
>> +{
>> + EFI_FW_VOL_INSTANCE *FwhInstance;
>> + UINTN Index;
>> +
>> + FwhInstance = mFvbModuleGlobal->FvInstance;
>> + EfiConvertPointer (0x0, (VOID **)&mFvbModuleGlobal->FvInstance);
>> +
>> + //
>> + // Convert the base address of all the instances
>> + //
>> + Index = 0;
>> + while (Index < mFvbModuleGlobal->NumFv) {
>> + EfiConvertPointer (0x0, (VOID **)&FwhInstance->FvBase);
>> + FwhInstance = (EFI_FW_VOL_INSTANCE *)
>> + (
>> + (UINTN)((UINT8 *)FwhInstance) +
>> + FwhInstance->VolumeHeader.HeaderLength +
>> + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
>> + );
>> + Index++;
>> + }
>> +
>> + EfiConvertPointer (0x0, (VOID **)&mFvbModuleGlobal);
>> + QemuFlashConvertPointers ();
>> +}
>> +
>> +
>> +VOID
>> +InstallVirtualAddressChangeHandler (
>> + VOID
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EFI_EVENT VirtualAddressChangeEvent;
>> +
>> + Status = gBS->CreateEventEx (
>> + EVT_NOTIFY_SIGNAL,
>> + TPL_NOTIFY,
>> + FvbVirtualAddressChangeEvent,
>> + NULL,
>> + &gEfiEventVirtualAddressChangeGuid,
>> + &VirtualAddressChangeEvent
>> + );
>> + ASSERT_EFI_ERROR (Status);
>> +}
>> diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c b/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c
>> new file mode 100644
>> index 0000000000..a85d736060
>> --- /dev/null
>> +++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c
>> @@ -0,0 +1,251 @@
>> +/** @file
>> + LoongArch support for QEMU system firmware flash device
>> +
>> + Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
>> +
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#include <Library/BaseMemoryLib.h>
>> +#include <Library/DebugLib.h>
>> +#include <Library/PcdLib.h>
>> +
>> +#include "QemuFlash.h"
>> +
>> +#define WRITE_BYTE_CMD 0x10
>> +#define BLOCK_ERASE_CMD 0x20
>> +#define CLEAR_STATUS_CMD 0x50
>> +#define READ_STATUS_CMD 0x70
>> +#define READ_DEVID_CMD 0x90
>> +#define BLOCK_ERASE_CONFIRM_CMD 0xd0
>> +#define READ_ARRAY_CMD 0xff
>> +
>> +#define CLEARED_ARRAY_STATUS 0x00
>> +
>> +UINT8 *mFlashBase;
>> +
>> +STATIC UINTN mFdBlockSize = 0;
>> +STATIC UINTN mFdBlockCount = 0;
>> +
>> +STATIC
>> +volatile UINT8 *
>> +QemuFlashPtr (
>> + IN EFI_LBA Lba,
>> + IN UINTN Offset
>> + )
>> +{
>> + return mFlashBase + ((UINTN)Lba * mFdBlockSize) + Offset;
>> +}
>> +
>> +
>> +/**
>> + Determines if the QEMU flash memory device is present.
>> +
>> + @retval FALSE The QEMU flash device is not present.
>> + @retval TRUE The QEMU flash device is present.
>> +
>> +**/
>> +STATIC
>> +BOOLEAN
>> +QemuFlashDetected (
>> + VOID
>> + )
>> +{
>> + BOOLEAN FlashDetected;
>> + volatile UINT8 *Ptr;
>> +
>> + UINTN Offset;
>> + UINT8 OriginalUint8;
>> + UINT8 ProbeUint8;
>> +
>> + FlashDetected = FALSE;
>> + Ptr = QemuFlashPtr (0, 0);
>> +
>> + for (Offset = 0; Offset < mFdBlockSize; Offset++) {
>> + Ptr = QemuFlashPtr (0, Offset);
>> + ProbeUint8 = *Ptr;
>> + if ((ProbeUint8 != CLEAR_STATUS_CMD) &&
>> + (ProbeUint8 != READ_STATUS_CMD) &&
>> + (ProbeUint8 != CLEARED_ARRAY_STATUS))
>> + {
>> + break;
>> + }
>> + }
>> +
>> + if (Offset >= mFdBlockSize) {
>> + DEBUG ((DEBUG_INFO, "QEMU Flash: Failed to find probe location\n"));
>> + return FALSE;
>> + }
>> +
>> + DEBUG ((DEBUG_INFO, "QEMU Flash: Attempting flash detection at %p\n", Ptr));
>> +
>> + OriginalUint8 = *Ptr;
>> + *Ptr = CLEAR_STATUS_CMD;
>> + ProbeUint8 = *Ptr;
>> + if ((OriginalUint8 != CLEAR_STATUS_CMD) &&
>> + (ProbeUint8 == CLEAR_STATUS_CMD))
>> + {
>> + DEBUG ((DEBUG_INFO, "QemuFlashDetected => FD behaves as RAM\n"));
>> + *Ptr = OriginalUint8;
>> + } else {
>> + *Ptr = READ_STATUS_CMD;
>> + ProbeUint8 = *Ptr;
>> + if (ProbeUint8 == OriginalUint8) {
>> + DEBUG ((DEBUG_INFO, "QemuFlashDetected => FD behaves as ROM\n"));
>> + } else if (ProbeUint8 == READ_STATUS_CMD) {
>> + DEBUG ((DEBUG_INFO, "QemuFlashDetected => FD behaves as RAM\n"));
>> + *Ptr = OriginalUint8;
>> + } else if (ProbeUint8 == CLEARED_ARRAY_STATUS) {
>> + DEBUG ((DEBUG_INFO, "QemuFlashDetected => FD behaves as FLASH\n"));
>> + FlashDetected = TRUE;
>> + *Ptr = READ_ARRAY_CMD;
>> + }
>> + }
>> +
>> + DEBUG ((
>> + DEBUG_INFO,
>> + "QemuFlashDetected => %a\n",
>> + FlashDetected ? "Yes" : "No"
>> + ));
>> + return FlashDetected;
>> +}
>> +
>> +
>> +/**
>> + Read from QEMU Flash
>> +
>> + @param[in] Lba The starting logical block index to read from.
>> + @param[in] Offset Offset into the block at which to begin reading.
>> + @param[in] NumBytes On input, indicates the requested read size. On
>> + output, indicates the actual number of bytes read
>> + @param[in] Buffer Pointer to the buffer to read into.
>> +
>> +**/
>> +EFI_STATUS
>> +QemuFlashRead (
>> + IN EFI_LBA Lba,
>> + IN UINTN Offset,
>> + IN UINTN *NumBytes,
>> + IN UINT8 *Buffer
>> + )
>> +{
>> + UINT8 *Ptr;
>> +
>> + //
>> + // Only write to the first 64k. We don't bother saving the FTW Spare
>> + // block into the flash memory.
>> + //
>> + if (Lba >= mFdBlockCount) {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> +
>> + //
>> + // Get flash address
>> + //
>> + Ptr = (UINT8 *)QemuFlashPtr (Lba, Offset);
>> +
>> + CopyMem (Buffer, Ptr, *NumBytes);
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +
>> +/**
>> + Write to QEMU Flash
>> +
>> + @param[in] Lba The starting logical block index to write to.
>> + @param[in] Offset Offset into the block at which to begin writing.
>> + @param[in] NumBytes On input, indicates the requested write size. On
>> + output, indicates the actual number of bytes written
>> + @param[in] Buffer Pointer to the data to write.
>> +
>> +**/
>> +EFI_STATUS
>> +QemuFlashWrite (
>> + IN EFI_LBA Lba,
>> + IN UINTN Offset,
>> + IN UINTN *NumBytes,
>> + IN UINT8 *Buffer
>> + )
>> +{
>> + volatile UINT8 *Ptr;
>> + UINTN Loop;
>> +
>> + //
>> + // Only write to the first 64k. We don't bother saving the FTW Spare
>> + // block into the flash memory.
>> + //
>> + if (Lba >= mFdBlockCount) {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> +
>> + //
>> + // Program flash
>> + //
>> + Ptr = QemuFlashPtr (Lba, Offset);
>> + for (Loop = 0; Loop < *NumBytes; Loop++) {
>> + *Ptr = WRITE_BYTE_CMD;
>> + *Ptr = Buffer[Loop];
>> + Ptr++;
>> + }
>> +
>> + //
>> + // Restore flash to read mode
>> + //
>> + if (*NumBytes > 0) {
>> + *(Ptr - 1) = READ_ARRAY_CMD;
>> + }
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +
>> +/**
>> + Erase a QEMU Flash block
>> +
>> + @param Lba The logical block index to erase.
>> +
>> +**/
>> +EFI_STATUS
>> +QemuFlashEraseBlock (
>> + IN EFI_LBA Lba
>> + )
>> +{
>> + volatile UINT8 *Ptr;
>> +
>> + if (Lba >= mFdBlockCount) {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> +
>> + Ptr = QemuFlashPtr (Lba, 0);
>> + *Ptr = BLOCK_ERASE_CMD;
>> + *Ptr = BLOCK_ERASE_CONFIRM_CMD;
>> + return EFI_SUCCESS;
>> +}
>> +
>> +
>> +/**
>> + Initializes QEMU flash memory support
>> +
>> + @retval EFI_WRITE_PROTECTED The QEMU flash device is not present.
>> + @retval EFI_SUCCESS The QEMU flash device is supported.
>> +
>> +**/
>> +EFI_STATUS
>> +QemuFlashInitialize (
>> + VOID
>> + )
>> +{
>> + mFlashBase = (UINT8 *)(UINTN)PcdGet64 (PcdOvmfFlashNvStorageVariableBase);
>> + mFdBlockSize = PcdGet32 (PcdFlashBlockSize);
>> + ASSERT(PcdGet32 (PcdAllVarSize) % mFdBlockSize == 0);
>> + mFdBlockCount = PcdGet32 (PcdAllVarSize) / mFdBlockSize;
>> +
>> + if (!QemuFlashDetected ()) {
>> + return EFI_WRITE_PROTECTED;
>> + }
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/QemuFlash.h b/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/QemuFlash.h
>> new file mode 100644
>> index 0000000000..27caabc5f0
>> --- /dev/null
>> +++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/QemuFlash.h
>> @@ -0,0 +1,86 @@
>> +/** @file
>> + LoongArch support for QEMU system firmware flash device
>> +
>> + Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
>> +
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#ifndef __QEMU_FLASH_H__
>> +#define __QEMU_FLASH_H__
>> +
>> +#include <Protocol/FirmwareVolumeBlock.h>
>> +
>> +extern UINT8 *mFlashBase;
>> +
>> +/**
>> + Read from QEMU Flash
>> +
>> + @param[in] Lba The starting logical block index to read from.
>> + @param[in] Offset Offset into the block at which to begin reading.
>> + @param[in] NumBytes On input, indicates the requested read size. On
>> + output, indicates the actual number of bytes read
>> + @param[in] Buffer Pointer to the buffer to read into.
>> +
>> +**/
>> +EFI_STATUS
>> +QemuFlashRead (
>> + IN EFI_LBA Lba,
>> + IN UINTN Offset,
>> + IN UINTN *NumBytes,
>> + IN UINT8 *Buffer
>> + );
>> +
>> +
>> +/**
>> + Write to QEMU Flash
>> +
>> + @param[in] Lba The starting logical block index to write to.
>> + @param[in] Offset Offset into the block at which to begin writing.
>> + @param[in] NumBytes On input, indicates the requested write size. On
>> + output, indicates the actual number of bytes written
>> + @param[in] Buffer Pointer to the data to write.
>> +
>> +**/
>> +EFI_STATUS
>> +QemuFlashWrite (
>> + IN EFI_LBA Lba,
>> + IN UINTN Offset,
>> + IN UINTN *NumBytes,
>> + IN UINT8 *Buffer
>> + );
>> +
>> +
>> +/**
>> + Erase a QEMU Flash block
>> +
>> + @param Lba The logical block index to erase.
>> +
>> +**/
>> +EFI_STATUS
>> +QemuFlashEraseBlock (
>> + IN EFI_LBA Lba
>> + );
>> +
>> +
>> +/**
>> + Initializes QEMU flash memory support
>> +
>> + @retval EFI_WRITE_PROTECTED The QEMU flash device is not present.
>> + @retval EFI_SUCCESS The QEMU flash device is supported.
>> +
>> +**/
>> +EFI_STATUS
>> +QemuFlashInitialize (
>> + VOID
>> + );
>> +
>> +
>> +VOID
>> +QemuFlashConvertPointers (
>> + VOID
>> + );
>> +
>> +#endif
>> +
>> diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/QemuFlashDxe.c b/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/QemuFlashDxe.c
>> new file mode 100644
>> index 0000000000..b63314aac2
>> --- /dev/null
>> +++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/QemuFlashDxe.c
>> @@ -0,0 +1,21 @@
>> +/** @file
>> + LoongArch support for QEMU system firmware flash device: functions specific to the
>> + runtime DXE driver build.
>> +
>> + Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
>> +
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#include <Library/UefiRuntimeLib.h>
>> +
>> +#include "QemuFlash.h"
>> +
>> +VOID
>> +QemuFlashConvertPointers (
>> + VOID
>> + )
>> +{
>> + EfiConvertPointer (0x0, (VOID **)&mFlashBase);
>> +}
>> diff --git a/Platform/Loongson/LoongArchQemuPkg/Loongson.dsc b/Platform/Loongson/LoongArchQemuPkg/Loongson.dsc
>> index 74c83720b7..59beafb34f 100644
>> --- a/Platform/Loongson/LoongArchQemuPkg/Loongson.dsc
>> +++ b/Platform/Loongson/LoongArchQemuPkg/Loongson.dsc
>> @@ -171,10 +171,10 @@
>> VirtioLib | OvmfPkg/Library/VirtioLib/VirtioLib.inf
>> FrameBufferBltLib | MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
>> QemuFwCfgLib | OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibMmio.inf
>> -
>> DebugLib | MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf
>> -
>> PeiServicesLib | MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
>> + VariableFlashInfoLib | MdeModulePkg/Library/BaseVariableFlashInfoLib/BaseVariableFlashInfoLib.inf
>> +
>> [LibraryClasses.common.SEC]
>> ReportStatusCodeLib | MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf
>> HobLib | MdePkg/Library/PeiHobLib/PeiHobLib.inf
>> --
>> 2.31.1
>>
next prev parent reply other threads:[~2022-10-17 12:56 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-10-14 4:01 [edk2-platforms][PATCH V3 00/16] Platform: Add Loongson support xianglai
2022-10-14 4:01 ` [edk2-platforms][PATCH V3 01/16] Platform/Loongson: Add Serial Port library xianglai
2022-10-14 4:01 ` [edk2-platforms][PATCH V3 02/16] Platform/Loongson: Support SEC And Add Readme.md xianglai
2022-10-14 4:01 ` [edk2-platforms][PATCH V3 03/16] Platform/Loongson: Add PeiServicesTablePointerLib xianglai
2022-10-14 4:01 ` [edk2-platforms][PATCH V3 04/16] Platform/Loongson: Add QemuFwCfgLib xianglai
2022-10-14 4:01 ` [edk2-platforms][PATCH V3 05/16] Platform/Loongson: Add MmuLib xianglai
2022-10-14 4:01 ` [edk2-platforms][PATCH V3 06/16] Platform/Loongson: Add StableTimerLib xianglai
2022-10-14 4:01 ` [edk2-platforms][PATCH V3 07/16] Platform/Loongson: Support PEI phase xianglai
2022-10-14 4:01 ` [edk2-platforms][PATCH V3 08/16] Platform/Loongson: Add CPU DXE driver xianglai
2022-10-14 4:01 ` [edk2-platforms][PATCH V3 09/16] Platform/Loongson: Add PciCpuIoDxe driver xianglai
2022-10-14 4:01 ` [edk2-platforms][PATCH V3 10/16] Platform/Loongson: Add timer Dxe driver xianglai
2022-10-14 4:01 ` [edk2-platforms][PATCH V3 11/16] Platform/Loongson: Add RealTime Clock lib xianglai
2022-10-14 4:01 ` [edk2-platforms][PATCH V3 12/16] Platform/Loongson: Add Platform Boot Manager Lib xianglai
2022-10-14 4:01 ` [edk2-platforms][PATCH V3 13/16] Platform/Loongson: Add Reset System Lib xianglai
2022-10-14 4:01 ` [edk2-platforms][PATCH V3 14/16] Platform/Loongson: Support Dxe xianglai
2022-10-14 4:01 ` [edk2-platforms][PATCH V3 15/16] Platform/Loongson: Add QemuFlashFvbServicesRuntimeDxe driver xianglai
2022-10-17 11:00 ` Ard Biesheuvel
2022-10-17 12:56 ` xianglai [this message]
2022-10-18 8:47 ` xianglai
2022-10-14 4:01 ` [edk2-platforms][PATCH V3 16/16] Platform/Loongson: Support for saving variables to flash xianglai
-- strict thread matches above, loose matches on Subject: below --
2022-09-29 7:07 [edk2-platforms][PATCH V3 00/16] Platform: Add Loongson support xianglai
2022-09-29 7:08 ` [edk2-platforms][PATCH V3 15/16] Platform/Loongson: Add QemuFlashFvbServicesRuntimeDxe driver xianglai
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=374be025-b836-b6fc-9214-8064e21997d4@loongson.cn \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox