TianoCore EDK2 master
Loading...
Searching...
No Matches
QemuFwCfgDxe.c
Go to the documentation of this file.
1
12#include <Uefi.h>
13
14#include <Protocol/IoMmu.h>
15
16#include <Library/BaseLib.h>
18#include <Library/IoLib.h>
19#include <Library/DebugLib.h>
24
26
27STATIC BOOLEAN mQemuFwCfgSupported = FALSE;
28STATIC BOOLEAN mQemuFwCfgDmaSupported;
29
30STATIC EDKII_IOMMU_PROTOCOL *mIoMmuProtocol;
31
42BOOLEAN
43EFIAPI
45 VOID
46 )
47{
49}
50
51RETURN_STATUS
52EFIAPI
53QemuFwCfgInitialize (
54 VOID
55 )
56{
57 UINT32 Signature;
58 UINT32 Revision;
59
60 //
61 // Enable the access routines while probing to see if it is supported.
62 // For probing we always use the IO Port (IoReadFifo8()) access method.
63 //
64 mQemuFwCfgSupported = TRUE;
65 mQemuFwCfgDmaSupported = FALSE;
66
67 QemuFwCfgSelectItem (QemuFwCfgItemSignature);
68 Signature = QemuFwCfgRead32 ();
69 DEBUG ((DEBUG_INFO, "FW CFG Signature: 0x%x\n", Signature));
70 QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion);
71 Revision = QemuFwCfgRead32 ();
72 DEBUG ((DEBUG_INFO, "FW CFG Revision: 0x%x\n", Revision));
73 if ((Signature != SIGNATURE_32 ('Q', 'E', 'M', 'U')) ||
74 (Revision < 1)
75 )
76 {
77 DEBUG ((DEBUG_INFO, "QemuFwCfg interface not supported.\n"));
78 mQemuFwCfgSupported = FALSE;
79 return RETURN_SUCCESS;
80 }
81
82 if ((Revision & FW_CFG_F_DMA) == 0) {
83 DEBUG ((DEBUG_INFO, "QemuFwCfg interface (IO Port) is supported.\n"));
84 } else {
85 mQemuFwCfgDmaSupported = TRUE;
86 DEBUG ((DEBUG_INFO, "QemuFwCfg interface (DMA) is supported.\n"));
87 }
88
89 if (mQemuFwCfgDmaSupported && (MemEncryptSevIsEnabled () || (MemEncryptTdxIsEnabled ()))) {
90 EFI_STATUS Status;
91
92 //
93 // IoMmuDxe driver must have installed the IOMMU protocol. If we are not
94 // able to locate the protocol then something must have gone wrong.
95 //
96 Status = gBS->LocateProtocol (
98 NULL,
99 (VOID **)&mIoMmuProtocol
100 );
101 if (EFI_ERROR (Status)) {
102 DEBUG ((
103 DEBUG_ERROR,
104 "QemuFwCfgDma %a:%a Failed to locate IOMMU protocol.\n",
105 gEfiCallerBaseName,
106 __func__
107 ));
108 ASSERT (FALSE);
109 CpuDeadLoop ();
110 }
111 }
112
113 return RETURN_SUCCESS;
114}
115
125BOOLEAN
127 VOID
128 )
129{
130 return mQemuFwCfgSupported;
131}
132
140BOOLEAN
142 VOID
143 )
144{
145 return mQemuFwCfgDmaSupported;
146}
147
154STATIC
155VOID
157 OUT VOID **Access,
158 OUT VOID **MapInfo
159 )
160{
161 UINTN Size;
162 UINTN NumPages;
163 EFI_STATUS Status;
164 VOID *HostAddress;
165 EFI_PHYSICAL_ADDRESS DmaAddress;
166 VOID *Mapping;
167
168 Size = sizeof (FW_CFG_DMA_ACCESS);
169 NumPages = EFI_SIZE_TO_PAGES (Size);
170
171 //
172 // As per UEFI spec, in order to map a host address with
173 // BusMasterCommonBuffer64, the buffer must be allocated using the IOMMU
174 // AllocateBuffer()
175 //
176 Status = mIoMmuProtocol->AllocateBuffer (
177 mIoMmuProtocol,
180 NumPages,
181 &HostAddress,
182 EDKII_IOMMU_ATTRIBUTE_DUAL_ADDRESS_CYCLE
183 );
184 if (EFI_ERROR (Status)) {
185 DEBUG ((
186 DEBUG_ERROR,
187 "%a:%a failed to allocate FW_CFG_DMA_ACCESS\n",
188 gEfiCallerBaseName,
189 __func__
190 ));
191 ASSERT (FALSE);
192 CpuDeadLoop ();
193 }
194
195 //
196 // Avoid exposing stale data even temporarily: zero the area before mapping
197 // it.
198 //
199 ZeroMem (HostAddress, Size);
200
201 //
202 // Map the host buffer with BusMasterCommonBuffer64
203 //
204 Status = mIoMmuProtocol->Map (
205 mIoMmuProtocol,
207 HostAddress,
208 &Size,
209 &DmaAddress,
210 &Mapping
211 );
212 if (EFI_ERROR (Status)) {
213 mIoMmuProtocol->FreeBuffer (mIoMmuProtocol, NumPages, HostAddress);
214 DEBUG ((
215 DEBUG_ERROR,
216 "%a:%a failed to Map() FW_CFG_DMA_ACCESS\n",
217 gEfiCallerBaseName,
218 __func__
219 ));
220 ASSERT (FALSE);
221 CpuDeadLoop ();
222 }
223
224 if (Size < sizeof (FW_CFG_DMA_ACCESS)) {
225 mIoMmuProtocol->Unmap (mIoMmuProtocol, Mapping);
226 mIoMmuProtocol->FreeBuffer (mIoMmuProtocol, NumPages, HostAddress);
227 DEBUG ((
228 DEBUG_ERROR,
229 "%a:%a failed to Map() - requested 0x%Lx got 0x%Lx\n",
230 gEfiCallerBaseName,
231 __func__,
232 (UINT64)sizeof (FW_CFG_DMA_ACCESS),
233 (UINT64)Size
234 ));
235 ASSERT (FALSE);
236 CpuDeadLoop ();
237 }
238
239 *Access = HostAddress;
240 *MapInfo = Mapping;
241}
242
248STATIC
249VOID
251 IN VOID *Access,
252 IN VOID *Mapping
253 )
254{
255 UINTN NumPages;
256 EFI_STATUS Status;
257
258 NumPages = EFI_SIZE_TO_PAGES (sizeof (FW_CFG_DMA_ACCESS));
259
260 Status = mIoMmuProtocol->Unmap (mIoMmuProtocol, Mapping);
261 if (EFI_ERROR (Status)) {
262 DEBUG ((
263 DEBUG_ERROR,
264 "%a:%a failed to UnMap() Mapping 0x%Lx\n",
265 gEfiCallerBaseName,
266 __func__,
267 (UINT64)(UINTN)Mapping
268 ));
269 ASSERT (FALSE);
270 CpuDeadLoop ();
271 }
272
273 Status = mIoMmuProtocol->FreeBuffer (mIoMmuProtocol, NumPages, Access);
274 if (EFI_ERROR (Status)) {
275 DEBUG ((
276 DEBUG_ERROR,
277 "%a:%a failed to Free() 0x%Lx\n",
278 gEfiCallerBaseName,
279 __func__,
280 (UINT64)(UINTN)Access
281 ));
282 ASSERT (FALSE);
283 CpuDeadLoop ();
284 }
285}
286
292STATIC
293VOID
295 IN BOOLEAN IsWrite,
296 IN VOID *HostAddress,
297 IN UINT32 Size,
298 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
299 OUT VOID **MapInfo
300 )
301{
302 EFI_STATUS Status;
303 UINTN NumberOfBytes;
304 VOID *Mapping;
305 EFI_PHYSICAL_ADDRESS PhysicalAddress;
306
307 NumberOfBytes = Size;
308 Status = mIoMmuProtocol->Map (
309 mIoMmuProtocol,
310 (IsWrite ?
313 HostAddress,
314 &NumberOfBytes,
315 &PhysicalAddress,
316 &Mapping
317 );
318 if (EFI_ERROR (Status)) {
319 DEBUG ((
320 DEBUG_ERROR,
321 "%a:%a failed to Map() Address 0x%Lx Size 0x%Lx\n",
322 gEfiCallerBaseName,
323 __func__,
324 (UINT64)(UINTN)HostAddress,
325 (UINT64)Size
326 ));
327 ASSERT (FALSE);
328 CpuDeadLoop ();
329 }
330
331 if (NumberOfBytes < Size) {
332 mIoMmuProtocol->Unmap (mIoMmuProtocol, Mapping);
333 DEBUG ((
334 DEBUG_ERROR,
335 "%a:%a failed to Map() - requested 0x%x got 0x%Lx\n",
336 gEfiCallerBaseName,
337 __func__,
338 Size,
339 (UINT64)NumberOfBytes
340 ));
341 ASSERT (FALSE);
342 CpuDeadLoop ();
343 }
344
345 *DeviceAddress = PhysicalAddress;
346 *MapInfo = Mapping;
347}
348
349STATIC
350VOID
351UnmapFwCfgDmaDataBuffer (
352 IN VOID *Mapping
353 )
354{
355 EFI_STATUS Status;
356
357 Status = mIoMmuProtocol->Unmap (mIoMmuProtocol, Mapping);
358 if (EFI_ERROR (Status)) {
359 DEBUG ((
360 DEBUG_ERROR,
361 "%a:%a failed to UnMap() Mapping 0x%Lx\n",
362 gEfiCallerBaseName,
363 __func__,
364 (UINT64)(UINTN)Mapping
365 ));
366 ASSERT (FALSE);
367 CpuDeadLoop ();
368 }
369}
370
386VOID
388 IN UINT32 Size,
389 IN OUT VOID *Buffer OPTIONAL,
390 IN UINT32 Control
391 )
392{
393 volatile FW_CFG_DMA_ACCESS LocalAccess;
394 volatile FW_CFG_DMA_ACCESS *Access;
395 UINT32 AccessHigh, AccessLow;
396 UINT32 Status;
397 VOID *AccessMapping, *DataMapping;
398 VOID *DataBuffer;
399
400 ASSERT (
401 Control == FW_CFG_DMA_CTL_WRITE || Control == FW_CFG_DMA_CTL_READ ||
402 Control == FW_CFG_DMA_CTL_SKIP
403 );
404
405 if (Size == 0) {
406 return;
407 }
408
409 Access = &LocalAccess;
410 AccessMapping = NULL;
411 DataMapping = NULL;
412 DataBuffer = Buffer;
413
414 //
415 // When SEV or TDX is enabled, map Buffer to DMA address before issuing the DMA
416 // request
417 //
419 VOID *AccessBuffer;
420 EFI_PHYSICAL_ADDRESS DataBufferAddress;
421
422 //
423 // Allocate DMA Access buffer
424 //
425 AllocFwCfgDmaAccessBuffer (&AccessBuffer, &AccessMapping);
426
427 Access = AccessBuffer;
428
429 //
430 // Map actual data buffer
431 //
432 if (Control != FW_CFG_DMA_CTL_SKIP) {
434 Control == FW_CFG_DMA_CTL_WRITE,
435 Buffer,
436 Size,
437 &DataBufferAddress,
438 &DataMapping
439 );
440
441 DataBuffer = (VOID *)(UINTN)DataBufferAddress;
442 }
443 }
444
445 Access->Control = SwapBytes32 (Control);
446 Access->Length = SwapBytes32 (Size);
447 Access->Address = SwapBytes64 ((UINTN)DataBuffer);
448
449 //
450 // Delimit the transfer from (a) modifications to Access, (b) in case of a
451 // write, from writes to Buffer by the caller.
452 //
453 MemoryFence ();
454
455 //
456 // Start the transfer.
457 //
458 AccessHigh = (UINT32)RShiftU64 ((UINTN)Access, 32);
459 AccessLow = (UINT32)(UINTN)Access;
460 IoWrite32 (FW_CFG_IO_DMA_ADDRESS, SwapBytes32 (AccessHigh));
461 IoWrite32 (FW_CFG_IO_DMA_ADDRESS + 4, SwapBytes32 (AccessLow));
462
463 //
464 // Don't look at Access.Control before starting the transfer.
465 //
466 MemoryFence ();
467
468 //
469 // Wait for the transfer to complete.
470 //
471 do {
472 Status = SwapBytes32 (Access->Control);
473 ASSERT ((Status & FW_CFG_DMA_CTL_ERROR) == 0);
474 } while (Status != 0);
475
476 //
477 // After a read, the caller will want to use Buffer.
478 //
479 MemoryFence ();
480
481 //
482 // If Access buffer was dynamically allocated then free it.
483 //
484 if (AccessMapping != NULL) {
485 FreeFwCfgDmaAccessBuffer ((VOID *)Access, AccessMapping);
486 }
487
488 //
489 // If DataBuffer was mapped then unmap it.
490 //
491 if (DataMapping != NULL) {
492 UnmapFwCfgDmaDataBuffer (DataMapping);
493 }
494}
UINT64 UINTN
VOID EFIAPI CpuDeadLoop(VOID)
Definition: CpuDeadLoop.c:25
VOID EFIAPI MemoryFence(VOID)
Definition: CpuBreakpoint.c:42
UINT32 EFIAPI SwapBytes32(IN UINT32 Value)
Definition: SwapBytes32.c:25
UINT64 EFIAPI RShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition: RShiftU64.c:28
UINT64 EFIAPI SwapBytes64(IN UINT64 Value)
Definition: SwapBytes64.c:25
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
UINT32 EFIAPI IoWrite32(IN UINTN Port, IN UINT32 Value)
Definition: IoLibArmVirt.c:300
#define NULL
Definition: Base.h:319
#define STATIC
Definition: Base.h:264
#define RETURN_SUCCESS
Definition: Base.h:1066
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define SIGNATURE_32(A, B, C, D)
Definition: Base.h:1310
#define OUT
Definition: Base.h:284
#define DEBUG(Expression)
Definition: DebugLib.h:434
BOOLEAN EFIAPI MemEncryptSevIsEnabled(VOID)
BOOLEAN EFIAPI MemEncryptTdxIsEnabled(VOID)
EFI_GUID gEdkiiIoMmuProtocolGuid
@ EdkiiIoMmuOperationBusMasterWrite64
Definition: IoMmu.h:69
@ EdkiiIoMmuOperationBusMasterRead64
Definition: IoMmu.h:64
@ EdkiiIoMmuOperationBusMasterCommonBuffer64
Definition: IoMmu.h:74
STATIC VOID MapFwCfgDmaDataBuffer(IN BOOLEAN IsWrite, IN VOID *HostAddress, IN UINT32 Size, OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, OUT VOID **MapInfo)
Definition: QemuFwCfgDxe.c:294
STATIC VOID FreeFwCfgDmaAccessBuffer(IN VOID *Access, IN VOID *Mapping)
Definition: QemuFwCfgDxe.c:250
BOOLEAN InternalQemuFwCfgIsAvailable(VOID)
Definition: QemuFwCfgDxe.c:126
VOID InternalQemuFwCfgDmaBytes(IN UINT32 Size, IN OUT VOID *Buffer OPTIONAL, IN UINT32 Control)
Definition: QemuFwCfgDxe.c:387
STATIC VOID AllocFwCfgDmaAccessBuffer(OUT VOID **Access, OUT VOID **MapInfo)
Definition: QemuFwCfgDxe.c:156
BOOLEAN InternalQemuFwCfgDmaIsAvailable(VOID)
Definition: QemuFwCfgDxe.c:141
BOOLEAN EFIAPI QemuFwCfgIsAvailable(VOID)
Definition: QemuFwCfgDxe.c:44
UINT32 EFIAPI QemuFwCfgRead32(VOID)
Definition: QemuFwCfgLib.c:205
VOID EFIAPI QemuFwCfgSelectItem(IN FIRMWARE_CONFIG_ITEM QemuFwCfgItem)
Definition: QemuFwCfgLib.c:33
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SIZE_TO_PAGES(Size)
Definition: UefiBaseType.h:200
EFI_BOOT_SERVICES * gBS
@ EfiBootServicesData
@ AllocateAnyPages
Definition: UefiSpec.h:33