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.web09.2233.1663299407662309031 for ; Thu, 15 Sep 2022 20:36:48 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: loongson.cn, ip: 114.242.206.163, mailfrom: lixianglai@loongson.cn) Received: from localhost.localdomain (unknown [10.2.5.185]) by localhost.localdomain (Coremail) with SMTP id AQAAf8DxPGtB7yNj984aAA--.41628S17; Fri, 16 Sep 2022 11:36:45 +0800 (CST) From: "xianglai" To: devel@edk2.groups.io Cc: quic_llindhol@quicinc.com, michael.d.kinney@intel.com, maobibo@loongson.cn Subject: [edk2-platforms][PATCH V2 15/16] Platform/Loongson: Add QemuFlashFvbServicesRuntimeDxe driver. Date: Fri, 16 Sep 2022 11:36:32 +0800 Message-Id: X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 X-CM-TRANSID: AQAAf8DxPGtB7yNj984aAA--.41628S17 X-Coremail-Antispam: 1UD129KBjvAXoWDXryxCr48Zr1UJw47AF13Jwb_yoW7WFWDGo WxtFyIkw18tw1kZryrGryqk3yjqFyrWFsaqr4rZr9Fy3Z5Jwn0kFZav3W5W393tw18Jrnx J3yrXr93AF43J3s5n29KB7ZKAUJUUUUU529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UjIYCTnIWjDUYxBIdaVFxhVjvjDU0xZFpf9x0zRUUUUUUUUU= X-CM-SenderInfo: 5ol0xt5qjotxo6or00hjvr0hdfq/ Content-Transfer-Encoding: quoted-printable This library provides flash read and write functionality and supports writing variables to flash. REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3D4054 Signed-off-by: xianglai li --- .../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/QemuFlashFvb= ServicesRuntimeDxe/FvbInfo.c create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvb= ServicesRuntimeDxe/FvbServicesRuntimeDxe.inf create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvb= ServicesRuntimeDxe/FwBlockService.c create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvb= ServicesRuntimeDxe/FwBlockService.h create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvb= ServicesRuntimeDxe/FwBlockServiceDxe.c create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvb= ServicesRuntimeDxe/QemuFlash.c create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvb= ServicesRuntimeDxe/QemuFlash.h create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvb= ServicesRuntimeDxe/QemuFlashDxe.c diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbService= sRuntimeDxe/FvbInfo.c b/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlas= hFvbServicesRuntimeDxe/FvbInfo.c new file mode 100644 index 0000000000..df772f72be --- /dev/null +++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntim= eDxe/FvbInfo.c @@ -0,0 +1,115 @@ +/** @file=0D + Defines data structure that is the volume header found.These data is int= ent=0D + to decouple FVB driver with FV header.=0D +=0D + Copyright (c) 2021 Loongson Technology Corporation Limited. All rights r= eserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +//=0D +// The package level header files this module uses=0D +//=0D +#include =0D +=0D +//=0D +// The protocols, PPI and GUID definitions for this module=0D +//=0D +#include =0D +//=0D +// The Library classes this module consumes=0D +//=0D +#include =0D +#include =0D +=0D +typedef struct {=0D + UINT64 FvLength;=0D + EFI_FIRMWARE_VOLUME_HEADER FvbInfo;=0D + //=0D + // EFI_FV_BLOCK_MAP_ENTRY ExtraBlockMap[n];//n=3D0=0D + //=0D + EFI_FV_BLOCK_MAP_ENTRY End[1];=0D +} EFI_FVB_MEDIA_INFO;=0D +=0D +EFI_FVB_MEDIA_INFO mPlatformFvbMediaInfo[] =3D {=0D + //=0D + // System NvStorage FVB=0D + //=0D + {=0D + FixedPcdGet32 (PcdAllVarSize),=0D + {=0D + {=0D + 0,=0D + }, // ZeroVector[16]=0D + EFI_SYSTEM_NV_DATA_FV_GUID,=0D + FixedPcdGet32 (PcdAllVarSize),=0D + EFI_FVH_SIGNATURE,=0D + EFI_FVB2_MEMORY_MAPPED |=0D + EFI_FVB2_READ_ENABLED_CAP |=0D + EFI_FVB2_READ_STATUS |=0D + EFI_FVB2_WRITE_ENABLED_CAP |=0D + EFI_FVB2_WRITE_STATUS |=0D + EFI_FVB2_ERASE_POLARITY |=0D + EFI_FVB2_ALIGNMENT_16,=0D + sizeof (EFI_FIRMWARE_VOLUME_HEADER) + sizeof (EFI_FV_BLOCK_MAP_ENTRY= ),=0D + 0, // CheckSum=0D + 0, // ExtHeaderOffset=0D + {=0D + 0,=0D + }, // Reserved[1]=0D + 2, // Revision=0D + {=0D + {=0D + (FixedPcdGet32 (PcdAllVarSize))/=0D + FixedPcdGet32 (PcdFlashBlockSize),=0D + FixedPcdGet32 (PcdFlashBlockSize),=0D + }=0D + } // BlockMap[1]=0D + },=0D + {=0D + {=0D + 0,=0D + 0=0D + }=0D + } // End[1]=0D + }=0D +};=0D +=0D +EFI_STATUS=0D +GetFvbInfo (=0D + IN UINT64 FvLength,=0D + OUT EFI_FIRMWARE_VOLUME_HEADER **FvbInfo=0D + )=0D +{=0D + STATIC BOOLEAN Checksummed =3D FALSE;=0D + UINTN Index;=0D +=0D + if (!Checksummed) {=0D + for (Index =3D 0;=0D + Index < sizeof (mPlatformFvbMediaInfo) / sizeof (EFI_FVB_MEDIA_IN= FO);=0D + Index +=3D 1)=0D + {=0D + UINT16 Checksum;=0D + mPlatformFvbMediaInfo[Index].FvbInfo.Checksum =3D 0;=0D + Checksum =3D CalculateCheckSum1= 6 (=0D + (UINT16 *)&mPlatfo= rmFvbMediaInfo[Index].FvbInfo,=0D + mPlatformFvbMediaI= nfo[Index].FvbInfo.HeaderLength=0D + );=0D + mPlatformFvbMediaInfo[Index].FvbInfo.Checksum =3D Checksum;=0D + }=0D + Checksummed =3D TRUE;=0D + }=0D +=0D + for (Index =3D 0;=0D + Index < sizeof (mPlatformFvbMediaInfo) / sizeof (EFI_FVB_MEDIA_INFO= );=0D + Index +=3D 1)=0D + {=0D + if (mPlatformFvbMediaInfo[Index].FvLength =3D=3D FvLength) {=0D + *FvbInfo =3D &mPlatformFvbMediaInfo[Index].FvbInfo;=0D + return EFI_SUCCESS;=0D + }=0D + }=0D +=0D + return EFI_NOT_FOUND;=0D +}=0D diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbService= sRuntimeDxe/FvbServicesRuntimeDxe.inf b/Platform/Loongson/LoongArchQemuPkg/= Drivers/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf new file mode 100644 index 0000000000..4b0c42b075 --- /dev/null +++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntim= eDxe/FvbServicesRuntimeDxe.inf @@ -0,0 +1,73 @@ +## @file=0D +# Component description file for Emu Fimware Volume Block DXE driver modul= e.=0D +#=0D +# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights = reserved.
=0D +#=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +#=0D +##=0D +=0D +=0D +[Defines]=0D + INF_VERSION =3D 0x00010005=0D + BASE_NAME =3D FvbServicesRuntimeDxe=0D + FILE_GUID =3D 733cbac2-b23f-4b92-bc8e-fb01ce5907b7= =0D + MODULE_TYPE =3D DXE_RUNTIME_DRIVER=0D + VERSION_STRING =3D 1.0=0D + ENTRY_POINT =3D FvbInitialize=0D +=0D +#=0D +# The following information is for reference only and not required by the = build=0D +# tools.=0D +#=0D +# VALID_ARCHITECTURES =3D IA32 X64=0D +#=0D +=0D +[Sources]=0D + FvbInfo.c=0D + FwBlockService.c=0D + FwBlockServiceDxe.c=0D + QemuFlash.c=0D + QemuFlashDxe.c=0D +=0D +[Packages]=0D + MdePkg/MdePkg.dec=0D + MdeModulePkg/MdeModulePkg.dec=0D + OvmfPkg/OvmfPkg.dec=0D + Platform/Loongson/LoongArchQemuPkg/Loongson.dec=0D +=0D +[LibraryClasses]=0D + BaseLib=0D + BaseMemoryLib=0D + DebugLib=0D + DevicePathLib=0D + DxeServicesTableLib=0D + MemoryAllocationLib=0D + PcdLib=0D + UefiBootServicesTableLib=0D + UefiDriverEntryPoint=0D + UefiRuntimeLib=0D +=0D +[Guids]=0D + gEfiEventVirtualAddressChangeGuid # ALWAYS_CONSUMED=0D + # gEfiEventVirtualAddressChangeGuid # Create Event: EVENT_GROUP_GUID=0D +=0D +[Protocols]=0D + gEfiFirmwareVolumeBlockProtocolGuid # PROTOCOL SOMETIMES_PRODU= CED=0D + gEfiDevicePathProtocolGuid # PROTOCOL SOMETIMES_PRODU= CED=0D +=0D +[FixedPcd]=0D + gLoongArchQemuPkgTokenSpaceGuid.PcdOvmfFlashNvStorageVariableBase=0D + gLoongArchQemuPkgTokenSpaceGuid.PcdOvmfFlashNvStorageFtwWorkingBase=0D + gLoongArchQemuPkgTokenSpaceGuid.PcdOvmfFlashNvStorageFtwSpareBase=0D + gLoongArchQemuPkgTokenSpaceGuid.PcdFlashFdBase=0D + gLoongArchQemuPkgTokenSpaceGuid.PcdAllVarSize=0D + gLoongArchQemuPkgTokenSpaceGuid.PcdFlashBlockSize=0D +[Pcd]=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64=0D + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64=0D +=0D +[Depex]=0D + TRUE=0D diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbService= sRuntimeDxe/FwBlockService.c b/Platform/Loongson/LoongArchQemuPkg/Drivers/Q= emuFlashFvbServicesRuntimeDxe/FwBlockService.c new file mode 100644 index 0000000000..d44f2b460c --- /dev/null +++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntim= eDxe/FwBlockService.c @@ -0,0 +1,1158 @@ +/** @file=0D + Implementations for Firmware Volume Block protocol.=0D +=0D + Copyright (c) 2021 Loongson Technology Corporation Limited. All rights r= eserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +//=0D +// The protocols, PPI and GUID definitions for this module=0D +//=0D +#include =0D +#include =0D +=0D +//=0D +// The Library classes this module consumes=0D +//=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#include "FwBlockService.h"=0D +#include "QemuFlash.h"=0D +=0D +#define EFI_FVB2_STATUS \=0D + (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_ST= ATUS)=0D +=0D +ESAL_FWB_GLOBAL *mFvbModuleGlobal;=0D +=0D +FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate =3D {=0D + {=0D + {=0D + HARDWARE_DEVICE_PATH,=0D + HW_MEMMAP_DP,=0D + {=0D + (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),=0D + (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8)=0D + }=0D + },=0D + EfiMemoryMappedIO,=0D + (EFI_PHYSICAL_ADDRESS)0,=0D + (EFI_PHYSICAL_ADDRESS)0,=0D + },=0D + {=0D + END_DEVICE_PATH_TYPE,=0D + END_ENTIRE_DEVICE_PATH_SUBTYPE,=0D + {=0D + END_DEVICE_PATH_LENGTH,=0D + 0=0D + }=0D + }=0D +};=0D +=0D +FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate =3D {=0D + {=0D + {=0D + MEDIA_DEVICE_PATH,=0D + MEDIA_PIWG_FW_VOL_DP,=0D + {=0D + (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)),=0D + (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8)=0D + }=0D + },=0D + { 0 }=0D + },=0D + {=0D + END_DEVICE_PATH_TYPE,=0D + END_ENTIRE_DEVICE_PATH_SUBTYPE,=0D + {=0D + END_DEVICE_PATH_LENGTH,=0D + 0=0D + }=0D + }=0D +};=0D +=0D +EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate =3D {=0D + FVB_DEVICE_SIGNATURE,=0D + NULL,=0D + 0,=0D + {=0D + FvbProtocolGetAttributes,=0D + FvbProtocolSetAttributes,=0D + FvbProtocolGetPhysicalAddress,=0D + FvbProtocolGetBlockSize,=0D + FvbProtocolRead,=0D + FvbProtocolWrite,=0D + FvbProtocolEraseBlocks,=0D + NULL=0D + }=0D +};=0D +=0D +=0D +EFI_STATUS=0D +GetFvbInstance (=0D + IN UINTN Instance,=0D + IN ESAL_FWB_GLOBAL *Global,=0D + OUT EFI_FW_VOL_INSTANCE **FwhInstance=0D + )=0D +/*++=0D +=0D + Routine Description:=0D + Retrieves the physical address of a memory mapped FV=0D +=0D + Arguments:=0D + Instance - The FV instance whose base address is going to= be=0D + returned=0D + Global - Pointer to ESAL_FWB_GLOBAL that contains all=0D + instance data=0D + FwhInstance - The EFI_FW_VOL_INSTANCE firmware instance stru= cture=0D +=0D + Returns:=0D + EFI_SUCCESS - Successfully returns=0D + EFI_INVALID_PARAMETER - Instance not found=0D +=0D +--*/=0D +{=0D + EFI_FW_VOL_INSTANCE *FwhRecord;=0D +=0D + *FwhInstance =3D NULL;=0D + if (Instance >=3D Global->NumFv) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D + //=0D + // Find the right instance of the FVB private data=0D + //=0D + FwhRecord =3D Global->FvInstance;=0D + while (Instance > 0) {=0D + FwhRecord =3D (EFI_FW_VOL_INSTANCE *)=0D + (=0D + (UINTN)((UINT8 *)FwhRecord) + FwhRecord->VolumeHeader.Hea= derLength +=0D + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLU= ME_HEADER))=0D + );=0D + Instance--;=0D + }=0D +=0D + *FwhInstance =3D FwhRecord;=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +EFI_STATUS=0D +FvbGetPhysicalAddress (=0D + IN UINTN Instance,=0D + OUT EFI_PHYSICAL_ADDRESS *Address,=0D + IN ESAL_FWB_GLOBAL *Global=0D + )=0D +/*++=0D +=0D + Routine Description:=0D + Retrieves the physical address of a memory mapped FV=0D +=0D + Arguments:=0D + Instance - The FV instance whose base address is going to= be=0D + returned=0D + Address - Pointer to a caller allocated EFI_PHYSICAL_ADD= RESS=0D + that on successful return, contains the base=0D + address of the firmware volume.=0D + Global - Pointer to ESAL_FWB_GLOBAL that contains all=0D + instance data=0D +=0D + Returns:=0D + EFI_SUCCESS - Successfully returns=0D + EFI_INVALID_PARAMETER - Instance not found=0D +=0D +--*/=0D +{=0D + EFI_FW_VOL_INSTANCE *FwhInstance;=0D + EFI_STATUS Status;=0D +=0D + //=0D + // Find the right instance of the FVB private data=0D + //=0D + Status =3D GetFvbInstance (Instance, Global, &FwhInstance);=0D + ASSERT_EFI_ERROR (Status);=0D + *Address =3D FwhInstance->FvBase;=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +EFI_STATUS=0D +FvbGetVolumeAttributes (=0D + IN UINTN Instance,=0D + OUT EFI_FVB_ATTRIBUTES_2 *Attributes,=0D + IN ESAL_FWB_GLOBAL *Global=0D + )=0D +/*++=0D +=0D + Routine Description:=0D + Retrieves attributes, insures positive polarity of attribute bits, ret= urns=0D + resulting attributes in output parameter=0D +=0D + Arguments:=0D + Instance - The FV instance whose attributes is going to b= e=0D + returned=0D + Attributes - Output buffer which contains attributes=0D + Global - Pointer to ESAL_FWB_GLOBAL that contains all=0D + instance data=0D +=0D + Returns:=0D + EFI_SUCCESS - Successfully returns=0D + EFI_INVALID_PARAMETER - Instance not found=0D +=0D +--*/=0D +{=0D + EFI_FW_VOL_INSTANCE *FwhInstance;=0D + EFI_STATUS Status;=0D +=0D + //=0D + // Find the right instance of the FVB private data=0D + //=0D + Status =3D GetFvbInstance (Instance, Global, &FwhInstance);=0D + ASSERT_EFI_ERROR (Status);=0D + *Attributes =3D FwhInstance->VolumeHeader.Attributes;=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +EFI_STATUS=0D +FvbGetLbaAddress (=0D + IN UINTN Instance,=0D + IN EFI_LBA Lba,=0D + OUT UINTN *LbaAddress,=0D + OUT UINTN *LbaLength,=0D + OUT UINTN *NumOfBlocks,=0D + IN ESAL_FWB_GLOBAL *Global=0D + )=0D +/*++=0D +=0D + Routine Description:=0D + Retrieves the starting address of an LBA in an FV=0D +=0D + Arguments:=0D + Instance - The FV instance which the Lba belongs to=0D + Lba - The logical block address=0D + LbaAddress - On output, contains the physical starting addr= ess=0D + of the Lba=0D + LbaLength - On output, contains the length of the block=0D + NumOfBlocks - A pointer to a caller allocated UINTN in which= the=0D + number of consecutive blocks starting with Lba= is=0D + returned. All blocks in this range have a size= of=0D + BlockSize=0D + Global - Pointer to ESAL_FWB_GLOBAL that contains all=0D + instance data=0D +=0D + Returns:=0D + EFI_SUCCESS - Successfully returns=0D + EFI_INVALID_PARAMETER - Instance not found=0D +=0D +--*/=0D +{=0D + UINT32 NumBlocks;=0D + UINT32 BlockLength;=0D + UINTN Offset;=0D + EFI_LBA StartLba;=0D + EFI_LBA NextLba;=0D + EFI_FW_VOL_INSTANCE *FwhInstance;=0D + EFI_FV_BLOCK_MAP_ENTRY *BlockMap;=0D + EFI_STATUS Status;=0D +=0D + //=0D + // Find the right instance of the FVB private data=0D + //=0D + Status =3D GetFvbInstance (Instance, Global, &FwhInstance);=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + StartLba =3D 0;=0D + Offset =3D 0;=0D + BlockMap =3D &(FwhInstance->VolumeHeader.BlockMap[0]);=0D +=0D + //=0D + // Parse the blockmap of the FV to find which map entry the Lba belongs = to=0D + //=0D + while (TRUE) {=0D + NumBlocks =3D BlockMap->NumBlocks;=0D + BlockLength =3D BlockMap->Length;=0D +=0D + if ((NumBlocks =3D=3D 0) || (BlockLength =3D=3D 0)) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + NextLba =3D StartLba + NumBlocks;=0D +=0D + //=0D + // The map entry found=0D + //=0D + if ((Lba >=3D StartLba) && (Lba < NextLba)) {=0D + Offset =3D Offset + (UINTN)MultU64x32 ((Lba - StartLba), BlockLength= );=0D + if (LbaAddress !=3D NULL) {=0D + *LbaAddress =3D FwhInstance->FvBase + Offset;=0D + }=0D +=0D + if (LbaLength !=3D NULL) {=0D + *LbaLength =3D BlockLength;=0D + }=0D +=0D + if (NumOfBlocks !=3D NULL) {=0D + *NumOfBlocks =3D (UINTN)(NextLba - Lba);=0D + }=0D +=0D + return EFI_SUCCESS;=0D + }=0D +=0D + StartLba =3D NextLba;=0D + Offset =3D Offset + NumBlocks * BlockLength;=0D + BlockMap++;=0D + }=0D +}=0D +=0D +EFI_STATUS=0D +FvbSetVolumeAttributes (=0D + IN UINTN Instance,=0D + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes,=0D + IN ESAL_FWB_GLOBAL *Global=0D + )=0D +/*++=0D +=0D + Routine Description:=0D + Modifies the current settings of the firmware volume according to the= =0D + input parameter, and returns the new setting of the volume=0D +=0D + Arguments:=0D + Instance - The FV instance whose attributes is going to b= e=0D + modified=0D + Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTE= S_2=0D + containing the desired firmware volume setting= s.=0D + On successful return, it contains the new sett= ings=0D + of the firmware volume=0D + Global - Pointer to ESAL_FWB_GLOBAL that contains all=0D + instance data=0D +=0D + Returns:=0D + EFI_SUCCESS - Successfully returns=0D + EFI_ACCESS_DENIED - The volume setting is locked and cannot be mod= ified=0D + EFI_INVALID_PARAMETER - Instance not found, or The attributes requeste= d are=0D + in conflict with the capabilities as declared = in=0D + the firmware volume header=0D +=0D +--*/=0D +{=0D + EFI_FW_VOL_INSTANCE *FwhInstance;=0D + EFI_FVB_ATTRIBUTES_2 OldAttributes;=0D + EFI_FVB_ATTRIBUTES_2 *AttribPtr;=0D + UINT32 Capabilities;=0D + UINT32 OldStatus;=0D + UINT32 NewStatus;=0D + EFI_STATUS Status;=0D + EFI_FVB_ATTRIBUTES_2 UnchangedAttributes;=0D +=0D + //=0D + // Find the right instance of the FVB private data=0D + //=0D + Status =3D GetFvbInstance (Instance, Global, &FwhInstance);=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + AttribPtr =3D=0D + (EFI_FVB_ATTRIBUTES_2 *)&(FwhInstance->VolumeHeader.Attributes);=0D + OldAttributes =3D *AttribPtr;=0D + Capabilities =3D OldAttributes & (EFI_FVB2_READ_DISABLED_CAP | \=0D + EFI_FVB2_READ_ENABLED_CAP | \=0D + EFI_FVB2_WRITE_DISABLED_CAP | \=0D + EFI_FVB2_WRITE_ENABLED_CAP | \=0D + EFI_FVB2_LOCK_CAP \=0D + );=0D + OldStatus =3D OldAttributes & EFI_FVB2_STATUS;=0D + NewStatus =3D *Attributes & EFI_FVB2_STATUS;=0D +=0D + UnchangedAttributes =3D EFI_FVB2_READ_DISABLED_CAP | \=0D + EFI_FVB2_READ_ENABLED_CAP | \=0D + EFI_FVB2_WRITE_DISABLED_CAP | \=0D + EFI_FVB2_WRITE_ENABLED_CAP | \=0D + EFI_FVB2_LOCK_CAP | \=0D + EFI_FVB2_STICKY_WRITE | \=0D + EFI_FVB2_MEMORY_MAPPED | \=0D + EFI_FVB2_ERASE_POLARITY | \=0D + EFI_FVB2_READ_LOCK_CAP | \=0D + EFI_FVB2_WRITE_LOCK_CAP | \=0D + EFI_FVB2_ALIGNMENT;=0D +=0D + //=0D + // Some attributes of FV is read only can *not* be set=0D + //=0D + if ((OldAttributes & UnchangedAttributes) ^=0D + (*Attributes & UnchangedAttributes))=0D + {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D + //=0D + // If firmware volume is locked, no status bit can be updated=0D + //=0D + if (OldAttributes & EFI_FVB2_LOCK_STATUS) {=0D + if (OldStatus ^ NewStatus) {=0D + return EFI_ACCESS_DENIED;=0D + }=0D + }=0D + //=0D + // Test read disable=0D + //=0D + if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) =3D=3D 0) {=0D + if ((NewStatus & EFI_FVB2_READ_STATUS) =3D=3D 0) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D + }=0D + //=0D + // Test read enable=0D + //=0D + if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) =3D=3D 0) {=0D + if (NewStatus & EFI_FVB2_READ_STATUS) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D + }=0D + //=0D + // Test write disable=0D + //=0D + if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) =3D=3D 0) {=0D + if ((NewStatus & EFI_FVB2_WRITE_STATUS) =3D=3D 0) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D + }=0D + //=0D + // Test write enable=0D + //=0D + if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) =3D=3D 0) {=0D + if (NewStatus & EFI_FVB2_WRITE_STATUS) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D + }=0D + //=0D + // Test lock=0D + //=0D + if ((Capabilities & EFI_FVB2_LOCK_CAP) =3D=3D 0) {=0D + if (NewStatus & EFI_FVB2_LOCK_STATUS) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D + }=0D +=0D + *AttribPtr =3D (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));=0D + *AttribPtr =3D (*AttribPtr) | NewStatus;=0D + *Attributes =3D *AttribPtr;=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +//=0D +// FVB protocol APIs=0D +//=0D +EFI_STATUS=0D +EFIAPI=0D +FvbProtocolGetPhysicalAddress (=0D + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,=0D + OUT EFI_PHYSICAL_ADDRESS *Address=0D + )=0D +/*++=0D +=0D + Routine Description:=0D +=0D + Retrieves the physical address of the device.=0D +=0D + Arguments:=0D +=0D + This - Calling context=0D + Address - Output buffer containing the address.=0D +=0D + Returns:=0D + EFI_SUCCESS - Successfully returns=0D +=0D +--*/=0D +{=0D + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;=0D +=0D + FvbDevice =3D FVB_DEVICE_FROM_THIS (This);=0D +=0D + return FvbGetPhysicalAddress (=0D + FvbDevice->Instance,=0D + Address,=0D + mFvbModuleGlobal=0D + );=0D +}=0D +=0D +EFI_STATUS=0D +EFIAPI=0D +FvbProtocolGetBlockSize (=0D + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,=0D + IN CONST EFI_LBA Lba,=0D + OUT UINTN *BlockSize,=0D + OUT UINTN *NumOfBlocks=0D + )=0D +/*++=0D +=0D + Routine Description:=0D + Retrieve the size of a logical block=0D +=0D + Arguments:=0D + This - Calling context=0D + Lba - Indicates which block to return the size for.= =0D + BlockSize - A pointer to a caller allocated UINTN in which= =0D + the size of the block is returned=0D + NumOfBlocks - a pointer to a caller allocated UINTN in which= the=0D + number of consecutive blocks starting with Lba= is=0D + returned. All blocks in this range have a size= of=0D + BlockSize=0D +=0D + Returns:=0D + EFI_SUCCESS - The firmware volume was read successfully and= =0D + contents are in Buffer=0D +=0D +--*/=0D +{=0D + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;=0D +=0D + FvbDevice =3D FVB_DEVICE_FROM_THIS (This);=0D +=0D + return FvbGetLbaAddress (=0D + FvbDevice->Instance,=0D + Lba,=0D + NULL,=0D + BlockSize,=0D + NumOfBlocks,=0D + mFvbModuleGlobal=0D + );=0D +}=0D +=0D +EFI_STATUS=0D +EFIAPI=0D +FvbProtocolGetAttributes (=0D + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,=0D + OUT EFI_FVB_ATTRIBUTES_2 *Attributes=0D + )=0D +/*++=0D +=0D + Routine Description:=0D + Retrieves Volume attributes. No polarity translations are done.=0D +=0D + Arguments:=0D + This - Calling context=0D + Attributes - output buffer which contains attributes=0D +=0D + Returns:=0D + EFI_SUCCESS - Successfully returns=0D +=0D +--*/=0D +{=0D + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;=0D +=0D + FvbDevice =3D FVB_DEVICE_FROM_THIS (This);=0D +=0D + return FvbGetVolumeAttributes (=0D + FvbDevice->Instance,=0D + Attributes,=0D + mFvbModuleGlobal=0D + );=0D +}=0D +=0D +EFI_STATUS=0D +EFIAPI=0D +FvbProtocolSetAttributes (=0D + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,=0D + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes=0D + )=0D +/*++=0D +=0D + Routine Description:=0D + Sets Volume attributes. No polarity translations are done.=0D +=0D + Arguments:=0D + This - Calling context=0D + Attributes - output buffer which contains attributes=0D +=0D + Returns:=0D + EFI_SUCCESS - Successfully returns=0D +=0D +--*/=0D +{=0D + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;=0D +=0D + FvbDevice =3D FVB_DEVICE_FROM_THIS (This);=0D +=0D + return FvbSetVolumeAttributes (=0D + FvbDevice->Instance,=0D + Attributes,=0D + mFvbModuleGlobal=0D + );=0D +}=0D +=0D +EFI_STATUS=0D +EFIAPI=0D +FvbProtocolEraseBlocks (=0D + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,=0D + ...=0D + )=0D +/*++=0D +=0D + Routine Description:=0D +=0D + The EraseBlock() function erases one or more blocks as denoted by the= =0D + variable argument list. The entire parameter list of blocks must be=0D + verified prior to erasing any blocks. If a block is requested that do= es=0D + not exist within the associated firmware volume (it has a larger index= than=0D + the last block of the firmware volume), the EraseBlock() function must= =0D + return EFI_INVALID_PARAMETER without modifying the contents of the fir= mware=0D + volume.=0D +=0D + Arguments:=0D + This - Calling context=0D + ... - Starting LBA followed by Number of Lba to eras= e.=0D + a -1 to terminate the list.=0D +=0D + Returns:=0D + EFI_SUCCESS - The erase request was successfully completed=0D + EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled st= ate=0D + EFI_DEVICE_ERROR - The block device is not functioning correctly = and=0D + could not be written. Firmware device may have= been=0D + partially erased=0D +=0D +--*/=0D +{=0D + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;=0D + EFI_FW_VOL_INSTANCE *FwhInstance;=0D + UINTN NumOfBlocks;=0D + VA_LIST args;=0D + EFI_LBA StartingLba;=0D + UINTN NumOfLba;=0D + EFI_STATUS Status;=0D +=0D + FvbDevice =3D FVB_DEVICE_FROM_THIS (This);=0D +=0D + Status =3D GetFvbInstance (=0D + FvbDevice->Instance,=0D + mFvbModuleGlobal,=0D + &FwhInstance=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + NumOfBlocks =3D FwhInstance->NumOfBlocks;=0D +=0D + VA_START (args, This);=0D +=0D + do {=0D + StartingLba =3D VA_ARG (args, EFI_LBA);=0D + if (StartingLba =3D=3D EFI_LBA_LIST_TERMINATOR) {=0D + break;=0D + }=0D +=0D + NumOfLba =3D VA_ARG (args, UINTN);=0D +=0D + //=0D + // Check input parameters=0D + //=0D + if ((NumOfLba =3D=3D 0) || ((StartingLba + NumOfLba) > NumOfBlocks)) {= =0D + VA_END (args);=0D + return EFI_INVALID_PARAMETER;=0D + }=0D + } while (1);=0D +=0D + VA_END (args);=0D +=0D + VA_START (args, This);=0D + do {=0D + StartingLba =3D VA_ARG (args, EFI_LBA);=0D + if (StartingLba =3D=3D EFI_LBA_LIST_TERMINATOR) {=0D + break;=0D + }=0D +=0D + NumOfLba =3D VA_ARG (args, UINTN);=0D +=0D + while (NumOfLba > 0) {=0D + Status =3D QemuFlashEraseBlock (StartingLba);=0D + if (EFI_ERROR (Status)) {=0D + VA_END (args);=0D + return Status;=0D + }=0D +=0D + StartingLba++;=0D + NumOfLba--;=0D + }=0D +=0D + } while (1);=0D +=0D + VA_END (args);=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +EFI_STATUS=0D +EFIAPI=0D +FvbProtocolWrite (=0D + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,=0D + IN EFI_LBA Lba,=0D + IN UINTN Offset,=0D + IN OUT UINTN *NumBytes,=0D + IN UINT8 *Buffer=0D + )=0D +/*++=0D +=0D + Routine Description:=0D +=0D + Writes data beginning at Lba:Offset from FV. The write terminates eith= er=0D + when *NumBytes of data have been written, or when a block boundary is= =0D + reached. *NumBytes is updated to reflect the actual number of bytes=0D + written. The write operation does not include erase. This routine will= =0D + attempt to write only the specified bytes. If the writes do not stick,= =0D + it will return an error.=0D +=0D + Arguments:=0D + This - Calling context=0D + Lba - Block in which to begin write=0D + Offset - Offset in the block at which to begin write=0D + NumBytes - On input, indicates the requested write size. = On=0D + output, indicates the actual number of bytes=0D + written=0D + Buffer - Buffer containing source data for the write.=0D +=0D + Returns:=0D + EFI_SUCCESS - The firmware volume was written successfully=0D + EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On outp= ut,=0D + NumBytes contains the total number of bytes=0D + actually written=0D + EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled st= ate=0D + EFI_DEVICE_ERROR - The block device is not functioning correctly = and=0D + could not be written=0D + EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL=0D +=0D +--*/=0D +{=0D + return QemuFlashWrite (=0D + (EFI_LBA)Lba,=0D + (UINTN)Offset,=0D + NumBytes,=0D + (UINT8 *)Buffer=0D + );=0D +}=0D +=0D +EFI_STATUS=0D +EFIAPI=0D +FvbProtocolRead (=0D + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,=0D + IN CONST EFI_LBA Lba,=0D + IN CONST UINTN Offset,=0D + IN OUT UINTN *NumBytes,=0D + IN UINT8 *Buffer=0D + )=0D +/*++=0D +=0D + Routine Description:=0D +=0D + Reads data beginning at Lba:Offset from FV. The Read terminates either= =0D + when *NumBytes of data have been read, or when a block boundary is=0D + reached. *NumBytes is updated to reflect the actual number of bytes=0D + written. The write operation does not include erase. This routine will= =0D + attempt to write only the specified bytes. If the writes do not stick,= =0D + it will return an error.=0D +=0D + Arguments:=0D + This - Calling context=0D + Lba - Block in which to begin Read=0D + Offset - Offset in the block at which to begin Read=0D + NumBytes - On input, indicates the requested write size. = On=0D + output, indicates the actual number of bytes R= ead=0D + Buffer - Buffer containing source data for the Read.=0D +=0D + Returns:=0D + EFI_SUCCESS - The firmware volume was read successfully and= =0D + contents are in Buffer=0D + EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On outpu= t,=0D + NumBytes contains the total number of bytes=0D + returned in Buffer=0D + EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled sta= te=0D + EFI_DEVICE_ERROR - The block device is not functioning correctly = and=0D + could not be read=0D + EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL=0D +=0D +--*/=0D +{=0D + return QemuFlashRead (=0D + (EFI_LBA)Lba,=0D + (UINTN)Offset,=0D + NumBytes,=0D + (UINT8 *)Buffer=0D + );=0D +}=0D +=0D +EFI_STATUS=0D +ValidateFvHeader (=0D + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader=0D + )=0D +/*++=0D +=0D + Routine Description:=0D + Check the integrity of firmware volume header=0D +=0D + Arguments:=0D + FwVolHeader - A pointer to a firmware volume header=0D +=0D + Returns:=0D + EFI_SUCCESS - The firmware volume is consistent=0D + EFI_NOT_FOUND - The firmware volume has corrupted. So it is no= t an=0D + FV=0D +=0D +--*/=0D +{=0D + UINT16 Checksum;=0D +=0D + //=0D + // Verify the header revision, header signature, length=0D + // Length of FvBlock cannot be 2**64-1=0D + // HeaderLength cannot be an odd number=0D + //=0D + if ((FwVolHeader->Revision !=3D EFI_FVH_REVISION) ||=0D + (FwVolHeader->Signature !=3D EFI_FVH_SIGNATURE) ||=0D + (FwVolHeader->FvLength =3D=3D ((UINTN)-1)) ||=0D + ((FwVolHeader->HeaderLength & 0x01) !=3D 0)=0D + )=0D + {=0D + return EFI_NOT_FOUND;=0D + }=0D +=0D + //=0D + // Verify the header checksum=0D + //=0D +=0D + Checksum =3D CalculateSum16 (=0D + (UINT16 *)FwVolHeader,=0D + FwVolHeader->HeaderLength=0D + );=0D + if (Checksum !=3D 0) {=0D + UINT16 Expected;=0D +=0D + Expected =3D=0D + (UINT16)(((UINTN)FwVolHeader->Checksum + 0x10000 - Checksum) & 0xfff= f);=0D +=0D + DEBUG ((=0D + DEBUG_INFO,=0D + "FV@%p Checksum is 0x%x, expected 0x%x\n",=0D + FwVolHeader,=0D + FwVolHeader->Checksum,=0D + Expected=0D + ));=0D + return EFI_NOT_FOUND;=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +STATIC=0D +EFI_STATUS=0D +MarkMemoryRangeForRuntimeAccess (=0D + EFI_PHYSICAL_ADDRESS BaseAddress,=0D + UINTN Length=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + //=0D + // Mark flash region as runtime memory=0D + //=0D + Status =3D gDS->RemoveMemorySpace (=0D + BaseAddress,=0D + Length=0D + );=0D +=0D + Status =3D gDS->AddMemorySpace (=0D + EfiGcdMemoryTypeSystemMemory,=0D + BaseAddress,=0D + Length,=0D + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + Status =3D gBS->AllocatePages (=0D + AllocateAddress,=0D + EfiRuntimeServicesData,=0D + EFI_SIZE_TO_PAGES (Length),=0D + &BaseAddress=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + return Status;=0D +}=0D +=0D +STATIC=0D +EFI_STATUS=0D +InitializeVariableFvHeader (=0D + VOID=0D + )=0D +{=0D + EFI_STATUS Status;=0D + EFI_FIRMWARE_VOLUME_HEADER *GoodFwVolHeader;=0D + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;=0D + UINTN Length;=0D + UINTN WriteLength;=0D + UINTN BlockSize;=0D +=0D + FwVolHeader =3D=0D + (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)=0D + PcdGet64 (PcdOvmfFlashNvStorageVariableBase);=0D +=0D + Length =3D FixedPcdGet32 (PcdAllVarSize);=0D + BlockSize =3D PcdGet32 (PcdFlashBlockSize);=0D +=0D + Status =3D ValidateFvHeader (FwVolHeader);=0D + if (!EFI_ERROR (Status)) {=0D + if ((FwVolHeader->FvLength !=3D Length) ||=0D + (FwVolHeader->BlockMap[0].Length !=3D BlockSize))=0D + {=0D + Status =3D EFI_VOLUME_CORRUPTED;=0D + }=0D + }=0D + if (EFI_ERROR (Status)) {=0D + UINTN Offset;=0D + UINTN Start;=0D +=0D + DEBUG ((=0D + DEBUG_INFO,=0D + "Variable FV header is not valid. It will be reinitialized.\n"=0D + ));=0D +=0D + //=0D + // Get FvbInfo to provide in FwhInstance.=0D + //=0D + Status =3D GetFvbInfo (Length, &GoodFwVolHeader);=0D + ASSERT (!EFI_ERROR (Status));=0D +=0D + Start =3D (UINTN)(UINT8*) FwVolHeader - PcdGet64 (PcdFlashFdBase);=0D + ASSERT (Start % BlockSize =3D=3D 0 && Length % BlockSize =3D=3D 0);=0D + ASSERT (GoodFwVolHeader->HeaderLength <=3D BlockSize);=0D +=0D + //=0D + // Erase all the blocks=0D + //=0D + for (Offset =3D Start; Offset < Start + Length; Offset +=3D BlockSize)= {=0D + Status =3D QemuFlashEraseBlock (Offset / BlockSize);=0D + ASSERT_EFI_ERROR (Status);=0D + }=0D +=0D + //=0D + // Write good FV header=0D + //=0D + WriteLength =3D GoodFwVolHeader->HeaderLength;=0D + Status =3D QemuFlashWrite (=0D + Start / BlockSize,=0D + 0,=0D + &WriteLength,=0D + (UINT8 *)GoodFwVolHeader=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D + ASSERT (WriteLength =3D=3D GoodFwVolHeader->HeaderLength);=0D + }=0D +=0D + return Status;=0D +}=0D +=0D +EFI_STATUS=0D +EFIAPI=0D +FvbInitialize (=0D + IN EFI_HANDLE ImageHandle,=0D + IN EFI_SYSTEM_TABLE *SystemTable=0D + )=0D +/*++=0D +=0D + Routine Description:=0D + This function does common initialization for FVB services=0D +=0D + Arguments:=0D +=0D + Returns:=0D +=0D +--*/=0D +{=0D + EFI_STATUS Status;=0D + EFI_FW_VOL_INSTANCE *FwhInstance;=0D + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;=0D + UINT32 BufferSize;=0D + EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;=0D + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;=0D + UINT32 MaxLbaSize;=0D + EFI_PHYSICAL_ADDRESS BaseAddress;=0D + UINTN Length;=0D + UINTN NumOfBlocks;=0D + RETURN_STATUS PcdStatus;=0D +=0D + if (EFI_ERROR (QemuFlashInitialize ())) {=0D + //=0D + // Return an error so image will be unloaded=0D + //=0D + DEBUG ((=0D + DEBUG_INFO,=0D + "QEMU flash was not detected. Writable FVB is not being installed.\n= "=0D + ));=0D + return EFI_WRITE_PROTECTED;=0D + }=0D +=0D + //=0D + // Allocate runtime services data for global variable, which contains=0D + // the private data of all firmware volume block instances=0D + //=0D + mFvbModuleGlobal =3D AllocateRuntimePool (sizeof (ESAL_FWB_GLOBAL));=0D + ASSERT (mFvbModuleGlobal !=3D NULL);=0D +=0D + BaseAddress =3D (UINTN) PcdGet64 (PcdOvmfFlashNvStorageVariableBase);=0D + Length =3D PcdGet32 (PcdAllVarSize);=0D +=0D + Status =3D InitializeVariableFvHeader ();=0D + if (EFI_ERROR (Status)) {=0D + DEBUG ((=0D + DEBUG_INFO,=0D + "QEMU Flash: Unable to initialize variable FV header\n"=0D + ));=0D + return EFI_WRITE_PROTECTED;=0D + }=0D +=0D + FwVolHeader =3D (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)BaseAddress;=0D + Status =3D ValidateFvHeader (FwVolHeader);=0D + if (EFI_ERROR (Status)) {=0D + //=0D + // Get FvbInfo=0D + //=0D + Status =3D GetFvbInfo (Length, &FwVolHeader);=0D + if (EFI_ERROR (Status)) {=0D + DEBUG ((DEBUG_INFO, "EFI_ERROR (GetFvbInfo (Length, &FwVolHeader))\n= "));=0D + return EFI_WRITE_PROTECTED;=0D + }=0D + }=0D +=0D + BufferSize =3D (sizeof (EFI_FW_VOL_INSTANCE) +=0D + FwVolHeader->HeaderLength -=0D + sizeof (EFI_FIRMWARE_VOLUME_HEADER)=0D + );=0D + mFvbModuleGlobal->FvInstance =3D AllocateRuntimePool (BufferSize);=0D + ASSERT (mFvbModuleGlobal->FvInstance !=3D NULL);=0D +=0D + FwhInstance =3D mFvbModuleGlobal->FvInstance;=0D +=0D + mFvbModuleGlobal->NumFv =3D 0;=0D + MaxLbaSize =3D 0;=0D +=0D + FwVolHeader =3D=0D + (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)=0D + PcdGet64 (PcdOvmfFlashNvStorageVariableBase);=0D +=0D + FwhInstance->FvBase =3D (UINTN)BaseAddress;=0D +=0D + CopyMem (=0D + (UINTN *)&(FwhInstance->VolumeHeader),=0D + (UINTN *)FwVolHeader,=0D + FwVolHeader->HeaderLength=0D + );=0D + FwVolHeader =3D &(FwhInstance->VolumeHeader);=0D +=0D + NumOfBlocks =3D 0;=0D +=0D + for (PtrBlockMapEntry =3D FwVolHeader->BlockMap;=0D + PtrBlockMapEntry->NumBlocks !=3D 0;=0D + PtrBlockMapEntry++)=0D + {=0D + //=0D + // Get the maximum size of a block.=0D + //=0D + if (MaxLbaSize < PtrBlockMapEntry->Length) {=0D + MaxLbaSize =3D PtrBlockMapEntry->Length;=0D + }=0D +=0D + NumOfBlocks =3D NumOfBlocks + PtrBlockMapEntry->NumBlocks;=0D + }=0D +=0D + //=0D + // The total number of blocks in the FV.=0D + //=0D + FwhInstance->NumOfBlocks =3D NumOfBlocks;=0D +=0D + //=0D + // Add a FVB Protocol Instance=0D + //=0D + FvbDevice =3D AllocateRuntimePool (sizeof (EFI_FW_VOL_BLOCK_DEVICE));=0D + ASSERT (FvbDevice !=3D NULL);=0D +=0D + CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE= ));=0D +=0D + FvbDevice->Instance =3D mFvbModuleGlobal->NumFv;=0D + mFvbModuleGlobal->NumFv++;=0D +=0D + //=0D + // Set up the devicepath=0D + //=0D + if (FwVolHeader->ExtHeaderOffset =3D=3D 0) {=0D + FV_MEMMAP_DEVICE_PATH *FvMemmapDevicePath;=0D +=0D + //=0D + // FV does not contains extension header, then produce MEMMAP_DEVICE_P= ATH=0D + //=0D + FvMemmapDevicePath =3D AllocateCopyPool (=0D + sizeof (FV_MEMMAP_DEVICE_PATH),=0D + &mFvMemmapDevicePathTemplate=0D + );=0D + FvMemmapDevicePath->MemMapDevPath.StartingAddress =3D BaseAddress;=0D + FvMemmapDevicePath->MemMapDevPath.EndingAddress =3D=0D + BaseAddress + FwVolHeader->FvLength - 1;=0D + FvbDevice->DevicePath =3D (EFI_DEVICE_PATH_PROTOCOL *)FvMemmapDevicePa= th;=0D + } else {=0D + FV_PIWG_DEVICE_PATH *FvPiwgDevicePath;=0D +=0D + FvPiwgDevicePath =3D AllocateCopyPool (=0D + sizeof (FV_PIWG_DEVICE_PATH),=0D + &mFvPIWGDevicePathTemplate=0D + );=0D + CopyGuid (=0D + &FvPiwgDevicePath->FvDevPath.FvName,=0D + (GUID *)(UINTN)(BaseAddress + FwVolHeader->ExtHeaderOffset)=0D + );=0D + FvbDevice->DevicePath =3D (EFI_DEVICE_PATH_PROTOCOL *)FvPiwgDevicePath= ;=0D + }=0D +=0D + //=0D + // Module type specific hook.=0D + //=0D + InstallProtocolInterfaces (FvbDevice);=0D +=0D + MarkMemoryRangeForRuntimeAccess (BaseAddress, Length);=0D +=0D + //=0D + // Set several PCD values to point to flash=0D + //=0D +=0D +=0D + PcdStatus =3D PcdSet64S (=0D + PcdFlashNvStorageVariableBase64,=0D + (UINTN) PcdGet64 (PcdOvmfFlashNvStorageVariableBase)=0D + );=0D + ASSERT_RETURN_ERROR (PcdStatus);=0D + PcdStatus =3D PcdSet64S (=0D + PcdFlashNvStorageFtwWorkingBase64,=0D + PcdGet64 (PcdOvmfFlashNvStorageFtwWorkingBase)=0D + );=0D + ASSERT_RETURN_ERROR (PcdStatus);=0D + PcdStatus =3D PcdSet64S (=0D + PcdFlashNvStorageFtwSpareBase64,=0D + PcdGet64 (PcdOvmfFlashNvStorageFtwSpareBase)=0D + );=0D + ASSERT_RETURN_ERROR (PcdStatus);=0D +=0D + FwhInstance =3D (EFI_FW_VOL_INSTANCE *)=0D + (=0D + (UINTN)((UINT8 *)FwhInstance) + FwVolHeader->HeaderLength= +=0D + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLU= ME_HEADER))=0D + );=0D +=0D + //=0D + // Module type specific hook.=0D + //=0D + InstallVirtualAddressChangeHandler ();=0D +=0D + PcdStatus =3D PcdSetBoolS (PcdOvmfFlashVariablesEnable, TRUE);=0D + ASSERT_RETURN_ERROR (PcdStatus);=0D + return EFI_SUCCESS;=0D +}=0D diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbService= sRuntimeDxe/FwBlockService.h b/Platform/Loongson/LoongArchQemuPkg/Drivers/Q= emuFlashFvbServicesRuntimeDxe/FwBlockService.h new file mode 100644 index 0000000000..e7234a0c5e --- /dev/null +++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntim= eDxe/FwBlockService.h @@ -0,0 +1,178 @@ +/** @file=0D + Firmware volume block driver for Intel Firmware Hub (FWH) device=0D +=0D + Copyright (c) 2021 Loongson Technology Corporation Limited. All rights r= eserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +#ifndef _FW_BLOCK_SERVICE_H=0D +#define _FW_BLOCK_SERVICE_H=0D +=0D +typedef struct {=0D + UINTN FvBase;=0D + UINTN NumOfBlocks;=0D + EFI_FIRMWARE_VOLUME_HEADER VolumeHeader;=0D +} EFI_FW_VOL_INSTANCE;=0D +=0D +typedef struct {=0D + UINT32 NumFv;=0D + EFI_FW_VOL_INSTANCE *FvInstance;=0D +} ESAL_FWB_GLOBAL;=0D +=0D +extern ESAL_FWB_GLOBAL *mFvbModuleGlobal;=0D +=0D +//=0D +// Fvb Protocol instance data=0D +//=0D +#define FVB_DEVICE_FROM_THIS(a) CR (a, EFI_FW_VOL_BLOCK_DEVICE,\=0D + FwVolBlockInstance, FVB_DEVICE_SIGNATURE= )=0D +=0D +#define FVB_EXTEND_DEVICE_FROM_THIS(a) CR (a, EFI_FW_VOL_BLOCK_DEVICE,\=0D + FvbExtension, FVB_DEVICE_SIGNATUR= E)=0D +=0D +#define FVB_DEVICE_SIGNATURE SIGNATURE_32 ('F', 'V', 'B', 'N')=0D +=0D +typedef struct {=0D + MEDIA_FW_VOL_DEVICE_PATH FvDevPath;=0D + EFI_DEVICE_PATH_PROTOCOL EndDevPath;=0D +} FV_PIWG_DEVICE_PATH;=0D +=0D +typedef struct {=0D + MEMMAP_DEVICE_PATH MemMapDevPath;=0D + EFI_DEVICE_PATH_PROTOCOL EndDevPath;=0D +} FV_MEMMAP_DEVICE_PATH;=0D +=0D +typedef struct {=0D + UINTN Signature;=0D + EFI_DEVICE_PATH_PROTOCOL *DevicePath;=0D + UINTN Instance;=0D + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL FwVolBlockInstance;=0D +} EFI_FW_VOL_BLOCK_DEVICE;=0D +=0D +EFI_STATUS=0D +GetFvbInfo (=0D + IN UINT64 FvLength,=0D + OUT EFI_FIRMWARE_VOLUME_HEADER **FvbInfo=0D + );=0D +=0D +EFI_STATUS=0D +FvbSetVolumeAttributes (=0D + IN UINTN Instance,=0D + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes,=0D + IN ESAL_FWB_GLOBAL *Global=0D + );=0D +=0D +EFI_STATUS=0D +FvbGetVolumeAttributes (=0D + IN UINTN Instance,=0D + OUT EFI_FVB_ATTRIBUTES_2 *Attributes,=0D + IN ESAL_FWB_GLOBAL *Global=0D + );=0D +=0D +EFI_STATUS=0D +FvbGetPhysicalAddress (=0D + IN UINTN Instance,=0D + OUT EFI_PHYSICAL_ADDRESS *Address,=0D + IN ESAL_FWB_GLOBAL *Global=0D + );=0D +=0D +EFI_STATUS=0D +EFIAPI=0D +FvbInitialize (=0D + IN EFI_HANDLE ImageHandle,=0D + IN EFI_SYSTEM_TABLE *SystemTable=0D + );=0D +=0D +=0D +VOID=0D +EFIAPI=0D +FvbClassAddressChangeEvent (=0D + IN EFI_EVENT Event,=0D + IN VOID *Context=0D + );=0D +=0D +EFI_STATUS=0D +FvbGetLbaAddress (=0D + IN UINTN Instance,=0D + IN EFI_LBA Lba,=0D + OUT UINTN *LbaAddress,=0D + OUT UINTN *LbaLength,=0D + OUT UINTN *NumOfBlocks,=0D + IN ESAL_FWB_GLOBAL *Global=0D + );=0D +=0D +//=0D +// Protocol APIs=0D +//=0D +EFI_STATUS=0D +EFIAPI=0D +FvbProtocolGetAttributes (=0D + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,=0D + OUT EFI_FVB_ATTRIBUTES_2 *Attributes=0D + );=0D +=0D +EFI_STATUS=0D +EFIAPI=0D +FvbProtocolSetAttributes (=0D + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,=0D + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes=0D + );=0D +=0D +EFI_STATUS=0D +EFIAPI=0D +FvbProtocolGetPhysicalAddress (=0D + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,=0D + OUT EFI_PHYSICAL_ADDRESS *Address=0D + );=0D +=0D +EFI_STATUS=0D +EFIAPI=0D +FvbProtocolGetBlockSize (=0D + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,=0D + IN CONST EFI_LBA Lba,=0D + OUT UINTN *BlockSize,=0D + OUT UINTN *NumOfBlocks=0D + );=0D +=0D +EFI_STATUS=0D +EFIAPI=0D +FvbProtocolRead (=0D + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,=0D + IN CONST EFI_LBA Lba,=0D + IN CONST UINTN Offset,=0D + IN OUT UINTN *NumBytes,=0D + IN UINT8 *Buffer=0D + );=0D +=0D +EFI_STATUS=0D +EFIAPI=0D +FvbProtocolWrite (=0D + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,=0D + IN EFI_LBA Lba,=0D + IN UINTN Offset,=0D + IN OUT UINTN *NumBytes,=0D + IN UINT8 *Buffer=0D + );=0D +=0D +EFI_STATUS=0D +EFIAPI=0D +FvbProtocolEraseBlocks (=0D + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,=0D + ...=0D + );=0D +=0D +//=0D +// The following functions have different implementations dependent on the= =0D +// module type chosen for building this driver.=0D +//=0D +VOID=0D +InstallProtocolInterfaces (=0D + IN EFI_FW_VOL_BLOCK_DEVICE *FvbDevice=0D + );=0D +=0D +VOID=0D +InstallVirtualAddressChangeHandler (=0D + VOID=0D + );=0D +#endif=0D diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbService= sRuntimeDxe/FwBlockServiceDxe.c b/Platform/Loongson/LoongArchQemuPkg/Driver= s/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c new file mode 100644 index 0000000000..cb85499539 --- /dev/null +++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntim= eDxe/FwBlockServiceDxe.c @@ -0,0 +1,152 @@ +/** @file=0D + Functions related to the Firmware Volume Block service whose=0D + implementation is specific to the runtime DXE driver build.=0D +=0D + Copyright (c) 2021 Loongson Technology Corporation Limited. All rights r= eserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#include "FwBlockService.h"=0D +#include "QemuFlash.h"=0D +=0D +VOID=0D +InstallProtocolInterfaces (=0D + IN EFI_FW_VOL_BLOCK_DEVICE *FvbDevice=0D + )=0D +{=0D + EFI_STATUS Status;=0D + EFI_HANDLE FwbHandle;=0D + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFwbInterface;=0D +=0D + //=0D + // Find a handle with a matching device path that has supports FW Block= =0D + // protocol=0D + //=0D + Status =3D gBS->LocateDevicePath (=0D + &gEfiFirmwareVolumeBlockProtocolGuid,=0D + &FvbDevice->DevicePath,=0D + &FwbHandle=0D + );=0D + if (EFI_ERROR (Status)) {=0D + //=0D + // LocateDevicePath fails so install a new interface and device path=0D + //=0D + FwbHandle =3D NULL;=0D + DEBUG ((DEBUG_INFO, "Installing QEMU flash FVB\n"));=0D + Status =3D gBS->InstallMultipleProtocolInterfaces (=0D + &FwbHandle,=0D + &gEfiFirmwareVolumeBlockProtocolGuid,=0D + &FvbDevice->FwVolBlockInstance,=0D + &gEfiDevicePathProtocolGuid,=0D + FvbDevice->DevicePath,=0D + NULL=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D + } else if (IsDevicePathEnd (FvbDevice->DevicePath)) {=0D + //=0D + // Device already exists, so reinstall the FVB protocol=0D + //=0D + Status =3D gBS->HandleProtocol (=0D + FwbHandle,=0D + &gEfiFirmwareVolumeBlockProtocolGuid,=0D + (VOID **)&OldFwbInterface=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + DEBUG ((DEBUG_INFO, "Reinstalling FVB for QEMU flash region\n"));=0D + Status =3D gBS->ReinstallProtocolInterface (=0D + FwbHandle,=0D + &gEfiFirmwareVolumeBlockProtocolGuid,=0D + OldFwbInterface,=0D + &FvbDevice->FwVolBlockInstance=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D + } else {=0D + //=0D + // There was a FVB protocol on an End Device Path node=0D + //=0D + ASSERT (FALSE);=0D + }=0D +}=0D +=0D +=0D +STATIC=0D +VOID=0D +EFIAPI=0D +FvbVirtualAddressChangeEvent (=0D + IN EFI_EVENT Event,=0D + IN VOID *Context=0D + )=0D +/*++=0D +=0D + Routine Description:=0D +=0D + Fixup internal data so that EFI and SAL can be call in virtual mode.=0D + Call the passed in Child Notify event and convert the mFvbModuleGlobal= =0D + date items to there virtual address.=0D +=0D + Arguments:=0D +=0D + (Standard EFI notify event - EFI_EVENT_NOTIFY)=0D +=0D + Returns:=0D +=0D + None=0D +=0D +--*/=0D +{=0D + EFI_FW_VOL_INSTANCE *FwhInstance;=0D + UINTN Index;=0D +=0D + FwhInstance =3D mFvbModuleGlobal->FvInstance;=0D + EfiConvertPointer (0x0, (VOID **)&mFvbModuleGlobal->FvInstance);=0D +=0D + //=0D + // Convert the base address of all the instances=0D + //=0D + Index =3D 0;=0D + while (Index < mFvbModuleGlobal->NumFv) {=0D + EfiConvertPointer (0x0, (VOID **)&FwhInstance->FvBase);=0D + FwhInstance =3D (EFI_FW_VOL_INSTANCE *)=0D + (=0D + (UINTN)((UINT8 *)FwhInstance) +=0D + FwhInstance->VolumeHeader.HeaderLength +=0D + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VO= LUME_HEADER))=0D + );=0D + Index++;=0D + }=0D +=0D + EfiConvertPointer (0x0, (VOID **)&mFvbModuleGlobal);=0D + QemuFlashConvertPointers ();=0D +}=0D +=0D +=0D +VOID=0D +InstallVirtualAddressChangeHandler (=0D + VOID=0D + )=0D +{=0D + EFI_STATUS Status;=0D + EFI_EVENT VirtualAddressChangeEvent;=0D +=0D + Status =3D gBS->CreateEventEx (=0D + EVT_NOTIFY_SIGNAL,=0D + TPL_NOTIFY,=0D + FvbVirtualAddressChangeEvent,=0D + NULL,=0D + &gEfiEventVirtualAddressChangeGuid,=0D + &VirtualAddressChangeEvent=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +}=0D diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbService= sRuntimeDxe/QemuFlash.c b/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFl= ashFvbServicesRuntimeDxe/QemuFlash.c new file mode 100644 index 0000000000..a85d736060 --- /dev/null +++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntim= eDxe/QemuFlash.c @@ -0,0 +1,251 @@ +/** @file=0D + LoongArch support for QEMU system firmware flash device=0D +=0D + Copyright (c) 2021 Loongson Technology Corporation Limited. All rights r= eserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#include =0D +#include =0D +#include =0D +=0D +#include "QemuFlash.h"=0D +=0D +#define WRITE_BYTE_CMD 0x10=0D +#define BLOCK_ERASE_CMD 0x20=0D +#define CLEAR_STATUS_CMD 0x50=0D +#define READ_STATUS_CMD 0x70=0D +#define READ_DEVID_CMD 0x90=0D +#define BLOCK_ERASE_CONFIRM_CMD 0xd0=0D +#define READ_ARRAY_CMD 0xff=0D +=0D +#define CLEARED_ARRAY_STATUS 0x00=0D +=0D +UINT8 *mFlashBase;=0D +=0D +STATIC UINTN mFdBlockSize =3D 0;=0D +STATIC UINTN mFdBlockCount =3D 0;=0D +=0D +STATIC=0D +volatile UINT8 *=0D +QemuFlashPtr (=0D + IN EFI_LBA Lba,=0D + IN UINTN Offset=0D + )=0D +{=0D + return mFlashBase + ((UINTN)Lba * mFdBlockSize) + Offset;=0D +}=0D +=0D +=0D +/**=0D + Determines if the QEMU flash memory device is present.=0D +=0D + @retval FALSE The QEMU flash device is not present.=0D + @retval TRUE The QEMU flash device is present.=0D +=0D +**/=0D +STATIC=0D +BOOLEAN=0D +QemuFlashDetected (=0D + VOID=0D + )=0D +{=0D + BOOLEAN FlashDetected;=0D + volatile UINT8 *Ptr;=0D +=0D + UINTN Offset;=0D + UINT8 OriginalUint8;=0D + UINT8 ProbeUint8;=0D +=0D + FlashDetected =3D FALSE;=0D + Ptr =3D QemuFlashPtr (0, 0);=0D +=0D + for (Offset =3D 0; Offset < mFdBlockSize; Offset++) {=0D + Ptr =3D QemuFlashPtr (0, Offset);=0D + ProbeUint8 =3D *Ptr;=0D + if ((ProbeUint8 !=3D CLEAR_STATUS_CMD) &&=0D + (ProbeUint8 !=3D READ_STATUS_CMD) &&=0D + (ProbeUint8 !=3D CLEARED_ARRAY_STATUS))=0D + {=0D + break;=0D + }=0D + }=0D +=0D + if (Offset >=3D mFdBlockSize) {=0D + DEBUG ((DEBUG_INFO, "QEMU Flash: Failed to find probe location\n"));=0D + return FALSE;=0D + }=0D +=0D + DEBUG ((DEBUG_INFO, "QEMU Flash: Attempting flash detection at %p\n", Pt= r));=0D +=0D + OriginalUint8 =3D *Ptr;=0D + *Ptr =3D CLEAR_STATUS_CMD;=0D + ProbeUint8 =3D *Ptr;=0D + if ((OriginalUint8 !=3D CLEAR_STATUS_CMD) &&=0D + (ProbeUint8 =3D=3D CLEAR_STATUS_CMD))=0D + {=0D + DEBUG ((DEBUG_INFO, "QemuFlashDetected =3D> FD behaves as RAM\n"));=0D + *Ptr =3D OriginalUint8;=0D + } else {=0D + *Ptr =3D READ_STATUS_CMD;=0D + ProbeUint8 =3D *Ptr;=0D + if (ProbeUint8 =3D=3D OriginalUint8) {=0D + DEBUG ((DEBUG_INFO, "QemuFlashDetected =3D> FD behaves as ROM\n"));= =0D + } else if (ProbeUint8 =3D=3D READ_STATUS_CMD) {=0D + DEBUG ((DEBUG_INFO, "QemuFlashDetected =3D> FD behaves as RAM\n"));= =0D + *Ptr =3D OriginalUint8;=0D + } else if (ProbeUint8 =3D=3D CLEARED_ARRAY_STATUS) {=0D + DEBUG ((DEBUG_INFO, "QemuFlashDetected =3D> FD behaves as FLASH\n"))= ;=0D + FlashDetected =3D TRUE;=0D + *Ptr =3D READ_ARRAY_CMD;=0D + }=0D + }=0D +=0D + DEBUG ((=0D + DEBUG_INFO,=0D + "QemuFlashDetected =3D> %a\n",=0D + FlashDetected ? "Yes" : "No"=0D + ));=0D + return FlashDetected;=0D +}=0D +=0D +=0D +/**=0D + Read from QEMU Flash=0D +=0D + @param[in] Lba The starting logical block index to read from.=0D + @param[in] Offset Offset into the block at which to begin reading.=0D + @param[in] NumBytes On input, indicates the requested read size. On=0D + output, indicates the actual number of bytes read=0D + @param[in] Buffer Pointer to the buffer to read into.=0D +=0D +**/=0D +EFI_STATUS=0D +QemuFlashRead (=0D + IN EFI_LBA Lba,=0D + IN UINTN Offset,=0D + IN UINTN *NumBytes,=0D + IN UINT8 *Buffer=0D + )=0D +{=0D + UINT8 *Ptr;=0D +=0D + //=0D + // Only write to the first 64k. We don't bother saving the FTW Spare=0D + // block into the flash memory.=0D + //=0D + if (Lba >=3D mFdBlockCount) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + //=0D + // Get flash address=0D + //=0D + Ptr =3D (UINT8 *)QemuFlashPtr (Lba, Offset);=0D +=0D + CopyMem (Buffer, Ptr, *NumBytes);=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +=0D +/**=0D + Write to QEMU Flash=0D +=0D + @param[in] Lba The starting logical block index to write to.=0D + @param[in] Offset Offset into the block at which to begin writing.=0D + @param[in] NumBytes On input, indicates the requested write size. On=0D + output, indicates the actual number of bytes written= =0D + @param[in] Buffer Pointer to the data to write.=0D +=0D +**/=0D +EFI_STATUS=0D +QemuFlashWrite (=0D + IN EFI_LBA Lba,=0D + IN UINTN Offset,=0D + IN UINTN *NumBytes,=0D + IN UINT8 *Buffer=0D + )=0D +{=0D + volatile UINT8 *Ptr;=0D + UINTN Loop;=0D +=0D + //=0D + // Only write to the first 64k. We don't bother saving the FTW Spare=0D + // block into the flash memory.=0D + //=0D + if (Lba >=3D mFdBlockCount) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + //=0D + // Program flash=0D + //=0D + Ptr =3D QemuFlashPtr (Lba, Offset);=0D + for (Loop =3D 0; Loop < *NumBytes; Loop++) {=0D + *Ptr =3D WRITE_BYTE_CMD;=0D + *Ptr =3D Buffer[Loop];=0D + Ptr++;=0D + }=0D +=0D + //=0D + // Restore flash to read mode=0D + //=0D + if (*NumBytes > 0) {=0D + *(Ptr - 1) =3D READ_ARRAY_CMD;=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +=0D +/**=0D + Erase a QEMU Flash block=0D +=0D + @param Lba The logical block index to erase.=0D +=0D +**/=0D +EFI_STATUS=0D +QemuFlashEraseBlock (=0D + IN EFI_LBA Lba=0D + )=0D +{=0D + volatile UINT8 *Ptr;=0D +=0D + if (Lba >=3D mFdBlockCount) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + Ptr =3D QemuFlashPtr (Lba, 0);=0D + *Ptr =3D BLOCK_ERASE_CMD;=0D + *Ptr =3D BLOCK_ERASE_CONFIRM_CMD;=0D + return EFI_SUCCESS;=0D +}=0D +=0D +=0D +/**=0D + Initializes QEMU flash memory support=0D +=0D + @retval EFI_WRITE_PROTECTED The QEMU flash device is not present.=0D + @retval EFI_SUCCESS The QEMU flash device is supported.=0D +=0D +**/=0D +EFI_STATUS=0D +QemuFlashInitialize (=0D + VOID=0D + )=0D +{=0D + mFlashBase =3D (UINT8 *)(UINTN)PcdGet64 (PcdOvmfFlashNvStorageVariable= Base);=0D + mFdBlockSize =3D PcdGet32 (PcdFlashBlockSize);=0D + ASSERT(PcdGet32 (PcdAllVarSize) % mFdBlockSize =3D=3D 0);=0D + mFdBlockCount =3D PcdGet32 (PcdAllVarSize) / mFdBlockSize;=0D +=0D + if (!QemuFlashDetected ()) {=0D + return EFI_WRITE_PROTECTED;=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbService= sRuntimeDxe/QemuFlash.h b/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFl= ashFvbServicesRuntimeDxe/QemuFlash.h new file mode 100644 index 0000000000..27caabc5f0 --- /dev/null +++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntim= eDxe/QemuFlash.h @@ -0,0 +1,86 @@ +/** @file=0D + LoongArch support for QEMU system firmware flash device=0D +=0D + Copyright (c) 2021 Loongson Technology Corporation Limited. All rights r= eserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#ifndef __QEMU_FLASH_H__=0D +#define __QEMU_FLASH_H__=0D +=0D +#include =0D +=0D +extern UINT8 *mFlashBase;=0D +=0D +/**=0D + Read from QEMU Flash=0D +=0D + @param[in] Lba The starting logical block index to read from.=0D + @param[in] Offset Offset into the block at which to begin reading.=0D + @param[in] NumBytes On input, indicates the requested read size. On=0D + output, indicates the actual number of bytes read=0D + @param[in] Buffer Pointer to the buffer to read into.=0D +=0D +**/=0D +EFI_STATUS=0D +QemuFlashRead (=0D + IN EFI_LBA Lba,=0D + IN UINTN Offset,=0D + IN UINTN *NumBytes,=0D + IN UINT8 *Buffer=0D + );=0D +=0D +=0D +/**=0D + Write to QEMU Flash=0D +=0D + @param[in] Lba The starting logical block index to write to.=0D + @param[in] Offset Offset into the block at which to begin writing.=0D + @param[in] NumBytes On input, indicates the requested write size. On=0D + output, indicates the actual number of bytes written= =0D + @param[in] Buffer Pointer to the data to write.=0D +=0D +**/=0D +EFI_STATUS=0D +QemuFlashWrite (=0D + IN EFI_LBA Lba,=0D + IN UINTN Offset,=0D + IN UINTN *NumBytes,=0D + IN UINT8 *Buffer=0D + );=0D +=0D +=0D +/**=0D + Erase a QEMU Flash block=0D +=0D + @param Lba The logical block index to erase.=0D +=0D +**/=0D +EFI_STATUS=0D +QemuFlashEraseBlock (=0D + IN EFI_LBA Lba=0D + );=0D +=0D +=0D +/**=0D + Initializes QEMU flash memory support=0D +=0D + @retval EFI_WRITE_PROTECTED The QEMU flash device is not present.=0D + @retval EFI_SUCCESS The QEMU flash device is supported.=0D +=0D +**/=0D +EFI_STATUS=0D +QemuFlashInitialize (=0D + VOID=0D + );=0D +=0D +=0D +VOID=0D +QemuFlashConvertPointers (=0D + VOID=0D + );=0D +=0D +#endif=0D +=0D diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbService= sRuntimeDxe/QemuFlashDxe.c b/Platform/Loongson/LoongArchQemuPkg/Drivers/Qem= uFlashFvbServicesRuntimeDxe/QemuFlashDxe.c new file mode 100644 index 0000000000..b63314aac2 --- /dev/null +++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntim= eDxe/QemuFlashDxe.c @@ -0,0 +1,21 @@ +/** @file=0D + LoongArch support for QEMU system firmware flash device: functions speci= fic to the=0D + runtime DXE driver build.=0D +=0D + Copyright (c) 2021 Loongson Technology Corporation Limited. All rights r= eserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#include =0D +=0D +#include "QemuFlash.h"=0D +=0D +VOID=0D +QemuFlashConvertPointers (=0D + VOID=0D + )=0D +{=0D + EfiConvertPointer (0x0, (VOID **)&mFlashBase);=0D +}=0D diff --git a/Platform/Loongson/LoongArchQemuPkg/Loongson.dsc b/Platform/Loo= ngson/LoongArchQemuPkg/Loongson.dsc index 578b80b7b0..ed06558f18 100644 --- a/Platform/Loongson/LoongArchQemuPkg/Loongson.dsc +++ b/Platform/Loongson/LoongArchQemuPkg/Loongson.dsc @@ -171,10 +171,10 @@ VirtioLib | OvmfPkg/Library/VirtioLib/VirtioLib.i= nf=0D FrameBufferBltLib | MdeModulePkg/Library/FrameBufferBltLi= b/FrameBufferBltLib.inf=0D QemuFwCfgLib | OvmfPkg/Library/QemuFwCfgLib/QemuFwCf= gLibMmio.inf=0D -=0D DebugLib | MdePkg/Library/BaseDebugLibSerialPort= /BaseDebugLibSerialPort.inf=0D -=0D PeiServicesLib | MdePkg/Library/PeiServicesLib/PeiServ= icesLib.inf=0D + VariableFlashInfoLib | MdeModulePkg/Library/BaseVariableFlas= hInfoLib/BaseVariableFlashInfoLib.inf=0D +=0D [LibraryClasses.common.SEC]=0D ReportStatusCodeLib | MdeModulePkg/Library/PeiReportStatusC= odeLib/PeiReportStatusCodeLib.inf=0D HobLib | MdePkg/Library/PeiHobLib/PeiHobLib.in= f=0D --=20 2.31.1