]> git.proxmox.com Git - mirror_edk2.git/blob - ArmVirtPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c
ArmVirtPkg, OvmfPkg: QemuFwCfgLib: move DMA-related defs to lib class
[mirror_edk2.git] / ArmVirtPkg / Library / QemuFwCfgLib / QemuFwCfgLib.c
1 /** @file
2
3 Stateful and implicitly initialized fw_cfg library implementation.
4
5 Copyright (C) 2013 - 2014, Red Hat, Inc.
6 Copyright (c) 2011 - 2013, Intel Corporation. All rights reserved.<BR>
7
8 This program and the accompanying materials are licensed and made available
9 under the terms and conditions of the BSD License which accompanies this
10 distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
12
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
14 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 **/
16
17 #include <Uefi.h>
18
19 #include <Library/BaseLib.h>
20 #include <Library/BaseMemoryLib.h>
21 #include <Library/DebugLib.h>
22 #include <Library/IoLib.h>
23 #include <Library/QemuFwCfgLib.h>
24 #include <Library/UefiBootServicesTableLib.h>
25
26 #include <Protocol/FdtClient.h>
27
28 STATIC UINTN mFwCfgSelectorAddress;
29 STATIC UINTN mFwCfgDataAddress;
30 STATIC UINTN mFwCfgDmaAddress;
31
32 /**
33 Reads firmware configuration bytes into a buffer
34
35 @param[in] Size Size in bytes to read
36 @param[in] Buffer Buffer to store data into (OPTIONAL if Size is 0)
37
38 **/
39 typedef
40 VOID (EFIAPI READ_BYTES_FUNCTION) (
41 IN UINTN Size,
42 IN VOID *Buffer OPTIONAL
43 );
44
45 //
46 // Forward declaration of the two implementations we have.
47 //
48 STATIC READ_BYTES_FUNCTION MmioReadBytes;
49 STATIC READ_BYTES_FUNCTION DmaReadBytes;
50
51 //
52 // This points to the one we detect at runtime.
53 //
54 STATIC READ_BYTES_FUNCTION *InternalQemuFwCfgReadBytes = MmioReadBytes;
55
56
57 /**
58 Returns a boolean indicating if the firmware configuration interface
59 is available or not.
60
61 This function may change fw_cfg state.
62
63 @retval TRUE The interface is available
64 @retval FALSE The interface is not available
65
66 **/
67 BOOLEAN
68 EFIAPI
69 QemuFwCfgIsAvailable (
70 VOID
71 )
72 {
73 return (BOOLEAN)(mFwCfgSelectorAddress != 0 && mFwCfgDataAddress != 0);
74 }
75
76
77 RETURN_STATUS
78 EFIAPI
79 QemuFwCfgInitialize (
80 VOID
81 )
82 {
83 EFI_STATUS Status;
84 FDT_CLIENT_PROTOCOL *FdtClient;
85 CONST UINT64 *Reg;
86 UINT32 RegSize;
87 UINTN AddressCells, SizeCells;
88 UINT64 FwCfgSelectorAddress;
89 UINT64 FwCfgSelectorSize;
90 UINT64 FwCfgDataAddress;
91 UINT64 FwCfgDataSize;
92 UINT64 FwCfgDmaAddress;
93 UINT64 FwCfgDmaSize;
94
95 Status = gBS->LocateProtocol (&gFdtClientProtocolGuid, NULL,
96 (VOID **)&FdtClient);
97 ASSERT_EFI_ERROR (Status);
98
99 Status = FdtClient->FindCompatibleNodeReg (FdtClient, "qemu,fw-cfg-mmio",
100 (CONST VOID **)&Reg, &AddressCells, &SizeCells,
101 &RegSize);
102 if (EFI_ERROR (Status)) {
103 DEBUG ((EFI_D_WARN,
104 "%a: No 'qemu,fw-cfg-mmio' compatible DT node found (Status == %r)\n",
105 __FUNCTION__, Status));
106 return EFI_SUCCESS;
107 }
108
109 ASSERT (AddressCells == 2);
110 ASSERT (SizeCells == 2);
111 ASSERT (RegSize == 2 * sizeof (UINT64));
112
113 FwCfgDataAddress = SwapBytes64 (Reg[0]);
114 FwCfgDataSize = 8;
115 FwCfgSelectorAddress = FwCfgDataAddress + FwCfgDataSize;
116 FwCfgSelectorSize = 2;
117
118 //
119 // The following ASSERT()s express
120 //
121 // Address + Size - 1 <= MAX_UINTN
122 //
123 // for both registers, that is, that the last byte in each MMIO range is
124 // expressible as a MAX_UINTN. The form below is mathematically
125 // equivalent, and it also prevents any unsigned overflow before the
126 // comparison.
127 //
128 ASSERT (FwCfgSelectorAddress <= MAX_UINTN - FwCfgSelectorSize + 1);
129 ASSERT (FwCfgDataAddress <= MAX_UINTN - FwCfgDataSize + 1);
130
131 mFwCfgSelectorAddress = FwCfgSelectorAddress;
132 mFwCfgDataAddress = FwCfgDataAddress;
133
134 DEBUG ((EFI_D_INFO, "Found FwCfg @ 0x%Lx/0x%Lx\n", FwCfgSelectorAddress,
135 FwCfgDataAddress));
136
137 if (SwapBytes64 (Reg[1]) >= 0x18) {
138 FwCfgDmaAddress = FwCfgDataAddress + 0x10;
139 FwCfgDmaSize = 0x08;
140
141 //
142 // See explanation above.
143 //
144 ASSERT (FwCfgDmaAddress <= MAX_UINTN - FwCfgDmaSize + 1);
145
146 DEBUG ((EFI_D_INFO, "Found FwCfg DMA @ 0x%Lx\n", FwCfgDmaAddress));
147 } else {
148 FwCfgDmaAddress = 0;
149 }
150
151 if (QemuFwCfgIsAvailable ()) {
152 UINT32 Signature;
153
154 QemuFwCfgSelectItem (QemuFwCfgItemSignature);
155 Signature = QemuFwCfgRead32 ();
156 if (Signature == SIGNATURE_32 ('Q', 'E', 'M', 'U')) {
157 //
158 // For DMA support, we require the DTB to advertise the register, and the
159 // feature bitmap (which we read without DMA) to confirm the feature.
160 //
161 if (FwCfgDmaAddress != 0) {
162 UINT32 Features;
163
164 QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion);
165 Features = QemuFwCfgRead32 ();
166 if ((Features & BIT1) != 0) {
167 mFwCfgDmaAddress = FwCfgDmaAddress;
168 InternalQemuFwCfgReadBytes = DmaReadBytes;
169 }
170 }
171 } else {
172 mFwCfgSelectorAddress = 0;
173 mFwCfgDataAddress = 0;
174 }
175 }
176 return RETURN_SUCCESS;
177 }
178
179
180 /**
181 Selects a firmware configuration item for reading.
182
183 Following this call, any data read from this item will start from the
184 beginning of the configuration item's data.
185
186 @param[in] QemuFwCfgItem Firmware Configuration item to read
187
188 **/
189 VOID
190 EFIAPI
191 QemuFwCfgSelectItem (
192 IN FIRMWARE_CONFIG_ITEM QemuFwCfgItem
193 )
194 {
195 if (QemuFwCfgIsAvailable ()) {
196 MmioWrite16 (mFwCfgSelectorAddress, SwapBytes16 ((UINT16)QemuFwCfgItem));
197 }
198 }
199
200
201 /**
202 Slow READ_BYTES_FUNCTION.
203 **/
204 STATIC
205 VOID
206 EFIAPI
207 MmioReadBytes (
208 IN UINTN Size,
209 IN VOID *Buffer OPTIONAL
210 )
211 {
212 UINTN Left;
213 UINT8 *Ptr;
214 UINT8 *End;
215
216 #ifdef MDE_CPU_AARCH64
217 Left = Size & 7;
218 #else
219 Left = Size & 3;
220 #endif
221
222 Size -= Left;
223 Ptr = Buffer;
224 End = Ptr + Size;
225
226 #ifdef MDE_CPU_AARCH64
227 while (Ptr < End) {
228 *(UINT64 *)Ptr = MmioRead64 (mFwCfgDataAddress);
229 Ptr += 8;
230 }
231 if (Left & 4) {
232 *(UINT32 *)Ptr = MmioRead32 (mFwCfgDataAddress);
233 Ptr += 4;
234 }
235 #else
236 while (Ptr < End) {
237 *(UINT32 *)Ptr = MmioRead32 (mFwCfgDataAddress);
238 Ptr += 4;
239 }
240 #endif
241
242 if (Left & 2) {
243 *(UINT16 *)Ptr = MmioRead16 (mFwCfgDataAddress);
244 Ptr += 2;
245 }
246 if (Left & 1) {
247 *Ptr = MmioRead8 (mFwCfgDataAddress);
248 }
249 }
250
251
252 /**
253 Fast READ_BYTES_FUNCTION.
254 **/
255 STATIC
256 VOID
257 EFIAPI
258 DmaReadBytes (
259 IN UINTN Size,
260 IN VOID *Buffer OPTIONAL
261 )
262 {
263 volatile FW_CFG_DMA_ACCESS Access;
264 UINT32 Status;
265
266 if (Size == 0) {
267 return;
268 }
269
270 ASSERT (Size <= MAX_UINT32);
271
272 Access.Control = SwapBytes32 (FW_CFG_DMA_CTL_READ);
273 Access.Length = SwapBytes32 ((UINT32)Size);
274 Access.Address = SwapBytes64 ((UINT64)(UINTN)Buffer);
275
276 //
277 // We shouldn't start the transfer before setting up Access.
278 //
279 MemoryFence ();
280
281 //
282 // This will fire off the transfer.
283 //
284 #ifdef MDE_CPU_AARCH64
285 MmioWrite64 (mFwCfgDmaAddress, SwapBytes64 ((UINT64)&Access));
286 #else
287 MmioWrite32 ((UINT32)(mFwCfgDmaAddress + 4), SwapBytes32 ((UINT32)&Access));
288 #endif
289
290 //
291 // We shouldn't look at Access.Control before starting the transfer.
292 //
293 MemoryFence ();
294
295 do {
296 Status = SwapBytes32 (Access.Control);
297 ASSERT ((Status & FW_CFG_DMA_CTL_ERROR) == 0);
298 } while (Status != 0);
299
300 //
301 // The caller will want to access the transferred data.
302 //
303 MemoryFence ();
304 }
305
306
307 /**
308 Reads firmware configuration bytes into a buffer
309
310 If called multiple times, then the data read will continue at the offset of
311 the firmware configuration item where the previous read ended.
312
313 @param[in] Size Size in bytes to read
314 @param[in] Buffer Buffer to store data into
315
316 **/
317 VOID
318 EFIAPI
319 QemuFwCfgReadBytes (
320 IN UINTN Size,
321 IN VOID *Buffer
322 )
323 {
324 if (QemuFwCfgIsAvailable ()) {
325 InternalQemuFwCfgReadBytes (Size, Buffer);
326 } else {
327 ZeroMem (Buffer, Size);
328 }
329 }
330
331 /**
332 Write firmware configuration bytes from a buffer
333
334 If called multiple times, then the data written will continue at the offset
335 of the firmware configuration item where the previous write ended.
336
337 @param[in] Size Size in bytes to write
338 @param[in] Buffer Buffer to read data from
339
340 **/
341 VOID
342 EFIAPI
343 QemuFwCfgWriteBytes (
344 IN UINTN Size,
345 IN VOID *Buffer
346 )
347 {
348 if (QemuFwCfgIsAvailable ()) {
349 UINTN Idx;
350
351 for (Idx = 0; Idx < Size; ++Idx) {
352 MmioWrite8 (mFwCfgDataAddress, ((UINT8 *)Buffer)[Idx]);
353 }
354 }
355 }
356
357
358 /**
359 Reads a UINT8 firmware configuration value
360
361 @return Value of Firmware Configuration item read
362
363 **/
364 UINT8
365 EFIAPI
366 QemuFwCfgRead8 (
367 VOID
368 )
369 {
370 UINT8 Result;
371
372 QemuFwCfgReadBytes (sizeof Result, &Result);
373 return Result;
374 }
375
376
377 /**
378 Reads a UINT16 firmware configuration value
379
380 @return Value of Firmware Configuration item read
381
382 **/
383 UINT16
384 EFIAPI
385 QemuFwCfgRead16 (
386 VOID
387 )
388 {
389 UINT16 Result;
390
391 QemuFwCfgReadBytes (sizeof Result, &Result);
392 return Result;
393 }
394
395
396 /**
397 Reads a UINT32 firmware configuration value
398
399 @return Value of Firmware Configuration item read
400
401 **/
402 UINT32
403 EFIAPI
404 QemuFwCfgRead32 (
405 VOID
406 )
407 {
408 UINT32 Result;
409
410 QemuFwCfgReadBytes (sizeof Result, &Result);
411 return Result;
412 }
413
414
415 /**
416 Reads a UINT64 firmware configuration value
417
418 @return Value of Firmware Configuration item read
419
420 **/
421 UINT64
422 EFIAPI
423 QemuFwCfgRead64 (
424 VOID
425 )
426 {
427 UINT64 Result;
428
429 QemuFwCfgReadBytes (sizeof Result, &Result);
430 return Result;
431 }
432
433
434 /**
435 Find the configuration item corresponding to the firmware configuration file.
436
437 @param[in] Name Name of file to look up.
438 @param[out] Item Configuration item corresponding to the file, to be passed
439 to QemuFwCfgSelectItem ().
440 @param[out] Size Number of bytes in the file.
441
442 @retval RETURN_SUCCESS If file is found.
443 @retval RETURN_NOT_FOUND If file is not found.
444 @retval RETURN_UNSUPPORTED If firmware configuration is unavailable.
445
446 **/
447 RETURN_STATUS
448 EFIAPI
449 QemuFwCfgFindFile (
450 IN CONST CHAR8 *Name,
451 OUT FIRMWARE_CONFIG_ITEM *Item,
452 OUT UINTN *Size
453 )
454 {
455 UINT32 Count;
456 UINT32 Idx;
457
458 if (!QemuFwCfgIsAvailable ()) {
459 return RETURN_UNSUPPORTED;
460 }
461
462 QemuFwCfgSelectItem (QemuFwCfgItemFileDir);
463 Count = SwapBytes32 (QemuFwCfgRead32 ());
464
465 for (Idx = 0; Idx < Count; ++Idx) {
466 UINT32 FileSize;
467 UINT16 FileSelect;
468 CHAR8 FName[QEMU_FW_CFG_FNAME_SIZE];
469
470 FileSize = QemuFwCfgRead32 ();
471 FileSelect = QemuFwCfgRead16 ();
472 QemuFwCfgRead16 (); // skip the field called "reserved"
473 InternalQemuFwCfgReadBytes (sizeof (FName), FName);
474
475 if (AsciiStrCmp (Name, FName) == 0) {
476 *Item = (FIRMWARE_CONFIG_ITEM) SwapBytes16 (FileSelect);
477 *Size = SwapBytes32 (FileSize);
478 return RETURN_SUCCESS;
479 }
480 }
481
482 return RETURN_NOT_FOUND;
483 }
484
485
486 /**
487 Determine if S3 support is explicitly enabled.
488
489 @retval TRUE if S3 support is explicitly enabled.
490 FALSE otherwise. This includes unavailability of the firmware
491 configuration interface.
492 **/
493 BOOLEAN
494 EFIAPI
495 QemuFwCfgS3Enabled (
496 VOID
497 )
498 {
499 return FALSE;
500 }