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 ();
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 ((DEBUG_INFO
, "FW CFG Signature: 0x%x\n", Signature
));
69 QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion
);
70 Revision
= QemuFwCfgRead32 ();
71 DEBUG ((DEBUG_INFO
, "FW CFG Revision: 0x%x\n", Revision
));
72 if ((Signature
!= SIGNATURE_32 ('Q', 'E', 'M', 'U')) ||
76 DEBUG ((DEBUG_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 (
96 &gEdkiiIoMmuProtocolGuid
,
98 (VOID
**)&mIoMmuProtocol
100 if (EFI_ERROR (Status
)) {
103 "QemuFwCfgSevDma %a:%a Failed to locate IOMMU protocol.\n",
112 return RETURN_SUCCESS
;
116 Returns a boolean indicating if the firmware configuration interface is
117 available for library-internal purposes.
119 This function never changes fw_cfg state.
121 @retval TRUE The interface is available internally.
122 @retval FALSE The interface is not available internally.
125 InternalQemuFwCfgIsAvailable (
129 return mQemuFwCfgSupported
;
133 Returns a boolean indicating whether QEMU provides the DMA-like access method
136 @retval TRUE The DMA-like access method is available.
137 @retval FALSE The DMA-like access method is unavailable.
140 InternalQemuFwCfgDmaIsAvailable (
144 return mQemuFwCfgDmaSupported
;
148 Function is used for allocating a bi-directional FW_CFG_DMA_ACCESS used
149 between Host and device to exchange the information. The buffer must be free'd
150 using FreeFwCfgDmaAccessBuffer ().
155 AllocFwCfgDmaAccessBuffer (
164 EFI_PHYSICAL_ADDRESS DmaAddress
;
167 Size
= sizeof (FW_CFG_DMA_ACCESS
);
168 NumPages
= EFI_SIZE_TO_PAGES (Size
);
171 // As per UEFI spec, in order to map a host address with
172 // BusMasterCommonBuffer64, the buffer must be allocated using the IOMMU
175 Status
= mIoMmuProtocol
->AllocateBuffer (
181 EDKII_IOMMU_ATTRIBUTE_DUAL_ADDRESS_CYCLE
183 if (EFI_ERROR (Status
)) {
186 "%a:%a failed to allocate FW_CFG_DMA_ACCESS\n",
195 // Avoid exposing stale data even temporarily: zero the area before mapping
198 ZeroMem (HostAddress
, Size
);
201 // Map the host buffer with BusMasterCommonBuffer64
203 Status
= mIoMmuProtocol
->Map (
205 EdkiiIoMmuOperationBusMasterCommonBuffer64
,
211 if (EFI_ERROR (Status
)) {
212 mIoMmuProtocol
->FreeBuffer (mIoMmuProtocol
, NumPages
, HostAddress
);
215 "%a:%a failed to Map() FW_CFG_DMA_ACCESS\n",
223 if (Size
< sizeof (FW_CFG_DMA_ACCESS
)) {
224 mIoMmuProtocol
->Unmap (mIoMmuProtocol
, Mapping
);
225 mIoMmuProtocol
->FreeBuffer (mIoMmuProtocol
, NumPages
, HostAddress
);
228 "%a:%a failed to Map() - requested 0x%Lx got 0x%Lx\n",
231 (UINT64
)sizeof (FW_CFG_DMA_ACCESS
),
238 *Access
= HostAddress
;
243 Function is to used for freeing the Access buffer allocated using
244 AllocFwCfgDmaAccessBuffer()
249 FreeFwCfgDmaAccessBuffer (
257 NumPages
= EFI_SIZE_TO_PAGES (sizeof (FW_CFG_DMA_ACCESS
));
259 Status
= mIoMmuProtocol
->Unmap (mIoMmuProtocol
, Mapping
);
260 if (EFI_ERROR (Status
)) {
263 "%a:%a failed to UnMap() Mapping 0x%Lx\n",
266 (UINT64
)(UINTN
)Mapping
272 Status
= mIoMmuProtocol
->FreeBuffer (mIoMmuProtocol
, NumPages
, Access
);
273 if (EFI_ERROR (Status
)) {
276 "%a:%a failed to Free() 0x%Lx\n",
279 (UINT64
)(UINTN
)Access
287 Function is used for mapping host address to device address. The buffer must
288 be unmapped with UnmapDmaDataBuffer ().
293 MapFwCfgDmaDataBuffer (
295 IN VOID
*HostAddress
,
297 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
304 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
306 NumberOfBytes
= Size
;
307 Status
= mIoMmuProtocol
->Map (
310 EdkiiIoMmuOperationBusMasterRead64
:
311 EdkiiIoMmuOperationBusMasterWrite64
),
317 if (EFI_ERROR (Status
)) {
320 "%a:%a failed to Map() Address 0x%Lx Size 0x%Lx\n",
323 (UINT64
)(UINTN
)HostAddress
,
330 if (NumberOfBytes
< Size
) {
331 mIoMmuProtocol
->Unmap (mIoMmuProtocol
, Mapping
);
334 "%a:%a failed to Map() - requested 0x%x got 0x%Lx\n",
338 (UINT64
)NumberOfBytes
344 *DeviceAddress
= PhysicalAddress
;
350 UnmapFwCfgDmaDataBuffer (
356 Status
= mIoMmuProtocol
->Unmap (mIoMmuProtocol
, Mapping
);
357 if (EFI_ERROR (Status
)) {
360 "%a:%a failed to UnMap() Mapping 0x%Lx\n",
363 (UINT64
)(UINTN
)Mapping
371 Transfer an array of bytes, or skip a number of bytes, using the DMA
374 @param[in] Size Size in bytes to transfer or skip.
376 @param[in,out] Buffer Buffer to read data into or write data from. Ignored,
377 and may be NULL, if Size is zero, or Control is
380 @param[in] Control One of the following:
381 FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer.
382 FW_CFG_DMA_CTL_READ - read from fw_cfg into Buffer.
383 FW_CFG_DMA_CTL_SKIP - skip bytes in fw_cfg.
386 InternalQemuFwCfgDmaBytes (
388 IN OUT VOID
*Buffer OPTIONAL
,
392 volatile FW_CFG_DMA_ACCESS LocalAccess
;
393 volatile FW_CFG_DMA_ACCESS
*Access
;
394 UINT32 AccessHigh
, AccessLow
;
396 VOID
*AccessMapping
, *DataMapping
;
400 Control
== FW_CFG_DMA_CTL_WRITE
|| Control
== FW_CFG_DMA_CTL_READ
||
401 Control
== FW_CFG_DMA_CTL_SKIP
408 Access
= &LocalAccess
;
409 AccessMapping
= NULL
;
414 // When SEV is enabled, map Buffer to DMA address before issuing the DMA
417 if (MemEncryptSevIsEnabled ()) {
419 EFI_PHYSICAL_ADDRESS DataBufferAddress
;
422 // Allocate DMA Access buffer
424 AllocFwCfgDmaAccessBuffer (&AccessBuffer
, &AccessMapping
);
426 Access
= AccessBuffer
;
429 // Map actual data buffer
431 if (Control
!= FW_CFG_DMA_CTL_SKIP
) {
432 MapFwCfgDmaDataBuffer (
433 Control
== FW_CFG_DMA_CTL_WRITE
,
440 DataBuffer
= (VOID
*)(UINTN
)DataBufferAddress
;
444 Access
->Control
= SwapBytes32 (Control
);
445 Access
->Length
= SwapBytes32 (Size
);
446 Access
->Address
= SwapBytes64 ((UINTN
)DataBuffer
);
449 // Delimit the transfer from (a) modifications to Access, (b) in case of a
450 // write, from writes to Buffer by the caller.
455 // Start the transfer.
457 AccessHigh
= (UINT32
)RShiftU64 ((UINTN
)Access
, 32);
458 AccessLow
= (UINT32
)(UINTN
)Access
;
459 IoWrite32 (FW_CFG_IO_DMA_ADDRESS
, SwapBytes32 (AccessHigh
));
460 IoWrite32 (FW_CFG_IO_DMA_ADDRESS
+ 4, SwapBytes32 (AccessLow
));
463 // Don't look at Access.Control before starting the transfer.
468 // Wait for the transfer to complete.
471 Status
= SwapBytes32 (Access
->Control
);
472 ASSERT ((Status
& FW_CFG_DMA_CTL_ERROR
) == 0);
473 } while (Status
!= 0);
476 // After a read, the caller will want to use Buffer.
481 // If Access buffer was dynamically allocated then free it.
483 if (AccessMapping
!= NULL
) {
484 FreeFwCfgDmaAccessBuffer ((VOID
*)Access
, AccessMapping
);
488 // If DataBuffer was mapped then unmap it.
490 if (DataMapping
!= NULL
) {
491 UnmapFwCfgDmaDataBuffer (DataMapping
);