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