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