From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from NAM12-BN8-obe.outbound.protection.outlook.com (NAM12-BN8-obe.outbound.protection.outlook.com [40.107.237.52]) by mx.groups.io with SMTP id smtpd.web10.100.1634144277811643942 for ; Wed, 13 Oct 2021 09:57:58 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="body hash did not verify" header.i=@amd.com header.s=selector1 header.b=byccdxjs; spf=permerror, err=parse error for token &{10 18 %{i}._ip.%{h}._ehlo.%{d}._spf.vali.email}: invalid domain name (domain: amd.com, ip: 40.107.237.52, mailfrom: brijesh.singh@amd.com) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=VYwqCs12Z7EJbX8XYPKF1P1gSCy3nBe1gK1RM8C1AVliypjGJocIAPi2augeSaiqf731YwMt84NCYPjcw+InpVoRraIBeB7CAVRM0EM/AuciXa8/Uz7bdEsG2aEmUUyDGGbB2hJ4hNdGAfaIIp33/EK0raQqnCSfAPLjZ5eV/U5wobNiWRM0ZZw2o2ihqOoJz+TDZhD13KTNeL2G12SzUOmrB+KWfCoKEm5YebVf1t3WuUiJ/LqfqMjIDN1Rn23g98q55yXwxII5GwanYUHjdL2S5Xk8FMJneVqHy5gF+dabdjWXSc72VVHo5uV2qgcTiT2d9q8wsDJFG5odGN5xzA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=1XJMdubsr8z8LYR1K4ANKgYP0plsJQGdqAnnTLmUj0k=; b=ZhUccNfxQwoG/T2yscLj+hN3CFb3xmqYKVQ8uz5die93/ZplHS2fKgMg4MQQetGLk7RZHaIXqIb5lxFlYiroaVlflDkXXGSyMegfaKIHoZBanYEJD1hcWYlPUkEm4sXeuEUKfu9oj4Nh4jh81CyioTzbHfJH3TffqIYq1ZGNHrKiWQqMzeJcqP1CU0+WLjvRhR2z6D0+0vORg4KuHeF0gmGtUlFXb/H5eH98u6hQwMvyHwwTGkxtbq1L5ab147ApN74gj9o+36BkZ/5wPlwNQ78uacmjZVa8s3thAi2Nrzdkqexr1WJIO9Ln6BlIiLb8HPdFdovv+aOjftqLoP/cJg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 165.204.84.17) smtp.rcpttodomain=edk2.groups.io smtp.mailfrom=amd.com; dmarc=pass (p=quarantine sp=quarantine pct=100) action=none header.from=amd.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amd.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=1XJMdubsr8z8LYR1K4ANKgYP0plsJQGdqAnnTLmUj0k=; b=byccdxjsSh0fNV9M2VuIFSe/FsLXp5wrx9ocMI5N2rMx4DSv9guv/raQmkJ2dV6o3JCVf4lsH6ALXKOurqmDWsi1eNGUolUXWvo3aw+gBntjUBciiHHEwWnWFgWI+RD2im94xnaar/ggjbiM7pRS2s51i9ACeiHkGHc92GS0/HI= Received: from MWHPR11CA0013.namprd11.prod.outlook.com (2603:10b6:301:1::23) by BYAPR12MB2997.namprd12.prod.outlook.com (2603:10b6:a03:db::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4608.16; Wed, 13 Oct 2021 16:57:54 +0000 Received: from CO1NAM11FT060.eop-nam11.prod.protection.outlook.com (2603:10b6:301:1:cafe::e2) by MWHPR11CA0013.outlook.office365.com (2603:10b6:301:1::23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4608.15 via Frontend Transport; Wed, 13 Oct 2021 16:57:54 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 165.204.84.17) smtp.mailfrom=amd.com; edk2.groups.io; dkim=none (message not signed) header.d=none;edk2.groups.io; dmarc=pass action=none header.from=amd.com; Received-SPF: Pass (protection.outlook.com: domain of amd.com designates 165.204.84.17 as permitted sender) receiver=protection.outlook.com; client-ip=165.204.84.17; helo=SATLEXMB04.amd.com; Received: from SATLEXMB04.amd.com (165.204.84.17) by CO1NAM11FT060.mail.protection.outlook.com (10.13.175.132) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.4608.15 via Frontend Transport; Wed, 13 Oct 2021 16:57:54 +0000 Received: from sbrijesh-desktop.amd.com (10.180.168.240) by SATLEXMB04.amd.com (10.181.40.145) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2308.8; Wed, 13 Oct 2021 11:57:47 -0500 From: "Brijesh Singh" To: CC: James Bottomley , Min Xu , "Jiewen Yao" , Tom Lendacky , "Jordan Justen" , Ard Biesheuvel , Erdem Aktas , "Michael Roth" , Gerd Hoffmann , Brijesh Singh , Michael Roth , Jiewen Yao Subject: [PATCH v9 14/32] OvmfPkg/MemEncryptSevLib: add support to validate system RAM Date: Wed, 13 Oct 2021 11:56:55 -0500 Message-ID: <20211013165713.727815-15-brijesh.singh@amd.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20211013165713.727815-1-brijesh.singh@amd.com> References: <20211013165713.727815-1-brijesh.singh@amd.com> MIME-Version: 1.0 Return-Path: brijesh.singh@amd.com X-Originating-IP: [10.180.168.240] X-ClientProxiedBy: SATLEXMB04.amd.com (10.181.40.145) To SATLEXMB04.amd.com (10.181.40.145) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 0726b910-18bb-49b5-1979-08d98e6a99d2 X-MS-TrafficTypeDiagnostic: BYAPR12MB2997: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:8273; X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: d4daEECnLiqbt6rpVhrG0s5LWKFBpXN0xrpmVEhXTA7ltZVmVpZ1u2ikyV4JADL02Tcg2+wDsEYwI56J33uoA4zBYNSSugZHd6mi2Xb0rCKtI2ynm/eirxDzYNoCTEzRZSjjPgBTAu2OFZGiARZ5gdlfvYyKqVxT4BC2kx/XpcwHQ1GfWOcuF13GbDdtBySyrUFBb4/eTjiCyeZK7naZaoJY3mBi+MfH8QC8lZkmLaLKvm0jgaXnvi/JF9lqM634gKRmvCP9ytwpsXlHMq3iSXAILXVujFZj/NxBAOKstwzIgxJwwpm4xAbK9xZMs/vHr55/oFlbZPWsqCqfKaPoETaO+NXzPHzhPm4Ntag44Y7OhG7D4FU7NS5tLNSIIJ4CcjJoHRf46cGrLHreOSjlyKrhUTUHqXwJY8EpuAgWUibiauJh2lxwm/Nu7LAKkmu9cP52dq8J9yGmRkfh71sT/MAkZwVkZqDnUfwWhtc/guyHYndLsaJbjcIM8CQbfrJ8XqamtUWbV/WQ0+qppAfryaOqf62iNH2pj3MOGT0Oo6g8K7g03X+MYscl0o6vpUt2S5hOOVXt3GUmQPvsPma2eIiYrzeB9LhDDDAhtHTkJ1W7e6tkjhLfLfQ/YW8UDllpsZGH5d8yQS0o09vyA5h7ekogFMwIb7wr/q9F8XzMuAPWmFEvgcBgjzw8n1QwQ7J/g4G5mNwQiTlthAedeuh1qqrzwN8JSCdvt0HD8UdXEQuLjDEA2pF6fxC0zZarQh5oiyWs2NdUUFjip3jv4FAuDacH5KHnHArvAt/a+rT47SUVzaT4yquvuvE9wlSs4O9z X-Forefront-Antispam-Report: CIP:165.204.84.17;CTRY:US;LANG:en;SCL:1;SRV:;IPV:CAL;SFV:NSPM;H:SATLEXMB04.amd.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(4636009)(36840700001)(46966006)(30864003)(2616005)(36860700001)(6916009)(1076003)(2906002)(81166007)(83380400001)(5660300002)(336012)(508600001)(47076005)(6666004)(44832011)(426003)(36756003)(4326008)(86362001)(186003)(16526019)(54906003)(19627235002)(8936002)(26005)(70206006)(70586007)(966005)(356005)(8676002)(316002)(7696005)(15650500001)(82310400003)(36900700001);DIR:OUT;SFP:1101; X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 13 Oct 2021 16:57:54.6539 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 0726b910-18bb-49b5-1979-08d98e6a99d2 X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=3dd8961f-e488-4e60-8e11-a82d994e183d;Ip=[165.204.84.17];Helo=[SATLEXMB04.amd.com] X-MS-Exchange-CrossTenant-AuthSource: CO1NAM11FT060.eop-nam11.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BYAPR12MB2997 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3D3275 Many of the integrity guarantees of SEV-SNP are enforced through the Reverse Map Table (RMP). Each RMP entry contains the GPA at which a particular page of DRAM should be mapped. The guest can request the hypervisor to add pages in the RMP table via the Page State Change VMGEXIT defined in the GHCB specification section 2.5.1 and 4.1.6. Inside each RMP entry is a Validated flag; this flag is automatically cleared to 0 by the CPU hardware when a new RMP entry is created for a guest. Each VM page can be either validated or invalidated, as indicated by the Validated flag in the RMP entry. Memory access to a private page that is not validated generates a #VC. A VM can use the PVALIDATE instruction to validate the private page before using it. During the guest creation, the boot ROM memory is pre-validated by the AMD-SEV firmware. The MemEncryptSevSnpValidateSystemRam() can be called during the SEC and PEI phase to validate the detected system RAM. One of the fields in the Page State Change NAE is the RMP page size. The page size input parameter indicates that either a 4KB or 2MB page should be used while adding the RMP entry. During the validation, when possible, the MemEncryptSevSnpValidateSystemRam() will use the 2MB entry. A hypervisor backing the memory may choose to use the different page size in the RMP entry. In those cases, the PVALIDATE instruction should return SIZEMISMATCH. If a SIZEMISMATCH is detected, then validate all 512-pages constituting a 2MB region. Upon completion, the PVALIDATE instruction sets the rFLAGS.CF to 0 if instruction changed the RMP entry and to 1 if the instruction did not change the RMP entry. The rFlags.CF will be 1 only when a memory region is already validated. We should not double validate a memory as it could lead to a security compromise. If double validation is detected, terminate the boot. Cc: Michael Roth Cc: James Bottomley Cc: Min Xu Cc: Jiewen Yao Cc: Tom Lendacky Cc: Jordan Justen Cc: Ard Biesheuvel Cc: Erdem Aktas Cc: Gerd Hoffmann Acked-by: Jiewen Yao Signed-off-by: Brijesh Singh --- OvmfPkg/OvmfPkgIa32.dsc | 1 + OvmfPkg/OvmfPkgIa32X64.dsc | 1 + .../DxeMemEncryptSevLib.inf | 3 + .../PeiMemEncryptSevLib.inf | 3 + .../SecMemEncryptSevLib.inf | 3 + OvmfPkg/Include/Library/MemEncryptSevLib.h | 14 + .../X64/SnpPageStateChange.h | 31 ++ .../Ia32/MemEncryptSevLib.c | 17 + .../X64/DxeSnpSystemRamValidate.c | 40 +++ .../X64/PeiSnpSystemRamValidate.c | 36 +++ .../X64/SecSnpSystemRamValidate.c | 36 +++ .../X64/SnpPageStateChangeInternal.c | 295 ++++++++++++++++++ 12 files changed, 480 insertions(+) create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateCh= ange.h create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/X64/DxeSnpSystemRa= mValidate.c create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRa= mValidate.c create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/X64/SecSnpSystemRa= mValidate.c create mode 100644 OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateCh= angeInternal.c diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc index 6a5be97c059d..1dc069e42420 100644 --- a/OvmfPkg/OvmfPkgIa32.dsc +++ b/OvmfPkg/OvmfPkgIa32.dsc @@ -266,6 +266,7 @@ [LibraryClasses.common.SEC] !else CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiC= puExceptionHandlerLib.inf !endif + MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLi= b.inf =20 [LibraryClasses.common.PEI_CORE] HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc index 13d9a1f111bc..a766457e6bc6 100644 --- a/OvmfPkg/OvmfPkgIa32X64.dsc +++ b/OvmfPkg/OvmfPkgIa32X64.dsc @@ -270,6 +270,7 @@ [LibraryClasses.common.SEC] !else CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiC= puExceptionHandlerLib.inf !endif + MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLi= b.inf =20 [LibraryClasses.common.PEI_CORE] HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf b= /OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf index f2e162d68076..f613bb314f5f 100644 --- a/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf @@ -34,8 +34,10 @@ [Sources] PeiDxeMemEncryptSevLibInternal.c =20 [Sources.X64] + X64/DxeSnpSystemRamValidate.c X64/MemEncryptSevLib.c X64/PeiDxeVirtualMemory.c + X64/SnpPageStateChangeInternal.c X64/VirtualMemory.c X64/VirtualMemory.h =20 @@ -49,6 +51,7 @@ [LibraryClasses] DebugLib MemoryAllocationLib PcdLib + VmgExitLib =20 [FeaturePcd] gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf b= /OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf index 03a78c32df28..0402e49a1028 100644 --- a/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf @@ -36,6 +36,8 @@ [Sources] [Sources.X64] X64/MemEncryptSevLib.c X64/PeiDxeVirtualMemory.c + X64/PeiSnpSystemRamValidate.c + X64/SnpPageStateChangeInternal.c X64/VirtualMemory.c X64/VirtualMemory.h =20 @@ -49,6 +51,7 @@ [LibraryClasses] DebugLib MemoryAllocationLib PcdLib + VmgExitLib =20 [FeaturePcd] gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf b= /OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf index 279c38bfbc2c..939af0a91ea4 100644 --- a/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf @@ -35,6 +35,8 @@ [Sources] [Sources.X64] X64/MemEncryptSevLib.c X64/SecVirtualMemory.c + X64/SecSnpSystemRamValidate.c + X64/SnpPageStateChangeInternal.c X64/VirtualMemory.c X64/VirtualMemory.h =20 @@ -46,6 +48,7 @@ [LibraryClasses] CpuLib DebugLib PcdLib + VmgExitLib =20 [FixedPcd] gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase diff --git a/OvmfPkg/Include/Library/MemEncryptSevLib.h b/OvmfPkg/Include/L= ibrary/MemEncryptSevLib.h index 796de62ec2f8..f708a0cdaa72 100644 --- a/OvmfPkg/Include/Library/MemEncryptSevLib.h +++ b/OvmfPkg/Include/Library/MemEncryptSevLib.h @@ -215,4 +215,18 @@ MemEncryptSevClearMmioPageEncMask ( IN UINTN NumPages ); =20 +/** + Pre-validate the system RAM when SEV-SNP is enabled in the guest VM. + + @param[in] BaseAddress Base address + @param[in] NumPages Number of pages starting from the ba= se address + +**/ +VOID +EFIAPI +MemEncryptSevSnpPreValidateSystemRam ( + IN PHYSICAL_ADDRESS BaseAddress, + IN UINTN NumPages + ); + #endif // _MEM_ENCRYPT_SEV_LIB_H_ diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChange.h = b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChange.h new file mode 100644 index 000000000000..8bbdf06468b9 --- /dev/null +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChange.h @@ -0,0 +1,31 @@ +/** @file + + SEV-SNP Page Validation functions. + + Copyright (c) 2021 AMD Incorporated. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef SNP_PAGE_STATE_INTERNAL_H_ +#define SNP_PAGE_STATE_INTERNAL_H_ + +// +// SEV-SNP Page states +// +typedef enum { + SevSnpPagePrivate, + SevSnpPageShared, + +} SEV_SNP_PAGE_STATE; + +VOID +InternalSetPageState ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINTN NumPages, + IN SEV_SNP_PAGE_STATE State, + IN BOOLEAN UseLargeEntry + ); + +#endif diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/Ia32/MemEncryptSevLib.c b= /OvmfPkg/Library/BaseMemEncryptSevLib/Ia32/MemEncryptSevLib.c index be260e0d1014..df5e4d61513d 100644 --- a/OvmfPkg/Library/BaseMemEncryptSevLib/Ia32/MemEncryptSevLib.c +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/Ia32/MemEncryptSevLib.c @@ -136,3 +136,20 @@ MemEncryptSevClearMmioPageEncMask ( // return RETURN_UNSUPPORTED; } + +/** + Pre-validate the system RAM when SEV-SNP is enabled in the guest VM. + + @param[in] BaseAddress Base address + @param[in] NumPages Number of pages starting from the ba= se address + +**/ +VOID +EFIAPI +MemEncryptSevSnpPreValidateSystemRam ( + IN PHYSICAL_ADDRESS BaseAddress, + IN UINTN NumPages + ) +{ + ASSERT (FALSE); +} diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/DxeSnpSystemRamValida= te.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/DxeSnpSystemRamValidate.c new file mode 100644 index 000000000000..ad8d8b388dc8 --- /dev/null +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/DxeSnpSystemRamValidate.c @@ -0,0 +1,40 @@ +/** @file + + SEV-SNP Page Validation functions. + + Copyright (c) 2021 AMD Incorporated. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include + +#include "SnpPageStateChange.h" + +/** + Pre-validate the system RAM when SEV-SNP is enabled in the guest VM. + + @param[in] BaseAddress Base address + @param[in] NumPages Number of pages starting from the ba= se address + +**/ +VOID +EFIAPI +MemEncryptSevSnpPreValidateSystemRam ( + IN PHYSICAL_ADDRESS BaseAddress, + IN UINTN NumPages + ) +{ + if (!MemEncryptSevSnpIsEnabled ()) { + return; + } + + // + // All the pre-validation must be completed in the PEI phase. + // + ASSERT (FALSE); +} diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValida= te.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c new file mode 100644 index 000000000000..64aab7f45b6d --- /dev/null +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiSnpSystemRamValidate.c @@ -0,0 +1,36 @@ +/** @file + + SEV-SNP Page Validation functions. + + Copyright (c) 2021 AMD Incorporated. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include + +#include "SnpPageStateChange.h" + +/** + Pre-validate the system RAM when SEV-SNP is enabled in the guest VM. + + @param[in] BaseAddress Base address + @param[in] NumPages Number of pages starting from the ba= se address + +**/ +VOID +EFIAPI +MemEncryptSevSnpPreValidateSystemRam ( + IN PHYSICAL_ADDRESS BaseAddress, + IN UINTN NumPages + ) +{ + if (!MemEncryptSevSnpIsEnabled ()) { + return; + } + + InternalSetPageState (BaseAddress, NumPages, SevSnpPagePrivate, TRUE); +} diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SecSnpSystemRamValida= te.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SecSnpSystemRamValidate.c new file mode 100644 index 000000000000..64aab7f45b6d --- /dev/null +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SecSnpSystemRamValidate.c @@ -0,0 +1,36 @@ +/** @file + + SEV-SNP Page Validation functions. + + Copyright (c) 2021 AMD Incorporated. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include + +#include "SnpPageStateChange.h" + +/** + Pre-validate the system RAM when SEV-SNP is enabled in the guest VM. + + @param[in] BaseAddress Base address + @param[in] NumPages Number of pages starting from the ba= se address + +**/ +VOID +EFIAPI +MemEncryptSevSnpPreValidateSystemRam ( + IN PHYSICAL_ADDRESS BaseAddress, + IN UINTN NumPages + ) +{ + if (!MemEncryptSevSnpIsEnabled ()) { + return; + } + + InternalSetPageState (BaseAddress, NumPages, SevSnpPagePrivate, TRUE); +} diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChangeInt= ernal.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChangeIntern= al.c new file mode 100644 index 000000000000..506df12d4e51 --- /dev/null +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChangeInternal.c @@ -0,0 +1,295 @@ +/** @file + + SEV-SNP Page Validation functions. + + Copyright (c) 2021 AMD Incorporated. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "SnpPageStateChange.h" + +#define IS_ALIGNED(x, y) ((((x) & (y - 1)) =3D=3D 0)) +#define PAGES_PER_LARGE_ENTRY 512 + +STATIC +UINTN +MemoryStateToGhcbOp ( + IN SEV_SNP_PAGE_STATE State + ) +{ + UINTN Cmd; + + switch (State) { + case SevSnpPageShared: Cmd =3D SNP_PAGE_STATE_SHARED; break; + case SevSnpPagePrivate: Cmd =3D SNP_PAGE_STATE_PRIVATE; break; + default: ASSERT(0); + } + + return Cmd; +} + +STATIC +VOID +SnpPageStateFailureTerminate ( + VOID + ) +{ + MSR_SEV_ES_GHCB_REGISTER Msr; + + // + // Use the GHCB MSR Protocol to request termination by the hypervisor + // + Msr.GhcbPhysicalAddress =3D 0; + Msr.GhcbTerminate.Function =3D GHCB_INFO_TERMINATE_REQUEST; + Msr.GhcbTerminate.ReasonCodeSet =3D GHCB_TERMINATE_GHCB; + Msr.GhcbTerminate.ReasonCode =3D GHCB_TERMINATE_GHCB_GENERAL; + AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress); + + AsmVmgExit (); + + ASSERT (FALSE); + CpuDeadLoop (); +} + +/** + This function issues the PVALIDATE instruction to validate or invalidate = the memory + range specified. If PVALIDATE returns size mismatch then it retry validat= ing with + smaller page size. + + */ +STATIC +VOID +PvalidateRange ( + IN SNP_PAGE_STATE_CHANGE_INFO *Info, + IN UINTN StartIndex, + IN UINTN EndIndex, + IN BOOLEAN Validate + ) +{ + UINTN Address, RmpPageSize, Ret, i; + + for (; StartIndex <=3D EndIndex; StartIndex++) { + // + // Get the address and the page size from the Info. + // + Address =3D Info->Entry[StartIndex].GuestFrameNumber << EFI_PAGE_SHIFT= ; + RmpPageSize =3D Info->Entry[StartIndex].PageSize; + + Ret =3D AsmPvalidate (RmpPageSize, Validate, Address); + + // + // If we fail to validate due to size mismatch then try with the + // smaller page size. This senario will occur if the backing page in + // the RMP entry is 4K and we are validating it as a 2MB. + // + if ((Ret =3D=3D PVALIDATE_RET_SIZE_MISMATCH) && (RmpPageSize =3D=3D Pv= alidatePageSize2MB)) { + for (i =3D 0; i < PAGES_PER_LARGE_ENTRY; i++) { + Ret =3D AsmPvalidate (PvalidatePageSize4K, Validate, Address); + if (Ret) { + break; + } + + Address =3D Address + EFI_PAGE_SIZE; + } + } + + // + // If validation failed then do not continue. + // + if (Ret) { + DEBUG (( + DEBUG_ERROR, "%a:%a: Failed to %a address 0x%Lx Error code %d\n", + gEfiCallerBaseName, + __FUNCTION__, + Validate ? "Validate" : "Invalidate", + Address, + Ret + )); + SnpPageStateFailureTerminate (); + } + } +} + +STATIC +EFI_PHYSICAL_ADDRESS +BuildPageStateBuffer ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN EFI_PHYSICAL_ADDRESS EndAddress, + IN SEV_SNP_PAGE_STATE State, + IN BOOLEAN UseLargeEntry, + IN SNP_PAGE_STATE_CHANGE_INFO *Info + ) +{ + EFI_PHYSICAL_ADDRESS NextAddress; + UINTN i, RmpPageSize; + + // Clear the page state structure + SetMem (Info, sizeof (*Info), 0); + + i =3D 0; + NextAddress =3D EndAddress; + + // + // Populate the page state entry structure + // + while ((BaseAddress < EndAddress) && (i < SNP_PAGE_STATE_MAX_ENTRY)) { + // + // Is this a 2MB aligned page? Check if we can use the Large RMP entry= . + // + if (UseLargeEntry && IS_ALIGNED (BaseAddress, SIZE_2MB) && + ((EndAddress - BaseAddress) >=3D SIZE_2MB)) { + RmpPageSize =3D PvalidatePageSize2MB; + NextAddress =3D BaseAddress + SIZE_2MB; + } else { + RmpPageSize =3D PvalidatePageSize4K; + NextAddress =3D BaseAddress + EFI_PAGE_SIZE; + } + + Info->Entry[i].GuestFrameNumber =3D BaseAddress >> EFI_PAGE_SHIFT; + Info->Entry[i].PageSize =3D RmpPageSize; + Info->Entry[i].Operation =3D MemoryStateToGhcbOp (State); + Info->Entry[i].CurrentPage =3D 0; + Info->Header.EndEntry =3D i; + + BaseAddress =3D NextAddress; + i++; + } + + return NextAddress; +} + +STATIC +VOID +PageStateChangeVmgExit ( + IN GHCB *Ghcb, + IN SNP_PAGE_STATE_CHANGE_INFO *Info + ) +{ + EFI_STATUS Status; + + // + // As per the GHCB specification, the hypervisor can resume the guest be= fore + // processing all the entries. Checks whether all the entries are proces= sed. + // + // The stragtegy here is to wait for the hypervisor to change the page + // state in the RMP table before guest access the memory pages. If the + // page state was not successful, then later memory access will result + // in the crash. + // + while (Info->Header.CurrentEntry <=3D Info->Header.EndEntry) { + Ghcb->SaveArea.SwScratch =3D (UINT64) Ghcb->SharedBuffer; + VmgSetOffsetValid (Ghcb, GhcbSwScratch); + + Status =3D VmgExit (Ghcb, SVM_EXIT_SNP_PAGE_STATE_CHANGE, 0, 0); + + // + // The Page State Change VMGEXIT can pass the failure through the + // ExitInfo2. Lets check both the return value as well as ExitInfo2. + // + if ((Status !=3D 0) || (Ghcb->SaveArea.SwExitInfo2)) { + SnpPageStateFailureTerminate (); + } + } +} + +/** + The function is used to set the page state when SEV-SNP is active. The pa= ge state + transition consist of changing the page ownership in the RMP table, and u= sing the + PVALIDATE instruction to update the Validated bit in RMP table. + + When the UseLargeEntry is set to TRUE, then function will try to use the = large RMP + entry (whevever possible). + */ +VOID +InternalSetPageState ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINTN NumPages, + IN SEV_SNP_PAGE_STATE State, + IN BOOLEAN UseLargeEntry + ) +{ + GHCB *Ghcb; + EFI_PHYSICAL_ADDRESS NextAddress, EndAddress; + MSR_SEV_ES_GHCB_REGISTER Msr; + BOOLEAN InterruptState; + SNP_PAGE_STATE_CHANGE_INFO *Info; + + Msr.GhcbPhysicalAddress =3D AsmReadMsr64 (MSR_SEV_ES_GHCB); + Ghcb =3D Msr.Ghcb; + + EndAddress =3D BaseAddress + EFI_PAGES_TO_SIZE (NumPages); + + DEBUG (( + DEBUG_VERBOSE, "%a:%a Address 0x%Lx - 0x%Lx State =3D %a LargeEntry = =3D %d\n", + gEfiCallerBaseName, + __FUNCTION__, + BaseAddress, + EndAddress, + State =3D=3D SevSnpPageShared ? "Shared" : "Private", + UseLargeEntry + )); + + while (BaseAddress < EndAddress) { + UINTN CurrentEntry, EndEntry; + + // + // Initialize the GHCB + // + VmgInit (Ghcb, &InterruptState); + + // + // Build the page state structure + // + Info =3D (SNP_PAGE_STATE_CHANGE_INFO *) Ghcb->SharedBuffer; + NextAddress =3D BuildPageStateBuffer (BaseAddress, + EndAddress, + State, + UseLargeEntry, + Info + ); + + // + // Save the current and end entry from the page state structure. We ne= ed + // it later. + // + CurrentEntry =3D Info->Header.CurrentEntry; + EndEntry =3D Info->Header.EndEntry; + + // + // If the caller requested to change the page state to shared then + // invalidate the pages before making the page shared in the RMP table= . + // + if (State =3D=3D SevSnpPageShared) { + PvalidateRange (Info, CurrentEntry, EndEntry, FALSE); + } + + // + // Invoke the page state change VMGEXIT. + // + PageStateChangeVmgExit (Ghcb, Info); + + // + // If the caller requested to change the page state to private then + // validate the pages after it has been added in the RMP table. + // + if (State =3D=3D SevSnpPagePrivate) { + PvalidateRange (Info, CurrentEntry, EndEntry, TRUE); + } + + VmgDone (Ghcb, InterruptState); + + BaseAddress =3D NextAddress; + } +} --=20 2.25.1