]> git.proxmox.com Git - mirror_edk2.git/blame - ArmVirtPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c
ArmVirtPkg/QemuFwCfgLib: remove superfluous InternalQemuFwCfgIsAvailable()
[mirror_edk2.git] / ArmVirtPkg / Library / QemuFwCfgLib / QemuFwCfgLib.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
7\r
8 This program and the accompanying materials are licensed and made available\r
9 under the terms and conditions of the BSD License which accompanies this\r
10 distribution. The full text of the license may be found at\r
11 http://opensource.org/licenses/bsd-license.php\r
12\r
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
14 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
15**/\r
16\r
7b6745cc
AB
17#include <Uefi.h>\r
18\r
6e2543b0
LE
19#include <Library/BaseLib.h>\r
20#include <Library/BaseMemoryLib.h>\r
953bcbcc 21#include <Library/DebugLib.h>\r
6e2543b0 22#include <Library/IoLib.h>\r
6e2543b0 23#include <Library/QemuFwCfgLib.h>\r
7b6745cc
AB
24#include <Library/UefiBootServicesTableLib.h>\r
25\r
26#include <Protocol/FdtClient.h>\r
6e2543b0
LE
27\r
28STATIC UINTN mFwCfgSelectorAddress;\r
29STATIC UINTN mFwCfgDataAddress;\r
953bcbcc
LE
30STATIC UINTN mFwCfgDmaAddress;\r
31\r
32/**\r
33 Reads firmware configuration bytes into a buffer\r
34\r
35 @param[in] Size Size in bytes to read\r
36 @param[in] Buffer Buffer to store data into (OPTIONAL if Size is 0)\r
37\r
38**/\r
39typedef\r
40VOID (EFIAPI READ_BYTES_FUNCTION) (\r
41 IN UINTN Size,\r
42 IN VOID *Buffer OPTIONAL\r
43 );\r
44\r
45//\r
46// Forward declaration of the two implementations we have.\r
47//\r
48STATIC READ_BYTES_FUNCTION MmioReadBytes;\r
49STATIC READ_BYTES_FUNCTION DmaReadBytes;\r
50\r
51//\r
52// This points to the one we detect at runtime.\r
53//\r
54STATIC READ_BYTES_FUNCTION *InternalQemuFwCfgReadBytes = MmioReadBytes;\r
55\r
56//\r
57// Communication structure for DmaReadBytes(). All fields are encoded in big\r
58// endian.\r
59//\r
60#pragma pack (1)\r
61typedef struct {\r
62 UINT32 Control;\r
63 UINT32 Length;\r
64 UINT64 Address;\r
65} FW_CFG_DMA_ACCESS;\r
66#pragma pack ()\r
67\r
68//\r
69// Macros for the FW_CFG_DMA_ACCESS.Control bitmap (in native encoding).\r
70//\r
71#define FW_CFG_DMA_CTL_ERROR BIT0\r
72#define FW_CFG_DMA_CTL_READ BIT1\r
73#define FW_CFG_DMA_CTL_SKIP BIT2\r
74#define FW_CFG_DMA_CTL_SELECT BIT3\r
6e2543b0
LE
75\r
76\r
6e2543b0
LE
77/**\r
78 Returns a boolean indicating if the firmware configuration interface\r
79 is available or not.\r
80\r
81 This function may change fw_cfg state.\r
82\r
83 @retval TRUE The interface is available\r
84 @retval FALSE The interface is not available\r
85\r
86**/\r
87BOOLEAN\r
88EFIAPI\r
89QemuFwCfgIsAvailable (\r
90 VOID\r
91 )\r
92{\r
1cb33be9 93 return (BOOLEAN)(mFwCfgSelectorAddress != 0 && mFwCfgDataAddress != 0);\r
6e2543b0
LE
94}\r
95\r
96\r
97RETURN_STATUS\r
98EFIAPI\r
99QemuFwCfgInitialize (\r
100 VOID\r
101 )\r
102{\r
7b6745cc
AB
103 EFI_STATUS Status;\r
104 FDT_CLIENT_PROTOCOL *FdtClient;\r
105 CONST UINT64 *Reg;\r
cfc8d51c
AB
106 UINT32 RegSize;\r
107 UINTN AddressCells, SizeCells;\r
7b6745cc
AB
108 UINT64 FwCfgSelectorAddress;\r
109 UINT64 FwCfgSelectorSize;\r
110 UINT64 FwCfgDataAddress;\r
111 UINT64 FwCfgDataSize;\r
112 UINT64 FwCfgDmaAddress;\r
113 UINT64 FwCfgDmaSize;\r
114\r
115 Status = gBS->LocateProtocol (&gFdtClientProtocolGuid, NULL,\r
116 (VOID **)&FdtClient);\r
117 ASSERT_EFI_ERROR (Status);\r
118\r
119 Status = FdtClient->FindCompatibleNodeReg (FdtClient, "qemu,fw-cfg-mmio",\r
cfc8d51c
AB
120 (CONST VOID **)&Reg, &AddressCells, &SizeCells,\r
121 &RegSize);\r
7b6745cc
AB
122 if (EFI_ERROR (Status)) {\r
123 DEBUG ((EFI_D_WARN,\r
124 "%a: No 'qemu,fw-cfg-mmio' compatible DT node found (Status == %r)\n",\r
125 __FUNCTION__, Status));\r
126 return EFI_SUCCESS;\r
127 }\r
128\r
cfc8d51c
AB
129 ASSERT (AddressCells == 2);\r
130 ASSERT (SizeCells == 2);\r
7b6745cc
AB
131 ASSERT (RegSize == 2 * sizeof (UINT64));\r
132\r
133 FwCfgDataAddress = SwapBytes64 (Reg[0]);\r
134 FwCfgDataSize = 8;\r
135 FwCfgSelectorAddress = FwCfgDataAddress + FwCfgDataSize;\r
136 FwCfgSelectorSize = 2;\r
137\r
138 //\r
139 // The following ASSERT()s express\r
140 //\r
141 // Address + Size - 1 <= MAX_UINTN\r
142 //\r
143 // for both registers, that is, that the last byte in each MMIO range is\r
144 // expressible as a MAX_UINTN. The form below is mathematically\r
145 // equivalent, and it also prevents any unsigned overflow before the\r
146 // comparison.\r
147 //\r
148 ASSERT (FwCfgSelectorAddress <= MAX_UINTN - FwCfgSelectorSize + 1);\r
149 ASSERT (FwCfgDataAddress <= MAX_UINTN - FwCfgDataSize + 1);\r
150\r
151 mFwCfgSelectorAddress = FwCfgSelectorAddress;\r
152 mFwCfgDataAddress = FwCfgDataAddress;\r
153\r
154 DEBUG ((EFI_D_INFO, "Found FwCfg @ 0x%Lx/0x%Lx\n", FwCfgSelectorAddress,\r
155 FwCfgDataAddress));\r
156\r
157 if (SwapBytes64 (Reg[1]) >= 0x18) {\r
158 FwCfgDmaAddress = FwCfgDataAddress + 0x10;\r
159 FwCfgDmaSize = 0x08;\r
160\r
161 //\r
162 // See explanation above.\r
163 //\r
164 ASSERT (FwCfgDmaAddress <= MAX_UINTN - FwCfgDmaSize + 1);\r
165\r
166 DEBUG ((EFI_D_INFO, "Found FwCfg DMA @ 0x%Lx\n", FwCfgDmaAddress));\r
167 } else {\r
168 FwCfgDmaAddress = 0;\r
169 }\r
6e2543b0 170\r
1cb33be9 171 if (QemuFwCfgIsAvailable ()) {\r
6e2543b0
LE
172 UINT32 Signature;\r
173\r
174 QemuFwCfgSelectItem (QemuFwCfgItemSignature);\r
175 Signature = QemuFwCfgRead32 ();\r
953bcbcc
LE
176 if (Signature == SIGNATURE_32 ('Q', 'E', 'M', 'U')) {\r
177 //\r
178 // For DMA support, we require the DTB to advertise the register, and the\r
179 // feature bitmap (which we read without DMA) to confirm the feature.\r
180 //\r
7b6745cc 181 if (FwCfgDmaAddress != 0) {\r
953bcbcc
LE
182 UINT32 Features;\r
183\r
184 QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion);\r
185 Features = QemuFwCfgRead32 ();\r
186 if ((Features & BIT1) != 0) {\r
7b6745cc 187 mFwCfgDmaAddress = FwCfgDmaAddress;\r
953bcbcc
LE
188 InternalQemuFwCfgReadBytes = DmaReadBytes;\r
189 }\r
190 }\r
191 } else {\r
6e2543b0
LE
192 mFwCfgSelectorAddress = 0;\r
193 mFwCfgDataAddress = 0;\r
194 }\r
195 }\r
196 return RETURN_SUCCESS;\r
197}\r
198\r
199\r
200/**\r
201 Selects a firmware configuration item for reading.\r
202\r
203 Following this call, any data read from this item will start from the\r
204 beginning of the configuration item's data.\r
205\r
206 @param[in] QemuFwCfgItem Firmware Configuration item to read\r
207\r
208**/\r
209VOID\r
210EFIAPI\r
211QemuFwCfgSelectItem (\r
212 IN FIRMWARE_CONFIG_ITEM QemuFwCfgItem\r
213 )\r
214{\r
1cb33be9 215 if (QemuFwCfgIsAvailable ()) {\r
6e2543b0
LE
216 MmioWrite16 (mFwCfgSelectorAddress, SwapBytes16 ((UINT16)QemuFwCfgItem));\r
217 }\r
218}\r
219\r
220\r
221/**\r
953bcbcc 222 Slow READ_BYTES_FUNCTION.\r
6e2543b0
LE
223**/\r
224STATIC\r
225VOID\r
226EFIAPI\r
953bcbcc 227MmioReadBytes (\r
6e2543b0
LE
228 IN UINTN Size,\r
229 IN VOID *Buffer OPTIONAL\r
230 )\r
231{\r
232 UINTN Left;\r
233 UINT8 *Ptr;\r
234 UINT8 *End;\r
235\r
236#ifdef MDE_CPU_AARCH64\r
237 Left = Size & 7;\r
238#else\r
239 Left = Size & 3;\r
240#endif\r
241\r
242 Size -= Left;\r
243 Ptr = Buffer;\r
244 End = Ptr + Size;\r
245\r
246#ifdef MDE_CPU_AARCH64\r
247 while (Ptr < End) {\r
248 *(UINT64 *)Ptr = MmioRead64 (mFwCfgDataAddress);\r
249 Ptr += 8;\r
250 }\r
251 if (Left & 4) {\r
252 *(UINT32 *)Ptr = MmioRead32 (mFwCfgDataAddress);\r
253 Ptr += 4;\r
254 }\r
255#else\r
256 while (Ptr < End) {\r
257 *(UINT32 *)Ptr = MmioRead32 (mFwCfgDataAddress);\r
258 Ptr += 4;\r
259 }\r
260#endif\r
261\r
262 if (Left & 2) {\r
263 *(UINT16 *)Ptr = MmioRead16 (mFwCfgDataAddress);\r
264 Ptr += 2;\r
265 }\r
266 if (Left & 1) {\r
267 *Ptr = MmioRead8 (mFwCfgDataAddress);\r
268 }\r
269}\r
270\r
271\r
953bcbcc
LE
272/**\r
273 Fast READ_BYTES_FUNCTION.\r
274**/\r
275STATIC\r
276VOID\r
277EFIAPI\r
278DmaReadBytes (\r
279 IN UINTN Size,\r
280 IN VOID *Buffer OPTIONAL\r
281 )\r
282{\r
283 volatile FW_CFG_DMA_ACCESS Access;\r
284 UINT32 Status;\r
285\r
286 if (Size == 0) {\r
287 return;\r
288 }\r
289\r
290 ASSERT (Size <= MAX_UINT32);\r
291\r
292 Access.Control = SwapBytes32 (FW_CFG_DMA_CTL_READ);\r
293 Access.Length = SwapBytes32 ((UINT32)Size);\r
294 Access.Address = SwapBytes64 ((UINT64)(UINTN)Buffer);\r
295\r
296 //\r
297 // We shouldn't start the transfer before setting up Access.\r
298 //\r
299 MemoryFence ();\r
300\r
301 //\r
302 // This will fire off the transfer.\r
303 //\r
304#ifdef MDE_CPU_AARCH64\r
305 MmioWrite64 (mFwCfgDmaAddress, SwapBytes64 ((UINT64)&Access));\r
306#else\r
307 MmioWrite32 ((UINT32)(mFwCfgDmaAddress + 4), SwapBytes32 ((UINT32)&Access));\r
308#endif\r
309\r
310 //\r
311 // We shouldn't look at Access.Control before starting the transfer.\r
312 //\r
313 MemoryFence ();\r
314\r
315 do {\r
316 Status = SwapBytes32 (Access.Control);\r
317 ASSERT ((Status & FW_CFG_DMA_CTL_ERROR) == 0);\r
318 } while (Status != 0);\r
319\r
320 //\r
321 // The caller will want to access the transferred data.\r
322 //\r
323 MemoryFence ();\r
324}\r
325\r
326\r
6e2543b0
LE
327/**\r
328 Reads firmware configuration bytes into a buffer\r
329\r
330 If called multiple times, then the data read will continue at the offset of\r
331 the firmware configuration item where the previous read ended.\r
332\r
333 @param[in] Size Size in bytes to read\r
334 @param[in] Buffer Buffer to store data into\r
335\r
336**/\r
337VOID\r
338EFIAPI\r
339QemuFwCfgReadBytes (\r
340 IN UINTN Size,\r
341 IN VOID *Buffer\r
342 )\r
343{\r
1cb33be9 344 if (QemuFwCfgIsAvailable ()) {\r
6e2543b0
LE
345 InternalQemuFwCfgReadBytes (Size, Buffer);\r
346 } else {\r
347 ZeroMem (Buffer, Size);\r
348 }\r
349}\r
350\r
351/**\r
352 Write firmware configuration bytes from a buffer\r
353\r
354 If called multiple times, then the data written will continue at the offset\r
355 of the firmware configuration item where the previous write ended.\r
356\r
357 @param[in] Size Size in bytes to write\r
358 @param[in] Buffer Buffer to read data from\r
359\r
360**/\r
361VOID\r
362EFIAPI\r
363QemuFwCfgWriteBytes (\r
364 IN UINTN Size,\r
365 IN VOID *Buffer\r
366 )\r
367{\r
1cb33be9 368 if (QemuFwCfgIsAvailable ()) {\r
6e2543b0
LE
369 UINTN Idx;\r
370\r
371 for (Idx = 0; Idx < Size; ++Idx) {\r
372 MmioWrite8 (mFwCfgDataAddress, ((UINT8 *)Buffer)[Idx]);\r
373 }\r
374 }\r
375}\r
376\r
377\r
378/**\r
379 Reads a UINT8 firmware configuration value\r
380\r
381 @return Value of Firmware Configuration item read\r
382\r
383**/\r
384UINT8\r
385EFIAPI\r
386QemuFwCfgRead8 (\r
387 VOID\r
388 )\r
389{\r
390 UINT8 Result;\r
391\r
392 QemuFwCfgReadBytes (sizeof Result, &Result);\r
393 return Result;\r
394}\r
395\r
396\r
397/**\r
398 Reads a UINT16 firmware configuration value\r
399\r
400 @return Value of Firmware Configuration item read\r
401\r
402**/\r
403UINT16\r
404EFIAPI\r
405QemuFwCfgRead16 (\r
406 VOID\r
407 )\r
408{\r
409 UINT16 Result;\r
410\r
411 QemuFwCfgReadBytes (sizeof Result, &Result);\r
412 return Result;\r
413}\r
414\r
415\r
416/**\r
417 Reads a UINT32 firmware configuration value\r
418\r
419 @return Value of Firmware Configuration item read\r
420\r
421**/\r
422UINT32\r
423EFIAPI\r
424QemuFwCfgRead32 (\r
425 VOID\r
426 )\r
427{\r
428 UINT32 Result;\r
429\r
430 QemuFwCfgReadBytes (sizeof Result, &Result);\r
431 return Result;\r
432}\r
433\r
434\r
435/**\r
436 Reads a UINT64 firmware configuration value\r
437\r
438 @return Value of Firmware Configuration item read\r
439\r
440**/\r
441UINT64\r
442EFIAPI\r
443QemuFwCfgRead64 (\r
444 VOID\r
445 )\r
446{\r
447 UINT64 Result;\r
448\r
449 QemuFwCfgReadBytes (sizeof Result, &Result);\r
450 return Result;\r
451}\r
452\r
453\r
454/**\r
455 Find the configuration item corresponding to the firmware configuration file.\r
456\r
457 @param[in] Name Name of file to look up.\r
458 @param[out] Item Configuration item corresponding to the file, to be passed\r
459 to QemuFwCfgSelectItem ().\r
460 @param[out] Size Number of bytes in the file.\r
461\r
462 @retval RETURN_SUCCESS If file is found.\r
463 @retval RETURN_NOT_FOUND If file is not found.\r
464 @retval RETURN_UNSUPPORTED If firmware configuration is unavailable.\r
465\r
466**/\r
467RETURN_STATUS\r
468EFIAPI\r
469QemuFwCfgFindFile (\r
470 IN CONST CHAR8 *Name,\r
471 OUT FIRMWARE_CONFIG_ITEM *Item,\r
472 OUT UINTN *Size\r
473 )\r
474{\r
475 UINT32 Count;\r
476 UINT32 Idx;\r
477\r
1cb33be9 478 if (!QemuFwCfgIsAvailable ()) {\r
6e2543b0
LE
479 return RETURN_UNSUPPORTED;\r
480 }\r
481\r
482 QemuFwCfgSelectItem (QemuFwCfgItemFileDir);\r
483 Count = SwapBytes32 (QemuFwCfgRead32 ());\r
484\r
485 for (Idx = 0; Idx < Count; ++Idx) {\r
486 UINT32 FileSize;\r
487 UINT16 FileSelect;\r
488 CHAR8 FName[QEMU_FW_CFG_FNAME_SIZE];\r
489\r
490 FileSize = QemuFwCfgRead32 ();\r
491 FileSelect = QemuFwCfgRead16 ();\r
492 QemuFwCfgRead16 (); // skip the field called "reserved"\r
493 InternalQemuFwCfgReadBytes (sizeof (FName), FName);\r
494\r
495 if (AsciiStrCmp (Name, FName) == 0) {\r
3f318fbf 496 *Item = (FIRMWARE_CONFIG_ITEM) SwapBytes16 (FileSelect);\r
6e2543b0
LE
497 *Size = SwapBytes32 (FileSize);\r
498 return RETURN_SUCCESS;\r
499 }\r
500 }\r
501\r
502 return RETURN_NOT_FOUND;\r
503}\r
504\r
505\r
506/**\r
507 Determine if S3 support is explicitly enabled.\r
508\r
509 @retval TRUE if S3 support is explicitly enabled.\r
510 FALSE otherwise. This includes unavailability of the firmware\r
511 configuration interface.\r
512**/\r
513BOOLEAN\r
514EFIAPI\r
515QemuFwCfgS3Enabled (\r
516 VOID\r
517 )\r
518{\r
519 return FALSE;\r
520}\r