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