]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c
OvmfPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / OvmfPkg / Library / QemuFwCfgLib / QemuFwCfgPei.c
1 /** @file
2
3 Stateful and implicitly initialized fw_cfg library implementation.
4
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>
8
9 SPDX-License-Identifier: BSD-2-Clause-Patent
10 **/
11
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>
17
18 #include "QemuFwCfgLibInternal.h"
19
20 STATIC BOOLEAN mQemuFwCfgSupported = FALSE;
21 STATIC BOOLEAN mQemuFwCfgDmaSupported;
22
23
24 /**
25 Returns a boolean indicating if the firmware configuration interface
26 is available or not.
27
28 This function may change fw_cfg state.
29
30 @retval TRUE The interface is available
31 @retval FALSE The interface is not available
32
33 **/
34 BOOLEAN
35 EFIAPI
36 QemuFwCfgIsAvailable (
37 VOID
38 )
39 {
40 return InternalQemuFwCfgIsAvailable ();
41 }
42
43
44 RETURN_STATUS
45 EFIAPI
46 QemuFwCfgInitialize (
47 VOID
48 )
49 {
50 UINT32 Signature;
51 UINT32 Revision;
52
53 //
54 // Enable the access routines while probing to see if it is supported.
55 // For probing we always use the IO Port (IoReadFifo8()) access method.
56 //
57 mQemuFwCfgSupported = TRUE;
58 mQemuFwCfgDmaSupported = FALSE;
59
60 QemuFwCfgSelectItem (QemuFwCfgItemSignature);
61 Signature = QemuFwCfgRead32 ();
62 DEBUG ((EFI_D_INFO, "FW CFG Signature: 0x%x\n", Signature));
63 QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion);
64 Revision = QemuFwCfgRead32 ();
65 DEBUG ((EFI_D_INFO, "FW CFG Revision: 0x%x\n", Revision));
66 if ((Signature != SIGNATURE_32 ('Q', 'E', 'M', 'U')) ||
67 (Revision < 1)
68 ) {
69 DEBUG ((EFI_D_INFO, "QemuFwCfg interface not supported.\n"));
70 mQemuFwCfgSupported = FALSE;
71 return RETURN_SUCCESS;
72 }
73
74 if ((Revision & FW_CFG_F_DMA) == 0) {
75 DEBUG ((DEBUG_INFO, "QemuFwCfg interface (IO Port) is supported.\n"));
76 } else {
77 //
78 // If SEV is enabled then we do not support DMA operations in PEI phase.
79 // This is mainly because DMA in SEV guest requires using bounce buffer
80 // (which need to allocate dynamic memory and allocating a PAGE size'd
81 // buffer can be challenge in PEI phase)
82 //
83 if (MemEncryptSevIsEnabled ()) {
84 DEBUG ((DEBUG_INFO, "SEV: QemuFwCfg fallback to IO Port interface.\n"));
85 } else {
86 mQemuFwCfgDmaSupported = TRUE;
87 DEBUG ((DEBUG_INFO, "QemuFwCfg interface (DMA) is supported.\n"));
88 }
89 }
90 return RETURN_SUCCESS;
91 }
92
93
94 /**
95 Returns a boolean indicating if the firmware configuration interface is
96 available for library-internal purposes.
97
98 This function never changes fw_cfg state.
99
100 @retval TRUE The interface is available internally.
101 @retval FALSE The interface is not available internally.
102 **/
103 BOOLEAN
104 InternalQemuFwCfgIsAvailable (
105 VOID
106 )
107 {
108 return mQemuFwCfgSupported;
109 }
110
111 /**
112 Returns a boolean indicating whether QEMU provides the DMA-like access method
113 for fw_cfg.
114
115 @retval TRUE The DMA-like access method is available.
116 @retval FALSE The DMA-like access method is unavailable.
117 **/
118 BOOLEAN
119 InternalQemuFwCfgDmaIsAvailable (
120 VOID
121 )
122 {
123 return mQemuFwCfgDmaSupported;
124 }
125
126 /**
127 Transfer an array of bytes, or skip a number of bytes, using the DMA
128 interface.
129
130 @param[in] Size Size in bytes to transfer or skip.
131
132 @param[in,out] Buffer Buffer to read data into or write data from. Ignored,
133 and may be NULL, if Size is zero, or Control is
134 FW_CFG_DMA_CTL_SKIP.
135
136 @param[in] Control One of the following:
137 FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer.
138 FW_CFG_DMA_CTL_READ - read from fw_cfg into Buffer.
139 FW_CFG_DMA_CTL_SKIP - skip bytes in fw_cfg.
140 **/
141 VOID
142 InternalQemuFwCfgDmaBytes (
143 IN UINT32 Size,
144 IN OUT VOID *Buffer OPTIONAL,
145 IN UINT32 Control
146 )
147 {
148 volatile FW_CFG_DMA_ACCESS Access;
149 UINT32 AccessHigh, AccessLow;
150 UINT32 Status;
151
152 ASSERT (Control == FW_CFG_DMA_CTL_WRITE || Control == FW_CFG_DMA_CTL_READ ||
153 Control == FW_CFG_DMA_CTL_SKIP);
154
155 if (Size == 0) {
156 return;
157 }
158
159 //
160 // SEV does not support DMA operations in PEI stage, we should
161 // not have reached here.
162 //
163 ASSERT (!MemEncryptSevIsEnabled ());
164
165 Access.Control = SwapBytes32 (Control);
166 Access.Length = SwapBytes32 (Size);
167 Access.Address = SwapBytes64 ((UINTN)Buffer);
168
169 //
170 // Delimit the transfer from (a) modifications to Access, (b) in case of a
171 // write, from writes to Buffer by the caller.
172 //
173 MemoryFence ();
174
175 //
176 // Start the transfer.
177 //
178 AccessHigh = (UINT32)RShiftU64 ((UINTN)&Access, 32);
179 AccessLow = (UINT32)(UINTN)&Access;
180 IoWrite32 (FW_CFG_IO_DMA_ADDRESS, SwapBytes32 (AccessHigh));
181 IoWrite32 (FW_CFG_IO_DMA_ADDRESS + 4, SwapBytes32 (AccessLow));
182
183 //
184 // Don't look at Access.Control before starting the transfer.
185 //
186 MemoryFence ();
187
188 //
189 // Wait for the transfer to complete.
190 //
191 do {
192 Status = SwapBytes32 (Access.Control);
193 ASSERT ((Status & FW_CFG_DMA_CTL_ERROR) == 0);
194 } while (Status != 0);
195
196 //
197 // After a read, the caller will want to use Buffer.
198 //
199 MemoryFence ();
200 }
201