From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from loongson.cn (loongson.cn [114.242.206.163]) by mx.groups.io with SMTP id smtpd.web08.4685.1666082831638546091 for ; Tue, 18 Oct 2022 01:47:12 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: loongson.cn, ip: 114.242.206.163, mailfrom: lixianglai@loongson.cn) Received: from loongson.cn (unknown [10.20.42.66]) by gateway (Coremail) with SMTP id _____8AxbdoMaE5jnFwAAA--.2310S3; Tue, 18 Oct 2022 16:47:09 +0800 (CST) Received: from [10.20.42.66] (unknown [10.20.42.66]) by localhost.localdomain (Coremail) with SMTP id AQAAf8Bxj+AKaE5jTJMAAA--.2327S3; Tue, 18 Oct 2022 16:47:06 +0800 (CST) Subject: Re: [edk2-platforms][PATCH V3 15/16] Platform/Loongson: Add QemuFlashFvbServicesRuntimeDxe driver. From: "xianglai" To: Ard Biesheuvel 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 References: <51ef7b9ee8b9ab9829b975aae3d751b819b2704e.1665719826.git.lixianglai@loongson.cn> <374be025-b836-b6fc-9214-8064e21997d4@loongson.cn> Message-ID: <5eab9d07-c1e7-802d-e70e-338de37a8c91@loongson.cn> Date: Tue, 18 Oct 2022 16:47:06 +0800 User-Agent: Mozilla/5.0 (X11; Linux mips64; rv:68.0) Gecko/20100101 Thunderbird/68.7.0 MIME-Version: 1.0 In-Reply-To: <374be025-b836-b6fc-9214-8064e21997d4@loongson.cn> X-CM-TRANSID: AQAAf8Bxj+AKaE5jTJMAAA--.2327S3 X-CM-SenderInfo: 5ol0xt5qjotxo6or00hjvr0hdfq/ X-Coremail-Antispam: 1Uk129KBjvAXoWkXr48KFy3XrWUCF4kXw4Utwb_yoWfXr17Go WUKr1fJr15Xr1UWr1UJr4UJr13JF1UJrnrJr1UGry7Jr10k3WUA3yUJryUt3yUJr18Gr15 Jr1UJryjyFyUXr15n29KB7ZKAUJUUUU7529EdanIXcx71UUUUU7KY7ZEXasCq-sGcSsGvf J3Ic02F40EFcxC0VAKzVAqx4xG6I80ebIjqfuFe4nvWSU5nxnvy29KBjDU0xBIdaVrnRJU UUBFb4IE77IF4wAFF20E14v26r1j6r4UM7CY07I20VC2zVCF04k26cxKx2IYs7xG6rWj6s 0DM7CIcVAFz4kK6r106r15M28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48ve4kI8wA2z4x0 Y4vE2Ix0cI8IcVAFwI0_JFI_Gr1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI0_Gr0_Cr1l84 ACjcxK6I8E87Iv67AKxVW8Jr0_Cr1UM28EF7xvwVC2z280aVCY1x0267AKxVW8Jr0_Cr1U M2kKe7AKxVWUXVWUAwAS0I0E0xvYzxvE52x082IY62kv0487Mc804VCY07AIYIkI8VC2zV CFFI0UMc02F40EFcxC0VAKzVAqx4xG6I80ewAv7VC0I7IYx2IY67AKxVWUAVWUtwAv7VC2 z280aVAFwI0_Jr0_Gr1lOx8S6xCaFVCjc4AY6r1j6r4UM4x0Y48IcVAKI48JMxk0xIA0c2 IEe2xFo4CEbIxvr21l42xK82IYc2Ij64vIr41l4I8I3I0E4IkC6x0Yz7v_Jr0_Gr1l4IxY O2xFxVAFwI0_Jrv_JF1lx2IqxVAqx4xG67AKxVWUJVWUGwC20s026x8GjcxK67AKxVWUGV WUWwC2zVAF1VAY17CE14v26r1q6r43MIIYrxkI7VAKI48JMIIF0xvE2Ix0cI8IcVAFwI0_ Jr0_JF4lIxAIcVC0I7IYx2IY6xkF7I0E14v26r1j6r4UMIIF0xvE42xK8VAvwI8IcIk0rV WUJVWUCwCI42IY6I8E87Iv67AKxVWUJVW8JwCI42IY6I8E87Iv6xkF7I0E14v26r1j6r4U YxBIdaVFxhVjvjDU0xZFpf9x07jeQ6JUUUUU= Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 8bit Content-Language: en-US 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 >> 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 >> 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.
>>> + >>> +  SPDX-License-Identifier: BSD-2-Clause-Patent >>> + >>> +**/ >>> + >>> +// >>> +// The package level header files this module uses >>> +// >>> +#include >>> + >>> +// >>> +// The protocols, PPI and GUID definitions for this module >>> +// >>> +#include >>> +// >>> +// The Library classes this module consumes >>> +// >>> +#include >>> +#include >>> + >>> +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.
>>> +# >>> +#  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.
>>> + >>> +  SPDX-License-Identifier: BSD-2-Clause-Patent >>> + >>> +**/ >>> + >>> +// >>> +// The protocols, PPI and GUID definitions for this module >>> +// >>> +#include >>> +#include >>> + >>> +// >>> +// The Library classes this module consumes >>> +// >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> + >>> +#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.
>>> + >>> +  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.
>>> + >>> +  SPDX-License-Identifier: BSD-2-Clause-Patent >>> + >>> +**/ >>> + >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> + >>> +#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.
>>> + >>> +  SPDX-License-Identifier: BSD-2-Clause-Patent >>> + >>> +**/ >>> + >>> +#include >>> +#include >>> +#include >>> + >>> +#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.
>>> + >>> +  SPDX-License-Identifier: BSD-2-Clause-Patent >>> + >>> +**/ >>> + >>> +#ifndef __QEMU_FLASH_H__ >>> +#define __QEMU_FLASH_H__ >>> + >>> +#include >>> + >>> +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.
>>> + >>> +  SPDX-License-Identifier: BSD-2-Clause-Patent >>> + >>> +**/ >>> + >>> +#include >>> + >>> +#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 >>>