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