From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6F3DBC43216 for ; Mon, 9 Aug 2021 17:56:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4AFFF61040 for ; Mon, 9 Aug 2021 17:56:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235142AbhHIR46 (ORCPT ); Mon, 9 Aug 2021 13:56:58 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36568 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235000AbhHIR4x (ORCPT ); Mon, 9 Aug 2021 13:56:53 -0400 Received: from mail-pl1-x629.google.com (mail-pl1-x629.google.com [IPv6:2607:f8b0:4864:20::629]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8EF25C0613D3; Mon, 9 Aug 2021 10:56:32 -0700 (PDT) Received: by mail-pl1-x629.google.com with SMTP id z3so17305261plg.8; Mon, 09 Aug 2021 10:56:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Zn6gCEnKxJzxqfuyJcO64i09lNmUHRRDFMW+U0r9l4c=; b=F4F48f4jr6DNkNJAqrdEmKYpyJXH1h/G5q/zjgsZrCdkssJo2/cWbiFQpW3YP7iLjY sXZCJj9c6tMDviC1cbicPKVYWNBpnrK7yAV4AHtPvfQjM5XkcSZOWLxb0fywEI9nUj6c 6ZcdMH0wYWG6o7FLNJ2ZkE0455JwRDus1HZ57miGOfy51q/Dc3MjRHe4mt5bOIDiS8AK 6CcihOvWiRXqTaeIV/+AlVz0rod48dEm17wA5a35+fmvkjBNVjiMtcaWCgPg/EA63dgQ ziV2CQI+/ejbhhsQ1JkIqLBwWPkQ8Q31SoHAavmQAa9PymbgUO5Wc/Iq2MHRhBzMJcK8 B8Fg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Zn6gCEnKxJzxqfuyJcO64i09lNmUHRRDFMW+U0r9l4c=; b=Gn776Uxdiv7yLbogZJ9LPutRRNiUkweGPIFE89hhDzMrdkpJb5YeoFSU+DKONjz3+v jUjg56dsMzT1Q26xQN/Jo8IWFCOR9RDSnxQQutzWhTeH2Zmvh8f4cPvOErGtFV4yFNtn ZfVvCmV/LhZWFYjLoqR3piXbBoBnnL+qT+0xE3L+C5KxJltsxfqZO/DZeSzIZk5X8gml qWSK86Ao4Im74PgCXFKppDn7eFp4xEfE3h2C5L3pT/r2CunCnJwqgMFero99GAUdwFTl rpt3FQx4Mi86YfEBdl7cEVbMDcNMnYLg3wBMMk4bw6HCtaKyXi6w20+PzPqKWBt5D7Pf a8Fg== X-Gm-Message-State: AOAM530zHT41bIJ+E90Lel8YdNVKhIlaB5LlQIiqMjXydzVKyggF2xMp qmdmdiB9vSHwscsm/+srhKg= X-Google-Smtp-Source: ABdhPJzj2I3P/UMvsOq2c11ZGlrODCC2Lo52LstZDkdvjFRxOvD2OIwXBZKpPA2TUULjg7qyGih5Qg== X-Received: by 2002:a17:90a:1f49:: with SMTP id y9mr296003pjy.225.1628531791065; Mon, 09 Aug 2021 10:56:31 -0700 (PDT) Received: from ubuntu-Virtual-Machine.corp.microsoft.com ([2001:4898:80e8:2:106e:6ed1:5da1:2ac4]) by smtp.gmail.com with ESMTPSA id x14sm20589708pfa.127.2021.08.09.10.56.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Aug 2021 10:56:30 -0700 (PDT) From: Tianyu Lan To: kys@microsoft.com, haiyangz@microsoft.com, sthemmin@microsoft.com, wei.liu@kernel.org, decui@microsoft.com, tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, x86@kernel.org, hpa@zytor.com, dave.hansen@linux.intel.com, luto@kernel.org, peterz@infradead.org, konrad.wilk@oracle.com, boris.ostrovsky@oracle.com, jgross@suse.com, sstabellini@kernel.org, joro@8bytes.org, will@kernel.org, davem@davemloft.net, kuba@kernel.org, jejb@linux.ibm.com, martin.petersen@oracle.com, arnd@arndb.de, hch@lst.de, m.szyprowski@samsung.com, robin.murphy@arm.com, thomas.lendacky@amd.com, brijesh.singh@amd.com, ardb@kernel.org, Tianyu.Lan@microsoft.com, pgonda@google.com, martin.b.radev@gmail.com, akpm@linux-foundation.org, kirill.shutemov@linux.intel.com, rppt@kernel.org, sfr@canb.auug.org.au, saravanand@fb.com, krish.sadhukhan@oracle.com, aneesh.kumar@linux.ibm.com, xen-devel@lists.xenproject.org, rientjes@google.com, hannes@cmpxchg.org, tj@kernel.org, michael.h.kelley@microsoft.com Cc: iommu@lists.linux-foundation.org, linux-arch@vger.kernel.org, linux-hyperv@vger.kernel.org, linux-kernel@vger.kernel.org, linux-scsi@vger.kernel.org, netdev@vger.kernel.org, vkuznets@redhat.com, parri.andrea@gmail.com, dave.hansen@intel.com Subject: [PATCH V3 03/13] x86/HV: Add new hvcall guest address host visibility support Date: Mon, 9 Aug 2021 13:56:07 -0400 Message-Id: <20210809175620.720923-4-ltykernel@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210809175620.720923-1-ltykernel@gmail.com> References: <20210809175620.720923-1-ltykernel@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Tianyu Lan Add new hvcall guest address host visibility support to mark memory visible to host. Call it inside set_memory_decrypted /encrypted(). Add HYPERVISOR feature check in the hv_is_isolation_supported() to optimize in non-virtualization environment. Signed-off-by: Tianyu Lan --- Change since v2: * Rework __set_memory_enc_dec() and call Hyper-V and AMD function according to platform check. Change since v1: * Use new staic call x86_set_memory_enc to avoid add Hyper-V specific check in the set_memory code. --- arch/x86/hyperv/Makefile | 2 +- arch/x86/hyperv/hv_init.c | 6 ++ arch/x86/hyperv/ivm.c | 114 +++++++++++++++++++++++++++++ arch/x86/include/asm/hyperv-tlfs.h | 20 +++++ arch/x86/include/asm/mshyperv.h | 4 +- arch/x86/mm/pat/set_memory.c | 19 +++-- include/asm-generic/hyperv-tlfs.h | 1 + include/asm-generic/mshyperv.h | 1 + 8 files changed, 160 insertions(+), 7 deletions(-) create mode 100644 arch/x86/hyperv/ivm.c diff --git a/arch/x86/hyperv/Makefile b/arch/x86/hyperv/Makefile index 48e2c51464e8..5d2de10809ae 100644 --- a/arch/x86/hyperv/Makefile +++ b/arch/x86/hyperv/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-y := hv_init.o mmu.o nested.o irqdomain.o +obj-y := hv_init.o mmu.o nested.o irqdomain.o ivm.o obj-$(CONFIG_X86_64) += hv_apic.o hv_proc.o ifdef CONFIG_X86_64 diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c index 0bb4d9ca7a55..b3683083208a 100644 --- a/arch/x86/hyperv/hv_init.c +++ b/arch/x86/hyperv/hv_init.c @@ -607,6 +607,12 @@ EXPORT_SYMBOL_GPL(hv_get_isolation_type); bool hv_is_isolation_supported(void) { + if (!cpu_feature_enabled(X86_FEATURE_HYPERVISOR)) + return 0; + + if (!hypervisor_is_type(X86_HYPER_MS_HYPERV)) + return 0; + return hv_get_isolation_type() != HV_ISOLATION_TYPE_NONE; } diff --git a/arch/x86/hyperv/ivm.c b/arch/x86/hyperv/ivm.c new file mode 100644 index 000000000000..8c905ffdba7f --- /dev/null +++ b/arch/x86/hyperv/ivm.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hyper-V Isolation VM interface with paravisor and hypervisor + * + * Author: + * Tianyu Lan + */ + +#include +#include +#include +#include +#include +#include + +/* + * hv_mark_gpa_visibility - Set pages visible to host via hvcall. + * + * In Isolation VM, all guest memory is encripted from host and guest + * needs to set memory visible to host via hvcall before sharing memory + * with host. + */ +int hv_mark_gpa_visibility(u16 count, const u64 pfn[], + enum hv_mem_host_visibility visibility) +{ + struct hv_gpa_range_for_visibility **input_pcpu, *input; + u16 pages_processed; + u64 hv_status; + unsigned long flags; + + /* no-op if partition isolation is not enabled */ + if (!hv_is_isolation_supported()) + return 0; + + if (count > HV_MAX_MODIFY_GPA_REP_COUNT) { + pr_err("Hyper-V: GPA count:%d exceeds supported:%lu\n", count, + HV_MAX_MODIFY_GPA_REP_COUNT); + return -EINVAL; + } + + local_irq_save(flags); + input_pcpu = (struct hv_gpa_range_for_visibility **) + this_cpu_ptr(hyperv_pcpu_input_arg); + input = *input_pcpu; + if (unlikely(!input)) { + local_irq_restore(flags); + return -EINVAL; + } + + input->partition_id = HV_PARTITION_ID_SELF; + input->host_visibility = visibility; + input->reserved0 = 0; + input->reserved1 = 0; + memcpy((void *)input->gpa_page_list, pfn, count * sizeof(*pfn)); + hv_status = hv_do_rep_hypercall( + HVCALL_MODIFY_SPARSE_GPA_PAGE_HOST_VISIBILITY, count, + 0, input, &pages_processed); + local_irq_restore(flags); + + if (!(hv_status & HV_HYPERCALL_RESULT_MASK)) + return 0; + + return hv_status & HV_HYPERCALL_RESULT_MASK; +} +EXPORT_SYMBOL(hv_mark_gpa_visibility); + +static int __hv_set_mem_host_visibility(void *kbuffer, int pagecount, + enum hv_mem_host_visibility visibility) +{ + u64 *pfn_array; + int ret = 0; + int i, pfn; + + if (!hv_is_isolation_supported() || !ms_hyperv.ghcb_base) + return 0; + + pfn_array = kzalloc(HV_HYP_PAGE_SIZE, GFP_KERNEL); + if (!pfn_array) + return -ENOMEM; + + for (i = 0, pfn = 0; i < pagecount; i++) { + pfn_array[pfn] = virt_to_hvpfn(kbuffer + i * HV_HYP_PAGE_SIZE); + pfn++; + + if (pfn == HV_MAX_MODIFY_GPA_REP_COUNT || i == pagecount - 1) { + ret |= hv_mark_gpa_visibility(pfn, pfn_array, + visibility); + pfn = 0; + + if (ret) + goto err_free_pfn_array; + } + } + + err_free_pfn_array: + kfree(pfn_array); + return ret; +} + +/* + * hv_set_mem_host_visibility - Set specified memory visible to host. + * + * In Isolation VM, all guest memory is encrypted from host and guest + * needs to set memory visible to host via hvcall before sharing memory + * with host. This function works as wrap of hv_mark_gpa_visibility() + * with memory base and size. + */ +int hv_set_mem_host_visibility(unsigned long addr, int numpages, bool visible) +{ + enum hv_mem_host_visibility visibility = visible ? + VMBUS_PAGE_VISIBLE_READ_WRITE : VMBUS_PAGE_NOT_VISIBLE; + + return __hv_set_mem_host_visibility((void *)addr, numpages, visibility); +} diff --git a/arch/x86/include/asm/hyperv-tlfs.h b/arch/x86/include/asm/hyperv-tlfs.h index 2322d6bd5883..1691d2bce0b7 100644 --- a/arch/x86/include/asm/hyperv-tlfs.h +++ b/arch/x86/include/asm/hyperv-tlfs.h @@ -276,6 +276,13 @@ enum hv_isolation_type { #define HV_X64_MSR_TIME_REF_COUNT HV_REGISTER_TIME_REF_COUNT #define HV_X64_MSR_REFERENCE_TSC HV_REGISTER_REFERENCE_TSC +/* Hyper-V memory host visibility */ +enum hv_mem_host_visibility { + VMBUS_PAGE_NOT_VISIBLE = 0, + VMBUS_PAGE_VISIBLE_READ_ONLY = 1, + VMBUS_PAGE_VISIBLE_READ_WRITE = 3 +}; + /* * Declare the MSR used to setup pages used to communicate with the hypervisor. */ @@ -587,4 +594,17 @@ enum hv_interrupt_type { #include +/* All input parameters should be in single page. */ +#define HV_MAX_MODIFY_GPA_REP_COUNT \ + ((PAGE_SIZE / sizeof(u64)) - 2) + +/* HvCallModifySparseGpaPageHostVisibility hypercall */ +struct hv_gpa_range_for_visibility { + u64 partition_id; + u32 host_visibility:2; + u32 reserved0:30; + u32 reserved1; + u64 gpa_page_list[HV_MAX_MODIFY_GPA_REP_COUNT]; +} __packed; + #endif diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h index 6627cfd2bfba..87a386fa97f7 100644 --- a/arch/x86/include/asm/mshyperv.h +++ b/arch/x86/include/asm/mshyperv.h @@ -190,7 +190,9 @@ struct irq_domain *hv_create_pci_msi_domain(void); int hv_map_ioapic_interrupt(int ioapic_id, bool level, int vcpu, int vector, struct hv_interrupt_entry *entry); int hv_unmap_ioapic_interrupt(int ioapic_id, struct hv_interrupt_entry *entry); - +int hv_mark_gpa_visibility(u16 count, const u64 pfn[], + enum hv_mem_host_visibility visibility); +int hv_set_mem_host_visibility(unsigned long addr, int numpages, bool visible); #else /* CONFIG_HYPERV */ static inline void hyperv_init(void) {} static inline void hyperv_setup_mmu_ops(void) {} diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c index ad8a5c586a35..1e4a0882820a 100644 --- a/arch/x86/mm/pat/set_memory.c +++ b/arch/x86/mm/pat/set_memory.c @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include "../mm_internal.h" @@ -1980,15 +1982,11 @@ 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_enc_pgtable(unsigned long addr, int numpages, bool enc) { struct cpa_data cpa; int ret; - /* Nothing to do if memory encryption is not active */ - if (!mem_encrypt_active()) - return 0; - /* Should not be working on unaligned addresses */ if (WARN_ONCE(addr & ~PAGE_MASK, "misaligned address: %#lx\n", addr)) addr &= PAGE_MASK; @@ -2023,6 +2021,17 @@ static int __set_memory_enc_dec(unsigned long addr, int numpages, bool enc) return ret; } +static int __set_memory_enc_dec(unsigned long addr, int numpages, bool enc) +{ + if (hv_is_isolation_supported()) + return hv_set_mem_host_visibility(addr, numpages, !enc); + + if (mem_encrypt_active()) + return __set_memory_enc_pgtable(addr, numpages, enc); + + return 0; +} + int set_memory_encrypted(unsigned long addr, int numpages) { return __set_memory_enc_dec(addr, numpages, true); diff --git a/include/asm-generic/hyperv-tlfs.h b/include/asm-generic/hyperv-tlfs.h index 56348a541c50..8ed6733d5146 100644 --- a/include/asm-generic/hyperv-tlfs.h +++ b/include/asm-generic/hyperv-tlfs.h @@ -158,6 +158,7 @@ struct ms_hyperv_tsc_page { #define HVCALL_RETARGET_INTERRUPT 0x007e #define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_SPACE 0x00af #define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_LIST 0x00b0 +#define HVCALL_MODIFY_SPARSE_GPA_PAGE_HOST_VISIBILITY 0x00db /* Extended hypercalls */ #define HV_EXT_CALL_QUERY_CAPABILITIES 0x8001 diff --git a/include/asm-generic/mshyperv.h b/include/asm-generic/mshyperv.h index aa26d24a5ca9..079988ed45b9 100644 --- a/include/asm-generic/mshyperv.h +++ b/include/asm-generic/mshyperv.h @@ -255,6 +255,7 @@ bool hv_query_ext_cap(u64 cap_query); static inline bool hv_is_hyperv_initialized(void) { return false; } static inline bool hv_is_hibernation_supported(void) { return false; } static inline void hyperv_cleanup(void) {} +static inline hv_is_isolation_supported(void); #endif /* CONFIG_HYPERV */ #endif -- 2.25.1