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