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
24STATIC UINTN mFwCfgSelectorAddress;
25STATIC UINTN mFwCfgDataAddress;
26STATIC 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**/
35typedef
36VOID (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//
44STATIC READ_BYTES_FUNCTION MmioReadBytes;
45STATIC READ_BYTES_FUNCTION DmaReadBytes;
46
47//
48// This points to the one we detect at runtime.
49//
50STATIC 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)
57typedef 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**/
82BOOLEAN
83EFIAPI
84InternalQemuFwCfgIsAvailable (
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**/
102BOOLEAN
103EFIAPI
104QemuFwCfgIsAvailable (
105  VOID
106  )
107{
108  return InternalQemuFwCfgIsAvailable ();
109}
110
111
112RETURN_STATUS
113EFIAPI
114QemuFwCfgInitialize (
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**/
159VOID
160EFIAPI
161QemuFwCfgSelectItem (
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**/
174STATIC
175VOID
176EFIAPI
177MmioReadBytes (
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**/
225STATIC
226VOID
227EFIAPI
228DmaReadBytes (
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**/
287VOID
288EFIAPI
289QemuFwCfgReadBytes (
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**/
311VOID
312EFIAPI
313QemuFwCfgWriteBytes (
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**/
334UINT8
335EFIAPI
336QemuFwCfgRead8 (
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**/
353UINT16
354EFIAPI
355QemuFwCfgRead16 (
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**/
372UINT32
373EFIAPI
374QemuFwCfgRead32 (
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**/
391UINT64
392EFIAPI
393QemuFwCfgRead64 (
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**/
417RETURN_STATUS
418EFIAPI
419QemuFwCfgFindFile (
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**/
463BOOLEAN
464EFIAPI
465QemuFwCfgS3Enabled (
466  VOID
467  )
468{
469  return FALSE;
470}
471