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 This program and the accompanying materials are licensed and made available
10 under the terms and conditions of the BSD License which accompanies this
11 distribution. The full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
15 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 #include <Library/BaseLib.h>
19 #include <Library/IoLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/QemuFwCfgLib.h>
22 #include <Library/MemEncryptSevLib.h>
24 #include "QemuFwCfgLibInternal.h"
26 STATIC BOOLEAN mQemuFwCfgSupported
= FALSE
;
27 STATIC BOOLEAN mQemuFwCfgDmaSupported
;
31 Returns a boolean indicating if the firmware configuration interface
34 This function may change fw_cfg state.
36 @retval TRUE The interface is available
37 @retval FALSE The interface is not available
42 QemuFwCfgIsAvailable (
46 return InternalQemuFwCfgIsAvailable ();
60 // Enable the access routines while probing to see if it is supported.
61 // For probing we always use the IO Port (IoReadFifo8()) access method.
63 mQemuFwCfgSupported
= TRUE
;
64 mQemuFwCfgDmaSupported
= FALSE
;
66 QemuFwCfgSelectItem (QemuFwCfgItemSignature
);
67 Signature
= QemuFwCfgRead32 ();
68 DEBUG ((EFI_D_INFO
, "FW CFG Signature: 0x%x\n", Signature
));
69 QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion
);
70 Revision
= QemuFwCfgRead32 ();
71 DEBUG ((EFI_D_INFO
, "FW CFG Revision: 0x%x\n", Revision
));
72 if ((Signature
!= SIGNATURE_32 ('Q', 'E', 'M', 'U')) ||
75 DEBUG ((EFI_D_INFO
, "QemuFwCfg interface not supported.\n"));
76 mQemuFwCfgSupported
= FALSE
;
77 return RETURN_SUCCESS
;
80 if ((Revision
& FW_CFG_F_DMA
) == 0) {
81 DEBUG ((DEBUG_INFO
, "QemuFwCfg interface (IO Port) is supported.\n"));
84 // If SEV is enabled then we do not support DMA operations in PEI phase.
85 // This is mainly because DMA in SEV guest requires using bounce buffer
86 // (which need to allocate dynamic memory and allocating a PAGE size'd
87 // buffer can be challenge in PEI phase)
89 if (MemEncryptSevIsEnabled ()) {
90 DEBUG ((DEBUG_INFO
, "SEV: QemuFwCfg fallback to IO Port interface.\n"));
92 mQemuFwCfgDmaSupported
= TRUE
;
93 DEBUG ((DEBUG_INFO
, "QemuFwCfg interface (DMA) is supported.\n"));
96 return RETURN_SUCCESS
;
101 Returns a boolean indicating if the firmware configuration interface is
102 available for library-internal purposes.
104 This function never changes fw_cfg state.
106 @retval TRUE The interface is available internally.
107 @retval FALSE The interface is not available internally.
110 InternalQemuFwCfgIsAvailable (
114 return mQemuFwCfgSupported
;
118 Returns a boolean indicating whether QEMU provides the DMA-like access method
121 @retval TRUE The DMA-like access method is available.
122 @retval FALSE The DMA-like access method is unavailable.
125 InternalQemuFwCfgDmaIsAvailable (
129 return mQemuFwCfgDmaSupported
;
133 Transfer an array of bytes, or skip a number of bytes, using the DMA
136 @param[in] Size Size in bytes to transfer or skip.
138 @param[in,out] Buffer Buffer to read data into or write data from. Ignored,
139 and may be NULL, if Size is zero, or Control is
142 @param[in] Control One of the following:
143 FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer.
144 FW_CFG_DMA_CTL_READ - read from fw_cfg into Buffer.
145 FW_CFG_DMA_CTL_SKIP - skip bytes in fw_cfg.
148 InternalQemuFwCfgDmaBytes (
150 IN OUT VOID
*Buffer OPTIONAL
,
154 volatile FW_CFG_DMA_ACCESS Access
;
155 UINT32 AccessHigh
, AccessLow
;
158 ASSERT (Control
== FW_CFG_DMA_CTL_WRITE
|| Control
== FW_CFG_DMA_CTL_READ
||
159 Control
== FW_CFG_DMA_CTL_SKIP
);
166 // SEV does not support DMA operations in PEI stage, we should
167 // not have reached here.
169 ASSERT (!MemEncryptSevIsEnabled ());
171 Access
.Control
= SwapBytes32 (Control
);
172 Access
.Length
= SwapBytes32 (Size
);
173 Access
.Address
= SwapBytes64 ((UINTN
)Buffer
);
176 // Delimit the transfer from (a) modifications to Access, (b) in case of a
177 // write, from writes to Buffer by the caller.
182 // Start the transfer.
184 AccessHigh
= (UINT32
)RShiftU64 ((UINTN
)&Access
, 32);
185 AccessLow
= (UINT32
)(UINTN
)&Access
;
186 IoWrite32 (FW_CFG_IO_DMA_ADDRESS
, SwapBytes32 (AccessHigh
));
187 IoWrite32 (FW_CFG_IO_DMA_ADDRESS
+ 4, SwapBytes32 (AccessLow
));
190 // Don't look at Access.Control before starting the transfer.
195 // Wait for the transfer to complete.
198 Status
= SwapBytes32 (Access
.Control
);
199 ASSERT ((Status
& FW_CFG_DMA_CTL_ERROR
) == 0);
200 } while (Status
!= 0);
203 // After a read, the caller will want to use Buffer.