]> git.proxmox.com Git - mirror_edk2.git/blame - ArmVirtPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c
BaseTools: use unsigned chars on ARM architectures
[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
17#include <Library/BaseLib.h>\r
18#include <Library/BaseMemoryLib.h>\r
953bcbcc 19#include <Library/DebugLib.h>\r
6e2543b0
LE
20#include <Library/IoLib.h>\r
21#include <Library/PcdLib.h>\r
22#include <Library/QemuFwCfgLib.h>\r
23\r
24STATIC UINTN mFwCfgSelectorAddress;\r
25STATIC UINTN mFwCfgDataAddress;\r
953bcbcc
LE
26STATIC UINTN mFwCfgDmaAddress;\r
27\r
28/**\r
29 Reads firmware configuration bytes into a buffer\r
30\r
31 @param[in] Size Size in bytes to read\r
32 @param[in] Buffer Buffer to store data into (OPTIONAL if Size is 0)\r
33\r
34**/\r
35typedef\r
36VOID (EFIAPI READ_BYTES_FUNCTION) (\r
37 IN UINTN Size,\r
38 IN VOID *Buffer OPTIONAL\r
39 );\r
40\r
41//\r
42// Forward declaration of the two implementations we have.\r
43//\r
44STATIC READ_BYTES_FUNCTION MmioReadBytes;\r
45STATIC READ_BYTES_FUNCTION DmaReadBytes;\r
46\r
47//\r
48// This points to the one we detect at runtime.\r
49//\r
50STATIC READ_BYTES_FUNCTION *InternalQemuFwCfgReadBytes = MmioReadBytes;\r
51\r
52//\r
53// Communication structure for DmaReadBytes(). All fields are encoded in big\r
54// endian.\r
55//\r
56#pragma pack (1)\r
57typedef struct {\r
58 UINT32 Control;\r
59 UINT32 Length;\r
60 UINT64 Address;\r
61} FW_CFG_DMA_ACCESS;\r
62#pragma pack ()\r
63\r
64//\r
65// Macros for the FW_CFG_DMA_ACCESS.Control bitmap (in native encoding).\r
66//\r
67#define FW_CFG_DMA_CTL_ERROR BIT0\r
68#define FW_CFG_DMA_CTL_READ BIT1\r
69#define FW_CFG_DMA_CTL_SKIP BIT2\r
70#define FW_CFG_DMA_CTL_SELECT BIT3\r
6e2543b0
LE
71\r
72\r
73/**\r
74 Returns a boolean indicating if the firmware configuration interface is\r
75 available for library-internal purposes.\r
76\r
77 This function never changes fw_cfg state.\r
78\r
79 @retval TRUE The interface is available internally.\r
80 @retval FALSE The interface is not available internally.\r
81**/\r
82BOOLEAN\r
83EFIAPI\r
84InternalQemuFwCfgIsAvailable (\r
85 VOID\r
86 )\r
87{\r
88 return (BOOLEAN)(mFwCfgSelectorAddress != 0 && mFwCfgDataAddress != 0);\r
89}\r
90\r
91\r
92/**\r
93 Returns a boolean indicating if the firmware configuration interface\r
94 is available or not.\r
95\r
96 This function may change fw_cfg state.\r
97\r
98 @retval TRUE The interface is available\r
99 @retval FALSE The interface is not available\r
100\r
101**/\r
102BOOLEAN\r
103EFIAPI\r
104QemuFwCfgIsAvailable (\r
105 VOID\r
106 )\r
107{\r
108 return InternalQemuFwCfgIsAvailable ();\r
109}\r
110\r
111\r
112RETURN_STATUS\r
113EFIAPI\r
114QemuFwCfgInitialize (\r
115 VOID\r
116 )\r
117{\r
118 mFwCfgSelectorAddress = (UINTN)PcdGet64 (PcdFwCfgSelectorAddress);\r
119 mFwCfgDataAddress = (UINTN)PcdGet64 (PcdFwCfgDataAddress);\r
120\r
121 if (InternalQemuFwCfgIsAvailable ()) {\r
122 UINT32 Signature;\r
123\r
124 QemuFwCfgSelectItem (QemuFwCfgItemSignature);\r
125 Signature = QemuFwCfgRead32 ();\r
953bcbcc
LE
126 if (Signature == SIGNATURE_32 ('Q', 'E', 'M', 'U')) {\r
127 //\r
128 // For DMA support, we require the DTB to advertise the register, and the\r
129 // feature bitmap (which we read without DMA) to confirm the feature.\r
130 //\r
131 if (PcdGet64 (PcdFwCfgDmaAddress) != 0) {\r
132 UINT32 Features;\r
133\r
134 QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion);\r
135 Features = QemuFwCfgRead32 ();\r
136 if ((Features & BIT1) != 0) {\r
137 mFwCfgDmaAddress = PcdGet64 (PcdFwCfgDmaAddress);\r
138 InternalQemuFwCfgReadBytes = DmaReadBytes;\r
139 }\r
140 }\r
141 } else {\r
6e2543b0
LE
142 mFwCfgSelectorAddress = 0;\r
143 mFwCfgDataAddress = 0;\r
144 }\r
145 }\r
146 return RETURN_SUCCESS;\r
147}\r
148\r
149\r
150/**\r
151 Selects a firmware configuration item for reading.\r
152\r
153 Following this call, any data read from this item will start from the\r
154 beginning of the configuration item's data.\r
155\r
156 @param[in] QemuFwCfgItem Firmware Configuration item to read\r
157\r
158**/\r
159VOID\r
160EFIAPI\r
161QemuFwCfgSelectItem (\r
162 IN FIRMWARE_CONFIG_ITEM QemuFwCfgItem\r
163 )\r
164{\r
165 if (InternalQemuFwCfgIsAvailable ()) {\r
166 MmioWrite16 (mFwCfgSelectorAddress, SwapBytes16 ((UINT16)QemuFwCfgItem));\r
167 }\r
168}\r
169\r
170\r
171/**\r
953bcbcc 172 Slow READ_BYTES_FUNCTION.\r
6e2543b0
LE
173**/\r
174STATIC\r
175VOID\r
176EFIAPI\r
953bcbcc 177MmioReadBytes (\r
6e2543b0
LE
178 IN UINTN Size,\r
179 IN VOID *Buffer OPTIONAL\r
180 )\r
181{\r
182 UINTN Left;\r
183 UINT8 *Ptr;\r
184 UINT8 *End;\r
185\r
186#ifdef MDE_CPU_AARCH64\r
187 Left = Size & 7;\r
188#else\r
189 Left = Size & 3;\r
190#endif\r
191\r
192 Size -= Left;\r
193 Ptr = Buffer;\r
194 End = Ptr + Size;\r
195\r
196#ifdef MDE_CPU_AARCH64\r
197 while (Ptr < End) {\r
198 *(UINT64 *)Ptr = MmioRead64 (mFwCfgDataAddress);\r
199 Ptr += 8;\r
200 }\r
201 if (Left & 4) {\r
202 *(UINT32 *)Ptr = MmioRead32 (mFwCfgDataAddress);\r
203 Ptr += 4;\r
204 }\r
205#else\r
206 while (Ptr < End) {\r
207 *(UINT32 *)Ptr = MmioRead32 (mFwCfgDataAddress);\r
208 Ptr += 4;\r
209 }\r
210#endif\r
211\r
212 if (Left & 2) {\r
213 *(UINT16 *)Ptr = MmioRead16 (mFwCfgDataAddress);\r
214 Ptr += 2;\r
215 }\r
216 if (Left & 1) {\r
217 *Ptr = MmioRead8 (mFwCfgDataAddress);\r
218 }\r
219}\r
220\r
221\r
953bcbcc
LE
222/**\r
223 Fast READ_BYTES_FUNCTION.\r
224**/\r
225STATIC\r
226VOID\r
227EFIAPI\r
228DmaReadBytes (\r
229 IN UINTN Size,\r
230 IN VOID *Buffer OPTIONAL\r
231 )\r
232{\r
233 volatile FW_CFG_DMA_ACCESS Access;\r
234 UINT32 Status;\r
235\r
236 if (Size == 0) {\r
237 return;\r
238 }\r
239\r
240 ASSERT (Size <= MAX_UINT32);\r
241\r
242 Access.Control = SwapBytes32 (FW_CFG_DMA_CTL_READ);\r
243 Access.Length = SwapBytes32 ((UINT32)Size);\r
244 Access.Address = SwapBytes64 ((UINT64)(UINTN)Buffer);\r
245\r
246 //\r
247 // We shouldn't start the transfer before setting up Access.\r
248 //\r
249 MemoryFence ();\r
250\r
251 //\r
252 // This will fire off the transfer.\r
253 //\r
254#ifdef MDE_CPU_AARCH64\r
255 MmioWrite64 (mFwCfgDmaAddress, SwapBytes64 ((UINT64)&Access));\r
256#else\r
257 MmioWrite32 ((UINT32)(mFwCfgDmaAddress + 4), SwapBytes32 ((UINT32)&Access));\r
258#endif\r
259\r
260 //\r
261 // We shouldn't look at Access.Control before starting the transfer.\r
262 //\r
263 MemoryFence ();\r
264\r
265 do {\r
266 Status = SwapBytes32 (Access.Control);\r
267 ASSERT ((Status & FW_CFG_DMA_CTL_ERROR) == 0);\r
268 } while (Status != 0);\r
269\r
270 //\r
271 // The caller will want to access the transferred data.\r
272 //\r
273 MemoryFence ();\r
274}\r
275\r
276\r
6e2543b0
LE
277/**\r
278 Reads firmware configuration bytes into a buffer\r
279\r
280 If called multiple times, then the data read will continue at the offset of\r
281 the firmware configuration item where the previous read ended.\r
282\r
283 @param[in] Size Size in bytes to read\r
284 @param[in] Buffer Buffer to store data into\r
285\r
286**/\r
287VOID\r
288EFIAPI\r
289QemuFwCfgReadBytes (\r
290 IN UINTN Size,\r
291 IN VOID *Buffer\r
292 )\r
293{\r
294 if (InternalQemuFwCfgIsAvailable ()) {\r
295 InternalQemuFwCfgReadBytes (Size, Buffer);\r
296 } else {\r
297 ZeroMem (Buffer, Size);\r
298 }\r
299}\r
300\r
301/**\r
302 Write firmware configuration bytes from a buffer\r
303\r
304 If called multiple times, then the data written will continue at the offset\r
305 of the firmware configuration item where the previous write ended.\r
306\r
307 @param[in] Size Size in bytes to write\r
308 @param[in] Buffer Buffer to read data from\r
309\r
310**/\r
311VOID\r
312EFIAPI\r
313QemuFwCfgWriteBytes (\r
314 IN UINTN Size,\r
315 IN VOID *Buffer\r
316 )\r
317{\r
318 if (InternalQemuFwCfgIsAvailable ()) {\r
319 UINTN Idx;\r
320\r
321 for (Idx = 0; Idx < Size; ++Idx) {\r
322 MmioWrite8 (mFwCfgDataAddress, ((UINT8 *)Buffer)[Idx]);\r
323 }\r
324 }\r
325}\r
326\r
327\r
328/**\r
329 Reads a UINT8 firmware configuration value\r
330\r
331 @return Value of Firmware Configuration item read\r
332\r
333**/\r
334UINT8\r
335EFIAPI\r
336QemuFwCfgRead8 (\r
337 VOID\r
338 )\r
339{\r
340 UINT8 Result;\r
341\r
342 QemuFwCfgReadBytes (sizeof Result, &Result);\r
343 return Result;\r
344}\r
345\r
346\r
347/**\r
348 Reads a UINT16 firmware configuration value\r
349\r
350 @return Value of Firmware Configuration item read\r
351\r
352**/\r
353UINT16\r
354EFIAPI\r
355QemuFwCfgRead16 (\r
356 VOID\r
357 )\r
358{\r
359 UINT16 Result;\r
360\r
361 QemuFwCfgReadBytes (sizeof Result, &Result);\r
362 return Result;\r
363}\r
364\r
365\r
366/**\r
367 Reads a UINT32 firmware configuration value\r
368\r
369 @return Value of Firmware Configuration item read\r
370\r
371**/\r
372UINT32\r
373EFIAPI\r
374QemuFwCfgRead32 (\r
375 VOID\r
376 )\r
377{\r
378 UINT32 Result;\r
379\r
380 QemuFwCfgReadBytes (sizeof Result, &Result);\r
381 return Result;\r
382}\r
383\r
384\r
385/**\r
386 Reads a UINT64 firmware configuration value\r
387\r
388 @return Value of Firmware Configuration item read\r
389\r
390**/\r
391UINT64\r
392EFIAPI\r
393QemuFwCfgRead64 (\r
394 VOID\r
395 )\r
396{\r
397 UINT64 Result;\r
398\r
399 QemuFwCfgReadBytes (sizeof Result, &Result);\r
400 return Result;\r
401}\r
402\r
403\r
404/**\r
405 Find the configuration item corresponding to the firmware configuration file.\r
406\r
407 @param[in] Name Name of file to look up.\r
408 @param[out] Item Configuration item corresponding to the file, to be passed\r
409 to QemuFwCfgSelectItem ().\r
410 @param[out] Size Number of bytes in the file.\r
411\r
412 @retval RETURN_SUCCESS If file is found.\r
413 @retval RETURN_NOT_FOUND If file is not found.\r
414 @retval RETURN_UNSUPPORTED If firmware configuration is unavailable.\r
415\r
416**/\r
417RETURN_STATUS\r
418EFIAPI\r
419QemuFwCfgFindFile (\r
420 IN CONST CHAR8 *Name,\r
421 OUT FIRMWARE_CONFIG_ITEM *Item,\r
422 OUT UINTN *Size\r
423 )\r
424{\r
425 UINT32 Count;\r
426 UINT32 Idx;\r
427\r
428 if (!InternalQemuFwCfgIsAvailable ()) {\r
429 return RETURN_UNSUPPORTED;\r
430 }\r
431\r
432 QemuFwCfgSelectItem (QemuFwCfgItemFileDir);\r
433 Count = SwapBytes32 (QemuFwCfgRead32 ());\r
434\r
435 for (Idx = 0; Idx < Count; ++Idx) {\r
436 UINT32 FileSize;\r
437 UINT16 FileSelect;\r
438 CHAR8 FName[QEMU_FW_CFG_FNAME_SIZE];\r
439\r
440 FileSize = QemuFwCfgRead32 ();\r
441 FileSelect = QemuFwCfgRead16 ();\r
442 QemuFwCfgRead16 (); // skip the field called "reserved"\r
443 InternalQemuFwCfgReadBytes (sizeof (FName), FName);\r
444\r
445 if (AsciiStrCmp (Name, FName) == 0) {\r
3f318fbf 446 *Item = (FIRMWARE_CONFIG_ITEM) SwapBytes16 (FileSelect);\r
6e2543b0
LE
447 *Size = SwapBytes32 (FileSize);\r
448 return RETURN_SUCCESS;\r
449 }\r
450 }\r
451\r
452 return RETURN_NOT_FOUND;\r
453}\r
454\r
455\r
456/**\r
457 Determine if S3 support is explicitly enabled.\r
458\r
459 @retval TRUE if S3 support is explicitly enabled.\r
460 FALSE otherwise. This includes unavailability of the firmware\r
461 configuration interface.\r
462**/\r
463BOOLEAN\r
464EFIAPI\r
465QemuFwCfgS3Enabled (\r
466 VOID\r
467 )\r
468{\r
469 return FALSE;\r
470}\r