Received: by 2002:a25:e74b:0:0:0:0:0 with SMTP id e72csp1705840ybh; Tue, 14 Jul 2020 05:19:47 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzTdmKAckUODankDsLgSM5OqD5PlTEMpIR5VotObxgNZ+LcnvGO0CVgZMrPhQuonCPuMu3z X-Received: by 2002:a17:906:b74e:: with SMTP id fx14mr4069088ejb.202.1594729187387; Tue, 14 Jul 2020 05:19:47 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1594729187; cv=none; d=google.com; s=arc-20160816; b=H5v+P5NPCoyyERJ5Ady4LEjmlrEzyd784d1urA1UOOdievxlTGTOrDANGDPlTsYc0D 1W+qlMo/n89eWGnFwxFZMZQcFRtLtD/w7W7czqE4sgDf8oRLkSWEw7zcGTlasMiDjjV5 p0XdjGomx11eQVki9z5qK//qXJ2ZFXR/NgwIQEb+lcvy6Zf6Fb5LOPNiIbwlHKtvlZiT A4oS2ZJLgBQ8r3mZI+SXrZCeUx3yrn9bVazJf6wmCVIwBCeXYmvvxRyfdGETUOJJ8Up2 RFOrQDgQrf6vw05eF5qmp0BNcXLRnP19niwe2ol0s4feq1sDDpjLQjIiNHom1M0O6KbT EkRQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=TpYjq2mRZOvmUAna3rK7uRu9Vng5tC3+7tAwKaV4GSc=; b=D6fp9IYjd8+NkaHZ5VVXrLzX2sOBTjGme6gZNpXeF4q+SyKdyIzixwYABembfB7e3r dCU8XuUQSu9q80w5dteMdTaKBr2hCx/CGlqqgNp+KaTSU7lzP9rXaLeAZai0xOkbDq7e RXwF8cPD2+iD/al2UDu1eaSX32A7zAjCqWY6n5UYx8mHEH8/fg8qMLs6xs3Lb+l206kA Td9E1Fc03oLz1zWU941aC3EdYP6hyNWXi4+zo6PUiyFWrTvXQBJaFStPiAOVXTpmMGU7 4XaBTLENmPnszOQIbmLa9mTYvB1gvn8Bqij/N6uYf/RxqvJXjnDFLKZNYddntiqZjCQV GjXg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=8bytes.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id a9si10780292edt.401.2020.07.14.05.19.23; Tue, 14 Jul 2020 05:19:47 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=8bytes.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728271AbgGNMKt (ORCPT + 99 others); Tue, 14 Jul 2020 08:10:49 -0400 Received: from 8bytes.org ([81.169.241.247]:52886 "EHLO theia.8bytes.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728253AbgGNMKr (ORCPT ); Tue, 14 Jul 2020 08:10:47 -0400 Received: from cap.home.8bytes.org (p5b006776.dip0.t-ipconnect.de [91.0.103.118]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by theia.8bytes.org (Postfix) with ESMTPSA id 405727BC; Tue, 14 Jul 2020 14:10:44 +0200 (CEST) From: Joerg Roedel To: x86@kernel.org Cc: Joerg Roedel , Joerg Roedel , hpa@zytor.com, Andy Lutomirski , Dave Hansen , Peter Zijlstra , Jiri Slaby , Dan Williams , Tom Lendacky , Juergen Gross , Kees Cook , David Rientjes , Cfir Cohen , Erdem Aktas , Masami Hiramatsu , Mike Stunes , Sean Christopherson , Martin Radev , linux-kernel@vger.kernel.org, kvm@vger.kernel.org, virtualization@lists.linux-foundation.org Subject: [PATCH v4 21/75] x86/boot/compressed/64: Add set_page_en/decrypted() helpers Date: Tue, 14 Jul 2020 14:08:23 +0200 Message-Id: <20200714120917.11253-22-joro@8bytes.org> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200714120917.11253-1-joro@8bytes.org> References: <20200714120917.11253-1-joro@8bytes.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Joerg Roedel The functions are needed to map the GHCB for SEV-ES guests. The GHCB is used for communication with the hypervisor, so its content must not be encrypted. After the GHCB is not needed anymore it must be mapped encrypted again so that the running kernel image can safely re-use the memory. Signed-off-by: Joerg Roedel --- arch/x86/boot/compressed/ident_map_64.c | 133 ++++++++++++++++++++++++ arch/x86/boot/compressed/misc.h | 2 + 2 files changed, 135 insertions(+) diff --git a/arch/x86/boot/compressed/ident_map_64.c b/arch/x86/boot/compressed/ident_map_64.c index aa91bebc0fe9..05742f641a06 100644 --- a/arch/x86/boot/compressed/ident_map_64.c +++ b/arch/x86/boot/compressed/ident_map_64.c @@ -24,6 +24,7 @@ /* These actually do the work of building the kernel identity maps. */ #include +#include #include #include #include @@ -165,6 +166,138 @@ void finalize_identity_maps(void) write_cr3(top_level_pgt); } +static pte_t *split_large_pmd(struct x86_mapping_info *info, + pmd_t *pmdp, unsigned long __address) +{ + unsigned long page_flags; + unsigned long address; + pte_t *pte; + pmd_t pmd; + int i; + + pte = (pte_t *)info->alloc_pgt_page(info->context); + if (!pte) + return NULL; + + address = __address & PMD_MASK; + /* No large page - clear PSE flag */ + page_flags = info->page_flag & ~_PAGE_PSE; + + /* Populate the PTEs */ + for (i = 0; i < PTRS_PER_PMD; i++) { + set_pte(&pte[i], __pte(address | page_flags)); + address += PAGE_SIZE; + } + + /* + * Ideally we need to clear the large PMD first and do a TLB + * flush before we write the new PMD. But the 2M range of the + * PMD might contain the code we execute and/or the stack + * we are on, so we can't do that. But that should be safe here + * because we are going from large to small mappings and we are + * also the only user of the page-table, so there is no chance + * of a TLB multihit. + */ + pmd = __pmd((unsigned long)pte | info->kernpg_flag); + set_pmd(pmdp, pmd); + /* Flush TLB to establish the new PMD */ + write_cr3(top_level_pgt); + + return pte + pte_index(__address); +} + +static void clflush_page(unsigned long address) +{ + unsigned int flush_size; + char *cl, *start, *end; + + /* + * Hardcode cl-size to 64 - CPUID can't be used here because that might + * cause another #VC exception and the GHCB is not ready to use yet. + */ + flush_size = 64; + start = (char *)(address & PAGE_MASK); + end = start + PAGE_SIZE; + + /* + * First make sure there are no pending writes on the cache-lines to + * flush. + */ + asm volatile("mfence" : : : "memory"); + + for (cl = start; cl != end; cl += flush_size) + clflush(cl); +} + +static int set_clr_page_flags(struct x86_mapping_info *info, + unsigned long address, + pteval_t set, pteval_t clr) +{ + pgd_t *pgdp = (pgd_t *)top_level_pgt; + p4d_t *p4dp; + pud_t *pudp; + pmd_t *pmdp; + pte_t *ptep, pte; + + /* + * First make sure there is a PMD mapping for 'address'. + * It should already exist, but keep things generic. + * + * To map the page just read from it and fault it in if there is no + * mapping yet. add_identity_map() can't be called here because that + * would unconditionally map the address on PMD level, destroying any + * PTE-level mappings that might already exist. Use assembly here so + * the access won't be optimized away. + */ + asm volatile("mov %[address], %%r9" + :: [address] "g" (*(unsigned long *)address) + : "r9", "memory"); + + /* + * The page is mapped at least with PMD size - so skip checks and walk + * directly to the PMD. + */ + p4dp = p4d_offset(pgdp, address); + pudp = pud_offset(p4dp, address); + pmdp = pmd_offset(pudp, address); + + if (pmd_large(*pmdp)) + ptep = split_large_pmd(info, pmdp, address); + else + ptep = pte_offset_kernel(pmdp, address); + + if (!ptep) + return -ENOMEM; + + /* + * Changing encryption attributes of a page requires to flush it from + * the caches. + */ + if ((set | clr) & _PAGE_ENC) + clflush_page(address); + + /* Update PTE */ + pte = *ptep; + pte = pte_set_flags(pte, set); + pte = pte_clear_flags(pte, clr); + set_pte(ptep, pte); + + /* Flush TLB after changing encryption attribute */ + write_cr3(top_level_pgt); + + return 0; +} + +int set_page_decrypted(unsigned long address) +{ + return set_clr_page_flags(&mapping_info, address, 0, _PAGE_ENC); +} + +int set_page_encrypted(unsigned long address) +{ + return set_clr_page_flags(&mapping_info, address, _PAGE_ENC, 0); +} + static void do_pf_error(const char *msg, unsigned long error_code, unsigned long address, unsigned long ip) { diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h index 65da40777bc1..5e569e8a7d75 100644 --- a/arch/x86/boot/compressed/misc.h +++ b/arch/x86/boot/compressed/misc.h @@ -98,6 +98,8 @@ static inline void choose_random_location(unsigned long input, #endif #ifdef CONFIG_X86_64 +extern int set_page_decrypted(unsigned long address); +extern int set_page_encrypted(unsigned long address); extern unsigned char _pgtable[]; #endif -- 2.27.0