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