]>
Commit | Line | Data |
---|---|---|
2ce7e221 LE |
1 | /** @file\r |
2 | \r | |
3 | Stateful and implicitly initialized fw_cfg library implementation.\r | |
4 | \r | |
5 | Copyright (C) 2013, Red Hat, Inc.\r | |
6 | Copyright (c) 2011 - 2013, Intel Corporation. All rights reserved.<BR>\r | |
5feae253 | 7 | Copyright (c) 2017, Advanced Micro Devices. All rights reserved.<BR>\r |
2ce7e221 | 8 | \r |
b26f0cf9 | 9 | SPDX-License-Identifier: BSD-2-Clause-Patent\r |
2ce7e221 LE |
10 | **/\r |
11 | \r | |
cda98df1 | 12 | #include <PiPei.h>\r |
5feae253 | 13 | #include <Library/BaseLib.h>\r |
2ce7e221 | 14 | #include <Library/DebugLib.h>\r |
cda98df1 GH |
15 | #include <Library/HobLib.h>\r |
16 | #include <Library/IoLib.h>\r | |
17 | #include <Library/PlatformInitLib.h>\r | |
2ce7e221 | 18 | #include <Library/QemuFwCfgLib.h>\r |
6b27c116 | 19 | #include <WorkArea.h>\r |
2ce7e221 | 20 | \r |
5297c0bf LE |
21 | #include "QemuFwCfgLibInternal.h"\r |
22 | \r | |
6b27c116 MX |
23 | /**\r |
24 | Check if it is Tdx guest\r | |
25 | \r | |
26 | @retval TRUE It is Tdx guest\r | |
27 | @retval FALSE It is not Tdx guest\r | |
28 | **/\r | |
81bbc145 | 29 | STATIC\r |
6b27c116 | 30 | BOOLEAN\r |
81bbc145 | 31 | QemuFwCfgIsCcGuest (\r |
6b27c116 MX |
32 | VOID\r |
33 | )\r | |
34 | {\r | |
35 | CONFIDENTIAL_COMPUTING_WORK_AREA_HEADER *CcWorkAreaHeader;\r | |
36 | \r | |
37 | CcWorkAreaHeader = (CONFIDENTIAL_COMPUTING_WORK_AREA_HEADER *)FixedPcdGet32 (PcdOvmfWorkAreaBase);\r | |
81bbc145 | 38 | return (CcWorkAreaHeader != NULL && CcWorkAreaHeader->GuestType != CcGuestTypeNonEncrypted);\r |
6b27c116 MX |
39 | }\r |
40 | \r | |
2ce7e221 LE |
41 | /**\r |
42 | Returns a boolean indicating if the firmware configuration interface\r | |
43 | is available or not.\r | |
44 | \r | |
45 | This function may change fw_cfg state.\r | |
46 | \r | |
47 | @retval TRUE The interface is available\r | |
48 | @retval FALSE The interface is not available\r | |
49 | \r | |
50 | **/\r | |
51 | BOOLEAN\r | |
52 | EFIAPI\r | |
53 | QemuFwCfgIsAvailable (\r | |
54 | VOID\r | |
55 | )\r | |
56 | {\r | |
57 | return InternalQemuFwCfgIsAvailable ();\r | |
58 | }\r | |
59 | \r | |
81bbc145 GH |
60 | STATIC\r |
61 | VOID\r | |
62 | QemuFwCfgProbe (\r | |
63 | BOOLEAN *Supported,\r | |
64 | BOOLEAN *DmaSupported\r | |
65 | )\r | |
66 | {\r | |
67 | UINT32 Signature;\r | |
68 | UINT32 Revision;\r | |
69 | BOOLEAN CcGuest;\r | |
70 | \r | |
71 | // Use direct Io* calls for probing to avoid recursion.\r | |
72 | IoWrite16 (FW_CFG_IO_SELECTOR, (UINT16)QemuFwCfgItemSignature);\r | |
73 | IoReadFifo8 (FW_CFG_IO_DATA, sizeof Signature, &Signature);\r | |
74 | IoWrite16 (FW_CFG_IO_SELECTOR, (UINT16)QemuFwCfgItemInterfaceVersion);\r | |
75 | IoReadFifo8 (FW_CFG_IO_DATA, sizeof Revision, &Revision);\r | |
76 | CcGuest = QemuFwCfgIsCcGuest ();\r | |
77 | \r | |
78 | *Supported = FALSE;\r | |
79 | *DmaSupported = FALSE;\r | |
80 | if ((Signature == SIGNATURE_32 ('Q', 'E', 'M', 'U')) && (Revision >= 1)) {\r | |
81 | *Supported = TRUE;\r | |
82 | if ((Revision & FW_CFG_F_DMA) && !CcGuest) {\r | |
83 | *DmaSupported = TRUE;\r | |
84 | }\r | |
85 | }\r | |
86 | \r | |
87 | DEBUG ((\r | |
88 | DEBUG_INFO,\r | |
89 | "%a: Supported %d, DMA %d\n",\r | |
90 | __func__,\r | |
91 | *Supported,\r | |
92 | *DmaSupported\r | |
93 | ));\r | |
94 | }\r | |
95 | \r | |
cda98df1 GH |
96 | STATIC\r |
97 | EFI_HOB_PLATFORM_INFO *\r | |
98 | QemuFwCfgGetPlatformInfo (\r | |
99 | VOID\r | |
100 | )\r | |
101 | {\r | |
102 | EFI_HOB_PLATFORM_INFO *PlatformInfoHob;\r | |
103 | EFI_HOB_GUID_TYPE *GuidHob;\r | |
104 | \r | |
105 | GuidHob = GetFirstGuidHob (&gUefiOvmfPkgPlatformInfoGuid);\r | |
106 | if (GuidHob == NULL) {\r | |
107 | return NULL;\r | |
108 | }\r | |
109 | \r | |
110 | PlatformInfoHob = (EFI_HOB_PLATFORM_INFO *)GET_GUID_HOB_DATA (GuidHob);\r | |
111 | \r | |
112 | if (!PlatformInfoHob->QemuFwCfgChecked) {\r | |
113 | QemuFwCfgProbe (\r | |
114 | &PlatformInfoHob->QemuFwCfgSupported,\r | |
115 | &PlatformInfoHob->QemuFwCfgDmaSupported\r | |
116 | );\r | |
117 | PlatformInfoHob->QemuFwCfgChecked = TRUE;\r | |
118 | }\r | |
119 | \r | |
120 | return PlatformInfoHob;\r | |
121 | }\r | |
122 | \r | |
2ce7e221 LE |
123 | RETURN_STATUS\r |
124 | EFIAPI\r | |
125 | QemuFwCfgInitialize (\r | |
126 | VOID\r | |
127 | )\r | |
128 | {\r | |
2ce7e221 LE |
129 | return RETURN_SUCCESS;\r |
130 | }\r | |
131 | \r | |
2ce7e221 LE |
132 | /**\r |
133 | Returns a boolean indicating if the firmware configuration interface is\r | |
134 | available for library-internal purposes.\r | |
135 | \r | |
136 | This function never changes fw_cfg state.\r | |
137 | \r | |
138 | @retval TRUE The interface is available internally.\r | |
139 | @retval FALSE The interface is not available internally.\r | |
140 | **/\r | |
141 | BOOLEAN\r | |
2ce7e221 LE |
142 | InternalQemuFwCfgIsAvailable (\r |
143 | VOID\r | |
144 | )\r | |
145 | {\r | |
cda98df1 GH |
146 | EFI_HOB_PLATFORM_INFO *PlatformInfoHob = QemuFwCfgGetPlatformInfo ();\r |
147 | \r | |
148 | return PlatformInfoHob->QemuFwCfgSupported;\r | |
2ce7e221 | 149 | }\r |
2c8dcbc6 LE |
150 | \r |
151 | /**\r | |
152 | Returns a boolean indicating whether QEMU provides the DMA-like access method\r | |
153 | for fw_cfg.\r | |
154 | \r | |
155 | @retval TRUE The DMA-like access method is available.\r | |
156 | @retval FALSE The DMA-like access method is unavailable.\r | |
157 | **/\r | |
158 | BOOLEAN\r | |
159 | InternalQemuFwCfgDmaIsAvailable (\r | |
160 | VOID\r | |
161 | )\r | |
162 | {\r | |
cda98df1 GH |
163 | EFI_HOB_PLATFORM_INFO *PlatformInfoHob = QemuFwCfgGetPlatformInfo ();\r |
164 | \r | |
165 | return PlatformInfoHob->QemuFwCfgDmaSupported;\r | |
2c8dcbc6 | 166 | }\r |
5feae253 BS |
167 | \r |
168 | /**\r | |
f6c909ae BS |
169 | Transfer an array of bytes, or skip a number of bytes, using the DMA\r |
170 | interface.\r | |
5feae253 | 171 | \r |
f6c909ae | 172 | @param[in] Size Size in bytes to transfer or skip.\r |
5feae253 | 173 | \r |
f6c909ae BS |
174 | @param[in,out] Buffer Buffer to read data into or write data from. Ignored,\r |
175 | and may be NULL, if Size is zero, or Control is\r | |
176 | FW_CFG_DMA_CTL_SKIP.\r | |
177 | \r | |
178 | @param[in] Control One of the following:\r | |
179 | FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer.\r | |
180 | FW_CFG_DMA_CTL_READ - read from fw_cfg into Buffer.\r | |
181 | FW_CFG_DMA_CTL_SKIP - skip bytes in fw_cfg.\r | |
5feae253 | 182 | **/\r |
f6c909ae BS |
183 | VOID\r |
184 | InternalQemuFwCfgDmaBytes (\r | |
ac0a286f MK |
185 | IN UINT32 Size,\r |
186 | IN OUT VOID *Buffer OPTIONAL,\r | |
187 | IN UINT32 Control\r | |
5feae253 BS |
188 | )\r |
189 | {\r | |
ac0a286f MK |
190 | volatile FW_CFG_DMA_ACCESS Access;\r |
191 | UINT32 AccessHigh, AccessLow;\r | |
192 | UINT32 Status;\r | |
5feae253 | 193 | \r |
ac0a286f MK |
194 | ASSERT (\r |
195 | Control == FW_CFG_DMA_CTL_WRITE || Control == FW_CFG_DMA_CTL_READ ||\r | |
196 | Control == FW_CFG_DMA_CTL_SKIP\r | |
197 | );\r | |
5feae253 | 198 | \r |
f6c909ae BS |
199 | if (Size == 0) {\r |
200 | return;\r | |
201 | }\r | |
5feae253 | 202 | \r |
6b27c116 MX |
203 | //\r |
204 | // TDX does not support DMA operations in PEI stage, we should\r | |
205 | // not have reached here.\r | |
206 | //\r | |
81bbc145 | 207 | ASSERT (!QemuFwCfgIsCcGuest ());\r |
6b27c116 | 208 | \r |
f6c909ae BS |
209 | Access.Control = SwapBytes32 (Control);\r |
210 | Access.Length = SwapBytes32 (Size);\r | |
211 | Access.Address = SwapBytes64 ((UINTN)Buffer);\r | |
5feae253 | 212 | \r |
f6c909ae BS |
213 | //\r |
214 | // Delimit the transfer from (a) modifications to Access, (b) in case of a\r | |
215 | // write, from writes to Buffer by the caller.\r | |
216 | //\r | |
217 | MemoryFence ();\r | |
218 | \r | |
219 | //\r | |
220 | // Start the transfer.\r | |
221 | //\r | |
222 | AccessHigh = (UINT32)RShiftU64 ((UINTN)&Access, 32);\r | |
223 | AccessLow = (UINT32)(UINTN)&Access;\r | |
ac0a286f | 224 | IoWrite32 (FW_CFG_IO_DMA_ADDRESS, SwapBytes32 (AccessHigh));\r |
f6c909ae | 225 | IoWrite32 (FW_CFG_IO_DMA_ADDRESS + 4, SwapBytes32 (AccessLow));\r |
5feae253 | 226 | \r |
5feae253 | 227 | //\r |
f6c909ae | 228 | // Don't look at Access.Control before starting the transfer.\r |
5feae253 | 229 | //\r |
f6c909ae BS |
230 | MemoryFence ();\r |
231 | \r | |
232 | //\r | |
233 | // Wait for the transfer to complete.\r | |
234 | //\r | |
235 | do {\r | |
236 | Status = SwapBytes32 (Access.Control);\r | |
237 | ASSERT ((Status & FW_CFG_DMA_CTL_ERROR) == 0);\r | |
238 | } while (Status != 0);\r | |
239 | \r | |
240 | //\r | |
241 | // After a read, the caller will want to use Buffer.\r | |
242 | //\r | |
243 | MemoryFence ();\r | |
5feae253 | 244 | }\r |