From nobody Fri Nov 29 04:45:19 2024 Delivered-To: importer@patchew.org Received-SPF: none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) client-ip=198.145.21.10; envelope-from=edk2-devel-bounces@lists.01.org; helo=ml01.01.org; Authentication-Results: mx.zoho.com; dkim=fail spf=none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) smtp.mailfrom=edk2-devel-bounces@lists.01.org; Return-Path: Received: from ml01.01.org (ml01.01.org [198.145.21.10]) by mx.zohomail.com with SMTPS id 1490130793127648.2756429110741; Tue, 21 Mar 2017 14:13:13 -0700 (PDT) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id EF51B80421; Tue, 21 Mar 2017 14:13:11 -0700 (PDT) Received: from mail-oi0-x244.google.com (mail-oi0-x244.google.com [IPv6:2607:f8b0:4003:c06::244]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id E3EFF8036C for ; Tue, 21 Mar 2017 14:13:09 -0700 (PDT) Received: by mail-oi0-x244.google.com with SMTP id a94so7281302oic.0 for ; Tue, 21 Mar 2017 14:13:09 -0700 (PDT) Received: from [127.0.1.1] ([165.204.77.1]) by smtp.gmail.com with ESMTPSA id 38sm7961783oth.49.2017.03.21.14.13.08 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 21 Mar 2017 14:13:08 -0700 (PDT) X-Original-To: edk2-devel@ml01.01.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:subject:to:cc:date:message-id:in-reply-to:references :user-agent:mime-version:content-transfer-encoding; bh=jUTG50UsEgcmS80uw7AfxjNAxa8GO3e5IwdsF0JzROM=; b=t2EDp31dRUJOxHHZ0P3mgKhdwZ2wrK4Q9ujCeEi7VEWczlTeZjNXHyJnnfqoDHeq34 Ll++lA4HLw2plnszZucwUr8ujLjOoPM8z7OgOv2/fJFTJap83QhzDi/CPyn9Jh7TAXAp 8iEvdf3pEbQVK6y8lWPxE/PMNkH5rBGu14v1wrbp69iSDDsUjZX5m7JPiS9mKn81rvG2 NQFRUz0+xYCJBUqOxFMPvJkAlXfQ2IxoyW1Gm3EgC3aM49kzETPi1H1F0kHUe00wyf4x DR5LNJTPLnb6JVrp7M0jKf3inuXKbVY+z69jXsl45I3OtOkzCvweg1A+VyvYrhzSHbh0 zUgw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:subject:to:cc:date:message-id:in-reply-to :references:user-agent:mime-version:content-transfer-encoding; bh=jUTG50UsEgcmS80uw7AfxjNAxa8GO3e5IwdsF0JzROM=; b=HR3h+QtcwZC62AOsTmn/+ASuiKdzp6VH4nmTcESDt5W9JTFmtfxbdovXgWavsksHIp aJbp62/rBFmD0uOlK8R1Ij0cSc1rArAa1RS2aSlkoFlzCujTN7HCEYe+O0GNQU0+1gh2 rAJ7jwMcuYLGae5gzYax4UT3tWfKv+/M23T9xSDDaH+1d0rPMNmXLVMRBw1L6ugSZJ4o mbgQYu1GPhOEfq/qt+9rs1QobiAu9vIiaElmXV5o5sUYfUd/ytPPyKg539hhU2qe9VSo BuZVy1yWlUk7s9hfsCzFPTYnXEo21i4a5zJXrOezRnC4cqFVNjyfoG5KDjaiCbkLVyZd l8Cg== X-Gm-Message-State: AFeK/H35Vt2W/ndI9YNe1z8jd62YjLWp5YUlf3TCPuLpMlZqtaZIkECAUWHL17khx0mq7g== X-Received: by 10.202.214.8 with SMTP id n8mr19960068oig.91.1490130788710; Tue, 21 Mar 2017 14:13:08 -0700 (PDT) From: Brijesh Singh X-Google-Original-From: Brijesh Singh To: michael.d.kinney@intel.com, jordan.l.justen@intel.com, edk2-devel@ml01.01.org, lersek@redhat.com, liming.gao@intel.com Date: Tue, 21 Mar 2017 17:13:07 -0400 Message-ID: <149013078709.27235.16179070664669554073.stgit@brijesh-build-machine> In-Reply-To: <149013076154.27235.10725020825643505862.stgit@brijesh-build-machine> References: <149013076154.27235.10725020825643505862.stgit@brijesh-build-machine> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Subject: [edk2] [RFC PATCH v2 04/10] OvmfPkg/BaseMemcryptSevLib: Add SEV helper library X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: brijesh.singh@amd.com, leo.duran@amd.com, Thomas.Lendacky@amd.com Content-Transfer-Encoding: quoted-printable Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RSF_4 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Add Secure Encrypted Virtualization (SEV) helper library. The library provi= des the routines to set or clear memory encryption bit for a given memory region and functions to check whether SEV is enabled. Signed-off-by: Brijesh Singh --- OvmfPkg/Include/Library/MemEncryptSevLib.h | 69 +++++ .../BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf | 46 +++ .../BaseMemEncryptSevLib/Ia32/MemEncryptSevLib.c | 124 ++++++++ .../BaseMemEncryptSevLib/X64/MemEncryptSevLib.c | 120 ++++++++ .../BaseMemEncryptSevLib/X64/VirtualMemory.c | 304 ++++++++++++++++= ++++ .../BaseMemEncryptSevLib/X64/VirtualMemory.h | 158 ++++++++++ OvmfPkg/OvmfPkgIa32.dsc | 1=20 OvmfPkg/OvmfPkgIa32X64.dsc | 1=20 OvmfPkg/OvmfPkgX64.dsc | 1=20 9 files changed, 824 insertions(+) create mode 100644 OvmfPkg/Include/Library/MemEncryptSevLib.h create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevL= ib.inf create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/Ia32/MemEncryptSev= Lib.c create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/X64/MemEncryptSevL= ib.c create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.h diff --git a/OvmfPkg/Include/Library/MemEncryptSevLib.h b/OvmfPkg/Include/L= ibrary/MemEncryptSevLib.h new file mode 100644 index 0000000..a9e9356 --- /dev/null +++ b/OvmfPkg/Include/Library/MemEncryptSevLib.h @@ -0,0 +1,69 @@ +/** @file + + Define Secure Encrypted Virtualization (SEV) base library helper function + + Copyright (c) 2017, AMD Incorporated. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BS= D License + which accompanies this distribution. The full text of the license may b= e 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 IMP= LIED. + +**/ + +#ifndef __MEM_ENCRYPT_SEV_LIB_H_ +#define __MEM_ENCRYPT_SEV_LIB_H_ + +#include + +/** + Returns a boolean to indicate whether SEV is enabled + + @retval TRUE When SEV is active + @retval FALSE When SEV is not enabled + **/ +BOOLEAN +EFIAPI +MemEncryptSevIsEnabled ( + VOID + ); + +/** + This function clears memory encryption bit for the memory region specifi= ed 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. + + @retval RETURN_SUCCESS The attributes were cleared for the me= mory region. + @retval RETURN_INVALID_PARAMETER Number of pages is zero. + @retval RETURN_UNSUPPORTED Clearing memory encryption attribute i= s not supported + **/ +RETURN_STATUS +EFIAPI +MemEncryptSevClearPageEncMask ( + IN PHYSICAL_ADDRESS BaseAddress, + IN UINT32 NumberOfPages + ); + +/** + 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. + + @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 i= s not supported + **/ +RETURN_STATUS +EFIAPI +MemEncryptSevSetPageEncMask ( + IN PHYSICAL_ADDRESS BaseAddress, + IN UINT32 NumberOfPages + ); +#endif // __MEM_ENCRYPT_SEV_LIB_H_ diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf = b/OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf new file mode 100644 index 0000000..c23261f --- /dev/null +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf @@ -0,0 +1,46 @@ +## @file +# +# Copyright (c) 2017 Advanced Micro Devices. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the B= SD License +# which accompanies this distribution. The full text of the license may b= e 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 IM= PLIED. +# +# +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D MemEncryptSevLib + FILE_GUID =3D c1594631-3888-4be4-949f-9c630dbc842b + MODULE_TYPE =3D BASE + VERSION_STRING =3D 1.0 + LIBRARY_CLASS =3D 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 =3D IA32 X64 +# + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + OvmfPkg/OvmfPkg.dec + UefiCpuPkg/UefiCpuPkg.dec + +[Sources.X64] + X64/MemEncryptSevLib.c + X64/VirtualMemory.c + +[Sources.IA32] + Ia32/MemEncryptSevLib.c + +[LibraryClasses] + BaseLib + DebugLib + MemoryAllocationLib + CacheMaintenanceLib diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/Ia32/MemEncryptSevLib.c b= /OvmfPkg/Library/BaseMemEncryptSevLib/Ia32/MemEncryptSevLib.c new file mode 100644 index 0000000..70fdd2e --- /dev/null +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/Ia32/MemEncryptSevLib.c @@ -0,0 +1,124 @@ +/** @file + + Secure Encrypted Virtualization (SEV) library helper function + + Copyright (c) 2017, AMD Incorporated. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BS= D License + which accompanies this distribution. The full text of the license may b= e 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 IMP= LIED. + +**/ + +#include "Uefi.h" +#include +#include +#include +#include +#include + +STATIC BOOLEAN SevStatus =3D FALSE; +STATIC BOOLEAN SevStatusChecked =3D FALSE; + +/** +=20 + Returns a boolean to indicate whether SEV is enabled + + @retval TRUE When SEV is active + @retval FALSE When SEV is not enabled + **/ +BOOLEAN +EFIAPI +MemEncryptSevIsEnabled ( + VOID + ) +{ + UINT32 RegEax; + MSR_SEV_STATUS_REGISTER Msr; + CPUID_MEMORY_ENCRYPTION_INFO_EAX Eax; + + // + // If Status is already checked then return it + // + if (SevStatusChecked) { + return SevStatus; + } + + // + // Check if memory encryption leaf exist + // + AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL); + if (RegEax >=3D 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 is Enabled) + // + Msr.Uint32 =3D AsmReadMsr32 (MSR_SEV_STATUS); + if (Msr.Bits.SevBit) { + return TRUE; + } + } + } + + SevStatusChecked =3D TRUE; + + return FALSE; +} + +/** + This function clears memory encryption bit for the memory region specifi= ed by BaseAddress and + Number of pages from the current page table context. + + @param[in] BaseAddress The physical address that is the sta= rt address of a memory region. + @param[in] NumberOfPages The number of pages from start memor= y region. + + @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 attrib= ute is not supported + **/ +RETURN_STATUS +EFIAPI +MemEncryptSevClearPageEncMask ( + IN PHYSICAL_ADDRESS BaseAddress, + IN UINT32 NumberOfPages + ) +{ + // + // 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] BaseAddress The physical address that is the sta= rt address of a memory region. + @param[in] NumberOfPages The number of pages from start memor= y region. + + @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 attrib= ute is not supported + **/ +RETURN_STATUS +EFIAPI +MemEncryptSevSetPageEncMask ( + IN PHYSICAL_ADDRESS BaseAddress, + IN UINT32 NumberOfPages + ) +{ + // + // Memory encryption bit is not accessible in 32-bit mode + // + return RETURN_UNSUPPORTED; +} + diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/MemEncryptSevLib.c b/= OvmfPkg/Library/BaseMemEncryptSevLib/X64/MemEncryptSevLib.c new file mode 100644 index 0000000..098acf2 --- /dev/null +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/MemEncryptSevLib.c @@ -0,0 +1,120 @@ +/** @file + + Secure Encrypted Virtualization (SEV) library helper function + + Copyright (c) 2017, AMD Incorporated. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BS= D License + which accompanies this distribution. The full text of the license may b= e 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 IMP= LIED. + +**/ + +#include "Uefi.h" +#include +#include +#include +#include +#include + +#include "VirtualMemory.h" + +STATIC BOOLEAN SevStatus =3D FALSE; +STATIC BOOLEAN SevStatusChecked =3D FALSE; + +/** + Returns a boolean to indicate whether SEV is enabled + + @retval TRUE When SEV is active + @retval FALSE When SEV is not enabled + **/ +BOOLEAN +EFIAPI +MemEncryptSevIsEnabled ( + VOID + ) +{ + UINT32 RegEax; + MSR_SEV_STATUS_REGISTER Msr; + CPUID_MEMORY_ENCRYPTION_INFO_EAX Eax; + + // + // If Status is already checked then return it + // + if (SevStatusChecked) { + return SevStatus; + } + + // + // Check if memory encryption leaf exist + // + AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL); + if (RegEax >=3D 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 =3D AsmReadMsr32 (MSR_SEV_STATUS); + if (Msr.Bits.SevBit) { + return TRUE; + } + } + } + + SevStatusChecked =3D TRUE; + + return FALSE; +} + +/** +=20 + This function clears memory encryption bit for the memory region specifi= ed by BaseAddress and + Number of pages from the current page table context. + + @param[in] BaseAddress The physical address that is the sta= rt address of a memory region. + @param[in] NumberOfPages The number of pages from start memor= y region. + + @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 attri= bute is not supported + **/ +RETURN_STATUS +EFIAPI +MemEncryptSevClearPageEncMask ( + IN PHYSICAL_ADDRESS BaseAddress, + IN UINT32 NumPages + ) +{ + return Set_Memory_Decrypted (BaseAddress, NumPages * EFI_PAGE_SIZE); +} + +/** +=20 + This function clears memory encryption bit for the memory region specifi= ed by BaseAddress and + Number of pages from the current page table context. + + @param[in] BaseAddress The physical address that is the sta= rt address of a memory region. + @param[in] NumberOfPages The number of pages from start memor= y region. + + @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 attri= bute is not supported + **/ +RETURN_STATUS +EFIAPI +MemEncryptSevSetPageEncMask ( + IN PHYSICAL_ADDRESS BaseAddress, + IN UINT32 NumPages + ) +{ + return Set_Memory_Encrypted (BaseAddress, NumPages * EFI_PAGE_SIZE); +} diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c b/Ovm= fPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c new file mode 100644 index 0000000..7acebf3 --- /dev/null +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c @@ -0,0 +1,304 @@ +/** @file +=20 + Virtual Memory Management Services to set or clear the memory encryption= bit + + References: + 1) IA-32 Intel(R) Architecture Software Developer's Manual Volume 1:Ba= sic Architecture, Intel + 2) IA-32 Intel(R) Architecture Software Developer's Manual Volume 2:In= struction Set Reference, Intel + 3) IA-32 Intel(R) Architecture Software Developer's Manual Volume 3:Sy= stem Programmer's Guide, Intel + +Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.
+Copyright (c) 2017, AMD Incorporated. All rights reserved.
+ +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 IMPLI= ED. + +**/ + +#include "VirtualMemory.h" + +#include + +STATIC UINT64 AddressEncMask; + +typedef enum { + SetCBit, + ClearCBit +} MAP_RANGE_MODE; + +/** + 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 EFI_PHYSICAL_ADDRESS PhysicalAddress, + IN OUT UINT64 *PageEntry2M, + IN EFI_PHYSICAL_ADDRESS StackBase, + IN UINTN StackSize + ) +{ + EFI_PHYSICAL_ADDRESS PhysicalAddress4K; + UINTN IndexOfPageTableEntries; + PAGE_TABLE_4K_ENTRY *PageTableEntry, *PageTableEntry1; + + PageTableEntry =3D AllocatePages(1); + + PageTableEntry1 =3D PageTableEntry; + + ASSERT (PageTableEntry !=3D NULL); + ASSERT (*PageEntry2M & AddressEncMask); + + PhysicalAddress4K =3D PhysicalAddress; + for (IndexOfPageTableEntries =3D 0; IndexOfPageTableEntries < 512; Index= OfPageTableEntries++, PageTableEntry++, PhysicalAddress4K +=3D SIZE_4KB) { + // + // Fill in the Page Table entries + // + PageTableEntry->Uint64 =3D (UINT64) PhysicalAddress4K | AddressEncMask; + PageTableEntry->Bits.ReadWrite =3D 1; + PageTableEntry->Bits.Present =3D 1; + if ((PhysicalAddress4K >=3D StackBase) && (PhysicalAddress4K < StackBa= se + StackSize)) { + // + // Set Nx bit for stack. + // + PageTableEntry->Bits.Nx =3D 1; + } + } + + // + // Fill in 2M page entry. + // + *PageEntry2M =3D (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 EFI_PHYSICAL_ADDRESS PhysicalAddress, + IN OUT UINT64 *PageEntry1G, + IN EFI_PHYSICAL_ADDRESS StackBase, + IN UINTN StackSize + ) +{ + EFI_PHYSICAL_ADDRESS PhysicalAddress2M; + UINTN IndexOfPageDirectoryEntries; + PAGE_TABLE_ENTRY *PageDirectoryEntry; + + PageDirectoryEntry =3D AllocatePages(1); + + ASSERT (PageDirectoryEntry !=3D NULL); + ASSERT (*PageEntry1G & AddressEncMask); + // + // Fill in 1G page entry. + // + *PageEntry1G =3D (UINT64) (UINTN) PageDirectoryEntry | IA32_PG_P | IA32_= PG_RW | AddressEncMask; + + PhysicalAddress2M =3D PhysicalAddress; + for (IndexOfPageDirectoryEntries =3D 0; IndexOfPageDirectoryEntries < 51= 2; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PhysicalAddress2M += =3D SIZE_2MB) { + if ((PhysicalAddress2M < StackBase + StackSize) && ((PhysicalAddress2M= + SIZE_2MB) > StackBase)) { + // + // Need to split this 2M page that covers stack range. + // + Split2MPageTo4K (PhysicalAddress2M, (UINT64 *) PageDirectoryEntry, S= tackBase, StackSize); + } else { + // + // Fill in the Page Directory entries + // + PageDirectoryEntry->Uint64 =3D (UINT64) PhysicalAddress2M | AddressE= ncMask; + PageDirectoryEntry->Bits.ReadWrite =3D 1; + PageDirectoryEntry->Bits.Present =3D 1; + PageDirectoryEntry->Bits.MustBe1 =3D 1; + } + } +} + + +STATIC VOID +SetOrClearCBit( + IN UINT64* PageTablePointer, + IN MAP_RANGE_MODE Mode + ) +{ + if (Mode =3D=3D SetCBit) { + *PageTablePointer |=3D AddressEncMask; + } else { + *PageTablePointer &=3D ~AddressEncMask; + } + +} + +STATIC +UINT64 +GetMemEncryptionAddressMask ( + VOID + ) +{ + UINT64 MeMask; + CPUID_MEMORY_ENCRYPTION_INFO_EBX Ebx; + + // + // CPUID Fn8000_001F[EBX] Bit 0:5 (memory encryption bit position) + // + AsmCpuid (CPUID_MEMORY_ENCRYPTION_INFO, NULL, &Ebx.Uint32, NULL, NULL); + MeMask =3D LShiftU64 (1, Ebx.Bits.PtePosBits); + + return MeMask & PAGING_1G_ADDRESS_MASK_64; +} + +STATIC +EFI_STATUS +EFIAPI +Set_Memory_Enc_Dec ( + IN EFI_PHYSICAL_ADDRESS PhysicalAddress, + IN UINT64 Length, + IN MAP_RANGE_MODE Mode + ) +{ + 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; + + AddressEncMask =3D GetMemEncryptionAddressMask (); + + if (!AddressEncMask) { + return RETURN_ACCESS_DENIED; + } + + PgTableMask =3D AddressEncMask | EFI_PAGE_MASK; + + DEBUG ((EFI_D_VERBOSE, "Set memory range 0x%#Lx+0x%x (%s)\n", PhysicalAd= dress, Length, + Mode =3D=3D ClearCBit ? "unencrypted" : "encrypted")); + + if (Length =3D=3D 0) { + return EFI_INVALID_PARAMETER; + } + + // + // We are going to change the memory encryption attribute from C=3D0 -> = C=3D1 or vice versa + // Flush the caches to ensure that data is written into memory with corr= ect C-bit + // + WriteBackInvalidateDataCacheRange((VOID*) PhysicalAddress, Length); + + while (Length) + { + + PageMapLevel4Entry =3D (VOID*) (AsmReadCr3() & ~PgTableMask); + PageMapLevel4Entry +=3D PML4_OFFSET(PhysicalAddress); + if (!PageMapLevel4Entry->Bits.Present) { + DEBUG((DEBUG_WARN, "ERROR bad PML4 for %lx\n", PhysicalAddress)); + return EFI_NO_MAPPING; + } + + PageDirectory1GEntry =3D (VOID*) (PageMapLevel4Entry->Bits.PageTableBa= seAddress<<12 & ~PgTableMask); + PageDirectory1GEntry +=3D PDP_OFFSET(PhysicalAddress); + if (!PageDirectory1GEntry->Bits.Present) { + DEBUG((DEBUG_WARN, "ERROR bad PDPE for %lx\n", PhysicalAddress)); + return EFI_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 & ((1<<30) - 1)) && Length >=3D (1<<30)) { + SetOrClearCBit(&PageDirectory1GEntry->Uint64, Mode); + DEBUG((DEBUG_VERBOSE, "Updated 1GB entry for %lx\n", PhysicalAddre= ss)); + PhysicalAddress +=3D 1<<30; + Length -=3D 1<<30; + } else { + // We must split the page + DEBUG((DEBUG_VERBOSE, "Spliting 1GB page\n")); + Split1GPageTo2M(((UINT64)PageDirectory1GEntry->Bits.PageTableBaseA= ddress)<<30, (UINT64*) PageDirectory1GEntry, 0, 0); + continue; + } + } else { + // Actually a PDP + PageUpperDirectoryPointerEntry =3D (PAGE_MAP_AND_DIRECTORY_POINTER*)= PageDirectory1GEntry; + PageDirectory2MEntry =3D (VOID*) (PageUpperDirectoryPointerEntry->Bi= ts.PageTableBaseAddress<<12 & ~PgTableMask); + PageDirectory2MEntry +=3D PDE_OFFSET(PhysicalAddress); + if (!PageDirectory2MEntry->Bits.Present) { + DEBUG((DEBUG_WARN, "ERROR bad PDE for %lx\n", PhysicalAddress)); + return EFI_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 ent= ry + if (!(PhysicalAddress & ((1<<21)-1)) && Length >=3D (1<<21)) { + SetOrClearCBit(&PageDirectory2MEntry->Uint64, Mode); + DEBUG((DEBUG_VERBOSE, "Updated 2MB entry for %lx\n", PhysicalAdd= ress)); + PhysicalAddress +=3D 1<<21; + Length -=3D 1<<21; + } else { + // We must split up this page into 4K pages + DEBUG((DEBUG_VERBOSE, "Spliting 2MB page at %lx\n", PhysicalAddr= ess)); + Split2MPageTo4K(((UINT64)PageDirectory2MEntry->Bits.PageTableBas= eAddress) << 21, (UINT64*) PageDirectory2MEntry, 0, 0); + continue; + } + } else { + PageDirectoryPointerEntry =3D (PAGE_MAP_AND_DIRECTORY_POINTER*) Pa= geDirectory2MEntry; + PageTableEntry =3D (VOID*) (PageDirectoryPointerEntry->Bits.PageTa= bleBaseAddress<<12 & ~PgTableMask); + PageTableEntry +=3D PTE_OFFSET(PhysicalAddress); + if (!PageTableEntry->Bits.Present) { + DEBUG((DEBUG_WARN, "ERROR bad PTE for %lx\n", PhysicalAddress)); + return EFI_NO_MAPPING; + } + SetOrClearCBit(&PageTableEntry->Uint64, Mode); + DEBUG((DEBUG_VERBOSE, "Updated 4KB entry for %lx\n", PhysicalAddre= ss)); + PhysicalAddress +=3D EFI_PAGE_SIZE; + Length -=3D EFI_PAGE_SIZE; + } + } + } + + // + // Flush TLB + // + AsmWriteCr3(AsmReadCr3()); + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +Set_Memory_Decrypted ( + IN EFI_PHYSICAL_ADDRESS PhysicalAddress, + IN UINT64 Length + ) +{ + return Set_Memory_Enc_Dec (PhysicalAddress, Length, ClearCBit); +} + +EFI_STATUS +EFIAPI +Set_Memory_Encrypted ( + IN EFI_PHYSICAL_ADDRESS PhysicalAddress, + IN UINT64 Length + ) +{ + return Set_Memory_Enc_Dec (PhysicalAddress, Length, SetCBit); +} + diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.h b/Ovm= fPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.h new file mode 100644 index 0000000..a556211 --- /dev/null +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.h @@ -0,0 +1,158 @@ +/** @file +=20 + Virtual Memory Management Services to set or clear the memory encryption= bit + + References: + 1) IA-32 Intel(R) Architecture Software Developer's Manual Volume 1:Ba= sic Architecture, Intel + 2) IA-32 Intel(R) Architecture Software Developer's Manual Volume 2:In= struction Set Reference, Intel + 3) IA-32 Intel(R) Architecture Software Developer's Manual Volume 3:Sy= stem Programmer's Guide, Intel + +Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.
+Copyright (c) 2017, AMD Incorporated. All rights reserved.
+ +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 IMPLI= ED. + +**/ + +#ifndef __VIRTUAL_MEMORY__ +#define __VIRTUAL_MEMORY__ + +#include +#include +#include +#include +#include +//#include +//#include + +#include +#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 =3D Not present in memory, 1 = =3D Present in memory + UINT64 ReadWrite:1; // 0 =3D Read-Only, 1=3D Read/Write + UINT64 UserSupervisor:1; // 0 =3D Supervisor, 1=3DUser + UINT64 WriteThrough:1; // 0 =3D Write-Back caching, 1=3DWri= te-Through caching + UINT64 CacheDisabled:1; // 0 =3D Cached, 1=3DNon-Cached + UINT64 Accessed:1; // 0 =3D Not accessed, 1 =3D Accesse= d (set by CPU) + UINT64 Reserved:1; // Reserved + UINT64 MustBeZero:2; // Must Be Zero + UINT64 Available:3; // Available for use by system softw= are + UINT64 PageTableBaseAddress:40; // Page Table Base Address + UINT64 AvabilableHigh:11; // Available for use by system softw= are + 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 =3D Not present in memory, 1 = =3D Present in memory + UINT64 ReadWrite:1; // 0 =3D Read-Only, 1=3D Read/Write + UINT64 UserSupervisor:1; // 0 =3D Supervisor, 1=3DUser + UINT64 WriteThrough:1; // 0 =3D Write-Back caching, 1=3DWri= te-Through caching + UINT64 CacheDisabled:1; // 0 =3D Cached, 1=3DNon-Cached + UINT64 Accessed:1; // 0 =3D Not accessed, 1 =3D Accesse= d (set by CPU) + UINT64 Dirty:1; // 0 =3D Not Dirty, 1 =3D written by= processor on access to page + UINT64 PAT:1; // + UINT64 Global:1; // 0 =3D Not global page, 1 =3D glob= al page TLB not cleared on CR3 write + UINT64 Available:3; // Available for use by system softw= are + UINT64 PageTableBaseAddress:40; // Page Table Base Address + UINT64 AvabilableHigh:11; // Available for use by system softw= are + UINT64 Nx:1; // 0 =3D Execute Code, 1 =3D No Code= Execution + } Bits; + UINT64 Uint64; +} PAGE_TABLE_4K_ENTRY; + +// +// Page Table Entry 2MB +// +typedef union { + struct { + UINT64 Present:1; // 0 =3D Not present in memory, 1 = =3D Present in memory + UINT64 ReadWrite:1; // 0 =3D Read-Only, 1=3D Read/Write + UINT64 UserSupervisor:1; // 0 =3D Supervisor, 1=3DUser + UINT64 WriteThrough:1; // 0 =3D Write-Back caching, 1=3DWri= te-Through caching + UINT64 CacheDisabled:1; // 0 =3D Cached, 1=3DNon-Cached + UINT64 Accessed:1; // 0 =3D Not accessed, 1 =3D Accesse= d (set by CPU) + UINT64 Dirty:1; // 0 =3D Not Dirty, 1 =3D written by= processor on access to page + UINT64 MustBe1:1; // Must be 1=20 + UINT64 Global:1; // 0 =3D Not global page, 1 =3D glob= al page TLB not cleared on CR3 write + UINT64 Available:3; // Available for use by system softw= are + UINT64 PAT:1; // + UINT64 MustBeZero:8; // Must be zero; + UINT64 PageTableBaseAddress:31; // Page Table Base Address + UINT64 AvabilableHigh:11; // Available for use by system softw= are + UINT64 Nx:1; // 0 =3D Execute Code, 1 =3D No Code= Execution + } Bits; + UINT64 Uint64; +} PAGE_TABLE_ENTRY; + +// +// Page Table Entry 1GB +// +typedef union { + struct { + UINT64 Present:1; // 0 =3D Not present in memory, 1 = =3D Present in memory + UINT64 ReadWrite:1; // 0 =3D Read-Only, 1=3D Read/Write + UINT64 UserSupervisor:1; // 0 =3D Supervisor, 1=3DUser + UINT64 WriteThrough:1; // 0 =3D Write-Back caching, 1=3DWri= te-Through caching + UINT64 CacheDisabled:1; // 0 =3D Cached, 1=3DNon-Cached + UINT64 Accessed:1; // 0 =3D Not accessed, 1 =3D Accesse= d (set by CPU) + UINT64 Dirty:1; // 0 =3D Not Dirty, 1 =3D written by= processor on access to page + UINT64 MustBe1:1; // Must be 1=20 + UINT64 Global:1; // 0 =3D Not global page, 1 =3D glob= al page TLB not cleared on CR3 write + UINT64 Available:3; // Available for use by system softw= are + UINT64 PAT:1; // + UINT64 MustBeZero:17; // Must be zero; + UINT64 PageTableBaseAddress:22; // Page Table Base Address + UINT64 AvabilableHigh:11; // Available for use by system softw= are + UINT64 Nx:1; // 0 =3D Execute Code, 1 =3D 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)=20 +#define PML4_OFFSET(x) ( (x >> 39) & PAGETABLE_ENTRY_MASK)=20 +#define PDP_OFFSET(x) ( (x >> 30) & PAGETABLE_ENTRY_MASK)=20 +#define PDE_OFFSET(x) ( (x >> 21) & PAGETABLE_ENTRY_MASK)=20 +#define PTE_OFFSET(x) ( (x >> 12) & PAGETABLE_ENTRY_MASK)=20 +#define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull + +EFI_STATUS +EFIAPI +Set_Memory_Decrypted ( + IN EFI_PHYSICAL_ADDRESS PhysicalAddress, + IN UINT64 Length + ); + +EFI_STATUS +EFIAPI +Set_Memory_Encrypted ( + IN EFI_PHYSICAL_ADDRESS PhysicalAddress, + IN UINT64 Length + ); + +#endif diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc index 769251d..c2821b7 100644 --- a/OvmfPkg/OvmfPkgIa32.dsc +++ b/OvmfPkg/OvmfPkgIa32.dsc @@ -126,6 +126,7 @@ QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf LoadLinuxLib|OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf + MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevL= ib.inf !if $(SMM_REQUIRE) =3D=3D FALSE LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf !endif diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc index 3874c35..1dd8064 100644 --- a/OvmfPkg/OvmfPkgIa32X64.dsc +++ b/OvmfPkg/OvmfPkgIa32X64.dsc @@ -131,6 +131,7 @@ QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf LoadLinuxLib|OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf + MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevL= ib.inf !if $(SMM_REQUIRE) =3D=3D FALSE LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf !endif diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc index fe7f086..06bee32 100644 --- a/OvmfPkg/OvmfPkgX64.dsc +++ b/OvmfPkg/OvmfPkgX64.dsc @@ -131,6 +131,7 @@ QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf LoadLinuxLib|OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf + MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevL= ib.inf !if $(SMM_REQUIRE) =3D=3D FALSE LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf !endif _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel