CcExitLib.c 6.1 KB

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