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
14 #include <Protocol/IoMmu.h>
16 #include <Library/BaseLib.h>
17 #include <Library/BaseMemoryLib.h>
18 #include <Library/IoLib.h>
19 #include <Library/DebugLib.h>
20 #include <Library/QemuFwCfgLib.h>
21 #include <Library/UefiBootServicesTableLib.h>
22 #include <Library/MemEncryptSevLib.h>
24 #include "QemuFwCfgLibInternal.h"
26 STATIC BOOLEAN mQemuFwCfgSupported
= FALSE
;
27 STATIC BOOLEAN mQemuFwCfgDmaSupported
;
29 STATIC EDKII_IOMMU_PROTOCOL
*mIoMmuProtocol
;
32 Returns a boolean indicating if the firmware configuration interface
35 This function may change fw_cfg state.
37 @retval TRUE The interface is available
38 @retval FALSE The interface is not available
43 QemuFwCfgIsAvailable (
47 return InternalQemuFwCfgIsAvailable ();
61 // Enable the access routines while probing to see if it is supported.
62 // For probing we always use the IO Port (IoReadFifo8()) access method.
64 mQemuFwCfgSupported
= TRUE
;
65 mQemuFwCfgDmaSupported
= FALSE
;
67 QemuFwCfgSelectItem (QemuFwCfgItemSignature
);
68 Signature
= QemuFwCfgRead32 ();
69 DEBUG ((EFI_D_INFO
, "FW CFG Signature: 0x%x\n", Signature
));
70 QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion
);
71 Revision
= QemuFwCfgRead32 ();
72 DEBUG ((EFI_D_INFO
, "FW CFG Revision: 0x%x\n", Revision
));
73 if ((Signature
!= SIGNATURE_32 ('Q', 'E', 'M', 'U')) ||
76 DEBUG ((EFI_D_INFO
, "QemuFwCfg interface not supported.\n"));
77 mQemuFwCfgSupported
= FALSE
;
78 return RETURN_SUCCESS
;
81 if ((Revision
& FW_CFG_F_DMA
) == 0) {
82 DEBUG ((DEBUG_INFO
, "QemuFwCfg interface (IO Port) is supported.\n"));
84 mQemuFwCfgDmaSupported
= TRUE
;
85 DEBUG ((DEBUG_INFO
, "QemuFwCfg interface (DMA) is supported.\n"));
88 if (mQemuFwCfgDmaSupported
&& MemEncryptSevIsEnabled ()) {
92 // IoMmuDxe driver must have installed the IOMMU protocol. If we are not
93 // able to locate the protocol then something must have gone wrong.
95 Status
= gBS
->LocateProtocol (&gEdkiiIoMmuProtocolGuid
, NULL
,
96 (VOID
**)&mIoMmuProtocol
);
97 if (EFI_ERROR (Status
)) {
99 "QemuFwCfgSevDma %a:%a Failed to locate IOMMU protocol.\n",
100 gEfiCallerBaseName
, __FUNCTION__
));
106 return RETURN_SUCCESS
;
111 Returns a boolean indicating if the firmware configuration interface is
112 available for library-internal purposes.
114 This function never changes fw_cfg state.
116 @retval TRUE The interface is available internally.
117 @retval FALSE The interface is not available internally.
120 InternalQemuFwCfgIsAvailable (
124 return mQemuFwCfgSupported
;
128 Returns a boolean indicating whether QEMU provides the DMA-like access method
131 @retval TRUE The DMA-like access method is available.
132 @retval FALSE The DMA-like access method is unavailable.
135 InternalQemuFwCfgDmaIsAvailable (
139 return mQemuFwCfgDmaSupported
;
143 Function is used for allocating a bi-directional FW_CFG_DMA_ACCESS used
144 between Host and device to exchange the information. The buffer must be free'd
145 using FreeFwCfgDmaAccessBuffer ().
150 AllocFwCfgDmaAccessBuffer (
159 EFI_PHYSICAL_ADDRESS DmaAddress
;
162 Size
= sizeof (FW_CFG_DMA_ACCESS
);
163 NumPages
= EFI_SIZE_TO_PAGES (Size
);
166 // As per UEFI spec, in order to map a host address with
167 // BusMasterCommomBuffer64, the buffer must be allocated using the IOMMU
170 Status
= mIoMmuProtocol
->AllocateBuffer (
176 EDKII_IOMMU_ATTRIBUTE_DUAL_ADDRESS_CYCLE
178 if (EFI_ERROR (Status
)) {
180 "%a:%a failed to allocate FW_CFG_DMA_ACCESS\n", gEfiCallerBaseName
,
187 // Avoid exposing stale data even temporarily: zero the area before mapping
190 ZeroMem (HostAddress
, Size
);
193 // Map the host buffer with BusMasterCommonBuffer64
195 Status
= mIoMmuProtocol
->Map (
197 EdkiiIoMmuOperationBusMasterCommonBuffer64
,
203 if (EFI_ERROR (Status
)) {
204 mIoMmuProtocol
->FreeBuffer (mIoMmuProtocol
, NumPages
, HostAddress
);
206 "%a:%a failed to Map() FW_CFG_DMA_ACCESS\n", gEfiCallerBaseName
,
212 if (Size
< sizeof (FW_CFG_DMA_ACCESS
)) {
213 mIoMmuProtocol
->Unmap (mIoMmuProtocol
, Mapping
);
214 mIoMmuProtocol
->FreeBuffer (mIoMmuProtocol
, NumPages
, HostAddress
);
216 "%a:%a failed to Map() - requested 0x%Lx got 0x%Lx\n", gEfiCallerBaseName
,
217 __FUNCTION__
, (UINT64
)sizeof (FW_CFG_DMA_ACCESS
), (UINT64
)Size
));
222 *Access
= HostAddress
;
227 Function is to used for freeing the Access buffer allocated using
228 AllocFwCfgDmaAccessBuffer()
233 FreeFwCfgDmaAccessBuffer (
241 NumPages
= EFI_SIZE_TO_PAGES (sizeof (FW_CFG_DMA_ACCESS
));
243 Status
= mIoMmuProtocol
->Unmap (mIoMmuProtocol
, Mapping
);
244 if (EFI_ERROR (Status
)) {
246 "%a:%a failed to UnMap() Mapping 0x%Lx\n", gEfiCallerBaseName
,
247 __FUNCTION__
, (UINT64
)(UINTN
)Mapping
));
252 Status
= mIoMmuProtocol
->FreeBuffer (mIoMmuProtocol
, NumPages
, Access
);
253 if (EFI_ERROR (Status
)) {
255 "%a:%a failed to Free() 0x%Lx\n", gEfiCallerBaseName
, __FUNCTION__
,
256 (UINT64
)(UINTN
)Access
));
263 Function is used for mapping host address to device address. The buffer must
264 be unmapped with UnmapDmaDataBuffer ().
269 MapFwCfgDmaDataBuffer (
271 IN VOID
*HostAddress
,
273 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
280 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
282 NumberOfBytes
= Size
;
283 Status
= mIoMmuProtocol
->Map (
286 EdkiiIoMmuOperationBusMasterRead64
:
287 EdkiiIoMmuOperationBusMasterWrite64
),
293 if (EFI_ERROR (Status
)) {
295 "%a:%a failed to Map() Address 0x%Lx Size 0x%Lx\n", gEfiCallerBaseName
,
296 __FUNCTION__
, (UINT64
)(UINTN
)HostAddress
, (UINT64
)Size
));
301 if (NumberOfBytes
< Size
) {
302 mIoMmuProtocol
->Unmap (mIoMmuProtocol
, Mapping
);
304 "%a:%a failed to Map() - requested 0x%x got 0x%Lx\n", gEfiCallerBaseName
,
305 __FUNCTION__
, Size
, (UINT64
)NumberOfBytes
));
310 *DeviceAddress
= PhysicalAddress
;
316 UnmapFwCfgDmaDataBuffer (
322 Status
= mIoMmuProtocol
->Unmap (mIoMmuProtocol
, Mapping
);
323 if (EFI_ERROR (Status
)) {
325 "%a:%a failed to UnMap() Mapping 0x%Lx\n", gEfiCallerBaseName
,
326 __FUNCTION__
, (UINT64
)(UINTN
)Mapping
));
333 Transfer an array of bytes, or skip a number of bytes, using the DMA
336 @param[in] Size Size in bytes to transfer or skip.
338 @param[in,out] Buffer Buffer to read data into or write data from. Ignored,
339 and may be NULL, if Size is zero, or Control is
342 @param[in] Control One of the following:
343 FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer.
344 FW_CFG_DMA_CTL_READ - read from fw_cfg into Buffer.
345 FW_CFG_DMA_CTL_SKIP - skip bytes in fw_cfg.
348 InternalQemuFwCfgDmaBytes (
350 IN OUT VOID
*Buffer OPTIONAL
,
354 volatile FW_CFG_DMA_ACCESS LocalAccess
;
355 volatile FW_CFG_DMA_ACCESS
*Access
;
356 UINT32 AccessHigh
, AccessLow
;
358 VOID
*AccessMapping
, *DataMapping
;
361 ASSERT (Control
== FW_CFG_DMA_CTL_WRITE
|| Control
== FW_CFG_DMA_CTL_READ
||
362 Control
== FW_CFG_DMA_CTL_SKIP
);
368 Access
= &LocalAccess
;
369 AccessMapping
= NULL
;
374 // When SEV is enabled, map Buffer to DMA address before issuing the DMA
377 if (MemEncryptSevIsEnabled ()) {
379 EFI_PHYSICAL_ADDRESS DataBufferAddress
;
382 // Allocate DMA Access buffer
384 AllocFwCfgDmaAccessBuffer (&AccessBuffer
, &AccessMapping
);
386 Access
= AccessBuffer
;
389 // Map actual data buffer
391 if (Control
!= FW_CFG_DMA_CTL_SKIP
) {
392 MapFwCfgDmaDataBuffer (
393 Control
== FW_CFG_DMA_CTL_WRITE
,
400 DataBuffer
= (VOID
*) (UINTN
) DataBufferAddress
;
404 Access
->Control
= SwapBytes32 (Control
);
405 Access
->Length
= SwapBytes32 (Size
);
406 Access
->Address
= SwapBytes64 ((UINTN
)DataBuffer
);
409 // Delimit the transfer from (a) modifications to Access, (b) in case of a
410 // write, from writes to Buffer by the caller.
415 // Start the transfer.
417 AccessHigh
= (UINT32
)RShiftU64 ((UINTN
)Access
, 32);
418 AccessLow
= (UINT32
)(UINTN
)Access
;
419 IoWrite32 (FW_CFG_IO_DMA_ADDRESS
, SwapBytes32 (AccessHigh
));
420 IoWrite32 (FW_CFG_IO_DMA_ADDRESS
+ 4, SwapBytes32 (AccessLow
));
423 // Don't look at Access.Control before starting the transfer.
428 // Wait for the transfer to complete.
431 Status
= SwapBytes32 (Access
->Control
);
432 ASSERT ((Status
& FW_CFG_DMA_CTL_ERROR
) == 0);
433 } while (Status
!= 0);
436 // After a read, the caller will want to use Buffer.
441 // If Access buffer was dynamically allocated then free it.
443 if (AccessMapping
!= NULL
) {
444 FreeFwCfgDmaAccessBuffer ((VOID
*)Access
, AccessMapping
);
448 // If DataBuffer was mapped then unmap it.
450 if (DataMapping
!= NULL
) {
451 UnmapFwCfgDmaDataBuffer (DataMapping
);