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