AmdSev.c 13 KB

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