1 /** @file
2 VMGEXIT Support Library.
3
4 Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include <Base.h>
10 #include <Uefi.h>
11 #include <Library/BaseMemoryLib.h>
12 #include <Library/VmgExitLib.h>
13 #include <Register/Amd/Msr.h>
14
15 /**
16 Check for VMGEXIT error
17
18 Check if the hypervisor has returned an error after completion of the VMGEXIT
19 by examining the SwExitInfo1 field of the GHCB.
20
21 @param[in] Ghcb A pointer to the GHCB
22
23 @retval 0 VMGEXIT succeeded.
24 @return Exception number to be propagated, VMGEXIT processing
25 did not succeed.
26
27 **/
28 STATIC
29 UINT64
VmgExitErrorCheck(IN GHCB * Ghcb)30 VmgExitErrorCheck (
31 IN GHCB *Ghcb
32 )
33 {
34 GHCB_EVENT_INJECTION Event;
35 GHCB_EXIT_INFO ExitInfo;
36 UINT64 Status;
37
38 ExitInfo.Uint64 = Ghcb->SaveArea.SwExitInfo1;
39 ASSERT ((ExitInfo.Elements.Lower32Bits == 0) ||
40 (ExitInfo.Elements.Lower32Bits == 1));
41
42 Status = 0;
43 if (ExitInfo.Elements.Lower32Bits == 0) {
44 return Status;
45 }
46
47 if (ExitInfo.Elements.Lower32Bits == 1) {
48 ASSERT (Ghcb->SaveArea.SwExitInfo2 != 0);
49
50 //
51 // Check that the return event is valid
52 //
53 Event.Uint64 = Ghcb->SaveArea.SwExitInfo2;
54 if (Event.Elements.Valid &&
55 Event.Elements.Type == GHCB_EVENT_INJECTION_TYPE_EXCEPTION) {
56 switch (Event.Elements.Vector) {
57 case GP_EXCEPTION:
58 case UD_EXCEPTION:
59 //
60 // Use returned event as return code
61 //
62 Status = Event.Uint64;
63 }
64 }
65 }
66
67 if (Status == 0) {
68 GHCB_EVENT_INJECTION GpEvent;
69
70 GpEvent.Uint64 = 0;
71 GpEvent.Elements.Vector = GP_EXCEPTION;
72 GpEvent.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION;
73 GpEvent.Elements.Valid = 1;
74
75 Status = GpEvent.Uint64;
76 }
77
78 return Status;
79 }
80
81 /**
82 Perform VMGEXIT.
83
84 Sets the necessary fields of the GHCB, invokes the VMGEXIT instruction and
85 then handles the return actions.
86
87 @param[in, out] Ghcb A pointer to the GHCB
88 @param[in] ExitCode VMGEXIT code to be assigned to the SwExitCode
89 field of the GHCB.
90 @param[in] ExitInfo1 VMGEXIT information to be assigned to the
91 SwExitInfo1 field of the GHCB.
92 @param[in] ExitInfo2 VMGEXIT information to be assigned to the
93 SwExitInfo2 field of the GHCB.
94
95 @retval 0 VMGEXIT succeeded.
96 @return Exception number to be propagated, VMGEXIT
97 processing did not succeed.
98
99 **/
100 UINT64
101 EFIAPI
VmgExit(IN OUT GHCB * Ghcb,IN UINT64 ExitCode,IN UINT64 ExitInfo1,IN UINT64 ExitInfo2)102 VmgExit (
103 IN OUT GHCB *Ghcb,
104 IN UINT64 ExitCode,
105 IN UINT64 ExitInfo1,
106 IN UINT64 ExitInfo2
107 )
108 {
109 Ghcb->SaveArea.SwExitCode = ExitCode;
110 Ghcb->SaveArea.SwExitInfo1 = ExitInfo1;
111 Ghcb->SaveArea.SwExitInfo2 = ExitInfo2;
112
113 //
114 // Guest memory is used for the guest-hypervisor communication, so fence
115 // the invocation of the VMGEXIT instruction to ensure GHCB accesses are
116 // synchronized properly.
117 //
118 MemoryFence ();
119 AsmVmgExit ();
120 MemoryFence ();
121
122 return VmgExitErrorCheck (Ghcb);
123 }
124
125 /**
126 Perform pre-VMGEXIT initialization/preparation.
127
128 Performs the necessary steps in preparation for invoking VMGEXIT. Must be
129 called before setting any fields within the GHCB.
130
131 @param[in, out] Ghcb A pointer to the GHCB
132
133 **/
134 VOID
135 EFIAPI
VmgInit(IN OUT GHCB * Ghcb)136 VmgInit (
137 IN OUT GHCB *Ghcb
138 )
139 {
140 SetMem (&Ghcb->SaveArea, sizeof (Ghcb->SaveArea), 0);
141 }
142
143 /**
144 Perform post-VMGEXIT cleanup.
145
146 Performs the necessary steps to cleanup after invoking VMGEXIT. Must be
147 called after obtaining needed fields within the GHCB.
148
149 @param[in, out] Ghcb A pointer to the GHCB
150
151 **/
152 VOID
153 EFIAPI
VmgDone(IN OUT GHCB * Ghcb)154 VmgDone (
155 IN OUT GHCB *Ghcb
156 )
157 {
158 }
159
160