]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibMmio.c
OvmfPkg: Apply uncrustify changes
[mirror_edk2.git] / OvmfPkg / Library / QemuFwCfgLib / QemuFwCfgLibMmio.c
CommitLineData
6e2543b0
LE
1/** @file\r
2\r
3 Stateful and implicitly initialized fw_cfg library implementation.\r
4\r
5 Copyright (C) 2013 - 2014, Red Hat, Inc.\r
6 Copyright (c) 2011 - 2013, Intel Corporation. All rights reserved.<BR>\r
26aa241d 7 (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>\r
6e2543b0 8\r
9792fb0e 9 SPDX-License-Identifier: BSD-2-Clause-Patent\r
6e2543b0
LE
10**/\r
11\r
7b6745cc
AB
12#include <Uefi.h>\r
13\r
6e2543b0
LE
14#include <Library/BaseLib.h>\r
15#include <Library/BaseMemoryLib.h>\r
953bcbcc 16#include <Library/DebugLib.h>\r
6e2543b0 17#include <Library/IoLib.h>\r
6e2543b0 18#include <Library/QemuFwCfgLib.h>\r
7b6745cc
AB
19#include <Library/UefiBootServicesTableLib.h>\r
20\r
21#include <Protocol/FdtClient.h>\r
6e2543b0 22\r
ac0a286f
MK
23STATIC UINTN mFwCfgSelectorAddress;\r
24STATIC UINTN mFwCfgDataAddress;\r
25STATIC UINTN mFwCfgDmaAddress;\r
953bcbcc
LE
26\r
27/**\r
28 Reads firmware configuration bytes into a buffer\r
29\r
30 @param[in] Size Size in bytes to read\r
31 @param[in] Buffer Buffer to store data into (OPTIONAL if Size is 0)\r
32\r
33**/\r
34typedef\r
ac0a286f 35VOID(EFIAPI READ_BYTES_FUNCTION)(\r
953bcbcc
LE
36 IN UINTN Size,\r
37 IN VOID *Buffer OPTIONAL\r
38 );\r
39\r
e8ae381f
LE
40/**\r
41 Writes bytes from a buffer to firmware configuration\r
42\r
43 @param[in] Size Size in bytes to write\r
44 @param[in] Buffer Buffer to transfer data from (OPTIONAL if Size is 0)\r
45\r
46**/\r
47typedef\r
ac0a286f 48VOID(EFIAPI WRITE_BYTES_FUNCTION)(\r
e8ae381f
LE
49 IN UINTN Size,\r
50 IN VOID *Buffer OPTIONAL\r
51 );\r
52\r
7fcb7354
LE
53/**\r
54 Skips bytes in firmware configuration\r
55\r
56 @param[in] Size Size in bytes to skip\r
57\r
58**/\r
59typedef\r
ac0a286f 60VOID(EFIAPI SKIP_BYTES_FUNCTION)(\r
7fcb7354
LE
61 IN UINTN Size\r
62 );\r
63\r
953bcbcc
LE
64//\r
65// Forward declaration of the two implementations we have.\r
66//\r
ac0a286f
MK
67STATIC READ_BYTES_FUNCTION MmioReadBytes;\r
68STATIC WRITE_BYTES_FUNCTION MmioWriteBytes;\r
69STATIC SKIP_BYTES_FUNCTION MmioSkipBytes;\r
70STATIC READ_BYTES_FUNCTION DmaReadBytes;\r
71STATIC WRITE_BYTES_FUNCTION DmaWriteBytes;\r
72STATIC SKIP_BYTES_FUNCTION DmaSkipBytes;\r
953bcbcc
LE
73\r
74//\r
e8ae381f 75// These correspond to the implementation we detect at runtime.\r
953bcbcc 76//\r
ac0a286f
MK
77STATIC READ_BYTES_FUNCTION *InternalQemuFwCfgReadBytes = MmioReadBytes;\r
78STATIC WRITE_BYTES_FUNCTION *InternalQemuFwCfgWriteBytes = MmioWriteBytes;\r
79STATIC SKIP_BYTES_FUNCTION *InternalQemuFwCfgSkipBytes = MmioSkipBytes;\r
6e2543b0 80\r
6e2543b0
LE
81/**\r
82 Returns a boolean indicating if the firmware configuration interface\r
83 is available or not.\r
84\r
85 This function may change fw_cfg state.\r
86\r
87 @retval TRUE The interface is available\r
88 @retval FALSE The interface is not available\r
89\r
90**/\r
91BOOLEAN\r
92EFIAPI\r
93QemuFwCfgIsAvailable (\r
94 VOID\r
95 )\r
96{\r
1cb33be9 97 return (BOOLEAN)(mFwCfgSelectorAddress != 0 && mFwCfgDataAddress != 0);\r
6e2543b0
LE
98}\r
99\r
6e2543b0
LE
100RETURN_STATUS\r
101EFIAPI\r
102QemuFwCfgInitialize (\r
103 VOID\r
104 )\r
105{\r
ac0a286f
MK
106 EFI_STATUS Status;\r
107 FDT_CLIENT_PROTOCOL *FdtClient;\r
108 CONST UINT64 *Reg;\r
109 UINT32 RegSize;\r
110 UINTN AddressCells, SizeCells;\r
111 UINT64 FwCfgSelectorAddress;\r
112 UINT64 FwCfgSelectorSize;\r
113 UINT64 FwCfgDataAddress;\r
114 UINT64 FwCfgDataSize;\r
115 UINT64 FwCfgDmaAddress;\r
116 UINT64 FwCfgDmaSize;\r
117\r
118 Status = gBS->LocateProtocol (\r
119 &gFdtClientProtocolGuid,\r
120 NULL,\r
121 (VOID **)&FdtClient\r
122 );\r
7b6745cc
AB
123 ASSERT_EFI_ERROR (Status);\r
124\r
ac0a286f
MK
125 Status = FdtClient->FindCompatibleNodeReg (\r
126 FdtClient,\r
127 "qemu,fw-cfg-mmio",\r
128 (CONST VOID **)&Reg,\r
129 &AddressCells,\r
130 &SizeCells,\r
131 &RegSize\r
132 );\r
7b6745cc 133 if (EFI_ERROR (Status)) {\r
ac0a286f
MK
134 DEBUG ((\r
135 DEBUG_WARN,\r
7b6745cc 136 "%a: No 'qemu,fw-cfg-mmio' compatible DT node found (Status == %r)\n",\r
ac0a286f
MK
137 __FUNCTION__,\r
138 Status\r
139 ));\r
7b6745cc
AB
140 return EFI_SUCCESS;\r
141 }\r
142\r
cfc8d51c
AB
143 ASSERT (AddressCells == 2);\r
144 ASSERT (SizeCells == 2);\r
7b6745cc
AB
145 ASSERT (RegSize == 2 * sizeof (UINT64));\r
146\r
147 FwCfgDataAddress = SwapBytes64 (Reg[0]);\r
148 FwCfgDataSize = 8;\r
149 FwCfgSelectorAddress = FwCfgDataAddress + FwCfgDataSize;\r
150 FwCfgSelectorSize = 2;\r
151\r
152 //\r
153 // The following ASSERT()s express\r
154 //\r
155 // Address + Size - 1 <= MAX_UINTN\r
156 //\r
157 // for both registers, that is, that the last byte in each MMIO range is\r
158 // expressible as a MAX_UINTN. The form below is mathematically\r
159 // equivalent, and it also prevents any unsigned overflow before the\r
160 // comparison.\r
161 //\r
162 ASSERT (FwCfgSelectorAddress <= MAX_UINTN - FwCfgSelectorSize + 1);\r
163 ASSERT (FwCfgDataAddress <= MAX_UINTN - FwCfgDataSize + 1);\r
164\r
165 mFwCfgSelectorAddress = FwCfgSelectorAddress;\r
166 mFwCfgDataAddress = FwCfgDataAddress;\r
167\r
ac0a286f
MK
168 DEBUG ((\r
169 DEBUG_INFO,\r
170 "Found FwCfg @ 0x%Lx/0x%Lx\n",\r
171 FwCfgSelectorAddress,\r
172 FwCfgDataAddress\r
173 ));\r
7b6745cc
AB
174\r
175 if (SwapBytes64 (Reg[1]) >= 0x18) {\r
176 FwCfgDmaAddress = FwCfgDataAddress + 0x10;\r
177 FwCfgDmaSize = 0x08;\r
178\r
179 //\r
180 // See explanation above.\r
181 //\r
182 ASSERT (FwCfgDmaAddress <= MAX_UINTN - FwCfgDmaSize + 1);\r
183\r
47719926 184 DEBUG ((DEBUG_INFO, "Found FwCfg DMA @ 0x%Lx\n", FwCfgDmaAddress));\r
7b6745cc
AB
185 } else {\r
186 FwCfgDmaAddress = 0;\r
187 }\r
6e2543b0 188\r
1cb33be9 189 if (QemuFwCfgIsAvailable ()) {\r
ac0a286f 190 UINT32 Signature;\r
6e2543b0
LE
191\r
192 QemuFwCfgSelectItem (QemuFwCfgItemSignature);\r
193 Signature = QemuFwCfgRead32 ();\r
953bcbcc
LE
194 if (Signature == SIGNATURE_32 ('Q', 'E', 'M', 'U')) {\r
195 //\r
196 // For DMA support, we require the DTB to advertise the register, and the\r
197 // feature bitmap (which we read without DMA) to confirm the feature.\r
198 //\r
7b6745cc 199 if (FwCfgDmaAddress != 0) {\r
ac0a286f 200 UINT32 Features;\r
953bcbcc
LE
201\r
202 QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion);\r
203 Features = QemuFwCfgRead32 ();\r
d61a5f45 204 if ((Features & FW_CFG_F_DMA) != 0) {\r
ac0a286f
MK
205 mFwCfgDmaAddress = FwCfgDmaAddress;\r
206 InternalQemuFwCfgReadBytes = DmaReadBytes;\r
e8ae381f 207 InternalQemuFwCfgWriteBytes = DmaWriteBytes;\r
ac0a286f 208 InternalQemuFwCfgSkipBytes = DmaSkipBytes;\r
953bcbcc
LE
209 }\r
210 }\r
211 } else {\r
6e2543b0
LE
212 mFwCfgSelectorAddress = 0;\r
213 mFwCfgDataAddress = 0;\r
214 }\r
215 }\r
ac0a286f 216\r
6e2543b0
LE
217 return RETURN_SUCCESS;\r
218}\r
219\r
6e2543b0
LE
220/**\r
221 Selects a firmware configuration item for reading.\r
222\r
223 Following this call, any data read from this item will start from the\r
224 beginning of the configuration item's data.\r
225\r
226 @param[in] QemuFwCfgItem Firmware Configuration item to read\r
227\r
228**/\r
229VOID\r
230EFIAPI\r
231QemuFwCfgSelectItem (\r
ac0a286f 232 IN FIRMWARE_CONFIG_ITEM QemuFwCfgItem\r
6e2543b0
LE
233 )\r
234{\r
1cb33be9 235 if (QemuFwCfgIsAvailable ()) {\r
6e2543b0
LE
236 MmioWrite16 (mFwCfgSelectorAddress, SwapBytes16 ((UINT16)QemuFwCfgItem));\r
237 }\r
238}\r
239\r
6e2543b0 240/**\r
953bcbcc 241 Slow READ_BYTES_FUNCTION.\r
6e2543b0
LE
242**/\r
243STATIC\r
244VOID\r
245EFIAPI\r
953bcbcc 246MmioReadBytes (\r
ac0a286f
MK
247 IN UINTN Size,\r
248 IN VOID *Buffer OPTIONAL\r
6e2543b0
LE
249 )\r
250{\r
ac0a286f
MK
251 UINTN Left;\r
252 UINT8 *Ptr;\r
253 UINT8 *End;\r
6e2543b0 254\r
ac0a286f 255 #if defined (MDE_CPU_AARCH64) || defined (MDE_CPU_RISCV64)\r
6e2543b0 256 Left = Size & 7;\r
ac0a286f 257 #else\r
6e2543b0 258 Left = Size & 3;\r
ac0a286f 259 #endif\r
6e2543b0
LE
260\r
261 Size -= Left;\r
ac0a286f
MK
262 Ptr = Buffer;\r
263 End = Ptr + Size;\r
6e2543b0 264\r
ac0a286f 265 #if defined (MDE_CPU_AARCH64) || defined (MDE_CPU_RISCV64)\r
6e2543b0
LE
266 while (Ptr < End) {\r
267 *(UINT64 *)Ptr = MmioRead64 (mFwCfgDataAddress);\r
ac0a286f 268 Ptr += 8;\r
6e2543b0 269 }\r
ac0a286f 270\r
6e2543b0
LE
271 if (Left & 4) {\r
272 *(UINT32 *)Ptr = MmioRead32 (mFwCfgDataAddress);\r
ac0a286f 273 Ptr += 4;\r
6e2543b0 274 }\r
ac0a286f
MK
275\r
276 #else\r
6e2543b0
LE
277 while (Ptr < End) {\r
278 *(UINT32 *)Ptr = MmioRead32 (mFwCfgDataAddress);\r
ac0a286f 279 Ptr += 4;\r
6e2543b0 280 }\r
ac0a286f
MK
281\r
282 #endif\r
6e2543b0
LE
283\r
284 if (Left & 2) {\r
285 *(UINT16 *)Ptr = MmioRead16 (mFwCfgDataAddress);\r
ac0a286f 286 Ptr += 2;\r
6e2543b0 287 }\r
ac0a286f 288\r
6e2543b0
LE
289 if (Left & 1) {\r
290 *Ptr = MmioRead8 (mFwCfgDataAddress);\r
291 }\r
292}\r
293\r
953bcbcc 294/**\r
4175356f
LE
295 Transfer an array of bytes, or skip a number of bytes, using the DMA\r
296 interface.\r
297\r
298 @param[in] Size Size in bytes to transfer or skip.\r
299\r
300 @param[in,out] Buffer Buffer to read data into or write data from. Ignored,\r
301 and may be NULL, if Size is zero, or Control is\r
302 FW_CFG_DMA_CTL_SKIP.\r
303\r
304 @param[in] Control One of the following:\r
305 FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer.\r
306 FW_CFG_DMA_CTL_READ - read from fw_cfg into Buffer.\r
307 FW_CFG_DMA_CTL_SKIP - skip bytes in fw_cfg.\r
953bcbcc
LE
308**/\r
309STATIC\r
310VOID\r
4175356f 311DmaTransferBytes (\r
ac0a286f
MK
312 IN UINTN Size,\r
313 IN OUT VOID *Buffer OPTIONAL,\r
314 IN UINT32 Control\r
953bcbcc
LE
315 )\r
316{\r
ac0a286f
MK
317 volatile FW_CFG_DMA_ACCESS Access;\r
318 UINT32 Status;\r
953bcbcc 319\r
ac0a286f
MK
320 ASSERT (\r
321 Control == FW_CFG_DMA_CTL_WRITE || Control == FW_CFG_DMA_CTL_READ ||\r
322 Control == FW_CFG_DMA_CTL_SKIP\r
323 );\r
4175356f 324\r
953bcbcc
LE
325 if (Size == 0) {\r
326 return;\r
327 }\r
328\r
329 ASSERT (Size <= MAX_UINT32);\r
330\r
4175356f 331 Access.Control = SwapBytes32 (Control);\r
953bcbcc
LE
332 Access.Length = SwapBytes32 ((UINT32)Size);\r
333 Access.Address = SwapBytes64 ((UINT64)(UINTN)Buffer);\r
334\r
335 //\r
336 // We shouldn't start the transfer before setting up Access.\r
337 //\r
338 MemoryFence ();\r
339\r
340 //\r
341 // This will fire off the transfer.\r
342 //\r
ac0a286f 343 #if defined (MDE_CPU_AARCH64) || defined (MDE_CPU_RISCV64)\r
953bcbcc 344 MmioWrite64 (mFwCfgDmaAddress, SwapBytes64 ((UINT64)&Access));\r
ac0a286f 345 #else\r
953bcbcc 346 MmioWrite32 ((UINT32)(mFwCfgDmaAddress + 4), SwapBytes32 ((UINT32)&Access));\r
ac0a286f 347 #endif\r
953bcbcc
LE
348\r
349 //\r
350 // We shouldn't look at Access.Control before starting the transfer.\r
351 //\r
352 MemoryFence ();\r
353\r
354 do {\r
355 Status = SwapBytes32 (Access.Control);\r
356 ASSERT ((Status & FW_CFG_DMA_CTL_ERROR) == 0);\r
357 } while (Status != 0);\r
358\r
359 //\r
360 // The caller will want to access the transferred data.\r
361 //\r
362 MemoryFence ();\r
363}\r
364\r
4175356f
LE
365/**\r
366 Fast READ_BYTES_FUNCTION.\r
367**/\r
368STATIC\r
369VOID\r
370EFIAPI\r
371DmaReadBytes (\r
ac0a286f
MK
372 IN UINTN Size,\r
373 IN VOID *Buffer OPTIONAL\r
4175356f
LE
374 )\r
375{\r
376 DmaTransferBytes (Size, Buffer, FW_CFG_DMA_CTL_READ);\r
377}\r
378\r
6e2543b0
LE
379/**\r
380 Reads firmware configuration bytes into a buffer\r
381\r
382 If called multiple times, then the data read will continue at the offset of\r
383 the firmware configuration item where the previous read ended.\r
384\r
385 @param[in] Size Size in bytes to read\r
386 @param[in] Buffer Buffer to store data into\r
387\r
388**/\r
389VOID\r
390EFIAPI\r
391QemuFwCfgReadBytes (\r
ac0a286f
MK
392 IN UINTN Size,\r
393 IN VOID *Buffer\r
6e2543b0
LE
394 )\r
395{\r
1cb33be9 396 if (QemuFwCfgIsAvailable ()) {\r
6e2543b0
LE
397 InternalQemuFwCfgReadBytes (Size, Buffer);\r
398 } else {\r
399 ZeroMem (Buffer, Size);\r
400 }\r
401}\r
402\r
e8ae381f
LE
403/**\r
404 Slow WRITE_BYTES_FUNCTION.\r
405**/\r
406STATIC\r
407VOID\r
408EFIAPI\r
409MmioWriteBytes (\r
ac0a286f
MK
410 IN UINTN Size,\r
411 IN VOID *Buffer OPTIONAL\r
e8ae381f
LE
412 )\r
413{\r
ac0a286f 414 UINTN Idx;\r
e8ae381f
LE
415\r
416 for (Idx = 0; Idx < Size; ++Idx) {\r
417 MmioWrite8 (mFwCfgDataAddress, ((UINT8 *)Buffer)[Idx]);\r
418 }\r
419}\r
420\r
e8ae381f
LE
421/**\r
422 Fast WRITE_BYTES_FUNCTION.\r
423**/\r
424STATIC\r
425VOID\r
426EFIAPI\r
427DmaWriteBytes (\r
ac0a286f
MK
428 IN UINTN Size,\r
429 IN VOID *Buffer OPTIONAL\r
e8ae381f
LE
430 )\r
431{\r
432 DmaTransferBytes (Size, Buffer, FW_CFG_DMA_CTL_WRITE);\r
433}\r
434\r
6e2543b0
LE
435/**\r
436 Write firmware configuration bytes from a buffer\r
437\r
438 If called multiple times, then the data written will continue at the offset\r
439 of the firmware configuration item where the previous write ended.\r
440\r
441 @param[in] Size Size in bytes to write\r
442 @param[in] Buffer Buffer to read data from\r
443\r
444**/\r
445VOID\r
446EFIAPI\r
447QemuFwCfgWriteBytes (\r
ac0a286f
MK
448 IN UINTN Size,\r
449 IN VOID *Buffer\r
6e2543b0
LE
450 )\r
451{\r
1cb33be9 452 if (QemuFwCfgIsAvailable ()) {\r
e8ae381f 453 InternalQemuFwCfgWriteBytes (Size, Buffer);\r
6e2543b0
LE
454 }\r
455}\r
456\r
7fcb7354
LE
457/**\r
458 Slow SKIP_BYTES_FUNCTION.\r
459**/\r
460STATIC\r
461VOID\r
462EFIAPI\r
463MmioSkipBytes (\r
ac0a286f 464 IN UINTN Size\r
7fcb7354
LE
465 )\r
466{\r
ac0a286f
MK
467 UINTN ChunkSize;\r
468 UINT8 SkipBuffer[256];\r
7fcb7354
LE
469\r
470 //\r
471 // Emulate the skip by reading data in chunks, and throwing it away. The\r
472 // implementation below doesn't affect the static data footprint for client\r
473 // modules. Large skips are not expected, therefore this fallback is not\r
474 // performance critical. The size of SkipBuffer is thought not to exert a\r
475 // large pressure on the stack.\r
476 //\r
477 while (Size > 0) {\r
478 ChunkSize = MIN (Size, sizeof SkipBuffer);\r
479 MmioReadBytes (ChunkSize, SkipBuffer);\r
480 Size -= ChunkSize;\r
481 }\r
482}\r
483\r
7fcb7354
LE
484/**\r
485 Fast SKIP_BYTES_FUNCTION.\r
486**/\r
487STATIC\r
488VOID\r
489EFIAPI\r
490DmaSkipBytes (\r
ac0a286f 491 IN UINTN Size\r
7fcb7354
LE
492 )\r
493{\r
494 DmaTransferBytes (Size, NULL, FW_CFG_DMA_CTL_SKIP);\r
495}\r
496\r
7fcb7354
LE
497/**\r
498 Skip bytes in the firmware configuration item.\r
499\r
500 Increase the offset of the firmware configuration item without transferring\r
501 bytes between the item and a caller-provided buffer. Subsequent read, write\r
502 or skip operations will commence at the increased offset.\r
503\r
504 @param[in] Size Number of bytes to skip.\r
505**/\r
506VOID\r
507EFIAPI\r
508QemuFwCfgSkipBytes (\r
ac0a286f 509 IN UINTN Size\r
7fcb7354
LE
510 )\r
511{\r
512 if (QemuFwCfgIsAvailable ()) {\r
513 InternalQemuFwCfgSkipBytes (Size);\r
514 }\r
515}\r
516\r
6e2543b0
LE
517/**\r
518 Reads a UINT8 firmware configuration value\r
519\r
520 @return Value of Firmware Configuration item read\r
521\r
522**/\r
523UINT8\r
524EFIAPI\r
525QemuFwCfgRead8 (\r
526 VOID\r
527 )\r
528{\r
ac0a286f 529 UINT8 Result;\r
6e2543b0
LE
530\r
531 QemuFwCfgReadBytes (sizeof Result, &Result);\r
532 return Result;\r
533}\r
534\r
6e2543b0
LE
535/**\r
536 Reads a UINT16 firmware configuration value\r
537\r
538 @return Value of Firmware Configuration item read\r
539\r
540**/\r
541UINT16\r
542EFIAPI\r
543QemuFwCfgRead16 (\r
544 VOID\r
545 )\r
546{\r
ac0a286f 547 UINT16 Result;\r
6e2543b0
LE
548\r
549 QemuFwCfgReadBytes (sizeof Result, &Result);\r
550 return Result;\r
551}\r
552\r
6e2543b0
LE
553/**\r
554 Reads a UINT32 firmware configuration value\r
555\r
556 @return Value of Firmware Configuration item read\r
557\r
558**/\r
559UINT32\r
560EFIAPI\r
561QemuFwCfgRead32 (\r
562 VOID\r
563 )\r
564{\r
ac0a286f 565 UINT32 Result;\r
6e2543b0
LE
566\r
567 QemuFwCfgReadBytes (sizeof Result, &Result);\r
568 return Result;\r
569}\r
570\r
6e2543b0
LE
571/**\r
572 Reads a UINT64 firmware configuration value\r
573\r
574 @return Value of Firmware Configuration item read\r
575\r
576**/\r
577UINT64\r
578EFIAPI\r
579QemuFwCfgRead64 (\r
580 VOID\r
581 )\r
582{\r
ac0a286f 583 UINT64 Result;\r
6e2543b0
LE
584\r
585 QemuFwCfgReadBytes (sizeof Result, &Result);\r
586 return Result;\r
587}\r
588\r
6e2543b0
LE
589/**\r
590 Find the configuration item corresponding to the firmware configuration file.\r
591\r
592 @param[in] Name Name of file to look up.\r
593 @param[out] Item Configuration item corresponding to the file, to be passed\r
594 to QemuFwCfgSelectItem ().\r
595 @param[out] Size Number of bytes in the file.\r
596\r
597 @retval RETURN_SUCCESS If file is found.\r
598 @retval RETURN_NOT_FOUND If file is not found.\r
599 @retval RETURN_UNSUPPORTED If firmware configuration is unavailable.\r
600\r
601**/\r
602RETURN_STATUS\r
603EFIAPI\r
604QemuFwCfgFindFile (\r
605 IN CONST CHAR8 *Name,\r
606 OUT FIRMWARE_CONFIG_ITEM *Item,\r
607 OUT UINTN *Size\r
608 )\r
609{\r
ac0a286f
MK
610 UINT32 Count;\r
611 UINT32 Idx;\r
6e2543b0 612\r
1cb33be9 613 if (!QemuFwCfgIsAvailable ()) {\r
6e2543b0
LE
614 return RETURN_UNSUPPORTED;\r
615 }\r
616\r
617 QemuFwCfgSelectItem (QemuFwCfgItemFileDir);\r
618 Count = SwapBytes32 (QemuFwCfgRead32 ());\r
619\r
620 for (Idx = 0; Idx < Count; ++Idx) {\r
ac0a286f
MK
621 UINT32 FileSize;\r
622 UINT16 FileSelect;\r
623 CHAR8 FName[QEMU_FW_CFG_FNAME_SIZE];\r
6e2543b0
LE
624\r
625 FileSize = QemuFwCfgRead32 ();\r
626 FileSelect = QemuFwCfgRead16 ();\r
627 QemuFwCfgRead16 (); // skip the field called "reserved"\r
628 InternalQemuFwCfgReadBytes (sizeof (FName), FName);\r
629\r
630 if (AsciiStrCmp (Name, FName) == 0) {\r
ac0a286f 631 *Item = (FIRMWARE_CONFIG_ITEM)SwapBytes16 (FileSelect);\r
6e2543b0
LE
632 *Size = SwapBytes32 (FileSize);\r
633 return RETURN_SUCCESS;\r
634 }\r
635 }\r
636\r
637 return RETURN_NOT_FOUND;\r
638}\r