]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/QemuFwCfgSimpleParserLib/QemuFwCfgSimpleParser.c
OvmfPkg: Apply uncrustify changes
[mirror_edk2.git] / OvmfPkg / Library / QemuFwCfgSimpleParserLib / QemuFwCfgSimpleParser.c
CommitLineData
611c7f11
LE
1/** @file\r
2 Parse the contents of named fw_cfg files as simple (scalar) data types.\r
3\r
4 Copyright (C) 2020, Red Hat, Inc.\r
5\r
6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
7**/\r
8\r
9#include <Library/BaseLib.h>\r
10#include <Library/QemuFwCfgLib.h>\r
11#include <Library/QemuFwCfgSimpleParserLib.h>\r
12\r
13//\r
14// Size of the longest valid UINT64 string, including the terminating NUL.\r
15//\r
16#define UINT64_STRING_MAX_SIZE \\r
17 MAX (sizeof "18446744073709551615", sizeof "0xFFFFFFFFFFFFFFFF")\r
18\r
19//\r
20// Size of the longest valid BOOL string (see the "mTrueString" and\r
21// "mFalseString" arrays below), including the terminating NUL.\r
22//\r
ac0a286f 23#define BOOL_STRING_MAX_SIZE (sizeof "disabled")\r
611c7f11
LE
24\r
25//\r
26// Length of "\r\n", not including the terminating NUL.\r
27//\r
ac0a286f 28#define CRLF_LENGTH (sizeof "\r\n" - 1)\r
611c7f11
LE
29\r
30//\r
31// Words recognized as representing TRUE or FALSE.\r
32//\r
ac0a286f 33STATIC CONST CHAR8 *CONST mTrueString[] = {\r
611c7f11
LE
34 "true", "yes", "y", "enable", "enabled", "1"\r
35};\r
ac0a286f 36STATIC CONST CHAR8 *CONST mFalseString[] = {\r
611c7f11
LE
37 "false", "no", "n", "disable", "disabled", "0"\r
38};\r
39\r
40//\r
41// Helper functions.\r
42//\r
43\r
44/**\r
45 Look up FileName with QemuFwCfgFindFile() from QemuFwCfgLib. Read the fw_cfg\r
46 file into the caller-provided CHAR8 array. NUL-terminate the array.\r
47\r
48 @param[in] FileName The name of the fw_cfg file to look up and read.\r
49\r
50 @param[in,out] BufferSize On input, number of bytes available in Buffer.\r
51\r
52 On output, the number of bytes that have been\r
53 stored to Buffer.\r
54\r
55 On error, BufferSize is indeterminate.\r
56\r
57 @param[out] Buffer The buffer to read the fw_cfg file into. If the\r
58 fw_cfg file contents are not NUL-terminated, then\r
59 a NUL character is placed into Buffer after the\r
60 fw_cfg file contents.\r
61\r
62 On error, Buffer is indeterminate.\r
63\r
64 @retval RETURN_SUCCESS Buffer has been populated with the fw_cfg file\r
65 contents. Buffer is NUL-terminated regardless\r
66 of whether the fw_cfg file itself was\r
67 NUL-terminated.\r
68\r
69 @retval RETURN_UNSUPPORTED Firmware configuration is unavailable.\r
70\r
71 @retval RETURN_PROTOCOL_ERROR The fw_cfg file does not fit into Buffer.\r
72 (This is considered a QEMU configuration\r
73 error; BufferSize is considered authoritative\r
74 for the contents of the fw_cfg file identified\r
75 by FileName.)\r
76\r
77 @retval RETURN_PROTOCOL_ERROR The fw_cfg file contents are not themselves\r
78 NUL-terminated, and an extra NUL byte does not\r
79 fit into Buffer. (Again a QEMU configuration\r
80 error.)\r
81\r
82 @return Error codes propagated from\r
83 QemuFwCfgFindFile().\r
84**/\r
85STATIC\r
86RETURN_STATUS\r
87QemuFwCfgGetAsString (\r
ac0a286f
MK
88 IN CONST CHAR8 *FileName,\r
89 IN OUT UINTN *BufferSize,\r
90 OUT CHAR8 *Buffer\r
611c7f11
LE
91 )\r
92{\r
ac0a286f
MK
93 RETURN_STATUS Status;\r
94 FIRMWARE_CONFIG_ITEM FwCfgItem;\r
95 UINTN FwCfgSize;\r
611c7f11
LE
96\r
97 if (!QemuFwCfgIsAvailable ()) {\r
98 return RETURN_UNSUPPORTED;\r
99 }\r
100\r
101 Status = QemuFwCfgFindFile (FileName, &FwCfgItem, &FwCfgSize);\r
102 if (RETURN_ERROR (Status)) {\r
103 return Status;\r
104 }\r
ac0a286f 105\r
611c7f11
LE
106 if (FwCfgSize > *BufferSize) {\r
107 return RETURN_PROTOCOL_ERROR;\r
108 }\r
109\r
110 QemuFwCfgSelectItem (FwCfgItem);\r
111 QemuFwCfgReadBytes (FwCfgSize, Buffer);\r
112\r
113 //\r
114 // If Buffer is already NUL-terminated due to fw_cfg contents, we're done.\r
115 //\r
ac0a286f 116 if ((FwCfgSize > 0) && (Buffer[FwCfgSize - 1] == '\0')) {\r
611c7f11
LE
117 *BufferSize = FwCfgSize;\r
118 return RETURN_SUCCESS;\r
119 }\r
ac0a286f 120\r
611c7f11
LE
121 //\r
122 // Otherwise, append a NUL byte to Buffer (if we have room for it).\r
123 //\r
124 if (FwCfgSize == *BufferSize) {\r
125 return RETURN_PROTOCOL_ERROR;\r
126 }\r
ac0a286f 127\r
611c7f11 128 Buffer[FwCfgSize] = '\0';\r
ac0a286f 129 *BufferSize = FwCfgSize + 1;\r
611c7f11
LE
130 return RETURN_SUCCESS;\r
131}\r
132\r
133/**\r
134 Remove a trailing \r\n or \n sequence from a string.\r
135\r
136 @param[in,out] BufferSize On input, the number of bytes in Buffer, including\r
137 the terminating NUL.\r
138\r
139 On output, the adjusted string size (including the\r
140 terminating NUL), after stripping the \r\n or \n\r
141 suffix.\r
142\r
143 @param[in,out] Buffer The NUL-terminated string to trim.\r
144**/\r
145STATIC\r
146VOID\r
147StripNewline (\r
ac0a286f
MK
148 IN OUT UINTN *BufferSize,\r
149 IN OUT CHAR8 *Buffer\r
611c7f11
LE
150 )\r
151{\r
ac0a286f 152 UINTN InSize, OutSize;\r
611c7f11 153\r
ac0a286f 154 InSize = *BufferSize;\r
611c7f11
LE
155 OutSize = InSize;\r
156\r
ac0a286f
MK
157 if ((InSize >= 3) &&\r
158 (Buffer[InSize - 3] == '\r') && (Buffer[InSize - 2] == '\n'))\r
159 {\r
611c7f11 160 OutSize = InSize - 2;\r
ac0a286f 161 } else if ((InSize >= 2) && (Buffer[InSize - 2] == '\n')) {\r
611c7f11
LE
162 OutSize = InSize - 1;\r
163 }\r
164\r
165 if (OutSize < InSize) {\r
166 Buffer[OutSize - 1] = '\0';\r
ac0a286f 167 *BufferSize = OutSize;\r
611c7f11
LE
168 }\r
169}\r
170\r
171/**\r
172 Read the fw_cfg file identified by FileName as a string into a small array\r
173 with automatic storage duration, using QemuFwCfgGetAsString(). Parse the\r
174 string as a UINT64. Perform a range-check on the parsed value.\r
175\r
176 @param[in] FileName The name of the fw_cfg file to look up and parse.\r
177\r
178 @param[in] ParseAsHex If TRUE, call BaseLib's AsciiStrHexToUint64S() for\r
179 parsing the fw_cfg file.\r
180\r
181 If FALSE, call BaseLib's AsciiStrDecimalToUint64S()\r
182 for parsing the fw_cfg file.\r
183\r
184 @param[in] Limit The inclusive upper bound on the parsed UINT64 value.\r
185\r
186 @param[out] Value On success, Value has been parsed with the BaseLib\r
187 function determined by ParseAsHex, and has been\r
188 range-checked against [0, Limit].\r
189\r
190 On failure, Value is not changed.\r
191\r
192 @retval RETURN_SUCCESS Parsing successful. Value has been set.\r
193\r
194 @retval RETURN_UNSUPPORTED Firmware configuration is unavailable.\r
195\r
196 @retval RETURN_PROTOCOL_ERROR Parsing failed. Value has not been changed.\r
197\r
198 @retval RETURN_PROTOCOL_ERROR Parsing succeeded, but the result does not fit\r
199 in the [0, Limit] range. Value has not been\r
200 changed.\r
201\r
202 @return Error codes propagated from\r
203 QemuFwCfgFindFile() and from the BaseLib\r
204 function selected by ParseAsHex. Value has not\r
205 been changed.\r
206**/\r
207STATIC\r
208RETURN_STATUS\r
209QemuFwCfgParseUint64WithLimit (\r
ac0a286f
MK
210 IN CONST CHAR8 *FileName,\r
211 IN BOOLEAN ParseAsHex,\r
212 IN UINT64 Limit,\r
213 OUT UINT64 *Value\r
611c7f11
LE
214 )\r
215{\r
ac0a286f
MK
216 UINTN Uint64StringSize;\r
217 CHAR8 Uint64String[UINT64_STRING_MAX_SIZE + CRLF_LENGTH];\r
218 RETURN_STATUS Status;\r
219 CHAR8 *EndPointer;\r
220 UINT64 Uint64;\r
611c7f11
LE
221\r
222 Uint64StringSize = sizeof Uint64String;\r
ac0a286f 223 Status = QemuFwCfgGetAsString (FileName, &Uint64StringSize, Uint64String);\r
611c7f11
LE
224 if (RETURN_ERROR (Status)) {\r
225 return Status;\r
226 }\r
227\r
228 StripNewline (&Uint64StringSize, Uint64String);\r
229\r
230 if (ParseAsHex) {\r
231 Status = AsciiStrHexToUint64S (Uint64String, &EndPointer, &Uint64);\r
232 } else {\r
233 Status = AsciiStrDecimalToUint64S (Uint64String, &EndPointer, &Uint64);\r
234 }\r
ac0a286f 235\r
611c7f11
LE
236 if (RETURN_ERROR (Status)) {\r
237 return Status;\r
238 }\r
239\r
240 //\r
241 // Report a wire protocol error if the subject sequence is empty, or trailing\r
242 // garbage is present, or Limit is not honored.\r
243 //\r
ac0a286f 244 if ((EndPointer == Uint64String) || (*EndPointer != '\0') || (Uint64 > Limit)) {\r
611c7f11
LE
245 return RETURN_PROTOCOL_ERROR;\r
246 }\r
247\r
248 *Value = Uint64;\r
249 return RETURN_SUCCESS;\r
250}\r
251\r
252//\r
253// Public functions.\r
254//\r
255\r
256RETURN_STATUS\r
257EFIAPI\r
258QemuFwCfgSimpleParserInit (\r
259 VOID\r
260 )\r
261{\r
262 //\r
263 // Do nothing, just participate in constructor dependency ordering.\r
264 //\r
265 return RETURN_SUCCESS;\r
266}\r
267\r
268RETURN_STATUS\r
269EFIAPI\r
270QemuFwCfgParseBool (\r
ac0a286f
MK
271 IN CONST CHAR8 *FileName,\r
272 OUT BOOLEAN *Value\r
611c7f11
LE
273 )\r
274{\r
ac0a286f
MK
275 UINTN BoolStringSize;\r
276 CHAR8 BoolString[BOOL_STRING_MAX_SIZE + CRLF_LENGTH];\r
277 RETURN_STATUS Status;\r
278 UINTN Idx;\r
611c7f11
LE
279\r
280 BoolStringSize = sizeof BoolString;\r
ac0a286f 281 Status = QemuFwCfgGetAsString (FileName, &BoolStringSize, BoolString);\r
611c7f11
LE
282 if (RETURN_ERROR (Status)) {\r
283 return Status;\r
284 }\r
285\r
286 StripNewline (&BoolStringSize, BoolString);\r
287\r
288 for (Idx = 0; Idx < ARRAY_SIZE (mTrueString); ++Idx) {\r
289 if (AsciiStriCmp (BoolString, mTrueString[Idx]) == 0) {\r
290 *Value = TRUE;\r
291 return RETURN_SUCCESS;\r
292 }\r
293 }\r
294\r
295 for (Idx = 0; Idx < ARRAY_SIZE (mFalseString); ++Idx) {\r
296 if (AsciiStriCmp (BoolString, mFalseString[Idx]) == 0) {\r
297 *Value = FALSE;\r
298 return RETURN_SUCCESS;\r
299 }\r
300 }\r
301\r
302 return RETURN_PROTOCOL_ERROR;\r
303}\r
304\r
305RETURN_STATUS\r
306EFIAPI\r
307QemuFwCfgParseUint8 (\r
ac0a286f
MK
308 IN CONST CHAR8 *FileName,\r
309 IN BOOLEAN ParseAsHex,\r
310 OUT UINT8 *Value\r
611c7f11
LE
311 )\r
312{\r
ac0a286f
MK
313 RETURN_STATUS Status;\r
314 UINT64 Uint64;\r
315\r
316 Status = QemuFwCfgParseUint64WithLimit (\r
317 FileName,\r
318 ParseAsHex,\r
319 MAX_UINT8,\r
320 &Uint64\r
321 );\r
611c7f11
LE
322 if (RETURN_ERROR (Status)) {\r
323 return Status;\r
324 }\r
ac0a286f 325\r
611c7f11
LE
326 *Value = (UINT8)Uint64;\r
327 return RETURN_SUCCESS;\r
328}\r
329\r
330RETURN_STATUS\r
331EFIAPI\r
332QemuFwCfgParseUint16 (\r
ac0a286f
MK
333 IN CONST CHAR8 *FileName,\r
334 IN BOOLEAN ParseAsHex,\r
335 OUT UINT16 *Value\r
611c7f11
LE
336 )\r
337{\r
ac0a286f
MK
338 RETURN_STATUS Status;\r
339 UINT64 Uint64;\r
340\r
341 Status = QemuFwCfgParseUint64WithLimit (\r
342 FileName,\r
343 ParseAsHex,\r
344 MAX_UINT16,\r
345 &Uint64\r
346 );\r
611c7f11
LE
347 if (RETURN_ERROR (Status)) {\r
348 return Status;\r
349 }\r
ac0a286f 350\r
611c7f11
LE
351 *Value = (UINT16)Uint64;\r
352 return RETURN_SUCCESS;\r
353}\r
354\r
355RETURN_STATUS\r
356EFIAPI\r
357QemuFwCfgParseUint32 (\r
ac0a286f
MK
358 IN CONST CHAR8 *FileName,\r
359 IN BOOLEAN ParseAsHex,\r
360 OUT UINT32 *Value\r
611c7f11
LE
361 )\r
362{\r
ac0a286f
MK
363 RETURN_STATUS Status;\r
364 UINT64 Uint64;\r
365\r
366 Status = QemuFwCfgParseUint64WithLimit (\r
367 FileName,\r
368 ParseAsHex,\r
369 MAX_UINT32,\r
370 &Uint64\r
371 );\r
611c7f11
LE
372 if (RETURN_ERROR (Status)) {\r
373 return Status;\r
374 }\r
ac0a286f 375\r
611c7f11
LE
376 *Value = (UINT32)Uint64;\r
377 return RETURN_SUCCESS;\r
378}\r
379\r
380RETURN_STATUS\r
381EFIAPI\r
382QemuFwCfgParseUint64 (\r
ac0a286f
MK
383 IN CONST CHAR8 *FileName,\r
384 IN BOOLEAN ParseAsHex,\r
385 OUT UINT64 *Value\r
611c7f11
LE
386 )\r
387{\r
ac0a286f
MK
388 RETURN_STATUS Status;\r
389 UINT64 Uint64;\r
390\r
391 Status = QemuFwCfgParseUint64WithLimit (\r
392 FileName,\r
393 ParseAsHex,\r
394 MAX_UINT64,\r
395 &Uint64\r
396 );\r
611c7f11
LE
397 if (RETURN_ERROR (Status)) {\r
398 return Status;\r
399 }\r
ac0a286f 400\r
611c7f11
LE
401 *Value = Uint64;\r
402 return RETURN_SUCCESS;\r
403}\r
404\r
405RETURN_STATUS\r
406EFIAPI\r
407QemuFwCfgParseUintn (\r
ac0a286f
MK
408 IN CONST CHAR8 *FileName,\r
409 IN BOOLEAN ParseAsHex,\r
410 OUT UINTN *Value\r
611c7f11
LE
411 )\r
412{\r
ac0a286f
MK
413 RETURN_STATUS Status;\r
414 UINT64 Uint64;\r
415\r
416 Status = QemuFwCfgParseUint64WithLimit (\r
417 FileName,\r
418 ParseAsHex,\r
419 MAX_UINTN,\r
420 &Uint64\r
421 );\r
611c7f11
LE
422 if (RETURN_ERROR (Status)) {\r
423 return Status;\r
424 }\r
ac0a286f 425\r
611c7f11
LE
426 *Value = (UINTN)Uint64;\r
427 return RETURN_SUCCESS;\r
428}\r