]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/CcExitLib/CcExitLib.c
OvmfPkg/UefiCpuPkg/UefiPayloadPkg: Rename VmgExitLib to CcExitLib
[mirror_edk2.git] / OvmfPkg / Library / CcExitLib / CcExitLib.c
1 /** @file
2 CcExitLib Support Library.
3
4 Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
5 Copyright (C) 2020 - 2022, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include <Base.h>
11 #include <Uefi.h>
12 #include <Library/BaseMemoryLib.h>
13 #include <Library/CcExitLib.h>
14 #include <Register/Amd/Msr.h>
15
16 /**
17 Check for VMGEXIT error
18
19 Check if the hypervisor has returned an error after completion of the VMGEXIT
20 by examining the SwExitInfo1 field of the GHCB.
21
22 @param[in] Ghcb A pointer to the GHCB
23
24 @retval 0 VMGEXIT succeeded.
25 @return Exception number to be propagated, VMGEXIT processing
26 did not succeed.
27
28 **/
29 STATIC
30 UINT64
31 VmgExitErrorCheck (
32 IN GHCB *Ghcb
33 )
34 {
35 GHCB_EVENT_INJECTION Event;
36 GHCB_EXIT_INFO ExitInfo;
37 UINT64 Status;
38
39 ExitInfo.Uint64 = Ghcb->SaveArea.SwExitInfo1;
40 ASSERT (
41 (ExitInfo.Elements.Lower32Bits == 0) ||
42 (ExitInfo.Elements.Lower32Bits == 1)
43 );
44
45 Status = 0;
46 if (ExitInfo.Elements.Lower32Bits == 0) {
47 return Status;
48 }
49
50 if (ExitInfo.Elements.Lower32Bits == 1) {
51 ASSERT (Ghcb->SaveArea.SwExitInfo2 != 0);
52
53 //
54 // Check that the return event is valid
55 //
56 Event.Uint64 = Ghcb->SaveArea.SwExitInfo2;
57 if (Event.Elements.Valid &&
58 (Event.Elements.Type == GHCB_EVENT_INJECTION_TYPE_EXCEPTION))
59 {
60 switch (Event.Elements.Vector) {
61 case GP_EXCEPTION:
62 case UD_EXCEPTION:
63 //
64 // Use returned event as return code
65 //
66 Status = Event.Uint64;
67 }
68 }
69 }
70
71 if (Status == 0) {
72 GHCB_EVENT_INJECTION GpEvent;
73
74 GpEvent.Uint64 = 0;
75 GpEvent.Elements.Vector = GP_EXCEPTION;
76 GpEvent.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION;
77 GpEvent.Elements.Valid = 1;
78
79 Status = GpEvent.Uint64;
80 }
81
82 return Status;
83 }
84
85 /**
86 Perform VMGEXIT.
87
88 Sets the necessary fields of the GHCB, invokes the VMGEXIT instruction and
89 then handles the return actions.
90
91 @param[in, out] Ghcb A pointer to the GHCB
92 @param[in] ExitCode VMGEXIT code to be assigned to the SwExitCode
93 field of the GHCB.
94 @param[in] ExitInfo1 VMGEXIT information to be assigned to the
95 SwExitInfo1 field of the GHCB.
96 @param[in] ExitInfo2 VMGEXIT information to be assigned to the
97 SwExitInfo2 field of the GHCB.
98
99 @retval 0 VMGEXIT succeeded.
100 @return Exception number to be propagated, VMGEXIT
101 processing did not succeed.
102
103 **/
104 UINT64
105 EFIAPI
106 VmgExit (
107 IN OUT GHCB *Ghcb,
108 IN UINT64 ExitCode,
109 IN UINT64 ExitInfo1,
110 IN UINT64 ExitInfo2
111 )
112 {
113 Ghcb->SaveArea.SwExitCode = ExitCode;
114 Ghcb->SaveArea.SwExitInfo1 = ExitInfo1;
115 Ghcb->SaveArea.SwExitInfo2 = ExitInfo2;
116
117 VmgSetOffsetValid (Ghcb, GhcbSwExitCode);
118 VmgSetOffsetValid (Ghcb, GhcbSwExitInfo1);
119 VmgSetOffsetValid (Ghcb, GhcbSwExitInfo2);
120
121 //
122 // Guest memory is used for the guest-hypervisor communication, so fence
123 // the invocation of the VMGEXIT instruction to ensure GHCB accesses are
124 // synchronized properly.
125 //
126 MemoryFence ();
127 AsmVmgExit ();
128 MemoryFence ();
129
130 return VmgExitErrorCheck (Ghcb);
131 }
132
133 /**
134 Perform pre-VMGEXIT initialization/preparation.
135
136 Performs the necessary steps in preparation for invoking VMGEXIT. Must be
137 called before setting any fields within the GHCB.
138
139 @param[in, out] Ghcb A pointer to the GHCB
140 @param[in, out] InterruptState A pointer to hold the current interrupt
141 state, used for restoring in VmgDone ()
142
143 **/
144 VOID
145 EFIAPI
146 VmgInit (
147 IN OUT GHCB *Ghcb,
148 IN OUT BOOLEAN *InterruptState
149 )
150 {
151 //
152 // Be sure that an interrupt can't cause a #VC while the GHCB is
153 // being used.
154 //
155 *InterruptState = GetInterruptState ();
156 if (*InterruptState) {
157 DisableInterrupts ();
158 }
159
160 SetMem (&Ghcb->SaveArea, sizeof (Ghcb->SaveArea), 0);
161 }
162
163 /**
164 Perform post-VMGEXIT cleanup.
165
166 Performs the necessary steps to cleanup after invoking VMGEXIT. Must be
167 called after obtaining needed fields within the GHCB.
168
169 @param[in, out] Ghcb A pointer to the GHCB
170 @param[in] InterruptState An indicator to conditionally (re)enable
171 interrupts
172
173 **/
174 VOID
175 EFIAPI
176 VmgDone (
177 IN OUT GHCB *Ghcb,
178 IN BOOLEAN InterruptState
179 )
180 {
181 if (InterruptState) {
182 EnableInterrupts ();
183 }
184 }
185
186 /**
187 Marks a field at the specified offset as valid in the GHCB.
188
189 The ValidBitmap area represents the areas of the GHCB that have been marked
190 valid. Set the bit in ValidBitmap for the input offset.
191
192 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication Block
193 @param[in] Offset Qword offset in the GHCB to mark valid
194
195 **/
196 VOID
197 EFIAPI
198 VmgSetOffsetValid (
199 IN OUT GHCB *Ghcb,
200 IN GHCB_REGISTER Offset
201 )
202 {
203 UINT32 OffsetIndex;
204 UINT32 OffsetBit;
205
206 OffsetIndex = Offset / 8;
207 OffsetBit = Offset % 8;
208
209 Ghcb->SaveArea.ValidBitmap[OffsetIndex] |= (1 << OffsetBit);
210 }
211
212 /**
213 Checks if a specified offset is valid in the GHCB.
214
215 The ValidBitmap area represents the areas of the GHCB that have been marked
216 valid. Return whether the bit in the ValidBitmap is set for the input offset.
217
218 @param[in] Ghcb A pointer to the GHCB
219 @param[in] Offset Qword offset in the GHCB to mark valid
220
221 @retval TRUE Offset is marked valid in the GHCB
222 @retval FALSE Offset is not marked valid in the GHCB
223
224 **/
225 BOOLEAN
226 EFIAPI
227 VmgIsOffsetValid (
228 IN GHCB *Ghcb,
229 IN GHCB_REGISTER Offset
230 )
231 {
232 UINT32 OffsetIndex;
233 UINT32 OffsetBit;
234
235 OffsetIndex = Offset / 8;
236 OffsetBit = Offset % 8;
237
238 return ((Ghcb->SaveArea.ValidBitmap[OffsetIndex] & (1 << OffsetBit)) != 0);
239 }