• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <Library/BaseLib.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/DebugLib.h>
20 #include <Library/IoLib.h>
21 #include <Library/PcdLib.h>
22 #include <Library/QemuFwCfgLib.h>
23 
24 STATIC UINTN mFwCfgSelectorAddress;
25 STATIC UINTN mFwCfgDataAddress;
26 STATIC UINTN mFwCfgDmaAddress;
27 
28 /**
29   Reads firmware configuration bytes into a buffer
30 
31   @param[in] Size    Size in bytes to read
32   @param[in] Buffer  Buffer to store data into  (OPTIONAL if Size is 0)
33 
34 **/
35 typedef
36 VOID (EFIAPI READ_BYTES_FUNCTION) (
37   IN UINTN Size,
38   IN VOID  *Buffer OPTIONAL
39   );
40 
41 //
42 // Forward declaration of the two implementations we have.
43 //
44 STATIC READ_BYTES_FUNCTION MmioReadBytes;
45 STATIC READ_BYTES_FUNCTION DmaReadBytes;
46 
47 //
48 // This points to the one we detect at runtime.
49 //
50 STATIC READ_BYTES_FUNCTION *InternalQemuFwCfgReadBytes = MmioReadBytes;
51 
52 //
53 // Communication structure for DmaReadBytes(). All fields are encoded in big
54 // endian.
55 //
56 #pragma pack (1)
57 typedef struct {
58   UINT32 Control;
59   UINT32 Length;
60   UINT64 Address;
61 } FW_CFG_DMA_ACCESS;
62 #pragma pack ()
63 
64 //
65 // Macros for the FW_CFG_DMA_ACCESS.Control bitmap (in native encoding).
66 //
67 #define FW_CFG_DMA_CTL_ERROR  BIT0
68 #define FW_CFG_DMA_CTL_READ   BIT1
69 #define FW_CFG_DMA_CTL_SKIP   BIT2
70 #define FW_CFG_DMA_CTL_SELECT BIT3
71 
72 
73 /**
74   Returns a boolean indicating if the firmware configuration interface is
75   available for library-internal purposes.
76 
77   This function never changes fw_cfg state.
78 
79   @retval TRUE   The interface is available internally.
80   @retval FALSE  The interface is not available internally.
81 **/
82 BOOLEAN
83 EFIAPI
InternalQemuFwCfgIsAvailable(VOID)84 InternalQemuFwCfgIsAvailable (
85   VOID
86   )
87 {
88   return (BOOLEAN)(mFwCfgSelectorAddress != 0 && mFwCfgDataAddress != 0);
89 }
90 
91 
92 /**
93   Returns a boolean indicating if the firmware configuration interface
94   is available or not.
95 
96   This function may change fw_cfg state.
97 
98   @retval TRUE   The interface is available
99   @retval FALSE  The interface is not available
100 
101 **/
102 BOOLEAN
103 EFIAPI
QemuFwCfgIsAvailable(VOID)104 QemuFwCfgIsAvailable (
105   VOID
106   )
107 {
108   return InternalQemuFwCfgIsAvailable ();
109 }
110 
111 
112 RETURN_STATUS
113 EFIAPI
QemuFwCfgInitialize(VOID)114 QemuFwCfgInitialize (
115   VOID
116   )
117 {
118   mFwCfgSelectorAddress = (UINTN)PcdGet64 (PcdFwCfgSelectorAddress);
119   mFwCfgDataAddress     = (UINTN)PcdGet64 (PcdFwCfgDataAddress);
120 
121   if (InternalQemuFwCfgIsAvailable ()) {
122     UINT32 Signature;
123 
124     QemuFwCfgSelectItem (QemuFwCfgItemSignature);
125     Signature = QemuFwCfgRead32 ();
126     if (Signature == SIGNATURE_32 ('Q', 'E', 'M', 'U')) {
127       //
128       // For DMA support, we require the DTB to advertise the register, and the
129       // feature bitmap (which we read without DMA) to confirm the feature.
130       //
131       if (PcdGet64 (PcdFwCfgDmaAddress) != 0) {
132         UINT32 Features;
133 
134         QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion);
135         Features = QemuFwCfgRead32 ();
136         if ((Features & BIT1) != 0) {
137           mFwCfgDmaAddress = PcdGet64 (PcdFwCfgDmaAddress);
138           InternalQemuFwCfgReadBytes = DmaReadBytes;
139         }
140       }
141     } else {
142       mFwCfgSelectorAddress = 0;
143       mFwCfgDataAddress     = 0;
144     }
145   }
146   return RETURN_SUCCESS;
147 }
148 
149 
150 /**
151   Selects a firmware configuration item for reading.
152 
153   Following this call, any data read from this item will start from the
154   beginning of the configuration item's data.
155 
156   @param[in] QemuFwCfgItem  Firmware Configuration item to read
157 
158 **/
159 VOID
160 EFIAPI
QemuFwCfgSelectItem(IN FIRMWARE_CONFIG_ITEM QemuFwCfgItem)161 QemuFwCfgSelectItem (
162   IN FIRMWARE_CONFIG_ITEM QemuFwCfgItem
163   )
164 {
165   if (InternalQemuFwCfgIsAvailable ()) {
166     MmioWrite16 (mFwCfgSelectorAddress, SwapBytes16 ((UINT16)QemuFwCfgItem));
167   }
168 }
169 
170 
171 /**
172   Slow READ_BYTES_FUNCTION.
173 **/
174 STATIC
175 VOID
176 EFIAPI
MmioReadBytes(IN UINTN Size,IN VOID * Buffer OPTIONAL)177 MmioReadBytes (
178   IN UINTN Size,
179   IN VOID  *Buffer OPTIONAL
180   )
181 {
182   UINTN Left;
183   UINT8 *Ptr;
184   UINT8 *End;
185 
186 #ifdef MDE_CPU_AARCH64
187   Left = Size & 7;
188 #else
189   Left = Size & 3;
190 #endif
191 
192   Size -= Left;
193   Ptr = Buffer;
194   End = Ptr + Size;
195 
196 #ifdef MDE_CPU_AARCH64
197   while (Ptr < End) {
198     *(UINT64 *)Ptr = MmioRead64 (mFwCfgDataAddress);
199     Ptr += 8;
200   }
201   if (Left & 4) {
202     *(UINT32 *)Ptr = MmioRead32 (mFwCfgDataAddress);
203     Ptr += 4;
204   }
205 #else
206   while (Ptr < End) {
207     *(UINT32 *)Ptr = MmioRead32 (mFwCfgDataAddress);
208     Ptr += 4;
209   }
210 #endif
211 
212   if (Left & 2) {
213     *(UINT16 *)Ptr = MmioRead16 (mFwCfgDataAddress);
214     Ptr += 2;
215   }
216   if (Left & 1) {
217     *Ptr = MmioRead8 (mFwCfgDataAddress);
218   }
219 }
220 
221 
222 /**
223   Fast READ_BYTES_FUNCTION.
224 **/
225 STATIC
226 VOID
227 EFIAPI
DmaReadBytes(IN UINTN Size,IN VOID * Buffer OPTIONAL)228 DmaReadBytes (
229   IN UINTN Size,
230   IN VOID  *Buffer OPTIONAL
231   )
232 {
233   volatile FW_CFG_DMA_ACCESS Access;
234   UINT32                     Status;
235 
236   if (Size == 0) {
237     return;
238   }
239 
240   ASSERT (Size <= MAX_UINT32);
241 
242   Access.Control = SwapBytes32 (FW_CFG_DMA_CTL_READ);
243   Access.Length  = SwapBytes32 ((UINT32)Size);
244   Access.Address = SwapBytes64 ((UINT64)(UINTN)Buffer);
245 
246   //
247   // We shouldn't start the transfer before setting up Access.
248   //
249   MemoryFence ();
250 
251   //
252   // This will fire off the transfer.
253   //
254 #ifdef MDE_CPU_AARCH64
255   MmioWrite64 (mFwCfgDmaAddress, SwapBytes64 ((UINT64)&Access));
256 #else
257   MmioWrite32 ((UINT32)(mFwCfgDmaAddress + 4), SwapBytes32 ((UINT32)&Access));
258 #endif
259 
260   //
261   // We shouldn't look at Access.Control before starting the transfer.
262   //
263   MemoryFence ();
264 
265   do {
266     Status = SwapBytes32 (Access.Control);
267     ASSERT ((Status & FW_CFG_DMA_CTL_ERROR) == 0);
268   } while (Status != 0);
269 
270   //
271   // The caller will want to access the transferred data.
272   //
273   MemoryFence ();
274 }
275 
276 
277 /**
278   Reads firmware configuration bytes into a buffer
279 
280   If called multiple times, then the data read will continue at the offset of
281   the firmware configuration item where the previous read ended.
282 
283   @param[in] Size    Size in bytes to read
284   @param[in] Buffer  Buffer to store data into
285 
286 **/
287 VOID
288 EFIAPI
QemuFwCfgReadBytes(IN UINTN Size,IN VOID * Buffer)289 QemuFwCfgReadBytes (
290   IN UINTN Size,
291   IN VOID  *Buffer
292   )
293 {
294   if (InternalQemuFwCfgIsAvailable ()) {
295     InternalQemuFwCfgReadBytes (Size, Buffer);
296   } else {
297     ZeroMem (Buffer, Size);
298   }
299 }
300 
301 /**
302   Write firmware configuration bytes from a buffer
303 
304   If called multiple times, then the data written will continue at the offset
305   of the firmware configuration item where the previous write ended.
306 
307   @param[in] Size    Size in bytes to write
308   @param[in] Buffer  Buffer to read data from
309 
310 **/
311 VOID
312 EFIAPI
QemuFwCfgWriteBytes(IN UINTN Size,IN VOID * Buffer)313 QemuFwCfgWriteBytes (
314   IN UINTN                  Size,
315   IN VOID                   *Buffer
316   )
317 {
318   if (InternalQemuFwCfgIsAvailable ()) {
319     UINTN Idx;
320 
321     for (Idx = 0; Idx < Size; ++Idx) {
322       MmioWrite8 (mFwCfgDataAddress, ((UINT8 *)Buffer)[Idx]);
323     }
324   }
325 }
326 
327 
328 /**
329   Reads a UINT8 firmware configuration value
330 
331   @return  Value of Firmware Configuration item read
332 
333 **/
334 UINT8
335 EFIAPI
QemuFwCfgRead8(VOID)336 QemuFwCfgRead8 (
337   VOID
338   )
339 {
340   UINT8 Result;
341 
342   QemuFwCfgReadBytes (sizeof Result, &Result);
343   return Result;
344 }
345 
346 
347 /**
348   Reads a UINT16 firmware configuration value
349 
350   @return  Value of Firmware Configuration item read
351 
352 **/
353 UINT16
354 EFIAPI
QemuFwCfgRead16(VOID)355 QemuFwCfgRead16 (
356   VOID
357   )
358 {
359   UINT16 Result;
360 
361   QemuFwCfgReadBytes (sizeof Result, &Result);
362   return Result;
363 }
364 
365 
366 /**
367   Reads a UINT32 firmware configuration value
368 
369   @return  Value of Firmware Configuration item read
370 
371 **/
372 UINT32
373 EFIAPI
QemuFwCfgRead32(VOID)374 QemuFwCfgRead32 (
375   VOID
376   )
377 {
378   UINT32 Result;
379 
380   QemuFwCfgReadBytes (sizeof Result, &Result);
381   return Result;
382 }
383 
384 
385 /**
386   Reads a UINT64 firmware configuration value
387 
388   @return  Value of Firmware Configuration item read
389 
390 **/
391 UINT64
392 EFIAPI
QemuFwCfgRead64(VOID)393 QemuFwCfgRead64 (
394   VOID
395   )
396 {
397   UINT64 Result;
398 
399   QemuFwCfgReadBytes (sizeof Result, &Result);
400   return Result;
401 }
402 
403 
404 /**
405   Find the configuration item corresponding to the firmware configuration file.
406 
407   @param[in]  Name  Name of file to look up.
408   @param[out] Item  Configuration item corresponding to the file, to be passed
409                     to QemuFwCfgSelectItem ().
410   @param[out] Size  Number of bytes in the file.
411 
412   @retval RETURN_SUCCESS      If file is found.
413   @retval RETURN_NOT_FOUND    If file is not found.
414   @retval RETURN_UNSUPPORTED  If firmware configuration is unavailable.
415 
416 **/
417 RETURN_STATUS
418 EFIAPI
QemuFwCfgFindFile(IN CONST CHAR8 * Name,OUT FIRMWARE_CONFIG_ITEM * Item,OUT UINTN * Size)419 QemuFwCfgFindFile (
420   IN   CONST CHAR8           *Name,
421   OUT  FIRMWARE_CONFIG_ITEM  *Item,
422   OUT  UINTN                 *Size
423   )
424 {
425   UINT32 Count;
426   UINT32 Idx;
427 
428   if (!InternalQemuFwCfgIsAvailable ()) {
429     return RETURN_UNSUPPORTED;
430   }
431 
432   QemuFwCfgSelectItem (QemuFwCfgItemFileDir);
433   Count = SwapBytes32 (QemuFwCfgRead32 ());
434 
435   for (Idx = 0; Idx < Count; ++Idx) {
436     UINT32 FileSize;
437     UINT16 FileSelect;
438     CHAR8  FName[QEMU_FW_CFG_FNAME_SIZE];
439 
440     FileSize   = QemuFwCfgRead32 ();
441     FileSelect = QemuFwCfgRead16 ();
442     QemuFwCfgRead16 (); // skip the field called "reserved"
443     InternalQemuFwCfgReadBytes (sizeof (FName), FName);
444 
445     if (AsciiStrCmp (Name, FName) == 0) {
446       *Item = (FIRMWARE_CONFIG_ITEM) SwapBytes16 (FileSelect);
447       *Size = SwapBytes32 (FileSize);
448       return RETURN_SUCCESS;
449     }
450   }
451 
452   return RETURN_NOT_FOUND;
453 }
454 
455 
456 /**
457   Determine if S3 support is explicitly enabled.
458 
459   @retval TRUE   if S3 support is explicitly enabled.
460           FALSE  otherwise. This includes unavailability of the firmware
461                  configuration interface.
462 **/
463 BOOLEAN
464 EFIAPI
QemuFwCfgS3Enabled(VOID)465 QemuFwCfgS3Enabled (
466   VOID
467   )
468 {
469   return FALSE;
470 }
471