/** @file Copyright (c) 2011 - 2013, Intel Corporation. All rights reserved.
Copyright (C) 2013, Red Hat, Inc. Copyright (c) 2017, AMD Incorporated. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "Uefi.h" #include #include #include #include #include #include #include #include "QemuFwCfgLibInternal.h" /** 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 ) { DEBUG ((DEBUG_INFO, "Select Item: 0x%x\n", (UINT16)(UINTN) QemuFwCfgItem)); IoWrite16 (FW_CFG_IO_SELECTOR, (UINT16)(UINTN) 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) **/ VOID EFIAPI InternalQemuFwCfgReadBytes ( IN UINTN Size, IN VOID *Buffer OPTIONAL ) { if (InternalQemuFwCfgDmaIsAvailable () && Size <= MAX_UINT32) { InternalQemuFwCfgDmaBytes ((UINT32)Size, Buffer, FW_CFG_DMA_CTL_READ); return; } IoReadFifo8 (FW_CFG_IO_DATA, Size, Buffer); } /** 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 ()) { if (InternalQemuFwCfgDmaIsAvailable () && Size <= MAX_UINT32) { InternalQemuFwCfgDmaBytes ((UINT32)Size, Buffer, FW_CFG_DMA_CTL_WRITE); return; } IoWriteFifo8 (FW_CFG_IO_DATA, Size, Buffer); } } /** Skip bytes in the firmware configuration item. Increase the offset of the firmware configuration item without transferring bytes between the item and a caller-provided buffer. Subsequent read, write or skip operations will commence at the increased offset. @param[in] Size Number of bytes to skip. **/ VOID EFIAPI QemuFwCfgSkipBytes ( IN UINTN Size ) { UINTN ChunkSize; UINT8 SkipBuffer[256]; if (!InternalQemuFwCfgIsAvailable ()) { return; } if (InternalQemuFwCfgDmaIsAvailable () && Size <= MAX_UINT32) { InternalQemuFwCfgDmaBytes ((UINT32)Size, NULL, FW_CFG_DMA_CTL_SKIP); return; } // // Emulate the skip by reading data in chunks, and throwing it away. The // implementation below is suitable even for phases where RAM or dynamic // allocation is not available or appropriate. It also doesn't affect the // static data footprint for client modules. Large skips are not expected, // therefore this fallback is not performance critical. The size of // SkipBuffer is thought not to exert a large pressure on the stack in any // phase. // while (Size > 0) { ChunkSize = MIN (Size, sizeof SkipBuffer); IoReadFifo8 (FW_CFG_IO_DATA, ChunkSize, SkipBuffer); Size -= ChunkSize; } } /** 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. @return RETURN_SUCCESS If file is found. RETURN_NOT_FOUND If file is not found. 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; UINT16 FileReserved; CHAR8 FName[QEMU_FW_CFG_FNAME_SIZE]; FileSize = QemuFwCfgRead32 (); FileSelect = QemuFwCfgRead16 (); FileReserved = QemuFwCfgRead16 (); (VOID) FileReserved; /* Force a do-nothing reference. */ InternalQemuFwCfgReadBytes (sizeof (FName), FName); if (AsciiStrCmp (Name, FName) == 0) { *Item = SwapBytes16 (FileSelect); *Size = SwapBytes32 (FileSize); return RETURN_SUCCESS; } } return RETURN_NOT_FOUND; }