On 05/22/17 17:23, Brijesh Singh wrote: > Add Secure Encrypted Virtualization (SEV) helper library. > The library provides the routines to: > - set or clear memory encryption bit for a given memory region. > - query whether SEV is enabled. > > > Cc: Jordan Justen <[email protected]> > Cc: Laszlo Ersek <[email protected]> > Contributed-under: TianoCore Contribution Agreement 1.0 > Signed-off-by: Brijesh Singh <[email protected]> > Reviewed-by: Laszlo Ersek <[email protected]> > --- > OvmfPkg/OvmfPkgIa32.dsc | 1 + > OvmfPkg/OvmfPkgIa32X64.dsc | 1 + > OvmfPkg/OvmfPkgX64.dsc | 1 + > OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf | 50 +++ > OvmfPkg/Include/Library/MemEncryptSevLib.h | 81 ++++ > OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.h | 184 > +++++++++ > OvmfPkg/Library/BaseMemEncryptSevLib/Ia32/MemEncryptSevLib.c | 84 ++++ > OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c | 90 ++++ > OvmfPkg/Library/BaseMemEncryptSevLib/X64/MemEncryptSevLib.c | 84 ++++ > OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c | 428 > ++++++++++++++++++++ > 10 files changed, 1004 insertions(+)
I have some comments for the case if you have to post a v6. Right now a v6 is not needed just for these comments. (1) In <[email protected]">http://mid.mail-archive.com/[email protected]> I mentioned "Since this is a BASE library, please don't use EFI_STATUS, EFI_INVALID_PARAMETER, EFI_NO_MAPPING, EFI_SUCCESS; use RETURN_xxx instead." You replaced most of them, but you left in "EFI_STATUS". That should be "RETURN_STATUS". (2) please check the lines where you added (as I asked, thanks) gEfiCallerBaseName and __FUNCTION__. On most lines, the indentation is incorrect, relative to "DEBUG ((". (3) Furthermore, in some spots where you added __FUNCTION__, you forgot to add a space after the comma. Again, no need to resubmit just because of this, but if you do resubmit anyway, these should be fixed up. Thanks Laszlo > diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc > index f3889c29f426..25b7d73807b6 100644 > --- a/OvmfPkg/OvmfPkgIa32.dsc > +++ b/OvmfPkg/OvmfPkgIa32.dsc > @@ -143,6 +143,7 @@ [LibraryClasses] > QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf > VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf > LoadLinuxLib|OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf > + > MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf > !if $(SMM_REQUIRE) == FALSE > LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf > !endif > diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc > index 2aaa21f79e49..88bf73b3fa01 100644 > --- a/OvmfPkg/OvmfPkgIa32X64.dsc > +++ b/OvmfPkg/OvmfPkgIa32X64.dsc > @@ -148,6 +148,7 @@ [LibraryClasses] > QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf > VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf > LoadLinuxLib|OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf > + > MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf > !if $(SMM_REQUIRE) == FALSE > LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf > !endif > diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc > index b1e35942ba03..b34fed16a860 100644 > --- a/OvmfPkg/OvmfPkgX64.dsc > +++ b/OvmfPkg/OvmfPkgX64.dsc > @@ -148,6 +148,7 @@ [LibraryClasses] > QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf > VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf > LoadLinuxLib|OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf > + > MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf > !if $(SMM_REQUIRE) == FALSE > LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf > !endif > diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf > b/OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf > new file mode 100644 > index 000000000000..3cfd80a28c1d > --- /dev/null > +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf > @@ -0,0 +1,50 @@ > +## @file > +# Library provides the helper functions for SEV guest > +# > +# Copyright (c) 2017 Advanced Micro Devices. All rights reserved.<BR> > +# > +# This program and the accompanying materials > +# are licensed and made available under the terms and conditions of the BSD > +# License which accompanies this distribution. The full text of the license > +# may be found at http://opensource.org/licenses/bsd-license.php > +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR > IMPLIED. > +# > +# > +## > + > +[Defines] > + INF_VERSION = 1.25 > + BASE_NAME = MemEncryptSevLib > + FILE_GUID = c1594631-3888-4be4-949f-9c630dbc842b > + MODULE_TYPE = BASE > + VERSION_STRING = 1.0 > + LIBRARY_CLASS = MemEncryptSevLib|PEIM DXE_DRIVER > DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_DRIVER > + > +# > +# The following information is for reference only and not required by the > build tools. > +# > +# VALID_ARCHITECTURES = IA32 X64 > +# > + > +[Packages] > + MdePkg/MdePkg.dec > + MdeModulePkg/MdeModulePkg.dec > + OvmfPkg/OvmfPkg.dec > + UefiCpuPkg/UefiCpuPkg.dec > + > +[Sources.X64] > + MemEncryptSevLibInternal.c > + X64/MemEncryptSevLib.c > + X64/VirtualMemory.c > + > +[Sources.IA32] > + MemEncryptSevLibInternal.c > + Ia32/MemEncryptSevLib.c > + > +[LibraryClasses] > + BaseLib > + CpuLib > + CacheMaintenanceLib > + DebugLib > + MemoryAllocationLib > diff --git a/OvmfPkg/Include/Library/MemEncryptSevLib.h > b/OvmfPkg/Include/Library/MemEncryptSevLib.h > new file mode 100644 > index 000000000000..b6753762423e > --- /dev/null > +++ b/OvmfPkg/Include/Library/MemEncryptSevLib.h > @@ -0,0 +1,81 @@ > +/** @file > + > + Define Secure Encrypted Virtualization (SEV) base library helper function > + > + Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR> > + > + This program and the accompanying materials are licensed and made available > + under the terms and conditions of the BSD License which accompanies this > + distribution. The full text of the license may be found at > + http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR > IMPLIED. > + > +**/ > + > +#ifndef _MEM_ENCRYPT_SEV_LIB_H_ > +#define _MEM_ENCRYPT_SEV_LIB_H_ > + > +#include <Base.h> > + > +/** > + Returns a boolean to indicate whether SEV is enabled > + > + @retval TRUE SEV is active > + @retval FALSE SEV is not enabled > + **/ > +BOOLEAN > +EFIAPI > +MemEncryptSevIsEnabled ( > + VOID > + ); > + > +/** > + This function clears memory encryption bit for the memory region specified > + by BaseAddress and Number of pages from the current page table context. > + > + @param[in] BaseAddress The physical address that is the start > address > + of a memory region. > + @param[in] NumberOfPages The number of pages from start memory > region. > + @param[in] Flush Flush the caches before clearing the bit > + (mostly TRUE except MMIO addresses) > + > + @retval RETURN_SUCCESS The attributes were cleared for the > memory region. > + @retval RETURN_INVALID_PARAMETER Number of pages is zero. > + @retval RETURN_UNSUPPORTED Clearing memory encryption attribute is > not > + supported > + **/ > +RETURN_STATUS > +EFIAPI > +MemEncryptSevClearPageEncMask ( > + IN PHYSICAL_ADDRESS Cr3BaseAddress, > + IN PHYSICAL_ADDRESS BaseAddress, > + IN UINTN NumberOfPages, > + IN BOOLEAN CacheFlush > + ); > + > +/** > + This function sets memory encryption bit for the memory region specified by > + BaseAddress and Number of pages from the current page table context. > + > + @param[in] BaseAddress The physical address that is the start > address > + of a memory region. > + @param[in] NumberOfPages The number of pages from start memory > region. > + @param[in] Flush Flush the caches before clearing the bit > + (mostly TRUE except MMIO addresses) > + > + @retval RETURN_SUCCESS The attributes were set for the memory > region. > + @retval RETURN_INVALID_PARAMETER Number of pages is zero. > + @retval RETURN_UNSUPPORTED Clearing memory encryption attribute is > not > + supported > + **/ > +RETURN_STATUS > +EFIAPI > +MemEncryptSevSetPageEncMask ( > + IN PHYSICAL_ADDRESS Cr3BaseAddress, > + IN PHYSICAL_ADDRESS BaseAddress, > + IN UINTN NumberOfPages, > + IN BOOLEAN CacheFlush > + ); > +#endif // _MEM_ENCRYPT_SEV_LIB_H_ > diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.h > b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.h > new file mode 100644 > index 000000000000..808a386ca07a > --- /dev/null > +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.h > @@ -0,0 +1,184 @@ > +/** @file > + > + Virtual Memory Management Services to set or clear the memory encryption > bit > + > +Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR> > +Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR> > + > +This program and the accompanying materials > +are licensed and made available under the terms and conditions of the BSD > License > +which accompanies this distribution. The full text of the license may be > found at > +http://opensource.org/licenses/bsd-license.php > + > +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + > +Code is derived from MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h > + > +**/ > + > +#ifndef __VIRTUAL_MEMORY__ > +#define __VIRTUAL_MEMORY__ > + > +#include <Uefi.h> > +#include <Library/BaseLib.h> > +#include <Library/BaseMemoryLib.h> > +#include <Library/DebugLib.h> > +#include <Library/MemoryAllocationLib.h> > + > +#include <Library/CacheMaintenanceLib.h> > +#define SYS_CODE64_SEL 0x38 > + > +#pragma pack(1) > + > +// > +// Page-Map Level-4 Offset (PML4) and > +// Page-Directory-Pointer Offset (PDPE) entries 4K & 2MB > +// > + > +typedef union { > + struct { > + UINT64 Present:1; // 0 = Not present in memory, 1 = > Present in memory > + UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write > + UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User > + UINT64 WriteThrough:1; // 0 = Write-Back caching, > 1=Write-Through caching > + UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached > + UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set > by CPU) > + UINT64 Reserved:1; // Reserved > + UINT64 MustBeZero:2; // Must Be Zero > + UINT64 Available:3; // Available for use by system software > + UINT64 PageTableBaseAddress:40; // Page Table Base Address > + UINT64 AvabilableHigh:11; // Available for use by system software > + UINT64 Nx:1; // No Execute bit > + } Bits; > + UINT64 Uint64; > +} PAGE_MAP_AND_DIRECTORY_POINTER; > + > +// > +// Page Table Entry 4KB > +// > +typedef union { > + struct { > + UINT64 Present:1; // 0 = Not present in memory, 1 = > Present in memory > + UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write > + UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User > + UINT64 WriteThrough:1; // 0 = Write-Back caching, > 1=Write-Through caching > + UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached > + UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set > by CPU) > + UINT64 Dirty:1; // 0 = Not Dirty, 1 = written by > processor on access to page > + UINT64 PAT:1; // > + UINT64 Global:1; // 0 = Not global page, 1 = global > page TLB not cleared on CR3 write > + UINT64 Available:3; // Available for use by system software > + UINT64 PageTableBaseAddress:40; // Page Table Base Address > + UINT64 AvabilableHigh:11; // Available for use by system software > + UINT64 Nx:1; // 0 = Execute Code, 1 = No Code > Execution > + } Bits; > + UINT64 Uint64; > +} PAGE_TABLE_4K_ENTRY; > + > +// > +// Page Table Entry 2MB > +// > +typedef union { > + struct { > + UINT64 Present:1; // 0 = Not present in memory, 1 = > Present in memory > + UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write > + UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User > + UINT64 WriteThrough:1; // 0 = Write-Back caching, > 1=Write-Through caching > + UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached > + UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set > by CPU) > + UINT64 Dirty:1; // 0 = Not Dirty, 1 = written by > processor on access to page > + UINT64 MustBe1:1; // Must be 1 > + UINT64 Global:1; // 0 = Not global page, 1 = global > page TLB not cleared on CR3 write > + UINT64 Available:3; // Available for use by system software > + UINT64 PAT:1; // > + UINT64 MustBeZero:8; // Must be zero; > + UINT64 PageTableBaseAddress:31; // Page Table Base Address > + UINT64 AvabilableHigh:11; // Available for use by system software > + UINT64 Nx:1; // 0 = Execute Code, 1 = No Code > Execution > + } Bits; > + UINT64 Uint64; > +} PAGE_TABLE_ENTRY; > + > +// > +// Page Table Entry 1GB > +// > +typedef union { > + struct { > + UINT64 Present:1; // 0 = Not present in memory, 1 = > Present in memory > + UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write > + UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User > + UINT64 WriteThrough:1; // 0 = Write-Back caching, > 1=Write-Through caching > + UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached > + UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set > by CPU) > + UINT64 Dirty:1; // 0 = Not Dirty, 1 = written by > processor on access to page > + UINT64 MustBe1:1; // Must be 1 > + UINT64 Global:1; // 0 = Not global page, 1 = global > page TLB not cleared on CR3 write > + UINT64 Available:3; // Available for use by system software > + UINT64 PAT:1; // > + UINT64 MustBeZero:17; // Must be zero; > + UINT64 PageTableBaseAddress:22; // Page Table Base Address > + UINT64 AvabilableHigh:11; // Available for use by system software > + UINT64 Nx:1; // 0 = Execute Code, 1 = No Code > Execution > + } Bits; > + UINT64 Uint64; > +} PAGE_TABLE_1G_ENTRY; > + > +#pragma pack() > + > +#define IA32_PG_P BIT0 > +#define IA32_PG_RW BIT1 > + > +#define PAGETABLE_ENTRY_MASK ((1UL << 9) - 1) > +#define PML4_OFFSET(x) ( (x >> 39) & PAGETABLE_ENTRY_MASK) > +#define PDP_OFFSET(x) ( (x >> 30) & PAGETABLE_ENTRY_MASK) > +#define PDE_OFFSET(x) ( (x >> 21) & PAGETABLE_ENTRY_MASK) > +#define PTE_OFFSET(x) ( (x >> 12) & PAGETABLE_ENTRY_MASK) > +#define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull > + > +/** > + This function clears memory encryption bit for the memory region specified > by PhysicalAddress > + and length from the current page table context. > + > + @param[in] PhysicalAddress The physical address that is the start > address of a memory region. > + @param[in] Length The length of memory region > + @param[in] Flush Flush the caches before applying the > encryption mask > + > + @retval RETURN_SUCCESS The attributes were cleared for the > memory region. > + @retval RETURN_INVALID_PARAMETER Number of pages is zero. > + @retval RETURN_UNSUPPORTED Setting the memory encyrption > attribute is not supported > +**/ > +EFI_STATUS > +EFIAPI > +InternalMemEncryptSevSetMemoryDecrypted ( > + IN PHYSICAL_ADDRESS Cr3BaseAddress, > + IN PHYSICAL_ADDRESS PhysicalAddress, > + IN UINT64 Length, > + IN BOOLEAN CacheFlush > + ); > + > +/** > + This function sets memory encryption bit for the memory region specified by > + PhysicalAddress and length from the current page table context. > + > + @param[in] PhysicalAddress The physical address that is the start > address > + of a memory region. > + @param[in] Length The length of memory region > + @param[in] Flush Flush the caches before applying the > + encryption mask > + > + @retval RETURN_SUCCESS The attributes were cleared for the > memory region. > + @retval RETURN_INVALID_PARAMETER Number of pages is zero. > + @retval RETURN_UNSUPPORTED Setting the memory encyrption > attribute is > + not supported > +**/ > +EFI_STATUS > +EFIAPI > +InternalMemEncryptSevSetMemoryEncrypted ( > + IN PHYSICAL_ADDRESS Cr3BaseAddress, > + IN PHYSICAL_ADDRESS PhysicalAddress, > + IN UINT64 Length, > + IN BOOLEAN CacheFlush > + ); > + > +#endif > diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/Ia32/MemEncryptSevLib.c > b/OvmfPkg/Library/BaseMemEncryptSevLib/Ia32/MemEncryptSevLib.c > new file mode 100644 > index 000000000000..a2ea99019917 > --- /dev/null > +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/Ia32/MemEncryptSevLib.c > @@ -0,0 +1,84 @@ > +/** @file > + > + Secure Encrypted Virtualization (SEV) library helper function > + > + Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR> > + > + This program and the accompanying materials > + are licensed and made available under the terms and conditions of the BSD > + License which accompanies this distribution. The full text of the license > may > + be found at http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR > IMPLIED. > + > +**/ > + > +#include <Library/BaseLib.h> > +#include <Library/DebugLib.h> > +#include <Register/Cpuid.h> > +#include <Register/Amd/Cpuid.h> > +#include <Register/Amd/Msr.h> > +#include <Library/MemEncryptSevLib.h> > + > +/** > + This function clears memory encryption bit for the memory region specified > + by BaseAddress and Number of pages from the current page table context. > + > + @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use > current CR3) > + @param[in] BaseAddress The physical address that is the start > address > + of a memory region. > + @param[in] NumberOfPages The number of pages from start memory > region. > + @param[in] Flush Flush the caches before clearing the bit > + (mostly TRUE except MMIO addresses) > + > + @retval RETURN_SUCCESS The attributes were cleared for the > memory region. > + @retval RETURN_INVALID_PARAMETER Number of pages is zero. > + @retval RETURN_UNSUPPORTED Clearing memory encryption attribute is > not > + supported > + **/ > +RETURN_STATUS > +EFIAPI > +MemEncryptSevClearPageEncMask ( > + IN PHYSICAL_ADDRESS Cr3BaseAddress, > + IN PHYSICAL_ADDRESS BaseAddress, > + IN UINTN NumberOfPages, > + IN BOOLEAN Flush > + ) > +{ > + // > + // Memory encryption bit is not accessible in 32-bit mode > + // > + return RETURN_UNSUPPORTED; > +} > + > +/** > + This function sets memory encryption bit for the memory region specified by > + BaseAddress and Number of pages from the current page table context. > + > + @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use > current CR3) > + @param[in] BaseAddress The physical address that is the start > address > + of a memory region. > + @param[in] NumberOfPages The number of pages from start memory > region. > + @param[in] Flush Flush the caches before clearing the bit > + (mostly TRUE except MMIO addresses) > + > + @retval RETURN_SUCCESS The attributes were set for the memory > region. > + @retval RETURN_INVALID_PARAMETER Number of pages is zero. > + @retval RETURN_UNSUPPORTED Clearing memory encryption attribute is > not > + supported > + **/ > +RETURN_STATUS > +EFIAPI > +MemEncryptSevSetPageEncMask ( > + IN PHYSICAL_ADDRESS Cr3BaseAddress, > + IN PHYSICAL_ADDRESS BaseAddress, > + IN UINTN NumberOfPages, > + IN BOOLEAN Flush > + ) > +{ > + // > + // Memory encryption bit is not accessible in 32-bit mode > + // > + return RETURN_UNSUPPORTED; > +} > diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c > b/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c > new file mode 100644 > index 000000000000..002f079c7eb3 > --- /dev/null > +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/MemEncryptSevLibInternal.c > @@ -0,0 +1,90 @@ > +/** @file > + > + Secure Encrypted Virtualization (SEV) library helper function > + > + Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR> > + > + This program and the accompanying materials > + are licensed and made available under the terms and conditions of the BSD > + License which accompanies this distribution. The full text of the license > may > + be found at http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR > IMPLIED. > + > +**/ > + > +#include <Library/BaseLib.h> > +#include <Library/DebugLib.h> > +#include <Register/Cpuid.h> > +#include <Register/Amd/Cpuid.h> > +#include <Register/Amd/Msr.h> > +#include <Library/MemEncryptSevLib.h> > + > +STATIC BOOLEAN mSevStatus = FALSE; > +STATIC BOOLEAN mSevStatusChecked = FALSE; > + > +/** > + > + Returns a boolean to indicate whether SEV is enabled > + > + @retval TRUE SEV is enabled > + @retval FALSE SEV is not enabled > + **/ > +STATIC > +BOOLEAN > +EFIAPI > +InternalMemEncryptSevIsEnabled ( > + VOID > + ) > +{ > + UINT32 RegEax; > + MSR_SEV_STATUS_REGISTER Msr; > + CPUID_MEMORY_ENCRYPTION_INFO_EAX Eax; > + > + // > + // Check if memory encryption leaf exist > + // > + AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL); > + if (RegEax >= CPUID_MEMORY_ENCRYPTION_INFO) { > + // > + // CPUID Fn8000_001F[EAX] Bit 1 (Sev supported) > + // > + AsmCpuid (CPUID_MEMORY_ENCRYPTION_INFO, &Eax.Uint32, NULL, NULL, NULL); > + > + if (Eax.Bits.SevBit) { > + // > + // Check MSR_0xC0010131 Bit 0 (Sev Enabled) > + // > + Msr.Uint32 = AsmReadMsr32 (MSR_SEV_STATUS); > + if (Msr.Bits.SevBit) { > + return TRUE; > + } > + } > + } > + > + return FALSE; > +} > + > +/** > + > + Returns a boolean to indicate whether SEV is enabled > + > + @retval TRUE SEV is enabled > + @retval FALSE SEV is not enabled > + **/ > +BOOLEAN > +EFIAPI > +MemEncryptSevIsEnabled ( > + VOID > + ) > +{ > + if (mSevStatusChecked) { > + return mSevStatus; > + } > + > + mSevStatus = InternalMemEncryptSevIsEnabled(); > + mSevStatusChecked = TRUE; > + > + return mSevStatus; > +} > diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/MemEncryptSevLib.c > b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/MemEncryptSevLib.c > new file mode 100644 > index 000000000000..9ec76708bd7b > --- /dev/null > +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/MemEncryptSevLib.c > @@ -0,0 +1,84 @@ > +/** @file > + > + Secure Encrypted Virtualization (SEV) library helper function > + > + Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR> > + > + This program and the accompanying materials > + are licensed and made available under the terms and conditions of the BSD > + License which accompanies this distribution. The full text of the license > may > + be found at http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR > IMPLIED. > + > +**/ > + > +#include <Library/BaseLib.h> > +#include <Library/DebugLib.h> > +#include <Register/Cpuid.h> > +#include <Register/Amd/Cpuid.h> > +#include <Register/Amd/Msr.h> > +#include <Library/MemEncryptSevLib.h> > + > +#include "VirtualMemory.h" > + > +/** > + > + This function clears memory encryption bit for the memory region specified > by > + BaseAddress and Number of pages from the current page table context. > + > + @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use > current CR3) > + @param[in] BaseAddress The physical address that is the start > address > + of a memory region. > + @param[in] NumberOfPages The number of pages from start memory > region. > + @param[in] Flush Flush the caches before clearing the > bit > + (mostly TRUE except MMIO addresses) > + > + @retval RETURN_SUCCESS The attributes were cleared for the > memory > + region. > + @retval RETURN_INVALID_PARAMETER Number of pages is zero. > + @retval RETURN_UNSUPPORTED Clearing the memory encryption > attribute is > + not supported > + **/ > +RETURN_STATUS > +EFIAPI > +MemEncryptSevClearPageEncMask ( > + IN PHYSICAL_ADDRESS Cr3BaseAddress, > + IN PHYSICAL_ADDRESS BaseAddress, > + IN UINTN NumPages, > + IN BOOLEAN Flush > + ) > +{ > + return InternalMemEncryptSevSetMemoryDecrypted (Cr3BaseAddress, > BaseAddress, EFI_PAGES_TO_SIZE(NumPages), Flush); > +} > + > +/** > + > + This function clears memory encryption bit for the memory region specified > by > + BaseAddress and Number of pages from the current page table context. > + > + @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use > current CR3) > + @param[in] BaseAddress The physical address that is the start > address > + of a memory region. > + @param[in] NumberOfPages The number of pages from start memory > region. > + @param[in] Flush Flush the caches before clearing the > bit > + (mostly TRUE except MMIO addresses) > + > + @retval RETURN_SUCCESS The attributes were cleared for the > memory > + region. > + @retval RETURN_INVALID_PARAMETER Number of pages is zero. > + @retval RETURN_UNSUPPORTED Clearing the memory encryption > attribute is > + not supported > + **/ > +RETURN_STATUS > +EFIAPI > +MemEncryptSevSetPageEncMask ( > + IN PHYSICAL_ADDRESS Cr3BaseAddress, > + IN PHYSICAL_ADDRESS BaseAddress, > + IN UINTN NumPages, > + IN BOOLEAN Flush > + ) > +{ > + return InternalMemEncryptSevSetMemoryEncrypted (Cr3BaseAddress, > BaseAddress, EFI_PAGES_TO_SIZE(NumPages), Flush); > +} > diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c > b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c > new file mode 100644 > index 000000000000..fa103a531dfb > --- /dev/null > +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c > @@ -0,0 +1,428 @@ > +/** @file > + > + Virtual Memory Management Services to set or clear the memory encryption > bit > + > +Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR> > +Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR> > + > +This program and the accompanying materials > +are licensed and made available under the terms and conditions of the BSD > License > +which accompanies this distribution. The full text of the license may be > found at > +http://opensource.org/licenses/bsd-license.php > + > +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + > +Code is derived from MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c > + > +**/ > + > +#include <Library/CpuLib.h> > +#include <Register/Cpuid.h> > +#include <Register/Amd/Cpuid.h> > + > +#include "VirtualMemory.h" > + > +STATIC BOOLEAN mAddressEncMaskChecked = FALSE; > +STATIC UINT64 mAddressEncMask; > + > +typedef enum { > + SetCBit, > + ClearCBit > +} MAP_RANGE_MODE; > + > +/** > + Get the memory encryption mask > + > + @param[out] EncryptionMask contains the pte mask. > + > +**/ > +STATIC > +UINT64 > +GetMemEncryptionAddressMask ( > + VOID > + ) > +{ > + UINT64 EncryptionMask; > + CPUID_MEMORY_ENCRYPTION_INFO_EBX Ebx; > + > + if (mAddressEncMaskChecked) { > + return mAddressEncMask; > + } > + > + // > + // CPUID Fn8000_001F[EBX] Bit 0:5 (memory encryption bit position) > + // > + AsmCpuid (CPUID_MEMORY_ENCRYPTION_INFO, NULL, &Ebx.Uint32, NULL, NULL); > + EncryptionMask = LShiftU64 (1, Ebx.Bits.PtePosBits); > + > + mAddressEncMask = EncryptionMask & PAGING_1G_ADDRESS_MASK_64; > + mAddressEncMaskChecked = TRUE; > + > + return mAddressEncMask; > +} > + > +/** > + Split 2M page to 4K. > + > + @param[in] PhysicalAddress Start physical address the 2M page > covered. > + @param[in, out] PageEntry2M Pointer to 2M page entry. > + @param[in] StackBase Stack base address. > + @param[in] StackSize Stack size. > + > +**/ > +STATIC > +VOID > +Split2MPageTo4K ( > + IN PHYSICAL_ADDRESS PhysicalAddress, > + IN OUT UINT64 *PageEntry2M, > + IN PHYSICAL_ADDRESS StackBase, > + IN UINTN StackSize > + ) > +{ > + PHYSICAL_ADDRESS PhysicalAddress4K; > + UINTN IndexOfPageTableEntries; > + PAGE_TABLE_4K_ENTRY *PageTableEntry, *PageTableEntry1; > + UINT64 AddressEncMask; > + > + PageTableEntry = AllocatePages(1); > + > + PageTableEntry1 = PageTableEntry; > + > + AddressEncMask = GetMemEncryptionAddressMask (); > + > + ASSERT (PageTableEntry != NULL); > + ASSERT (*PageEntry2M & AddressEncMask); > + > + PhysicalAddress4K = PhysicalAddress; > + for (IndexOfPageTableEntries = 0; IndexOfPageTableEntries < 512; > IndexOfPageTableEntries++, PageTableEntry++, PhysicalAddress4K += SIZE_4KB) { > + // > + // Fill in the Page Table entries > + // > + PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K | AddressEncMask; > + PageTableEntry->Bits.ReadWrite = 1; > + PageTableEntry->Bits.Present = 1; > + if ((PhysicalAddress4K >= StackBase) && (PhysicalAddress4K < StackBase + > StackSize)) { > + // > + // Set Nx bit for stack. > + // > + PageTableEntry->Bits.Nx = 1; > + } > + } > + > + // > + // Fill in 2M page entry. > + // > + *PageEntry2M = (UINT64) (UINTN) PageTableEntry1 | IA32_PG_P | IA32_PG_RW | > AddressEncMask; > +} > + > +/** > + Split 1G page to 2M. > + > + @param[in] PhysicalAddress Start physical address the 1G page > covered. > + @param[in, out] PageEntry1G Pointer to 1G page entry. > + @param[in] StackBase Stack base address. > + @param[in] StackSize Stack size. > + > +**/ > +STATIC > +VOID > +Split1GPageTo2M ( > + IN PHYSICAL_ADDRESS PhysicalAddress, > + IN OUT UINT64 *PageEntry1G, > + IN PHYSICAL_ADDRESS StackBase, > + IN UINTN StackSize > + ) > +{ > + PHYSICAL_ADDRESS PhysicalAddress2M; > + UINTN IndexOfPageDirectoryEntries; > + PAGE_TABLE_ENTRY *PageDirectoryEntry; > + UINT64 AddressEncMask; > + > + PageDirectoryEntry = AllocatePages(1); > + > + AddressEncMask = GetMemEncryptionAddressMask (); > + ASSERT (PageDirectoryEntry != NULL); > + ASSERT (*PageEntry1G & GetMemEncryptionAddressMask ()); > + // > + // Fill in 1G page entry. > + // > + *PageEntry1G = (UINT64) (UINTN) PageDirectoryEntry | IA32_PG_P | > IA32_PG_RW | AddressEncMask; > + > + PhysicalAddress2M = PhysicalAddress; > + for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; > IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PhysicalAddress2M += > SIZE_2MB) { > + if ((PhysicalAddress2M < StackBase + StackSize) && ((PhysicalAddress2M + > SIZE_2MB) > StackBase)) { > + // > + // Need to split this 2M page that covers stack range. > + // > + Split2MPageTo4K (PhysicalAddress2M, (UINT64 *) PageDirectoryEntry, > StackBase, StackSize); > + } else { > + // > + // Fill in the Page Directory entries > + // > + PageDirectoryEntry->Uint64 = (UINT64) PhysicalAddress2M | > AddressEncMask; > + PageDirectoryEntry->Bits.ReadWrite = 1; > + PageDirectoryEntry->Bits.Present = 1; > + PageDirectoryEntry->Bits.MustBe1 = 1; > + } > + } > +} > + > + > +/** > + Set or Clear the memory encryption bit > + > + @param[in] PagetablePoint Page table entry pointer (PTE). > + @param[in] Mode Set or Clear encryption bit > + > +**/ > +STATIC VOID > +SetOrClearCBit( > + IN OUT UINT64* PageTablePointer, > + IN MAP_RANGE_MODE Mode > + ) > +{ > + UINT64 AddressEncMask; > + > + AddressEncMask = GetMemEncryptionAddressMask (); > + > + if (Mode == SetCBit) { > + *PageTablePointer |= AddressEncMask; > + } else { > + *PageTablePointer &= ~AddressEncMask; > + } > + > +} > + > +/** > + This function either sets or clears memory encryption bit for the memory > region > + specified by PhysicalAddress and length from the current page table > context. > + > + The function iterates through the physicalAddress one page at a time, and > set > + or clears the memory encryption mask in the page table. If it encounters > + that a given physical address range is part of large page then it attempts > to > + change the attribute at one go (based on size), otherwise it splits the > + large pages into smaller (e.g 2M page into 4K pages) and then try to set or > + clear the encryption bit on the smallest page size. > + > + @param[in] PhysicalAddress The physical address that is the start > + address of a memory region. > + @param[in] Length The length of memory region > + @param[in] Mode Set or Clear mode > + @param[in] Flush Flush the caches before applying the > + encryption mask > + > + @retval RETURN_SUCCESS The attributes were cleared for the > memory > + region. > + @retval RETURN_INVALID_PARAMETER Number of pages is zero. > + @retval RETURN_UNSUPPORTED Setting the memory encyrption > attribute is > + not supported > +**/ > + > +STATIC > +EFI_STATUS > +EFIAPI > +SetMemoryEncDec ( > + IN PHYSICAL_ADDRESS Cr3BaseAddress, > + IN PHYSICAL_ADDRESS PhysicalAddress, > + IN UINTN Length, > + IN MAP_RANGE_MODE Mode, > + IN BOOLEAN CacheFlush > + ) > +{ > + PAGE_MAP_AND_DIRECTORY_POINTER *PageMapLevel4Entry; > + PAGE_MAP_AND_DIRECTORY_POINTER *PageUpperDirectoryPointerEntry; > + PAGE_MAP_AND_DIRECTORY_POINTER *PageDirectoryPointerEntry; > + PAGE_TABLE_1G_ENTRY *PageDirectory1GEntry; > + PAGE_TABLE_ENTRY *PageDirectory2MEntry; > + PAGE_TABLE_4K_ENTRY *PageTableEntry; > + UINT64 PgTableMask; > + UINT64 AddressEncMask; > + > + // > + // Check if we have a valid memory encryption mask > + // > + AddressEncMask = GetMemEncryptionAddressMask (); > + if (!AddressEncMask) { > + return RETURN_ACCESS_DENIED; > + } > + > + PgTableMask = AddressEncMask | EFI_PAGE_MASK; > + > + if (Length == 0) { > + return RETURN_INVALID_PARAMETER; > + } > + > + // > + // We are going to change the memory encryption attribute from C=0 -> C=1 > or > + // vice versa Flush the caches to ensure that data is written into memory > with > + // correct C-bit > + // > + if (CacheFlush) { > + WriteBackInvalidateDataCacheRange((VOID*) (UINTN)PhysicalAddress, > Length); > + } > + > + while (Length) > + { > + // > + // If Cr3BaseAddress is not specified then read the current CR3 > + // > + if (Cr3BaseAddress == 0) { > + Cr3BaseAddress = AsmReadCr3(); > + } > + > + PageMapLevel4Entry = (VOID*) (Cr3BaseAddress & ~PgTableMask); > + PageMapLevel4Entry += PML4_OFFSET(PhysicalAddress); > + if (!PageMapLevel4Entry->Bits.Present) { > + DEBUG ((DEBUG_WARN, "%a:%a ERROR bad PML4 for %lx\n", > gEfiCallerBaseName, > + __FUNCTION__, PhysicalAddress)); > + return RETURN_NO_MAPPING; > + } > + > + PageDirectory1GEntry = (VOID*) > ((PageMapLevel4Entry->Bits.PageTableBaseAddress<<12) & ~PgTableMask); > + PageDirectory1GEntry += PDP_OFFSET(PhysicalAddress); > + if (!PageDirectory1GEntry->Bits.Present) { > + DEBUG ((DEBUG_WARN, "%a:%a ERROR bad PDPE for %lx\n", > gEfiCallerBaseName, > + __FUNCTION__, PhysicalAddress)); > + return RETURN_NO_MAPPING; > + } > + > + // > + // If the MustBe1 bit is not 1, it's not actually a 1GB entry > + // > + if (PageDirectory1GEntry->Bits.MustBe1) { > + // > + // Valid 1GB page > + // If we have at least 1GB to go, we can just update this entry > + // > + if (!(PhysicalAddress & (BIT30 - 1)) && Length >= BIT30) { > + SetOrClearCBit(&PageDirectory1GEntry->Uint64, Mode); > + DEBUG ((DEBUG_VERBOSE, "%a:%a Updated 1GB entry for %lx\n", > + gEfiCallerBaseName, __FUNCTION__, PhysicalAddress)); > + PhysicalAddress += BIT30; > + Length -= BIT30; > + } else { > + // > + // We must split the page > + // > + DEBUG ((DEBUG_VERBOSE, "%a:%a Spliting 1GB page\n", > gEfiCallerBaseName, __FUNCTION__)); > + > Split1GPageTo2M(((UINT64)PageDirectory1GEntry->Bits.PageTableBaseAddress)<<30, > (UINT64*) PageDirectory1GEntry, 0, 0); > + continue; > + } > + } else { > + // > + // Actually a PDP > + // > + PageUpperDirectoryPointerEntry = (PAGE_MAP_AND_DIRECTORY_POINTER*) > PageDirectory1GEntry; > + PageDirectory2MEntry = (VOID*) > ((PageUpperDirectoryPointerEntry->Bits.PageTableBaseAddress<<12) & > ~PgTableMask); > + PageDirectory2MEntry += PDE_OFFSET(PhysicalAddress); > + if (!PageDirectory2MEntry->Bits.Present) { > + DEBUG ((DEBUG_WARN, "%a:%a ERROR bad PDE for %lx\n", > gEfiCallerBaseName, > + __FUNCTION__,PhysicalAddress)); > + return RETURN_NO_MAPPING; > + } > + // > + // If the MustBe1 bit is not a 1, it's not a 2MB entry > + // > + if (PageDirectory2MEntry->Bits.MustBe1) { > + // > + // Valid 2MB page > + // If we have at least 2MB left to go, we can just update this entry > + // > + if (!(PhysicalAddress & (BIT21-1)) && Length >= BIT21) { > + SetOrClearCBit (&PageDirectory2MEntry->Uint64, Mode); > + PhysicalAddress += BIT21; > + Length -= BIT21; > + } else { > + // > + // We must split up this page into 4K pages > + // > + DEBUG ((DEBUG_VERBOSE, "%a:%a Spliting 2MB page at %lx\n", > gEfiCallerBaseName, > + __FUNCTION__, PhysicalAddress)); > + Split2MPageTo4K > (((UINT64)PageDirectory2MEntry->Bits.PageTableBaseAddress) << 21, (UINT64*) > PageDirectory2MEntry, 0, 0); > + continue; > + } > + } else { > + PageDirectoryPointerEntry = (PAGE_MAP_AND_DIRECTORY_POINTER*) > PageDirectory2MEntry; > + PageTableEntry = (VOID*) > (PageDirectoryPointerEntry->Bits.PageTableBaseAddress<<12 & ~PgTableMask); > + PageTableEntry += PTE_OFFSET(PhysicalAddress); > + if (!PageTableEntry->Bits.Present) { > + DEBUG ((DEBUG_WARN, "%a:%a ERROR bad PTE for %lx\n", > gEfiCallerBaseName, > + __FUNCTION__,PhysicalAddress)); > + return RETURN_NO_MAPPING; > + } > + SetOrClearCBit (&PageTableEntry->Uint64, Mode); > + PhysicalAddress += EFI_PAGE_SIZE; > + Length -= EFI_PAGE_SIZE; > + } > + } > + } > + > + // > + // Flush TLB > + // > + CpuFlushTlb(); > + > + return RETURN_SUCCESS; > +} > + > +/** > + This function clears memory encryption bit for the memory region specified > by > + PhysicalAddress and length from the current page table context. > + > + @param[in] PhysicalAddress The physical address that is the start > + address of a memory region. > + @param[in] Length The length of memory region > + @param[in] Flush Flush the caches before applying the > + encryption mask > + > + @retval RETURN_SUCCESS The attributes were cleared for the > memory > + region. > + @retval RETURN_INVALID_PARAMETER Number of pages is zero. > + @retval RETURN_UNSUPPORTED Setting the memory encyrption > attribute is > + not supported > +**/ > +EFI_STATUS > +EFIAPI > +InternalMemEncryptSevSetMemoryDecrypted ( > + IN PHYSICAL_ADDRESS Cr3BaseAddress, > + IN PHYSICAL_ADDRESS PhysicalAddress, > + IN UINTN Length, > + IN BOOLEAN Flush > + ) > +{ > + > + DEBUG ((DEBUG_VERBOSE, "%a:%a Clear C-bit Cr3 %Lx Base %Lx Length %Lx > flush %d\n", > + gEfiCallerBaseName, __FUNCTION__, Cr3BaseAddress, PhysicalAddress, > Length, Flush)); > + return SetMemoryEncDec (Cr3BaseAddress, PhysicalAddress, Length, > ClearCBit, Flush); > +} > + > +/** > + This function sets memory encryption bit for the memory region specified by > + PhysicalAddress and length from the current page table context. > + > + @param[in] PhysicalAddress The physical address that is the start > address > + of a memory region. > + @param[in] Length The length of memory region > + @param[in] Flush Flush the caches before applying the > + encryption mask > + > + @retval RETURN_SUCCESS The attributes were cleared for the > memory > + region. > + @retval RETURN_INVALID_PARAMETER Number of pages is zero. > + @retval RETURN_UNSUPPORTED Setting the memory encyrption > attribute is > + not supported > +**/ > +EFI_STATUS > +EFIAPI > +InternalMemEncryptSevSetMemoryEncrypted ( > + IN PHYSICAL_ADDRESS Cr3BaseAddress, > + IN PHYSICAL_ADDRESS PhysicalAddress, > + IN UINTN Length, > + IN BOOLEAN Flush > + ) > +{ > + DEBUG ((DEBUG_VERBOSE, "%a:%a Set C-bit Cr3 %Lx Base %Lx Length %Lx flush > %d\n", > + gEfiCallerBaseName, __FUNCTION__, Cr3BaseAddress, PhysicalAddress, > Length, Flush)); > + return SetMemoryEncDec (Cr3BaseAddress, PhysicalAddress, Length, SetCBit, > Flush); > +} > _______________________________________________ edk2-devel mailing list [email protected] https://lists.01.org/mailman/listinfo/edk2-devel

