]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxe.c
OvmfPkg/Virtio: take RingBaseShift in SetQueueAddress()
[mirror_edk2.git] / OvmfPkg / Library / QemuFwCfgLib / QemuFwCfgDxe.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 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
13
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.
16 **/
17
18 #include <Uefi.h>
19
20 #include <Protocol/IoMmu.h>
21
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>
28
29 #include "QemuFwCfgLibInternal.h"
30
31 STATIC BOOLEAN mQemuFwCfgSupported = FALSE;
32 STATIC BOOLEAN mQemuFwCfgDmaSupported;
33
34 STATIC EDKII_IOMMU_PROTOCOL *mIoMmuProtocol;
35
36 /**
37 Returns a boolean indicating if the firmware configuration interface
38 is available or not.
39
40 This function may change fw_cfg state.
41
42 @retval TRUE The interface is available
43 @retval FALSE The interface is not available
44
45 **/
46 BOOLEAN
47 EFIAPI
48 QemuFwCfgIsAvailable (
49 VOID
50 )
51 {
52 return InternalQemuFwCfgIsAvailable ();
53 }
54
55
56 RETURN_STATUS
57 EFIAPI
58 QemuFwCfgInitialize (
59 VOID
60 )
61 {
62 UINT32 Signature;
63 UINT32 Revision;
64
65 //
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.
68 //
69 mQemuFwCfgSupported = TRUE;
70 mQemuFwCfgDmaSupported = FALSE;
71
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')) ||
79 (Revision < 1)
80 ) {
81 DEBUG ((EFI_D_INFO, "QemuFwCfg interface not supported.\n"));
82 mQemuFwCfgSupported = FALSE;
83 return RETURN_SUCCESS;
84 }
85
86 if ((Revision & FW_CFG_F_DMA) == 0) {
87 DEBUG ((DEBUG_INFO, "QemuFwCfg interface (IO Port) is supported.\n"));
88 } else {
89 mQemuFwCfgDmaSupported = TRUE;
90 DEBUG ((DEBUG_INFO, "QemuFwCfg interface (DMA) is supported.\n"));
91 }
92
93 if (mQemuFwCfgDmaSupported && MemEncryptSevIsEnabled ()) {
94 EFI_STATUS Status;
95
96 //
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.
99 //
100 Status = gBS->LocateProtocol (&gEdkiiIoMmuProtocolGuid, NULL,
101 (VOID **)&mIoMmuProtocol);
102 if (EFI_ERROR (Status)) {
103 DEBUG ((DEBUG_ERROR,
104 "QemuFwCfgSevDma %a:%a Failed to locate IOMMU protocol.\n",
105 gEfiCallerBaseName, __FUNCTION__));
106 ASSERT (FALSE);
107 CpuDeadLoop ();
108 }
109 }
110
111 return RETURN_SUCCESS;
112 }
113
114
115 /**
116 Returns a boolean indicating if the firmware configuration interface is
117 available for library-internal purposes.
118
119 This function never changes fw_cfg state.
120
121 @retval TRUE The interface is available internally.
122 @retval FALSE The interface is not available internally.
123 **/
124 BOOLEAN
125 InternalQemuFwCfgIsAvailable (
126 VOID
127 )
128 {
129 return mQemuFwCfgSupported;
130 }
131
132 /**
133 Returns a boolean indicating whether QEMU provides the DMA-like access method
134 for fw_cfg.
135
136 @retval TRUE The DMA-like access method is available.
137 @retval FALSE The DMA-like access method is unavailable.
138 **/
139 BOOLEAN
140 InternalQemuFwCfgDmaIsAvailable (
141 VOID
142 )
143 {
144 return mQemuFwCfgDmaSupported;
145 }
146
147 /**
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 ().
151
152 **/
153 STATIC
154 VOID
155 AllocFwCfgDmaAccessBuffer (
156 OUT VOID **Access,
157 OUT VOID **MapInfo
158 )
159 {
160 UINTN Size;
161 UINTN NumPages;
162 EFI_STATUS Status;
163 VOID *HostAddress;
164 EFI_PHYSICAL_ADDRESS DmaAddress;
165 VOID *Mapping;
166
167 Size = sizeof (FW_CFG_DMA_ACCESS);
168 NumPages = EFI_SIZE_TO_PAGES (Size);
169
170 //
171 // As per UEFI spec, in order to map a host address with
172 // BusMasterCommomBuffer64, the buffer must be allocated using the IOMMU
173 // AllocateBuffer()
174 //
175 Status = mIoMmuProtocol->AllocateBuffer (
176 mIoMmuProtocol,
177 AllocateAnyPages,
178 EfiBootServicesData,
179 NumPages,
180 &HostAddress,
181 EDKII_IOMMU_ATTRIBUTE_DUAL_ADDRESS_CYCLE
182 );
183 if (EFI_ERROR (Status)) {
184 DEBUG ((DEBUG_ERROR,
185 "%a:%a failed to allocate FW_CFG_DMA_ACCESS\n", gEfiCallerBaseName,
186 __FUNCTION__));
187 ASSERT (FALSE);
188 CpuDeadLoop ();
189 }
190
191 //
192 // Map the host buffer with BusMasterCommonBuffer64
193 //
194 Status = mIoMmuProtocol->Map (
195 mIoMmuProtocol,
196 EdkiiIoMmuOperationBusMasterCommonBuffer64,
197 HostAddress,
198 &Size,
199 &DmaAddress,
200 &Mapping
201 );
202 if (EFI_ERROR (Status)) {
203 mIoMmuProtocol->FreeBuffer (mIoMmuProtocol, NumPages, HostAddress);
204 DEBUG ((DEBUG_ERROR,
205 "%a:%a failed to Map() FW_CFG_DMA_ACCESS\n", gEfiCallerBaseName,
206 __FUNCTION__));
207 ASSERT (FALSE);
208 CpuDeadLoop ();
209 }
210
211 if (Size < sizeof (FW_CFG_DMA_ACCESS)) {
212 mIoMmuProtocol->Unmap (mIoMmuProtocol, Mapping);
213 mIoMmuProtocol->FreeBuffer (mIoMmuProtocol, NumPages, HostAddress);
214 DEBUG ((DEBUG_ERROR,
215 "%a:%a failed to Map() - requested 0x%Lx got 0x%Lx\n", gEfiCallerBaseName,
216 __FUNCTION__, (UINT64)sizeof (FW_CFG_DMA_ACCESS), (UINT64)Size));
217 ASSERT (FALSE);
218 CpuDeadLoop ();
219 }
220
221 *Access = HostAddress;
222 *MapInfo = Mapping;
223 }
224
225 /**
226 Function is to used for freeing the Access buffer allocated using
227 AllocFwCfgDmaAccessBuffer()
228
229 **/
230 STATIC
231 VOID
232 FreeFwCfgDmaAccessBuffer (
233 IN VOID *Access,
234 IN VOID *Mapping
235 )
236 {
237 UINTN NumPages;
238 EFI_STATUS Status;
239
240 NumPages = EFI_SIZE_TO_PAGES (sizeof (FW_CFG_DMA_ACCESS));
241
242 Status = mIoMmuProtocol->Unmap (mIoMmuProtocol, Mapping);
243 if (EFI_ERROR (Status)) {
244 DEBUG ((DEBUG_ERROR,
245 "%a:%a failed to UnMap() Mapping 0x%Lx\n", gEfiCallerBaseName,
246 __FUNCTION__, (UINT64)(UINTN)Mapping));
247 ASSERT (FALSE);
248 CpuDeadLoop ();
249 }
250
251 Status = mIoMmuProtocol->FreeBuffer (mIoMmuProtocol, NumPages, Access);
252 if (EFI_ERROR (Status)) {
253 DEBUG ((DEBUG_ERROR,
254 "%a:%a failed to Free() 0x%Lx\n", gEfiCallerBaseName, __FUNCTION__,
255 (UINT64)(UINTN)Access));
256 ASSERT (FALSE);
257 CpuDeadLoop ();
258 }
259 }
260
261 /**
262 Function is used for mapping host address to device address. The buffer must
263 be unmapped with UnmapDmaDataBuffer ().
264
265 **/
266 STATIC
267 VOID
268 MapFwCfgDmaDataBuffer (
269 IN BOOLEAN IsWrite,
270 IN VOID *HostAddress,
271 IN UINT32 Size,
272 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
273 OUT VOID **MapInfo
274 )
275 {
276 EFI_STATUS Status;
277 UINTN NumberOfBytes;
278 VOID *Mapping;
279 EFI_PHYSICAL_ADDRESS PhysicalAddress;
280
281 NumberOfBytes = Size;
282 Status = mIoMmuProtocol->Map (
283 mIoMmuProtocol,
284 (IsWrite ?
285 EdkiiIoMmuOperationBusMasterRead64 :
286 EdkiiIoMmuOperationBusMasterWrite64),
287 HostAddress,
288 &NumberOfBytes,
289 &PhysicalAddress,
290 &Mapping
291 );
292 if (EFI_ERROR (Status)) {
293 DEBUG ((DEBUG_ERROR,
294 "%a:%a failed to Map() Address 0x%Lx Size 0x%Lx\n", gEfiCallerBaseName,
295 __FUNCTION__, (UINT64)(UINTN)HostAddress, (UINT64)Size));
296 ASSERT (FALSE);
297 CpuDeadLoop ();
298 }
299
300 if (NumberOfBytes < Size) {
301 mIoMmuProtocol->Unmap (mIoMmuProtocol, Mapping);
302 DEBUG ((DEBUG_ERROR,
303 "%a:%a failed to Map() - requested 0x%x got 0x%Lx\n", gEfiCallerBaseName,
304 __FUNCTION__, Size, (UINT64)NumberOfBytes));
305 ASSERT (FALSE);
306 CpuDeadLoop ();
307 }
308
309 *DeviceAddress = PhysicalAddress;
310 *MapInfo = Mapping;
311 }
312
313 STATIC
314 VOID
315 UnmapFwCfgDmaDataBuffer (
316 IN VOID *Mapping
317 )
318 {
319 EFI_STATUS Status;
320
321 Status = mIoMmuProtocol->Unmap (mIoMmuProtocol, Mapping);
322 if (EFI_ERROR (Status)) {
323 DEBUG ((DEBUG_ERROR,
324 "%a:%a failed to UnMap() Mapping 0x%Lx\n", gEfiCallerBaseName,
325 __FUNCTION__, (UINT64)(UINTN)Mapping));
326 ASSERT (FALSE);
327 CpuDeadLoop ();
328 }
329 }
330
331 /**
332 Transfer an array of bytes, or skip a number of bytes, using the DMA
333 interface.
334
335 @param[in] Size Size in bytes to transfer or skip.
336
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
339 FW_CFG_DMA_CTL_SKIP.
340
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.
345 **/
346 VOID
347 InternalQemuFwCfgDmaBytes (
348 IN UINT32 Size,
349 IN OUT VOID *Buffer OPTIONAL,
350 IN UINT32 Control
351 )
352 {
353 volatile FW_CFG_DMA_ACCESS LocalAccess;
354 volatile FW_CFG_DMA_ACCESS *Access;
355 UINT32 AccessHigh, AccessLow;
356 UINT32 Status;
357 VOID *AccessMapping, *DataMapping;
358 VOID *DataBuffer;
359
360 ASSERT (Control == FW_CFG_DMA_CTL_WRITE || Control == FW_CFG_DMA_CTL_READ ||
361 Control == FW_CFG_DMA_CTL_SKIP);
362
363 if (Size == 0) {
364 return;
365 }
366
367 Access = &LocalAccess;
368 AccessMapping = NULL;
369 DataMapping = NULL;
370 DataBuffer = Buffer;
371
372 //
373 // When SEV is enabled, map Buffer to DMA address before issuing the DMA
374 // request
375 //
376 if (MemEncryptSevIsEnabled ()) {
377 VOID *AccessBuffer;
378 EFI_PHYSICAL_ADDRESS DataBufferAddress;
379
380 //
381 // Allocate DMA Access buffer
382 //
383 AllocFwCfgDmaAccessBuffer (&AccessBuffer, &AccessMapping);
384
385 Access = AccessBuffer;
386
387 //
388 // Map actual data buffer
389 //
390 if (Control != FW_CFG_DMA_CTL_SKIP) {
391 MapFwCfgDmaDataBuffer (
392 Control == FW_CFG_DMA_CTL_WRITE,
393 Buffer,
394 Size,
395 &DataBufferAddress,
396 &DataMapping
397 );
398
399 DataBuffer = (VOID *) (UINTN) DataBufferAddress;
400 }
401 }
402
403 Access->Control = SwapBytes32 (Control);
404 Access->Length = SwapBytes32 (Size);
405 Access->Address = SwapBytes64 ((UINTN)DataBuffer);
406
407 //
408 // Delimit the transfer from (a) modifications to Access, (b) in case of a
409 // write, from writes to Buffer by the caller.
410 //
411 MemoryFence ();
412
413 //
414 // Start the transfer.
415 //
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));
420
421 //
422 // Don't look at Access.Control before starting the transfer.
423 //
424 MemoryFence ();
425
426 //
427 // Wait for the transfer to complete.
428 //
429 do {
430 Status = SwapBytes32 (Access->Control);
431 ASSERT ((Status & FW_CFG_DMA_CTL_ERROR) == 0);
432 } while (Status != 0);
433
434 //
435 // After a read, the caller will want to use Buffer.
436 //
437 MemoryFence ();
438
439 //
440 // If Access buffer was dynamically allocated then free it.
441 //
442 if (AccessMapping != NULL) {
443 FreeFwCfgDmaAccessBuffer ((VOID *)Access, AccessMapping);
444 }
445
446 //
447 // If DataBuffer was mapped then unmap it.
448 //
449 if (DataMapping != NULL) {
450 UnmapFwCfgDmaDataBuffer (DataMapping);
451 }
452 }