]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c
OvmfPkg: Apply uncrustify changes
[mirror_edk2.git] / OvmfPkg / Library / QemuFwCfgLib / QemuFwCfgPei.c
1 /** @file
2
3 Stateful and implicitly initialized fw_cfg library implementation.
4
5 Copyright (C) 2013, Red Hat, Inc.
6 Copyright (c) 2011 - 2013, Intel Corporation. All rights reserved.<BR>
7 Copyright (c) 2017, Advanced Micro Devices. All rights reserved.<BR>
8
9 SPDX-License-Identifier: BSD-2-Clause-Patent
10 **/
11
12 #include <Library/BaseLib.h>
13 #include <Library/IoLib.h>
14 #include <Library/DebugLib.h>
15 #include <Library/QemuFwCfgLib.h>
16 #include <Library/MemEncryptSevLib.h>
17
18 #include "QemuFwCfgLibInternal.h"
19
20 STATIC BOOLEAN mQemuFwCfgSupported = FALSE;
21 STATIC BOOLEAN mQemuFwCfgDmaSupported;
22
23 /**
24 Returns a boolean indicating if the firmware configuration interface
25 is available or not.
26
27 This function may change fw_cfg state.
28
29 @retval TRUE The interface is available
30 @retval FALSE The interface is not available
31
32 **/
33 BOOLEAN
34 EFIAPI
35 QemuFwCfgIsAvailable (
36 VOID
37 )
38 {
39 return InternalQemuFwCfgIsAvailable ();
40 }
41
42 RETURN_STATUS
43 EFIAPI
44 QemuFwCfgInitialize (
45 VOID
46 )
47 {
48 UINT32 Signature;
49 UINT32 Revision;
50
51 //
52 // Enable the access routines while probing to see if it is supported.
53 // For probing we always use the IO Port (IoReadFifo8()) access method.
54 //
55 mQemuFwCfgSupported = TRUE;
56 mQemuFwCfgDmaSupported = FALSE;
57
58 QemuFwCfgSelectItem (QemuFwCfgItemSignature);
59 Signature = QemuFwCfgRead32 ();
60 DEBUG ((DEBUG_INFO, "FW CFG Signature: 0x%x\n", Signature));
61 QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion);
62 Revision = QemuFwCfgRead32 ();
63 DEBUG ((DEBUG_INFO, "FW CFG Revision: 0x%x\n", Revision));
64 if ((Signature != SIGNATURE_32 ('Q', 'E', 'M', 'U')) ||
65 (Revision < 1)
66 )
67 {
68 DEBUG ((DEBUG_INFO, "QemuFwCfg interface not supported.\n"));
69 mQemuFwCfgSupported = FALSE;
70 return RETURN_SUCCESS;
71 }
72
73 if ((Revision & FW_CFG_F_DMA) == 0) {
74 DEBUG ((DEBUG_INFO, "QemuFwCfg interface (IO Port) is supported.\n"));
75 } else {
76 //
77 // If SEV is enabled then we do not support DMA operations in PEI phase.
78 // This is mainly because DMA in SEV guest requires using bounce buffer
79 // (which need to allocate dynamic memory and allocating a PAGE size'd
80 // buffer can be challenge in PEI phase)
81 //
82 if (MemEncryptSevIsEnabled ()) {
83 DEBUG ((DEBUG_INFO, "SEV: QemuFwCfg fallback to IO Port interface.\n"));
84 } else {
85 mQemuFwCfgDmaSupported = TRUE;
86 DEBUG ((DEBUG_INFO, "QemuFwCfg interface (DMA) is supported.\n"));
87 }
88 }
89
90 return RETURN_SUCCESS;
91 }
92
93 /**
94 Returns a boolean indicating if the firmware configuration interface is
95 available for library-internal purposes.
96
97 This function never changes fw_cfg state.
98
99 @retval TRUE The interface is available internally.
100 @retval FALSE The interface is not available internally.
101 **/
102 BOOLEAN
103 InternalQemuFwCfgIsAvailable (
104 VOID
105 )
106 {
107 return mQemuFwCfgSupported;
108 }
109
110 /**
111 Returns a boolean indicating whether QEMU provides the DMA-like access method
112 for fw_cfg.
113
114 @retval TRUE The DMA-like access method is available.
115 @retval FALSE The DMA-like access method is unavailable.
116 **/
117 BOOLEAN
118 InternalQemuFwCfgDmaIsAvailable (
119 VOID
120 )
121 {
122 return mQemuFwCfgDmaSupported;
123 }
124
125 /**
126 Transfer an array of bytes, or skip a number of bytes, using the DMA
127 interface.
128
129 @param[in] Size Size in bytes to transfer or skip.
130
131 @param[in,out] Buffer Buffer to read data into or write data from. Ignored,
132 and may be NULL, if Size is zero, or Control is
133 FW_CFG_DMA_CTL_SKIP.
134
135 @param[in] Control One of the following:
136 FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer.
137 FW_CFG_DMA_CTL_READ - read from fw_cfg into Buffer.
138 FW_CFG_DMA_CTL_SKIP - skip bytes in fw_cfg.
139 **/
140 VOID
141 InternalQemuFwCfgDmaBytes (
142 IN UINT32 Size,
143 IN OUT VOID *Buffer OPTIONAL,
144 IN UINT32 Control
145 )
146 {
147 volatile FW_CFG_DMA_ACCESS Access;
148 UINT32 AccessHigh, AccessLow;
149 UINT32 Status;
150
151 ASSERT (
152 Control == FW_CFG_DMA_CTL_WRITE || Control == FW_CFG_DMA_CTL_READ ||
153 Control == FW_CFG_DMA_CTL_SKIP
154 );
155
156 if (Size == 0) {
157 return;
158 }
159
160 //
161 // SEV does not support DMA operations in PEI stage, we should
162 // not have reached here.
163 //
164 ASSERT (!MemEncryptSevIsEnabled ());
165
166 Access.Control = SwapBytes32 (Control);
167 Access.Length = SwapBytes32 (Size);
168 Access.Address = SwapBytes64 ((UINTN)Buffer);
169
170 //
171 // Delimit the transfer from (a) modifications to Access, (b) in case of a
172 // write, from writes to Buffer by the caller.
173 //
174 MemoryFence ();
175
176 //
177 // Start the transfer.
178 //
179 AccessHigh = (UINT32)RShiftU64 ((UINTN)&Access, 32);
180 AccessLow = (UINT32)(UINTN)&Access;
181 IoWrite32 (FW_CFG_IO_DMA_ADDRESS, SwapBytes32 (AccessHigh));
182 IoWrite32 (FW_CFG_IO_DMA_ADDRESS + 4, SwapBytes32 (AccessLow));
183
184 //
185 // Don't look at Access.Control before starting the transfer.
186 //
187 MemoryFence ();
188
189 //
190 // Wait for the transfer to complete.
191 //
192 do {
193 Status = SwapBytes32 (Access.Control);
194 ASSERT ((Status & FW_CFG_DMA_CTL_ERROR) == 0);
195 } while (Status != 0);
196
197 //
198 // After a read, the caller will want to use Buffer.
199 //
200 MemoryFence ();
201 }