3 Stateful and implicitly initialized fw_cfg library implementation.
5 Copyright (C) 2013, Red Hat, Inc.
6 Copyright (c) 2011 - 2013, Intel Corporation. All rights reserved.<BR>
7 Copyright (c) 2017, Advanced Micro Devices. All rights reserved.<BR>
9 SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include <Library/BaseLib.h>
13 #include <Library/IoLib.h>
14 #include <Library/DebugLib.h>
15 #include <Library/QemuFwCfgLib.h>
16 #include <Library/MemEncryptSevLib.h>
18 #include "QemuFwCfgLibInternal.h"
20 STATIC BOOLEAN mQemuFwCfgSupported
= FALSE
;
21 STATIC BOOLEAN mQemuFwCfgDmaSupported
;
24 Returns a boolean indicating if the firmware configuration interface
27 This function may change fw_cfg state.
29 @retval TRUE The interface is available
30 @retval FALSE The interface is not available
35 QemuFwCfgIsAvailable (
39 return InternalQemuFwCfgIsAvailable ();
52 // Enable the access routines while probing to see if it is supported.
53 // For probing we always use the IO Port (IoReadFifo8()) access method.
55 mQemuFwCfgSupported
= TRUE
;
56 mQemuFwCfgDmaSupported
= FALSE
;
58 QemuFwCfgSelectItem (QemuFwCfgItemSignature
);
59 Signature
= QemuFwCfgRead32 ();
60 DEBUG ((DEBUG_INFO
, "FW CFG Signature: 0x%x\n", Signature
));
61 QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion
);
62 Revision
= QemuFwCfgRead32 ();
63 DEBUG ((DEBUG_INFO
, "FW CFG Revision: 0x%x\n", Revision
));
64 if ((Signature
!= SIGNATURE_32 ('Q', 'E', 'M', 'U')) ||
68 DEBUG ((DEBUG_INFO
, "QemuFwCfg interface not supported.\n"));
69 mQemuFwCfgSupported
= FALSE
;
70 return RETURN_SUCCESS
;
73 if ((Revision
& FW_CFG_F_DMA
) == 0) {
74 DEBUG ((DEBUG_INFO
, "QemuFwCfg interface (IO Port) is supported.\n"));
77 // If SEV is enabled then we do not support DMA operations in PEI phase.
78 // This is mainly because DMA in SEV guest requires using bounce buffer
79 // (which need to allocate dynamic memory and allocating a PAGE size'd
80 // buffer can be challenge in PEI phase)
82 if (MemEncryptSevIsEnabled ()) {
83 DEBUG ((DEBUG_INFO
, "SEV: QemuFwCfg fallback to IO Port interface.\n"));
85 mQemuFwCfgDmaSupported
= TRUE
;
86 DEBUG ((DEBUG_INFO
, "QemuFwCfg interface (DMA) is supported.\n"));
90 return RETURN_SUCCESS
;
94 Returns a boolean indicating if the firmware configuration interface is
95 available for library-internal purposes.
97 This function never changes fw_cfg state.
99 @retval TRUE The interface is available internally.
100 @retval FALSE The interface is not available internally.
103 InternalQemuFwCfgIsAvailable (
107 return mQemuFwCfgSupported
;
111 Returns a boolean indicating whether QEMU provides the DMA-like access method
114 @retval TRUE The DMA-like access method is available.
115 @retval FALSE The DMA-like access method is unavailable.
118 InternalQemuFwCfgDmaIsAvailable (
122 return mQemuFwCfgDmaSupported
;
126 Transfer an array of bytes, or skip a number of bytes, using the DMA
129 @param[in] Size Size in bytes to transfer or skip.
131 @param[in,out] Buffer Buffer to read data into or write data from. Ignored,
132 and may be NULL, if Size is zero, or Control is
135 @param[in] Control One of the following:
136 FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer.
137 FW_CFG_DMA_CTL_READ - read from fw_cfg into Buffer.
138 FW_CFG_DMA_CTL_SKIP - skip bytes in fw_cfg.
141 InternalQemuFwCfgDmaBytes (
143 IN OUT VOID
*Buffer OPTIONAL
,
147 volatile FW_CFG_DMA_ACCESS Access
;
148 UINT32 AccessHigh
, AccessLow
;
152 Control
== FW_CFG_DMA_CTL_WRITE
|| Control
== FW_CFG_DMA_CTL_READ
||
153 Control
== FW_CFG_DMA_CTL_SKIP
161 // SEV does not support DMA operations in PEI stage, we should
162 // not have reached here.
164 ASSERT (!MemEncryptSevIsEnabled ());
166 Access
.Control
= SwapBytes32 (Control
);
167 Access
.Length
= SwapBytes32 (Size
);
168 Access
.Address
= SwapBytes64 ((UINTN
)Buffer
);
171 // Delimit the transfer from (a) modifications to Access, (b) in case of a
172 // write, from writes to Buffer by the caller.
177 // Start the transfer.
179 AccessHigh
= (UINT32
)RShiftU64 ((UINTN
)&Access
, 32);
180 AccessLow
= (UINT32
)(UINTN
)&Access
;
181 IoWrite32 (FW_CFG_IO_DMA_ADDRESS
, SwapBytes32 (AccessHigh
));
182 IoWrite32 (FW_CFG_IO_DMA_ADDRESS
+ 4, SwapBytes32 (AccessLow
));
185 // Don't look at Access.Control before starting the transfer.
190 // Wait for the transfer to complete.
193 Status
= SwapBytes32 (Access
.Control
);
194 ASSERT ((Status
& FW_CFG_DMA_CTL_ERROR
) == 0);
195 } while (Status
!= 0);
198 // After a read, the caller will want to use Buffer.