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