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