0bbf121de432d489b07bfed490d0cf6b928ff56c
[mirror_edk2.git] / OvmfPkg / Library / QemuFwCfgLib / QemuFwCfgLib.c
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
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
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
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
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
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
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
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
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
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
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
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 }