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>
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
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.
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>
26 #include "QemuFwCfgLibInternal.h"
30 Selects a firmware configuration item for reading.
32 Following this call, any data read from this item will start from
33 the beginning of the configuration item's data.
35 @param[in] QemuFwCfgItem - Firmware Configuration item to read
41 IN FIRMWARE_CONFIG_ITEM QemuFwCfgItem
44 DEBUG ((EFI_D_INFO
, "Select Item: 0x%x\n", (UINT16
)(UINTN
) QemuFwCfgItem
));
45 IoWrite16 (FW_CFG_IO_SELECTOR
, (UINT16
)(UINTN
) QemuFwCfgItem
);
50 Transfer an array of bytes, or skip a number of bytes, using the DMA
53 @param[in] Size Size in bytes to transfer or skip.
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
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.
65 InternalQemuFwCfgDmaBytes (
67 IN OUT VOID
*Buffer OPTIONAL
,
71 volatile FW_CFG_DMA_ACCESS LocalAccess
;
72 volatile FW_CFG_DMA_ACCESS
*Access
;
73 UINT32 AccessHigh
, AccessLow
;
76 VOID
*DmaBuffer
, *BounceBuffer
;
78 ASSERT (Control
== FW_CFG_DMA_CTL_WRITE
|| Control
== FW_CFG_DMA_CTL_READ
||
79 Control
== FW_CFG_DMA_CTL_SKIP
);
86 // set NumPages to suppress incorrect compiler/analyzer warnings
91 // When SEV is enabled then allocate DMA bounce buffer
93 if (InternalQemuFwCfgSevIsEnabled ()) {
96 TotalSize
= sizeof (*Access
);
98 // Skip operation does not need buffer
100 if (Control
!= FW_CFG_DMA_CTL_SKIP
) {
105 // Allocate SEV DMA buffer
107 NumPages
= (UINT32
)EFI_SIZE_TO_PAGES (TotalSize
);
108 InternalQemuFwCfgSevDmaAllocateBuffer (&BounceBuffer
, NumPages
);
110 Access
= BounceBuffer
;
111 DmaBuffer
= (UINT8
*)BounceBuffer
+ sizeof (*Access
);
114 // Decrypt data from encrypted guest buffer into DMA buffer
116 if (Control
== FW_CFG_DMA_CTL_WRITE
) {
117 CopyMem (DmaBuffer
, Buffer
, Size
);
120 Access
= &LocalAccess
;
125 Access
->Control
= SwapBytes32 (Control
);
126 Access
->Length
= SwapBytes32 (Size
);
127 Access
->Address
= SwapBytes64 ((UINTN
)DmaBuffer
);
130 // Delimit the transfer from (a) modifications to Access, (b) in case of a
131 // write, from writes to Buffer by the caller.
136 // Start the transfer.
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
));
144 // Don't look at Access.Control before starting the transfer.
149 // Wait for the transfer to complete.
152 Status
= SwapBytes32 (Access
->Control
);
153 ASSERT ((Status
& FW_CFG_DMA_CTL_ERROR
) == 0);
154 } while (Status
!= 0);
157 // After a read, the caller will want to use Buffer.
162 // If Bounce buffer was allocated then copy the data into guest buffer and
163 // free the bounce buffer
165 if (BounceBuffer
!= NULL
) {
167 // Encrypt the data from DMA buffer into guest buffer
169 if (Control
== FW_CFG_DMA_CTL_READ
) {
170 CopyMem (Buffer
, DmaBuffer
, Size
);
173 InternalQemuFwCfgSevDmaFreeBuffer (BounceBuffer
, NumPages
);
179 Reads firmware configuration bytes into a buffer
181 @param[in] Size - Size in bytes to read
182 @param[in] Buffer - Buffer to store data into (OPTIONAL if Size is 0)
187 InternalQemuFwCfgReadBytes (
189 IN VOID
*Buffer OPTIONAL
192 if (InternalQemuFwCfgDmaIsAvailable () && Size
<= MAX_UINT32
) {
193 InternalQemuFwCfgDmaBytes ((UINT32
)Size
, Buffer
, FW_CFG_DMA_CTL_READ
);
196 IoReadFifo8 (FW_CFG_IO_DATA
, Size
, Buffer
);
201 Reads firmware configuration bytes into a buffer
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.
207 @param[in] Size - Size in bytes to read
208 @param[in] Buffer - Buffer to store data into
218 if (InternalQemuFwCfgIsAvailable ()) {
219 InternalQemuFwCfgReadBytes (Size
, Buffer
);
221 ZeroMem (Buffer
, Size
);
226 Write firmware configuration bytes from a buffer
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.
232 @param[in] Size - Size in bytes to write
233 @param[in] Buffer - Buffer to read data from
238 QemuFwCfgWriteBytes (
243 if (InternalQemuFwCfgIsAvailable ()) {
244 if (InternalQemuFwCfgDmaIsAvailable () && Size
<= MAX_UINT32
) {
245 InternalQemuFwCfgDmaBytes ((UINT32
)Size
, Buffer
, FW_CFG_DMA_CTL_WRITE
);
248 IoWriteFifo8 (FW_CFG_IO_DATA
, Size
, Buffer
);
254 Skip bytes in the firmware configuration item.
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.
260 @param[in] Size Number of bytes to skip.
269 UINT8 SkipBuffer
[256];
271 if (!InternalQemuFwCfgIsAvailable ()) {
275 if (InternalQemuFwCfgDmaIsAvailable () && Size
<= MAX_UINT32
) {
276 InternalQemuFwCfgDmaBytes ((UINT32
)Size
, NULL
, FW_CFG_DMA_CTL_SKIP
);
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
290 ChunkSize
= MIN (Size
, sizeof SkipBuffer
);
291 IoReadFifo8 (FW_CFG_IO_DATA
, ChunkSize
, SkipBuffer
);
298 Reads a UINT8 firmware configuration value
300 @return Value of Firmware Configuration item read
311 QemuFwCfgReadBytes (sizeof (Result
), &Result
);
318 Reads a UINT16 firmware configuration value
320 @return Value of Firmware Configuration item read
331 QemuFwCfgReadBytes (sizeof (Result
), &Result
);
338 Reads a UINT32 firmware configuration value
340 @return Value of Firmware Configuration item read
351 QemuFwCfgReadBytes (sizeof (Result
), &Result
);
358 Reads a UINT64 firmware configuration value
360 @return Value of Firmware Configuration item read
371 QemuFwCfgReadBytes (sizeof (Result
), &Result
);
378 Find the configuration item corresponding to the firmware configuration file.
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.
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.
393 IN CONST CHAR8
*Name
,
394 OUT FIRMWARE_CONFIG_ITEM
*Item
,
401 if (!InternalQemuFwCfgIsAvailable ()) {
402 return RETURN_UNSUPPORTED
;
405 QemuFwCfgSelectItem (QemuFwCfgItemFileDir
);
406 Count
= SwapBytes32 (QemuFwCfgRead32 ());
408 for (Idx
= 0; Idx
< Count
; ++Idx
) {
412 CHAR8 FName
[QEMU_FW_CFG_FNAME_SIZE
];
414 FileSize
= QemuFwCfgRead32 ();
415 FileSelect
= QemuFwCfgRead16 ();
416 FileReserved
= QemuFwCfgRead16 ();
417 (VOID
) FileReserved
; /* Force a do-nothing reference. */
418 InternalQemuFwCfgReadBytes (sizeof (FName
), FName
);
420 if (AsciiStrCmp (Name
, FName
) == 0) {
421 *Item
= SwapBytes16 (FileSelect
);
422 *Size
= SwapBytes32 (FileSize
);
423 return RETURN_SUCCESS
;
427 return RETURN_NOT_FOUND
;