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
;
25 Returns a boolean indicating if the firmware configuration interface
28 This function may change fw_cfg state.
30 @retval TRUE The interface is available
31 @retval FALSE The interface is not available
36 QemuFwCfgIsAvailable (
40 return InternalQemuFwCfgIsAvailable ();
54 // Enable the access routines while probing to see if it is supported.
55 // For probing we always use the IO Port (IoReadFifo8()) access method.
57 mQemuFwCfgSupported
= TRUE
;
58 mQemuFwCfgDmaSupported
= FALSE
;
60 QemuFwCfgSelectItem (QemuFwCfgItemSignature
);
61 Signature
= QemuFwCfgRead32 ();
62 DEBUG ((EFI_D_INFO
, "FW CFG Signature: 0x%x\n", Signature
));
63 QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion
);
64 Revision
= QemuFwCfgRead32 ();
65 DEBUG ((EFI_D_INFO
, "FW CFG Revision: 0x%x\n", Revision
));
66 if ((Signature
!= SIGNATURE_32 ('Q', 'E', 'M', 'U')) ||
69 DEBUG ((EFI_D_INFO
, "QemuFwCfg interface not supported.\n"));
70 mQemuFwCfgSupported
= FALSE
;
71 return RETURN_SUCCESS
;
74 if ((Revision
& FW_CFG_F_DMA
) == 0) {
75 DEBUG ((DEBUG_INFO
, "QemuFwCfg interface (IO Port) is supported.\n"));
78 // If SEV is enabled then we do not support DMA operations in PEI phase.
79 // This is mainly because DMA in SEV guest requires using bounce buffer
80 // (which need to allocate dynamic memory and allocating a PAGE size'd
81 // buffer can be challenge in PEI phase)
83 if (MemEncryptSevIsEnabled ()) {
84 DEBUG ((DEBUG_INFO
, "SEV: QemuFwCfg fallback to IO Port interface.\n"));
86 mQemuFwCfgDmaSupported
= TRUE
;
87 DEBUG ((DEBUG_INFO
, "QemuFwCfg interface (DMA) is supported.\n"));
90 return RETURN_SUCCESS
;
95 Returns a boolean indicating if the firmware configuration interface is
96 available for library-internal purposes.
98 This function never changes fw_cfg state.
100 @retval TRUE The interface is available internally.
101 @retval FALSE The interface is not available internally.
104 InternalQemuFwCfgIsAvailable (
108 return mQemuFwCfgSupported
;
112 Returns a boolean indicating whether QEMU provides the DMA-like access method
115 @retval TRUE The DMA-like access method is available.
116 @retval FALSE The DMA-like access method is unavailable.
119 InternalQemuFwCfgDmaIsAvailable (
123 return mQemuFwCfgDmaSupported
;
127 Transfer an array of bytes, or skip a number of bytes, using the DMA
130 @param[in] Size Size in bytes to transfer or skip.
132 @param[in,out] Buffer Buffer to read data into or write data from. Ignored,
133 and may be NULL, if Size is zero, or Control is
136 @param[in] Control One of the following:
137 FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer.
138 FW_CFG_DMA_CTL_READ - read from fw_cfg into Buffer.
139 FW_CFG_DMA_CTL_SKIP - skip bytes in fw_cfg.
142 InternalQemuFwCfgDmaBytes (
144 IN OUT VOID
*Buffer OPTIONAL
,
148 volatile FW_CFG_DMA_ACCESS Access
;
149 UINT32 AccessHigh
, AccessLow
;
152 ASSERT (Control
== FW_CFG_DMA_CTL_WRITE
|| Control
== FW_CFG_DMA_CTL_READ
||
153 Control
== FW_CFG_DMA_CTL_SKIP
);
160 // SEV does not support DMA operations in PEI stage, we should
161 // not have reached here.
163 ASSERT (!MemEncryptSevIsEnabled ());
165 Access
.Control
= SwapBytes32 (Control
);
166 Access
.Length
= SwapBytes32 (Size
);
167 Access
.Address
= SwapBytes64 ((UINTN
)Buffer
);
170 // Delimit the transfer from (a) modifications to Access, (b) in case of a
171 // write, from writes to Buffer by the caller.
176 // Start the transfer.
178 AccessHigh
= (UINT32
)RShiftU64 ((UINTN
)&Access
, 32);
179 AccessLow
= (UINT32
)(UINTN
)&Access
;
180 IoWrite32 (FW_CFG_IO_DMA_ADDRESS
, SwapBytes32 (AccessHigh
));
181 IoWrite32 (FW_CFG_IO_DMA_ADDRESS
+ 4, SwapBytes32 (AccessLow
));
184 // Don't look at Access.Control before starting the transfer.
189 // Wait for the transfer to complete.
192 Status
= SwapBytes32 (Access
.Control
);
193 ASSERT ((Status
& FW_CFG_DMA_CTL_ERROR
) == 0);
194 } while (Status
!= 0);
197 // After a read, the caller will want to use Buffer.