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