From patchwork Sat Feb 11 01:37:54 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oliver Upton X-Patchwork-Id: 13136684 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 33686C05027 for ; Sat, 11 Feb 2023 01:39:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=1CksOady7NFcm+O3fbpFnrt+lQ+dk48BE21LLECWh5Y=; b=toyWkyPTCQgNS4 eIuQz9zZ+XN5eLYWH0E6tUVr3eW7qlyzyqFUKHuw0QOkWhrQ3nrBSEgdQ/DfugoreW/fYv0jvlcOp vSpB+wPYQ/QxRcPuXOUyxu2lcjiA9wfsXF+/fZWC2IEZigPYpK3t5pWuEI7YMyxxE0QV5g624SaDC WVk4+GwM23lBYVbUyAKNDKUbuTSaoXBgjL1wj+AqVulioJ6r0ANQgJh37QKVuyy4zAkBXlecC4AYm J1Zv7DobUvI281DHr6so1w6CQM/idbhFp6T6PJhrRi6UxYJpNbDKQFiQjDM8DZoiJ6SC8Nncfpg5x OT2FcSeSQyiLnZwHy/qg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1pQeqO-008Eyu-MC; Sat, 11 Feb 2023 01:38:24 +0000 Received: from out-190.mta1.migadu.com ([95.215.58.190]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1pQeqF-008EwT-43 for linux-arm-kernel@lists.infradead.org; Sat, 11 Feb 2023 01:38:16 +0000 X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1676079492; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=SnleMSFb+rskKwYj4g6FPeijRBKlwpY8LmQKrkG/ANo=; b=nztVWU9+Q7ym6nSUBYzgYeAyrMBfd/c406v3xQtei5pQdZ5jHcvInPraLAwgYvWjDqcp0r 3jpX3ODaav/lhtF4UZ9wggAIPTlux0040sD5Ln0AzT+BBNJra8aGXU4jjPi7esbr1TqsJ3 +ODX5l8KYfXXQWPJgjE0MVW7NR/xbI8= From: Oliver Upton To: Marc Zyngier Cc: James Morse , Suzuki K Poulose , kvmarm@lists.linux.dev, Akihiko Odaki , Zenghui Yu , Raghavendra Rao Ananta , linux-arm-kernel@lists.infradead.org, Salil Mehta , Oliver Upton Subject: [RFC PATCH v2 1/6] KVM: arm64: Add a helper to check if a VM has ran once Date: Sat, 11 Feb 2023 01:37:54 +0000 Message-Id: <20230211013759.3556016-2-oliver.upton@linux.dev> In-Reply-To: <20230211013759.3556016-1-oliver.upton@linux.dev> References: <20230211013759.3556016-1-oliver.upton@linux.dev> MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20230210_173815_330055_06E92CB8 X-CRM114-Status: GOOD ( 12.03 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org The test_bit(...) pattern is quite a lot of keystrokes. Replace existing callsites with a helper. No functional change intended. Signed-off-by: Oliver Upton --- arch/arm64/include/asm/kvm_host.h | 3 +++ arch/arm64/kvm/pmu-emul.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 35a159d131b5..012e94bc9e4a 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -1019,6 +1019,9 @@ bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu); (system_supports_32bit_el0() && \ !static_branch_unlikely(&arm64_mismatched_32bit_el0)) +#define kvm_vm_has_ran_once(kvm) \ + (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &(kvm)->arch.flags)) + int kvm_trng_call(struct kvm_vcpu *vcpu); #ifdef CONFIG_KVM extern phys_addr_t hyp_mem_base; diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c index 24908400e190..a0fc569fdbca 100644 --- a/arch/arm64/kvm/pmu-emul.c +++ b/arch/arm64/kvm/pmu-emul.c @@ -880,7 +880,7 @@ static int kvm_arm_pmu_v3_set_pmu(struct kvm_vcpu *vcpu, int pmu_id) list_for_each_entry(entry, &arm_pmus, entry) { arm_pmu = entry->arm_pmu; if (arm_pmu->pmu.type == pmu_id) { - if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags) || + if (kvm_vm_has_ran_once(kvm) || (kvm->arch.pmu_filter && kvm->arch.arm_pmu != arm_pmu)) { ret = -EBUSY; break; @@ -963,7 +963,7 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) mutex_lock(&kvm->lock); - if (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags)) { + if (kvm_vm_has_ran_once(kvm)) { mutex_unlock(&kvm->lock); return -EBUSY; } From patchwork Sat Feb 11 01:37:55 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oliver Upton X-Patchwork-Id: 13136686 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 3CDEBC636D4 for ; Sat, 11 Feb 2023 01:39:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=h9ErkutylJQtClr3FNobgfqEQ1PhXxtyeZ29Ql60VzQ=; b=klmhWqqPT6ezbW MiU2SiVf0U/jv06BRPw0vcojmzI0b0vO0KkjUUtbF7k5uzFb77ysFH3vR4AsfA6I/bb6v0tWjLQl2 Hne9xiSYUbtrZoypoQ5rDNXx2Kp4eF1GcE4wpMKkWTkrakiUMabxP91f+n4LoI6eB2I6texlljWo4 N+GFZitiNgX3Ym6tRGqe/KdC4nBIf9mcgjxJKDU9SmaHpKvZRfcQ6oN5r//DStvHukWGItjXW9+EZ XLXwb2qU6HhVtlvIerA/jgMtOcpxAWdpjBrQIJ2AVCXXswI1MZhl71SSO6QGUGzQ+bBpi3OaM5Sts gZDdmEwt7oqOfpaBzVgA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1pQeqW-008F08-8w; Sat, 11 Feb 2023 01:38:32 +0000 Received: from out-44.mta1.migadu.com ([95.215.58.44]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1pQeqH-008Ewu-9x for linux-arm-kernel@lists.infradead.org; Sat, 11 Feb 2023 01:38:18 +0000 X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1676079494; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=uYKcrnYt5tqTigyH3lLK4W3VAbMxWX7++cvj3eUL8OA=; b=lOAAqD0vQEau104DxzBl5UeQ5ic6uEJOS06NzyWZhUFdOZriFHXvb22Avzooyb0wMOImdw jK7Ggub1wCbPfbnf8wy8rMiqwS75DFADbWLPPD29XXWByPC2g/9F5QBNcMoSKUgNg8Vr4y 3YXNoB8WemcB7I6oGfgHWsTFrQCbu4k= From: Oliver Upton To: Marc Zyngier Cc: James Morse , Suzuki K Poulose , kvmarm@lists.linux.dev, Akihiko Odaki , Zenghui Yu , Raghavendra Rao Ananta , linux-arm-kernel@lists.infradead.org, Salil Mehta , Oliver Upton Subject: [RFC PATCH v2 2/6] KVM: arm64: Add vm fd device attribute accessors Date: Sat, 11 Feb 2023 01:37:55 +0000 Message-Id: <20230211013759.3556016-3-oliver.upton@linux.dev> In-Reply-To: <20230211013759.3556016-1-oliver.upton@linux.dev> References: <20230211013759.3556016-1-oliver.upton@linux.dev> MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20230210_173817_523424_1EAEF501 X-CRM114-Status: UNSURE ( 9.64 ) X-CRM114-Notice: Please train this message. X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org A subsequent change will allow userspace to convey a filter for hypercalls through a vm device attribute. Add the requisite boilerplate for vm attribute accessors. Signed-off-by: Oliver Upton --- arch/arm64/kvm/arm.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 9c5573bc4614..09efa893e03a 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -1449,11 +1449,28 @@ static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm, } } +static int kvm_vm_has_attr(struct kvm *kvm, struct kvm_device_attr *attr) +{ + switch (attr->group) { + default: + return -ENXIO; + } +} + +static int kvm_vm_set_attr(struct kvm *kvm, struct kvm_device_attr *attr) +{ + switch (attr->group) { + default: + return -ENXIO; + } +} + long kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { struct kvm *kvm = filp->private_data; void __user *argp = (void __user *)arg; + struct kvm_device_attr attr; switch (ioctl) { case KVM_CREATE_IRQCHIP: { @@ -1489,6 +1506,18 @@ long kvm_arch_vm_ioctl(struct file *filp, return -EFAULT; return kvm_vm_ioctl_mte_copy_tags(kvm, ©_tags); } + case KVM_HAS_DEVICE_ATTR: { + if (copy_from_user(&attr, argp, sizeof(attr))) + return -EFAULT; + + return kvm_vm_has_attr(kvm, &attr); + } + case KVM_SET_DEVICE_ATTR: { + if (copy_from_user(&attr, argp, sizeof(attr))) + return -EFAULT; + + return kvm_vm_set_attr(kvm, &attr); + } default: return -EINVAL; } From patchwork Sat Feb 11 01:37:56 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oliver Upton X-Patchwork-Id: 13136687 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 37575C636D4 for ; Sat, 11 Feb 2023 01:40:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=NWsrByxyNAEk3Tk34Bc5QFShP5+uEGaWBY1Vdc2sDKY=; b=FQbvO/UZvsS8fk aoQOT0vnCK7m6Z/QzH4IkshddyBoiiYGErcPtHok2seydSexLWeG1/oMFfGbBBtKmEqnsFh5VD8bK p0TX5cSItLjXUKtZdv35chYBR1wPeWErGiO5/YAULZYlNuz2euOHISbe7nEoUskz48XBADODq9+2d mF2+gW0cOnrYhmTqXlFGzt+6vk7N4XkbL62EuQY6CLP1Rg30Vj1oCLQGHbYGxIpRYn+Qw/+XvAH4V YVHNWhz+rALRKRm+iQ8CsJdqqFEVDg+/SALvX9V2/UAJItHBM9WCSxQ5J2cnp9+9P84itxyHN0Ed4 YxSWYtdIpB5ZQaYLDBcg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1pQeqe-008F1K-Bo; Sat, 11 Feb 2023 01:38:40 +0000 Received: from out-39.mta1.migadu.com ([2001:41d0:203:375::27]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1pQeqJ-008ExP-Jn for linux-arm-kernel@lists.infradead.org; Sat, 11 Feb 2023 01:38:21 +0000 X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1676079497; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=gFpL4/I0DKoGOSnQFmuQKeZGgj9YF7hQjBRrKkFy/9E=; b=Za7rPboJuAbzjZWqisIAVCCAQcTNcQbe6okC/6DzyKnfV/WJ/vNoVCEcWIIz+aOnjowTrF Vhv+MoJnu2lCt2vN5Wl41fV+28eD3x1DGbT4ASOC9fOzKxfzn/x5wf3AATJwWGi/nOw2wR 5lPTvubDMDxX8sK7WJUC1eCTpCxu3Jw= From: Oliver Upton To: Marc Zyngier Cc: James Morse , Suzuki K Poulose , kvmarm@lists.linux.dev, Akihiko Odaki , Zenghui Yu , Raghavendra Rao Ananta , linux-arm-kernel@lists.infradead.org, Salil Mehta , Oliver Upton Subject: [RFC PATCH v2 3/6] KVM: arm64: Refactor hvc filtering to support different actions Date: Sat, 11 Feb 2023 01:37:56 +0000 Message-Id: <20230211013759.3556016-4-oliver.upton@linux.dev> In-Reply-To: <20230211013759.3556016-1-oliver.upton@linux.dev> References: <20230211013759.3556016-1-oliver.upton@linux.dev> MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20230210_173819_817611_4E5BE6A2 X-CRM114-Status: GOOD ( 10.79 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org KVM presently allows userspace to filter guest hypercalls with bitmaps expressed via pseudo-firmware registers. These bitmaps have a narrow scope and, of course, can only allow/deny a particular call. A subsequent change to KVM will introduce a generalized UAPI for filtering hypercalls, allowing functions to be forwarded to userspace. Refactor the existing hypercall filtering logic to make room for more than two actions. While at it, generalize the function names around SMCCC as it is the basis for the upcoming UAPI. No functional change intended. Signed-off-by: Oliver Upton --- arch/arm64/include/uapi/asm/kvm.h | 9 +++++++++ arch/arm64/kvm/hypercalls.c | 19 +++++++++++++++---- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index a7a857f1784d..e298574a45ea 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -468,6 +468,15 @@ enum { /* run->fail_entry.hardware_entry_failure_reason codes. */ #define KVM_EXIT_FAIL_ENTRY_CPU_UNSUPPORTED (1ULL << 0) +enum kvm_smccc_filter_action { + KVM_SMCCC_FILTER_ALLOW = 0, + KVM_SMCCC_FILTER_DENY, + +#ifdef __KERNEL__ + NR_SMCCC_FILTER_ACTIONS +#endif +}; + #endif #endif /* __ARM_KVM_H__ */ diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c index c9f401fa01a9..980546b295b3 100644 --- a/arch/arm64/kvm/hypercalls.c +++ b/arch/arm64/kvm/hypercalls.c @@ -65,7 +65,7 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val) val[3] = lower_32_bits(cycles); } -static bool kvm_hvc_call_default_allowed(u32 func_id) +static bool kvm_smccc_default_call(u32 func_id) { switch (func_id) { /* @@ -93,7 +93,7 @@ static bool kvm_hvc_call_default_allowed(u32 func_id) } } -static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id) +static bool kvm_smccc_test_fw_bmap(struct kvm_vcpu *vcpu, u32 func_id) { struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat; @@ -117,19 +117,30 @@ static bool kvm_hvc_call_allowed(struct kvm_vcpu *vcpu, u32 func_id) return test_bit(KVM_REG_ARM_VENDOR_HYP_BIT_PTP, &smccc_feat->vendor_hyp_bmap); default: - return kvm_hvc_call_default_allowed(func_id); + return false; } } +static u8 kvm_hvc_get_action(struct kvm_vcpu *vcpu, u32 func_id) +{ + if (kvm_smccc_default_call(func_id) || + kvm_smccc_test_fw_bmap(vcpu, func_id)) + return KVM_SMCCC_FILTER_ALLOW; + + return KVM_SMCCC_FILTER_DENY; +} + int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) { struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat; u32 func_id = smccc_get_function(vcpu); u64 val[4] = {SMCCC_RET_NOT_SUPPORTED}; u32 feature; + u8 action; gpa_t gpa; - if (!kvm_hvc_call_allowed(vcpu, func_id)) + action = kvm_hvc_get_action(vcpu, func_id); + if (action == KVM_SMCCC_FILTER_DENY) goto out; switch (func_id) { From patchwork Sat Feb 11 01:37:57 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oliver Upton X-Patchwork-Id: 13136688 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 873B5C636D4 for ; Sat, 11 Feb 2023 01:40:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=UgeG7oR+ixLC2lOFlsWHVUfZPbmfw4HKPxtMHl7LzoA=; b=wmOV9EVY2vFvR0 OF/8ktToUl4k0pHJp3xgX2oaPOPE0hCvdlNhtpA0VzU3wx+nK30ddZgxdqKrtxa0Xb9vqutrcOgyV zKtje5UayrPXdxYo0zAI1o8vAReVbwRo/OB4dZoga0xlL4w/bkOXTaa/GSlWNckyYX3SZXWESWtsa n8uszU+ScsLVmXqMfinn4JUaCLOps/kYYOJloJuuKxKxv9QQhY+FNFPeWFnZupxE5Y4xdlIP9z95H Z46CdpOibZ4ZJwLXPHtJ1l4WSQOeGUGlHS2+GjIWASY9jy6aXKQHLhgIFx0ds3oHZteNZJoqiwQp6 rr077CVsbhqz+MDO0eXg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1pQeqm-008F3E-3s; Sat, 11 Feb 2023 01:38:48 +0000 Received: from out-197.mta1.migadu.com ([2001:41d0:203:375::c5]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1pQeqL-008Exh-OV for linux-arm-kernel@lists.infradead.org; Sat, 11 Feb 2023 01:38:23 +0000 X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1676079499; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=HTIjnmJEX0Ff4LF+cABR46hUjNT8pZt9yyzf6CFseOs=; b=KPzZE4RX0oxZ6YwfAsTX/G0myxSaZ/T2wRvxTx4kia842xF/FC9HmrH6j2YqapRkKV9adc miPxQnWUC0yIhnzT/QGCocnwz3HrNBpDZinSp2AaMt8WKR9tkfgTxSzgIqK+9YMdLsnkE6 PM4bhRUIkGbnsWJHRgaQVvptASf0rqI= From: Oliver Upton To: Marc Zyngier Cc: James Morse , Suzuki K Poulose , kvmarm@lists.linux.dev, Akihiko Odaki , Zenghui Yu , Raghavendra Rao Ananta , linux-arm-kernel@lists.infradead.org, Salil Mehta , Oliver Upton Subject: [RFC PATCH v2 4/6] KVM: arm64: Use a maple tree to represent the SMCCC filter Date: Sat, 11 Feb 2023 01:37:57 +0000 Message-Id: <20230211013759.3556016-5-oliver.upton@linux.dev> In-Reply-To: <20230211013759.3556016-1-oliver.upton@linux.dev> References: <20230211013759.3556016-1-oliver.upton@linux.dev> MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20230210_173822_103602_C3B87177 X-CRM114-Status: GOOD ( 17.29 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Maple tree is an efficient B-tree implementation that is intended for storing non-overlapping intervals. Such a data structure is a good fit for the SMCCC filter as it is desirable to sparsely allocate the 32 bit function ID space. To that end, add a maple tree to kvm_arch and correctly init/teardown along with the VM. Wire in a test against the hypercall filter for HVCs which does nothing until the controls are exposed to userspace. Signed-off-by: Oliver Upton --- arch/arm64/include/asm/kvm_host.h | 5 +++- arch/arm64/kvm/arm.c | 2 ++ arch/arm64/kvm/hypercalls.c | 38 +++++++++++++++++++++++++++++++ include/kvm/arm_hypercalls.h | 1 + 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 012e94bc9e4a..a20875dde1f5 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -213,7 +214,8 @@ struct kvm_arch { #define KVM_ARCH_FLAG_EL1_32BIT 4 /* PSCI SYSTEM_SUSPEND enabled for the guest */ #define KVM_ARCH_FLAG_SYSTEM_SUSPEND_ENABLED 5 - + /* SMCCC filter initialized for the VM */ +#define KVM_ARCH_FLAG_SMCCC_FILTER_CONFIGURED 6 unsigned long flags; /* @@ -234,6 +236,7 @@ struct kvm_arch { /* Hypercall features firmware registers' descriptor */ struct kvm_smccc_features smccc_feat; + struct maple_tree smccc_filter; /* * For an untrusted host VM, 'pkvm.handle' is used to lookup diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 09efa893e03a..e04690caad77 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -202,6 +202,8 @@ void kvm_arch_destroy_vm(struct kvm *kvm) kvm_destroy_vcpus(kvm); kvm_unshare_hyp(kvm, kvm + 1); + + kvm_arm_teardown_hypercalls(kvm); } int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c index 980546b295b3..45b8371816fd 100644 --- a/arch/arm64/kvm/hypercalls.c +++ b/arch/arm64/kvm/hypercalls.c @@ -121,8 +121,39 @@ static bool kvm_smccc_test_fw_bmap(struct kvm_vcpu *vcpu, u32 func_id) } } +static bool kvm_smccc_filter_configured(struct kvm *kvm) +{ + return test_bit(KVM_ARCH_FLAG_SMCCC_FILTER_CONFIGURED, &kvm->arch.flags); +} + +static u8 kvm_smccc_filter_get_action(struct kvm *kvm, u32 func_id) +{ + unsigned long index = func_id; + void *val; + + if (!kvm_smccc_filter_configured(kvm)) + return KVM_SMCCC_FILTER_ALLOW; + + /* + * But where's the error handling, you say? + * + * mt_find() returns NULL if no entry was found, which just so happens + * to match KVM_SMCCC_FILTER_ALLOW. + */ + val = mt_find(&kvm->arch.smccc_filter, &index, index); + return xa_to_value(val); +} + static u8 kvm_hvc_get_action(struct kvm_vcpu *vcpu, u32 func_id) { + /* + * Intervening actions in the SMCCC filter take precedence over the + * pseudo-firmware register bitmaps. + */ + u8 action = kvm_smccc_filter_get_action(vcpu->kvm, func_id); + if (action != KVM_SMCCC_FILTER_ALLOW) + return action; + if (kvm_smccc_default_call(func_id) || kvm_smccc_test_fw_bmap(vcpu, func_id)) return KVM_SMCCC_FILTER_ALLOW; @@ -256,6 +287,13 @@ void kvm_arm_init_hypercalls(struct kvm *kvm) smccc_feat->std_bmap = KVM_ARM_SMCCC_STD_FEATURES; smccc_feat->std_hyp_bmap = KVM_ARM_SMCCC_STD_HYP_FEATURES; smccc_feat->vendor_hyp_bmap = KVM_ARM_SMCCC_VENDOR_HYP_FEATURES; + + mt_init(&kvm->arch.smccc_filter); +} + +void kvm_arm_teardown_hypercalls(struct kvm *kvm) +{ + mtree_destroy(&kvm->arch.smccc_filter); } int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu) diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h index 1188f116cf4e..ae1ada68cdc2 100644 --- a/include/kvm/arm_hypercalls.h +++ b/include/kvm/arm_hypercalls.h @@ -43,6 +43,7 @@ static inline void smccc_set_retval(struct kvm_vcpu *vcpu, struct kvm_one_reg; void kvm_arm_init_hypercalls(struct kvm *kvm); +void kvm_arm_teardown_hypercalls(struct kvm *kvm); int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu); int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices); int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg); From patchwork Sat Feb 11 01:37:58 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oliver Upton X-Patchwork-Id: 13136689 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 74203C05027 for ; Sat, 11 Feb 2023 01:40:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=GKk2t3dM3jieW0TVnGBQ3Sul1agNQpUVi7VZakFiyz0=; b=dc52SF1/eaEX6k wunw9ADrZmQc5Yite5s1zYC5+RQ/G/fLQ3G6HWa9FI10K2c5MDX1rj1kJOP6WUQ5ko1bOj0KXi2Gc 8BHjXUbThbmmvxycyXMrxbOxm1oaE4yQPYegw+p+kadtvST6WfFJkhMD9LZrT+g6DwKzbnu1TDT1d 3TMVhVPjy5+1hygAHfy3yXp5aTtTuQlqcG0ZacZhU/6HpgNxLHB/IWX2phs8I6qXSPJYTzVaH2FvY PERiTx3J3t3dsifVHsQ+lqwX56/bbKlFIfeiTOxPLqerkoxJ3H7qm7S6Qubs+Ger/U9+NBhiP6Ccx CBj4ynWqWle3KYqf1Rew==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1pQequ-008F5Z-0W; Sat, 11 Feb 2023 01:38:56 +0000 Received: from out-85.mta1.migadu.com ([2001:41d0:203:375::55]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1pQeqN-008Ey8-UA for linux-arm-kernel@lists.infradead.org; Sat, 11 Feb 2023 01:38:25 +0000 X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1676079501; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=XMHylM3w6c4OLWhS6cH5kkFUnRyYPx005aFa1ArQdjA=; b=WWkeWl7sjI1Gpg8qoCkjEUHiGV2dAqXuKmNZm7O2cbD8OEAlTS+xPvSCJO73OHBMz8sbah cH6d/k09iT21iO6Lqcne7ZP/AnV5Lw5W/67EajnpaGalghi5njhXajNU9CO2iuI8WOj02I QWMIxRS6rgcnZpbTnr8K8WLhCm0OhwU= From: Oliver Upton To: Marc Zyngier Cc: James Morse , Suzuki K Poulose , kvmarm@lists.linux.dev, Akihiko Odaki , Zenghui Yu , Raghavendra Rao Ananta , linux-arm-kernel@lists.infradead.org, Salil Mehta , Oliver Upton Subject: [RFC PATCH v2 5/6] KVM: arm64: Add support for KVM_EXIT_HYPERCALL Date: Sat, 11 Feb 2023 01:37:58 +0000 Message-Id: <20230211013759.3556016-6-oliver.upton@linux.dev> In-Reply-To: <20230211013759.3556016-1-oliver.upton@linux.dev> References: <20230211013759.3556016-1-oliver.upton@linux.dev> MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20230210_173824_144474_25B19195 X-CRM114-Status: GOOD ( 26.58 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org In anticipation of user hypercall filters, add the necessary plumbing to get SMCCC calls out to userspace. Even though the exit structure has space for KVM to pass register arguments, let's just avoid it altogether and let userspace poke at the registers via KVM_GET_ONE_REG. This deliberately stretches the definition of a 'hypercall' to cover SMCs from EL1 in addition to the HVCs we know and love. KVM doesn't support EL1 calls into secure services, but now we can paint that as a userspace problem and be done with it. Finally, we need a flag to let userspace know what conduit instruction was used (i.e. SMC vs. HVC). Redefine the remaining padding in kvm_run::hypercall to accomplish this. Let's all take a moment to admire the flowers and see how 'longmode' tied up a full u32 in the UAPI. Weep. Signed-off-by: Oliver Upton --- Documentation/virt/kvm/api.rst | 24 +++++++++++++++++++++--- arch/arm64/include/uapi/asm/kvm.h | 4 ++++ arch/arm64/kvm/handle_exit.c | 12 +++++++++--- arch/arm64/kvm/hypercalls.c | 31 +++++++++++++++++++++++++++++++ include/kvm/arm_hypercalls.h | 1 + include/uapi/linux/kvm.h | 2 +- 6 files changed, 67 insertions(+), 7 deletions(-) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index deb494f759ed..c82da1a84590 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -6119,14 +6119,32 @@ to the byte array. __u64 args[6]; __u64 ret; __u32 longmode; - __u32 pad; + __u32 flags; } hypercall; -Unused. This was once used for 'hypercall to userspace'. To implement -such functionality, use KVM_EXIT_IO (x86) or KVM_EXIT_MMIO (all except s390). + +It is strongly recommended that userspace use ``KVM_EXIT_IO`` (x86) or +``KVM_EXIT_MMIO`` (all except s390) to implement functionality that +requires a guest to interact with host userpace. .. note:: KVM_EXIT_IO is significantly faster than KVM_EXIT_MMIO. +For arm64: +---------- + +SMCCC exits can be enabled depending on the configuration of the SMCCC +filter. See the Documentation/virt/kvm/devices/vm.rst +``KVM_ARM_SMCCC_FILTER`` for more details. + +``nr`` contains the function ID of the guest's SMCCC call. Userspace is +expected to use the ``KVM_GET_ONE_REG`` ioctl to retrieve the call +parameters from the vCPU's GPRs. + +Definition of ``flags``: + - ``KVM_HYPERCALL_EXIT_SMC``: Indicates that the guest used the SMC + conduit to initiate the SMCCC call. If this bit is 0 then the guest + used the HVC conduit for the SMCCC call. + :: /* KVM_EXIT_TPR_ACCESS */ diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index e298574a45ea..5c98e7c39ba1 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -471,12 +471,16 @@ enum { enum kvm_smccc_filter_action { KVM_SMCCC_FILTER_ALLOW = 0, KVM_SMCCC_FILTER_DENY, + KVM_SMCCC_FILTER_FWD_TO_USER, #ifdef __KERNEL__ NR_SMCCC_FILTER_ACTIONS #endif }; +/* arm64-specific KVM_EXIT_HYPERCALL flags */ +#define KVM_HYPERCALL_EXIT_SMC (1U << 0) + #endif #endif /* __ARM_KVM_H__ */ diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index e778eefcf214..d15ff6c795e1 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -52,6 +52,8 @@ static int handle_hvc(struct kvm_vcpu *vcpu) static int handle_smc(struct kvm_vcpu *vcpu) { + int ret = kvm_smc_call_handler(vcpu); + /* * "If an SMC instruction executed at Non-secure EL1 is * trapped to EL2 because HCR_EL2.TSC is 1, the exception is a @@ -60,9 +62,13 @@ static int handle_smc(struct kvm_vcpu *vcpu) * We need to advance the PC after the trap, as it would * otherwise return to the same address... */ - vcpu_set_reg(vcpu, 0, ~0UL); - kvm_incr_pc(vcpu); - return 1; + if (ret < 0) { + vcpu_set_reg(vcpu, 0, ~0UL); + kvm_incr_pc(vcpu); + return 1; + } + + return ret; } /* diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c index 45b8371816fd..f095c048730a 100644 --- a/arch/arm64/kvm/hypercalls.c +++ b/arch/arm64/kvm/hypercalls.c @@ -161,6 +161,17 @@ static u8 kvm_hvc_get_action(struct kvm_vcpu *vcpu, u32 func_id) return KVM_SMCCC_FILTER_DENY; } +static void kvm_prepare_hypercall_exit(struct kvm_vcpu *vcpu, u32 func_id, bool smc) +{ + struct kvm_run *run = vcpu->run; + + run->exit_reason = KVM_EXIT_HYPERCALL; + run->hypercall.nr = func_id; + + if (smc) + run->hypercall.flags = KVM_HYPERCALL_EXIT_SMC; +} + int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) { struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat; @@ -173,6 +184,10 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) action = kvm_hvc_get_action(vcpu, func_id); if (action == KVM_SMCCC_FILTER_DENY) goto out; + if (action == KVM_SMCCC_FILTER_FWD_TO_USER) { + kvm_prepare_hypercall_exit(vcpu, func_id, false); + return 0; + } switch (func_id) { case ARM_SMCCC_VERSION_FUNC_ID: @@ -270,6 +285,22 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) return 1; } +int kvm_smc_call_handler(struct kvm_vcpu *vcpu) +{ + u32 func_id = smccc_get_function(vcpu); + u8 action = kvm_smccc_filter_get_action(vcpu->kvm, func_id); + + /* + * KVM doesn't support SMCs from EL1, so reject the call if userspace + * doesn't want it. + */ + if (action != KVM_SMCCC_FILTER_FWD_TO_USER) + return -ENOSYS; + + kvm_prepare_hypercall_exit(vcpu, func_id, true); + return 0; +} + static const u64 kvm_arm_fw_reg_ids[] = { KVM_REG_ARM_PSCI_VERSION, KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1, diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h index ae1ada68cdc2..4707aa206c4e 100644 --- a/include/kvm/arm_hypercalls.h +++ b/include/kvm/arm_hypercalls.h @@ -7,6 +7,7 @@ #include int kvm_hvc_call_handler(struct kvm_vcpu *vcpu); +int kvm_smc_call_handler(struct kvm_vcpu *vcpu); static inline u32 smccc_get_function(struct kvm_vcpu *vcpu) { diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 55155e262646..0ae7cf8ca2db 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -342,7 +342,7 @@ struct kvm_run { __u64 args[6]; __u64 ret; __u32 longmode; - __u32 pad; + __u32 flags; } hypercall; /* KVM_EXIT_TPR_ACCESS */ struct { From patchwork Sat Feb 11 01:37:59 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oliver Upton X-Patchwork-Id: 13136690 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 0CCB4C636D4 for ; Sat, 11 Feb 2023 01:40:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=eklfYnDv4AtPjmmnYyj4hTaWwrg+Cf8EB5fWYU/r93I=; b=k5LIQyF+I1BPMN xFs7O5EKE834vfrTSlD42XBavYLA6XWawlDOXexn6w6ypGBLlmm38zE8kiIQGgoFxPBz4Qrr8A1qf TmQ/QmbJuQDYf1l12WUWzdY1f8WpMVmU8b0YfMx3fnNsvMlbEzJlgNOkp8J9TgjHWIHlEyuM5uBKk RlViwiY4SzuFzUbs+wnqpQ4wvo08tYZI6PNMBY3ebCqLfe/Bpr+DFCTWQqudIfJVZ3D9i7OuWqGzk CKeNi3zrYBjx9MtL2KC+oQB0r/5rZfLYsJup0ip5NEHftE71z7izgs9EEVUm3bHPp5KBhd2yW8Ozb PUGKuFEhUung4ksDqpBA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1pQer3-008F9W-IJ; Sat, 11 Feb 2023 01:39:05 +0000 Received: from out-100.mta1.migadu.com ([95.215.58.100]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1pQeqP-008Eyc-Se for linux-arm-kernel@lists.infradead.org; Sat, 11 Feb 2023 01:38:27 +0000 X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1676079503; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=syiYntVIx4yEzUsRcb7fd+ST1Ff/5bk0NJqoAiJ5rq8=; b=pEMPYXZ/DCfYEl4kUIxJK6Haro9Pd+lRW9te4an9NTR6aHWQg+XP2afY1XNqARzoo19EUY fj4PHMXWz+AkNOvAJ4ULBzEDFdXRnYJT9xE3MUp9HsxQsD9ymv/mn99l5N4WahQ6Dkp7r+ n8RPiuEO6IzeGG8r3ik5FR8RvhXqgk8= From: Oliver Upton To: Marc Zyngier Cc: James Morse , Suzuki K Poulose , kvmarm@lists.linux.dev, Akihiko Odaki , Zenghui Yu , Raghavendra Rao Ananta , linux-arm-kernel@lists.infradead.org, Salil Mehta , Oliver Upton Subject: [RFC PATCH v2 6/6] KVM: arm64: Indroduce support for userspace SMCCC filtering Date: Sat, 11 Feb 2023 01:37:59 +0000 Message-Id: <20230211013759.3556016-7-oliver.upton@linux.dev> In-Reply-To: <20230211013759.3556016-1-oliver.upton@linux.dev> References: <20230211013759.3556016-1-oliver.upton@linux.dev> MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20230210_173826_099695_4D6589FB X-CRM114-Status: GOOD ( 22.33 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org As the SMCCC (and related specifications) march towards an 'everything and the kitchen sink' interface for interacting with a system it becomes less likely that KVM will support every related feature. We could do better by letting userspace have a crack at it instead. Allow userspace to define an 'SMCCC filter' that applies to both HVCs and SMCs initiated by the guest. Supporting both conduits with this interface is important for a couple of reasons. Guest SMC usage is table stakes for a nested guest, as HVCs are always taken to the virtual EL2. Additionally, guests may want to interact with a service on the secure side which can now be proxied by userspace. Signed-off-by: Oliver Upton --- Documentation/virt/kvm/devices/vm.rst | 67 ++++++++++++++++++++ arch/arm64/include/uapi/asm/kvm.h | 18 ++++++ arch/arm64/kvm/arm.c | 4 ++ arch/arm64/kvm/hypercalls.c | 88 +++++++++++++++++++++++++++ include/kvm/arm_hypercalls.h | 3 + 5 files changed, 180 insertions(+) diff --git a/Documentation/virt/kvm/devices/vm.rst b/Documentation/virt/kvm/devices/vm.rst index 60acc39e0e93..564ecc7cff0d 100644 --- a/Documentation/virt/kvm/devices/vm.rst +++ b/Documentation/virt/kvm/devices/vm.rst @@ -317,3 +317,70 @@ Allows userspace to query the status of migration mode. if it is enabled :Returns: -EFAULT if the given address is not accessible from kernel space; 0 in case of success. + +6. GROUP: KVM_ARM_VM_SMCCC_CTRL +=============================== + +:Architectures: arm64 + +6.1. ATTRIBUTE: KVM_ARM_VM_SMCCC_FILTER (w/o) +--------------------------------------------- + +:Parameters: Pointer to a ``struct kvm_smccc_filter`` + +:Returns: + + ======= =========================================== + -EEXIST SMCCC filter already configured for the VM + -EBUSY A vCPU in the VM has already run + -EINVAL Invalid filter configuration + -ENOMEM Failed to allocate memory for the in-kernel + representation of the SMCCC filter + ======= =========================================== + +Request the installation of an SMCCC call filter described as follows:: + + enum kvm_smccc_filter_action { + KVM_SMCCC_FILTER_ALLOW = 0, + KVM_SMCCC_FILTER_DENY, + KVM_SMCCC_FILTER_FWD_TO_USER, + }; + + struct kvm_smccc_filter_range { + __u32 base; + __u32 nr_functions; + __u8 action; + __u8 pad[7]; + }; + + struct kvm_smccc_filter { + __u32 nr_entries; + __u32 pad; + + struct kvm_smccc_filter_range entries[]; + }; + +The filter is defined as a set of non-overlapping ranges. Each +range defines an action to be applied to SMCCC calls within the range. +The default configuration of KVM is such that all implemented SMCCC +calls are allowed by default. Thus, the SMCCC filter can be defined +sparsely by userspace, only describing ranges that modify the default +behavior. + +The range expressed by ``struct kvm_smccc_filter_range`` is +[@base, @base + @nr_functions). + +The SMCCC filter applies to both SMC and HVC calls initiated by the +guest. + +Actions: + + - ``KVM_SMCCC_FILTER_ALLOW``: Allows the guest SMCCC call to be + handled in-kernel. It is strongly recommended that userspace *not* + explicitly describe the allowed SMCCC call ranges. + + - ``KVM_SMCCC_FILTER_DENY``: Rejects the guest SMCCC call in-kernel + and returns to the guest. + + - ``KVM_SMCCC_FILTER_FWD_TO_USER``: The guest SMCCC call is forwarded + to userspace with an exit reason of ``KVM_EXIT_HYPERCALL``. diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index 5c98e7c39ba1..5973031c959d 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -371,6 +371,10 @@ enum { #endif }; +/* Device Control API on vm fd */ +#define KVM_ARM_VM_SMCCC_CTRL 0 +#define KVM_ARM_VM_SMCCC_FILTER 0 + /* Device Control API: ARM VGIC */ #define KVM_DEV_ARM_VGIC_GRP_ADDR 0 #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1 @@ -478,6 +482,20 @@ enum kvm_smccc_filter_action { #endif }; +struct kvm_smccc_filter_range { + __u32 base; + __u32 nr_functions; + __u8 action; + __u8 pad[7]; +}; + +struct kvm_smccc_filter { + __u32 nr_entries; + __u32 pad; + + struct kvm_smccc_filter_range entries[]; +}; + /* arm64-specific KVM_EXIT_HYPERCALL flags */ #define KVM_HYPERCALL_EXIT_SMC (1U << 0) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index e04690caad77..3d64f025ccba 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -1454,6 +1454,8 @@ static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm, static int kvm_vm_has_attr(struct kvm *kvm, struct kvm_device_attr *attr) { switch (attr->group) { + case KVM_ARM_VM_SMCCC_CTRL: + return kvm_vm_smccc_has_attr(kvm, attr); default: return -ENXIO; } @@ -1462,6 +1464,8 @@ static int kvm_vm_has_attr(struct kvm *kvm, struct kvm_device_attr *attr) static int kvm_vm_set_attr(struct kvm *kvm, struct kvm_device_attr *attr) { switch (attr->group) { + case KVM_ARM_VM_SMCCC_CTRL: + return kvm_vm_smccc_set_attr(kvm, attr); default: return -ENXIO; } diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c index f095c048730a..1984df78a307 100644 --- a/arch/arm64/kvm/hypercalls.c +++ b/arch/arm64/kvm/hypercalls.c @@ -126,6 +126,72 @@ static bool kvm_smccc_filter_configured(struct kvm *kvm) return test_bit(KVM_ARCH_FLAG_SMCCC_FILTER_CONFIGURED, &kvm->arch.flags); } +static int kvm_smccc_filter_insert_range(struct kvm *kvm, + struct kvm_smccc_filter_range *range) +{ + struct maple_tree *mt = &kvm->arch.smccc_filter; + unsigned long start = range->base; + unsigned long end = start + range->nr_functions - 1; + int r; + + if (!range->nr_functions || range->action >= NR_SMCCC_FILTER_ACTIONS) + return -EINVAL; + + r = mtree_insert_range(mt, start, end, xa_mk_value(range->action), GFP_KERNEL_ACCOUNT); + if (r == -EEXIST) + return -EINVAL; + + return r; +} + +static int kvm_smccc_set_filter(struct kvm *kvm, struct kvm_smccc_filter __user *uaddr) +{ + struct kvm_smccc_filter_range *entries; + struct kvm_smccc_filter filter; + int i, r; + + if (copy_from_user(&filter, uaddr, sizeof(filter))) + return -EFAULT; + + entries = memdup_user(&uaddr->entries, sizeof(*entries) * filter.nr_entries); + if (IS_ERR(entries)) + return PTR_ERR(entries); + + mutex_lock(&kvm->lock); + + if (kvm_vm_has_ran_once(kvm)) { + r = -EBUSY; + goto out; + } + + if (kvm_smccc_filter_configured(kvm)) { + r = -EEXIST; + goto out; + } + + for (i = 0; i < filter.nr_entries; i++) { + struct kvm_smccc_filter_range *range = &entries[i]; + + r = kvm_smccc_filter_insert_range(kvm, range); + if (r) + goto out_reset_mt; + } + + set_bit(KVM_ARCH_FLAG_SMCCC_FILTER_CONFIGURED, &kvm->arch.flags); + + mutex_unlock(&kvm->lock); + kfree(entries); + return 0; + +out_reset_mt: + mtree_destroy(&kvm->arch.smccc_filter); + mt_init(&kvm->arch.smccc_filter); +out: + kfree(entries); + mutex_unlock(&kvm->lock); + return r; +} + static u8 kvm_smccc_filter_get_action(struct kvm *kvm, u32 func_id) { unsigned long index = func_id; @@ -559,3 +625,25 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) return -EINVAL; } + +int kvm_vm_smccc_has_attr(struct kvm *kvm, struct kvm_device_attr *attr) +{ + switch (attr->attr) { + case KVM_ARM_VM_SMCCC_FILTER: + return 0; + default: + return -ENXIO; + } +} + +int kvm_vm_smccc_set_attr(struct kvm *kvm, struct kvm_device_attr *attr) +{ + void __user *uaddr = (void __user *)attr->addr; + + switch (attr->attr) { + case KVM_ARM_VM_SMCCC_FILTER: + return kvm_smccc_set_filter(kvm, uaddr); + default: + return -ENXIO; + } +} diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h index 4707aa206c4e..d01cef2983ee 100644 --- a/include/kvm/arm_hypercalls.h +++ b/include/kvm/arm_hypercalls.h @@ -50,4 +50,7 @@ int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices); int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg); int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg); +int kvm_vm_smccc_has_attr(struct kvm *kvm, struct kvm_device_attr *attr); +int kvm_vm_smccc_set_attr(struct kvm *kvm, struct kvm_device_attr *attr); + #endif