--- /dev/null
+/** @file\r
+\r
+ Stateful and implicitly initialized fw_cfg library implementation.\r
+\r
+ Copyright (C) 2013 - 2014, Red Hat, Inc.\r
+ Copyright (c) 2011 - 2013, Intel Corporation. All rights reserved.<BR>\r
+\r
+ This program and the accompanying materials are licensed and made available\r
+ under the terms and conditions of the BSD License which accompanies this\r
+ distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
+ WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/QemuFwCfgLib.h>\r
+\r
+STATIC UINTN mFwCfgSelectorAddress;\r
+STATIC UINTN mFwCfgDataAddress;\r
+\r
+\r
+/**\r
+ Returns a boolean indicating if the firmware configuration interface is\r
+ available for library-internal purposes.\r
+\r
+ This function never changes fw_cfg state.\r
+\r
+ @retval TRUE The interface is available internally.\r
+ @retval FALSE The interface is not available internally.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+InternalQemuFwCfgIsAvailable (\r
+ VOID\r
+ )\r
+{\r
+ return (BOOLEAN)(mFwCfgSelectorAddress != 0 && mFwCfgDataAddress != 0);\r
+}\r
+\r
+\r
+/**\r
+ Returns a boolean indicating if the firmware configuration interface\r
+ is available or not.\r
+\r
+ This function may change fw_cfg state.\r
+\r
+ @retval TRUE The interface is available\r
+ @retval FALSE The interface is not available\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+QemuFwCfgIsAvailable (\r
+ VOID\r
+ )\r
+{\r
+ return InternalQemuFwCfgIsAvailable ();\r
+}\r
+\r
+\r
+RETURN_STATUS\r
+EFIAPI\r
+QemuFwCfgInitialize (\r
+ VOID\r
+ )\r
+{\r
+ mFwCfgSelectorAddress = (UINTN)PcdGet64 (PcdFwCfgSelectorAddress);\r
+ mFwCfgDataAddress = (UINTN)PcdGet64 (PcdFwCfgDataAddress);\r
+\r
+ if (InternalQemuFwCfgIsAvailable ()) {\r
+ UINT32 Signature;\r
+\r
+ QemuFwCfgSelectItem (QemuFwCfgItemSignature);\r
+ Signature = QemuFwCfgRead32 ();\r
+ if (Signature != SIGNATURE_32 ('Q', 'E', 'M', 'U')) {\r
+ mFwCfgSelectorAddress = 0;\r
+ mFwCfgDataAddress = 0;\r
+ }\r
+ }\r
+ return RETURN_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Selects a firmware configuration item for reading.\r
+\r
+ Following this call, any data read from this item will start from the\r
+ beginning of the configuration item's data.\r
+\r
+ @param[in] QemuFwCfgItem Firmware Configuration item to read\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+QemuFwCfgSelectItem (\r
+ IN FIRMWARE_CONFIG_ITEM QemuFwCfgItem\r
+ )\r
+{\r
+ if (InternalQemuFwCfgIsAvailable ()) {\r
+ MmioWrite16 (mFwCfgSelectorAddress, SwapBytes16 ((UINT16)QemuFwCfgItem));\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Reads firmware configuration bytes into a buffer\r
+\r
+ @param[in] Size Size in bytes to read\r
+ @param[in] Buffer Buffer to store data into (OPTIONAL if Size is 0)\r
+\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+InternalQemuFwCfgReadBytes (\r
+ IN UINTN Size,\r
+ IN VOID *Buffer OPTIONAL\r
+ )\r
+{\r
+ UINTN Left;\r
+ UINT8 *Ptr;\r
+ UINT8 *End;\r
+\r
+#ifdef MDE_CPU_AARCH64\r
+ Left = Size & 7;\r
+#else\r
+ Left = Size & 3;\r
+#endif\r
+\r
+ Size -= Left;\r
+ Ptr = Buffer;\r
+ End = Ptr + Size;\r
+\r
+#ifdef MDE_CPU_AARCH64\r
+ while (Ptr < End) {\r
+ *(UINT64 *)Ptr = MmioRead64 (mFwCfgDataAddress);\r
+ Ptr += 8;\r
+ }\r
+ if (Left & 4) {\r
+ *(UINT32 *)Ptr = MmioRead32 (mFwCfgDataAddress);\r
+ Ptr += 4;\r
+ }\r
+#else\r
+ while (Ptr < End) {\r
+ *(UINT32 *)Ptr = MmioRead32 (mFwCfgDataAddress);\r
+ Ptr += 4;\r
+ }\r
+#endif\r
+\r
+ if (Left & 2) {\r
+ *(UINT16 *)Ptr = MmioRead16 (mFwCfgDataAddress);\r
+ Ptr += 2;\r
+ }\r
+ if (Left & 1) {\r
+ *Ptr = MmioRead8 (mFwCfgDataAddress);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Reads firmware configuration bytes into a buffer\r
+\r
+ If called multiple times, then the data read will continue at the offset of\r
+ the firmware configuration item where the previous read ended.\r
+\r
+ @param[in] Size Size in bytes to read\r
+ @param[in] Buffer Buffer to store data into\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+QemuFwCfgReadBytes (\r
+ IN UINTN Size,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ if (InternalQemuFwCfgIsAvailable ()) {\r
+ InternalQemuFwCfgReadBytes (Size, Buffer);\r
+ } else {\r
+ ZeroMem (Buffer, Size);\r
+ }\r
+}\r
+\r
+/**\r
+ Write firmware configuration bytes from a buffer\r
+\r
+ If called multiple times, then the data written will continue at the offset\r
+ of the firmware configuration item where the previous write ended.\r
+\r
+ @param[in] Size Size in bytes to write\r
+ @param[in] Buffer Buffer to read data from\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+QemuFwCfgWriteBytes (\r
+ IN UINTN Size,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ if (InternalQemuFwCfgIsAvailable ()) {\r
+ UINTN Idx;\r
+\r
+ for (Idx = 0; Idx < Size; ++Idx) {\r
+ MmioWrite8 (mFwCfgDataAddress, ((UINT8 *)Buffer)[Idx]);\r
+ }\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Reads a UINT8 firmware configuration value\r
+\r
+ @return Value of Firmware Configuration item read\r
+\r
+**/\r
+UINT8\r
+EFIAPI\r
+QemuFwCfgRead8 (\r
+ VOID\r
+ )\r
+{\r
+ UINT8 Result;\r
+\r
+ QemuFwCfgReadBytes (sizeof Result, &Result);\r
+ return Result;\r
+}\r
+\r
+\r
+/**\r
+ Reads a UINT16 firmware configuration value\r
+\r
+ @return Value of Firmware Configuration item read\r
+\r
+**/\r
+UINT16\r
+EFIAPI\r
+QemuFwCfgRead16 (\r
+ VOID\r
+ )\r
+{\r
+ UINT16 Result;\r
+\r
+ QemuFwCfgReadBytes (sizeof Result, &Result);\r
+ return Result;\r
+}\r
+\r
+\r
+/**\r
+ Reads a UINT32 firmware configuration value\r
+\r
+ @return Value of Firmware Configuration item read\r
+\r
+**/\r
+UINT32\r
+EFIAPI\r
+QemuFwCfgRead32 (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 Result;\r
+\r
+ QemuFwCfgReadBytes (sizeof Result, &Result);\r
+ return Result;\r
+}\r
+\r
+\r
+/**\r
+ Reads a UINT64 firmware configuration value\r
+\r
+ @return Value of Firmware Configuration item read\r
+\r
+**/\r
+UINT64\r
+EFIAPI\r
+QemuFwCfgRead64 (\r
+ VOID\r
+ )\r
+{\r
+ UINT64 Result;\r
+\r
+ QemuFwCfgReadBytes (sizeof Result, &Result);\r
+ return Result;\r
+}\r
+\r
+\r
+/**\r
+ Find the configuration item corresponding to the firmware configuration file.\r
+\r
+ @param[in] Name Name of file to look up.\r
+ @param[out] Item Configuration item corresponding to the file, to be passed\r
+ to QemuFwCfgSelectItem ().\r
+ @param[out] Size Number of bytes in the file.\r
+\r
+ @retval RETURN_SUCCESS If file is found.\r
+ @retval RETURN_NOT_FOUND If file is not found.\r
+ @retval RETURN_UNSUPPORTED If firmware configuration is unavailable.\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+QemuFwCfgFindFile (\r
+ IN CONST CHAR8 *Name,\r
+ OUT FIRMWARE_CONFIG_ITEM *Item,\r
+ OUT UINTN *Size\r
+ )\r
+{\r
+ UINT32 Count;\r
+ UINT32 Idx;\r
+\r
+ if (!InternalQemuFwCfgIsAvailable ()) {\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
+\r
+ QemuFwCfgSelectItem (QemuFwCfgItemFileDir);\r
+ Count = SwapBytes32 (QemuFwCfgRead32 ());\r
+\r
+ for (Idx = 0; Idx < Count; ++Idx) {\r
+ UINT32 FileSize;\r
+ UINT16 FileSelect;\r
+ CHAR8 FName[QEMU_FW_CFG_FNAME_SIZE];\r
+\r
+ FileSize = QemuFwCfgRead32 ();\r
+ FileSelect = QemuFwCfgRead16 ();\r
+ QemuFwCfgRead16 (); // skip the field called "reserved"\r
+ InternalQemuFwCfgReadBytes (sizeof (FName), FName);\r
+\r
+ if (AsciiStrCmp (Name, FName) == 0) {\r
+ *Item = SwapBytes16 (FileSelect);\r
+ *Size = SwapBytes32 (FileSize);\r
+ return RETURN_SUCCESS;\r
+ }\r
+ }\r
+\r
+ return RETURN_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+ Determine if S3 support is explicitly enabled.\r
+\r
+ @retval TRUE if S3 support is explicitly enabled.\r
+ FALSE otherwise. This includes unavailability of the firmware\r
+ configuration interface.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+QemuFwCfgS3Enabled (\r
+ VOID\r
+ )\r
+{\r
+ return FALSE;\r
+}\r