• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2 
3   Copyright (c) 2011 - 2013, Intel Corporation. All rights reserved.<BR>
4   Copyright (C) 2013, Red Hat, Inc.
5 
6   This program and the accompanying materials
7   are licensed and made available under the terms and conditions of the BSD License
8   which accompanies this distribution.  The full text of the license may be found at
9   http://opensource.org/licenses/bsd-license.php
10 
11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include "Uefi.h"
17 #include <Library/BaseLib.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/DebugLib.h>
20 #include <Library/IoLib.h>
21 #include <Library/QemuFwCfgLib.h>
22 #include <Library/MemoryAllocationLib.h>
23 #include <Library/UefiBootServicesTableLib.h>
24 
25 #include "QemuFwCfgLibInternal.h"
26 
27 
28 /**
29   Reads an 8-bit I/O port fifo into a block of memory.
30 
31   Reads the 8-bit I/O fifo port specified by Port.
32 
33   The port is read Count times, and the read data is
34   stored in the provided Buffer.
35 
36   This function must guarantee that all I/O read and write operations are
37   serialized.
38 
39   If 8-bit I/O port operations are not supported, then ASSERT().
40 
41   @param  Port    The I/O port to read.
42   @param  Count   The number of times to read I/O port.
43   @param  Buffer  The buffer to store the read data into.
44 
45 **/
46 VOID
47 EFIAPI
48 IoReadFifo8 (
49   IN      UINTN                     Port,
50   IN      UINTN                     Count,
51   OUT     VOID                      *Buffer
52   );
53 
54 /**
55   Writes an 8-bit I/O port fifo from a block of memory.
56 
57   Writes the 8-bit I/O fifo port specified by Port.
58 
59   The port is written Count times, and the data are obtained
60   from the provided Buffer.
61 
62   This function must guarantee that all I/O read and write operations are
63   serialized.
64 
65   If 8-bit I/O port operations are not supported, then ASSERT().
66 
67   @param  Port    The I/O port to read.
68   @param  Count   The number of times to read I/O port.
69   @param  Buffer  The buffer to store the read data into.
70 
71 **/
72 VOID
73 EFIAPI
74 IoWriteFifo8 (
75   IN      UINTN                     Port,
76   IN      UINTN                     Count,
77   OUT     VOID                      *Buffer
78   );
79 
80 
81 /**
82   Selects a firmware configuration item for reading.
83 
84   Following this call, any data read from this item will start from
85   the beginning of the configuration item's data.
86 
87   @param[in] QemuFwCfgItem - Firmware Configuration item to read
88 
89 **/
90 VOID
91 EFIAPI
QemuFwCfgSelectItem(IN FIRMWARE_CONFIG_ITEM QemuFwCfgItem)92 QemuFwCfgSelectItem (
93   IN FIRMWARE_CONFIG_ITEM   QemuFwCfgItem
94   )
95 {
96   DEBUG ((EFI_D_INFO, "Select Item: 0x%x\n", (UINT16)(UINTN) QemuFwCfgItem));
97   IoWrite16 (0x510, (UINT16)(UINTN) QemuFwCfgItem);
98 }
99 
100 
101 /**
102   Transfer an array of bytes using the DMA interface.
103 
104   @param[in]     Size    Size in bytes to transfer.
105   @param[in,out] Buffer  Buffer to read data into or write data from. May be
106                          NULL if Size is zero.
107   @param[in]     Write   TRUE if writing to fw_cfg from Buffer, FALSE if
108                          reading from fw_cfg into Buffer.
109 **/
110 VOID
InternalQemuFwCfgDmaBytes(IN UINT32 Size,IN OUT VOID * Buffer OPTIONAL,IN BOOLEAN Write)111 InternalQemuFwCfgDmaBytes (
112   IN     UINT32   Size,
113   IN OUT VOID     *Buffer OPTIONAL,
114   IN     BOOLEAN  Write
115   )
116 {
117   volatile FW_CFG_DMA_ACCESS Access;
118   UINT32                     AccessHigh, AccessLow;
119   UINT32                     Status;
120 
121   if (Size == 0) {
122     return;
123   }
124 
125   Access.Control = SwapBytes32 (
126                     Write ? FW_CFG_DMA_CTL_WRITE : FW_CFG_DMA_CTL_READ
127                     );
128   Access.Length  = SwapBytes32 (Size);
129   Access.Address = SwapBytes64 ((UINTN)Buffer);
130 
131   //
132   // Delimit the transfer from (a) modifications to Access, (b) in case of a
133   // write, from writes to Buffer by the caller.
134   //
135   MemoryFence ();
136 
137   //
138   // Start the transfer.
139   //
140   AccessHigh = (UINT32)RShiftU64 ((UINTN)&Access, 32);
141   AccessLow  = (UINT32)(UINTN)&Access;
142   IoWrite32 (0x514, SwapBytes32 (AccessHigh));
143   IoWrite32 (0x518, SwapBytes32 (AccessLow));
144 
145   //
146   // Don't look at Access.Control before starting the transfer.
147   //
148   MemoryFence ();
149 
150   //
151   // Wait for the transfer to complete.
152   //
153   do {
154     Status = SwapBytes32 (Access.Control);
155     ASSERT ((Status & FW_CFG_DMA_CTL_ERROR) == 0);
156   } while (Status != 0);
157 
158   //
159   // After a read, the caller will want to use Buffer.
160   //
161   MemoryFence ();
162 }
163 
164 
165 /**
166   Reads firmware configuration bytes into a buffer
167 
168   @param[in] Size - Size in bytes to read
169   @param[in] Buffer - Buffer to store data into  (OPTIONAL if Size is 0)
170 
171 **/
172 VOID
173 EFIAPI
InternalQemuFwCfgReadBytes(IN UINTN Size,IN VOID * Buffer OPTIONAL)174 InternalQemuFwCfgReadBytes (
175   IN UINTN                  Size,
176   IN VOID                   *Buffer  OPTIONAL
177   )
178 {
179   if (InternalQemuFwCfgDmaIsAvailable () && Size <= MAX_UINT32) {
180     InternalQemuFwCfgDmaBytes ((UINT32)Size, Buffer, FALSE);
181     return;
182   }
183   IoReadFifo8 (0x511, Size, Buffer);
184 }
185 
186 
187 /**
188   Reads firmware configuration bytes into a buffer
189 
190   If called multiple times, then the data read will
191   continue at the offset of the firmware configuration
192   item where the previous read ended.
193 
194   @param[in] Size - Size in bytes to read
195   @param[in] Buffer - Buffer to store data into
196 
197 **/
198 VOID
199 EFIAPI
QemuFwCfgReadBytes(IN UINTN Size,IN VOID * Buffer)200 QemuFwCfgReadBytes (
201   IN UINTN                  Size,
202   IN VOID                   *Buffer
203   )
204 {
205   if (InternalQemuFwCfgIsAvailable ()) {
206     InternalQemuFwCfgReadBytes (Size, Buffer);
207   } else {
208     ZeroMem (Buffer, Size);
209   }
210 }
211 
212 /**
213   Write firmware configuration bytes from a buffer
214 
215   If called multiple times, then the data written will
216   continue at the offset of the firmware configuration
217   item where the previous write ended.
218 
219   @param[in] Size - Size in bytes to write
220   @param[in] Buffer - Buffer to read data from
221 
222 **/
223 VOID
224 EFIAPI
QemuFwCfgWriteBytes(IN UINTN Size,IN VOID * Buffer)225 QemuFwCfgWriteBytes (
226   IN UINTN                  Size,
227   IN VOID                   *Buffer
228   )
229 {
230   if (InternalQemuFwCfgIsAvailable ()) {
231     if (InternalQemuFwCfgDmaIsAvailable () && Size <= MAX_UINT32) {
232       InternalQemuFwCfgDmaBytes ((UINT32)Size, Buffer, TRUE);
233       return;
234     }
235     IoWriteFifo8 (0x511, Size, Buffer);
236   }
237 }
238 
239 
240 /**
241   Reads a UINT8 firmware configuration value
242 
243   @return    Value of Firmware Configuration item read
244 
245 **/
246 UINT8
247 EFIAPI
QemuFwCfgRead8(VOID)248 QemuFwCfgRead8 (
249   VOID
250   )
251 {
252   UINT8 Result;
253 
254   QemuFwCfgReadBytes (sizeof (Result), &Result);
255 
256   return Result;
257 }
258 
259 
260 /**
261   Reads a UINT16 firmware configuration value
262 
263   @return    Value of Firmware Configuration item read
264 
265 **/
266 UINT16
267 EFIAPI
QemuFwCfgRead16(VOID)268 QemuFwCfgRead16 (
269   VOID
270   )
271 {
272   UINT16 Result;
273 
274   QemuFwCfgReadBytes (sizeof (Result), &Result);
275 
276   return Result;
277 }
278 
279 
280 /**
281   Reads a UINT32 firmware configuration value
282 
283   @return    Value of Firmware Configuration item read
284 
285 **/
286 UINT32
287 EFIAPI
QemuFwCfgRead32(VOID)288 QemuFwCfgRead32 (
289   VOID
290   )
291 {
292   UINT32 Result;
293 
294   QemuFwCfgReadBytes (sizeof (Result), &Result);
295 
296   return Result;
297 }
298 
299 
300 /**
301   Reads a UINT64 firmware configuration value
302 
303   @return    Value of Firmware Configuration item read
304 
305 **/
306 UINT64
307 EFIAPI
QemuFwCfgRead64(VOID)308 QemuFwCfgRead64 (
309   VOID
310   )
311 {
312   UINT64 Result;
313 
314   QemuFwCfgReadBytes (sizeof (Result), &Result);
315 
316   return Result;
317 }
318 
319 
320 /**
321   Find the configuration item corresponding to the firmware configuration file.
322 
323   @param[in]  Name - Name of file to look up.
324   @param[out] Item - Configuration item corresponding to the file, to be passed
325                      to QemuFwCfgSelectItem ().
326   @param[out] Size - Number of bytes in the file.
327 
328   @return    RETURN_SUCCESS       If file is found.
329              RETURN_NOT_FOUND     If file is not found.
330              RETURN_UNSUPPORTED   If firmware configuration is unavailable.
331 
332 **/
333 RETURN_STATUS
334 EFIAPI
QemuFwCfgFindFile(IN CONST CHAR8 * Name,OUT FIRMWARE_CONFIG_ITEM * Item,OUT UINTN * Size)335 QemuFwCfgFindFile (
336   IN   CONST CHAR8           *Name,
337   OUT  FIRMWARE_CONFIG_ITEM  *Item,
338   OUT  UINTN                 *Size
339   )
340 {
341   UINT32 Count;
342   UINT32 Idx;
343 
344   if (!InternalQemuFwCfgIsAvailable ()) {
345     return RETURN_UNSUPPORTED;
346   }
347 
348   QemuFwCfgSelectItem (QemuFwCfgItemFileDir);
349   Count = SwapBytes32 (QemuFwCfgRead32 ());
350 
351   for (Idx = 0; Idx < Count; ++Idx) {
352     UINT32 FileSize;
353     UINT16 FileSelect;
354     UINT16 FileReserved;
355     CHAR8  FName[QEMU_FW_CFG_FNAME_SIZE];
356 
357     FileSize     = QemuFwCfgRead32 ();
358     FileSelect   = QemuFwCfgRead16 ();
359     FileReserved = QemuFwCfgRead16 ();
360     (VOID) FileReserved; /* Force a do-nothing reference. */
361     InternalQemuFwCfgReadBytes (sizeof (FName), FName);
362 
363     if (AsciiStrCmp (Name, FName) == 0) {
364       *Item = SwapBytes16 (FileSelect);
365       *Size = SwapBytes32 (FileSize);
366       return RETURN_SUCCESS;
367     }
368   }
369 
370   return RETURN_NOT_FOUND;
371 }
372 
373 
374 /**
375   Determine if S3 support is explicitly enabled.
376 
377   @retval  TRUE   if S3 support is explicitly enabled.
378            FALSE  otherwise. This includes unavailability of the firmware
379                   configuration interface.
380 **/
381 BOOLEAN
382 EFIAPI
QemuFwCfgS3Enabled(VOID)383 QemuFwCfgS3Enabled (
384   VOID
385   )
386 {
387   RETURN_STATUS        Status;
388   FIRMWARE_CONFIG_ITEM FwCfgItem;
389   UINTN                FwCfgSize;
390   UINT8                SystemStates[6];
391 
392   Status = QemuFwCfgFindFile ("etc/system-states", &FwCfgItem, &FwCfgSize);
393   if (Status != RETURN_SUCCESS || FwCfgSize != sizeof SystemStates) {
394     return FALSE;
395   }
396   QemuFwCfgSelectItem (FwCfgItem);
397   QemuFwCfgReadBytes (sizeof SystemStates, SystemStates);
398   return (BOOLEAN) (SystemStates[3] & BIT7);
399 }
400