123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463 |
- /** @file
- Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- @par Glossary:
- - FwCfg - firmWare Configure
- - CTL - Control
- **/
- #include "Uefi.h"
- #include <Library/BaseLib.h>
- #include <Library/BaseMemoryLib.h>
- #include <Library/DebugLib.h>
- #include <Library/IoLib.h>
- #include <Library/QemuFwCfgLib.h>
- #include <Library/MemoryAllocationLib.h>
- #include <Library/UefiBootServicesTableLib.h>
- #include <Library/PcdLib.h>
- #include <libfdt.h>
- #include "QemuFwCfgLibInternal.h"
- STATIC UINTN mFwCfgSelectorAddress;
- STATIC UINTN mFwCfgDataAddress;
- /**
- To get firmware configure selector address.
- @param VOID
- @retval firmware configure selector address
- **/
- UINTN
- EFIAPI
- QemuGetFwCfgSelectorAddress (
- VOID
- )
- {
- UINTN FwCfgSelectorAddress = mFwCfgSelectorAddress;
- if (FwCfgSelectorAddress == 0) {
- FwCfgSelectorAddress = (UINTN)PcdGet64 (PcdFwCfgSelectorAddress);
- }
- return FwCfgSelectorAddress;
- }
- /**
- To get firmware configure Data address.
- @param VOID
- @retval firmware configure data address
- **/
- UINTN
- EFIAPI
- QemuGetFwCfgDataAddress (
- VOID
- )
- {
- UINTN FwCfgDataAddress = mFwCfgDataAddress;
- if (FwCfgDataAddress == 0) {
- FwCfgDataAddress = (UINTN)PcdGet64 (PcdFwCfgDataAddress);
- }
- return FwCfgDataAddress;
- }
- /**
- 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
- )
- {
- UINTN FwCfgSelectorAddress;
- FwCfgSelectorAddress = QemuGetFwCfgSelectorAddress ();
- MmioWrite16 (FwCfgSelectorAddress, SwapBytes16((UINT16) (UINTN)QemuFwCfgItem));
- }
- /**
- Slow READ_BYTES_FUNCTION.
- @param[in] The size of the data to be read.
- @param[in] Buffer The buffer that stores the readout data.
- **/
- VOID
- EFIAPI
- MmioReadBytes (
- IN UINTN Size,
- IN VOID *Buffer OPTIONAL
- )
- {
- UINTN Left;
- UINT8 *Ptr;
- UINT8 *End;
- UINTN FwCfgDataAddress;
- Left = Size & 7;
- Size -= Left;
- Ptr = Buffer;
- End = Ptr + Size;
- FwCfgDataAddress = QemuGetFwCfgDataAddress ();
- while (Ptr < End) {
- *(UINT64 *)Ptr = MmioRead64 (FwCfgDataAddress);
- Ptr += 8;
- }
- if (Left & 4) {
- *(UINT32 *)Ptr = MmioRead32 (FwCfgDataAddress);
- Ptr += 4;
- }
- if (Left & 2) {
- *(UINT16 *)Ptr = MmioRead16 (FwCfgDataAddress);
- Ptr += 2;
- }
- if (Left & 1) {
- *Ptr = MmioRead8 (FwCfgDataAddress);
- }
- }
- /**
- Slow WRITE_BYTES_FUNCTION.
- @param[in] The size of the data to be write.
- @param[in] Buffer The buffer that stores the writein data.
- **/
- VOID
- EFIAPI
- MmioWriteBytes (
- IN UINTN Size,
- IN VOID *Buffer OPTIONAL
- )
- {
- UINTN Idx;
- UINTN FwCfgDataAddress;
- FwCfgDataAddress = QemuGetFwCfgDataAddress ();
- for (Idx = 0; Idx < Size; ++Idx) {
- MmioWrite8 (FwCfgDataAddress, ((UINT8 *)Buffer)[Idx]);
- }
- }
- /**
- 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;
- }
- MmioReadBytes (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;
- }
- MmioWriteBytes (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);
- MmioReadBytes (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;
- CHAR8 FileName[QEMU_FW_CFG_FNAME_SIZE];
- FileSize = QemuFwCfgRead32 ();
- FileSelect = QemuFwCfgRead16 ();
- QemuFwCfgRead16 (); // skip the field called "reserved"
- InternalQemuFwCfgReadBytes (sizeof (FileName), FileName);
- if (AsciiStrCmp (Name, FileName) == 0) {
- *Item = SwapBytes16 (FileSelect);
- *Size = SwapBytes32 (FileSize);
- return RETURN_SUCCESS;
- }
- }
- return RETURN_NOT_FOUND;
- }
- /**
- firmware config initialize.
- @param VOID
- @return RETURN_SUCCESS Initialization succeeded.
- **/
- RETURN_STATUS
- EFIAPI
- QemuFwCfgInitialize (
- VOID
- )
- {
- VOID *DeviceTreeBase;
- INT32 Node;
- INT32 Prev;
- CONST CHAR8 *Type;
- INT32 Len;
- CONST UINT64 *RegProp;
- UINT64 FwCfgSelectorAddress;
- UINT64 FwCfgDataAddress;
- UINT64 FwCfgDataSize;
- RETURN_STATUS PcdStatus;
- DeviceTreeBase = (VOID *) (UINTN)PcdGet64 (PcdDeviceTreeBase);
- ASSERT (DeviceTreeBase != NULL);
- //
- // Make sure we have a valid device tree blob
- //
- ASSERT (fdt_check_header (DeviceTreeBase) == 0);
- for (Prev = 0;; Prev = Node) {
- Node = fdt_next_node (DeviceTreeBase, Prev, NULL);
- if (Node < 0) {
- break;
- }
- //
- // Check for memory node
- //
- Type = fdt_getprop (DeviceTreeBase, Node, "compatible", &Len);
- if ((Type)
- && (AsciiStrnCmp (Type, "qemu,fw-cfg-mmio", Len) == 0))
- {
- //
- // Get the 'reg' property of this node. For now, we will assume
- // two 8 byte quantities for base and size, respectively.
- //
- RegProp = fdt_getprop (DeviceTreeBase, Node, "reg", &Len);
- if ((RegProp != 0)
- && (Len == (2 * sizeof (UINT64))))
- {
- FwCfgDataAddress = SwapBytes64 (RegProp[0]);
- FwCfgDataSize = 8;
- FwCfgSelectorAddress = FwCfgDataAddress + FwCfgDataSize;
- mFwCfgSelectorAddress = FwCfgSelectorAddress;
- mFwCfgDataAddress = FwCfgDataAddress;
- PcdStatus = PcdSet64S (
- PcdFwCfgSelectorAddress,
- FwCfgSelectorAddress
- );
- ASSERT_RETURN_ERROR (PcdStatus);
- PcdStatus = PcdSet64S (
- PcdFwCfgDataAddress,
- FwCfgDataAddress
- );
- ASSERT_RETURN_ERROR (PcdStatus);
- break;
- } else {
- DEBUG ((DEBUG_ERROR, "%a: Failed to parse FDT QemuCfg node\n",
- __FUNCTION__));
- break;
- }
- }
- }
- return RETURN_SUCCESS;
- }
|