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