From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from NAM11-CO1-obe.outbound.protection.outlook.com (NAM11-CO1-obe.outbound.protection.outlook.com [40.107.220.43]) by mx.groups.io with SMTP id smtpd.web12.7429.1617282448146070845 for ; Thu, 01 Apr 2021 06:07:28 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@amd.com header.s=selector1 header.b=HTOvDG5R; 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.220.43, mailfrom: brijesh.singh@amd.com) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=jqS3BeCv1mcfFch3m+RXoyIY+FqHBpXiOqKOfZp3wMzQLoivWLQnDDWJ+JTzv+ZVx6UETwlctGSuzHxw6Uo++hRamdyAgmYUe5mLtD5hx+QT+C8ud9keiZDGzBnJpCku9cTu802hEoFS+1qdWE6O9sBTLYD6346jLCHM29Ee8EAwngVKHFrY5uEDULhPQXTOzfPBs4aCGcjqoC1Jn9wGdLb8xA30nVd83ReYK4RoFD2S7jxZhMTEEqNtinBQKS2NULf2T3RuxqXgHGaYgQtIYLjai1pY3pKxF+ZqrCHxgKSw6kmWJMrq9uFK+gbPaOy2InkBAeFbRWC6ik4KL7wRdA== 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-SenderADCheck; bh=gt4tF0Y5F4p0MIW8GqaJcvzmsAY2o9a7Xa7OYOmnmec=; b=KxCAlRiwrpzKWkl5WLbm4jtZJ0CV74EUZQcDYrzaO6UF71bIaRE1Ne/dDwsBs9lEW1EFXhiiykFuwrFH5gMcxKsJ30xlfNYj8wsuTn3z9RSmogNqeP9YFuLJse052qD9bzi1PWFrlb9cDn2UejZCPJJ9rzm2hAaGceV4LWludcGkfq+uUQGWti2WRAWYCVsl2JYp7OJNmuFGfq0iGEniYSHXluK7JWKsQ734OZHzwHYWeoGRgs7Sp1i03eLeHAP0mghQuSae3Q6QP1Mo3zaR0pNax5NxqwIIWG44rGeTIZNeij5faYUq3oO/iUDdOsRjv9bC4ixiKjiM1Vvy8HetCg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=amd.com; dmarc=pass action=none header.from=amd.com; dkim=pass header.d=amd.com; 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=gt4tF0Y5F4p0MIW8GqaJcvzmsAY2o9a7Xa7OYOmnmec=; b=HTOvDG5Rey9R94rmhEnkaRJa4hyLbPWf0+A3Y8L282ZGJuUS1fuYfDAg49+PNCWeidqHXRfhXUzPUv+tUonV8UkMYtVnecP9G6Fc8upC0pxAh3ZsTwlejTuPK6VZIeat9gC/eDeUZ1u74sWgKWQlCwiE6JwQkeN78BJ8chXkcag= Authentication-Results: redhat.com; dkim=none (message not signed) header.d=none;redhat.com; dmarc=none action=none header.from=amd.com; Received: from SN6PR12MB2718.namprd12.prod.outlook.com (2603:10b6:805:6f::22) by SN1PR12MB2367.namprd12.prod.outlook.com (2603:10b6:802:26::31) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3999.28; Thu, 1 Apr 2021 13:07:26 +0000 Received: from SN6PR12MB2718.namprd12.prod.outlook.com ([fe80::30fb:2d6c:a0bf:2f1d]) by SN6PR12MB2718.namprd12.prod.outlook.com ([fe80::30fb:2d6c:a0bf:2f1d%3]) with mapi id 15.20.3977.033; Thu, 1 Apr 2021 13:07:25 +0000 Cc: brijesh.singh@amd.com, James Bottomley , "Xu, Min M" , Tom Lendacky , "Justen, Jordan L" , Ard Biesheuvel , Laszlo Ersek Subject: Re: [RFC PATCH 12/19] OvmfPkg/MemEncryptSevLib: Add support to validate system RAM To: "Yao, Jiewen" , "devel@edk2.groups.io" References: <20210324153215.17971-1-brijesh.singh@amd.com> <20210324153215.17971-13-brijesh.singh@amd.com> From: "Brijesh Singh" Message-ID: <3ff216eb-9e21-0b16-2e5c-bfc54f132b53@amd.com> Date: Thu, 1 Apr 2021 08:07:23 -0500 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:78.0) Gecko/20100101 Thunderbird/78.9.0 In-Reply-To: X-Originating-IP: [70.112.153.56] X-ClientProxiedBy: SN1PR12CA0073.namprd12.prod.outlook.com (2603:10b6:802:20::44) To SN6PR12MB2718.namprd12.prod.outlook.com (2603:10b6:805:6f::22) Return-Path: brijesh.singh@amd.com MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 Received: from Brijeshs-MacBook-Pro.local (70.112.153.56) by SN1PR12CA0073.namprd12.prod.outlook.com (2603:10b6:802:20::44) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3999.27 via Frontend Transport; Thu, 1 Apr 2021 13:07:24 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 3d6741e5-df76-4cac-a126-08d8f50f1845 X-MS-TrafficTypeDiagnostic: SN1PR12MB2367: X-MS-Exchange-Transport-Forked: True X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:10000; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: eRGKs9twE/sKfKNQZMgOYN/nxNM4tAUHpK7Gfs5aAmHecrXebh06DXUlz6qxVgUxJBnYvSToST53hHwV0eYvBKDDEyuJLNC5kc8BSFUzLp1YAdIiJmMFWb1LHblZ+KibD98EHP/j7KDDZzkwo0dg+bI/NFqTzP0a26Bzef+wRIOs6eoCrPu85V2mRWDmulv7CUeW2E/wdBguZxNSo880NdZWxXLqmcEajfZp9ElIY5DJaSKeWxiw00n/gZ5luVP64sDJNrnYsZ1acIKT9VCm4qH/x1G4W34Vk6ERbANq4gskp9C1GzsIzr4F0o9kXwskQ6f5uQqaJG6x9dU2ZJPYlv7rJN1d7xbQITbZMO9VfW0RSuwnWjXwkxH4g55hA/M1SD3AbM0rGMM86cEo+RUxXp6X0JdNQsV4ZKa9UGfkHWmhStSOdBTHTwgIabsrI4wFdSHuTpvlJs/vZXeyPZwEcOySpbpDXbHDw3gepEr3+FvhnSu1u2kUECiGd/lMwinfJZ2IGzQoAnMoXzhJSvBmWt/PFoOYFUqzOPhq5o1BCi2iWye9pHWjiZCksTIbfmKWuV9Ho5xa6hHdxaiPSDm2Ulmgv91d5ttexOHjEZIQyFe2JspMYcu3kwCSVRPNwr4OiArYCW4uUcbUnPBAqcaSQ/OQSMdOa4bluZKiPGMkRagsXqdGc3/n8buqkDaTg+XbWtmq50m1ie7iojTxi8sSPpS4tAu6GpXi+IawsWbrk9EhkUVEoppCNE6y8h4dESGpD5yhLqLpnM+npcad2LYyYLrGD2HjIH0UoF5lUE22EvA= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:SN6PR12MB2718.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(4636009)(136003)(39860400002)(396003)(376002)(346002)(366004)(44832011)(66946007)(31696002)(66556008)(66476007)(2616005)(6506007)(53546011)(956004)(478600001)(966005)(6486002)(5660300002)(36756003)(45080400002)(38100700001)(52116002)(6512007)(2906002)(31686004)(45954011)(30864003)(15650500001)(16526019)(316002)(8676002)(186003)(4326008)(110136005)(54906003)(8936002)(86362001)(26005)(19627235002)(83380400001)(43740500002)(45980500001);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData: =?utf-8?B?L0t5aDE3bmlMZHFsR3k4d2NMakYwaVdkZHNVWVFTL2pFU1NRdjVkK0E1STZT?= =?utf-8?B?OXRubnBNbGRFVVluK2UyYlNDbWFDNnVEWEc4cjZ0cHhIN2hWZWJBNjJyY2pz?= =?utf-8?B?bGJrNkFodzVJYXpTN25Gc2FPdkNXditSS09RSzJwQXlNVnhlbGwrVFJiZ0xm?= =?utf-8?B?SGNrbmVmRnp5aU1iWlVyK2UzVmd4dVVrOHh1eE1ia0xuYzRXQXZZTnV2cTBW?= =?utf-8?B?QW1YTWZ1Qk8rSWVIRUxXaEl3WS9PU3VPSUwwZVl0SXQvbm1DaTVMTERmUVc3?= =?utf-8?B?aHJ5aTJIemNYTTZMQmpEd2hRV2NmTTNiVzlYZmQ3OEFXeC92SFhkVmpjcitl?= =?utf-8?B?UHJqd21YOEI1V3IyTDhvV2w0SFA5cXpVaVpQRG10Qmx2T2RKYm9jYm9VQjB4?= =?utf-8?B?SFJ5amVta2t6UVJlNWErQ3k4WDd5MVNLdEUzK2Y0cmFMaEUvSHluWmcvOVJJ?= =?utf-8?B?OWhpRHdmZjR1VlpudmZ3S241SWFRcGVyL2xaNEZnNDh4TDNSWit2aDQxbnlK?= =?utf-8?B?anhBNENsWDEvWFpIalFNbnR6bXZsR1IzSk9oRU9iZ2c5aWxBRktOdGc0ZFd5?= =?utf-8?B?YmpPRzVPRG9PVjZTcDJ4NDZRS3ZxRndGQUxRQjE2bnJza3Q1M2plNXpqOVBq?= =?utf-8?B?MEJnTDhyUEZHbG1tVHVpZlFPYWlYWExxemV0NFh2eDhXNlp2OGlTR0dMeldw?= =?utf-8?B?OGNJL2pSazd1ZTg2dWg0OGk5dmN6Q0xERnExeWFOL1VBUHZVODE5elZZMnp5?= =?utf-8?B?c2NWOVRuYk53OTI2a3hJb25Lcjh3eFMvOXh4U1pwRlVrRVhFUEZrRHIrRGpD?= =?utf-8?B?Z3lBdzdrSDZwOWtVVlNDdFE5dk1pMDNPWmdickxoekVwVllhMEw1VSs3Zm1r?= =?utf-8?B?Qnh5d3RiZXJ0ZUI5aHIzdkVhZmZrVnRpV3p0VjNjSUNWeS9KcnAwcW9XWS9C?= =?utf-8?B?SmRnYUdxdXJZY2pvL3dvclMvZ2REVVM1dGU2MDdFdGp6RitJWWI4V0U4K2dH?= =?utf-8?B?Ry8zREFQUmJuUDd5NEorYnAvTjRrUXFUSGUxcnQ0c214VWVpSU1yUzZZTlpV?= =?utf-8?B?bGNaVFhMaE16RFUvM1A3MjFBcm5ER0pIc3lUR2syOHIyWldpSzlkbDlIQUxx?= =?utf-8?B?ZzdMVVFBNHhqbE5TbmttRUJxWmptWDJkYlEzdmtvaEI4ZDNJa05na2tjZVdp?= =?utf-8?B?RWpUSk9FZk4zR05VdDZCTEhVeWRjcEhQS0NDTUxOVW50VWhVSnVWRjZxK1Vp?= =?utf-8?B?MGtaZVlmdXovQmtxQktic0JtNUd3cEwrcmRNNEdEU0JEYU9Ja0s1WlNHRWlo?= =?utf-8?B?b08xOXl4bkFBT0lsMExIcXlLOVErRFZZb0RneHBBOXYwaHBFeW5jdWtVbDJa?= =?utf-8?B?Z2xoQ1poNWYxZkVXZEwrWEgzanc5cUJYdlU0bGwxWlJGeEdGQnE5QlpJUjZP?= =?utf-8?B?dTVPNTVEQ1hqdXlFNHRCUC9uQ0ErT1c1eW5haEdDb2JRWFRXNitSZDFwcThv?= =?utf-8?B?eGxabENsL2pQSFVMbG1pMk44VFY3ei9MdHRRZ0g3OE5lblNmVFhkUTJxQlI4?= =?utf-8?B?bzZzQjloeDAvMFBvY2Fvd1RkL05kd2ZlUHgwQzM4dnozejh3ZGJHT2RHak9P?= =?utf-8?B?NFNoMkRkeWtYdVVTakZqSm9PcmNZREZSZlU5M1pLUTVhQU5yLzgzSjRta1pl?= =?utf-8?B?WlQvQVF0K2dUVXBSMUxPYkk2M2s1cDJjNGJYRFdYNnpGM2xkZHdaU3FkaXMv?= =?utf-8?Q?/jxZiqSAtn0qbehZ9/quEqo1vgx8FVqHjj1muzh?= X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-Network-Message-Id: 3d6741e5-df76-4cac-a126-08d8f50f1845 X-MS-Exchange-CrossTenant-AuthSource: SN6PR12MB2718.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Apr 2021 13:07:25.6764 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: NBDgR+wuJpwr5wK11p8pIQnwSY8x/cgZKJTgY91UldlKxEQvKzGNFB6ldYLvfDoFdL5rirkqpj6OWX0qTFuUQA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SN1PR12MB2367 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit Content-Language: en-US Hi Yao, On 4/1/21 1:37 AM, Yao, Jiewen wrote: > Hi > Would you please clarify why the IA32 version implementation is empty? > > Does it mean IA32 does not need validate? > Or IA32 should never call this function? > > Anyway, I recommend to add some comment to describe it clearly. > If it should never be called, I recommend to add ASSERT(FALSE). AMD SEV, SEV-ES and SEV-SNP support is not available for the IA32 architecture. Nobody should be calling it. I will add an ASSERT(). Thanks > > +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/Ia32/SnpPageStateChange.c > @@ -0,0 +1,17 @@ > +#include > + > +#include "../SnpPageStateChange.h" > + > +/** > + The function is used to set the page state when SEV-SNP is active. The page state > + transition consist of changing the page ownership in the RMP table, and using the > + PVALIDATE instruction to update the Validated bit in RMP table. > + > + */ > +VOID > +SevSnpValidateSystemRamInternal ( > + IN EFI_PHYSICAL_ADDRESS BaseAddress, > + IN UINTN NumPages > + ) > +{ > +} > >> -----Original Message----- >> From: Brijesh Singh >> Sent: Wednesday, March 24, 2021 11:32 PM >> To: devel@edk2.groups.io >> Cc: Brijesh Singh ; James Bottomley >> ; Xu, Min M ; Yao, Jiewen >> ; Tom Lendacky ; Justen, >> Jordan L ; Ard Biesheuvel >> ; Laszlo Ersek >> Subject: [RFC PATCH 12/19] OvmfPkg/MemEncryptSevLib: Add support to >> validate system RAM >> >> BZ: https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fbugzilla.tianocore.org%2Fshow_bug.cgi%3Fid%3D3275&data=04%7C01%7Cbrijesh.singh%40amd.com%7C599bf9c821c94c0241ed08d8f4d8b2a5%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637528558846316719%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&sdata=4Lq97rE69lPFAsGjYb44e3u2mA9QlrJdayxTP9FG7w8%3D&reserved=0 >> >> 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: James Bottomley >> Cc: Min Xu >> Cc: Jiewen Yao >> Cc: Tom Lendacky >> Cc: Jordan Justen >> Cc: Ard Biesheuvel >> Cc: Laszlo Ersek >> Signed-off-by: Brijesh Singh >> --- >> OvmfPkg/Include/Library/MemEncryptSevLib.h | 15 ++ >> OvmfPkg/Library/BaseMemEncryptSevLib/Ia32/SnpPageStateChange.c | 17 >> ++ >> OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf | 4 + >> OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLibInternal.c | >> 20 ++ >> OvmfPkg/Library/BaseMemEncryptSevLib/SnpPageStateChange.h | 37 >> +++ >> OvmfPkg/Library/BaseMemEncryptSevLib/X64/SecSnpSystemRamValidate.c | >> 23 ++ >> OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChangeInternal.c | >> 254 ++++++++++++++++++++ >> 7 files changed, 370 insertions(+) >> >> diff --git a/OvmfPkg/Include/Library/MemEncryptSevLib.h >> b/OvmfPkg/Include/Library/MemEncryptSevLib.h >> index 03d9eda392..47d6802b61 100644 >> --- a/OvmfPkg/Include/Library/MemEncryptSevLib.h >> +++ b/OvmfPkg/Include/Library/MemEncryptSevLib.h >> @@ -215,4 +215,19 @@ MemEncryptSevGetAddressRangeState ( >> IN UINTN Length >> ); >> >> +/** >> + If SEV-SNP is active then set the page state of the specified virtual >> + address range. This should be called in SEC and PEI phases only. >> + >> + @param[in] BaseAddress Base address >> + @param[in] NumPages Number of pages starting from the base >> address >> + >> +**/ >> +VOID >> +EFIAPI >> +MemEncryptSevSnpValidateSystemRam ( >> + IN PHYSICAL_ADDRESS BaseAddress, >> + IN UINTN NumPages >> + ); >> + >> #endif // _MEM_ENCRYPT_SEV_LIB_H_ >> diff --git >> a/OvmfPkg/Library/BaseMemEncryptSevLib/Ia32/SnpPageStateChange.c >> b/OvmfPkg/Library/BaseMemEncryptSevLib/Ia32/SnpPageStateChange.c >> new file mode 100644 >> index 0000000000..dace5c0bcf >> --- /dev/null >> +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/Ia32/SnpPageStateChange.c >> @@ -0,0 +1,17 @@ >> +#include >> + >> +#include "../SnpPageStateChange.h" >> + >> +/** >> + The function is used to set the page state when SEV-SNP is active. The page >> state >> + transition consist of changing the page ownership in the RMP table, and using >> the >> + PVALIDATE instruction to update the Validated bit in RMP table. >> + >> + */ >> +VOID >> +SevSnpValidateSystemRamInternal ( >> + IN EFI_PHYSICAL_ADDRESS BaseAddress, >> + IN UINTN NumPages >> + ) >> +{ >> +} >> diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf >> b/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf >> index 279c38bfbc..8595e244c2 100644 >> --- a/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf >> +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf >> @@ -31,15 +31,19 @@ >> >> [Sources] >> SecMemEncryptSevLibInternal.c >> + SnpPageStateChange.h >> >> [Sources.X64] >> X64/MemEncryptSevLib.c >> X64/SecVirtualMemory.c >> + X64/SecSnpSystemRamValidate.c >> + X64/SnpPageStateChangeInternal.c >> X64/VirtualMemory.c >> X64/VirtualMemory.h >> >> [Sources.IA32] >> Ia32/MemEncryptSevLib.c >> + Ia32/SnpPageStateChange.c >> >> [LibraryClasses] >> BaseLib >> diff --git >> a/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLibInternal.c >> b/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLibInternal.c >> index 69852779e2..35a222e75e 100644 >> --- a/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLibInternal.c >> +++ >> b/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLibInternal.c >> @@ -17,6 +17,8 @@ >> #include >> #include >> >> +#include "SnpPageStateChange.h" >> + >> /** >> Reads and sets the status of SEV features. >> >> @@ -172,3 +174,21 @@ >> MemEncryptSevLocateInitialSmramSaveStateMapPages ( >> { >> return RETURN_UNSUPPORTED; >> } >> + >> +/** >> + If SEV-SNP is active then set the page state of the specified virtual >> + address range. This should be called in SEC and PEI phases only. >> + >> + @param[in] BaseAddress Base address >> + @param[in] NumPages Number of pages starting from the base >> address >> + >> +**/ >> +VOID >> +EFIAPI >> +MemEncryptSevSnpValidateSystemRam ( >> + IN PHYSICAL_ADDRESS BaseAddress, >> + IN UINTN NumPages >> + ) >> +{ >> + SevSnpValidateSystemRam (BaseAddress, NumPages); >> +} >> diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/SnpPageStateChange.h >> b/OvmfPkg/Library/BaseMemEncryptSevLib/SnpPageStateChange.h >> new file mode 100644 >> index 0000000000..3040930999 >> --- /dev/null >> +++ b/OvmfPkg/Library/BaseMemEncryptSevLib/SnpPageStateChange.h >> @@ -0,0 +1,37 @@ >> +/** @file >> + >> + SEV-SNP Page Validation functions. >> + >> + Copyright (c) 2020 - 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 >> +SevSnpValidateSystemRam ( >> + IN EFI_PHYSICAL_ADDRESS BaseAddress, >> + IN UINTN NumPages >> + ); >> + >> +VOID >> +SetPageStateInternal ( >> + IN EFI_PHYSICAL_ADDRESS BaseAddress, >> + IN UINTN NumPages, >> + IN SEV_SNP_PAGE_STATE State, >> + IN BOOLEAN UseLargeEntry >> + ); >> + >> +#endif >> diff --git >> a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SecSnpSystemRamValidate.c >> b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SecSnpSystemRamValidate.c >> new file mode 100644 >> index 0000000000..915706aad0 >> --- /dev/null >> +++ >> b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SecSnpSystemRamValidate.c >> @@ -0,0 +1,23 @@ >> +/** @file >> + >> + SEV-SNP Page Validation functions. >> + >> + Copyright (c) 2020 - 2021, AMD Incorporated. All rights reserved.
>> + >> + SPDX-License-Identifier: BSD-2-Clause-Patent >> + >> +**/ >> + >> +#include >> +#include >> + >> +#include "../SnpPageStateChange.h" >> + >> +VOID >> +SevSnpValidateSystemRam ( >> + IN EFI_PHYSICAL_ADDRESS BaseAddress, >> + IN UINTN NumPages >> + ) >> +{ >> + SetPageStateInternal (BaseAddress, NumPages, SevSnpPagePrivate, TRUE); >> +} >> diff --git >> a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChangeInternal.c >> b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChangeInternal.c >> new file mode 100644 >> index 0000000000..5a34db33fe >> --- /dev/null >> +++ >> b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SnpPageStateChangeInternal.c >> @@ -0,0 +1,254 @@ >> +/** @file >> + >> + SEV-SNP Page Validation functions. >> + >> + Copyright (c) 2020 - 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)) == 0)) >> +#define PAGES_PER_LARGE_ENTRY 512 >> +#define EFI_LARGE_PAGE (EFI_PAGE_SIZE * PAGES_PER_LARGE_ENTRY) >> + >> +STATIC >> +UINTN >> +MemoryStateToGhcbOp ( >> + IN SEV_SNP_PAGE_STATE State >> + ) >> +{ >> + UINTN Cmd; >> + >> + switch (State) { >> + case SevSnpPageShared: Cmd = SNP_PAGE_STATE_SHARED; break; >> + case SevSnpPagePrivate: Cmd = 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 = 0; >> + Msr.GhcbTerminate.Function = GHCB_INFO_TERMINATE_REQUEST; >> + Msr.GhcbTerminate.ReasonCodeSet = GHCB_TERMINATE_GHCB; >> + Msr.GhcbTerminate.ReasonCode = GHCB_TERMINATE_GHCB_GENERAL; >> + AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress); >> + >> + AsmVmgExit (); >> + >> + ASSERT (FALSE); >> + CpuDeadLoop (); >> +} >> + >> +STATIC >> +UINTN >> +IssuePvalidate ( >> + IN UINTN Address, >> + IN UINTN RmpPageSize, >> + IN BOOLEAN Validate >> + ) >> +{ >> + IA32_EFLAGS32 EFlags; >> + UINTN Ret; >> + >> + Ret = AsmPvalidate (RmpPageSize, Validate, Address, &EFlags); >> + >> + // >> + // Check the rFlags.CF to verify that PVALIDATE updated the RMP >> + // entry. If there was a no change in the RMP entry then we are >> + // either double validating or invalidating the memory. This can >> + // lead to a security compromise. >> + // >> + if (EFlags.Bits.CF) { >> + DEBUG ((DEBUG_ERROR, "%a:%a: Double %a detected for address 0x%Lx\n", >> + gEfiCallerBaseName, >> + __FUNCTION__, >> + Validate ? "Validate" : "Invalidate", >> + Address)); >> + SnpPageStateFailureTerminate (); >> + } >> + >> + return Ret; >> +} >> + >> +/** >> + This function issues the PVALIDATE instruction to validate or invalidate the >> memory >> + range specified. If PVALIDATE returns size mismatch then it tries validating >> 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 < EndIndex; StartIndex++) { >> + Address = Info->Entry[StartIndex].GuestFrameNumber << EFI_PAGE_SHIFT; >> + RmpPageSize = Info->Entry[StartIndex].PageSize; >> + >> + Ret = IssuePvalidate (Address, RmpPageSize, Validate); >> + >> + // >> + // 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 == PVALIDATE_RET_FAIL_SIZEMISMATCH) && >> + (RmpPageSize == PVALIDATE_PAGE_SIZE_2M)) { >> + for (i = 0; i < PAGES_PER_LARGE_ENTRY; i++) { >> + >> + Ret = IssuePvalidate (Address, PVALIDATE_PAGE_SIZE_4K, Validate); >> + if (Ret) { >> + break; >> + } >> + >> + Address = Address + EFI_PAGE_SIZE; >> + } >> + } >> + >> + 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 (); >> + } >> + } >> +} >> + >> +/** >> + The function is used to set the page state when SEV-SNP is active. The page >> state >> + transition consist of changing the page ownership in the RMP table, and using >> the >> + PVALIDATE instruction to update the Validated bit in RMP table. >> + >> + When the UseLargeEntry is set to TRUE, then use the large RMP entry. >> + */ >> +VOID >> +SetPageStateInternal ( >> + IN EFI_PHYSICAL_ADDRESS BaseAddress, >> + IN UINTN NumPages, >> + IN SEV_SNP_PAGE_STATE State, >> + IN BOOLEAN UseLargeEntry >> + ) >> +{ >> + EFI_STATUS Status; >> + GHCB *Ghcb; >> + EFI_PHYSICAL_ADDRESS NextAddress, EndAddress; >> + MSR_SEV_ES_GHCB_REGISTER Msr; >> + BOOLEAN InterruptState; >> + SNP_PAGE_STATE_CHANGE_INFO *Info; >> + UINTN i, RmpPageSize; >> + >> + Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB); >> + Ghcb = Msr.Ghcb; >> + >> + EndAddress = BaseAddress + EFI_PAGES_TO_SIZE (NumPages); >> + >> + DEBUG ((DEBUG_VERBOSE, "%a:%a Address 0x%Lx - 0x%Lx State = %a >> LargeEntry = %d\n", >> + gEfiCallerBaseName, >> + __FUNCTION__, >> + BaseAddress, >> + EndAddress, >> + State == SevSnpPageShared ? "Shared" : "Private", >> + UseLargeEntry)); >> + >> + for (; BaseAddress < EndAddress; BaseAddress = NextAddress) { >> + >> + // >> + // Initialize the GHCB and setup scratch sw to point to shared buffer. >> + // >> + VmgInit (Ghcb, &InterruptState); >> + Info = (SNP_PAGE_STATE_CHANGE_INFO *) Ghcb->SharedBuffer; >> + >> + SetMem (Info, sizeof (*Info), 0); >> + >> + // >> + // Build page state change buffer >> + // >> + for (i = 0; (EndAddress > BaseAddress) && i < SNP_PAGE_STATE_MAX_ENTRY; >> + BaseAddress = NextAddress, i++) { >> + // >> + // Is this a 2MB aligned page? Check if we can use the Large RMP entry. >> + // >> + if (UseLargeEntry && >> + IS_ALIGNED (BaseAddress, EFI_LARGE_PAGE) && >> + ((EndAddress - BaseAddress) >> EFI_PAGE_SHIFT) >= >> PAGES_PER_LARGE_ENTRY) { >> + RmpPageSize = PVALIDATE_PAGE_SIZE_2M; >> + NextAddress = BaseAddress + EFI_LARGE_PAGE; >> + } else { >> + RmpPageSize = PVALIDATE_PAGE_SIZE_4K; >> + NextAddress = BaseAddress + EFI_PAGE_SIZE; >> + } >> + >> + Info->Entry[i].GuestFrameNumber = BaseAddress >> EFI_PAGE_SHIFT; >> + Info->Entry[i].PageSize = RmpPageSize; >> + Info->Entry[i].Op = MemoryStateToGhcbOp (State); >> + Info->Entry[i].CurrentPage = 0; >> + } >> + >> + Info->Header.CurrentEntry = 0; >> + Info->Header.EndEntry = i - 1; >> + >> + // >> + // If the request page state change is shared then invalidate the pages before >> + // adding the page in the RMP table. >> + // >> + if (State == SevSnpPageShared) { >> + PvalidateRange (Info, 0, i, FALSE); >> + } >> + >> + // >> + // Issue the VMGEXIT and retry if hypervisor failed to process all the entries. >> + // >> + Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer; >> + VmgSetOffsetValid (Ghcb, GhcbSwScratch); >> + while (Info->Header.CurrentEntry <= Info->Header.EndEntry) { >> + Status = VmgExit (Ghcb, SVM_EXIT_SNP_PAGE_STATE_CHANGE, 0, 0); >> + if (EFI_ERROR (Status)) { >> + SnpPageStateFailureTerminate (); >> + } >> + } >> + >> + // >> + // If the request page state change is shared then invalidate the pages before >> + // adding the page in the RMP table. >> + // >> + if (State == SevSnpPagePrivate) { >> + PvalidateRange (Info, 0, i, TRUE); >> + } >> + >> + VmgDone (Ghcb, InterruptState); >> + } >> +} >> -- >> 2.17.1