3 Stateful and implicitly initialized fw_cfg library implementation.
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>
9 SPDX-License-Identifier: BSD-2-Clause-Patent
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>
21 #include <Protocol/FdtClient.h>
23 STATIC UINTN mFwCfgSelectorAddress
;
24 STATIC UINTN mFwCfgDataAddress
;
25 STATIC UINTN mFwCfgDmaAddress
;
28 Reads firmware configuration bytes into a buffer
30 @param[in] Size Size in bytes to read
31 @param[in] Buffer Buffer to store data into (OPTIONAL if Size is 0)
35 VOID (EFIAPI READ_BYTES_FUNCTION
) (
37 IN VOID
*Buffer OPTIONAL
41 Writes bytes from a buffer to firmware configuration
43 @param[in] Size Size in bytes to write
44 @param[in] Buffer Buffer to transfer data from (OPTIONAL if Size is 0)
48 VOID (EFIAPI WRITE_BYTES_FUNCTION
) (
50 IN VOID
*Buffer OPTIONAL
54 Skips bytes in firmware configuration
56 @param[in] Size Size in bytes to skip
60 VOID (EFIAPI SKIP_BYTES_FUNCTION
) (
65 // Forward declaration of the two implementations we have.
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
;
75 // These correspond to the implementation we detect at runtime.
77 STATIC READ_BYTES_FUNCTION
*InternalQemuFwCfgReadBytes
= MmioReadBytes
;
78 STATIC WRITE_BYTES_FUNCTION
*InternalQemuFwCfgWriteBytes
= MmioWriteBytes
;
79 STATIC SKIP_BYTES_FUNCTION
*InternalQemuFwCfgSkipBytes
= MmioSkipBytes
;
83 Returns a boolean indicating if the firmware configuration interface
86 This function may change fw_cfg state.
88 @retval TRUE The interface is available
89 @retval FALSE The interface is not available
94 QemuFwCfgIsAvailable (
98 return (BOOLEAN
)(mFwCfgSelectorAddress
!= 0 && mFwCfgDataAddress
!= 0);
104 QemuFwCfgInitialize (
109 FDT_CLIENT_PROTOCOL
*FdtClient
;
112 UINTN AddressCells
, SizeCells
;
113 UINT64 FwCfgSelectorAddress
;
114 UINT64 FwCfgSelectorSize
;
115 UINT64 FwCfgDataAddress
;
116 UINT64 FwCfgDataSize
;
117 UINT64 FwCfgDmaAddress
;
120 Status
= gBS
->LocateProtocol (&gFdtClientProtocolGuid
, NULL
,
121 (VOID
**)&FdtClient
);
122 ASSERT_EFI_ERROR (Status
);
124 Status
= FdtClient
->FindCompatibleNodeReg (FdtClient
, "qemu,fw-cfg-mmio",
125 (CONST VOID
**)&Reg
, &AddressCells
, &SizeCells
,
127 if (EFI_ERROR (Status
)) {
129 "%a: No 'qemu,fw-cfg-mmio' compatible DT node found (Status == %r)\n",
130 __FUNCTION__
, Status
));
134 ASSERT (AddressCells
== 2);
135 ASSERT (SizeCells
== 2);
136 ASSERT (RegSize
== 2 * sizeof (UINT64
));
138 FwCfgDataAddress
= SwapBytes64 (Reg
[0]);
140 FwCfgSelectorAddress
= FwCfgDataAddress
+ FwCfgDataSize
;
141 FwCfgSelectorSize
= 2;
144 // The following ASSERT()s express
146 // Address + Size - 1 <= MAX_UINTN
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
153 ASSERT (FwCfgSelectorAddress
<= MAX_UINTN
- FwCfgSelectorSize
+ 1);
154 ASSERT (FwCfgDataAddress
<= MAX_UINTN
- FwCfgDataSize
+ 1);
156 mFwCfgSelectorAddress
= FwCfgSelectorAddress
;
157 mFwCfgDataAddress
= FwCfgDataAddress
;
159 DEBUG ((DEBUG_INFO
, "Found FwCfg @ 0x%Lx/0x%Lx\n", FwCfgSelectorAddress
,
162 if (SwapBytes64 (Reg
[1]) >= 0x18) {
163 FwCfgDmaAddress
= FwCfgDataAddress
+ 0x10;
167 // See explanation above.
169 ASSERT (FwCfgDmaAddress
<= MAX_UINTN
- FwCfgDmaSize
+ 1);
171 DEBUG ((DEBUG_INFO
, "Found FwCfg DMA @ 0x%Lx\n", FwCfgDmaAddress
));
176 if (QemuFwCfgIsAvailable ()) {
179 QemuFwCfgSelectItem (QemuFwCfgItemSignature
);
180 Signature
= QemuFwCfgRead32 ();
181 if (Signature
== SIGNATURE_32 ('Q', 'E', 'M', 'U')) {
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.
186 if (FwCfgDmaAddress
!= 0) {
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
;
199 mFwCfgSelectorAddress
= 0;
200 mFwCfgDataAddress
= 0;
203 return RETURN_SUCCESS
;
208 Selects a firmware configuration item for reading.
210 Following this call, any data read from this item will start from the
211 beginning of the configuration item's data.
213 @param[in] QemuFwCfgItem Firmware Configuration item to read
218 QemuFwCfgSelectItem (
219 IN FIRMWARE_CONFIG_ITEM QemuFwCfgItem
222 if (QemuFwCfgIsAvailable ()) {
223 MmioWrite16 (mFwCfgSelectorAddress
, SwapBytes16 ((UINT16
)QemuFwCfgItem
));
229 Slow READ_BYTES_FUNCTION.
236 IN VOID
*Buffer OPTIONAL
243 #if defined(MDE_CPU_AARCH64) || defined(MDE_CPU_RISCV64)
253 #if defined(MDE_CPU_AARCH64) || defined(MDE_CPU_RISCV64)
255 *(UINT64
*)Ptr
= MmioRead64 (mFwCfgDataAddress
);
259 *(UINT32
*)Ptr
= MmioRead32 (mFwCfgDataAddress
);
264 *(UINT32
*)Ptr
= MmioRead32 (mFwCfgDataAddress
);
270 *(UINT16
*)Ptr
= MmioRead16 (mFwCfgDataAddress
);
274 *Ptr
= MmioRead8 (mFwCfgDataAddress
);
280 Transfer an array of bytes, or skip a number of bytes, using the DMA
283 @param[in] Size Size in bytes to transfer or skip.
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
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.
298 IN OUT VOID
*Buffer OPTIONAL
,
302 volatile FW_CFG_DMA_ACCESS Access
;
305 ASSERT (Control
== FW_CFG_DMA_CTL_WRITE
|| Control
== FW_CFG_DMA_CTL_READ
||
306 Control
== FW_CFG_DMA_CTL_SKIP
);
312 ASSERT (Size
<= MAX_UINT32
);
314 Access
.Control
= SwapBytes32 (Control
);
315 Access
.Length
= SwapBytes32 ((UINT32
)Size
);
316 Access
.Address
= SwapBytes64 ((UINT64
)(UINTN
)Buffer
);
319 // We shouldn't start the transfer before setting up Access.
324 // This will fire off the transfer.
326 #if defined(MDE_CPU_AARCH64) || defined(MDE_CPU_RISCV64)
327 MmioWrite64 (mFwCfgDmaAddress
, SwapBytes64 ((UINT64
)&Access
));
329 MmioWrite32 ((UINT32
)(mFwCfgDmaAddress
+ 4), SwapBytes32 ((UINT32
)&Access
));
333 // We shouldn't look at Access.Control before starting the transfer.
338 Status
= SwapBytes32 (Access
.Control
);
339 ASSERT ((Status
& FW_CFG_DMA_CTL_ERROR
) == 0);
340 } while (Status
!= 0);
343 // The caller will want to access the transferred data.
350 Fast READ_BYTES_FUNCTION.
357 IN VOID
*Buffer OPTIONAL
360 DmaTransferBytes (Size
, Buffer
, FW_CFG_DMA_CTL_READ
);
365 Reads firmware configuration bytes into a buffer
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.
370 @param[in] Size Size in bytes to read
371 @param[in] Buffer Buffer to store data into
381 if (QemuFwCfgIsAvailable ()) {
382 InternalQemuFwCfgReadBytes (Size
, Buffer
);
384 ZeroMem (Buffer
, Size
);
390 Slow WRITE_BYTES_FUNCTION.
397 IN VOID
*Buffer OPTIONAL
402 for (Idx
= 0; Idx
< Size
; ++Idx
) {
403 MmioWrite8 (mFwCfgDataAddress
, ((UINT8
*)Buffer
)[Idx
]);
409 Fast WRITE_BYTES_FUNCTION.
416 IN VOID
*Buffer OPTIONAL
419 DmaTransferBytes (Size
, Buffer
, FW_CFG_DMA_CTL_WRITE
);
424 Write firmware configuration bytes from a buffer
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.
429 @param[in] Size Size in bytes to write
430 @param[in] Buffer Buffer to read data from
435 QemuFwCfgWriteBytes (
440 if (QemuFwCfgIsAvailable ()) {
441 InternalQemuFwCfgWriteBytes (Size
, Buffer
);
447 Slow SKIP_BYTES_FUNCTION.
457 UINT8 SkipBuffer
[256];
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.
467 ChunkSize
= MIN (Size
, sizeof SkipBuffer
);
468 MmioReadBytes (ChunkSize
, SkipBuffer
);
475 Fast SKIP_BYTES_FUNCTION.
484 DmaTransferBytes (Size
, NULL
, FW_CFG_DMA_CTL_SKIP
);
489 Skip bytes in the firmware configuration item.
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.
495 @param[in] Size Number of bytes to skip.
503 if (QemuFwCfgIsAvailable ()) {
504 InternalQemuFwCfgSkipBytes (Size
);
510 Reads a UINT8 firmware configuration value
512 @return Value of Firmware Configuration item read
523 QemuFwCfgReadBytes (sizeof Result
, &Result
);
529 Reads a UINT16 firmware configuration value
531 @return Value of Firmware Configuration item read
542 QemuFwCfgReadBytes (sizeof Result
, &Result
);
548 Reads a UINT32 firmware configuration value
550 @return Value of Firmware Configuration item read
561 QemuFwCfgReadBytes (sizeof Result
, &Result
);
567 Reads a UINT64 firmware configuration value
569 @return Value of Firmware Configuration item read
580 QemuFwCfgReadBytes (sizeof Result
, &Result
);
586 Find the configuration item corresponding to the firmware configuration file.
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.
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.
601 IN CONST CHAR8
*Name
,
602 OUT FIRMWARE_CONFIG_ITEM
*Item
,
609 if (!QemuFwCfgIsAvailable ()) {
610 return RETURN_UNSUPPORTED
;
613 QemuFwCfgSelectItem (QemuFwCfgItemFileDir
);
614 Count
= SwapBytes32 (QemuFwCfgRead32 ());
616 for (Idx
= 0; Idx
< Count
; ++Idx
) {
619 CHAR8 FName
[QEMU_FW_CFG_FNAME_SIZE
];
621 FileSize
= QemuFwCfgRead32 ();
622 FileSelect
= QemuFwCfgRead16 ();
623 QemuFwCfgRead16 (); // skip the field called "reserved"
624 InternalQemuFwCfgReadBytes (sizeof (FName
), FName
);
626 if (AsciiStrCmp (Name
, FName
) == 0) {
627 *Item
= (FIRMWARE_CONFIG_ITEM
) SwapBytes16 (FileSelect
);
628 *Size
= SwapBytes32 (FileSize
);
629 return RETURN_SUCCESS
;
633 return RETURN_NOT_FOUND
;