]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxe.c
OvmfPkg: Apply uncrustify changes
[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 SPDX-License-Identifier: BSD-2-Clause-Patent
10 **/
11
12 #include <Uefi.h>
13
14 #include <Protocol/IoMmu.h>
15
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>
23
24 #include "QemuFwCfgLibInternal.h"
25
26 STATIC BOOLEAN mQemuFwCfgSupported = FALSE;
27 STATIC BOOLEAN mQemuFwCfgDmaSupported;
28
29 STATIC EDKII_IOMMU_PROTOCOL *mIoMmuProtocol;
30
31 /**
32 Returns a boolean indicating if the firmware configuration interface
33 is available or not.
34
35 This function may change fw_cfg state.
36
37 @retval TRUE The interface is available
38 @retval FALSE The interface is not available
39
40 **/
41 BOOLEAN
42 EFIAPI
43 QemuFwCfgIsAvailable (
44 VOID
45 )
46 {
47 return InternalQemuFwCfgIsAvailable ();
48 }
49
50 RETURN_STATUS
51 EFIAPI
52 QemuFwCfgInitialize (
53 VOID
54 )
55 {
56 UINT32 Signature;
57 UINT32 Revision;
58
59 //
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.
62 //
63 mQemuFwCfgSupported = TRUE;
64 mQemuFwCfgDmaSupported = FALSE;
65
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')) ||
73 (Revision < 1)
74 )
75 {
76 DEBUG ((DEBUG_INFO, "QemuFwCfg interface not supported.\n"));
77 mQemuFwCfgSupported = FALSE;
78 return RETURN_SUCCESS;
79 }
80
81 if ((Revision & FW_CFG_F_DMA) == 0) {
82 DEBUG ((DEBUG_INFO, "QemuFwCfg interface (IO Port) is supported.\n"));
83 } else {
84 mQemuFwCfgDmaSupported = TRUE;
85 DEBUG ((DEBUG_INFO, "QemuFwCfg interface (DMA) is supported.\n"));
86 }
87
88 if (mQemuFwCfgDmaSupported && MemEncryptSevIsEnabled ()) {
89 EFI_STATUS Status;
90
91 //
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.
94 //
95 Status = gBS->LocateProtocol (
96 &gEdkiiIoMmuProtocolGuid,
97 NULL,
98 (VOID **)&mIoMmuProtocol
99 );
100 if (EFI_ERROR (Status)) {
101 DEBUG ((
102 DEBUG_ERROR,
103 "QemuFwCfgSevDma %a:%a Failed to locate IOMMU protocol.\n",
104 gEfiCallerBaseName,
105 __FUNCTION__
106 ));
107 ASSERT (FALSE);
108 CpuDeadLoop ();
109 }
110 }
111
112 return RETURN_SUCCESS;
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 // BusMasterCommonBuffer64, 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 ((
185 DEBUG_ERROR,
186 "%a:%a failed to allocate FW_CFG_DMA_ACCESS\n",
187 gEfiCallerBaseName,
188 __FUNCTION__
189 ));
190 ASSERT (FALSE);
191 CpuDeadLoop ();
192 }
193
194 //
195 // Avoid exposing stale data even temporarily: zero the area before mapping
196 // it.
197 //
198 ZeroMem (HostAddress, Size);
199
200 //
201 // Map the host buffer with BusMasterCommonBuffer64
202 //
203 Status = mIoMmuProtocol->Map (
204 mIoMmuProtocol,
205 EdkiiIoMmuOperationBusMasterCommonBuffer64,
206 HostAddress,
207 &Size,
208 &DmaAddress,
209 &Mapping
210 );
211 if (EFI_ERROR (Status)) {
212 mIoMmuProtocol->FreeBuffer (mIoMmuProtocol, NumPages, HostAddress);
213 DEBUG ((
214 DEBUG_ERROR,
215 "%a:%a failed to Map() FW_CFG_DMA_ACCESS\n",
216 gEfiCallerBaseName,
217 __FUNCTION__
218 ));
219 ASSERT (FALSE);
220 CpuDeadLoop ();
221 }
222
223 if (Size < sizeof (FW_CFG_DMA_ACCESS)) {
224 mIoMmuProtocol->Unmap (mIoMmuProtocol, Mapping);
225 mIoMmuProtocol->FreeBuffer (mIoMmuProtocol, NumPages, HostAddress);
226 DEBUG ((
227 DEBUG_ERROR,
228 "%a:%a failed to Map() - requested 0x%Lx got 0x%Lx\n",
229 gEfiCallerBaseName,
230 __FUNCTION__,
231 (UINT64)sizeof (FW_CFG_DMA_ACCESS),
232 (UINT64)Size
233 ));
234 ASSERT (FALSE);
235 CpuDeadLoop ();
236 }
237
238 *Access = HostAddress;
239 *MapInfo = Mapping;
240 }
241
242 /**
243 Function is to used for freeing the Access buffer allocated using
244 AllocFwCfgDmaAccessBuffer()
245
246 **/
247 STATIC
248 VOID
249 FreeFwCfgDmaAccessBuffer (
250 IN VOID *Access,
251 IN VOID *Mapping
252 )
253 {
254 UINTN NumPages;
255 EFI_STATUS Status;
256
257 NumPages = EFI_SIZE_TO_PAGES (sizeof (FW_CFG_DMA_ACCESS));
258
259 Status = mIoMmuProtocol->Unmap (mIoMmuProtocol, Mapping);
260 if (EFI_ERROR (Status)) {
261 DEBUG ((
262 DEBUG_ERROR,
263 "%a:%a failed to UnMap() Mapping 0x%Lx\n",
264 gEfiCallerBaseName,
265 __FUNCTION__,
266 (UINT64)(UINTN)Mapping
267 ));
268 ASSERT (FALSE);
269 CpuDeadLoop ();
270 }
271
272 Status = mIoMmuProtocol->FreeBuffer (mIoMmuProtocol, NumPages, Access);
273 if (EFI_ERROR (Status)) {
274 DEBUG ((
275 DEBUG_ERROR,
276 "%a:%a failed to Free() 0x%Lx\n",
277 gEfiCallerBaseName,
278 __FUNCTION__,
279 (UINT64)(UINTN)Access
280 ));
281 ASSERT (FALSE);
282 CpuDeadLoop ();
283 }
284 }
285
286 /**
287 Function is used for mapping host address to device address. The buffer must
288 be unmapped with UnmapDmaDataBuffer ().
289
290 **/
291 STATIC
292 VOID
293 MapFwCfgDmaDataBuffer (
294 IN BOOLEAN IsWrite,
295 IN VOID *HostAddress,
296 IN UINT32 Size,
297 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
298 OUT VOID **MapInfo
299 )
300 {
301 EFI_STATUS Status;
302 UINTN NumberOfBytes;
303 VOID *Mapping;
304 EFI_PHYSICAL_ADDRESS PhysicalAddress;
305
306 NumberOfBytes = Size;
307 Status = mIoMmuProtocol->Map (
308 mIoMmuProtocol,
309 (IsWrite ?
310 EdkiiIoMmuOperationBusMasterRead64 :
311 EdkiiIoMmuOperationBusMasterWrite64),
312 HostAddress,
313 &NumberOfBytes,
314 &PhysicalAddress,
315 &Mapping
316 );
317 if (EFI_ERROR (Status)) {
318 DEBUG ((
319 DEBUG_ERROR,
320 "%a:%a failed to Map() Address 0x%Lx Size 0x%Lx\n",
321 gEfiCallerBaseName,
322 __FUNCTION__,
323 (UINT64)(UINTN)HostAddress,
324 (UINT64)Size
325 ));
326 ASSERT (FALSE);
327 CpuDeadLoop ();
328 }
329
330 if (NumberOfBytes < Size) {
331 mIoMmuProtocol->Unmap (mIoMmuProtocol, Mapping);
332 DEBUG ((
333 DEBUG_ERROR,
334 "%a:%a failed to Map() - requested 0x%x got 0x%Lx\n",
335 gEfiCallerBaseName,
336 __FUNCTION__,
337 Size,
338 (UINT64)NumberOfBytes
339 ));
340 ASSERT (FALSE);
341 CpuDeadLoop ();
342 }
343
344 *DeviceAddress = PhysicalAddress;
345 *MapInfo = Mapping;
346 }
347
348 STATIC
349 VOID
350 UnmapFwCfgDmaDataBuffer (
351 IN VOID *Mapping
352 )
353 {
354 EFI_STATUS Status;
355
356 Status = mIoMmuProtocol->Unmap (mIoMmuProtocol, Mapping);
357 if (EFI_ERROR (Status)) {
358 DEBUG ((
359 DEBUG_ERROR,
360 "%a:%a failed to UnMap() Mapping 0x%Lx\n",
361 gEfiCallerBaseName,
362 __FUNCTION__,
363 (UINT64)(UINTN)Mapping
364 ));
365 ASSERT (FALSE);
366 CpuDeadLoop ();
367 }
368 }
369
370 /**
371 Transfer an array of bytes, or skip a number of bytes, using the DMA
372 interface.
373
374 @param[in] Size Size in bytes to transfer or skip.
375
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
378 FW_CFG_DMA_CTL_SKIP.
379
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.
384 **/
385 VOID
386 InternalQemuFwCfgDmaBytes (
387 IN UINT32 Size,
388 IN OUT VOID *Buffer OPTIONAL,
389 IN UINT32 Control
390 )
391 {
392 volatile FW_CFG_DMA_ACCESS LocalAccess;
393 volatile FW_CFG_DMA_ACCESS *Access;
394 UINT32 AccessHigh, AccessLow;
395 UINT32 Status;
396 VOID *AccessMapping, *DataMapping;
397 VOID *DataBuffer;
398
399 ASSERT (
400 Control == FW_CFG_DMA_CTL_WRITE || Control == FW_CFG_DMA_CTL_READ ||
401 Control == FW_CFG_DMA_CTL_SKIP
402 );
403
404 if (Size == 0) {
405 return;
406 }
407
408 Access = &LocalAccess;
409 AccessMapping = NULL;
410 DataMapping = NULL;
411 DataBuffer = Buffer;
412
413 //
414 // When SEV is enabled, map Buffer to DMA address before issuing the DMA
415 // request
416 //
417 if (MemEncryptSevIsEnabled ()) {
418 VOID *AccessBuffer;
419 EFI_PHYSICAL_ADDRESS DataBufferAddress;
420
421 //
422 // Allocate DMA Access buffer
423 //
424 AllocFwCfgDmaAccessBuffer (&AccessBuffer, &AccessMapping);
425
426 Access = AccessBuffer;
427
428 //
429 // Map actual data buffer
430 //
431 if (Control != FW_CFG_DMA_CTL_SKIP) {
432 MapFwCfgDmaDataBuffer (
433 Control == FW_CFG_DMA_CTL_WRITE,
434 Buffer,
435 Size,
436 &DataBufferAddress,
437 &DataMapping
438 );
439
440 DataBuffer = (VOID *)(UINTN)DataBufferAddress;
441 }
442 }
443
444 Access->Control = SwapBytes32 (Control);
445 Access->Length = SwapBytes32 (Size);
446 Access->Address = SwapBytes64 ((UINTN)DataBuffer);
447
448 //
449 // Delimit the transfer from (a) modifications to Access, (b) in case of a
450 // write, from writes to Buffer by the caller.
451 //
452 MemoryFence ();
453
454 //
455 // Start the transfer.
456 //
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));
461
462 //
463 // Don't look at Access.Control before starting the transfer.
464 //
465 MemoryFence ();
466
467 //
468 // Wait for the transfer to complete.
469 //
470 do {
471 Status = SwapBytes32 (Access->Control);
472 ASSERT ((Status & FW_CFG_DMA_CTL_ERROR) == 0);
473 } while (Status != 0);
474
475 //
476 // After a read, the caller will want to use Buffer.
477 //
478 MemoryFence ();
479
480 //
481 // If Access buffer was dynamically allocated then free it.
482 //
483 if (AccessMapping != NULL) {
484 FreeFwCfgDmaAccessBuffer ((VOID *)Access, AccessMapping);
485 }
486
487 //
488 // If DataBuffer was mapped then unmap it.
489 //
490 if (DataMapping != NULL) {
491 UnmapFwCfgDmaDataBuffer (DataMapping);
492 }
493 }