--- /dev/null
+/** @file\r
+ Parse the contents of named fw_cfg files as simple (scalar) data types.\r
+\r
+ Copyright (C) 2020, Red Hat, Inc.\r
+\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+**/\r
+\r
+#ifndef QEMU_FW_CFG_SIMPLE_PARSER_LIB_H_\r
+#define QEMU_FW_CFG_SIMPLE_PARSER_LIB_H_\r
+\r
+#include <Base.h>\r
+\r
+/**\r
+ Look up FileName with QemuFwCfgFindFile() from QemuFwCfgLib. Read the fw_cfg\r
+ file into a small array with automatic storage duration. Parse the array as\r
+ the textual representation of a BOOLEAN.\r
+\r
+ @param[in] FileName The name of the fw_cfg file to look up and parse.\r
+\r
+ @param[out] Value On success, Value is TRUE if the contents of the fw_cfg\r
+ file case-insensitively match "true", "yes", "y",\r
+ "enable", "enabled", "1".\r
+\r
+ On success, Value is FALSE if the contents of the fw_cfg\r
+ file case-insensitively match "false", "no", "n",\r
+ "disable", "disabled", "0".\r
+\r
+ On failure, Value is not changed.\r
+\r
+ @retval RETURN_SUCCESS Parsing successful. Value has been set.\r
+\r
+ @retval RETURN_UNSUPPORTED Firmware configuration is unavailable.\r
+\r
+ @retval RETURN_PROTOCOL_ERROR Parsing failed. Value has not been changed.\r
+\r
+ @return Error codes propagated from\r
+ QemuFwCfgFindFile(). Value has not been\r
+ changed.\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+QemuFwCfgParseBool (\r
+ IN CONST CHAR8 *FileName,\r
+ OUT BOOLEAN *Value\r
+ );\r
+\r
+/**\r
+ Look up FileName with QemuFwCfgFindFile() from QemuFwCfgLib. Read the fw_cfg\r
+ file into a small array with automatic storage duration. Parse the array as\r
+ the textual representation of a UINT8.\r
+\r
+ @param[in] FileName The name of the fw_cfg file to look up and parse.\r
+\r
+ @param[in] ParseAsHex If TRUE, call BaseLib's AsciiStrHexToUint64S() for\r
+ parsing the fw_cfg file.\r
+\r
+ If FALSE, call BaseLib's AsciiStrDecimalToUint64S()\r
+ for parsing the fw_cfg file.\r
+\r
+ @param[out] Value On success, Value has been parsed with the BaseLib\r
+ function determined by ParseAsHex, and also\r
+ range-checked for [0, MAX_UINT8].\r
+\r
+ On failure, Value is not changed.\r
+\r
+ @retval RETURN_SUCCESS Parsing successful. Value has been set.\r
+\r
+ @retval RETURN_UNSUPPORTED Firmware configuration is unavailable.\r
+\r
+ @retval RETURN_PROTOCOL_ERROR Parsing failed. Value has not been changed.\r
+\r
+ @retval RETURN_PROTOCOL_ERROR Parsing succeeded, but the result does not fit\r
+ in the [0, MAX_UINT8] range. Value has not\r
+ been changed.\r
+\r
+ @return Error codes propagated from\r
+ QemuFwCfgFindFile() and from the BaseLib\r
+ function selected by ParseAsHex. Value has not\r
+ been changed.\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+QemuFwCfgParseUint8 (\r
+ IN CONST CHAR8 *FileName,\r
+ IN BOOLEAN ParseAsHex,\r
+ OUT UINT8 *Value\r
+ );\r
+\r
+//\r
+// The following functions behave identically to QemuFwCfgParseUint8(),\r
+// only their range checks use MAX_UINT16, MAX_UINT32, MAX_UINT64, MAX_UINTN,\r
+// respectively.\r
+//\r
+\r
+RETURN_STATUS\r
+EFIAPI\r
+QemuFwCfgParseUint16 (\r
+ IN CONST CHAR8 *FileName,\r
+ IN BOOLEAN ParseAsHex,\r
+ OUT UINT16 *Value\r
+ );\r
+\r
+RETURN_STATUS\r
+EFIAPI\r
+QemuFwCfgParseUint32 (\r
+ IN CONST CHAR8 *FileName,\r
+ IN BOOLEAN ParseAsHex,\r
+ OUT UINT32 *Value\r
+ );\r
+\r
+RETURN_STATUS\r
+EFIAPI\r
+QemuFwCfgParseUint64 (\r
+ IN CONST CHAR8 *FileName,\r
+ IN BOOLEAN ParseAsHex,\r
+ OUT UINT64 *Value\r
+ );\r
+\r
+RETURN_STATUS\r
+EFIAPI\r
+QemuFwCfgParseUintn (\r
+ IN CONST CHAR8 *FileName,\r
+ IN BOOLEAN ParseAsHex,\r
+ OUT UINTN *Value\r
+ );\r
+\r
+#endif // QEMU_FW_CFG_SIMPLE_PARSER_LIB_H_\r
--- /dev/null
+/** @file\r
+ Parse the contents of named fw_cfg files as simple (scalar) data types.\r
+\r
+ Copyright (C) 2020, Red Hat, Inc.\r
+\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+**/\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/QemuFwCfgLib.h>\r
+#include <Library/QemuFwCfgSimpleParserLib.h>\r
+\r
+//\r
+// Size of the longest valid UINT64 string, including the terminating NUL.\r
+//\r
+#define UINT64_STRING_MAX_SIZE \\r
+ MAX (sizeof "18446744073709551615", sizeof "0xFFFFFFFFFFFFFFFF")\r
+\r
+//\r
+// Size of the longest valid BOOL string (see the "mTrueString" and\r
+// "mFalseString" arrays below), including the terminating NUL.\r
+//\r
+#define BOOL_STRING_MAX_SIZE (sizeof "disabled")\r
+\r
+//\r
+// Length of "\r\n", not including the terminating NUL.\r
+//\r
+#define CRLF_LENGTH (sizeof "\r\n" - 1)\r
+\r
+//\r
+// Words recognized as representing TRUE or FALSE.\r
+//\r
+STATIC CONST CHAR8 * CONST mTrueString[] = {\r
+ "true", "yes", "y", "enable", "enabled", "1"\r
+};\r
+STATIC CONST CHAR8 * CONST mFalseString[] = {\r
+ "false", "no", "n", "disable", "disabled", "0"\r
+};\r
+\r
+//\r
+// Helper functions.\r
+//\r
+\r
+/**\r
+ Look up FileName with QemuFwCfgFindFile() from QemuFwCfgLib. Read the fw_cfg\r
+ file into the caller-provided CHAR8 array. NUL-terminate the array.\r
+\r
+ @param[in] FileName The name of the fw_cfg file to look up and read.\r
+\r
+ @param[in,out] BufferSize On input, number of bytes available in Buffer.\r
+\r
+ On output, the number of bytes that have been\r
+ stored to Buffer.\r
+\r
+ On error, BufferSize is indeterminate.\r
+\r
+ @param[out] Buffer The buffer to read the fw_cfg file into. If the\r
+ fw_cfg file contents are not NUL-terminated, then\r
+ a NUL character is placed into Buffer after the\r
+ fw_cfg file contents.\r
+\r
+ On error, Buffer is indeterminate.\r
+\r
+ @retval RETURN_SUCCESS Buffer has been populated with the fw_cfg file\r
+ contents. Buffer is NUL-terminated regardless\r
+ of whether the fw_cfg file itself was\r
+ NUL-terminated.\r
+\r
+ @retval RETURN_UNSUPPORTED Firmware configuration is unavailable.\r
+\r
+ @retval RETURN_PROTOCOL_ERROR The fw_cfg file does not fit into Buffer.\r
+ (This is considered a QEMU configuration\r
+ error; BufferSize is considered authoritative\r
+ for the contents of the fw_cfg file identified\r
+ by FileName.)\r
+\r
+ @retval RETURN_PROTOCOL_ERROR The fw_cfg file contents are not themselves\r
+ NUL-terminated, and an extra NUL byte does not\r
+ fit into Buffer. (Again a QEMU configuration\r
+ error.)\r
+\r
+ @return Error codes propagated from\r
+ QemuFwCfgFindFile().\r
+**/\r
+STATIC\r
+RETURN_STATUS\r
+QemuFwCfgGetAsString (\r
+ IN CONST CHAR8 *FileName,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT CHAR8 *Buffer\r
+ )\r
+{\r
+ RETURN_STATUS Status;\r
+ FIRMWARE_CONFIG_ITEM FwCfgItem;\r
+ UINTN FwCfgSize;\r
+\r
+ if (!QemuFwCfgIsAvailable ()) {\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
+\r
+ Status = QemuFwCfgFindFile (FileName, &FwCfgItem, &FwCfgSize);\r
+ if (RETURN_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ if (FwCfgSize > *BufferSize) {\r
+ return RETURN_PROTOCOL_ERROR;\r
+ }\r
+\r
+ QemuFwCfgSelectItem (FwCfgItem);\r
+ QemuFwCfgReadBytes (FwCfgSize, Buffer);\r
+\r
+ //\r
+ // If Buffer is already NUL-terminated due to fw_cfg contents, we're done.\r
+ //\r
+ if (FwCfgSize > 0 && Buffer[FwCfgSize - 1] == '\0') {\r
+ *BufferSize = FwCfgSize;\r
+ return RETURN_SUCCESS;\r
+ }\r
+ //\r
+ // Otherwise, append a NUL byte to Buffer (if we have room for it).\r
+ //\r
+ if (FwCfgSize == *BufferSize) {\r
+ return RETURN_PROTOCOL_ERROR;\r
+ }\r
+ Buffer[FwCfgSize] = '\0';\r
+ *BufferSize = FwCfgSize + 1;\r
+ return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+ Remove a trailing \r\n or \n sequence from a string.\r
+\r
+ @param[in,out] BufferSize On input, the number of bytes in Buffer, including\r
+ the terminating NUL.\r
+\r
+ On output, the adjusted string size (including the\r
+ terminating NUL), after stripping the \r\n or \n\r
+ suffix.\r
+\r
+ @param[in,out] Buffer The NUL-terminated string to trim.\r
+**/\r
+STATIC\r
+VOID\r
+StripNewline (\r
+ IN OUT UINTN *BufferSize,\r
+ IN OUT CHAR8 *Buffer\r
+ )\r
+{\r
+ UINTN InSize, OutSize;\r
+\r
+ InSize = *BufferSize;\r
+ OutSize = InSize;\r
+\r
+ if (InSize >= 3 &&\r
+ Buffer[InSize - 3] == '\r' && Buffer[InSize - 2] == '\n') {\r
+ OutSize = InSize - 2;\r
+ } else if (InSize >= 2 && Buffer[InSize - 2] == '\n') {\r
+ OutSize = InSize - 1;\r
+ }\r
+\r
+ if (OutSize < InSize) {\r
+ Buffer[OutSize - 1] = '\0';\r
+ *BufferSize = OutSize;\r
+ }\r
+}\r
+\r
+/**\r
+ Read the fw_cfg file identified by FileName as a string into a small array\r
+ with automatic storage duration, using QemuFwCfgGetAsString(). Parse the\r
+ string as a UINT64. Perform a range-check on the parsed value.\r
+\r
+ @param[in] FileName The name of the fw_cfg file to look up and parse.\r
+\r
+ @param[in] ParseAsHex If TRUE, call BaseLib's AsciiStrHexToUint64S() for\r
+ parsing the fw_cfg file.\r
+\r
+ If FALSE, call BaseLib's AsciiStrDecimalToUint64S()\r
+ for parsing the fw_cfg file.\r
+\r
+ @param[in] Limit The inclusive upper bound on the parsed UINT64 value.\r
+\r
+ @param[out] Value On success, Value has been parsed with the BaseLib\r
+ function determined by ParseAsHex, and has been\r
+ range-checked against [0, Limit].\r
+\r
+ On failure, Value is not changed.\r
+\r
+ @retval RETURN_SUCCESS Parsing successful. Value has been set.\r
+\r
+ @retval RETURN_UNSUPPORTED Firmware configuration is unavailable.\r
+\r
+ @retval RETURN_PROTOCOL_ERROR Parsing failed. Value has not been changed.\r
+\r
+ @retval RETURN_PROTOCOL_ERROR Parsing succeeded, but the result does not fit\r
+ in the [0, Limit] range. Value has not been\r
+ changed.\r
+\r
+ @return Error codes propagated from\r
+ QemuFwCfgFindFile() and from the BaseLib\r
+ function selected by ParseAsHex. Value has not\r
+ been changed.\r
+**/\r
+STATIC\r
+RETURN_STATUS\r
+QemuFwCfgParseUint64WithLimit (\r
+ IN CONST CHAR8 *FileName,\r
+ IN BOOLEAN ParseAsHex,\r
+ IN UINT64 Limit,\r
+ OUT UINT64 *Value\r
+ )\r
+{\r
+ UINTN Uint64StringSize;\r
+ CHAR8 Uint64String[UINT64_STRING_MAX_SIZE + CRLF_LENGTH];\r
+ RETURN_STATUS Status;\r
+ CHAR8 *EndPointer;\r
+ UINT64 Uint64;\r
+\r
+ Uint64StringSize = sizeof Uint64String;\r
+ Status = QemuFwCfgGetAsString (FileName, &Uint64StringSize, Uint64String);\r
+ if (RETURN_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ StripNewline (&Uint64StringSize, Uint64String);\r
+\r
+ if (ParseAsHex) {\r
+ Status = AsciiStrHexToUint64S (Uint64String, &EndPointer, &Uint64);\r
+ } else {\r
+ Status = AsciiStrDecimalToUint64S (Uint64String, &EndPointer, &Uint64);\r
+ }\r
+ if (RETURN_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Report a wire protocol error if the subject sequence is empty, or trailing\r
+ // garbage is present, or Limit is not honored.\r
+ //\r
+ if (EndPointer == Uint64String || *EndPointer != '\0' || Uint64 > Limit) {\r
+ return RETURN_PROTOCOL_ERROR;\r
+ }\r
+\r
+ *Value = Uint64;\r
+ return RETURN_SUCCESS;\r
+}\r
+\r
+//\r
+// Public functions.\r
+//\r
+\r
+RETURN_STATUS\r
+EFIAPI\r
+QemuFwCfgSimpleParserInit (\r
+ VOID\r
+ )\r
+{\r
+ //\r
+ // Do nothing, just participate in constructor dependency ordering.\r
+ //\r
+ return RETURN_SUCCESS;\r
+}\r
+\r
+RETURN_STATUS\r
+EFIAPI\r
+QemuFwCfgParseBool (\r
+ IN CONST CHAR8 *FileName,\r
+ OUT BOOLEAN *Value\r
+ )\r
+{\r
+ UINTN BoolStringSize;\r
+ CHAR8 BoolString[BOOL_STRING_MAX_SIZE + CRLF_LENGTH];\r
+ RETURN_STATUS Status;\r
+ UINTN Idx;\r
+\r
+ BoolStringSize = sizeof BoolString;\r
+ Status = QemuFwCfgGetAsString (FileName, &BoolStringSize, BoolString);\r
+ if (RETURN_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ StripNewline (&BoolStringSize, BoolString);\r
+\r
+ for (Idx = 0; Idx < ARRAY_SIZE (mTrueString); ++Idx) {\r
+ if (AsciiStriCmp (BoolString, mTrueString[Idx]) == 0) {\r
+ *Value = TRUE;\r
+ return RETURN_SUCCESS;\r
+ }\r
+ }\r
+\r
+ for (Idx = 0; Idx < ARRAY_SIZE (mFalseString); ++Idx) {\r
+ if (AsciiStriCmp (BoolString, mFalseString[Idx]) == 0) {\r
+ *Value = FALSE;\r
+ return RETURN_SUCCESS;\r
+ }\r
+ }\r
+\r
+ return RETURN_PROTOCOL_ERROR;\r
+}\r
+\r
+RETURN_STATUS\r
+EFIAPI\r
+QemuFwCfgParseUint8 (\r
+ IN CONST CHAR8 *FileName,\r
+ IN BOOLEAN ParseAsHex,\r
+ OUT UINT8 *Value\r
+ )\r
+{\r
+ RETURN_STATUS Status;\r
+ UINT64 Uint64;\r
+\r
+ Status = QemuFwCfgParseUint64WithLimit (FileName, ParseAsHex, MAX_UINT8,\r
+ &Uint64);\r
+ if (RETURN_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ *Value = (UINT8)Uint64;\r
+ return RETURN_SUCCESS;\r
+}\r
+\r
+RETURN_STATUS\r
+EFIAPI\r
+QemuFwCfgParseUint16 (\r
+ IN CONST CHAR8 *FileName,\r
+ IN BOOLEAN ParseAsHex,\r
+ OUT UINT16 *Value\r
+ )\r
+{\r
+ RETURN_STATUS Status;\r
+ UINT64 Uint64;\r
+\r
+ Status = QemuFwCfgParseUint64WithLimit (FileName, ParseAsHex, MAX_UINT16,\r
+ &Uint64);\r
+ if (RETURN_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ *Value = (UINT16)Uint64;\r
+ return RETURN_SUCCESS;\r
+}\r
+\r
+RETURN_STATUS\r
+EFIAPI\r
+QemuFwCfgParseUint32 (\r
+ IN CONST CHAR8 *FileName,\r
+ IN BOOLEAN ParseAsHex,\r
+ OUT UINT32 *Value\r
+ )\r
+{\r
+ RETURN_STATUS Status;\r
+ UINT64 Uint64;\r
+\r
+ Status = QemuFwCfgParseUint64WithLimit (FileName, ParseAsHex, MAX_UINT32,\r
+ &Uint64);\r
+ if (RETURN_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ *Value = (UINT32)Uint64;\r
+ return RETURN_SUCCESS;\r
+}\r
+\r
+RETURN_STATUS\r
+EFIAPI\r
+QemuFwCfgParseUint64 (\r
+ IN CONST CHAR8 *FileName,\r
+ IN BOOLEAN ParseAsHex,\r
+ OUT UINT64 *Value\r
+ )\r
+{\r
+ RETURN_STATUS Status;\r
+ UINT64 Uint64;\r
+\r
+ Status = QemuFwCfgParseUint64WithLimit (FileName, ParseAsHex, MAX_UINT64,\r
+ &Uint64);\r
+ if (RETURN_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ *Value = Uint64;\r
+ return RETURN_SUCCESS;\r
+}\r
+\r
+RETURN_STATUS\r
+EFIAPI\r
+QemuFwCfgParseUintn (\r
+ IN CONST CHAR8 *FileName,\r
+ IN BOOLEAN ParseAsHex,\r
+ OUT UINTN *Value\r
+ )\r
+{\r
+ RETURN_STATUS Status;\r
+ UINT64 Uint64;\r
+\r
+ Status = QemuFwCfgParseUint64WithLimit (FileName, ParseAsHex, MAX_UINTN,\r
+ &Uint64);\r
+ if (RETURN_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ *Value = (UINTN)Uint64;\r
+ return RETURN_SUCCESS;\r
+}\r