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