BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275 The Flush parameter is used to provide a hint whether the specified range is Mmio address. Now that we have a dedicated helper to clear the memory encryption mask for the Mmio address range, its safe to remove the Flush parameter from MemEncryptSev{Set,Clear}PageEncMask(). Since the address specified in the MemEncryptSev{Set,Clear}PageEncMask() points to a system RAM, thus a cache flush is required during the encryption mask update. Cc: James Bottomley <jejb@linux.ibm.com> Cc: Min Xu <min.m.xu@intel.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org> Cc: Laszlo Ersek <lersek@redhat.com> Cc: Erdem Aktas <erdemaktas@google.com> Reviewed-by: Laszlo Ersek <lersek@redhat.com> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com> Message-Id: <20210519181949.6574-14-brijesh.singh@amd.com>
		
			
				
	
	
		
			213 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			213 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /**@file
 | |
|   Initialize Secure Encrypted Virtualization (SEV) support
 | |
| 
 | |
|   Copyright (c) 2017 - 2020, Advanced Micro Devices. All rights reserved.<BR>
 | |
| 
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| //
 | |
| // The package level header files this module uses
 | |
| //
 | |
| #include <IndustryStandard/Q35MchIch9.h>
 | |
| #include <Library/BaseMemoryLib.h>
 | |
| #include <Library/DebugLib.h>
 | |
| #include <Library/HobLib.h>
 | |
| #include <Library/MemEncryptSevLib.h>
 | |
| #include <Library/MemoryAllocationLib.h>
 | |
| #include <Library/PcdLib.h>
 | |
| #include <PiPei.h>
 | |
| #include <Register/Amd/Msr.h>
 | |
| #include <Register/Intel/SmramSaveStateMap.h>
 | |
| 
 | |
| #include "Platform.h"
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Initialize SEV-ES support if running as an SEV-ES guest.
 | |
| 
 | |
|   **/
 | |
| STATIC
 | |
| VOID
 | |
| AmdSevEsInitialize (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   UINT8                *GhcbBase;
 | |
|   PHYSICAL_ADDRESS     GhcbBasePa;
 | |
|   UINTN                GhcbPageCount;
 | |
|   UINT8                *GhcbBackupBase;
 | |
|   UINT8                *GhcbBackupPages;
 | |
|   UINTN                GhcbBackupPageCount;
 | |
|   SEV_ES_PER_CPU_DATA  *SevEsData;
 | |
|   UINTN                PageCount;
 | |
|   RETURN_STATUS        PcdStatus, DecryptStatus;
 | |
|   IA32_DESCRIPTOR      Gdtr;
 | |
|   VOID                 *Gdt;
 | |
| 
 | |
|   if (!MemEncryptSevEsIsEnabled ()) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   PcdStatus = PcdSetBoolS (PcdSevEsIsEnabled, TRUE);
 | |
|   ASSERT_RETURN_ERROR (PcdStatus);
 | |
| 
 | |
|   //
 | |
|   // Allocate GHCB and per-CPU variable pages.
 | |
|   //   Since the pages must survive across the UEFI to OS transition
 | |
|   //   make them reserved.
 | |
|   //
 | |
|   GhcbPageCount = mMaxCpuCount * 2;
 | |
|   GhcbBase = AllocateReservedPages (GhcbPageCount);
 | |
|   ASSERT (GhcbBase != NULL);
 | |
| 
 | |
|   GhcbBasePa = (PHYSICAL_ADDRESS)(UINTN) GhcbBase;
 | |
| 
 | |
|   //
 | |
|   // Each vCPU gets two consecutive pages, the first is the GHCB and the
 | |
|   // second is the per-CPU variable page. Loop through the allocation and
 | |
|   // only clear the encryption mask for the GHCB pages.
 | |
|   //
 | |
|   for (PageCount = 0; PageCount < GhcbPageCount; PageCount += 2) {
 | |
|     DecryptStatus = MemEncryptSevClearPageEncMask (
 | |
|       0,
 | |
|       GhcbBasePa + EFI_PAGES_TO_SIZE (PageCount),
 | |
|       1
 | |
|       );
 | |
|     ASSERT_RETURN_ERROR (DecryptStatus);
 | |
|   }
 | |
| 
 | |
|   ZeroMem (GhcbBase, EFI_PAGES_TO_SIZE (GhcbPageCount));
 | |
| 
 | |
|   PcdStatus = PcdSet64S (PcdGhcbBase, GhcbBasePa);
 | |
|   ASSERT_RETURN_ERROR (PcdStatus);
 | |
|   PcdStatus = PcdSet64S (PcdGhcbSize, EFI_PAGES_TO_SIZE (GhcbPageCount));
 | |
|   ASSERT_RETURN_ERROR (PcdStatus);
 | |
| 
 | |
|   DEBUG ((DEBUG_INFO,
 | |
|     "SEV-ES is enabled, %lu GHCB pages allocated starting at 0x%p\n",
 | |
|     (UINT64)GhcbPageCount, GhcbBase));
 | |
| 
 | |
|   //
 | |
|   // Allocate #VC recursion backup pages. The number of backup pages needed is
 | |
|   // one less than the maximum VC count.
 | |
|   //
 | |
|   GhcbBackupPageCount = mMaxCpuCount * (VMGEXIT_MAXIMUM_VC_COUNT - 1);
 | |
|   GhcbBackupBase = AllocatePages (GhcbBackupPageCount);
 | |
|   ASSERT (GhcbBackupBase != NULL);
 | |
| 
 | |
|   GhcbBackupPages = GhcbBackupBase;
 | |
|   for (PageCount = 1; PageCount < GhcbPageCount; PageCount += 2) {
 | |
|     SevEsData =
 | |
|       (SEV_ES_PER_CPU_DATA *)(GhcbBase + EFI_PAGES_TO_SIZE (PageCount));
 | |
|     SevEsData->GhcbBackupPages = GhcbBackupPages;
 | |
| 
 | |
|     GhcbBackupPages += EFI_PAGE_SIZE * (VMGEXIT_MAXIMUM_VC_COUNT - 1);
 | |
|   }
 | |
| 
 | |
|   DEBUG ((DEBUG_INFO,
 | |
|     "SEV-ES is enabled, %lu GHCB backup pages allocated starting at 0x%p\n",
 | |
|     (UINT64)GhcbBackupPageCount, GhcbBackupBase));
 | |
| 
 | |
|   AsmWriteMsr64 (MSR_SEV_ES_GHCB, GhcbBasePa);
 | |
| 
 | |
|   //
 | |
|   // The SEV support will clear the C-bit from non-RAM areas.  The early GDT
 | |
|   // lives in a non-RAM area, so when an exception occurs (like a #VC) the GDT
 | |
|   // will be read as un-encrypted even though it was created before the C-bit
 | |
|   // was cleared (encrypted). This will result in a failure to be able to
 | |
|   // handle the exception.
 | |
|   //
 | |
|   AsmReadGdtr (&Gdtr);
 | |
| 
 | |
|   Gdt = AllocatePages (EFI_SIZE_TO_PAGES ((UINTN) Gdtr.Limit + 1));
 | |
|   ASSERT (Gdt != NULL);
 | |
| 
 | |
|   CopyMem (Gdt, (VOID *) Gdtr.Base, Gdtr.Limit + 1);
 | |
|   Gdtr.Base = (UINTN) Gdt;
 | |
|   AsmWriteGdtr (&Gdtr);
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Function checks if SEV support is available, if present then it sets
 | |
|   the dynamic PcdPteMemoryEncryptionAddressOrMask with memory encryption mask.
 | |
| 
 | |
|   **/
 | |
| VOID
 | |
| AmdSevInitialize (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   UINT64                            EncryptionMask;
 | |
|   RETURN_STATUS                     PcdStatus;
 | |
| 
 | |
|   //
 | |
|   // Check if SEV is enabled
 | |
|   //
 | |
|   if (!MemEncryptSevIsEnabled ()) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Set Memory Encryption Mask PCD
 | |
|   //
 | |
|   EncryptionMask = MemEncryptSevGetEncryptionMask ();
 | |
|   PcdStatus = PcdSet64S (PcdPteMemoryEncryptionAddressOrMask, EncryptionMask);
 | |
|   ASSERT_RETURN_ERROR (PcdStatus);
 | |
| 
 | |
|   DEBUG ((DEBUG_INFO, "SEV is enabled (mask 0x%lx)\n", EncryptionMask));
 | |
| 
 | |
|   //
 | |
|   // Set Pcd to Deny the execution of option ROM when security
 | |
|   // violation.
 | |
|   //
 | |
|   PcdStatus = PcdSet32S (PcdOptionRomImageVerificationPolicy, 0x4);
 | |
|   ASSERT_RETURN_ERROR (PcdStatus);
 | |
| 
 | |
|   //
 | |
|   // When SMM is required, cover the pages containing the initial SMRAM Save
 | |
|   // State Map with a memory allocation HOB:
 | |
|   //
 | |
|   // There's going to be a time interval between our decrypting those pages for
 | |
|   // SMBASE relocation and re-encrypting the same pages after SMBASE
 | |
|   // relocation. We shall ensure that the DXE phase stay away from those pages
 | |
|   // until after re-encryption, in order to prevent an information leak to the
 | |
|   // hypervisor.
 | |
|   //
 | |
|   if (FeaturePcdGet (PcdSmmSmramRequire) && (mBootMode != BOOT_ON_S3_RESUME)) {
 | |
|     RETURN_STATUS LocateMapStatus;
 | |
|     UINTN         MapPagesBase;
 | |
|     UINTN         MapPagesCount;
 | |
| 
 | |
|     LocateMapStatus = MemEncryptSevLocateInitialSmramSaveStateMapPages (
 | |
|                         &MapPagesBase,
 | |
|                         &MapPagesCount
 | |
|                         );
 | |
|     ASSERT_RETURN_ERROR (LocateMapStatus);
 | |
| 
 | |
|     if (mQ35SmramAtDefaultSmbase) {
 | |
|       //
 | |
|       // The initial SMRAM Save State Map has been covered as part of a larger
 | |
|       // reserved memory allocation in InitializeRamRegions().
 | |
|       //
 | |
|       ASSERT (SMM_DEFAULT_SMBASE <= MapPagesBase);
 | |
|       ASSERT (
 | |
|         (MapPagesBase + EFI_PAGES_TO_SIZE (MapPagesCount) <=
 | |
|          SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE)
 | |
|         );
 | |
|     } else {
 | |
|       BuildMemoryAllocationHob (
 | |
|         MapPagesBase,                      // BaseAddress
 | |
|         EFI_PAGES_TO_SIZE (MapPagesCount), // Length
 | |
|         EfiBootServicesData                // MemoryType
 | |
|         );
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Check and perform SEV-ES initialization if required.
 | |
|   //
 | |
|   AmdSevEsInitialize ();
 | |
| }
 |