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>
19 #include "QemuFwCfgLibInternal.h"
21 STATIC BOOLEAN mQemuFwCfgSupported
= FALSE
;
22 STATIC BOOLEAN mQemuFwCfgDmaSupported
;
25 Check if it is Tdx guest
27 @retval TRUE It is Tdx guest
28 @retval FALSE It is not Tdx guest
35 CONFIDENTIAL_COMPUTING_WORK_AREA_HEADER
*CcWorkAreaHeader
;
37 CcWorkAreaHeader
= (CONFIDENTIAL_COMPUTING_WORK_AREA_HEADER
*)FixedPcdGet32 (PcdOvmfWorkAreaBase
);
38 return (CcWorkAreaHeader
!= NULL
&& CcWorkAreaHeader
->GuestType
== GUEST_TYPE_INTEL_TDX
);
42 Returns a boolean indicating if the firmware configuration interface
45 This function may change fw_cfg state.
47 @retval TRUE The interface is available
48 @retval FALSE The interface is not available
53 QemuFwCfgIsAvailable (
57 return InternalQemuFwCfgIsAvailable ();
70 // Enable the access routines while probing to see if it is supported.
71 // For probing we always use the IO Port (IoReadFifo8()) access method.
73 mQemuFwCfgSupported
= TRUE
;
74 mQemuFwCfgDmaSupported
= FALSE
;
76 QemuFwCfgSelectItem (QemuFwCfgItemSignature
);
77 Signature
= QemuFwCfgRead32 ();
78 DEBUG ((DEBUG_INFO
, "FW CFG Signature: 0x%x\n", Signature
));
79 QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion
);
80 Revision
= QemuFwCfgRead32 ();
81 DEBUG ((DEBUG_INFO
, "FW CFG Revision: 0x%x\n", Revision
));
82 if ((Signature
!= SIGNATURE_32 ('Q', 'E', 'M', 'U')) ||
86 DEBUG ((DEBUG_INFO
, "QemuFwCfg interface not supported.\n"));
87 mQemuFwCfgSupported
= FALSE
;
88 return RETURN_SUCCESS
;
91 if ((Revision
& FW_CFG_F_DMA
) == 0) {
92 DEBUG ((DEBUG_INFO
, "QemuFwCfg interface (IO Port) is supported.\n"));
95 // If SEV is enabled then we do not support DMA operations in PEI phase.
96 // This is mainly because DMA in SEV guest requires using bounce buffer
97 // (which need to allocate dynamic memory and allocating a PAGE size'd
98 // buffer can be challenge in PEI phase)
100 if (MemEncryptSevIsEnabled ()) {
101 DEBUG ((DEBUG_INFO
, "SEV: QemuFwCfg fallback to IO Port interface.\n"));
102 } else if (QemuFwCfgIsTdxGuest ()) {
104 // If TDX is enabled then we do not support DMA operations in PEI phase.
105 // This is mainly because DMA in TDX guest requires using bounce buffer
106 // (which need to allocate dynamic memory and allocating a PAGE size'd
107 // buffer can be challenge in PEI phase)
109 DEBUG ((DEBUG_INFO
, "TDX: QemuFwCfg fallback to IO Port interface.\n"));
111 mQemuFwCfgDmaSupported
= TRUE
;
112 DEBUG ((DEBUG_INFO
, "QemuFwCfg interface (DMA) is supported.\n"));
116 return RETURN_SUCCESS
;
120 Returns a boolean indicating if the firmware configuration interface is
121 available for library-internal purposes.
123 This function never changes fw_cfg state.
125 @retval TRUE The interface is available internally.
126 @retval FALSE The interface is not available internally.
129 InternalQemuFwCfgIsAvailable (
133 return mQemuFwCfgSupported
;
137 Returns a boolean indicating whether QEMU provides the DMA-like access method
140 @retval TRUE The DMA-like access method is available.
141 @retval FALSE The DMA-like access method is unavailable.
144 InternalQemuFwCfgDmaIsAvailable (
148 return mQemuFwCfgDmaSupported
;
152 Transfer an array of bytes, or skip a number of bytes, using the DMA
155 @param[in] Size Size in bytes to transfer or skip.
157 @param[in,out] Buffer Buffer to read data into or write data from. Ignored,
158 and may be NULL, if Size is zero, or Control is
161 @param[in] Control One of the following:
162 FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer.
163 FW_CFG_DMA_CTL_READ - read from fw_cfg into Buffer.
164 FW_CFG_DMA_CTL_SKIP - skip bytes in fw_cfg.
167 InternalQemuFwCfgDmaBytes (
169 IN OUT VOID
*Buffer OPTIONAL
,
173 volatile FW_CFG_DMA_ACCESS Access
;
174 UINT32 AccessHigh
, AccessLow
;
178 Control
== FW_CFG_DMA_CTL_WRITE
|| Control
== FW_CFG_DMA_CTL_READ
||
179 Control
== FW_CFG_DMA_CTL_SKIP
187 // SEV does not support DMA operations in PEI stage, we should
188 // not have reached here.
190 ASSERT (!MemEncryptSevIsEnabled ());
193 // TDX does not support DMA operations in PEI stage, we should
194 // not have reached here.
196 ASSERT (!QemuFwCfgIsTdxGuest ());
198 Access
.Control
= SwapBytes32 (Control
);
199 Access
.Length
= SwapBytes32 (Size
);
200 Access
.Address
= SwapBytes64 ((UINTN
)Buffer
);
203 // Delimit the transfer from (a) modifications to Access, (b) in case of a
204 // write, from writes to Buffer by the caller.
209 // Start the transfer.
211 AccessHigh
= (UINT32
)RShiftU64 ((UINTN
)&Access
, 32);
212 AccessLow
= (UINT32
)(UINTN
)&Access
;
213 IoWrite32 (FW_CFG_IO_DMA_ADDRESS
, SwapBytes32 (AccessHigh
));
214 IoWrite32 (FW_CFG_IO_DMA_ADDRESS
+ 4, SwapBytes32 (AccessLow
));
217 // Don't look at Access.Control before starting the transfer.
222 // Wait for the transfer to complete.
225 Status
= SwapBytes32 (Access
.Control
);
226 ASSERT ((Status
& FW_CFG_DMA_CTL_ERROR
) == 0);
227 } while (Status
!= 0);
230 // After a read, the caller will want to use Buffer.