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.
20 #include <Protocol/IoMmu.h>
22 #include <Library/BaseLib.h>
23 #include <Library/IoLib.h>
24 #include <Library/DebugLib.h>
25 #include <Library/QemuFwCfgLib.h>
26 #include <Library/UefiBootServicesTableLib.h>
27 #include <Library/MemEncryptSevLib.h>
29 #include "QemuFwCfgLibInternal.h"
31 STATIC BOOLEAN mQemuFwCfgSupported
= FALSE
;
32 STATIC BOOLEAN mQemuFwCfgDmaSupported
;
34 STATIC EDKII_IOMMU_PROTOCOL
*mIoMmuProtocol
;
37 Returns a boolean indicating if the firmware configuration interface
40 This function may change fw_cfg state.
42 @retval TRUE The interface is available
43 @retval FALSE The interface is not available
48 QemuFwCfgIsAvailable (
52 return InternalQemuFwCfgIsAvailable ();
66 // Enable the access routines while probing to see if it is supported.
67 // For probing we always use the IO Port (IoReadFifo8()) access method.
69 mQemuFwCfgSupported
= TRUE
;
70 mQemuFwCfgDmaSupported
= FALSE
;
72 QemuFwCfgSelectItem (QemuFwCfgItemSignature
);
73 Signature
= QemuFwCfgRead32 ();
74 DEBUG ((EFI_D_INFO
, "FW CFG Signature: 0x%x\n", Signature
));
75 QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion
);
76 Revision
= QemuFwCfgRead32 ();
77 DEBUG ((EFI_D_INFO
, "FW CFG Revision: 0x%x\n", Revision
));
78 if ((Signature
!= SIGNATURE_32 ('Q', 'E', 'M', 'U')) ||
81 DEBUG ((EFI_D_INFO
, "QemuFwCfg interface not supported.\n"));
82 mQemuFwCfgSupported
= FALSE
;
83 return RETURN_SUCCESS
;
86 if ((Revision
& FW_CFG_F_DMA
) == 0) {
87 DEBUG ((DEBUG_INFO
, "QemuFwCfg interface (IO Port) is supported.\n"));
89 mQemuFwCfgDmaSupported
= TRUE
;
90 DEBUG ((DEBUG_INFO
, "QemuFwCfg interface (DMA) is supported.\n"));
93 if (mQemuFwCfgDmaSupported
&& MemEncryptSevIsEnabled ()) {
97 // IoMmuDxe driver must have installed the IOMMU protocol. If we are not
98 // able to locate the protocol then something must have gone wrong.
100 Status
= gBS
->LocateProtocol (&gEdkiiIoMmuProtocolGuid
, NULL
,
101 (VOID
**)&mIoMmuProtocol
);
102 if (EFI_ERROR (Status
)) {
104 "QemuFwCfgSevDma %a:%a Failed to locate IOMMU protocol.\n",
105 gEfiCallerBaseName
, __FUNCTION__
));
111 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 // BusMasterCommomBuffer64, the buffer must be allocated using the IOMMU
175 Status
= mIoMmuProtocol
->AllocateBuffer (
181 EDKII_IOMMU_ATTRIBUTE_DUAL_ADDRESS_CYCLE
183 if (EFI_ERROR (Status
)) {
185 "%a:%a failed to allocate FW_CFG_DMA_ACCESS\n", gEfiCallerBaseName
,
192 // Map the host buffer with BusMasterCommonBuffer64
194 Status
= mIoMmuProtocol
->Map (
196 EdkiiIoMmuOperationBusMasterCommonBuffer64
,
202 if (EFI_ERROR (Status
)) {
203 mIoMmuProtocol
->FreeBuffer (mIoMmuProtocol
, NumPages
, HostAddress
);
205 "%a:%a failed to Map() FW_CFG_DMA_ACCESS\n", gEfiCallerBaseName
,
211 if (Size
< sizeof (FW_CFG_DMA_ACCESS
)) {
212 mIoMmuProtocol
->Unmap (mIoMmuProtocol
, Mapping
);
213 mIoMmuProtocol
->FreeBuffer (mIoMmuProtocol
, NumPages
, HostAddress
);
215 "%a:%a failed to Map() - requested 0x%Lx got 0x%Lx\n", gEfiCallerBaseName
,
216 __FUNCTION__
, (UINT64
)sizeof (FW_CFG_DMA_ACCESS
), (UINT64
)Size
));
221 *Access
= HostAddress
;
226 Function is to used for freeing the Access buffer allocated using
227 AllocFwCfgDmaAccessBuffer()
232 FreeFwCfgDmaAccessBuffer (
240 NumPages
= EFI_SIZE_TO_PAGES (sizeof (FW_CFG_DMA_ACCESS
));
242 Status
= mIoMmuProtocol
->Unmap (mIoMmuProtocol
, Mapping
);
243 if (EFI_ERROR (Status
)) {
245 "%a:%a failed to UnMap() Mapping 0x%Lx\n", gEfiCallerBaseName
,
246 __FUNCTION__
, (UINT64
)(UINTN
)Mapping
));
251 Status
= mIoMmuProtocol
->FreeBuffer (mIoMmuProtocol
, NumPages
, Access
);
252 if (EFI_ERROR (Status
)) {
254 "%a:%a failed to Free() 0x%Lx\n", gEfiCallerBaseName
, __FUNCTION__
,
255 (UINT64
)(UINTN
)Access
));
262 Function is used for mapping host address to device address. The buffer must
263 be unmapped with UnmapDmaDataBuffer ().
268 MapFwCfgDmaDataBuffer (
270 IN VOID
*HostAddress
,
272 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
279 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
281 NumberOfBytes
= Size
;
282 Status
= mIoMmuProtocol
->Map (
285 EdkiiIoMmuOperationBusMasterRead64
:
286 EdkiiIoMmuOperationBusMasterWrite64
),
292 if (EFI_ERROR (Status
)) {
294 "%a:%a failed to Map() Address 0x%Lx Size 0x%Lx\n", gEfiCallerBaseName
,
295 __FUNCTION__
, (UINT64
)(UINTN
)HostAddress
, (UINT64
)Size
));
300 if (NumberOfBytes
< Size
) {
301 mIoMmuProtocol
->Unmap (mIoMmuProtocol
, Mapping
);
303 "%a:%a failed to Map() - requested 0x%x got 0x%Lx\n", gEfiCallerBaseName
,
304 __FUNCTION__
, Size
, (UINT64
)NumberOfBytes
));
309 *DeviceAddress
= PhysicalAddress
;
315 UnmapFwCfgDmaDataBuffer (
321 Status
= mIoMmuProtocol
->Unmap (mIoMmuProtocol
, Mapping
);
322 if (EFI_ERROR (Status
)) {
324 "%a:%a failed to UnMap() Mapping 0x%Lx\n", gEfiCallerBaseName
,
325 __FUNCTION__
, (UINT64
)(UINTN
)Mapping
));
332 Transfer an array of bytes, or skip a number of bytes, using the DMA
335 @param[in] Size Size in bytes to transfer or skip.
337 @param[in,out] Buffer Buffer to read data into or write data from. Ignored,
338 and may be NULL, if Size is zero, or Control is
341 @param[in] Control One of the following:
342 FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer.
343 FW_CFG_DMA_CTL_READ - read from fw_cfg into Buffer.
344 FW_CFG_DMA_CTL_SKIP - skip bytes in fw_cfg.
347 InternalQemuFwCfgDmaBytes (
349 IN OUT VOID
*Buffer OPTIONAL
,
353 volatile FW_CFG_DMA_ACCESS LocalAccess
;
354 volatile FW_CFG_DMA_ACCESS
*Access
;
355 UINT32 AccessHigh
, AccessLow
;
357 VOID
*AccessMapping
, *DataMapping
;
360 ASSERT (Control
== FW_CFG_DMA_CTL_WRITE
|| Control
== FW_CFG_DMA_CTL_READ
||
361 Control
== FW_CFG_DMA_CTL_SKIP
);
367 Access
= &LocalAccess
;
368 AccessMapping
= NULL
;
373 // When SEV is enabled, map Buffer to DMA address before issuing the DMA
376 if (MemEncryptSevIsEnabled ()) {
378 EFI_PHYSICAL_ADDRESS DataBufferAddress
;
381 // Allocate DMA Access buffer
383 AllocFwCfgDmaAccessBuffer (&AccessBuffer
, &AccessMapping
);
385 Access
= AccessBuffer
;
388 // Map actual data buffer
390 if (Control
!= FW_CFG_DMA_CTL_SKIP
) {
391 MapFwCfgDmaDataBuffer (
392 Control
== FW_CFG_DMA_CTL_WRITE
,
399 DataBuffer
= (VOID
*) (UINTN
) DataBufferAddress
;
403 Access
->Control
= SwapBytes32 (Control
);
404 Access
->Length
= SwapBytes32 (Size
);
405 Access
->Address
= SwapBytes64 ((UINTN
)DataBuffer
);
408 // Delimit the transfer from (a) modifications to Access, (b) in case of a
409 // write, from writes to Buffer by the caller.
414 // Start the transfer.
416 AccessHigh
= (UINT32
)RShiftU64 ((UINTN
)Access
, 32);
417 AccessLow
= (UINT32
)(UINTN
)Access
;
418 IoWrite32 (FW_CFG_IO_DMA_ADDRESS
, SwapBytes32 (AccessHigh
));
419 IoWrite32 (FW_CFG_IO_DMA_ADDRESS
+ 4, SwapBytes32 (AccessLow
));
422 // Don't look at Access.Control before starting the transfer.
427 // Wait for the transfer to complete.
430 Status
= SwapBytes32 (Access
->Control
);
431 ASSERT ((Status
& FW_CFG_DMA_CTL_ERROR
) == 0);
432 } while (Status
!= 0);
435 // After a read, the caller will want to use Buffer.
440 // If Access buffer was dynamically allocated then free it.
442 if (AccessMapping
!= NULL
) {
443 FreeFwCfgDmaAccessBuffer ((VOID
*)Access
, AccessMapping
);
447 // If DataBuffer was mapped then unmap it.
449 if (DataMapping
!= NULL
) {
450 UnmapFwCfgDmaDataBuffer (DataMapping
);