AmdSev.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. /**@file
  2. Initialize Secure Encrypted Virtualization (SEV) support
  3. Copyright (c) 2017 - 2020, Advanced Micro Devices. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. //
  7. // The package level header files this module uses
  8. //
  9. #include <IndustryStandard/Q35MchIch9.h>
  10. #include <Library/BaseMemoryLib.h>
  11. #include <Library/DebugLib.h>
  12. #include <Library/HobLib.h>
  13. #include <Library/MemEncryptSevLib.h>
  14. #include <Library/MemoryAllocationLib.h>
  15. #include <Library/PcdLib.h>
  16. #include <PiPei.h>
  17. #include <Register/Amd/Msr.h>
  18. #include <Register/Intel/SmramSaveStateMap.h>
  19. #include <Library/CcExitLib.h>
  20. #include <ConfidentialComputingGuestAttr.h>
  21. #include "Platform.h"
  22. STATIC
  23. UINT64
  24. GetHypervisorFeature (
  25. VOID
  26. );
  27. /**
  28. Initialize SEV-SNP support if running as an SEV-SNP guest.
  29. **/
  30. STATIC
  31. VOID
  32. AmdSevSnpInitialize (
  33. VOID
  34. )
  35. {
  36. EFI_PEI_HOB_POINTERS Hob;
  37. EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
  38. UINT64 HvFeatures;
  39. EFI_STATUS PcdStatus;
  40. if (!MemEncryptSevSnpIsEnabled ()) {
  41. return;
  42. }
  43. //
  44. // Query the hypervisor feature using the CcExitVmgExit and set the value in the
  45. // hypervisor features PCD.
  46. //
  47. HvFeatures = GetHypervisorFeature ();
  48. PcdStatus = PcdSet64S (PcdGhcbHypervisorFeatures, HvFeatures);
  49. ASSERT_RETURN_ERROR (PcdStatus);
  50. //
  51. // Iterate through the system RAM and validate it.
  52. //
  53. for (Hob.Raw = GetHobList (); !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
  54. if ((Hob.Raw != NULL) && (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR)) {
  55. ResourceHob = Hob.ResourceDescriptor;
  56. if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {
  57. MemEncryptSevSnpPreValidateSystemRam (
  58. ResourceHob->PhysicalStart,
  59. EFI_SIZE_TO_PAGES ((UINTN)ResourceHob->ResourceLength)
  60. );
  61. }
  62. }
  63. }
  64. }
  65. /**
  66. Handle an SEV-SNP/GHCB protocol check failure.
  67. Notify the hypervisor using the VMGEXIT instruction that the SEV-SNP guest
  68. wishes to be terminated.
  69. @param[in] ReasonCode Reason code to provide to the hypervisor for the
  70. termination request.
  71. **/
  72. STATIC
  73. VOID
  74. SevEsProtocolFailure (
  75. IN UINT8 ReasonCode
  76. )
  77. {
  78. MSR_SEV_ES_GHCB_REGISTER Msr;
  79. //
  80. // Use the GHCB MSR Protocol to request termination by the hypervisor
  81. //
  82. Msr.GhcbPhysicalAddress = 0;
  83. Msr.GhcbTerminate.Function = GHCB_INFO_TERMINATE_REQUEST;
  84. Msr.GhcbTerminate.ReasonCodeSet = GHCB_TERMINATE_GHCB;
  85. Msr.GhcbTerminate.ReasonCode = ReasonCode;
  86. AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
  87. AsmVmgExit ();
  88. ASSERT (FALSE);
  89. CpuDeadLoop ();
  90. }
  91. /**
  92. Get the hypervisor features bitmap
  93. **/
  94. STATIC
  95. UINT64
  96. GetHypervisorFeature (
  97. VOID
  98. )
  99. {
  100. UINT64 Status;
  101. GHCB *Ghcb;
  102. MSR_SEV_ES_GHCB_REGISTER Msr;
  103. BOOLEAN InterruptState;
  104. UINT64 Features;
  105. Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
  106. Ghcb = Msr.Ghcb;
  107. //
  108. // Initialize the GHCB
  109. //
  110. CcExitVmgInit (Ghcb, &InterruptState);
  111. //
  112. // Query the Hypervisor Features.
  113. //
  114. Status = CcExitVmgExit (Ghcb, SVM_EXIT_HYPERVISOR_FEATURES, 0, 0);
  115. if ((Status != 0)) {
  116. SevEsProtocolFailure (GHCB_TERMINATE_GHCB_GENERAL);
  117. }
  118. Features = Ghcb->SaveArea.SwExitInfo2;
  119. CcExitVmgDone (Ghcb, InterruptState);
  120. return Features;
  121. }
  122. /**
  123. This function can be used to register the GHCB GPA.
  124. @param[in] Address The physical address to be registered.
  125. **/
  126. STATIC
  127. VOID
  128. GhcbRegister (
  129. IN EFI_PHYSICAL_ADDRESS Address
  130. )
  131. {
  132. MSR_SEV_ES_GHCB_REGISTER Msr;
  133. MSR_SEV_ES_GHCB_REGISTER CurrentMsr;
  134. //
  135. // Save the current MSR Value
  136. //
  137. CurrentMsr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
  138. //
  139. // Use the GHCB MSR Protocol to request to register the GPA.
  140. //
  141. Msr.GhcbPhysicalAddress = Address & ~EFI_PAGE_MASK;
  142. Msr.GhcbGpaRegister.Function = GHCB_INFO_GHCB_GPA_REGISTER_REQUEST;
  143. AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
  144. AsmVmgExit ();
  145. Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
  146. //
  147. // If hypervisor responded with a different GPA than requested then fail.
  148. //
  149. if ((Msr.GhcbGpaRegister.Function != GHCB_INFO_GHCB_GPA_REGISTER_RESPONSE) ||
  150. ((Msr.GhcbPhysicalAddress & ~EFI_PAGE_MASK) != Address))
  151. {
  152. SevEsProtocolFailure (GHCB_TERMINATE_GHCB_GENERAL);
  153. }
  154. //
  155. // Restore the MSR
  156. //
  157. AsmWriteMsr64 (MSR_SEV_ES_GHCB, CurrentMsr.GhcbPhysicalAddress);
  158. }
  159. /**
  160. Initialize SEV-ES support if running as an SEV-ES guest.
  161. **/
  162. STATIC
  163. VOID
  164. AmdSevEsInitialize (
  165. VOID
  166. )
  167. {
  168. UINT8 *GhcbBase;
  169. PHYSICAL_ADDRESS GhcbBasePa;
  170. UINTN GhcbPageCount;
  171. UINT8 *GhcbBackupBase;
  172. UINT8 *GhcbBackupPages;
  173. UINTN GhcbBackupPageCount;
  174. SEV_ES_PER_CPU_DATA *SevEsData;
  175. UINTN PageCount;
  176. RETURN_STATUS PcdStatus, DecryptStatus;
  177. IA32_DESCRIPTOR Gdtr;
  178. VOID *Gdt;
  179. if (!MemEncryptSevEsIsEnabled ()) {
  180. return;
  181. }
  182. PcdStatus = PcdSetBoolS (PcdSevEsIsEnabled, TRUE);
  183. ASSERT_RETURN_ERROR (PcdStatus);
  184. //
  185. // Allocate GHCB and per-CPU variable pages.
  186. // Since the pages must survive across the UEFI to OS transition
  187. // make them reserved.
  188. //
  189. GhcbPageCount = mPlatformInfoHob.PcdCpuMaxLogicalProcessorNumber * 2;
  190. GhcbBase = AllocateReservedPages (GhcbPageCount);
  191. ASSERT (GhcbBase != NULL);
  192. GhcbBasePa = (PHYSICAL_ADDRESS)(UINTN)GhcbBase;
  193. //
  194. // Each vCPU gets two consecutive pages, the first is the GHCB and the
  195. // second is the per-CPU variable page. Loop through the allocation and
  196. // only clear the encryption mask for the GHCB pages.
  197. //
  198. for (PageCount = 0; PageCount < GhcbPageCount; PageCount += 2) {
  199. DecryptStatus = MemEncryptSevClearPageEncMask (
  200. 0,
  201. GhcbBasePa + EFI_PAGES_TO_SIZE (PageCount),
  202. 1
  203. );
  204. ASSERT_RETURN_ERROR (DecryptStatus);
  205. }
  206. ZeroMem (GhcbBase, EFI_PAGES_TO_SIZE (GhcbPageCount));
  207. PcdStatus = PcdSet64S (PcdGhcbBase, GhcbBasePa);
  208. ASSERT_RETURN_ERROR (PcdStatus);
  209. PcdStatus = PcdSet64S (PcdGhcbSize, EFI_PAGES_TO_SIZE (GhcbPageCount));
  210. ASSERT_RETURN_ERROR (PcdStatus);
  211. DEBUG ((
  212. DEBUG_INFO,
  213. "SEV-ES is enabled, %lu GHCB pages allocated starting at 0x%p\n",
  214. (UINT64)GhcbPageCount,
  215. GhcbBase
  216. ));
  217. //
  218. // Allocate #VC recursion backup pages. The number of backup pages needed is
  219. // one less than the maximum VC count.
  220. //
  221. GhcbBackupPageCount = mPlatformInfoHob.PcdCpuMaxLogicalProcessorNumber * (VMGEXIT_MAXIMUM_VC_COUNT - 1);
  222. GhcbBackupBase = AllocatePages (GhcbBackupPageCount);
  223. ASSERT (GhcbBackupBase != NULL);
  224. GhcbBackupPages = GhcbBackupBase;
  225. for (PageCount = 1; PageCount < GhcbPageCount; PageCount += 2) {
  226. SevEsData =
  227. (SEV_ES_PER_CPU_DATA *)(GhcbBase + EFI_PAGES_TO_SIZE (PageCount));
  228. SevEsData->GhcbBackupPages = GhcbBackupPages;
  229. GhcbBackupPages += EFI_PAGE_SIZE * (VMGEXIT_MAXIMUM_VC_COUNT - 1);
  230. }
  231. DEBUG ((
  232. DEBUG_INFO,
  233. "SEV-ES is enabled, %lu GHCB backup pages allocated starting at 0x%p\n",
  234. (UINT64)GhcbBackupPageCount,
  235. GhcbBackupBase
  236. ));
  237. //
  238. // SEV-SNP guest requires that GHCB GPA must be registered before using it.
  239. //
  240. if (MemEncryptSevSnpIsEnabled ()) {
  241. GhcbRegister (GhcbBasePa);
  242. }
  243. AsmWriteMsr64 (MSR_SEV_ES_GHCB, GhcbBasePa);
  244. //
  245. // The SEV support will clear the C-bit from non-RAM areas. The early GDT
  246. // lives in a non-RAM area, so when an exception occurs (like a #VC) the GDT
  247. // will be read as un-encrypted even though it was created before the C-bit
  248. // was cleared (encrypted). This will result in a failure to be able to
  249. // handle the exception.
  250. //
  251. AsmReadGdtr (&Gdtr);
  252. Gdt = AllocatePages (EFI_SIZE_TO_PAGES ((UINTN)Gdtr.Limit + 1));
  253. ASSERT (Gdt != NULL);
  254. CopyMem (Gdt, (VOID *)Gdtr.Base, Gdtr.Limit + 1);
  255. Gdtr.Base = (UINTN)Gdt;
  256. AsmWriteGdtr (&Gdtr);
  257. }
  258. /**
  259. Function checks if SEV support is available, if present then it sets
  260. the dynamic PcdPteMemoryEncryptionAddressOrMask with memory encryption mask.
  261. **/
  262. VOID
  263. AmdSevInitialize (
  264. VOID
  265. )
  266. {
  267. UINT64 EncryptionMask;
  268. RETURN_STATUS PcdStatus;
  269. //
  270. // Check if SEV is enabled
  271. //
  272. if (!MemEncryptSevIsEnabled ()) {
  273. return;
  274. }
  275. //
  276. // Check and perform SEV-SNP initialization if required. This need to be
  277. // done before the GHCB page is made shared in the AmdSevEsInitialize(). This
  278. // is because the system RAM must be validated before it is made shared.
  279. // The AmdSevSnpInitialize() validates the system RAM.
  280. //
  281. AmdSevSnpInitialize ();
  282. //
  283. // Set Memory Encryption Mask PCD
  284. //
  285. EncryptionMask = MemEncryptSevGetEncryptionMask ();
  286. PcdStatus = PcdSet64S (PcdPteMemoryEncryptionAddressOrMask, EncryptionMask);
  287. ASSERT_RETURN_ERROR (PcdStatus);
  288. DEBUG ((DEBUG_INFO, "SEV is enabled (mask 0x%lx)\n", EncryptionMask));
  289. //
  290. // Set Pcd to Deny the execution of option ROM when security
  291. // violation.
  292. //
  293. PcdStatus = PcdSet32S (PcdOptionRomImageVerificationPolicy, 0x4);
  294. ASSERT_RETURN_ERROR (PcdStatus);
  295. //
  296. // When SMM is required, cover the pages containing the initial SMRAM Save
  297. // State Map with a memory allocation HOB:
  298. //
  299. // There's going to be a time interval between our decrypting those pages for
  300. // SMBASE relocation and re-encrypting the same pages after SMBASE
  301. // relocation. We shall ensure that the DXE phase stay away from those pages
  302. // until after re-encryption, in order to prevent an information leak to the
  303. // hypervisor.
  304. //
  305. if (mPlatformInfoHob.SmmSmramRequire && (mPlatformInfoHob.BootMode != BOOT_ON_S3_RESUME)) {
  306. RETURN_STATUS LocateMapStatus;
  307. UINTN MapPagesBase;
  308. UINTN MapPagesCount;
  309. LocateMapStatus = MemEncryptSevLocateInitialSmramSaveStateMapPages (
  310. &MapPagesBase,
  311. &MapPagesCount
  312. );
  313. ASSERT_RETURN_ERROR (LocateMapStatus);
  314. if (mPlatformInfoHob.Q35SmramAtDefaultSmbase) {
  315. //
  316. // The initial SMRAM Save State Map has been covered as part of a larger
  317. // reserved memory allocation in InitializeRamRegions().
  318. //
  319. ASSERT (SMM_DEFAULT_SMBASE <= MapPagesBase);
  320. ASSERT (
  321. (MapPagesBase + EFI_PAGES_TO_SIZE (MapPagesCount) <=
  322. SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE)
  323. );
  324. } else {
  325. BuildMemoryAllocationHob (
  326. MapPagesBase, // BaseAddress
  327. EFI_PAGES_TO_SIZE (MapPagesCount), // Length
  328. EfiBootServicesData // MemoryType
  329. );
  330. }
  331. }
  332. //
  333. // Check and perform SEV-ES initialization if required.
  334. //
  335. AmdSevEsInitialize ();
  336. //
  337. // Set the Confidential computing attr PCD to communicate which SEV
  338. // technology is active.
  339. //
  340. if (MemEncryptSevSnpIsEnabled ()) {
  341. PcdStatus = PcdSet64S (PcdConfidentialComputingGuestAttr, CCAttrAmdSevSnp);
  342. } else if (MemEncryptSevEsIsEnabled ()) {
  343. PcdStatus = PcdSet64S (PcdConfidentialComputingGuestAttr, CCAttrAmdSevEs);
  344. } else {
  345. PcdStatus = PcdSet64S (PcdConfidentialComputingGuestAttr, CCAttrAmdSev);
  346. }
  347. ASSERT_RETURN_ERROR (PcdStatus);
  348. }
  349. /**
  350. The function performs SEV specific region initialization.
  351. **/
  352. VOID
  353. SevInitializeRam (
  354. VOID
  355. )
  356. {
  357. if (MemEncryptSevSnpIsEnabled ()) {
  358. //
  359. // If SEV-SNP is enabled, reserve the Secrets and CPUID memory area.
  360. //
  361. // This memory range is given to the PSP by the hypervisor to populate
  362. // the information used during the SNP VM boots, and it need to persist
  363. // across the kexec boots. Mark it as EfiReservedMemoryType so that
  364. // the guest firmware and OS does not use it as a system memory.
  365. //
  366. BuildMemoryAllocationHob (
  367. (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfSnpSecretsBase),
  368. (UINT64)(UINTN)PcdGet32 (PcdOvmfSnpSecretsSize),
  369. EfiReservedMemoryType
  370. );
  371. BuildMemoryAllocationHob (
  372. (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfCpuidBase),
  373. (UINT64)(UINTN)PcdGet32 (PcdOvmfCpuidSize),
  374. EfiReservedMemoryType
  375. );
  376. }
  377. }