]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibMmio.c
OvmfPkg: Apply uncrustify changes
[mirror_edk2.git] / OvmfPkg / Library / QemuFwCfgLib / QemuFwCfgLibMmio.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 (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
8
9 SPDX-License-Identifier: BSD-2-Clause-Patent
10 **/
11
12 #include <Uefi.h>
13
14 #include <Library/BaseLib.h>
15 #include <Library/BaseMemoryLib.h>
16 #include <Library/DebugLib.h>
17 #include <Library/IoLib.h>
18 #include <Library/QemuFwCfgLib.h>
19 #include <Library/UefiBootServicesTableLib.h>
20
21 #include <Protocol/FdtClient.h>
22
23 STATIC UINTN mFwCfgSelectorAddress;
24 STATIC UINTN mFwCfgDataAddress;
25 STATIC UINTN mFwCfgDmaAddress;
26
27 /**
28 Reads firmware configuration bytes into a buffer
29
30 @param[in] Size Size in bytes to read
31 @param[in] Buffer Buffer to store data into (OPTIONAL if Size is 0)
32
33 **/
34 typedef
35 VOID(EFIAPI READ_BYTES_FUNCTION)(
36 IN UINTN Size,
37 IN VOID *Buffer OPTIONAL
38 );
39
40 /**
41 Writes bytes from a buffer to firmware configuration
42
43 @param[in] Size Size in bytes to write
44 @param[in] Buffer Buffer to transfer data from (OPTIONAL if Size is 0)
45
46 **/
47 typedef
48 VOID(EFIAPI WRITE_BYTES_FUNCTION)(
49 IN UINTN Size,
50 IN VOID *Buffer OPTIONAL
51 );
52
53 /**
54 Skips bytes in firmware configuration
55
56 @param[in] Size Size in bytes to skip
57
58 **/
59 typedef
60 VOID(EFIAPI SKIP_BYTES_FUNCTION)(
61 IN UINTN Size
62 );
63
64 //
65 // Forward declaration of the two implementations we have.
66 //
67 STATIC READ_BYTES_FUNCTION MmioReadBytes;
68 STATIC WRITE_BYTES_FUNCTION MmioWriteBytes;
69 STATIC SKIP_BYTES_FUNCTION MmioSkipBytes;
70 STATIC READ_BYTES_FUNCTION DmaReadBytes;
71 STATIC WRITE_BYTES_FUNCTION DmaWriteBytes;
72 STATIC SKIP_BYTES_FUNCTION DmaSkipBytes;
73
74 //
75 // These correspond to the implementation we detect at runtime.
76 //
77 STATIC READ_BYTES_FUNCTION *InternalQemuFwCfgReadBytes = MmioReadBytes;
78 STATIC WRITE_BYTES_FUNCTION *InternalQemuFwCfgWriteBytes = MmioWriteBytes;
79 STATIC SKIP_BYTES_FUNCTION *InternalQemuFwCfgSkipBytes = MmioSkipBytes;
80
81 /**
82 Returns a boolean indicating if the firmware configuration interface
83 is available or not.
84
85 This function may change fw_cfg state.
86
87 @retval TRUE The interface is available
88 @retval FALSE The interface is not available
89
90 **/
91 BOOLEAN
92 EFIAPI
93 QemuFwCfgIsAvailable (
94 VOID
95 )
96 {
97 return (BOOLEAN)(mFwCfgSelectorAddress != 0 && mFwCfgDataAddress != 0);
98 }
99
100 RETURN_STATUS
101 EFIAPI
102 QemuFwCfgInitialize (
103 VOID
104 )
105 {
106 EFI_STATUS Status;
107 FDT_CLIENT_PROTOCOL *FdtClient;
108 CONST UINT64 *Reg;
109 UINT32 RegSize;
110 UINTN AddressCells, SizeCells;
111 UINT64 FwCfgSelectorAddress;
112 UINT64 FwCfgSelectorSize;
113 UINT64 FwCfgDataAddress;
114 UINT64 FwCfgDataSize;
115 UINT64 FwCfgDmaAddress;
116 UINT64 FwCfgDmaSize;
117
118 Status = gBS->LocateProtocol (
119 &gFdtClientProtocolGuid,
120 NULL,
121 (VOID **)&FdtClient
122 );
123 ASSERT_EFI_ERROR (Status);
124
125 Status = FdtClient->FindCompatibleNodeReg (
126 FdtClient,
127 "qemu,fw-cfg-mmio",
128 (CONST VOID **)&Reg,
129 &AddressCells,
130 &SizeCells,
131 &RegSize
132 );
133 if (EFI_ERROR (Status)) {
134 DEBUG ((
135 DEBUG_WARN,
136 "%a: No 'qemu,fw-cfg-mmio' compatible DT node found (Status == %r)\n",
137 __FUNCTION__,
138 Status
139 ));
140 return EFI_SUCCESS;
141 }
142
143 ASSERT (AddressCells == 2);
144 ASSERT (SizeCells == 2);
145 ASSERT (RegSize == 2 * sizeof (UINT64));
146
147 FwCfgDataAddress = SwapBytes64 (Reg[0]);
148 FwCfgDataSize = 8;
149 FwCfgSelectorAddress = FwCfgDataAddress + FwCfgDataSize;
150 FwCfgSelectorSize = 2;
151
152 //
153 // The following ASSERT()s express
154 //
155 // Address + Size - 1 <= MAX_UINTN
156 //
157 // for both registers, that is, that the last byte in each MMIO range is
158 // expressible as a MAX_UINTN. The form below is mathematically
159 // equivalent, and it also prevents any unsigned overflow before the
160 // comparison.
161 //
162 ASSERT (FwCfgSelectorAddress <= MAX_UINTN - FwCfgSelectorSize + 1);
163 ASSERT (FwCfgDataAddress <= MAX_UINTN - FwCfgDataSize + 1);
164
165 mFwCfgSelectorAddress = FwCfgSelectorAddress;
166 mFwCfgDataAddress = FwCfgDataAddress;
167
168 DEBUG ((
169 DEBUG_INFO,
170 "Found FwCfg @ 0x%Lx/0x%Lx\n",
171 FwCfgSelectorAddress,
172 FwCfgDataAddress
173 ));
174
175 if (SwapBytes64 (Reg[1]) >= 0x18) {
176 FwCfgDmaAddress = FwCfgDataAddress + 0x10;
177 FwCfgDmaSize = 0x08;
178
179 //
180 // See explanation above.
181 //
182 ASSERT (FwCfgDmaAddress <= MAX_UINTN - FwCfgDmaSize + 1);
183
184 DEBUG ((DEBUG_INFO, "Found FwCfg DMA @ 0x%Lx\n", FwCfgDmaAddress));
185 } else {
186 FwCfgDmaAddress = 0;
187 }
188
189 if (QemuFwCfgIsAvailable ()) {
190 UINT32 Signature;
191
192 QemuFwCfgSelectItem (QemuFwCfgItemSignature);
193 Signature = QemuFwCfgRead32 ();
194 if (Signature == SIGNATURE_32 ('Q', 'E', 'M', 'U')) {
195 //
196 // For DMA support, we require the DTB to advertise the register, and the
197 // feature bitmap (which we read without DMA) to confirm the feature.
198 //
199 if (FwCfgDmaAddress != 0) {
200 UINT32 Features;
201
202 QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion);
203 Features = QemuFwCfgRead32 ();
204 if ((Features & FW_CFG_F_DMA) != 0) {
205 mFwCfgDmaAddress = FwCfgDmaAddress;
206 InternalQemuFwCfgReadBytes = DmaReadBytes;
207 InternalQemuFwCfgWriteBytes = DmaWriteBytes;
208 InternalQemuFwCfgSkipBytes = DmaSkipBytes;
209 }
210 }
211 } else {
212 mFwCfgSelectorAddress = 0;
213 mFwCfgDataAddress = 0;
214 }
215 }
216
217 return RETURN_SUCCESS;
218 }
219
220 /**
221 Selects a firmware configuration item for reading.
222
223 Following this call, any data read from this item will start from the
224 beginning of the configuration item's data.
225
226 @param[in] QemuFwCfgItem Firmware Configuration item to read
227
228 **/
229 VOID
230 EFIAPI
231 QemuFwCfgSelectItem (
232 IN FIRMWARE_CONFIG_ITEM QemuFwCfgItem
233 )
234 {
235 if (QemuFwCfgIsAvailable ()) {
236 MmioWrite16 (mFwCfgSelectorAddress, SwapBytes16 ((UINT16)QemuFwCfgItem));
237 }
238 }
239
240 /**
241 Slow READ_BYTES_FUNCTION.
242 **/
243 STATIC
244 VOID
245 EFIAPI
246 MmioReadBytes (
247 IN UINTN Size,
248 IN VOID *Buffer OPTIONAL
249 )
250 {
251 UINTN Left;
252 UINT8 *Ptr;
253 UINT8 *End;
254
255 #if defined (MDE_CPU_AARCH64) || defined (MDE_CPU_RISCV64)
256 Left = Size & 7;
257 #else
258 Left = Size & 3;
259 #endif
260
261 Size -= Left;
262 Ptr = Buffer;
263 End = Ptr + Size;
264
265 #if defined (MDE_CPU_AARCH64) || defined (MDE_CPU_RISCV64)
266 while (Ptr < End) {
267 *(UINT64 *)Ptr = MmioRead64 (mFwCfgDataAddress);
268 Ptr += 8;
269 }
270
271 if (Left & 4) {
272 *(UINT32 *)Ptr = MmioRead32 (mFwCfgDataAddress);
273 Ptr += 4;
274 }
275
276 #else
277 while (Ptr < End) {
278 *(UINT32 *)Ptr = MmioRead32 (mFwCfgDataAddress);
279 Ptr += 4;
280 }
281
282 #endif
283
284 if (Left & 2) {
285 *(UINT16 *)Ptr = MmioRead16 (mFwCfgDataAddress);
286 Ptr += 2;
287 }
288
289 if (Left & 1) {
290 *Ptr = MmioRead8 (mFwCfgDataAddress);
291 }
292 }
293
294 /**
295 Transfer an array of bytes, or skip a number of bytes, using the DMA
296 interface.
297
298 @param[in] Size Size in bytes to transfer or skip.
299
300 @param[in,out] Buffer Buffer to read data into or write data from. Ignored,
301 and may be NULL, if Size is zero, or Control is
302 FW_CFG_DMA_CTL_SKIP.
303
304 @param[in] Control One of the following:
305 FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer.
306 FW_CFG_DMA_CTL_READ - read from fw_cfg into Buffer.
307 FW_CFG_DMA_CTL_SKIP - skip bytes in fw_cfg.
308 **/
309 STATIC
310 VOID
311 DmaTransferBytes (
312 IN UINTN Size,
313 IN OUT VOID *Buffer OPTIONAL,
314 IN UINT32 Control
315 )
316 {
317 volatile FW_CFG_DMA_ACCESS Access;
318 UINT32 Status;
319
320 ASSERT (
321 Control == FW_CFG_DMA_CTL_WRITE || Control == FW_CFG_DMA_CTL_READ ||
322 Control == FW_CFG_DMA_CTL_SKIP
323 );
324
325 if (Size == 0) {
326 return;
327 }
328
329 ASSERT (Size <= MAX_UINT32);
330
331 Access.Control = SwapBytes32 (Control);
332 Access.Length = SwapBytes32 ((UINT32)Size);
333 Access.Address = SwapBytes64 ((UINT64)(UINTN)Buffer);
334
335 //
336 // We shouldn't start the transfer before setting up Access.
337 //
338 MemoryFence ();
339
340 //
341 // This will fire off the transfer.
342 //
343 #if defined (MDE_CPU_AARCH64) || defined (MDE_CPU_RISCV64)
344 MmioWrite64 (mFwCfgDmaAddress, SwapBytes64 ((UINT64)&Access));
345 #else
346 MmioWrite32 ((UINT32)(mFwCfgDmaAddress + 4), SwapBytes32 ((UINT32)&Access));
347 #endif
348
349 //
350 // We shouldn't look at Access.Control before starting the transfer.
351 //
352 MemoryFence ();
353
354 do {
355 Status = SwapBytes32 (Access.Control);
356 ASSERT ((Status & FW_CFG_DMA_CTL_ERROR) == 0);
357 } while (Status != 0);
358
359 //
360 // The caller will want to access the transferred data.
361 //
362 MemoryFence ();
363 }
364
365 /**
366 Fast READ_BYTES_FUNCTION.
367 **/
368 STATIC
369 VOID
370 EFIAPI
371 DmaReadBytes (
372 IN UINTN Size,
373 IN VOID *Buffer OPTIONAL
374 )
375 {
376 DmaTransferBytes (Size, Buffer, FW_CFG_DMA_CTL_READ);
377 }
378
379 /**
380 Reads firmware configuration bytes into a buffer
381
382 If called multiple times, then the data read will continue at the offset of
383 the firmware configuration item where the previous read ended.
384
385 @param[in] Size Size in bytes to read
386 @param[in] Buffer Buffer to store data into
387
388 **/
389 VOID
390 EFIAPI
391 QemuFwCfgReadBytes (
392 IN UINTN Size,
393 IN VOID *Buffer
394 )
395 {
396 if (QemuFwCfgIsAvailable ()) {
397 InternalQemuFwCfgReadBytes (Size, Buffer);
398 } else {
399 ZeroMem (Buffer, Size);
400 }
401 }
402
403 /**
404 Slow WRITE_BYTES_FUNCTION.
405 **/
406 STATIC
407 VOID
408 EFIAPI
409 MmioWriteBytes (
410 IN UINTN Size,
411 IN VOID *Buffer OPTIONAL
412 )
413 {
414 UINTN Idx;
415
416 for (Idx = 0; Idx < Size; ++Idx) {
417 MmioWrite8 (mFwCfgDataAddress, ((UINT8 *)Buffer)[Idx]);
418 }
419 }
420
421 /**
422 Fast WRITE_BYTES_FUNCTION.
423 **/
424 STATIC
425 VOID
426 EFIAPI
427 DmaWriteBytes (
428 IN UINTN Size,
429 IN VOID *Buffer OPTIONAL
430 )
431 {
432 DmaTransferBytes (Size, Buffer, FW_CFG_DMA_CTL_WRITE);
433 }
434
435 /**
436 Write firmware configuration bytes from a buffer
437
438 If called multiple times, then the data written will continue at the offset
439 of the firmware configuration item where the previous write ended.
440
441 @param[in] Size Size in bytes to write
442 @param[in] Buffer Buffer to read data from
443
444 **/
445 VOID
446 EFIAPI
447 QemuFwCfgWriteBytes (
448 IN UINTN Size,
449 IN VOID *Buffer
450 )
451 {
452 if (QemuFwCfgIsAvailable ()) {
453 InternalQemuFwCfgWriteBytes (Size, Buffer);
454 }
455 }
456
457 /**
458 Slow SKIP_BYTES_FUNCTION.
459 **/
460 STATIC
461 VOID
462 EFIAPI
463 MmioSkipBytes (
464 IN UINTN Size
465 )
466 {
467 UINTN ChunkSize;
468 UINT8 SkipBuffer[256];
469
470 //
471 // Emulate the skip by reading data in chunks, and throwing it away. The
472 // implementation below doesn't affect the static data footprint for client
473 // modules. Large skips are not expected, therefore this fallback is not
474 // performance critical. The size of SkipBuffer is thought not to exert a
475 // large pressure on the stack.
476 //
477 while (Size > 0) {
478 ChunkSize = MIN (Size, sizeof SkipBuffer);
479 MmioReadBytes (ChunkSize, SkipBuffer);
480 Size -= ChunkSize;
481 }
482 }
483
484 /**
485 Fast SKIP_BYTES_FUNCTION.
486 **/
487 STATIC
488 VOID
489 EFIAPI
490 DmaSkipBytes (
491 IN UINTN Size
492 )
493 {
494 DmaTransferBytes (Size, NULL, FW_CFG_DMA_CTL_SKIP);
495 }
496
497 /**
498 Skip bytes in the firmware configuration item.
499
500 Increase the offset of the firmware configuration item without transferring
501 bytes between the item and a caller-provided buffer. Subsequent read, write
502 or skip operations will commence at the increased offset.
503
504 @param[in] Size Number of bytes to skip.
505 **/
506 VOID
507 EFIAPI
508 QemuFwCfgSkipBytes (
509 IN UINTN Size
510 )
511 {
512 if (QemuFwCfgIsAvailable ()) {
513 InternalQemuFwCfgSkipBytes (Size);
514 }
515 }
516
517 /**
518 Reads a UINT8 firmware configuration value
519
520 @return Value of Firmware Configuration item read
521
522 **/
523 UINT8
524 EFIAPI
525 QemuFwCfgRead8 (
526 VOID
527 )
528 {
529 UINT8 Result;
530
531 QemuFwCfgReadBytes (sizeof Result, &Result);
532 return Result;
533 }
534
535 /**
536 Reads a UINT16 firmware configuration value
537
538 @return Value of Firmware Configuration item read
539
540 **/
541 UINT16
542 EFIAPI
543 QemuFwCfgRead16 (
544 VOID
545 )
546 {
547 UINT16 Result;
548
549 QemuFwCfgReadBytes (sizeof Result, &Result);
550 return Result;
551 }
552
553 /**
554 Reads a UINT32 firmware configuration value
555
556 @return Value of Firmware Configuration item read
557
558 **/
559 UINT32
560 EFIAPI
561 QemuFwCfgRead32 (
562 VOID
563 )
564 {
565 UINT32 Result;
566
567 QemuFwCfgReadBytes (sizeof Result, &Result);
568 return Result;
569 }
570
571 /**
572 Reads a UINT64 firmware configuration value
573
574 @return Value of Firmware Configuration item read
575
576 **/
577 UINT64
578 EFIAPI
579 QemuFwCfgRead64 (
580 VOID
581 )
582 {
583 UINT64 Result;
584
585 QemuFwCfgReadBytes (sizeof Result, &Result);
586 return Result;
587 }
588
589 /**
590 Find the configuration item corresponding to the firmware configuration file.
591
592 @param[in] Name Name of file to look up.
593 @param[out] Item Configuration item corresponding to the file, to be passed
594 to QemuFwCfgSelectItem ().
595 @param[out] Size Number of bytes in the file.
596
597 @retval RETURN_SUCCESS If file is found.
598 @retval RETURN_NOT_FOUND If file is not found.
599 @retval RETURN_UNSUPPORTED If firmware configuration is unavailable.
600
601 **/
602 RETURN_STATUS
603 EFIAPI
604 QemuFwCfgFindFile (
605 IN CONST CHAR8 *Name,
606 OUT FIRMWARE_CONFIG_ITEM *Item,
607 OUT UINTN *Size
608 )
609 {
610 UINT32 Count;
611 UINT32 Idx;
612
613 if (!QemuFwCfgIsAvailable ()) {
614 return RETURN_UNSUPPORTED;
615 }
616
617 QemuFwCfgSelectItem (QemuFwCfgItemFileDir);
618 Count = SwapBytes32 (QemuFwCfgRead32 ());
619
620 for (Idx = 0; Idx < Count; ++Idx) {
621 UINT32 FileSize;
622 UINT16 FileSelect;
623 CHAR8 FName[QEMU_FW_CFG_FNAME_SIZE];
624
625 FileSize = QemuFwCfgRead32 ();
626 FileSelect = QemuFwCfgRead16 ();
627 QemuFwCfgRead16 (); // skip the field called "reserved"
628 InternalQemuFwCfgReadBytes (sizeof (FName), FName);
629
630 if (AsciiStrCmp (Name, FName) == 0) {
631 *Item = (FIRMWARE_CONFIG_ITEM)SwapBytes16 (FileSelect);
632 *Size = SwapBytes32 (FileSize);
633 return RETURN_SUCCESS;
634 }
635 }
636
637 return RETURN_NOT_FOUND;
638 }