From 6e2543b01d0cbd16b3fbcc6f12f6938d8c12bcc8 Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Fri, 2 Jan 2015 12:04:15 +0000 Subject: [PATCH] ArmVirtualizationPkg: introduce QemuFwCfgLib instance for DXE drivers After reviewing OvmfPkg's use of its own QemuFwCfgLib instances, it is clear that its only pre-DXE fw_cfg dependency concerns S3 support (the QemuFwCfgS3Enabled() call in "PlatformPei/Platform.c"). For ARM guests, S3 is in the distant future, but we can see several shorter term applications for fw_cfg that all reside in DXE: - controlling boot order (to be implemented in PlatformBdsLib for Intel BDS), - supporting -kernel / -initrd / -append boot on QEMU (to be implemented in PlatformBdsLib for Intel BDS, similarly), - loading and linking ACPI tables, - installing SMBIOS tables. Therefore it makes sense to add a simple MMIO-based fw_cfg client library to ArmVirtualizationPkg that for the moment is only available to DXE_DRIVER modules. Because MMIO accesses are costly on KVM/ARM, InternalQemuFwCfgReadBytes() accesses the fw_cfg data register in full words. This speeds up transfers almost linearly. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16567 6f19259b-4bc3-4df7-8a09-765794883524 --- .../ArmVirtualizationQemu.dsc | 1 + .../Library/QemuFwCfgLib/QemuFwCfgLib.c | 358 ++++++++++++++++++ .../Library/QemuFwCfgLib/QemuFwCfgLib.inf | 52 +++ 3 files changed, 411 insertions(+) create mode 100644 ArmPlatformPkg/ArmVirtualizationPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c create mode 100644 ArmPlatformPkg/ArmVirtualizationPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf diff --git a/ArmPlatformPkg/ArmVirtualizationPkg/ArmVirtualizationQemu.dsc b/ArmPlatformPkg/ArmVirtualizationPkg/ArmVirtualizationQemu.dsc index d23832fc01..c18b7a0609 100644 --- a/ArmPlatformPkg/ArmVirtualizationPkg/ArmVirtualizationQemu.dsc +++ b/ArmPlatformPkg/ArmVirtualizationPkg/ArmVirtualizationQemu.dsc @@ -42,6 +42,7 @@ # Virtio Support VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf VirtioMmioDeviceLib|OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceLib.inf + QemuFwCfgLib|ArmPlatformPkg/ArmVirtualizationPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf ArmPlatformLib|ArmPlatformPkg/ArmVirtualizationPkg/Library/ArmVirtualizationPlatformLib/ArmVirtualizationPlatformLib.inf ArmPlatformSysConfigLib|ArmPlatformPkg/Library/ArmPlatformSysConfigLibNull/ArmPlatformSysConfigLibNull.inf diff --git a/ArmPlatformPkg/ArmVirtualizationPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c b/ArmPlatformPkg/ArmVirtualizationPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c new file mode 100644 index 0000000000..e9e96d7a8d --- /dev/null +++ b/ArmPlatformPkg/ArmVirtualizationPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c @@ -0,0 +1,358 @@ +/** @file + + Stateful and implicitly initialized fw_cfg library implementation. + + Copyright (C) 2013 - 2014, Red Hat, Inc. + Copyright (c) 2011 - 2013, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License which accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +**/ + +#include +#include +#include +#include +#include + +STATIC UINTN mFwCfgSelectorAddress; +STATIC UINTN mFwCfgDataAddress; + + +/** + Returns a boolean indicating if the firmware configuration interface is + available for library-internal purposes. + + This function never changes fw_cfg state. + + @retval TRUE The interface is available internally. + @retval FALSE The interface is not available internally. +**/ +BOOLEAN +EFIAPI +InternalQemuFwCfgIsAvailable ( + VOID + ) +{ + return (BOOLEAN)(mFwCfgSelectorAddress != 0 && mFwCfgDataAddress != 0); +} + + +/** + Returns a boolean indicating if the firmware configuration interface + is available or not. + + This function may change fw_cfg state. + + @retval TRUE The interface is available + @retval FALSE The interface is not available + +**/ +BOOLEAN +EFIAPI +QemuFwCfgIsAvailable ( + VOID + ) +{ + return InternalQemuFwCfgIsAvailable (); +} + + +RETURN_STATUS +EFIAPI +QemuFwCfgInitialize ( + VOID + ) +{ + mFwCfgSelectorAddress = (UINTN)PcdGet64 (PcdFwCfgSelectorAddress); + mFwCfgDataAddress = (UINTN)PcdGet64 (PcdFwCfgDataAddress); + + if (InternalQemuFwCfgIsAvailable ()) { + UINT32 Signature; + + QemuFwCfgSelectItem (QemuFwCfgItemSignature); + Signature = QemuFwCfgRead32 (); + if (Signature != SIGNATURE_32 ('Q', 'E', 'M', 'U')) { + mFwCfgSelectorAddress = 0; + mFwCfgDataAddress = 0; + } + } + return RETURN_SUCCESS; +} + + +/** + Selects a firmware configuration item for reading. + + Following this call, any data read from this item will start from the + beginning of the configuration item's data. + + @param[in] QemuFwCfgItem Firmware Configuration item to read + +**/ +VOID +EFIAPI +QemuFwCfgSelectItem ( + IN FIRMWARE_CONFIG_ITEM QemuFwCfgItem + ) +{ + if (InternalQemuFwCfgIsAvailable ()) { + MmioWrite16 (mFwCfgSelectorAddress, SwapBytes16 ((UINT16)QemuFwCfgItem)); + } +} + + +/** + Reads firmware configuration bytes into a buffer + + @param[in] Size Size in bytes to read + @param[in] Buffer Buffer to store data into (OPTIONAL if Size is 0) + +**/ +STATIC +VOID +EFIAPI +InternalQemuFwCfgReadBytes ( + IN UINTN Size, + IN VOID *Buffer OPTIONAL + ) +{ + UINTN Left; + UINT8 *Ptr; + UINT8 *End; + +#ifdef MDE_CPU_AARCH64 + Left = Size & 7; +#else + Left = Size & 3; +#endif + + Size -= Left; + Ptr = Buffer; + End = Ptr + Size; + +#ifdef MDE_CPU_AARCH64 + while (Ptr < End) { + *(UINT64 *)Ptr = MmioRead64 (mFwCfgDataAddress); + Ptr += 8; + } + if (Left & 4) { + *(UINT32 *)Ptr = MmioRead32 (mFwCfgDataAddress); + Ptr += 4; + } +#else + while (Ptr < End) { + *(UINT32 *)Ptr = MmioRead32 (mFwCfgDataAddress); + Ptr += 4; + } +#endif + + if (Left & 2) { + *(UINT16 *)Ptr = MmioRead16 (mFwCfgDataAddress); + Ptr += 2; + } + if (Left & 1) { + *Ptr = MmioRead8 (mFwCfgDataAddress); + } +} + + +/** + Reads firmware configuration bytes into a buffer + + If called multiple times, then the data read will continue at the offset of + the firmware configuration item where the previous read ended. + + @param[in] Size Size in bytes to read + @param[in] Buffer Buffer to store data into + +**/ +VOID +EFIAPI +QemuFwCfgReadBytes ( + IN UINTN Size, + IN VOID *Buffer + ) +{ + if (InternalQemuFwCfgIsAvailable ()) { + InternalQemuFwCfgReadBytes (Size, Buffer); + } else { + ZeroMem (Buffer, Size); + } +} + +/** + Write firmware configuration bytes from a buffer + + If called multiple times, then the data written will continue at the offset + of the firmware configuration item where the previous write ended. + + @param[in] Size Size in bytes to write + @param[in] Buffer Buffer to read data from + +**/ +VOID +EFIAPI +QemuFwCfgWriteBytes ( + IN UINTN Size, + IN VOID *Buffer + ) +{ + if (InternalQemuFwCfgIsAvailable ()) { + UINTN Idx; + + for (Idx = 0; Idx < Size; ++Idx) { + MmioWrite8 (mFwCfgDataAddress, ((UINT8 *)Buffer)[Idx]); + } + } +} + + +/** + Reads a UINT8 firmware configuration value + + @return Value of Firmware Configuration item read + +**/ +UINT8 +EFIAPI +QemuFwCfgRead8 ( + VOID + ) +{ + UINT8 Result; + + QemuFwCfgReadBytes (sizeof Result, &Result); + return Result; +} + + +/** + Reads a UINT16 firmware configuration value + + @return Value of Firmware Configuration item read + +**/ +UINT16 +EFIAPI +QemuFwCfgRead16 ( + VOID + ) +{ + UINT16 Result; + + QemuFwCfgReadBytes (sizeof Result, &Result); + return Result; +} + + +/** + Reads a UINT32 firmware configuration value + + @return Value of Firmware Configuration item read + +**/ +UINT32 +EFIAPI +QemuFwCfgRead32 ( + VOID + ) +{ + UINT32 Result; + + QemuFwCfgReadBytes (sizeof Result, &Result); + return Result; +} + + +/** + Reads a UINT64 firmware configuration value + + @return Value of Firmware Configuration item read + +**/ +UINT64 +EFIAPI +QemuFwCfgRead64 ( + VOID + ) +{ + UINT64 Result; + + QemuFwCfgReadBytes (sizeof Result, &Result); + return Result; +} + + +/** + Find the configuration item corresponding to the firmware configuration file. + + @param[in] Name Name of file to look up. + @param[out] Item Configuration item corresponding to the file, to be passed + to QemuFwCfgSelectItem (). + @param[out] Size Number of bytes in the file. + + @retval RETURN_SUCCESS If file is found. + @retval RETURN_NOT_FOUND If file is not found. + @retval RETURN_UNSUPPORTED If firmware configuration is unavailable. + +**/ +RETURN_STATUS +EFIAPI +QemuFwCfgFindFile ( + IN CONST CHAR8 *Name, + OUT FIRMWARE_CONFIG_ITEM *Item, + OUT UINTN *Size + ) +{ + UINT32 Count; + UINT32 Idx; + + if (!InternalQemuFwCfgIsAvailable ()) { + return RETURN_UNSUPPORTED; + } + + QemuFwCfgSelectItem (QemuFwCfgItemFileDir); + Count = SwapBytes32 (QemuFwCfgRead32 ()); + + for (Idx = 0; Idx < Count; ++Idx) { + UINT32 FileSize; + UINT16 FileSelect; + CHAR8 FName[QEMU_FW_CFG_FNAME_SIZE]; + + FileSize = QemuFwCfgRead32 (); + FileSelect = QemuFwCfgRead16 (); + QemuFwCfgRead16 (); // skip the field called "reserved" + InternalQemuFwCfgReadBytes (sizeof (FName), FName); + + if (AsciiStrCmp (Name, FName) == 0) { + *Item = SwapBytes16 (FileSelect); + *Size = SwapBytes32 (FileSize); + return RETURN_SUCCESS; + } + } + + return RETURN_NOT_FOUND; +} + + +/** + Determine if S3 support is explicitly enabled. + + @retval TRUE if S3 support is explicitly enabled. + FALSE otherwise. This includes unavailability of the firmware + configuration interface. +**/ +BOOLEAN +EFIAPI +QemuFwCfgS3Enabled ( + VOID + ) +{ + return FALSE; +} diff --git a/ArmPlatformPkg/ArmVirtualizationPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf b/ArmPlatformPkg/ArmVirtualizationPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf new file mode 100644 index 0000000000..21ab2bf186 --- /dev/null +++ b/ArmPlatformPkg/ArmVirtualizationPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf @@ -0,0 +1,52 @@ +## @file +# +# Stateful, implicitly initialized fw_cfg library. +# +# Copyright (C) 2013 - 2014, Red Hat, Inc. +# Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials are licensed and made available +# under the terms and conditions of the BSD License which accompanies this +# distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR +# IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = QemuFwCfgLib + FILE_GUID = B271F41F-B841-48A9-BA8D-545B4BC2E2BF + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = QemuFwCfgLib|DXE_DRIVER + + CONSTRUCTOR = QemuFwCfgInitialize + +# +# The following information is for reference only and not required by the build +# tools. +# +# VALID_ARCHITECTURES = ARM AARCH64 +# + +[Sources] + QemuFwCfgLib.c + +[Packages] + MdePkg/MdePkg.dec + OvmfPkg/OvmfPkg.dec + ArmPlatformPkg/ArmVirtualizationPkg/ArmVirtualizationPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + IoLib + PcdLib + +[Pcd] + gArmVirtualizationTokenSpaceGuid.PcdFwCfgSelectorAddress + gArmVirtualizationTokenSpaceGuid.PcdFwCfgDataAddress -- 2.39.2