OvmfPkg/QemuFwCfgLib: Suppress GCC49 IA32 build failure
[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 LocalAccess;
72 volatile FW_CFG_DMA_ACCESS *Access;
73 UINT32 AccessHigh, AccessLow;
74 UINT32 Status;
75 UINT32 NumPages;
76 VOID *DmaBuffer, *BounceBuffer;
77
78 ASSERT (Control == FW_CFG_DMA_CTL_WRITE || Control == FW_CFG_DMA_CTL_READ ||
79 Control == FW_CFG_DMA_CTL_SKIP);
80
81 if (Size == 0) {
82 return;
83 }
84
85 //
86 // set NumPages to suppress incorrect compiler/analyzer warnings
87 //
88 NumPages = 0;
89
90 //
91 // When SEV is enabled then allocate DMA bounce buffer
92 //
93 if (InternalQemuFwCfgSevIsEnabled ()) {
94 UINTN TotalSize;
95
96 TotalSize = sizeof (*Access);
97 //
98 // Skip operation does not need buffer
99 //
100 if (Control != FW_CFG_DMA_CTL_SKIP) {
101 TotalSize += Size;
102 }
103
104 //
105 // Allocate SEV DMA buffer
106 //
107 NumPages = (UINT32)EFI_SIZE_TO_PAGES (TotalSize);
108 InternalQemuFwCfgSevDmaAllocateBuffer (&BounceBuffer, NumPages);
109
110 Access = BounceBuffer;
111 DmaBuffer = (UINT8*)BounceBuffer + sizeof (*Access);
112
113 //
114 // Decrypt data from encrypted guest buffer into DMA buffer
115 //
116 if (Control == FW_CFG_DMA_CTL_WRITE) {
117 CopyMem (DmaBuffer, Buffer, Size);
118 }
119 } else {
120 Access = &LocalAccess;
121 DmaBuffer = Buffer;
122 BounceBuffer = NULL;
123 }
124
125 Access->Control = SwapBytes32 (Control);
126 Access->Length = SwapBytes32 (Size);
127 Access->Address = SwapBytes64 ((UINTN)DmaBuffer);
128
129 //
130 // Delimit the transfer from (a) modifications to Access, (b) in case of a
131 // write, from writes to Buffer by the caller.
132 //
133 MemoryFence ();
134
135 //
136 // Start the transfer.
137 //
138 AccessHigh = (UINT32)RShiftU64 ((UINTN)Access, 32);
139 AccessLow = (UINT32)(UINTN)Access;
140 IoWrite32 (FW_CFG_IO_DMA_ADDRESS, SwapBytes32 (AccessHigh));
141 IoWrite32 (FW_CFG_IO_DMA_ADDRESS + 4, SwapBytes32 (AccessLow));
142
143 //
144 // Don't look at Access.Control before starting the transfer.
145 //
146 MemoryFence ();
147
148 //
149 // Wait for the transfer to complete.
150 //
151 do {
152 Status = SwapBytes32 (Access->Control);
153 ASSERT ((Status & FW_CFG_DMA_CTL_ERROR) == 0);
154 } while (Status != 0);
155
156 //
157 // After a read, the caller will want to use Buffer.
158 //
159 MemoryFence ();
160
161 //
162 // If Bounce buffer was allocated then copy the data into guest buffer and
163 // free the bounce buffer
164 //
165 if (BounceBuffer != NULL) {
166 //
167 // Encrypt the data from DMA buffer into guest buffer
168 //
169 if (Control == FW_CFG_DMA_CTL_READ) {
170 CopyMem (Buffer, DmaBuffer, Size);
171 }
172
173 InternalQemuFwCfgSevDmaFreeBuffer (BounceBuffer, NumPages);
174 }
175 }
176
177
178 /**
179 Reads firmware configuration bytes into a buffer
180
181 @param[in] Size - Size in bytes to read
182 @param[in] Buffer - Buffer to store data into (OPTIONAL if Size is 0)
183
184 **/
185 VOID
186 EFIAPI
187 InternalQemuFwCfgReadBytes (
188 IN UINTN Size,
189 IN VOID *Buffer OPTIONAL
190 )
191 {
192 if (InternalQemuFwCfgDmaIsAvailable () && Size <= MAX_UINT32) {
193 InternalQemuFwCfgDmaBytes ((UINT32)Size, Buffer, FW_CFG_DMA_CTL_READ);
194 return;
195 }
196 IoReadFifo8 (FW_CFG_IO_DATA, Size, Buffer);
197 }
198
199
200 /**
201 Reads firmware configuration bytes into a buffer
202
203 If called multiple times, then the data read will
204 continue at the offset of the firmware configuration
205 item where the previous read ended.
206
207 @param[in] Size - Size in bytes to read
208 @param[in] Buffer - Buffer to store data into
209
210 **/
211 VOID
212 EFIAPI
213 QemuFwCfgReadBytes (
214 IN UINTN Size,
215 IN VOID *Buffer
216 )
217 {
218 if (InternalQemuFwCfgIsAvailable ()) {
219 InternalQemuFwCfgReadBytes (Size, Buffer);
220 } else {
221 ZeroMem (Buffer, Size);
222 }
223 }
224
225 /**
226 Write firmware configuration bytes from a buffer
227
228 If called multiple times, then the data written will
229 continue at the offset of the firmware configuration
230 item where the previous write ended.
231
232 @param[in] Size - Size in bytes to write
233 @param[in] Buffer - Buffer to read data from
234
235 **/
236 VOID
237 EFIAPI
238 QemuFwCfgWriteBytes (
239 IN UINTN Size,
240 IN VOID *Buffer
241 )
242 {
243 if (InternalQemuFwCfgIsAvailable ()) {
244 if (InternalQemuFwCfgDmaIsAvailable () && Size <= MAX_UINT32) {
245 InternalQemuFwCfgDmaBytes ((UINT32)Size, Buffer, FW_CFG_DMA_CTL_WRITE);
246 return;
247 }
248 IoWriteFifo8 (FW_CFG_IO_DATA, Size, Buffer);
249 }
250 }
251
252
253 /**
254 Skip bytes in the firmware configuration item.
255
256 Increase the offset of the firmware configuration item without transferring
257 bytes between the item and a caller-provided buffer. Subsequent read, write
258 or skip operations will commence at the increased offset.
259
260 @param[in] Size Number of bytes to skip.
261 **/
262 VOID
263 EFIAPI
264 QemuFwCfgSkipBytes (
265 IN UINTN Size
266 )
267 {
268 UINTN ChunkSize;
269 UINT8 SkipBuffer[256];
270
271 if (!InternalQemuFwCfgIsAvailable ()) {
272 return;
273 }
274
275 if (InternalQemuFwCfgDmaIsAvailable () && Size <= MAX_UINT32) {
276 InternalQemuFwCfgDmaBytes ((UINT32)Size, NULL, FW_CFG_DMA_CTL_SKIP);
277 return;
278 }
279
280 //
281 // Emulate the skip by reading data in chunks, and throwing it away. The
282 // implementation below is suitable even for phases where RAM or dynamic
283 // allocation is not available or appropriate. It also doesn't affect the
284 // static data footprint for client modules. Large skips are not expected,
285 // therefore this fallback is not performance critical. The size of
286 // SkipBuffer is thought not to exert a large pressure on the stack in any
287 // phase.
288 //
289 while (Size > 0) {
290 ChunkSize = MIN (Size, sizeof SkipBuffer);
291 IoReadFifo8 (FW_CFG_IO_DATA, ChunkSize, SkipBuffer);
292 Size -= ChunkSize;
293 }
294 }
295
296
297 /**
298 Reads a UINT8 firmware configuration value
299
300 @return Value of Firmware Configuration item read
301
302 **/
303 UINT8
304 EFIAPI
305 QemuFwCfgRead8 (
306 VOID
307 )
308 {
309 UINT8 Result;
310
311 QemuFwCfgReadBytes (sizeof (Result), &Result);
312
313 return Result;
314 }
315
316
317 /**
318 Reads a UINT16 firmware configuration value
319
320 @return Value of Firmware Configuration item read
321
322 **/
323 UINT16
324 EFIAPI
325 QemuFwCfgRead16 (
326 VOID
327 )
328 {
329 UINT16 Result;
330
331 QemuFwCfgReadBytes (sizeof (Result), &Result);
332
333 return Result;
334 }
335
336
337 /**
338 Reads a UINT32 firmware configuration value
339
340 @return Value of Firmware Configuration item read
341
342 **/
343 UINT32
344 EFIAPI
345 QemuFwCfgRead32 (
346 VOID
347 )
348 {
349 UINT32 Result;
350
351 QemuFwCfgReadBytes (sizeof (Result), &Result);
352
353 return Result;
354 }
355
356
357 /**
358 Reads a UINT64 firmware configuration value
359
360 @return Value of Firmware Configuration item read
361
362 **/
363 UINT64
364 EFIAPI
365 QemuFwCfgRead64 (
366 VOID
367 )
368 {
369 UINT64 Result;
370
371 QemuFwCfgReadBytes (sizeof (Result), &Result);
372
373 return Result;
374 }
375
376
377 /**
378 Find the configuration item corresponding to the firmware configuration file.
379
380 @param[in] Name - Name of file to look up.
381 @param[out] Item - Configuration item corresponding to the file, to be passed
382 to QemuFwCfgSelectItem ().
383 @param[out] Size - Number of bytes in the file.
384
385 @return RETURN_SUCCESS If file is found.
386 RETURN_NOT_FOUND If file is not found.
387 RETURN_UNSUPPORTED If firmware configuration is unavailable.
388
389 **/
390 RETURN_STATUS
391 EFIAPI
392 QemuFwCfgFindFile (
393 IN CONST CHAR8 *Name,
394 OUT FIRMWARE_CONFIG_ITEM *Item,
395 OUT UINTN *Size
396 )
397 {
398 UINT32 Count;
399 UINT32 Idx;
400
401 if (!InternalQemuFwCfgIsAvailable ()) {
402 return RETURN_UNSUPPORTED;
403 }
404
405 QemuFwCfgSelectItem (QemuFwCfgItemFileDir);
406 Count = SwapBytes32 (QemuFwCfgRead32 ());
407
408 for (Idx = 0; Idx < Count; ++Idx) {
409 UINT32 FileSize;
410 UINT16 FileSelect;
411 UINT16 FileReserved;
412 CHAR8 FName[QEMU_FW_CFG_FNAME_SIZE];
413
414 FileSize = QemuFwCfgRead32 ();
415 FileSelect = QemuFwCfgRead16 ();
416 FileReserved = QemuFwCfgRead16 ();
417 (VOID) FileReserved; /* Force a do-nothing reference. */
418 InternalQemuFwCfgReadBytes (sizeof (FName), FName);
419
420 if (AsciiStrCmp (Name, FName) == 0) {
421 *Item = SwapBytes16 (FileSelect);
422 *Size = SwapBytes32 (FileSize);
423 return RETURN_SUCCESS;
424 }
425 }
426
427 return RETURN_NOT_FOUND;
428 }