public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
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, 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: Tue, 18 Oct 2022 16:47:06 +0800	[thread overview]
Message-ID: <5eab9d07-c1e7-802d-e70e-338de37a8c91@loongson.cn> (raw)
In-Reply-To: <374be025-b836-b6fc-9214-8064e21997d4@loongson.cn>

Hi Ard Biesheuvel :

   We have researched a bit, the flash implementation of loongson may be 
a bit unreasonable,

the corresponding flash implementation of loongson in qemu has not been 
submitted to the community,

its final solution has not been determined,

we want to wait for the solution to be determined before re-implementing 
the flash-related drivers,

I believe that by then NorFlashDxe has been ported into the OvmfPkg/.

So I will remove the flash-related patch in the next version.


Thanks

xianglai




On 2022/10/17 下午8:56, xianglaili wrote:
> 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
>>>


  reply	other threads:[~2022-10-18  8:47 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
2022-10-18  8:47       ` xianglai [this message]
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=5eab9d07-c1e7-802d-e70e-338de37a8c91@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