]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxe.c
f8eb03bc3a9a4d7188f5aa110086b0651c831f04
[mirror_edk2.git] / OvmfPkg / Library / QemuFwCfgLib / QemuFwCfgDxe.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 <Uefi.h>
19
20 #include <Protocol/IoMmu.h>
21
22 #include <Library/BaseLib.h>
23 #include <Library/DebugLib.h>
24 #include <Library/QemuFwCfgLib.h>
25 #include <Library/UefiBootServicesTableLib.h>
26 #include <Library/MemEncryptSevLib.h>
27
28 #include "QemuFwCfgLibInternal.h"
29
30 STATIC BOOLEAN mQemuFwCfgSupported = FALSE;
31 STATIC BOOLEAN mQemuFwCfgDmaSupported;
32
33 STATIC EDKII_IOMMU_PROTOCOL *mIoMmuProtocol;
34 /**
35
36 Returns a boolean indicating whether SEV is enabled
37
38 @retval TRUE SEV is enabled
39 @retval FALSE SEV is disabled
40 **/
41 BOOLEAN
42 InternalQemuFwCfgSevIsEnabled (
43 VOID
44 )
45 {
46 return MemEncryptSevIsEnabled ();
47 }
48
49 /**
50 Returns a boolean indicating if the firmware configuration interface
51 is available or not.
52
53 This function may change fw_cfg state.
54
55 @retval TRUE The interface is available
56 @retval FALSE The interface is not available
57
58 **/
59 BOOLEAN
60 EFIAPI
61 QemuFwCfgIsAvailable (
62 VOID
63 )
64 {
65 return InternalQemuFwCfgIsAvailable ();
66 }
67
68
69 RETURN_STATUS
70 EFIAPI
71 QemuFwCfgInitialize (
72 VOID
73 )
74 {
75 UINT32 Signature;
76 UINT32 Revision;
77
78 //
79 // Enable the access routines while probing to see if it is supported.
80 // For probing we always use the IO Port (IoReadFifo8()) access method.
81 //
82 mQemuFwCfgSupported = TRUE;
83 mQemuFwCfgDmaSupported = FALSE;
84
85 QemuFwCfgSelectItem (QemuFwCfgItemSignature);
86 Signature = QemuFwCfgRead32 ();
87 DEBUG ((EFI_D_INFO, "FW CFG Signature: 0x%x\n", Signature));
88 QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion);
89 Revision = QemuFwCfgRead32 ();
90 DEBUG ((EFI_D_INFO, "FW CFG Revision: 0x%x\n", Revision));
91 if ((Signature != SIGNATURE_32 ('Q', 'E', 'M', 'U')) ||
92 (Revision < 1)
93 ) {
94 DEBUG ((EFI_D_INFO, "QemuFwCfg interface not supported.\n"));
95 mQemuFwCfgSupported = FALSE;
96 return RETURN_SUCCESS;
97 }
98
99 if ((Revision & FW_CFG_F_DMA) == 0) {
100 DEBUG ((DEBUG_INFO, "QemuFwCfg interface (IO Port) is supported.\n"));
101 } else {
102 mQemuFwCfgDmaSupported = TRUE;
103 DEBUG ((DEBUG_INFO, "QemuFwCfg interface (DMA) is supported.\n"));
104 }
105
106 if (mQemuFwCfgDmaSupported && MemEncryptSevIsEnabled ()) {
107 EFI_STATUS Status;
108
109 //
110 // IoMmuDxe driver must have installed the IOMMU protocol. If we are not
111 // able to locate the protocol then something must have gone wrong.
112 //
113 Status = gBS->LocateProtocol (&gEdkiiIoMmuProtocolGuid, NULL, (VOID **)&mIoMmuProtocol);
114 if (EFI_ERROR (Status)) {
115 DEBUG ((DEBUG_ERROR,
116 "QemuFwCfgSevDma %a:%a Failed to locate IOMMU protocol.\n",
117 gEfiCallerBaseName, __FUNCTION__));
118 ASSERT (FALSE);
119 CpuDeadLoop ();
120 }
121 }
122
123 return RETURN_SUCCESS;
124 }
125
126
127 /**
128 Returns a boolean indicating if the firmware configuration interface is
129 available for library-internal purposes.
130
131 This function never changes fw_cfg state.
132
133 @retval TRUE The interface is available internally.
134 @retval FALSE The interface is not available internally.
135 **/
136 BOOLEAN
137 InternalQemuFwCfgIsAvailable (
138 VOID
139 )
140 {
141 return mQemuFwCfgSupported;
142 }
143
144 /**
145 Returns a boolean indicating whether QEMU provides the DMA-like access method
146 for fw_cfg.
147
148 @retval TRUE The DMA-like access method is available.
149 @retval FALSE The DMA-like access method is unavailable.
150 **/
151 BOOLEAN
152 InternalQemuFwCfgDmaIsAvailable (
153 VOID
154 )
155 {
156 return mQemuFwCfgDmaSupported;
157 }
158
159 /**
160 Allocate a bounce buffer for SEV DMA.
161
162 @param[in] NumPage Number of pages.
163 @param[out] Buffer Allocated DMA Buffer pointer
164
165 **/
166 VOID
167 InternalQemuFwCfgSevDmaAllocateBuffer (
168 OUT VOID **Buffer,
169 IN UINT32 NumPages
170 )
171 {
172 EFI_STATUS Status;
173
174 ASSERT (mIoMmuProtocol != NULL);
175
176 Status = mIoMmuProtocol->AllocateBuffer (
177 mIoMmuProtocol,
178 0,
179 EfiBootServicesData,
180 NumPages,
181 Buffer,
182 EDKII_IOMMU_ATTRIBUTE_MEMORY_CACHED
183 );
184 if (EFI_ERROR (Status)) {
185 DEBUG ((DEBUG_ERROR,
186 "%a:%a failed to allocate %u pages\n", gEfiCallerBaseName, __FUNCTION__,
187 NumPages));
188 ASSERT (FALSE);
189 CpuDeadLoop ();
190 }
191
192 DEBUG ((DEBUG_VERBOSE,
193 "%a:%a buffer 0x%Lx Pages %u\n", gEfiCallerBaseName, __FUNCTION__,
194 (UINT64)(UINTN)Buffer, NumPages));
195 }
196
197 /**
198 Free the DMA buffer allocated using InternalQemuFwCfgSevDmaAllocateBuffer
199
200 @param[in] NumPage Number of pages.
201 @param[in] Buffer DMA Buffer pointer
202
203 **/
204 VOID
205 InternalQemuFwCfgSevDmaFreeBuffer (
206 IN VOID *Buffer,
207 IN UINT32 NumPages
208 )
209 {
210 EFI_STATUS Status;
211
212 ASSERT (mIoMmuProtocol != NULL);
213
214 Status = mIoMmuProtocol->FreeBuffer (
215 mIoMmuProtocol,
216 NumPages,
217 Buffer
218 );
219 if (EFI_ERROR (Status)) {
220 DEBUG ((DEBUG_ERROR,
221 "%a:%a failed to free buffer 0x%Lx pages %u\n", gEfiCallerBaseName,
222 __FUNCTION__, (UINT64)(UINTN)Buffer, NumPages));
223 ASSERT (FALSE);
224 CpuDeadLoop ();
225 }
226
227 DEBUG ((DEBUG_VERBOSE,
228 "%a:%a buffer 0x%Lx Pages %u\n", gEfiCallerBaseName,__FUNCTION__,
229 (UINT64)(UINTN)Buffer, NumPages));
230 }