Received: by 2002:a05:6520:2586:b029:fa:41f3:c225 with SMTP id u6csp29643lky; Wed, 9 Jun 2021 14:57:51 -0700 (PDT) X-Google-Smtp-Source: ABdhPJw7ZCUh43vPRLUC5LgeAIGkUJLs/LRIgjt8wX2e4GgRrFT/kXFzQoMcuJ0oIM7qW6+GlgD4 X-Received: by 2002:a17:906:1f90:: with SMTP id t16mr1640373ejr.297.1623275871010; Wed, 09 Jun 2021 14:57:51 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1623275871; cv=none; d=google.com; s=arc-20160816; b=LupXQbGfYM4MhSXTL5GHw7Sb3NdTnj6kvjKpNnkJrZL5OSKTmqwcza0U8FmS8jsKtY UM3gPJ1Sfgzdwf8x92QlK/He1bjVLPcH7FpkBWLNb5K34+dKjqs2D0ERTu1R5QVknuUE UGIe6UeG3bSwm7qjvhAgOih/Gi5rOxbfBf2zrSI/MnD/PpZuE5PktsSNcQLF4/eYfffg nWHJBllGrxCmcVtTmf4Xl/Z1kE/O5ZygXd6jBtimaTHU7Zhhx7AB4YzhLzBZ9Tz5HWwo cvoUYbp6Q8oXbmRkFjf+pi5XyO5FnxrPsvi4qnhR2v0QtO6Pw6lYN97zf21JSiBcBhMu Aejw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :ironport-sdr:ironport-sdr; bh=+fvMFPDTEm2wWH/dM9oXjqzs4/sZWVyfJPymEr6wMXU=; b=L2Ec5iRJHl4cnZp/bK5qFjRHairZR1R+CtIfAT4NLKNL6eU4sdMoWnHvhhPHyl68Gv BEBZh/VXm/09j8kDLxBAuuo97lO9vOtMo6xK3MziBbet841VuNVsQdcLd3zgTJTKrDkf rnXd0whO0CpORi+Q493X16VRRxdh2etDB1s8g0TxyD7y+XRrOPkQVJsNQcO/Ozz20qll CiH2fgmytvbV6Bz+ANBfFZE9316TYed4ZmH+kVC8PsGkNDcwv8dLGQjr5i1j9YeX6Chz rGDNmIjKRK36R6so8m4OgvrJWX9y2OK++70KQmRr/gnJxCPOAXHDf9WT8Y65Y0Hw4RfN sefA== 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=intel.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id bc3si637506edb.214.2021.06.09.14.57.27; Wed, 09 Jun 2021 14:57:51 -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=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230136AbhFIV5z (ORCPT + 99 others); Wed, 9 Jun 2021 17:57:55 -0400 Received: from mga03.intel.com ([134.134.136.65]:1785 "EHLO mga03.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230017AbhFIV5u (ORCPT ); Wed, 9 Jun 2021 17:57:50 -0400 IronPort-SDR: 4oRQnWHwSRMHCD2RHKW5Quj3HprMrDYnKRZ6Wqr1KUo1ZkQsfEjrNF6KpSQydNT9TkQMTxa5QV qh7ye8qUsxfw== X-IronPort-AV: E=McAfee;i="6200,9189,10010"; a="205208548" X-IronPort-AV: E=Sophos;i="5.83,261,1616482800"; d="scan'208";a="205208548" Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 09 Jun 2021 14:55:55 -0700 IronPort-SDR: IRFnChYaecZgk6Vg9VuYwYyEY9CHtV8P+9F4/HT/Fe8NsON6kto77BpuNy33Xkiub5ZMOq6ecq 3NVb06AckvPg== X-IronPort-AV: E=Sophos;i="5.83,261,1616482800"; d="scan'208";a="482555107" Received: from qwang4-mobl1.ccr.corp.intel.com (HELO skuppusw-desk1.amr.corp.intel.com) ([10.254.35.228]) by orsmga001-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 09 Jun 2021 14:55:53 -0700 From: Kuppuswamy Sathyanarayanan To: Thomas Gleixner , Ingo Molnar , Borislav Petkov , Peter Zijlstra , Andy Lutomirski Cc: Peter H Anvin , Dave Hansen , Tony Luck , Dan Williams , Andi Kleen , Kirill Shutemov , Sean Christopherson , Kuppuswamy Sathyanarayanan , x86@kernel.org, linux-kernel@vger.kernel.org, Kai Huang , Sean Christopherson Subject: [PATCH v1 5/7] x86/tdx: Make DMA pages shared Date: Wed, 9 Jun 2021 14:55:35 -0700 Message-Id: <20210609215537.1956150-6-sathyanarayanan.kuppuswamy@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210609215537.1956150-1-sathyanarayanan.kuppuswamy@linux.intel.com> References: <20210609215537.1956150-1-sathyanarayanan.kuppuswamy@linux.intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: "Kirill A. Shutemov" Just like MKTME, TDX reassigns bits of the physical address for metadata. MKTME used several bits for an encryption KeyID. TDX uses a single bit in guests to communicate whether a physical page should be protected by TDX as private memory (bit set to 0) or unprotected and shared with the VMM (bit set to 1). __set_memory_enc_dec() is now aware about TDX and sets Shared bit accordingly following with relevant TDX hypercall. Also, Do TDACCEPTPAGE on every 4k page after mapping the GPA range when converting memory to private. Using 4k page size limit is due to current TDX spec restriction. Also, If the GPA (range) was already mapped as an active, private page, the host VMM may remove the private page from the TD by following the “Removing TD Private Pages” sequence in the Intel TDX-module specification [1] to safely block the mapping(s), flush the TLB and cache, and remove the mapping(s). BUG() if TDACCEPTPAGE fails (except "previously accepted page" case) , as the guest is completely hosed if it can't access memory.  [1] https://software.intel.com/content/dam/develop/external/us/en/documents/tdx-module-1eas-v0.85.039.pdf Tested-by: Kai Huang Signed-off-by: Kirill A. Shutemov Signed-off-by: Sean Christopherson Reviewed-by: Andi Kleen Reviewed-by: Tony Luck Signed-off-by: Kuppuswamy Sathyanarayanan --- arch/x86/include/asm/pgtable.h | 1 + arch/x86/kernel/tdx.c | 34 ++++++++++++++++++----- arch/x86/mm/mem_encrypt_common.c | 3 +++ arch/x86/mm/pat/set_memory.c | 46 +++++++++++++++++++++++++++----- 4 files changed, 71 insertions(+), 13 deletions(-) diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index 5b77843dfa10..41c8d3ace070 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -24,6 +24,7 @@ /* Make the page accesable by VMM for protected guests */ #define pgprot_protected_guest(prot) __pgprot(pgprot_val(prot) | \ tdg_shared_mask()) +#define pgprot_pg_shared_mask() __pgprot(tdg_shared_mask()) #ifndef __ASSEMBLY__ #include diff --git a/arch/x86/kernel/tdx.c b/arch/x86/kernel/tdx.c index 591643abae88..c90871a10443 100644 --- a/arch/x86/kernel/tdx.c +++ b/arch/x86/kernel/tdx.c @@ -16,10 +16,14 @@ /* TDX Module call Leaf IDs */ #define TDINFO 1 #define TDGETVEINFO 3 +#define TDACCEPTPAGE 6 /* TDX hypercall Leaf IDs */ #define TDVMCALL_MAP_GPA 0x10001 +/* TDX Module call error codes */ +#define TDX_PAGE_ALREADY_ACCEPTED 0x8000000000000001 + #define VE_IS_IO_OUT(exit_qual) (((exit_qual) & 8) ? 0 : 1) #define VE_GET_IO_SIZE(exit_qual) (((exit_qual) & 7) + 1) #define VE_GET_PORT_NUM(exit_qual) ((exit_qual) >> 16) @@ -124,25 +128,43 @@ static void tdg_get_info(void) physical_mask &= ~tdg_shared_mask(); } +static void tdg_accept_page(phys_addr_t gpa) +{ + u64 ret; + + ret = __tdx_module_call(TDACCEPTPAGE, gpa, 0, 0, 0, NULL); + + BUG_ON(ret && ret != TDX_PAGE_ALREADY_ACCEPTED); +} + /* * Inform the VMM of the guest's intent for this physical page: * shared with the VMM or private to the guest. The VMM is * expected to change its mapping of the page in response. - * - * Note: shared->private conversions require further guest - * action to accept the page. */ int tdx_hcall_gpa_intent(phys_addr_t gpa, int numpages, enum tdx_map_type map_type) { - u64 ret; + u64 ret = 0; + int i; if (map_type == TDX_MAP_SHARED) gpa |= tdg_shared_mask(); - ret = tdx_hypercall(TDVMCALL_MAP_GPA, gpa, PAGE_SIZE * numpages, 0, 0); + if (tdx_hypercall(TDVMCALL_MAP_GPA, gpa, PAGE_SIZE * numpages, 0, 0)) + ret = -EIO; - return ret ? -EIO : 0; + if (ret || map_type == TDX_MAP_SHARED) + return ret; + + /* + * For shared->private conversion, accept the page using TDACCEPTPAGE + * TDX module call. + */ + for (i = 0; i < numpages; i++) + tdg_accept_page(gpa + i * PAGE_SIZE); + + return 0; } static __cpuidle void tdg_halt(void) diff --git a/arch/x86/mm/mem_encrypt_common.c b/arch/x86/mm/mem_encrypt_common.c index 4a9a4d5f36cd..8053b43298ff 100644 --- a/arch/x86/mm/mem_encrypt_common.c +++ b/arch/x86/mm/mem_encrypt_common.c @@ -16,5 +16,8 @@ bool force_dma_unencrypted(struct device *dev) if (sev_active() || sme_active()) return amd_force_dma_unencrypted(dev); + if (prot_guest_has(PR_GUEST_MEM_ENCRYPT)) + return true; + return false; } diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c index 156cd235659f..fa0f2de20617 100644 --- a/arch/x86/mm/pat/set_memory.c +++ b/arch/x86/mm/pat/set_memory.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "../mm_internal.h" @@ -1980,13 +1981,16 @@ int set_memory_global(unsigned long addr, int numpages) __pgprot(_PAGE_GLOBAL), 0); } -static int __set_memory_enc_dec(unsigned long addr, int numpages, bool enc) +static int __set_memory_protect(unsigned long addr, int numpages, bool protect) { + pgprot_t mem_protected_bits, mem_plain_bits; struct cpa_data cpa; + enum tdx_map_type map_type; int ret; /* Nothing to do if memory encryption is not active */ - if (!mem_encrypt_active()) + if (!mem_encrypt_active() && + !prot_guest_has(PR_GUEST_MEM_ENCRYPT_ACTIVE)) return 0; /* Should not be working on unaligned addresses */ @@ -1996,8 +2000,25 @@ static int __set_memory_enc_dec(unsigned long addr, int numpages, bool enc) memset(&cpa, 0, sizeof(cpa)); cpa.vaddr = &addr; cpa.numpages = numpages; - cpa.mask_set = enc ? __pgprot(_PAGE_ENC) : __pgprot(0); - cpa.mask_clr = enc ? __pgprot(0) : __pgprot(_PAGE_ENC); + + if (prot_guest_has(PR_GUEST_SHARED_MAPPING_INIT)) { + mem_protected_bits = __pgprot(0); + mem_plain_bits = pgprot_pg_shared_mask(); + } else { + mem_protected_bits = __pgprot(_PAGE_ENC); + mem_plain_bits = __pgprot(0); + } + + if (protect) { + cpa.mask_set = mem_protected_bits; + cpa.mask_clr = mem_plain_bits; + map_type = TDX_MAP_PRIVATE; + } else { + cpa.mask_set = mem_plain_bits; + cpa.mask_clr = mem_protected_bits; + map_type = TDX_MAP_SHARED; + } + cpa.pgd = init_mm.pgd; /* Must avoid aliasing mappings in the highmem code */ @@ -2006,8 +2027,16 @@ static int __set_memory_enc_dec(unsigned long addr, int numpages, bool enc) /* * Before changing the encryption attribute, we need to flush caches. + * + * For TDX we need to flush caches on private->shared. VMM is + * responsible for flushing on shared->private. */ - cpa_flush(&cpa, !this_cpu_has(X86_FEATURE_SME_COHERENT)); + if (is_tdx_guest()) { + if (map_type == TDX_MAP_SHARED) + cpa_flush(&cpa, 1); + } else { + cpa_flush(&cpa, !this_cpu_has(X86_FEATURE_SME_COHERENT)); + } ret = __change_page_attr_set_clr(&cpa, 1); @@ -2020,18 +2049,21 @@ static int __set_memory_enc_dec(unsigned long addr, int numpages, bool enc) */ cpa_flush(&cpa, 0); + if (!ret && prot_guest_has(PR_GUEST_SHARED_MAPPING_INIT)) + ret = tdx_hcall_gpa_intent(__pa(addr), numpages, map_type); + return ret; } int set_memory_encrypted(unsigned long addr, int numpages) { - return __set_memory_enc_dec(addr, numpages, true); + return __set_memory_protect(addr, numpages, true); } EXPORT_SYMBOL_GPL(set_memory_encrypted); int set_memory_decrypted(unsigned long addr, int numpages) { - return __set_memory_enc_dec(addr, numpages, false); + return __set_memory_protect(addr, numpages, false); } EXPORT_SYMBOL_GPL(set_memory_decrypted); -- 2.25.1