AmdSev.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  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. IN EFI_HOB_PLATFORM_INFO *PlatformInfoHob
  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 Status;
  177. IA32_DESCRIPTOR Gdtr;
  178. VOID *Gdt;
  179. if (!MemEncryptSevEsIsEnabled ()) {
  180. return;
  181. }
  182. Status = PcdSetBoolS (PcdSevEsIsEnabled, TRUE);
  183. ASSERT_RETURN_ERROR (Status);
  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 = PlatformInfoHob->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. Status = MemEncryptSevClearPageEncMask (
  200. 0,
  201. GhcbBasePa + EFI_PAGES_TO_SIZE (PageCount),
  202. 1
  203. );
  204. ASSERT_RETURN_ERROR (Status);
  205. }
  206. ZeroMem (GhcbBase, EFI_PAGES_TO_SIZE (GhcbPageCount));
  207. Status = PcdSet64S (PcdGhcbBase, GhcbBasePa);
  208. ASSERT_RETURN_ERROR (Status);
  209. Status = PcdSet64S (PcdGhcbSize, EFI_PAGES_TO_SIZE (GhcbPageCount));
  210. ASSERT_RETURN_ERROR (Status);
  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 = PlatformInfoHob->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. // Now that the PEI GHCB is set up, the SEC GHCB page is no longer necessary
  246. // to keep shared. Later, it is exposed to the OS as EfiConventionalMemory, so
  247. // it needs to be marked private. The size of the region is hardcoded in
  248. // OvmfPkg/ResetVector/ResetVector.nasmb in the definition of
  249. // SNP_SEC_MEM_BASE_DESC_2.
  250. //
  251. Status = MemEncryptSevSetPageEncMask (
  252. 0, // Cr3 -- use system Cr3
  253. FixedPcdGet32 (PcdOvmfSecGhcbBase), // BaseAddress
  254. 1 // NumPages
  255. );
  256. ASSERT_RETURN_ERROR (Status);
  257. //
  258. // The SEV support will clear the C-bit from non-RAM areas. The early GDT
  259. // lives in a non-RAM area, so when an exception occurs (like a #VC) the GDT
  260. // will be read as un-encrypted even though it was created before the C-bit
  261. // was cleared (encrypted). This will result in a failure to be able to
  262. // handle the exception.
  263. //
  264. AsmReadGdtr (&Gdtr);
  265. Gdt = AllocatePages (EFI_SIZE_TO_PAGES ((UINTN)Gdtr.Limit + 1));
  266. ASSERT (Gdt != NULL);
  267. CopyMem (Gdt, (VOID *)Gdtr.Base, Gdtr.Limit + 1);
  268. Gdtr.Base = (UINTN)Gdt;
  269. AsmWriteGdtr (&Gdtr);
  270. }
  271. /**
  272. Function checks if SEV support is available, if present then it sets
  273. the dynamic PcdPteMemoryEncryptionAddressOrMask with memory encryption mask.
  274. **/
  275. VOID
  276. AmdSevInitialize (
  277. IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob
  278. )
  279. {
  280. UINT64 EncryptionMask;
  281. RETURN_STATUS PcdStatus;
  282. //
  283. // Check if SEV is enabled
  284. //
  285. if (!MemEncryptSevIsEnabled ()) {
  286. return;
  287. }
  288. //
  289. // Check and perform SEV-SNP initialization if required. This need to be
  290. // done before the GHCB page is made shared in the AmdSevEsInitialize(). This
  291. // is because the system RAM must be validated before it is made shared.
  292. // The AmdSevSnpInitialize() validates the system RAM.
  293. //
  294. AmdSevSnpInitialize ();
  295. //
  296. // Set Memory Encryption Mask PCD
  297. //
  298. EncryptionMask = MemEncryptSevGetEncryptionMask ();
  299. PcdStatus = PcdSet64S (PcdPteMemoryEncryptionAddressOrMask, EncryptionMask);
  300. ASSERT_RETURN_ERROR (PcdStatus);
  301. DEBUG ((DEBUG_INFO, "SEV is enabled (mask 0x%lx)\n", EncryptionMask));
  302. //
  303. // Set Pcd to Deny the execution of option ROM when security
  304. // violation.
  305. //
  306. PcdStatus = PcdSet32S (PcdOptionRomImageVerificationPolicy, 0x4);
  307. ASSERT_RETURN_ERROR (PcdStatus);
  308. //
  309. // When SMM is required, cover the pages containing the initial SMRAM Save
  310. // State Map with a memory allocation HOB:
  311. //
  312. // There's going to be a time interval between our decrypting those pages for
  313. // SMBASE relocation and re-encrypting the same pages after SMBASE
  314. // relocation. We shall ensure that the DXE phase stay away from those pages
  315. // until after re-encryption, in order to prevent an information leak to the
  316. // hypervisor.
  317. //
  318. if (PlatformInfoHob->SmmSmramRequire && (PlatformInfoHob->BootMode != BOOT_ON_S3_RESUME)) {
  319. RETURN_STATUS LocateMapStatus;
  320. UINTN MapPagesBase;
  321. UINTN MapPagesCount;
  322. LocateMapStatus = MemEncryptSevLocateInitialSmramSaveStateMapPages (
  323. &MapPagesBase,
  324. &MapPagesCount
  325. );
  326. ASSERT_RETURN_ERROR (LocateMapStatus);
  327. if (PlatformInfoHob->Q35SmramAtDefaultSmbase) {
  328. //
  329. // The initial SMRAM Save State Map has been covered as part of a larger
  330. // reserved memory allocation in InitializeRamRegions().
  331. //
  332. ASSERT (SMM_DEFAULT_SMBASE <= MapPagesBase);
  333. ASSERT (
  334. (MapPagesBase + EFI_PAGES_TO_SIZE (MapPagesCount) <=
  335. SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE)
  336. );
  337. } else {
  338. BuildMemoryAllocationHob (
  339. MapPagesBase, // BaseAddress
  340. EFI_PAGES_TO_SIZE (MapPagesCount), // Length
  341. EfiBootServicesData // MemoryType
  342. );
  343. }
  344. }
  345. //
  346. // Check and perform SEV-ES initialization if required.
  347. //
  348. AmdSevEsInitialize (PlatformInfoHob);
  349. //
  350. // Set the Confidential computing attr PCD to communicate which SEV
  351. // technology is active.
  352. //
  353. if (MemEncryptSevSnpIsEnabled ()) {
  354. PcdStatus = PcdSet64S (PcdConfidentialComputingGuestAttr, CCAttrAmdSevSnp);
  355. } else if (MemEncryptSevEsIsEnabled ()) {
  356. PcdStatus = PcdSet64S (PcdConfidentialComputingGuestAttr, CCAttrAmdSevEs);
  357. } else {
  358. PcdStatus = PcdSet64S (PcdConfidentialComputingGuestAttr, CCAttrAmdSev);
  359. }
  360. ASSERT_RETURN_ERROR (PcdStatus);
  361. }
  362. /**
  363. The function performs SEV specific region initialization.
  364. **/
  365. VOID
  366. SevInitializeRam (
  367. VOID
  368. )
  369. {
  370. if (MemEncryptSevSnpIsEnabled ()) {
  371. //
  372. // If SEV-SNP is enabled, reserve the Secrets and CPUID memory area.
  373. //
  374. // This memory range is given to the PSP by the hypervisor to populate
  375. // the information used during the SNP VM boots, and it need to persist
  376. // across the kexec boots. Mark it as EfiReservedMemoryType so that
  377. // the guest firmware and OS does not use it as a system memory.
  378. //
  379. BuildMemoryAllocationHob (
  380. (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfSnpSecretsBase),
  381. (UINT64)(UINTN)PcdGet32 (PcdOvmfSnpSecretsSize),
  382. EfiReservedMemoryType
  383. );
  384. BuildMemoryAllocationHob (
  385. (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfCpuidBase),
  386. (UINT64)(UINTN)PcdGet32 (PcdOvmfCpuidSize),
  387. EfiReservedMemoryType
  388. );
  389. }
  390. }