From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by mx.groups.io with SMTP id smtpd.web10.39394.1666004450099754151 for ; Mon, 17 Oct 2022 04:00:50 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=ZJ7mHThL; spf=pass (domain: kernel.org, ip: 139.178.84.217, mailfrom: ardb@kernel.org) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 1BD5861050 for ; Mon, 17 Oct 2022 11:00:49 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9B059C4347C for ; Mon, 17 Oct 2022 11:00:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1666004448; bh=OPmWZChFIn8Y1s1q6f0XdQ5MvGNuNS23DEt7irlGB4U=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=ZJ7mHThLK0vCgsjy5pHj4wf78ObFyIySh/43McDmTHZtDCi3AM8UD6bFmCAzweskM hNv0ls+QR23zibQwpm31Yec6JJRbUrdZf5YtMYqA+RIY47QSUqbJdmoAJs/D791kI5 jIiENUaTg/xyT/2u3AwZNiKxoncIkBTHrMxOtqREsKXnLEr+EsQz3/KhFWSFbjtZyH Jr+8gtAeMMJXjMHVqHBDq2iUJs7o3YSGTueCtQOb13JckphPLLBHfKZBz/WlalMIPh xRgRg24swks0Goo1LYDE+6afYHWRDfqIRq2kWq8ZMy0gHRoAgHPOZ/cv7vVKHM5Yju jnJggiPn3SISw== Received: by mail-lf1-f52.google.com with SMTP id f37so16874752lfv.8 for ; Mon, 17 Oct 2022 04:00:47 -0700 (PDT) X-Gm-Message-State: ACrzQf1FQRgPm2xVGrPBKEGN2/RBjQBwywKR+c4il9NXZuLltT82plMT waHgNAnJG7m4J9bN80ThAoeMosZ86MfqSMkX7VA= X-Google-Smtp-Source: AMsMyM7HFvpp8dVZojBcNOdcELRuTDdUMZdmYmrSPvPoPPqNFnUmHW5cDWa24tVj+b6QIqkI0wEw4bfHb37M27a9nSk= X-Received: by 2002:a05:6512:314a:b0:4a2:d0b9:aa20 with SMTP id s10-20020a056512314a00b004a2d0b9aa20mr4268078lfi.110.1666004444989; Mon, 17 Oct 2022 04:00:44 -0700 (PDT) MIME-Version: 1.0 References: <51ef7b9ee8b9ab9829b975aae3d751b819b2704e.1665719826.git.lixianglai@loongson.cn> In-Reply-To: <51ef7b9ee8b9ab9829b975aae3d751b819b2704e.1665719826.git.lixianglai@loongson.cn> From: "Ard Biesheuvel" Date: Mon, 17 Oct 2022 13:00:33 +0200 X-Gmail-Original-Message-ID: Message-ID: Subject: Re: [edk2-platforms][PATCH V3 15/16] Platform/Loongson: Add QemuFlashFvbServicesRuntimeDxe driver. To: xianglai li Cc: devel@edk2.groups.io, quic_llindhol@quicinc.com, michael.d.kinney@intel.com, kraxel@redhat.com, maobibo@loongson.cn Content-Type: text/plain; charset="UTF-8" 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 >