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