From nobody Mon Jun 22 14:25:00 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4AC4AC433F5 for ; Tue, 22 Mar 2022 08:08:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229801AbiCVIJ1 (ORCPT ); Tue, 22 Mar 2022 04:09:27 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52432 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229602AbiCVIJY (ORCPT ); Tue, 22 Mar 2022 04:09:24 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id A691EDF7D for ; Tue, 22 Mar 2022 01:07:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1647936476; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=N9c9KYfInlm3WESUry5oYf1sTxA1uf+ImXpH7d2FaLk=; b=LlS40oTbSSla2J6g3LoKxw2SpRgoiJy6hPu57YBCU0JA6MnWsDHnSUoOiNwEBcfWm0G207 WorIiflAzxbvYsZQZw9NbncmSPHZLbv1aJdfr6isCaEBsmhLNhuzzqiPlNZiQWyg7qw+PI dNibwVzVbNWhu7WPm2eYwAPqVMlY8YU= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-569-o8EAzm0_PpO9EZ1_Y38Gag-1; Tue, 22 Mar 2022 04:07:53 -0400 X-MC-Unique: o8EAzm0_PpO9EZ1_Y38Gag-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 4061E1C04B66; Tue, 22 Mar 2022 08:07:53 +0000 (UTC) Received: from gshan.redhat.com (ovpn-12-33.pek2.redhat.com [10.72.12.33]) by smtp.corp.redhat.com (Postfix) with ESMTPS id E6FC61121324; Tue, 22 Mar 2022 08:07:41 +0000 (UTC) From: Gavin Shan To: kvmarm@lists.cs.columbia.edu Cc: linux-kernel@vger.kernel.org, eauger@redhat.com, shannon.zhaosl@gmail.com, maz@kernel.org, Jonathan.Cameron@huawei.com, will@kernel.org, pbonzini@redhat.com, james.morse@arm.com, mark.rutland@arm.com, drjones@redhat.com, vkuznets@redhat.com, shan.gavin@gmail.com Subject: [PATCH v5 01/22] KVM: arm64: Introduce template for inline functions Date: Tue, 22 Mar 2022 16:06:49 +0800 Message-Id: <20220322080710.51727-2-gshan@redhat.com> In-Reply-To: <20220322080710.51727-1-gshan@redhat.com> References: <20220322080710.51727-1-gshan@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" The inline functions used to get the SMCCC parameters have same layout. It means these functions can be presented by an unified template, to make the code simplified. Besides, this adds more similar inline functions like smccc_get_arg{4,5,6,7,8}() to get more SMCCC arguments, which are needed by SDEI virtualization support. Signed-off-by: Gavin Shan --- include/kvm/arm_hypercalls.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h index 0e2509d27910..d5144c852fe4 100644 --- a/include/kvm/arm_hypercalls.h +++ b/include/kvm/arm_hypercalls.h @@ -13,20 +13,20 @@ static inline u32 smccc_get_function(struct kvm_vcpu *v= cpu) return vcpu_get_reg(vcpu, 0); } =20 -static inline unsigned long smccc_get_arg1(struct kvm_vcpu *vcpu) -{ - return vcpu_get_reg(vcpu, 1); -} - -static inline unsigned long smccc_get_arg2(struct kvm_vcpu *vcpu) -{ - return vcpu_get_reg(vcpu, 2); +#define SMCCC_DECLARE_GET_ARG(reg) \ +static inline unsigned long smccc_get_arg##reg(struct kvm_vcpu *vcpu) \ +{ \ + return vcpu_get_reg(vcpu, reg); \ } =20 -static inline unsigned long smccc_get_arg3(struct kvm_vcpu *vcpu) -{ - return vcpu_get_reg(vcpu, 3); -} +SMCCC_DECLARE_GET_ARG(1) +SMCCC_DECLARE_GET_ARG(2) +SMCCC_DECLARE_GET_ARG(3) +SMCCC_DECLARE_GET_ARG(4) +SMCCC_DECLARE_GET_ARG(5) +SMCCC_DECLARE_GET_ARG(6) +SMCCC_DECLARE_GET_ARG(7) +SMCCC_DECLARE_GET_ARG(8) =20 static inline void smccc_set_retval(struct kvm_vcpu *vcpu, unsigned long a0, --=20 2.23.0 From nobody Mon Jun 22 14:25:00 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id EB24AC433F5 for ; Tue, 22 Mar 2022 08:08:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229849AbiCVIJt (ORCPT ); Tue, 22 Mar 2022 04:09:49 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52904 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229819AbiCVIJl (ORCPT ); Tue, 22 Mar 2022 04:09:41 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 19FC35AA66 for ; Tue, 22 Mar 2022 01:08:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1647936491; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=44GyAHa6Pj1FMP5IguIZbUGFA3CdvqimJarOV3Ihudw=; b=JwkF8IQsO0zWUaFKCMv7TjRTwEBQL5kgsSwjh44mtFhD0ZZSsDmr6SGl5Ca5mdH2bBjLvd RmDkoJ+DdOD1wLB0kzm0xU0h4loLjGns46ePJrfPEbRIw1q6u4NJRo5B3RtHXC3sa2Wamz nyRfPlzIfeXfdB4oAH92885SKVkNu0A= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-316-Wt3p9bdXPUSPujdnsEsqPg-1; Tue, 22 Mar 2022 04:08:07 -0400 X-MC-Unique: Wt3p9bdXPUSPujdnsEsqPg-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 61C4E899EC1; Tue, 22 Mar 2022 08:08:07 +0000 (UTC) Received: from gshan.redhat.com (ovpn-12-33.pek2.redhat.com [10.72.12.33]) by smtp.corp.redhat.com (Postfix) with ESMTPS id E80861121324; Tue, 22 Mar 2022 08:07:53 +0000 (UTC) From: Gavin Shan To: kvmarm@lists.cs.columbia.edu Cc: linux-kernel@vger.kernel.org, eauger@redhat.com, shannon.zhaosl@gmail.com, maz@kernel.org, Jonathan.Cameron@huawei.com, will@kernel.org, pbonzini@redhat.com, james.morse@arm.com, mark.rutland@arm.com, drjones@redhat.com, vkuznets@redhat.com, shan.gavin@gmail.com Subject: [PATCH v5 02/22] KVM: arm64: Add SDEI virtualization infrastructure Date: Tue, 22 Mar 2022 16:06:50 +0800 Message-Id: <20220322080710.51727-3-gshan@redhat.com> In-Reply-To: <20220322080710.51727-1-gshan@redhat.com> References: <20220322080710.51727-1-gshan@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Software Delegated Exception Interface (SDEI) provides a mechanism for registering and servicing system events. Those system events are high priority events, which must be serviced immediately. It's going to be used by Asynchronous Page Fault (APF) to deliver notification from KVM to guest. It's noted that SDEI is defined by ARM DEN0054C specification. This introduces SDEI virtualization infrastructure where the SDEI events are registered and manipulated by the guest through hypercall. The SDEI event is delivered to one specific vCPU by KVM once it's raised. This introduces data structures to represent the needed objects to support the feature, which is highlighted as below. As those objects could be migrated between VMs, these data structures are partially exposed to user space. * kvm_sdei_exposed_event The exposed events are determined and added by VMM through ioctl interface. Only the exposed events can be registered from the guest. * kvm_sdei_registered_event The events that have been registered from the guest through the SDEI_1_0_FN_SDEI_EVENT_REGISTER hypercall. * kvm_sdei_vcpu_event The events that have been delivered to the target vCPU. * kvm_sdei_vcpu Used to save the preempted context when the SDEI event is serviced and delivered. After the SDEI event handling is completed, the execution is resumed from the preempted context. * kvm_sdei_kvm Place holder for the exposed and registered events. The error of SDEI_NOT_SUPPORTED is returned for all SDEI hypercalls for now. They will be supported in the subsequent patches. Signed-off-by: Gavin Shan --- arch/arm64/include/asm/kvm_host.h | 3 + arch/arm64/include/asm/kvm_sdei.h | 171 +++++++++++++ arch/arm64/include/uapi/asm/kvm.h | 1 + arch/arm64/include/uapi/asm/kvm_sdei_state.h | 72 ++++++ arch/arm64/kvm/Makefile | 2 +- arch/arm64/kvm/arm.c | 8 + arch/arm64/kvm/hypercalls.c | 21 ++ arch/arm64/kvm/sdei.c | 244 +++++++++++++++++++ include/uapi/linux/arm_sdei.h | 2 + 9 files changed, 523 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/include/asm/kvm_sdei.h create mode 100644 arch/arm64/include/uapi/asm/kvm_sdei_state.h create mode 100644 arch/arm64/kvm/sdei.c diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm= _host.h index 031e3a2537fc..5d37e046a458 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -113,6 +113,8 @@ struct kvm_arch { /* Interrupt controller */ struct vgic_dist vgic; =20 + struct kvm_sdei_kvm *sdei; + /* Mandated version of PSCI */ u32 psci_version; =20 @@ -338,6 +340,7 @@ struct kvm_vcpu_arch { * Anything that is not used directly from assembly code goes * here. */ + struct kvm_sdei_vcpu *sdei; =20 /* * Guest registers we preserve during guest debugging. diff --git a/arch/arm64/include/asm/kvm_sdei.h b/arch/arm64/include/asm/kvm= _sdei.h new file mode 100644 index 000000000000..6f58a846d05c --- /dev/null +++ b/arch/arm64/include/asm/kvm_sdei.h @@ -0,0 +1,171 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Definitions of various KVM SDEI events. + * + * Copyright (C) 2022 Red Hat, Inc. + * + * Author(s): Gavin Shan + */ + +#ifndef __ARM64_KVM_SDEI_H__ +#define __ARM64_KVM_SDEI_H__ + +#include +#include +#include +#include +#include + +struct kvm_vcpu; + +struct kvm_sdei_exposed_event { + struct kvm_sdei_exposed_event_state state; + struct kvm *kvm; + unsigned int registered_event_count; + struct list_head link; +}; + +struct kvm_sdei_registered_event { + struct kvm_sdei_registered_event_state state; + struct kvm *kvm; + struct kvm_sdei_exposed_event *exposed_event; + unsigned int vcpu_event_count; + struct list_head link; +}; + +struct kvm_sdei_vcpu_event { + struct kvm_sdei_vcpu_event_state state; + struct kvm_vcpu *vcpu; + struct kvm_sdei_registered_event *registered_event; + struct list_head link; +}; + +struct kvm_sdei_kvm { + spinlock_t lock; + unsigned int exposed_event_count; + unsigned int registered_event_count; + struct list_head exposed_events; + struct list_head registered_events; +}; + +struct kvm_sdei_vcpu { + spinlock_t lock; + struct kvm_sdei_vcpu_state state; + struct kvm_sdei_vcpu_event *critical_event; + struct kvm_sdei_vcpu_event *normal_event; + unsigned int critical_event_count; + unsigned int normal_event_count; + struct list_head critical_events; + struct list_head normal_events; +}; + +/* + * According to SDEI specification (v1.1), the event number spans 32-bits + * and the lower 24-bits are used as the (real) event number. I don't + * think we can use that much SDEI numbers in one system. So we reserve + * two bits from the 24-bits real event number, to indicate its types: + * physical or virtual event. One reserved bit is enough for now, but + * two bits are reserved for possible extension in future. + * + * The physical events are owned by firmware while the virtual events + * are used by VMM and KVM. + */ +#define KVM_SDEI_EVENT_NUM_TYPE_SHIFT 22 +#define KVM_SDEI_EVENT_NUM_TYPE_MASK (3UL << KVM_SDEI_EVENT_NUM_TYPE_SHIFT) +#define KVM_SDEI_EVENT_NUM_TYPE_PHYS 0 +#define KVM_SDEI_EVENT_NUM_TYPE_VIRT 1 + +static inline bool kvm_sdei_is_virtual(unsigned long num) +{ + unsigned long type; + + if (num >> 32) + return false; + + type =3D (num & KVM_SDEI_EVENT_NUM_TYPE_MASK) >> + KVM_SDEI_EVENT_NUM_TYPE_SHIFT; + if (type !=3D KVM_SDEI_EVENT_NUM_TYPE_VIRT) + return false; + + return true; +} + +static inline bool kvm_sdei_is_default(unsigned long num) +{ + return num =3D=3D KVM_SDEI_DEFAULT_EVENT; +} + +static inline bool kvm_sdei_is_supported(unsigned long num) +{ + return kvm_sdei_is_default(num) || kvm_sdei_is_virtual(num); +} + +static inline bool kvm_sdei_is_shared(unsigned char type) +{ + return type =3D=3D SDEI_EVENT_TYPE_SHARED; +} + +static inline bool kvm_sdei_is_private(unsigned char type) +{ + return type =3D=3D SDEI_EVENT_TYPE_PRIVATE; +} + +static inline bool kvm_sdei_is_critical(unsigned char priority) +{ + return priority =3D=3D SDEI_EVENT_PRIORITY_CRITICAL; +} + +static inline bool kvm_sdei_is_normal(unsigned char priority) +{ + return priority =3D=3D SDEI_EVENT_PRIORITY_NORMAL; +} + +static inline unsigned int +kvm_sdei_vcpu_index(struct kvm_vcpu *vcpu, + struct kvm_sdei_exposed_event *event) +{ + return kvm_sdei_is_private(event->state.type) ? vcpu->vcpu_idx : 0; +} + +/* Accessors for the registered event */ +#define KVM_SDEI_REGISTERED_EVENT_FUNC(field) \ +static inline bool \ +kvm_sdei_is_##field(struct kvm_sdei_registered_event *event, \ + unsigned int index) \ +{ \ + return !!test_bit(index, (void *)(event->state.field)); \ +} \ + \ +static inline bool \ +kvm_sdei_none_##field(struct kvm_sdei_registered_event *event) \ +{ \ + return bitmap_empty((void *)(event->state.field), \ + KVM_SDEI_MAX_VCPUS); \ +} \ + \ +static inline void \ +kvm_sdei_set_##field(struct kvm_sdei_registered_event *event, \ + unsigned int index) \ +{ \ + set_bit(index, (void *)(event->state.field)); \ +} \ + \ +static inline void \ +kvm_sdei_clear_##field(struct kvm_sdei_registered_event *event, \ + unsigned int index) \ +{ \ + clear_bit(index, (void *)(event->state.field)); \ +} + +KVM_SDEI_REGISTERED_EVENT_FUNC(registered) +KVM_SDEI_REGISTERED_EVENT_FUNC(enabled) +KVM_SDEI_REGISTERED_EVENT_FUNC(unregister_pending) + +/* APIs */ +void kvm_sdei_init_vm(struct kvm *kvm); +void kvm_sdei_create_vcpu(struct kvm_vcpu *vcpu); +int kvm_sdei_hypercall(struct kvm_vcpu *vcpu); +void kvm_sdei_destroy_vcpu(struct kvm_vcpu *vcpu); +void kvm_sdei_destroy_vm(struct kvm *kvm); + +#endif /* __ARM64_KVM_SDEI_H__ */ diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/as= m/kvm.h index 323e251ed37b..33ee95bc088e 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -36,6 +36,7 @@ #include #include #include +#include =20 #define __KVM_HAVE_GUEST_DEBUG #define __KVM_HAVE_IRQ_LINE diff --git a/arch/arm64/include/uapi/asm/kvm_sdei_state.h b/arch/arm64/incl= ude/uapi/asm/kvm_sdei_state.h new file mode 100644 index 000000000000..b14844230117 --- /dev/null +++ b/arch/arm64/include/uapi/asm/kvm_sdei_state.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Definitions of various KVM SDEI event states. + * + * Copyright (C) 2022 Red Hat, Inc. + * + * Author(s): Gavin Shan + */ + +#ifndef _UAPI__ASM_KVM_SDEI_STATE_H +#define _UAPI__ASM_KVM_SDEI_STATE_H + +#ifndef __ASSEMBLY__ +#include + +/* + * The software signaled event is the default one, which is + * defined in v1.1 specification. + */ +#define KVM_SDEI_INVALID_EVENT 0xFFFFFFFF +#define KVM_SDEI_DEFAULT_EVENT 0 + +#define KVM_SDEI_MAX_VCPUS 512 /* Aligned to 64 */ +#define KVM_SDEI_MAX_EVENTS 128 + +struct kvm_sdei_exposed_event_state { + __u64 num; + + __u8 type; + __u8 signaled; + __u8 priority; + __u8 padding[5]; + __u64 notifier; +}; + +struct kvm_sdei_registered_event_state { + __u64 num; + + __u8 route_mode; + __u8 padding[3]; + __u64 route_affinity; + __u64 ep_address[KVM_SDEI_MAX_VCPUS]; + __u64 ep_arg[KVM_SDEI_MAX_VCPUS]; + __u64 registered[KVM_SDEI_MAX_VCPUS/64]; + __u64 enabled[KVM_SDEI_MAX_VCPUS/64]; + __u64 unregister_pending[KVM_SDEI_MAX_VCPUS/64]; +}; + +struct kvm_sdei_vcpu_event_state { + __u64 num; + + __u32 event_count; + __u32 padding; +}; + +struct kvm_sdei_vcpu_regs_state { + __u64 regs[18]; + __u64 pc; + __u64 pstate; +}; + +struct kvm_sdei_vcpu_state { + __u8 masked; + __u8 padding[7]; + __u64 critical_num; + __u64 normal_num; + struct kvm_sdei_vcpu_regs_state critical_regs; + struct kvm_sdei_vcpu_regs_state normal_regs; +}; + +#endif /* !__ASSEMBLY__ */ +#endif /* _UAPI__ASM_KVM_SDEI_STATE_H */ diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile index 91861fd8b897..a12903a21d1f 100644 --- a/arch/arm64/kvm/Makefile +++ b/arch/arm64/kvm/Makefile @@ -14,7 +14,7 @@ kvm-y +=3D arm.o mmu.o mmio.o psci.o hypercalls.o pvtime.= o \ inject_fault.o va_layout.o handle_exit.o \ guest.o debug.o reset.o sys_regs.o \ vgic-sys-reg-v3.o fpsimd.o pmu.o pkvm.o \ - arch_timer.o trng.o\ + arch_timer.o trng.o sdei.o \ vgic/vgic.o vgic/vgic-init.o \ vgic/vgic-irqfd.o vgic/vgic-v2.o \ vgic/vgic-v3.o vgic/vgic-v4.o \ diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 4dca6ffd03d4..96fcae5beee4 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -38,6 +38,7 @@ #include #include #include +#include #include =20 #include @@ -152,6 +153,8 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long typ= e) =20 kvm_vgic_early_init(kvm); =20 + kvm_sdei_init_vm(kvm); + /* The maximum number of VCPUs is limited by the host's GIC model */ kvm->arch.max_vcpus =3D kvm_arm_default_max_vcpus(); =20 @@ -179,6 +182,8 @@ void kvm_arch_destroy_vm(struct kvm *kvm) =20 kvm_vgic_destroy(kvm); =20 + kvm_sdei_destroy_vm(kvm); + kvm_destroy_vcpus(kvm); =20 kvm_unshare_hyp(kvm, kvm + 1); @@ -330,6 +335,8 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) =20 kvm_arm_pvtime_vcpu_init(&vcpu->arch); =20 + kvm_sdei_create_vcpu(vcpu); + vcpu->arch.hw_mmu =3D &vcpu->kvm->arch.mmu; =20 err =3D kvm_vgic_vcpu_init(vcpu); @@ -351,6 +358,7 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) kvm_mmu_free_memory_cache(&vcpu->arch.mmu_page_cache); kvm_timer_vcpu_terminate(vcpu); kvm_pmu_vcpu_destroy(vcpu); + kvm_sdei_destroy_vcpu(vcpu); =20 kvm_arm_vcpu_destroy(vcpu); } diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c index 202b8c455724..3c20fee72bb4 100644 --- a/arch/arm64/kvm/hypercalls.c +++ b/arch/arm64/kvm/hypercalls.c @@ -5,6 +5,7 @@ #include =20 #include +#include =20 #include #include @@ -151,6 +152,26 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) case ARM_SMCCC_TRNG_RND32: case ARM_SMCCC_TRNG_RND64: return kvm_trng_call(vcpu); + case SDEI_1_0_FN_SDEI_VERSION: + case SDEI_1_0_FN_SDEI_EVENT_REGISTER: + case SDEI_1_0_FN_SDEI_EVENT_ENABLE: + case SDEI_1_0_FN_SDEI_EVENT_DISABLE: + case SDEI_1_0_FN_SDEI_EVENT_CONTEXT: + case SDEI_1_0_FN_SDEI_EVENT_COMPLETE: + case SDEI_1_0_FN_SDEI_EVENT_COMPLETE_AND_RESUME: + case SDEI_1_0_FN_SDEI_EVENT_UNREGISTER: + case SDEI_1_0_FN_SDEI_EVENT_STATUS: + case SDEI_1_0_FN_SDEI_EVENT_GET_INFO: + case SDEI_1_0_FN_SDEI_EVENT_ROUTING_SET: + case SDEI_1_0_FN_SDEI_PE_MASK: + case SDEI_1_0_FN_SDEI_PE_UNMASK: + case SDEI_1_0_FN_SDEI_INTERRUPT_BIND: + case SDEI_1_0_FN_SDEI_INTERRUPT_RELEASE: + case SDEI_1_1_FN_SDEI_EVENT_SIGNAL: + case SDEI_1_0_FN_SDEI_PRIVATE_RESET: + case SDEI_1_0_FN_SDEI_SHARED_RESET: + case SDEI_1_1_FN_SDEI_FEATURES: + return kvm_sdei_hypercall(vcpu); default: return kvm_psci_call(vcpu); } diff --git a/arch/arm64/kvm/sdei.c b/arch/arm64/kvm/sdei.c new file mode 100644 index 000000000000..8a9b477b8977 --- /dev/null +++ b/arch/arm64/kvm/sdei.c @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * SDEI virtualization support. + * + * Copyright (C) 2022 Red Hat, Inc. + * + * Author(s): Gavin Shan + */ + +#include +#include +#include +#include +#include +#include + +static void remove_all_exposed_events(struct kvm *kvm) +{ + struct kvm_sdei_kvm *ksdei =3D kvm->arch.sdei; + struct kvm_sdei_exposed_event *exposed_event, *tmp; + + list_for_each_entry_safe(exposed_event, tmp, + &ksdei->exposed_events, link) { + ksdei->exposed_event_count--; + list_del(&exposed_event->link); + + kfree(exposed_event); + } +} + +static void remove_one_registered_event(struct kvm *kvm, + struct kvm_sdei_registered_event *registered_event) +{ + struct kvm_sdei_kvm *ksdei =3D kvm->arch.sdei; + struct kvm_sdei_exposed_event *exposed_event; + + exposed_event =3D registered_event->exposed_event; + ksdei->registered_event_count--; + exposed_event->registered_event_count--; + + list_del(®istered_event->link); + kfree(registered_event); +} + +static void remove_all_registered_events(struct kvm *kvm) +{ + struct kvm_sdei_kvm *ksdei =3D kvm->arch.sdei; + struct kvm_sdei_registered_event *registered_event, *tmp; + + list_for_each_entry_safe(registered_event, tmp, + &ksdei->registered_events, link) { + remove_one_registered_event(kvm, registered_event); + } +} + +static void remove_one_vcpu_event(struct kvm_vcpu *vcpu, + struct kvm_sdei_vcpu_event *vcpu_event) +{ + struct kvm_sdei_vcpu *vsdei =3D vcpu->arch.sdei; + struct kvm_sdei_exposed_event *exposed_event; + struct kvm_sdei_registered_event *registered_event; + + registered_event =3D vcpu_event->registered_event; + exposed_event =3D registered_event->exposed_event; + registered_event->vcpu_event_count--; + if (kvm_sdei_is_critical(exposed_event->state.priority)) + vsdei->critical_event_count--; + else + vsdei->normal_event_count--; + + list_del(&vcpu_event->link); + kfree(vcpu_event); +} + +static bool remove_all_vcpu_events(struct kvm_vcpu *vcpu, + unsigned long num) +{ + struct kvm_sdei_vcpu *vsdei =3D vcpu->arch.sdei; + struct kvm_sdei_vcpu_event *vcpu_event, *tmp; + bool pending =3D false; + + list_for_each_entry_safe(vcpu_event, tmp, + &vsdei->critical_events, link) { + if (!kvm_sdei_is_supported(num)) { + remove_one_vcpu_event(vcpu, vcpu_event); + continue; + } + + if (vcpu_event->state.num !=3D num) + continue; + + if (vsdei->critical_event =3D=3D vcpu_event) { + vcpu_event->state.event_count =3D 1; + pending =3D true; + } else { + remove_one_vcpu_event(vcpu, vcpu_event); + } + } + + list_for_each_entry_safe(vcpu_event, tmp, + &vsdei->normal_events, link) { + if (!kvm_sdei_is_supported(num)) { + remove_one_vcpu_event(vcpu, vcpu_event); + continue; + } + + if (vcpu_event->state.num !=3D num) + continue; + + if (vsdei->normal_event =3D=3D vcpu_event) { + vcpu_event->state.event_count =3D 1; + pending =3D true; + } else { + remove_one_vcpu_event(vcpu, vcpu_event); + } + } + + return pending; +} + +int kvm_sdei_hypercall(struct kvm_vcpu *vcpu) +{ + struct kvm *kvm =3D vcpu->kvm; + struct kvm_sdei_kvm *ksdei =3D kvm->arch.sdei; + struct kvm_sdei_vcpu *vsdei =3D vcpu->arch.sdei; + u32 func =3D smccc_get_function(vcpu); + bool has_result =3D true; + unsigned long ret; + + /* + * We don't have return value for COMPLETE or COMPLETE_AND_RESUME + * hypercalls. Otherwise, the restored context will be corrupted. + */ + if (func =3D=3D SDEI_1_0_FN_SDEI_EVENT_COMPLETE || + func =3D=3D SDEI_1_0_FN_SDEI_EVENT_COMPLETE_AND_RESUME) + has_result =3D false; + + if (!(ksdei && vsdei)) { + ret =3D SDEI_NOT_SUPPORTED; + goto out; + } + + switch (func) { + case SDEI_1_0_FN_SDEI_VERSION: + case SDEI_1_0_FN_SDEI_EVENT_REGISTER: + case SDEI_1_0_FN_SDEI_EVENT_ENABLE: + case SDEI_1_0_FN_SDEI_EVENT_DISABLE: + case SDEI_1_0_FN_SDEI_EVENT_CONTEXT: + case SDEI_1_0_FN_SDEI_EVENT_COMPLETE: + case SDEI_1_0_FN_SDEI_EVENT_COMPLETE_AND_RESUME: + case SDEI_1_0_FN_SDEI_EVENT_UNREGISTER: + case SDEI_1_0_FN_SDEI_EVENT_STATUS: + case SDEI_1_0_FN_SDEI_EVENT_GET_INFO: + case SDEI_1_0_FN_SDEI_EVENT_ROUTING_SET: + case SDEI_1_0_FN_SDEI_PE_MASK: + case SDEI_1_0_FN_SDEI_PE_UNMASK: + case SDEI_1_0_FN_SDEI_INTERRUPT_BIND: + case SDEI_1_0_FN_SDEI_INTERRUPT_RELEASE: + case SDEI_1_1_FN_SDEI_EVENT_SIGNAL: + case SDEI_1_0_FN_SDEI_PRIVATE_RESET: + case SDEI_1_0_FN_SDEI_SHARED_RESET: + case SDEI_1_1_FN_SDEI_FEATURES: + default: + ret =3D SDEI_NOT_SUPPORTED; + } + +out: + if (has_result) + smccc_set_retval(vcpu, ret, 0, 0, 0); + + return 1; +} + +void kvm_sdei_init_vm(struct kvm *kvm) +{ + struct kvm_sdei_kvm *ksdei; + + ksdei =3D kzalloc(sizeof(*ksdei), GFP_KERNEL_ACCOUNT); + if (!ksdei) + return; + + spin_lock_init(&ksdei->lock); + INIT_LIST_HEAD(&ksdei->exposed_events); + INIT_LIST_HEAD(&ksdei->registered_events); + + kvm->arch.sdei =3D ksdei; +} + +void kvm_sdei_create_vcpu(struct kvm_vcpu *vcpu) +{ + struct kvm *kvm =3D vcpu->kvm; + struct kvm_sdei_vcpu *vsdei; + + if (!kvm->arch.sdei) + return; + + vsdei =3D kzalloc(sizeof(*vsdei), GFP_KERNEL_ACCOUNT); + if (!vsdei) + return; + + spin_lock_init(&vsdei->lock); + vsdei->state.masked =3D 1; + vsdei->state.critical_num =3D KVM_SDEI_INVALID_EVENT; + vsdei->state.normal_num =3D KVM_SDEI_INVALID_EVENT; + vsdei->critical_event =3D NULL; + vsdei->normal_event =3D NULL; + INIT_LIST_HEAD(&vsdei->critical_events); + INIT_LIST_HEAD(&vsdei->normal_events); + + vcpu->arch.sdei =3D vsdei; +} + +void kvm_sdei_destroy_vcpu(struct kvm_vcpu *vcpu) +{ + struct kvm *kvm =3D vcpu->kvm; + struct kvm_sdei_kvm *ksdei =3D kvm->arch.sdei; + struct kvm_sdei_vcpu *vsdei =3D vcpu->arch.sdei; + + if (ksdei && vsdei) { + spin_lock(&ksdei->lock); + spin_lock(&vsdei->lock); + remove_all_vcpu_events(vcpu, KVM_SDEI_INVALID_EVENT); + spin_unlock(&vsdei->lock); + spin_unlock(&ksdei->lock); + + kfree(vsdei); + vcpu->arch.sdei =3D NULL; + } +} + +void kvm_sdei_destroy_vm(struct kvm *kvm) +{ + struct kvm_sdei_kvm *ksdei =3D kvm->arch.sdei; + + if (ksdei) { + spin_lock(&ksdei->lock); + remove_all_registered_events(kvm); + remove_all_exposed_events(kvm); + spin_unlock(&ksdei->lock); + + kfree(ksdei); + kvm->arch.sdei =3D NULL; + } +} diff --git a/include/uapi/linux/arm_sdei.h b/include/uapi/linux/arm_sdei.h index af0630ba5437..39bcf6dbbea0 100644 --- a/include/uapi/linux/arm_sdei.h +++ b/include/uapi/linux/arm_sdei.h @@ -22,8 +22,10 @@ #define SDEI_1_0_FN_SDEI_PE_UNMASK SDEI_1_0_FN(0x0C) #define SDEI_1_0_FN_SDEI_INTERRUPT_BIND SDEI_1_0_FN(0x0D) #define SDEI_1_0_FN_SDEI_INTERRUPT_RELEASE SDEI_1_0_FN(0x0E) +#define SDEI_1_1_FN_SDEI_EVENT_SIGNAL SDEI_1_0_FN(0x0F) #define SDEI_1_0_FN_SDEI_PRIVATE_RESET SDEI_1_0_FN(0x11) #define SDEI_1_0_FN_SDEI_SHARED_RESET SDEI_1_0_FN(0x12) +#define SDEI_1_1_FN_SDEI_FEATURES SDEI_1_0_FN(0x30) =20 #define SDEI_VERSION_MAJOR_SHIFT 48 #define SDEI_VERSION_MAJOR_MASK 0x7fff --=20 2.23.0 From nobody Mon Jun 22 14:25:00 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8AE9DC433EF for ; Tue, 22 Mar 2022 08:08:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229884AbiCVIKE (ORCPT ); Tue, 22 Mar 2022 04:10:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53046 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229819AbiCVIJu (ORCPT ); Tue, 22 Mar 2022 04:09:50 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 199D55A5B6 for ; Tue, 22 Mar 2022 01:08:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1647936498; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=hhCVxnMMhxOLAoQ7CT56ngfiw6zvDll/EwZY6fngGZg=; b=YRsiklvnVTBdwT8mNY7KiZ4Hik7rVoFmkcp9IPbxEnUbn3eARCcYiHC2nV01YHcjkWpxOi CWF2cH3HVATlmAZS58Do5cvjuPFn8b/8hMJDgtkz4e/G4QrF3hKBlu4bRJUzim19nWCq9w E+QbBcyPwL417YPrdZVlAzGll/ZHbDU= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-97-GRq1ZWpqOvKw7cQW1QWGrQ-1; Tue, 22 Mar 2022 04:08:14 -0400 X-MC-Unique: GRq1ZWpqOvKw7cQW1QWGrQ-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 26ACC38041CE; Tue, 22 Mar 2022 08:08:14 +0000 (UTC) Received: from gshan.redhat.com (ovpn-12-33.pek2.redhat.com [10.72.12.33]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 187621121325; Tue, 22 Mar 2022 08:08:07 +0000 (UTC) From: Gavin Shan To: kvmarm@lists.cs.columbia.edu Cc: linux-kernel@vger.kernel.org, eauger@redhat.com, shannon.zhaosl@gmail.com, maz@kernel.org, Jonathan.Cameron@huawei.com, will@kernel.org, pbonzini@redhat.com, james.morse@arm.com, mark.rutland@arm.com, drjones@redhat.com, vkuznets@redhat.com, shan.gavin@gmail.com Subject: [PATCH v5 03/22] KVM: arm64: Support SDEI_VERSION hypercall Date: Tue, 22 Mar 2022 16:06:51 +0800 Message-Id: <20220322080710.51727-4-gshan@redhat.com> In-Reply-To: <20220322080710.51727-1-gshan@redhat.com> References: <20220322080710.51727-1-gshan@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This supports SDEI_VERSION hypercall by returning v1.1, which is the specification version we're following. The vendor is set to 'KVM'. Signed-off-by: Gavin Shan --- arch/arm64/kvm/sdei.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm64/kvm/sdei.c b/arch/arm64/kvm/sdei.c index 8a9b477b8977..5a3a64cd6e84 100644 --- a/arch/arm64/kvm/sdei.c +++ b/arch/arm64/kvm/sdei.c @@ -118,6 +118,14 @@ static bool remove_all_vcpu_events(struct kvm_vcpu *vc= pu, return pending; } =20 +static unsigned long hypercall_version(struct kvm_vcpu *vcpu) +{ + /* v1.1 and the vendor is KVM */ + return (1UL << SDEI_VERSION_MAJOR_SHIFT) | + (1UL << SDEI_VERSION_MINOR_SHIFT) | + 0x4b564d; +} + int kvm_sdei_hypercall(struct kvm_vcpu *vcpu) { struct kvm *kvm =3D vcpu->kvm; @@ -142,6 +150,8 @@ int kvm_sdei_hypercall(struct kvm_vcpu *vcpu) =20 switch (func) { case SDEI_1_0_FN_SDEI_VERSION: + ret =3D hypercall_version(vcpu); + break; case SDEI_1_0_FN_SDEI_EVENT_REGISTER: case SDEI_1_0_FN_SDEI_EVENT_ENABLE: case SDEI_1_0_FN_SDEI_EVENT_DISABLE: --=20 2.23.0 From nobody Mon Jun 22 14:25:00 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C5DB6C433FE for ; Tue, 22 Mar 2022 08:08:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229851AbiCVIKP (ORCPT ); Tue, 22 Mar 2022 04:10:15 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53588 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229758AbiCVIKG (ORCPT ); Tue, 22 Mar 2022 04:10:06 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 4E10F14008 for ; Tue, 22 Mar 2022 01:08:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1647936511; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=XwXLs2x0k3sHxPIhNa8hpQ1441Z7oOsOWyaaI8W2j5s=; b=dEGgChpSD7oVXmnKLkhhyVmA2CCxcye/xsF2HDudVYKiSpXxkeIkYLClZhunANZOm3E54V jyfdQFRgC9GejgkIO2tzFCaue8t92ncwsqnQxhfhDrkuJ0w1EfkLD/fggba6U6uiGkGl7S 247IgO5BZpXvVDknScOLpbgifr1ISD4= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-384-eyCSNExZP8-7hhveFCSmRw-1; Tue, 22 Mar 2022 04:08:26 -0400 X-MC-Unique: eyCSNExZP8-7hhveFCSmRw-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id B1BA6185A79C; Tue, 22 Mar 2022 08:08:25 +0000 (UTC) Received: from gshan.redhat.com (ovpn-12-33.pek2.redhat.com [10.72.12.33]) by smtp.corp.redhat.com (Postfix) with ESMTPS id E00A21121324; Tue, 22 Mar 2022 08:08:14 +0000 (UTC) From: Gavin Shan To: kvmarm@lists.cs.columbia.edu Cc: linux-kernel@vger.kernel.org, eauger@redhat.com, shannon.zhaosl@gmail.com, maz@kernel.org, Jonathan.Cameron@huawei.com, will@kernel.org, pbonzini@redhat.com, james.morse@arm.com, mark.rutland@arm.com, drjones@redhat.com, vkuznets@redhat.com, shan.gavin@gmail.com Subject: [PATCH v5 04/22] KVM: arm64: Support SDEI_EVENT_REGISTER hypercall Date: Tue, 22 Mar 2022 16:06:52 +0800 Message-Id: <20220322080710.51727-5-gshan@redhat.com> In-Reply-To: <20220322080710.51727-1-gshan@redhat.com> References: <20220322080710.51727-1-gshan@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This supports SDEI_EVENT_REGISTER hypercall, which is used by guest to register SDEI events. The SDEI event won't be raised until it's registered and enabled explicitly. Only the exposed events can be registered. For shared event, the registered event instance is created. However, the instance may be not created for the private events. Signed-off-by: Gavin Shan --- arch/arm64/kvm/sdei.c | 128 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) diff --git a/arch/arm64/kvm/sdei.c b/arch/arm64/kvm/sdei.c index 5a3a64cd6e84..2458dc666445 100644 --- a/arch/arm64/kvm/sdei.c +++ b/arch/arm64/kvm/sdei.c @@ -14,6 +14,35 @@ #include #include =20 +static struct kvm_sdei_exposed_event * +find_exposed_event(struct kvm *kvm, unsigned long num) +{ + struct kvm_sdei_kvm *ksdei =3D kvm->arch.sdei; + struct kvm_sdei_exposed_event *exposed_event; + + list_for_each_entry(exposed_event, &ksdei->exposed_events, link) { + if (exposed_event->state.num =3D=3D num) + return exposed_event; + } + + return NULL; +} + +static struct kvm_sdei_registered_event * +find_registered_event(struct kvm *kvm, unsigned long num) +{ + struct kvm_sdei_kvm *ksdei =3D kvm->arch.sdei; + struct kvm_sdei_registered_event *registered_event; + + list_for_each_entry(registered_event, + &ksdei->registered_events, link) { + if (registered_event->state.num =3D=3D num) + return registered_event; + } + + return NULL; +} + static void remove_all_exposed_events(struct kvm *kvm) { struct kvm_sdei_kvm *ksdei =3D kvm->arch.sdei; @@ -126,6 +155,103 @@ static unsigned long hypercall_version(struct kvm_vcp= u *vcpu) 0x4b564d; } =20 +static unsigned long hypercall_register(struct kvm_vcpu *vcpu) +{ + struct kvm *kvm =3D vcpu->kvm; + struct kvm_sdei_kvm *ksdei =3D kvm->arch.sdei; + struct kvm_sdei_exposed_event *exposed_event; + struct kvm_sdei_registered_event *registered_event; + unsigned long event_num =3D smccc_get_arg1(vcpu); + unsigned long event_ep_address =3D smccc_get_arg2(vcpu); + unsigned long event_ep_arg =3D smccc_get_arg3(vcpu); + unsigned long route_mode =3D smccc_get_arg4(vcpu); + unsigned long route_affinity =3D smccc_get_arg5(vcpu); + int index; + unsigned long ret =3D SDEI_SUCCESS; + + if (!kvm_sdei_is_supported(event_num)) { + ret =3D SDEI_INVALID_PARAMETERS; + goto out; + } + + if (route_mode !=3D SDEI_EVENT_REGISTER_RM_ANY && + route_mode !=3D SDEI_EVENT_REGISTER_RM_PE) { + ret =3D SDEI_INVALID_PARAMETERS; + goto out; + } + + spin_lock(&ksdei->lock); + + /* + * The registered event could have been existing if it's a private + * one. We needn't to create another registered event instance + * in this case. + */ + registered_event =3D find_registered_event(kvm, event_num); + if (registered_event) { + exposed_event =3D registered_event->exposed_event; + index =3D kvm_sdei_vcpu_index(vcpu, exposed_event); + if (kvm_sdei_is_registered(registered_event, index) || + kvm_sdei_is_unregister_pending(registered_event, index)) { + ret =3D SDEI_DENIED; + goto unlock; + } + + registered_event->state.route_mode =3D route_mode; + registered_event->state.route_affinity =3D route_affinity; + registered_event->state.ep_address[index] =3D event_ep_address; + registered_event->state.ep_arg[index] =3D event_ep_arg; + kvm_sdei_set_registered(registered_event, index); + goto unlock; + } + + /* Check if the exposed event exists */ + exposed_event =3D find_exposed_event(kvm, event_num); + if (!exposed_event) { + ret =3D SDEI_INVALID_PARAMETERS; + goto unlock; + } + + /* + * Check if the count of registered event instances exceeds + * the limit. + */ + if (ksdei->registered_event_count >=3D KVM_SDEI_MAX_EVENTS) { + ret =3D SDEI_OUT_OF_RESOURCE; + goto unlock; + } + + /* Allocate the registered event instance */ + registered_event =3D kzalloc(sizeof(*registered_event), + GFP_KERNEL_ACCOUNT); + if (!registered_event) { + ret =3D SDEI_OUT_OF_RESOURCE; + goto unlock; + } + + /* Initialize the registered event state */ + index =3D kvm_sdei_vcpu_index(vcpu, exposed_event); + registered_event->state.num =3D event_num; + registered_event->state.route_mode =3D route_affinity; + registered_event->state.route_affinity =3D route_affinity; + registered_event->state.ep_address[index] =3D event_ep_address; + registered_event->state.ep_arg[index] =3D event_ep_arg; + registered_event->kvm =3D kvm; + registered_event->exposed_event =3D exposed_event; + registered_event->vcpu_event_count =3D 0; + kvm_sdei_set_registered(registered_event, index); + + /* Add the registered event instance */ + ksdei->registered_event_count++; + exposed_event->registered_event_count++; + list_add_tail(®istered_event->link, &ksdei->registered_events); + +unlock: + spin_unlock(&ksdei->lock); +out: + return ret; +} + int kvm_sdei_hypercall(struct kvm_vcpu *vcpu) { struct kvm *kvm =3D vcpu->kvm; @@ -153,6 +279,8 @@ int kvm_sdei_hypercall(struct kvm_vcpu *vcpu) ret =3D hypercall_version(vcpu); break; case SDEI_1_0_FN_SDEI_EVENT_REGISTER: + ret =3D hypercall_register(vcpu); + break; case SDEI_1_0_FN_SDEI_EVENT_ENABLE: case SDEI_1_0_FN_SDEI_EVENT_DISABLE: case SDEI_1_0_FN_SDEI_EVENT_CONTEXT: --=20 2.23.0 From nobody Mon Jun 22 14:25:00 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A8A4CC433F5 for ; Tue, 22 Mar 2022 08:08:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229831AbiCVIKK (ORCPT ); Tue, 22 Mar 2022 04:10:10 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53628 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229829AbiCVIKH (ORCPT ); Tue, 22 Mar 2022 04:10:07 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id D9958B02 for ; Tue, 22 Mar 2022 01:08:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1647936516; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=RDKgDYiBOvXHcRQ85sq8ZIkE8hhZPdi12RYn7yZMjUw=; b=eZmq4a0ftCgQxpHplP4/5yNsk6yg5aVrs+kE/A1ASV/uPjto2OqrjCJscITbr3wL6NNRPj zuAUqxWCf5j7uPnb4DsNODMqqjTx7tUDZekVqOG8PbduZoktO4QKNvASp+AAIrZdRbnueY VGqSRCxg/8AogUh7bH67KJG6xbo0Qn4= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-625-ZDCvtjobO4Cgi80HYpcbYQ-1; Tue, 22 Mar 2022 04:08:32 -0400 X-MC-Unique: ZDCvtjobO4Cgi80HYpcbYQ-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 3B8B4811E75; Tue, 22 Mar 2022 08:08:32 +0000 (UTC) Received: from gshan.redhat.com (ovpn-12-33.pek2.redhat.com [10.72.12.33]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 779721121324; Tue, 22 Mar 2022 08:08:26 +0000 (UTC) From: Gavin Shan To: kvmarm@lists.cs.columbia.edu Cc: linux-kernel@vger.kernel.org, eauger@redhat.com, shannon.zhaosl@gmail.com, maz@kernel.org, Jonathan.Cameron@huawei.com, will@kernel.org, pbonzini@redhat.com, james.morse@arm.com, mark.rutland@arm.com, drjones@redhat.com, vkuznets@redhat.com, shan.gavin@gmail.com Subject: [PATCH v5 05/22] KVM: arm64: Support SDEI_EVENT_{ENABLE, DISABLE} hypercall Date: Tue, 22 Mar 2022 16:06:53 +0800 Message-Id: <20220322080710.51727-6-gshan@redhat.com> In-Reply-To: <20220322080710.51727-1-gshan@redhat.com> References: <20220322080710.51727-1-gshan@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This supports SDEI_EVENT_{ENABLE, DISABLE} hypercall. After SDEI event is registered by guest, it won't be delivered to the guest until it's enabled. For unregistration pending event, we can't enable or disable it as the registered event is going to be destroyed after current event is handled. Signed-off-by: Gavin Shan --- arch/arm64/kvm/sdei.c | 49 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/arch/arm64/kvm/sdei.c b/arch/arm64/kvm/sdei.c index 2458dc666445..4ab58f264992 100644 --- a/arch/arm64/kvm/sdei.c +++ b/arch/arm64/kvm/sdei.c @@ -252,6 +252,51 @@ static unsigned long hypercall_register(struct kvm_vcp= u *vcpu) return ret; } =20 +static unsigned long hypercall_enable(struct kvm_vcpu *vcpu, bool enable) +{ + struct kvm *kvm =3D vcpu->kvm; + struct kvm_sdei_kvm *ksdei =3D kvm->arch.sdei; + struct kvm_sdei_exposed_event *exposed_event; + struct kvm_sdei_registered_event *registered_event; + unsigned long event_num =3D smccc_get_arg1(vcpu); + int index; + unsigned long ret =3D SDEI_SUCCESS; + + if (!kvm_sdei_is_supported(event_num)) { + ret =3D SDEI_INVALID_PARAMETERS; + goto out; + } + + spin_lock(&ksdei->lock); + + /* Check if the registered event exists */ + registered_event =3D find_registered_event(kvm, event_num); + if (!registered_event) { + ret =3D SDEI_DENIED; + goto unlock; + } + + /* Check if the event is registered and pending for unregistration */ + exposed_event =3D registered_event->exposed_event; + index =3D kvm_sdei_vcpu_index(vcpu, exposed_event); + if (!kvm_sdei_is_registered(registered_event, index) || + kvm_sdei_is_unregister_pending(registered_event, index)) { + ret =3D SDEI_DENIED; + goto unlock; + } + + /* Update the enablement state */ + if (enable) + kvm_sdei_set_enabled(registered_event, index); + else + kvm_sdei_clear_enabled(registered_event, index); + +unlock: + spin_unlock(&ksdei->lock); +out: + return ret; +} + int kvm_sdei_hypercall(struct kvm_vcpu *vcpu) { struct kvm *kvm =3D vcpu->kvm; @@ -282,7 +327,11 @@ int kvm_sdei_hypercall(struct kvm_vcpu *vcpu) ret =3D hypercall_register(vcpu); break; case SDEI_1_0_FN_SDEI_EVENT_ENABLE: + ret =3D hypercall_enable(vcpu, true); + break; case SDEI_1_0_FN_SDEI_EVENT_DISABLE: + ret =3D hypercall_enable(vcpu, false); + break; case SDEI_1_0_FN_SDEI_EVENT_CONTEXT: case SDEI_1_0_FN_SDEI_EVENT_COMPLETE: case SDEI_1_0_FN_SDEI_EVENT_COMPLETE_AND_RESUME: --=20 2.23.0 From nobody Mon Jun 22 14:25:00 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 65835C433F5 for ; Tue, 22 Mar 2022 08:08:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229930AbiCVIKW (ORCPT ); Tue, 22 Mar 2022 04:10:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53914 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229816AbiCVIKO (ORCPT ); Tue, 22 Mar 2022 04:10:14 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 74CA42BFA for ; Tue, 22 Mar 2022 01:08:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1647936526; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=CA0H5z8Y8jCywSeEwJTZ/p/KNFj1y45LOqR+04gyQvM=; b=P4lejcfDAKxMRzaHpAeRSzLSu6hyMzT1etaaXEZuOz37uFb5/hryx/Tz5CqoWausnHFmyT MRAhDcLjDHMyhIMfjZp2etuRx1IjL80eW9gLobgHVLhxKNVKNzX2c0agKBZ+IY5ts+ANER 9XGBqOqMXnJTftO4DgTHS0XXL1CnjvU= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-594-IV6VDCqaMjeWV-YfzD9R6Q-1; Tue, 22 Mar 2022 04:08:43 -0400 X-MC-Unique: IV6VDCqaMjeWV-YfzD9R6Q-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id C0B5B1C05AF2; Tue, 22 Mar 2022 08:08:42 +0000 (UTC) Received: from gshan.redhat.com (ovpn-12-33.pek2.redhat.com [10.72.12.33]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 0ACDB1121324; Tue, 22 Mar 2022 08:08:32 +0000 (UTC) From: Gavin Shan To: kvmarm@lists.cs.columbia.edu Cc: linux-kernel@vger.kernel.org, eauger@redhat.com, shannon.zhaosl@gmail.com, maz@kernel.org, Jonathan.Cameron@huawei.com, will@kernel.org, pbonzini@redhat.com, james.morse@arm.com, mark.rutland@arm.com, drjones@redhat.com, vkuznets@redhat.com, shan.gavin@gmail.com Subject: [PATCH v5 06/22] KVM: arm64: Support SDEI_EVENT_CONTEXT hypercall Date: Tue, 22 Mar 2022 16:06:54 +0800 Message-Id: <20220322080710.51727-7-gshan@redhat.com> In-Reply-To: <20220322080710.51727-1-gshan@redhat.com> References: <20220322080710.51727-1-gshan@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This supports SDEI_EVENT_CONTEXT hypercall. It's used by the guest to retrieve the registers (R0 - R17) in the preempted context in the SDEI event handler. The preempted context is saved prior to servicing or handling the SDEI event and restored after that. Signed-off-by: Gavin Shan --- arch/arm64/kvm/sdei.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/arch/arm64/kvm/sdei.c b/arch/arm64/kvm/sdei.c index 4ab58f264992..4488d3f044f2 100644 --- a/arch/arm64/kvm/sdei.c +++ b/arch/arm64/kvm/sdei.c @@ -297,6 +297,34 @@ static unsigned long hypercall_enable(struct kvm_vcpu = *vcpu, bool enable) return ret; } =20 +static unsigned long hypercall_context(struct kvm_vcpu *vcpu) +{ + struct kvm_sdei_vcpu *vsdei =3D vcpu->arch.sdei; + struct kvm_sdei_vcpu_regs_state *regs; + unsigned long param_id =3D smccc_get_arg1(vcpu); + unsigned long ret =3D SDEI_SUCCESS; + + spin_lock(&vsdei->lock); + + /* Check if the pending event exists */ + if (!vsdei->critical_event && !vsdei->normal_event) { + ret =3D SDEI_DENIED; + goto unlock; + } + + /* Fetch the requested register */ + regs =3D vsdei->critical_event ? &vsdei->state.critical_regs : + &vsdei->state.normal_regs; + if (param_id < ARRAY_SIZE(regs->regs)) + ret =3D regs->regs[param_id]; + else + ret =3D SDEI_INVALID_PARAMETERS; + +unlock: + spin_unlock(&vsdei->lock); + return ret; +} + int kvm_sdei_hypercall(struct kvm_vcpu *vcpu) { struct kvm *kvm =3D vcpu->kvm; @@ -333,6 +361,8 @@ int kvm_sdei_hypercall(struct kvm_vcpu *vcpu) ret =3D hypercall_enable(vcpu, false); break; case SDEI_1_0_FN_SDEI_EVENT_CONTEXT: + ret =3D hypercall_context(vcpu); + break; case SDEI_1_0_FN_SDEI_EVENT_COMPLETE: case SDEI_1_0_FN_SDEI_EVENT_COMPLETE_AND_RESUME: case SDEI_1_0_FN_SDEI_EVENT_UNREGISTER: --=20 2.23.0 From nobody Mon Jun 22 14:25:00 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9BEF3C433FE for ; Tue, 22 Mar 2022 08:09:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229973AbiCVIK3 (ORCPT ); Tue, 22 Mar 2022 04:10:29 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54442 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229909AbiCVIKZ (ORCPT ); Tue, 22 Mar 2022 04:10:25 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 8898E2C4 for ; Tue, 22 Mar 2022 01:08:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1647936536; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=iiu9RjNPKo0dVPTWpVo+lOgd3Qb2+2dr9PAVFbVsol0=; b=XrSDr+lTNn28NsxVtmBQ806M4dd6zfgOLZv5+BIkmqZDV9yyM2KvPOmWQNYKXSs5PxQ0P5 vP/ssqG/RImYlJisntbwez4mfp9x0yVZeyy1NJ1nKunegklmuNNAMiSXRf1k+iQ9GkPUI+ /XipnnTK/ASygG0Uzz76qXlLq4frrZ8= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-668-aqx-ZFLUPc2h8Xc4Xdgv-A-1; Tue, 22 Mar 2022 04:08:52 -0400 X-MC-Unique: aqx-ZFLUPc2h8Xc4Xdgv-A-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 1AD48811E75; Tue, 22 Mar 2022 08:08:52 +0000 (UTC) Received: from gshan.redhat.com (ovpn-12-33.pek2.redhat.com [10.72.12.33]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 822931121324; Tue, 22 Mar 2022 08:08:43 +0000 (UTC) From: Gavin Shan To: kvmarm@lists.cs.columbia.edu Cc: linux-kernel@vger.kernel.org, eauger@redhat.com, shannon.zhaosl@gmail.com, maz@kernel.org, Jonathan.Cameron@huawei.com, will@kernel.org, pbonzini@redhat.com, james.morse@arm.com, mark.rutland@arm.com, drjones@redhat.com, vkuznets@redhat.com, shan.gavin@gmail.com Subject: [PATCH v5 07/22] KVM: arm64: Support SDEI_EVENT_UNREGISTER hypercall Date: Tue, 22 Mar 2022 16:06:55 +0800 Message-Id: <20220322080710.51727-8-gshan@redhat.com> In-Reply-To: <20220322080710.51727-1-gshan@redhat.com> References: <20220322080710.51727-1-gshan@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This supports SDEI_EVENT_UNREGISTER hypercall. It's used by the guest to unregister SDEI event. The SDEI event won't be raised to the guest after it's unregistered. The SDEI event is disabled automatically on unregistration. The currently handled events can't be unregistered. We set the unregistration pending state for the event so that it can be unregistered when the event handler is completed by receiving SDEI_EVENT_{COMPLETE, COMPLETE_AND_RESUME} hypercall. Signed-off-by: Gavin Shan --- arch/arm64/kvm/sdei.c | 133 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/arch/arm64/kvm/sdei.c b/arch/arm64/kvm/sdei.c index 4488d3f044f2..36eda31e0392 100644 --- a/arch/arm64/kvm/sdei.c +++ b/arch/arm64/kvm/sdei.c @@ -325,6 +325,135 @@ static unsigned long hypercall_context(struct kvm_vcp= u *vcpu) return ret; } =20 +static unsigned long +unregister_one_event(struct kvm *kvm, struct kvm_vcpu *vcpu, + struct kvm_sdei_registered_event *registered_event) +{ + struct kvm_vcpu *vcpup; + struct kvm_sdei_vcpu *vsdei; + struct kvm_sdei_exposed_event *exposed_event; + int index; + bool pending; + unsigned long i, ret =3D SDEI_SUCCESS; + + /* + * Cancel all vcpu events that have been queued, but not dispatched + * yet. If the vcpu event has been dispatched, we should mark it + * as pending for unregistration. The unregistration will be executed + * when the event handler is to be completed. + */ + exposed_event =3D registered_event->exposed_event; + kvm_for_each_vcpu(i, vcpup, kvm) { + vsdei =3D vcpup->arch.sdei; + if (!vsdei) + continue; + + /* + * The private vcpu events are requested to be unregistered + * on the specific vcpu or all vcpus. @vcpu is used to + * identify the cases. For the shared vcpu events, we need + * to unregister them on all vcpus. + */ + if (kvm_sdei_is_private(exposed_event->state.type) && + vcpu && vcpu !=3D vcpup) + continue; + + if (registered_event->vcpu_event_count > 0) { + spin_lock(&vsdei->lock); + pending =3D remove_all_vcpu_events(vcpup, + registered_event->state.num); + spin_unlock(&vsdei->lock); + } else { + pending =3D false; + } + + /* + * For the private event, the pending state for unregistration + * is scattered and we need to update them individually. + * However, that same state for the shared event has to be + * updated at once according to @ret after the iteration is + * done. + */ + ret =3D pending ? SDEI_PENDING : ret; + if (!kvm_sdei_is_private(exposed_event->state.type)) + continue; + + index =3D kvm_sdei_vcpu_index(vcpup, exposed_event); + if (pending) { + kvm_sdei_set_unregister_pending(registered_event, + index); + } else { + kvm_sdei_clear_enabled(registered_event, index); + kvm_sdei_clear_registered(registered_event, index); + } + } + + /* + * Update the pending state for unregistration for the shared event + * at once. + */ + if (kvm_sdei_is_shared(exposed_event->state.type)) { + index =3D kvm_sdei_vcpu_index(vcpu, exposed_event); + if (ret =3D=3D SDEI_PENDING) { + kvm_sdei_set_unregister_pending(registered_event, + index); + } else { + kvm_sdei_clear_enabled(registered_event, index); + kvm_sdei_clear_registered(registered_event, index); + } + } + + /* Destroy the registered event instance if needed */ + if (kvm_sdei_none_registered(registered_event)) + remove_one_registered_event(kvm, registered_event); + + return ret; +} + +static unsigned long hypercall_unregister(struct kvm_vcpu *vcpu) +{ + struct kvm *kvm =3D vcpu->kvm; + struct kvm_sdei_kvm *ksdei =3D kvm->arch.sdei; + struct kvm_sdei_exposed_event *exposed_event; + struct kvm_sdei_registered_event *registered_event; + unsigned long event_num =3D smccc_get_arg1(vcpu); + int index; + unsigned long ret =3D SDEI_SUCCESS; + + if (!kvm_sdei_is_supported(event_num)) + return SDEI_INVALID_PARAMETERS; + + spin_lock(&ksdei->lock); + + /* Check if the registered event exists */ + registered_event =3D find_registered_event(kvm, event_num); + if (!registered_event) { + ret =3D SDEI_INVALID_PARAMETERS; + goto unlock; + } + + /* Check if the event has been registered */ + exposed_event =3D registered_event->exposed_event; + index =3D kvm_sdei_vcpu_index(vcpu, exposed_event); + if (!kvm_sdei_is_registered(registered_event, index)) { + ret =3D SDEI_DENIED; + goto unlock; + } + + /* Check if the event has been pending for unregistration */ + if (kvm_sdei_is_unregister_pending(registered_event, index)) { + ret =3D SDEI_PENDING; + goto unlock; + } + + ret =3D unregister_one_event(kvm, vcpu, registered_event); + +unlock: + spin_unlock(&ksdei->lock); + + return ret; +} + int kvm_sdei_hypercall(struct kvm_vcpu *vcpu) { struct kvm *kvm =3D vcpu->kvm; @@ -365,7 +494,11 @@ int kvm_sdei_hypercall(struct kvm_vcpu *vcpu) break; case SDEI_1_0_FN_SDEI_EVENT_COMPLETE: case SDEI_1_0_FN_SDEI_EVENT_COMPLETE_AND_RESUME: + ret =3D SDEI_NOT_SUPPORTED; + break; case SDEI_1_0_FN_SDEI_EVENT_UNREGISTER: + ret =3D hypercall_unregister(vcpu); + break; case SDEI_1_0_FN_SDEI_EVENT_STATUS: case SDEI_1_0_FN_SDEI_EVENT_GET_INFO: case SDEI_1_0_FN_SDEI_EVENT_ROUTING_SET: --=20 2.23.0 From nobody Mon Jun 22 14:25:00 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C4F36C433F5 for ; Tue, 22 Mar 2022 08:09:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230064AbiCVIKt (ORCPT ); Tue, 22 Mar 2022 04:10:49 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54262 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229985AbiCVIKe (ORCPT ); Tue, 22 Mar 2022 04:10:34 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 21AC626F3 for ; Tue, 22 Mar 2022 01:09:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1647936542; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=fTnMxADpXxnYuQkzViZbgk/aAQ/eKV1ZLVLzIbtgdgU=; b=IRJD8jJUHT+4OR81WJWXjXvK6G1a+WpdQjCnH1Z/4JsQXMs0StxGE5a6Y8suAhn/7Ec7n9 hcimO9JLnTmEtqT7W1UxNsmmSUubxWc07OGnnUdfw2K4WHBYxbU0TAQhoSlyQk4nIB2Enc cbVZ228PMvBYM5HqZYbI6zODWHbYbeQ= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-155-bvRgHREHPe-x5Yy-r3kExA-1; Tue, 22 Mar 2022 04:08:58 -0400 X-MC-Unique: bvRgHREHPe-x5Yy-r3kExA-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 485DD8038E3; Tue, 22 Mar 2022 08:08:58 +0000 (UTC) Received: from gshan.redhat.com (ovpn-12-33.pek2.redhat.com [10.72.12.33]) by smtp.corp.redhat.com (Postfix) with ESMTPS id C40281121324; Tue, 22 Mar 2022 08:08:52 +0000 (UTC) From: Gavin Shan To: kvmarm@lists.cs.columbia.edu Cc: linux-kernel@vger.kernel.org, eauger@redhat.com, shannon.zhaosl@gmail.com, maz@kernel.org, Jonathan.Cameron@huawei.com, will@kernel.org, pbonzini@redhat.com, james.morse@arm.com, mark.rutland@arm.com, drjones@redhat.com, vkuznets@redhat.com, shan.gavin@gmail.com Subject: [PATCH v5 08/22] KVM: arm64: Support SDEI_EVENT_STATUS hypercall Date: Tue, 22 Mar 2022 16:06:56 +0800 Message-Id: <20220322080710.51727-9-gshan@redhat.com> In-Reply-To: <20220322080710.51727-1-gshan@redhat.com> References: <20220322080710.51727-1-gshan@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This supports SDEI_EVENT_STATUS hypercall. It's used by the guest to retrieve the status about the specified SDEI event. A bitmap is returned to indicate the corresponding status, including registration, enablement and delivery state. Signed-off-by: Gavin Shan --- arch/arm64/kvm/sdei.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/arch/arm64/kvm/sdei.c b/arch/arm64/kvm/sdei.c index 36eda31e0392..5c43c8912ea1 100644 --- a/arch/arm64/kvm/sdei.c +++ b/arch/arm64/kvm/sdei.c @@ -454,6 +454,46 @@ static unsigned long hypercall_unregister(struct kvm_v= cpu *vcpu) return ret; } =20 +static unsigned long hypercall_status(struct kvm_vcpu *vcpu) +{ + struct kvm *kvm =3D vcpu->kvm; + struct kvm_sdei_kvm *ksdei =3D kvm->arch.sdei; + struct kvm_sdei_exposed_event *exposed_event; + struct kvm_sdei_registered_event *registered_event; + unsigned long event_num =3D smccc_get_arg1(vcpu); + int index; + unsigned long ret =3D 0; + + if (!kvm_sdei_is_supported(event_num)) { + ret =3D SDEI_INVALID_PARAMETERS; + goto out; + } + + spin_lock(&ksdei->lock); + + /* + * Check if the registered event exists. None of the flags + * will be set if it doesn't exist. + */ + registered_event =3D find_registered_event(kvm, event_num); + if (!registered_event) + goto unlock; + + exposed_event =3D registered_event->exposed_event; + index =3D kvm_sdei_vcpu_index(vcpu, exposed_event); + if (kvm_sdei_is_registered(registered_event, index)) + ret |=3D (1UL << SDEI_EVENT_STATUS_REGISTERED); + if (kvm_sdei_is_enabled(registered_event, index)) + ret |=3D (1UL << SDEI_EVENT_STATUS_ENABLED); + if (registered_event->vcpu_event_count > 0) + ret |=3D (1UL << SDEI_EVENT_STATUS_RUNNING); + +unlock: + spin_unlock(&ksdei->lock); +out: + return ret; +} + int kvm_sdei_hypercall(struct kvm_vcpu *vcpu) { struct kvm *kvm =3D vcpu->kvm; @@ -500,6 +540,8 @@ int kvm_sdei_hypercall(struct kvm_vcpu *vcpu) ret =3D hypercall_unregister(vcpu); break; case SDEI_1_0_FN_SDEI_EVENT_STATUS: + ret =3D hypercall_status(vcpu); + break; case SDEI_1_0_FN_SDEI_EVENT_GET_INFO: case SDEI_1_0_FN_SDEI_EVENT_ROUTING_SET: case SDEI_1_0_FN_SDEI_PE_MASK: --=20 2.23.0 From nobody Mon Jun 22 14:25:00 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C18FEC433F5 for ; Tue, 22 Mar 2022 08:09:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229543AbiCVIKz (ORCPT ); Tue, 22 Mar 2022 04:10:55 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55206 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230014AbiCVIKk (ORCPT ); Tue, 22 Mar 2022 04:10:40 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id BA82A636E for ; Tue, 22 Mar 2022 01:09:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1647936546; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=uBmvh5ZuowzkjTYHJM1SHAN/6NzyYtxJ4RrsdQ22jlY=; b=dv8g+DDaiBy3m7Vm2gbOsKYC8dgxsURw7XZj32x6MDmKLlQqojC8Hb4yCoPDI14tBPwwKm nTfZseJJpVnNl4QH14l6xZZwmKDeHuXEd6uJ1BD9qA0FZy9iq6Hhe8XKsLU6Q7Fn0RkXrr PADlKKbYfYRL716VQ402/2CNdRdWtyY= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-451-KasuIbuaPbesOOtic6uUbg-1; Tue, 22 Mar 2022 04:09:05 -0400 X-MC-Unique: KasuIbuaPbesOOtic6uUbg-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 6FB1B1044562; Tue, 22 Mar 2022 08:09:04 +0000 (UTC) Received: from gshan.redhat.com (ovpn-12-33.pek2.redhat.com [10.72.12.33]) by smtp.corp.redhat.com (Postfix) with ESMTPS id F41401121324; Tue, 22 Mar 2022 08:08:58 +0000 (UTC) From: Gavin Shan To: kvmarm@lists.cs.columbia.edu Cc: linux-kernel@vger.kernel.org, eauger@redhat.com, shannon.zhaosl@gmail.com, maz@kernel.org, Jonathan.Cameron@huawei.com, will@kernel.org, pbonzini@redhat.com, james.morse@arm.com, mark.rutland@arm.com, drjones@redhat.com, vkuznets@redhat.com, shan.gavin@gmail.com Subject: [PATCH v5 09/22] KVM: arm64: Support SDEI_EVENT_GET_INFO hypercall Date: Tue, 22 Mar 2022 16:06:57 +0800 Message-Id: <20220322080710.51727-10-gshan@redhat.com> In-Reply-To: <20220322080710.51727-1-gshan@redhat.com> References: <20220322080710.51727-1-gshan@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This supports SDEI_EVENT_GET_INFO hypercall. It's used by the guest to retrieve various information about the exposed or registered event, including type, signaled, routing mode and affinity. The routing mode and affinity information is only valid to the shared and registered event. Signed-off-by: Gavin Shan --- arch/arm64/kvm/sdei.c | 73 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/arch/arm64/kvm/sdei.c b/arch/arm64/kvm/sdei.c index 5c43c8912ea1..4f26e5f70bff 100644 --- a/arch/arm64/kvm/sdei.c +++ b/arch/arm64/kvm/sdei.c @@ -494,6 +494,77 @@ static unsigned long hypercall_status(struct kvm_vcpu = *vcpu) return ret; } =20 +static unsigned long hypercall_info(struct kvm_vcpu *vcpu) +{ + struct kvm *kvm =3D vcpu->kvm; + struct kvm_sdei_kvm *ksdei =3D kvm->arch.sdei; + struct kvm_sdei_exposed_event *exposed_event =3D NULL; + struct kvm_sdei_registered_event *registered_event =3D NULL; + unsigned long event_num =3D smccc_get_arg1(vcpu); + unsigned long event_info =3D smccc_get_arg2(vcpu); + int index; + unsigned long ret =3D SDEI_SUCCESS; + + if (!kvm_sdei_is_supported(event_num)) { + ret =3D SDEI_INVALID_PARAMETERS; + goto out; + } + + spin_lock(&ksdei->lock); + + /* + * Retrieve the information from the registered event if it exists. + * Otherwise, we turn into the exposed event if needed. + */ + registered_event =3D find_registered_event(kvm, event_num); + exposed_event =3D registered_event ? registered_event->exposed_event : + find_exposed_event(kvm, event_num); + if (!exposed_event) { + ret =3D SDEI_INVALID_PARAMETERS; + goto unlock; + } + + /* Retrieve the requested information */ + switch (event_info) { + case SDEI_EVENT_INFO_EV_TYPE: + ret =3D exposed_event->state.type; + break; + case SDEI_EVENT_INFO_EV_SIGNALED: + ret =3D exposed_event->state.signaled; + break; + case SDEI_EVENT_INFO_EV_PRIORITY: + ret =3D exposed_event->state.priority; + break; + case SDEI_EVENT_INFO_EV_ROUTING_MODE: + case SDEI_EVENT_INFO_EV_ROUTING_AFF: + if (!kvm_sdei_is_shared(exposed_event->state.type)) { + ret =3D SDEI_INVALID_PARAMETERS; + break; + } + + index =3D kvm_sdei_vcpu_index(vcpu, exposed_event); + if (!registered_event || + !kvm_sdei_is_registered(registered_event, index)) { + ret =3D SDEI_DENIED; + break; + } + + if (event_info =3D=3D SDEI_EVENT_INFO_EV_ROUTING_MODE) + ret =3D registered_event->state.route_mode; + else + ret =3D registered_event->state.route_affinity; + + break; + default: + ret =3D SDEI_INVALID_PARAMETERS; + } + +unlock: + spin_unlock(&ksdei->lock); +out: + return ret; +} + int kvm_sdei_hypercall(struct kvm_vcpu *vcpu) { struct kvm *kvm =3D vcpu->kvm; @@ -543,6 +614,8 @@ int kvm_sdei_hypercall(struct kvm_vcpu *vcpu) ret =3D hypercall_status(vcpu); break; case SDEI_1_0_FN_SDEI_EVENT_GET_INFO: + ret =3D hypercall_info(vcpu); + break; case SDEI_1_0_FN_SDEI_EVENT_ROUTING_SET: case SDEI_1_0_FN_SDEI_PE_MASK: case SDEI_1_0_FN_SDEI_PE_UNMASK: --=20 2.23.0 From nobody Mon Jun 22 14:25:00 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AAE91C433EF for ; Tue, 22 Mar 2022 08:09:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230154AbiCVILE (ORCPT ); Tue, 22 Mar 2022 04:11:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55720 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230090AbiCVIKv (ORCPT ); Tue, 22 Mar 2022 04:10:51 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 5958D60EB for ; Tue, 22 Mar 2022 01:09:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1647936554; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=MDMpbl/XXWJVxRKGa6DuNkU1Ki68AS56WQu7ISeC4wY=; b=AKjro7zkW2wRqr0kC++yEuKv8/0VDv/0yi24Gqwfu/6rVDtYMo7DCmZBaop+TuDX1x/1AM WSINxP3Juh/cXPqJ4FeS1K8u+0cleShAfM/GIuZkVCMNHZgrbNixV8sGI+BEWrvi28YFWC OzfMKLRWlo57RmdXOeNlygIeTX08hMs= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-465-dnfIR7HYP1mBixtvi6tvFA-1; Tue, 22 Mar 2022 04:09:11 -0400 X-MC-Unique: dnfIR7HYP1mBixtvi6tvFA-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id A093D1044566; Tue, 22 Mar 2022 08:09:10 +0000 (UTC) Received: from gshan.redhat.com (ovpn-12-33.pek2.redhat.com [10.72.12.33]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 244501121324; Tue, 22 Mar 2022 08:09:04 +0000 (UTC) From: Gavin Shan To: kvmarm@lists.cs.columbia.edu Cc: linux-kernel@vger.kernel.org, eauger@redhat.com, shannon.zhaosl@gmail.com, maz@kernel.org, Jonathan.Cameron@huawei.com, will@kernel.org, pbonzini@redhat.com, james.morse@arm.com, mark.rutland@arm.com, drjones@redhat.com, vkuznets@redhat.com, shan.gavin@gmail.com Subject: [PATCH v5 10/22] KVM: arm64: Support SDEI_EVENT_ROUTING_SET hypercall Date: Tue, 22 Mar 2022 16:06:58 +0800 Message-Id: <20220322080710.51727-11-gshan@redhat.com> In-Reply-To: <20220322080710.51727-1-gshan@redhat.com> References: <20220322080710.51727-1-gshan@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This supports SDEI_EVENT_ROUTING_SET hypercall. It's used by the guest to set route mode and affinity for the shared and registered events. The request to configure the routing mode and affinity for the private events are disallowed. Besides, It's not allowed to do when the corresponding vCPU events are existing. Signed-off-by: Gavin Shan --- arch/arm64/kvm/sdei.c | 62 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/arch/arm64/kvm/sdei.c b/arch/arm64/kvm/sdei.c index 4f26e5f70bff..db82ea441eae 100644 --- a/arch/arm64/kvm/sdei.c +++ b/arch/arm64/kvm/sdei.c @@ -565,6 +565,66 @@ static unsigned long hypercall_info(struct kvm_vcpu *v= cpu) return ret; } =20 +static unsigned long hypercall_route(struct kvm_vcpu *vcpu) +{ + struct kvm *kvm =3D vcpu->kvm; + struct kvm_sdei_kvm *ksdei =3D kvm->arch.sdei; + struct kvm_sdei_exposed_event *exposed_event; + struct kvm_sdei_registered_event *registered_event; + unsigned long event_num =3D smccc_get_arg1(vcpu); + unsigned long route_mode =3D smccc_get_arg2(vcpu); + unsigned long route_affinity =3D smccc_get_arg3(vcpu); + int index =3D 0; + unsigned long ret =3D SDEI_SUCCESS; + + if (!kvm_sdei_is_supported(event_num)) { + ret =3D SDEI_INVALID_PARAMETERS; + goto out; + } + + /* + * FIXME: The affinity should be verified when it's supported. We + * accept anything for now. + */ + if (route_mode !=3D SDEI_EVENT_REGISTER_RM_ANY && + route_mode !=3D SDEI_EVENT_REGISTER_RM_PE) { + ret =3D SDEI_INVALID_PARAMETERS; + goto out; + } + + spin_lock(&ksdei->lock); + + /* Check if the registered event exists */ + registered_event =3D find_registered_event(kvm, event_num); + if (!registered_event) { + ret =3D SDEI_INVALID_PARAMETERS; + goto unlock; + } + + /* Check the registered event is a shared one */ + exposed_event =3D registered_event->exposed_event; + if (!kvm_sdei_is_shared(exposed_event->state.type)) { + ret =3D SDEI_DENIED; + goto unlock; + } + + if (!kvm_sdei_is_registered(registered_event, index) || + kvm_sdei_is_enabled(registered_event, index) || + registered_event->vcpu_event_count > 0) { + ret =3D SDEI_DENIED; + goto unlock; + } + + /* Update the registered event state */ + registered_event->state.route_mode =3D route_mode; + registered_event->state.route_affinity =3D route_affinity; + +unlock: + spin_unlock(&ksdei->lock); +out: + return ret; +} + int kvm_sdei_hypercall(struct kvm_vcpu *vcpu) { struct kvm *kvm =3D vcpu->kvm; @@ -617,6 +677,8 @@ int kvm_sdei_hypercall(struct kvm_vcpu *vcpu) ret =3D hypercall_info(vcpu); break; case SDEI_1_0_FN_SDEI_EVENT_ROUTING_SET: + ret =3D hypercall_route(vcpu); + break; case SDEI_1_0_FN_SDEI_PE_MASK: case SDEI_1_0_FN_SDEI_PE_UNMASK: case SDEI_1_0_FN_SDEI_INTERRUPT_BIND: --=20 2.23.0 From nobody Mon Jun 22 14:25:00 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id ED100C433EF for ; Tue, 22 Mar 2022 08:09:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230021AbiCVILS (ORCPT ); Tue, 22 Mar 2022 04:11:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56618 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229925AbiCVILN (ORCPT ); Tue, 22 Mar 2022 04:11:13 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id C593A24BCF for ; Tue, 22 Mar 2022 01:09:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1647936577; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=gltiXYOSEEjNUqLYmzcduTiT7DayTJW8FdFdmgcfQdQ=; b=Qlhkp5N7pnoK6QmXIx33LHIeZTB4dZRGIL477PRRpuT/xMxRg/CbsEn9LUc+cVCYV9RGNV sdcqFIUY8Nr5ylNFRQ+mhatunR1nKZFutpm3CMYMjiBKbMYxGOpaQUcF50H+X+MDHAj89Q OuXFsp/gRc2b8PSk9NzYlDFVs+zyfOA= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-651-Q090hviFPbuszSirU_DsBQ-1; Tue, 22 Mar 2022 04:09:34 -0400 X-MC-Unique: Q090hviFPbuszSirU_DsBQ-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 96E4C185A794; Tue, 22 Mar 2022 08:09:33 +0000 (UTC) Received: from gshan.redhat.com (ovpn-12-33.pek2.redhat.com [10.72.12.33]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 5ED681121324; Tue, 22 Mar 2022 08:09:11 +0000 (UTC) From: Gavin Shan To: kvmarm@lists.cs.columbia.edu Cc: linux-kernel@vger.kernel.org, eauger@redhat.com, shannon.zhaosl@gmail.com, maz@kernel.org, Jonathan.Cameron@huawei.com, will@kernel.org, pbonzini@redhat.com, james.morse@arm.com, mark.rutland@arm.com, drjones@redhat.com, vkuznets@redhat.com, shan.gavin@gmail.com Subject: [PATCH v5 11/22] KVM: arm64: Support SDEI_PE_{MASK, UNMASK} hypercall Date: Tue, 22 Mar 2022 16:06:59 +0800 Message-Id: <20220322080710.51727-12-gshan@redhat.com> In-Reply-To: <20220322080710.51727-1-gshan@redhat.com> References: <20220322080710.51727-1-gshan@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This supports SDEI_PE_{MASK, UNMASK} hypercall. They are used by the guest to stop or start receiving SDEI event on the specified vCPU. Signed-off-by: Gavin Shan --- arch/arm64/kvm/sdei.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/arm64/kvm/sdei.c b/arch/arm64/kvm/sdei.c index db82ea441eae..b2a916724cfa 100644 --- a/arch/arm64/kvm/sdei.c +++ b/arch/arm64/kvm/sdei.c @@ -625,6 +625,18 @@ static unsigned long hypercall_route(struct kvm_vcpu *= vcpu) return ret; } =20 +static unsigned long hypercall_mask(struct kvm_vcpu *vcpu, bool mask) +{ + struct kvm_sdei_vcpu *vsdei =3D vcpu->arch.sdei; + unsigned long ret =3D SDEI_SUCCESS; + + spin_lock(&vsdei->lock); + vsdei->state.masked =3D mask ? 1 : 0; + spin_unlock(&vsdei->lock); + + return ret; +} + int kvm_sdei_hypercall(struct kvm_vcpu *vcpu) { struct kvm *kvm =3D vcpu->kvm; @@ -680,7 +692,11 @@ int kvm_sdei_hypercall(struct kvm_vcpu *vcpu) ret =3D hypercall_route(vcpu); break; case SDEI_1_0_FN_SDEI_PE_MASK: + ret =3D hypercall_mask(vcpu, true); + break; case SDEI_1_0_FN_SDEI_PE_UNMASK: + ret =3D hypercall_mask(vcpu, false); + break; case SDEI_1_0_FN_SDEI_INTERRUPT_BIND: case SDEI_1_0_FN_SDEI_INTERRUPT_RELEASE: case SDEI_1_1_FN_SDEI_EVENT_SIGNAL: --=20 2.23.0 From nobody Mon Jun 22 14:25:00 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5ACCDC433F5 for ; Tue, 22 Mar 2022 08:09:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230083AbiCVILX (ORCPT ); Tue, 22 Mar 2022 04:11:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55872 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229995AbiCVILQ (ORCPT ); Tue, 22 Mar 2022 04:11:16 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 0308BB7EB for ; Tue, 22 Mar 2022 01:09:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1647936587; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=KDBG9hheIqOVlljCf2sb5fT6Csq9yFBt9fZvXIcLh5A=; b=LFYC2VGEFThpNRS6KuFWp2LDatyHp/mIWZdo9tv+ZBCIaAqheRwi7v+gkAdolWYmSq0Lly 5y+dpDLjUtBUZQn8qqAFZ3Ox5HfFxrjFClexzngv0g4fB77Zd+m+zh6tEqjKcBqfV0kUjr t9zGP2gwQhGsrsMfURr3cvbiGSzBdi8= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-19-fw8RiBStPEioOqaJUno_BA-1; Tue, 22 Mar 2022 04:09:43 -0400 X-MC-Unique: fw8RiBStPEioOqaJUno_BA-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 4B6FB85A5BC; Tue, 22 Mar 2022 08:09:43 +0000 (UTC) Received: from gshan.redhat.com (ovpn-12-33.pek2.redhat.com [10.72.12.33]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 5D33F1121324; Tue, 22 Mar 2022 08:09:33 +0000 (UTC) From: Gavin Shan To: kvmarm@lists.cs.columbia.edu Cc: linux-kernel@vger.kernel.org, eauger@redhat.com, shannon.zhaosl@gmail.com, maz@kernel.org, Jonathan.Cameron@huawei.com, will@kernel.org, pbonzini@redhat.com, james.morse@arm.com, mark.rutland@arm.com, drjones@redhat.com, vkuznets@redhat.com, shan.gavin@gmail.com Subject: [PATCH v5 12/22] KVM: arm64: Support SDEI_{PRIVATE, SHARED}_RESET Date: Tue, 22 Mar 2022 16:07:00 +0800 Message-Id: <20220322080710.51727-13-gshan@redhat.com> In-Reply-To: <20220322080710.51727-1-gshan@redhat.com> References: <20220322080710.51727-1-gshan@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This supports SDEI_{PRIVATE, SHARED}_RESET. They are used by the guest to reset the private events on the calling vCPU or the shared events on all vCPUs. Signed-off-by: Gavin Shan --- arch/arm64/kvm/sdei.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/arch/arm64/kvm/sdei.c b/arch/arm64/kvm/sdei.c index b2a916724cfa..0dec35a0eed1 100644 --- a/arch/arm64/kvm/sdei.c +++ b/arch/arm64/kvm/sdei.c @@ -637,6 +637,31 @@ static unsigned long hypercall_mask(struct kvm_vcpu *v= cpu, bool mask) return ret; } =20 +static unsigned long hypercall_reset(struct kvm_vcpu *vcpu, bool private) +{ + struct kvm *kvm =3D vcpu->kvm; + struct kvm_sdei_kvm *ksdei =3D kvm->arch.sdei; + struct kvm_sdei_exposed_event *exposed_event; + struct kvm_sdei_registered_event *registered_event, *tmp; + unsigned long r, ret =3D SDEI_SUCCESS; + + spin_lock(&ksdei->lock); + + list_for_each_entry_safe(registered_event, tmp, + &ksdei->registered_events, link) { + exposed_event =3D registered_event->exposed_event; + if (private ^ kvm_sdei_is_shared(exposed_event->state.type)) + continue; + + r =3D unregister_one_event(kvm, NULL, registered_event); + ret =3D (r =3D=3D SDEI_SUCCESS) ? ret : r; + } + + spin_unlock(&ksdei->lock); + + return ret; +} + int kvm_sdei_hypercall(struct kvm_vcpu *vcpu) { struct kvm *kvm =3D vcpu->kvm; @@ -700,8 +725,14 @@ int kvm_sdei_hypercall(struct kvm_vcpu *vcpu) case SDEI_1_0_FN_SDEI_INTERRUPT_BIND: case SDEI_1_0_FN_SDEI_INTERRUPT_RELEASE: case SDEI_1_1_FN_SDEI_EVENT_SIGNAL: + ret =3D SDEI_NOT_SUPPORTED; + break; case SDEI_1_0_FN_SDEI_PRIVATE_RESET: + ret =3D hypercall_reset(vcpu, true); + break; case SDEI_1_0_FN_SDEI_SHARED_RESET: + ret =3D hypercall_reset(vcpu, false); + break; case SDEI_1_1_FN_SDEI_FEATURES: default: ret =3D SDEI_NOT_SUPPORTED; --=20 2.23.0 From nobody Mon Jun 22 14:25:00 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AC7B4C433FE for ; Tue, 22 Mar 2022 08:10:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229982AbiCVILb (ORCPT ); Tue, 22 Mar 2022 04:11:31 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55872 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230088AbiCVILX (ORCPT ); Tue, 22 Mar 2022 04:11:23 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 1821317AA8 for ; Tue, 22 Mar 2022 01:09:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1647936595; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=tBV53gfAtLB3fP5o321O7+SQMgvVIUsp841j85CAZrU=; b=eOdwpFvM2V3JnEHZiQILgYKXqmYOU+tZ/CWebpL2kZjtaEpJUDzYL0VJOcvJAPKM14S79L gVYanVU5BUcxUBWbGkCHgm6uGbh6HJtq8QgxhQgiRZK3qnmnN9F1oeRjRSNeiNkoSrEHMZ k+RFxVlIBy2HO2nSlbg7MBIGBCJJ8oc= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-446-PO0S3A_wOziZB4dY8nXkWw-1; Tue, 22 Mar 2022 04:09:52 -0400 X-MC-Unique: PO0S3A_wOziZB4dY8nXkWw-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 47F80899EC4; Tue, 22 Mar 2022 08:09:51 +0000 (UTC) Received: from gshan.redhat.com (ovpn-12-33.pek2.redhat.com [10.72.12.33]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 1A89D1121324; Tue, 22 Mar 2022 08:09:43 +0000 (UTC) From: Gavin Shan To: kvmarm@lists.cs.columbia.edu Cc: linux-kernel@vger.kernel.org, eauger@redhat.com, shannon.zhaosl@gmail.com, maz@kernel.org, Jonathan.Cameron@huawei.com, will@kernel.org, pbonzini@redhat.com, james.morse@arm.com, mark.rutland@arm.com, drjones@redhat.com, vkuznets@redhat.com, shan.gavin@gmail.com Subject: [PATCH v5 13/22] KVM: arm64: Support SDEI_FEATURES hypercall Date: Tue, 22 Mar 2022 16:07:01 +0800 Message-Id: <20220322080710.51727-14-gshan@redhat.com> In-Reply-To: <20220322080710.51727-1-gshan@redhat.com> References: <20220322080710.51727-1-gshan@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This supports SDEI_FEATURES hypercall. It's used by the guest to retrieve the supported features, which are number of binding slots and relative mode for the event handler. Currently, none of them is supported. Signed-off-by: Gavin Shan --- arch/arm64/kvm/sdei.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/arm64/kvm/sdei.c b/arch/arm64/kvm/sdei.c index 0dec35a0eed1..1e0ca9022eaa 100644 --- a/arch/arm64/kvm/sdei.c +++ b/arch/arm64/kvm/sdei.c @@ -662,6 +662,20 @@ static unsigned long hypercall_reset(struct kvm_vcpu *= vcpu, bool private) return ret; } =20 +static unsigned long hypercall_features(struct kvm_vcpu *vcpu) +{ + unsigned long feature =3D smccc_get_arg1(vcpu); + + switch (feature) { + case 0: /* BIND_SLOTS */ + return 0; + case 1: /* RELATIVE_MODE */ + return 0; + } + + return SDEI_INVALID_PARAMETERS; +} + int kvm_sdei_hypercall(struct kvm_vcpu *vcpu) { struct kvm *kvm =3D vcpu->kvm; @@ -734,6 +748,8 @@ int kvm_sdei_hypercall(struct kvm_vcpu *vcpu) ret =3D hypercall_reset(vcpu, false); break; case SDEI_1_1_FN_SDEI_FEATURES: + ret =3D hypercall_features(vcpu); + break; default: ret =3D SDEI_NOT_SUPPORTED; } --=20 2.23.0 From nobody Mon Jun 22 14:25:00 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A714DC433EF for ; Tue, 22 Mar 2022 08:10:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230085AbiCVILo (ORCPT ); Tue, 22 Mar 2022 04:11:44 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59702 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229974AbiCVILb (ORCPT ); Tue, 22 Mar 2022 04:11:31 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 56D451BEB3 for ; Tue, 22 Mar 2022 01:10:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1647936602; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=oDLPhdNil8yIekdEaTNLezmS6s9ralEFlQuei0yDjLk=; b=XJU7Iktwa7ytc9/pELkWAHmT+qY8u9S3e6kv4NcIHiw3BO6PpguK8AaF7GkL4KGLrF/ADZ 51YAThjBeT7QhXg81+5PoJuV60DGrEw/qHIo0d4noedtafxeLOUxNp9xaXQlVlujPDUf7b 7WvSVUeH4pxF3ILT+eJlHg71itEJMBs= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-292-mY_uTFJ6PLWkyTLln4adnw-1; Tue, 22 Mar 2022 04:09:58 -0400 X-MC-Unique: mY_uTFJ6PLWkyTLln4adnw-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id E8331801585; Tue, 22 Mar 2022 08:09:57 +0000 (UTC) Received: from gshan.redhat.com (ovpn-12-33.pek2.redhat.com [10.72.12.33]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 177A81121324; Tue, 22 Mar 2022 08:09:51 +0000 (UTC) From: Gavin Shan To: kvmarm@lists.cs.columbia.edu Cc: linux-kernel@vger.kernel.org, eauger@redhat.com, shannon.zhaosl@gmail.com, maz@kernel.org, Jonathan.Cameron@huawei.com, will@kernel.org, pbonzini@redhat.com, james.morse@arm.com, mark.rutland@arm.com, drjones@redhat.com, vkuznets@redhat.com, shan.gavin@gmail.com Subject: [PATCH v5 14/22] KVM: arm64: Support SDEI event injection, delivery and cancellation Date: Tue, 22 Mar 2022 16:07:02 +0800 Message-Id: <20220322080710.51727-15-gshan@redhat.com> In-Reply-To: <20220322080710.51727-1-gshan@redhat.com> References: <20220322080710.51727-1-gshan@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This supports SDEI event injection, delivery and cancellation. The SDEI event is injected by kvm_sdei_inject_event(). The injected event can be cancelled by kvm_sdei_cancel_event() before it's delivered and handled. KVM_REQ_SDEI request becomes pending once the SDEI event is injected and kvm_sdei_deliver_event() is called to accommodate the request. The injected SDEI event is delivered and handled in this way. The context for execution is switched like below: * x0 - x17 are saved. All of them are cleared except the following registers: x0: SDEI event number x1: user argument associated with the SDEI event x2: PC of the interrupted or preempted context x3: PSTATE of the interrupted or preempted context * PC is set to the handler of the SDEI event, which was provided during its registration. PSTATE is modified according to the SDEI specification. * The SDEI event with normal priority can be preempted by that with critical priority. However, no one can preempt the SDEI event with critical event. Signed-off-by: Gavin Shan --- arch/arm64/include/asm/kvm_host.h | 1 + arch/arm64/include/asm/kvm_sdei.h | 4 + arch/arm64/kvm/arm.c | 3 + arch/arm64/kvm/sdei.c | 284 ++++++++++++++++++++++++++++++ 4 files changed, 292 insertions(+) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm= _host.h index 5d37e046a458..e2762d08ab1c 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -46,6 +46,7 @@ #define KVM_REQ_RECORD_STEAL KVM_ARCH_REQ(3) #define KVM_REQ_RELOAD_GICv4 KVM_ARCH_REQ(4) #define KVM_REQ_RELOAD_PMU KVM_ARCH_REQ(5) +#define KVM_REQ_SDEI KVM_ARCH_REQ(6) =20 #define KVM_DIRTY_LOG_MANUAL_CAPS (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE |= \ KVM_DIRTY_LOG_INITIALLY_SET) diff --git a/arch/arm64/include/asm/kvm_sdei.h b/arch/arm64/include/asm/kvm= _sdei.h index 6f58a846d05c..54c730acd298 100644 --- a/arch/arm64/include/asm/kvm_sdei.h +++ b/arch/arm64/include/asm/kvm_sdei.h @@ -165,6 +165,10 @@ KVM_SDEI_REGISTERED_EVENT_FUNC(unregister_pending) void kvm_sdei_init_vm(struct kvm *kvm); void kvm_sdei_create_vcpu(struct kvm_vcpu *vcpu); int kvm_sdei_hypercall(struct kvm_vcpu *vcpu); +int kvm_sdei_inject_event(struct kvm_vcpu *vcpu, + unsigned long num, bool immediate); +int kvm_sdei_cancel_event(struct kvm_vcpu *vcpu, unsigned long num); +void kvm_sdei_deliver_event(struct kvm_vcpu *vcpu); void kvm_sdei_destroy_vcpu(struct kvm_vcpu *vcpu); void kvm_sdei_destroy_vm(struct kvm *kvm); =20 diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 96fcae5beee4..00c136a6e8df 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -734,6 +734,9 @@ static void check_vcpu_requests(struct kvm_vcpu *vcpu) if (kvm_check_request(KVM_REQ_VCPU_RESET, vcpu)) kvm_reset_vcpu(vcpu); =20 + if (kvm_check_request(KVM_REQ_SDEI, vcpu)) + kvm_sdei_deliver_event(vcpu); + /* * Clear IRQ_PENDING requests that were made to guarantee * that a VCPU sees new virtual interrupts. diff --git a/arch/arm64/kvm/sdei.c b/arch/arm64/kvm/sdei.c index 1e0ca9022eaa..a24270378305 100644 --- a/arch/arm64/kvm/sdei.c +++ b/arch/arm64/kvm/sdei.c @@ -43,6 +43,25 @@ find_registered_event(struct kvm *kvm, unsigned long num) return NULL; } =20 +static struct kvm_sdei_vcpu_event * +find_vcpu_event(struct kvm_vcpu *vcpu, unsigned long num) +{ + struct kvm_sdei_vcpu *vsdei =3D vcpu->arch.sdei; + struct kvm_sdei_vcpu_event *vcpu_event; + + list_for_each_entry(vcpu_event, &vsdei->critical_events, link) { + if (vcpu_event->state.num =3D=3D num) + return vcpu_event; + } + + list_for_each_entry(vcpu_event, &vsdei->normal_events, link) { + if (vcpu_event->state.num =3D=3D num) + return vcpu_event; + } + + return NULL; +} + static void remove_all_exposed_events(struct kvm *kvm) { struct kvm_sdei_kvm *ksdei =3D kvm->arch.sdei; @@ -637,6 +656,76 @@ static unsigned long hypercall_mask(struct kvm_vcpu *v= cpu, bool mask) return ret; } =20 +static int do_inject_event(struct kvm_vcpu *vcpu, + struct kvm_sdei_registered_event *registered_event, + bool immediate) +{ + struct kvm_sdei_vcpu *vsdei =3D vcpu->arch.sdei; + struct kvm_sdei_exposed_event *exposed_event; + struct kvm_sdei_vcpu_event *vcpu_event; + unsigned int vcpu_event_count; + + /* + * In some cases, the injected event is expected to be delivered + * immediately. However, there are two cases the injected event + * can't be delivered immediately: (a) the injected event is a + * critical one, but we already have pending critical events for + * delivery. (b) the injected event is a normal one, but we have + * pending events for delivery, regardless of their priorities. + */ + exposed_event =3D registered_event->exposed_event; + if (immediate) { + vcpu_event_count =3D vsdei->critical_event_count; + if (kvm_sdei_is_normal(exposed_event->state.priority)) + vcpu_event_count +=3D vsdei->normal_event_count; + + if (vcpu_event_count > 0) + return -ENOSPC; + } + + /* Check if the vcpu event exists */ + vcpu_event =3D find_vcpu_event(vcpu, registered_event->state.num); + if (vcpu_event) { + vcpu_event->state.event_count++; + kvm_make_request(KVM_REQ_SDEI, vcpu); + return 0; + } + + /* Check if the count of vcpu event instances exceeds the limit */ + vcpu_event_count =3D vsdei->critical_event_count + + vsdei->normal_event_count; + if (vcpu_event_count >=3D KVM_SDEI_MAX_EVENTS) + return -ERANGE; + + /* Allocate the vcpu event */ + vcpu_event =3D kzalloc(sizeof(*vcpu_event), GFP_KERNEL_ACCOUNT); + if (!vcpu_event) + return -ENOMEM; + + /* + * We should take lock to update the registered event because its + * reference count might be zero. In that case, the registered event + * could be released. + */ + vcpu_event->state.num =3D registered_event->state.num; + vcpu_event->state.event_count =3D 1; + vcpu_event->vcpu =3D vcpu; + vcpu_event->registered_event =3D registered_event; + + registered_event->vcpu_event_count++; + if (kvm_sdei_is_critical(exposed_event->state.priority)) { + list_add_tail(&vcpu_event->link, &vsdei->critical_events); + vsdei->critical_event_count++; + } else { + list_add_tail(&vcpu_event->link, &vsdei->normal_events); + vsdei->normal_event_count++; + } + + kvm_make_request(KVM_REQ_SDEI, vcpu); + + return 0; +} + static unsigned long hypercall_reset(struct kvm_vcpu *vcpu, bool private) { struct kvm *kvm =3D vcpu->kvm; @@ -761,6 +850,201 @@ int kvm_sdei_hypercall(struct kvm_vcpu *vcpu) return 1; } =20 +int kvm_sdei_inject_event(struct kvm_vcpu *vcpu, + unsigned long num, + bool immediate) +{ + struct kvm *kvm =3D vcpu->kvm; + struct kvm_sdei_kvm *ksdei =3D kvm->arch.sdei; + struct kvm_sdei_vcpu *vsdei =3D vcpu->arch.sdei; + struct kvm_sdei_exposed_event *exposed_event =3D NULL; + struct kvm_sdei_registered_event *registered_event =3D NULL; + int index, ret =3D 0; + + if (!(ksdei && vsdei)) { + ret =3D -EPERM; + goto out; + } + + if (!kvm_sdei_is_supported(num)) { + ret =3D -EINVAL; + goto out; + } + + spin_lock(&ksdei->lock); + + /* Check if the registered event exists */ + registered_event =3D find_registered_event(kvm, num); + if (!registered_event) { + ret =3D -ENOENT; + goto unlock_kvm; + } + + /* Check if the event has been registered and enabled */ + exposed_event =3D registered_event->exposed_event; + index =3D kvm_sdei_vcpu_index(vcpu, exposed_event); + if (!kvm_sdei_is_registered(registered_event, index) || + !kvm_sdei_is_enabled(registered_event, index) || + kvm_sdei_is_unregister_pending(registered_event, index)) { + ret =3D -EPERM; + goto unlock_kvm; + } + + /* Check if the vcpu has been masked off */ + spin_lock(&vsdei->lock); + if (vsdei->state.masked) { + ret =3D -EPERM; + goto unlock_vcpu; + } + + /* Inject the event */ + ret =3D do_inject_event(vcpu, registered_event, immediate); + +unlock_vcpu: + spin_unlock(&vsdei->lock); +unlock_kvm: + spin_unlock(&ksdei->lock); +out: + return ret; +} + +int kvm_sdei_cancel_event(struct kvm_vcpu *vcpu, unsigned long num) +{ + struct kvm *kvm =3D vcpu->kvm; + struct kvm_sdei_kvm *ksdei =3D kvm->arch.sdei; + struct kvm_sdei_vcpu *vsdei =3D vcpu->arch.sdei; + struct kvm_sdei_exposed_event *exposed_event =3D NULL; + struct kvm_sdei_registered_event *registered_event =3D NULL; + struct kvm_sdei_vcpu_event *vcpu_event =3D NULL; + int ret =3D 0; + + if (!(ksdei && vsdei)) { + ret =3D -EPERM; + goto out; + } + + spin_lock(&ksdei->lock); + spin_lock(&vsdei->lock); + + /* Find the vcpu event */ + vcpu_event =3D find_vcpu_event(vcpu, num); + if (!vcpu_event) { + ret =3D -EINVAL; + goto unlock; + } + + /* We can't cancel the event if it has been delivered */ + if (vcpu_event->state.event_count <=3D 1 && + (vsdei->critical_event =3D=3D vcpu_event || + vsdei->normal_event =3D=3D vcpu_event)) { + ret =3D -EINPROGRESS; + goto unlock; + } + + /* Destroy the vcpu event instance if needed */ + registered_event =3D vcpu_event->registered_event; + exposed_event =3D registered_event->exposed_event; + vcpu_event->state.event_count--; + if (!vcpu_event->state.event_count) + remove_one_vcpu_event(vcpu, vcpu_event); + +unlock: + spin_unlock(&vsdei->lock); + spin_unlock(&ksdei->lock); +out: + return ret; +} + +void kvm_sdei_deliver_event(struct kvm_vcpu *vcpu) +{ + struct kvm *kvm =3D vcpu->kvm; + struct kvm_sdei_kvm *ksdei =3D kvm->arch.sdei; + struct kvm_sdei_vcpu *vsdei =3D vcpu->arch.sdei; + struct kvm_sdei_exposed_event *exposed_event; + struct kvm_sdei_registered_event *registered_event; + struct kvm_sdei_vcpu_event *vcpu_event; + struct kvm_sdei_vcpu_regs_state *regs; + unsigned long pstate; + int index; + + if (!(ksdei && vsdei)) + return; + + spin_lock(&vsdei->lock); + + /* The critical event can't be preempted */ + if (vsdei->critical_event) + goto unlock; + + /* + * The normal event can be preempted by the critical event. + * However, the normal event can't be preempted by another + * normal event. + */ + vcpu_event =3D list_first_entry_or_null(&vsdei->critical_events, + struct kvm_sdei_vcpu_event, link); + if (!vcpu_event && !vsdei->normal_event) { + vcpu_event =3D list_first_entry_or_null(&vsdei->normal_events, + struct kvm_sdei_vcpu_event, link); + } + + if (!vcpu_event) + goto unlock; + + registered_event =3D vcpu_event->registered_event; + exposed_event =3D registered_event->exposed_event; + if (kvm_sdei_is_critical(exposed_event->state.priority)) { + vsdei->critical_event =3D vcpu_event; + vsdei->state.critical_num =3D vcpu_event->state.num; + regs =3D &vsdei->state.critical_regs; + } else { + vsdei->normal_event =3D vcpu_event; + vsdei->state.normal_num =3D vcpu_event->state.num; + regs =3D &vsdei->state.normal_regs; + } + + /* + * Save registers: x0 -> x17, PC, PState. There might be pending + * exception or PC increment request in the last run on this vCPU. + * In this case, we need to save the site in advance. Otherwise, + * the passed entry point could be floated by 4 bytes in the + * subsequent call to __kvm_adjust_pc(). + */ + __kvm_adjust_pc(vcpu); + for (index =3D 0; index < ARRAY_SIZE(regs->regs); index++) + regs->regs[index] =3D vcpu_get_reg(vcpu, index); + + regs->pc =3D *vcpu_pc(vcpu); + regs->pstate =3D *vcpu_cpsr(vcpu); + + /* + * Inject SDEI event: x0 -> x3, PC, PState. We needn't take lock + * for the registered event as it can't be released because of + * its reference count. + */ + for (index =3D 0; index < ARRAY_SIZE(regs->regs); index++) + vcpu_set_reg(vcpu, index, 0); + + index =3D kvm_sdei_vcpu_index(vcpu, exposed_event); + vcpu_set_reg(vcpu, 0, registered_event->state.num); + vcpu_set_reg(vcpu, 1, registered_event->state.ep_arg[index]); + vcpu_set_reg(vcpu, 2, regs->pc); + vcpu_set_reg(vcpu, 3, regs->pstate); + + pstate =3D regs->pstate; + pstate |=3D (PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT); + pstate &=3D ~PSR_MODE_MASK; + pstate |=3D PSR_MODE_EL1h; + pstate &=3D ~PSR_MODE32_BIT; + + vcpu_write_sys_reg(vcpu, regs->pstate, SPSR_EL1); + *vcpu_cpsr(vcpu) =3D pstate; + *vcpu_pc(vcpu) =3D registered_event->state.ep_address[index]; + +unlock: + spin_unlock(&vsdei->lock); +} + void kvm_sdei_init_vm(struct kvm *kvm) { struct kvm_sdei_kvm *ksdei; --=20 2.23.0 From nobody Mon Jun 22 14:25:00 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3A6CFC433F5 for ; Tue, 22 Mar 2022 08:10:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230095AbiCVILv (ORCPT ); Tue, 22 Mar 2022 04:11:51 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33076 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230135AbiCVILs (ORCPT ); Tue, 22 Mar 2022 04:11:48 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 7FFC21A839 for ; Tue, 22 Mar 2022 01:10:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1647936613; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=npnSDsjzzEy3QMCifPgGVfzBgN0vFmIBHdTnsx69Pjw=; b=VXa8DDS5hND5ZBWk66+gq3WPQacDElJJ4X697qFd1Or+4djaQstNC6DYSUBaLzutIXVRtZ tVu4AxfJkSaoU1tKAMFctwqIshDgRuysgl/4PP8YI5fO+XYEtU6iU5b+XwIPuOwc7KwqAV u2v8N105Pqt/LsviLR9Mz9jaQfeRSIM= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-60-RkZBMxGnOUOEPHCQHC-T7w-1; Tue, 22 Mar 2022 04:10:10 -0400 X-MC-Unique: RkZBMxGnOUOEPHCQHC-T7w-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id ABC63811E75; Tue, 22 Mar 2022 08:10:09 +0000 (UTC) Received: from gshan.redhat.com (ovpn-12-33.pek2.redhat.com [10.72.12.33]) by smtp.corp.redhat.com (Postfix) with ESMTPS id A9A461121324; Tue, 22 Mar 2022 08:09:58 +0000 (UTC) From: Gavin Shan To: kvmarm@lists.cs.columbia.edu Cc: linux-kernel@vger.kernel.org, eauger@redhat.com, shannon.zhaosl@gmail.com, maz@kernel.org, Jonathan.Cameron@huawei.com, will@kernel.org, pbonzini@redhat.com, james.morse@arm.com, mark.rutland@arm.com, drjones@redhat.com, vkuznets@redhat.com, shan.gavin@gmail.com Subject: [PATCH v5 15/22] KVM: arm64: Support SDEI_EVENT_SIGNAL hypercall Date: Tue, 22 Mar 2022 16:07:03 +0800 Message-Id: <20220322080710.51727-16-gshan@redhat.com> In-Reply-To: <20220322080710.51727-1-gshan@redhat.com> References: <20220322080710.51727-1-gshan@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This supports SDEI_EVENT_SIGNAL hypercall. It's used by the guest to inject SDEI event, whose number must be zero to the specified vCPU. As the routing mode and affinity isn't supported yet, the calling vCPU is assumed to be the target. The SDEI event 0x0 is a private one, with normal priority. It's usually used for testing. Signed-off-by: Gavin Shan --- arch/arm64/kvm/sdei.c | 64 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/sdei.c b/arch/arm64/kvm/sdei.c index a24270378305..ba2ca65c871b 100644 --- a/arch/arm64/kvm/sdei.c +++ b/arch/arm64/kvm/sdei.c @@ -726,6 +726,66 @@ static int do_inject_event(struct kvm_vcpu *vcpu, return 0; } =20 +static unsigned long hypercall_signal(struct kvm_vcpu *vcpu) +{ + struct kvm *kvm =3D vcpu->kvm; + struct kvm_sdei_kvm *ksdei =3D kvm->arch.sdei; + struct kvm_sdei_vcpu *vsdei =3D vcpu->arch.sdei; + struct kvm_sdei_exposed_event *exposed_event; + struct kvm_sdei_registered_event *registered_event; + unsigned long event_num =3D smccc_get_arg1(vcpu); + int index; + unsigned long ret =3D SDEI_SUCCESS; + + /* @event_num must be zero */ + if (!kvm_sdei_is_default(event_num)) { + ret =3D SDEI_INVALID_PARAMETERS; + goto out; + } + + spin_lock(&ksdei->lock); + + /* Check if the registered event exists */ + registered_event =3D find_registered_event(kvm, event_num); + if (!registered_event) { + ret =3D SDEI_INVALID_PARAMETERS; + goto unlock_kvm; + } + + /* + * Check if the event has been registered and enabled. The + * @target_pe parameter isn't checked for now and the event + * is assumed to injected the current vcpu. We should fix it + * when the routing mode and affinity are supported. + */ + exposed_event =3D registered_event->exposed_event; + index =3D kvm_sdei_vcpu_index(vcpu, exposed_event); + if (!kvm_sdei_is_registered(registered_event, index) || + !kvm_sdei_is_enabled(registered_event, index) || + kvm_sdei_is_unregister_pending(registered_event, index)) { + ret =3D SDEI_INVALID_PARAMETERS; + goto unlock_kvm; + } + + /* Check if the vcpu has been masked off */ + spin_lock(&vsdei->lock); + if (vsdei->state.masked) { + ret =3D SDEI_INVALID_PARAMETERS; + goto unlock_vcpu; + } + + /* Inject the event */ + if (do_inject_event(vcpu, registered_event, false)) + ret =3D SDEI_INVALID_PARAMETERS; + +unlock_vcpu: + spin_unlock(&vsdei->lock); +unlock_kvm: + spin_unlock(&ksdei->lock); +out: + return ret; +} + static unsigned long hypercall_reset(struct kvm_vcpu *vcpu, bool private) { struct kvm *kvm =3D vcpu->kvm; @@ -827,9 +887,11 @@ int kvm_sdei_hypercall(struct kvm_vcpu *vcpu) break; case SDEI_1_0_FN_SDEI_INTERRUPT_BIND: case SDEI_1_0_FN_SDEI_INTERRUPT_RELEASE: - case SDEI_1_1_FN_SDEI_EVENT_SIGNAL: ret =3D SDEI_NOT_SUPPORTED; break; + case SDEI_1_1_FN_SDEI_EVENT_SIGNAL: + ret =3D hypercall_signal(vcpu); + break; case SDEI_1_0_FN_SDEI_PRIVATE_RESET: ret =3D hypercall_reset(vcpu, true); break; --=20 2.23.0 From nobody Mon Jun 22 14:25:00 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1F4D2C433EF for ; Tue, 22 Mar 2022 08:10:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230152AbiCVILy (ORCPT ); Tue, 22 Mar 2022 04:11:54 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33288 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230090AbiCVILv (ORCPT ); Tue, 22 Mar 2022 04:11:51 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id E995722532 for ; Tue, 22 Mar 2022 01:10:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1647936620; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=/LIZ4+UZDR/rmIDcVGPelhK/TR916yFa76+4h/+44F4=; b=D1aKnyDwyWcPU/Gh0MI2X4BRF3jzmQnaBs4Tqlbnhz5QEid5We+9xd0gXpsQ0fYU+lYFDZ N4GcUcGgDBLS5vkS7LRjkqEtOX8aLHrly4zYI7uLh9JAoXkMxr9BBfWvFQ31ImS25IL/up tq10QtRLXkIIp08FCX01RYSH5PaewJc= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-615-izDC0cl_MU2_BVqHHkgCZw-1; Tue, 22 Mar 2022 04:10:16 -0400 X-MC-Unique: izDC0cl_MU2_BVqHHkgCZw-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 454D3801E67; Tue, 22 Mar 2022 08:10:16 +0000 (UTC) Received: from gshan.redhat.com (ovpn-12-33.pek2.redhat.com [10.72.12.33]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 604F41121324; Tue, 22 Mar 2022 08:10:10 +0000 (UTC) From: Gavin Shan To: kvmarm@lists.cs.columbia.edu Cc: linux-kernel@vger.kernel.org, eauger@redhat.com, shannon.zhaosl@gmail.com, maz@kernel.org, Jonathan.Cameron@huawei.com, will@kernel.org, pbonzini@redhat.com, james.morse@arm.com, mark.rutland@arm.com, drjones@redhat.com, vkuznets@redhat.com, shan.gavin@gmail.com Subject: [PATCH v5 16/22] KVM: arm64: Support SDEI_EVENT_{COMPLETE,COMPLETE_AND_RESUME} hypercall Date: Tue, 22 Mar 2022 16:07:04 +0800 Message-Id: <20220322080710.51727-17-gshan@redhat.com> In-Reply-To: <20220322080710.51727-1-gshan@redhat.com> References: <20220322080710.51727-1-gshan@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This supports SDEI_EVENT_{COMPLETE, COMPLETE_AND_RESUME} hypercall. They are used by the guest to notify the completion of the SDEI event in the handler. The executing context or registers are modified according to the SDEI specification like below: * x0 - x17, PC and PState are restored to what values we had in the interrupted or preempted context. * If it's SDEI_EVENT_COMPLETE_AND_RESUME hypercall, IRQ exception is injected. Signed-off-by: Gavin Shan --- arch/arm64/include/asm/kvm_emulate.h | 1 + arch/arm64/include/asm/kvm_host.h | 1 + arch/arm64/kvm/inject_fault.c | 29 +++++++++++ arch/arm64/kvm/sdei.c | 76 +++++++++++++++++++++++++++- 4 files changed, 106 insertions(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/= kvm_emulate.h index d62405ce3e6d..ca9de9f24923 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -37,6 +37,7 @@ bool kvm_condition_valid32(const struct kvm_vcpu *vcpu); void kvm_skip_instr32(struct kvm_vcpu *vcpu); =20 void kvm_inject_undefined(struct kvm_vcpu *vcpu); +void kvm_inject_irq(struct kvm_vcpu *vcpu); void kvm_inject_vabt(struct kvm_vcpu *vcpu); void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr); void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr); diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm= _host.h index e2762d08ab1c..282913e1afb0 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -428,6 +428,7 @@ struct kvm_vcpu_arch { #define KVM_ARM64_EXCEPT_AA32_UND (0 << 9) #define KVM_ARM64_EXCEPT_AA32_IABT (1 << 9) #define KVM_ARM64_EXCEPT_AA32_DABT (2 << 9) +#define KVM_ARM64_EXCEPT_AA32_IRQ (3 << 9) /* For AArch64: */ #define KVM_ARM64_EXCEPT_AA64_ELx_SYNC (0 << 9) #define KVM_ARM64_EXCEPT_AA64_ELx_IRQ (1 << 9) diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c index b47df73e98d7..c8a8791bdf28 100644 --- a/arch/arm64/kvm/inject_fault.c +++ b/arch/arm64/kvm/inject_fault.c @@ -66,6 +66,13 @@ static void inject_undef64(struct kvm_vcpu *vcpu) vcpu_write_sys_reg(vcpu, esr, ESR_EL1); } =20 +static void inject_irq64(struct kvm_vcpu *vcpu) +{ + vcpu->arch.flags |=3D (KVM_ARM64_EXCEPT_AA64_EL1 | + KVM_ARM64_EXCEPT_AA64_ELx_IRQ | + KVM_ARM64_PENDING_EXCEPTION); +} + #define DFSR_FSC_EXTABT_LPAE 0x10 #define DFSR_FSC_EXTABT_nLPAE 0x08 #define DFSR_LPAE BIT(9) @@ -77,6 +84,12 @@ static void inject_undef32(struct kvm_vcpu *vcpu) KVM_ARM64_PENDING_EXCEPTION); } =20 +static void inject_irq32(struct kvm_vcpu *vcpu) +{ + vcpu->arch.flags |=3D (KVM_ARM64_EXCEPT_AA32_IRQ | + KVM_ARM64_PENDING_EXCEPTION); +} + /* * Modelled after TakeDataAbortException() and TakePrefetchAbortException * pseudocode. @@ -160,6 +173,22 @@ void kvm_inject_undefined(struct kvm_vcpu *vcpu) inject_undef64(vcpu); } =20 +/** + * kvm_inject_irq - inject an IRQ into the guest + * @vcpu: The vCPU in which to inject IRQ + * + * Inject IRQs to the target vCPU. It is assumed that this code is + * called from the VCPU thread and that the VCPU therefore is not + * currently executing guest code. + */ +void kvm_inject_irq(struct kvm_vcpu *vcpu) +{ + if (vcpu_el1_is_32bit(vcpu)) + inject_irq32(vcpu); + else + inject_irq64(vcpu); +} + void kvm_set_sei_esr(struct kvm_vcpu *vcpu, u64 esr) { vcpu_set_vsesr(vcpu, esr & ESR_ELx_ISS_MASK); diff --git a/arch/arm64/kvm/sdei.c b/arch/arm64/kvm/sdei.c index ba2ca65c871b..3019ac196e76 100644 --- a/arch/arm64/kvm/sdei.c +++ b/arch/arm64/kvm/sdei.c @@ -344,6 +344,78 @@ static unsigned long hypercall_context(struct kvm_vcpu= *vcpu) return ret; } =20 +static unsigned long hypercall_complete(struct kvm_vcpu *vcpu, bool resume) +{ + struct kvm *kvm =3D vcpu->kvm; + struct kvm_sdei_kvm *ksdei =3D kvm->arch.sdei; + struct kvm_sdei_vcpu *vsdei =3D vcpu->arch.sdei; + struct kvm_sdei_exposed_event *exposed_event; + struct kvm_sdei_registered_event *registered_event; + struct kvm_sdei_vcpu_event *vcpu_event; + struct kvm_sdei_vcpu_regs_state *regs; + unsigned long ret =3D SDEI_SUCCESS; + int index; + + spin_lock(&ksdei->lock); + spin_lock(&vsdei->lock); + + if (vsdei->critical_event) { + vcpu_event =3D vsdei->critical_event; + regs =3D &vsdei->state.critical_regs; + vsdei->critical_event =3D NULL; + vsdei->state.critical_num =3D KVM_SDEI_INVALID_EVENT; + } else if (vsdei->normal_event) { + vcpu_event =3D vsdei->normal_event; + regs =3D &vsdei->state.normal_regs; + vsdei->normal_event =3D NULL; + vsdei->state.normal_num =3D KVM_SDEI_INVALID_EVENT; + } else { + ret =3D SDEI_DENIED; + goto unlock; + } + + /* Restore registers: x0 -> x17, PC, PState */ + for (index =3D 0; index < ARRAY_SIZE(regs->regs); index++) + vcpu_set_reg(vcpu, index, regs->regs[index]); + + *vcpu_cpsr(vcpu) =3D regs->pstate; + *vcpu_pc(vcpu) =3D regs->pc; + + /* Inject interrupt if needed */ + if (resume) + kvm_inject_irq(vcpu); + + /* Dereference the vcpu event and destroy it if needed */ + vcpu_event->state.event_count--; + if (!vcpu_event->state.event_count) + remove_one_vcpu_event(vcpu, vcpu_event); + + /* + * We need to check if the registered event is pending for + * unregistration. In that case, the registered event should + * be unregistered and destroyed if needed. + */ + registered_event =3D vcpu_event->registered_event; + exposed_event =3D registered_event->exposed_event; + index =3D kvm_sdei_vcpu_index(vcpu, exposed_event); + if (kvm_sdei_is_unregister_pending(registered_event, index)) { + kvm_sdei_clear_enabled(registered_event, index); + kvm_sdei_clear_registered(registered_event, index); + if (kvm_sdei_none_registered(registered_event)) + remove_one_registered_event(kvm, registered_event); + } + + /* Make another request if we have any pending events */ + if ((vsdei->critical_event_count + vsdei->normal_event_count) > 0) + kvm_make_request(KVM_REQ_SDEI, vcpu); + +unlock: + spin_unlock(&vsdei->lock); + spin_unlock(&ksdei->lock); + + return ret; +} + static unsigned long unregister_one_event(struct kvm *kvm, struct kvm_vcpu *vcpu, struct kvm_sdei_registered_event *registered_event) @@ -864,8 +936,10 @@ int kvm_sdei_hypercall(struct kvm_vcpu *vcpu) ret =3D hypercall_context(vcpu); break; case SDEI_1_0_FN_SDEI_EVENT_COMPLETE: + ret =3D hypercall_complete(vcpu, false); + break; case SDEI_1_0_FN_SDEI_EVENT_COMPLETE_AND_RESUME: - ret =3D SDEI_NOT_SUPPORTED; + ret =3D hypercall_complete(vcpu, true); break; case SDEI_1_0_FN_SDEI_EVENT_UNREGISTER: ret =3D hypercall_unregister(vcpu); --=20 2.23.0 From nobody Mon Jun 22 14:25:00 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 443FFC433EF for ; Tue, 22 Mar 2022 08:10:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230122AbiCVIMJ (ORCPT ); Tue, 22 Mar 2022 04:12:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35132 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230090AbiCVIMH (ORCPT ); Tue, 22 Mar 2022 04:12:07 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 269525D65B for ; Tue, 22 Mar 2022 01:10:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1647936632; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=6LiuGwo8D8luzu1fufiYqiwAA/jy3lFuWpH7KFm91+c=; b=YulK/btdthXXv2JNHL9iYDa8P1LnJZH0Q+0NnECcUnDsWDl2JmucwnRaKe10xsTMfRZOPS FA0+/U17Oktou7x7cunse/unbhXcnuILTd6Dqcf5nW3crNaGAx7JtUpOeliW4QKGL4wqmR Z31+d4+u1EzOzh7NLOd6n1qSEY4brpw= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-57-urwu8cqxMw-e_yxNDHdsDg-1; Tue, 22 Mar 2022 04:10:31 -0400 X-MC-Unique: urwu8cqxMw-e_yxNDHdsDg-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id E1AF63C01C0F; Tue, 22 Mar 2022 08:10:30 +0000 (UTC) Received: from gshan.redhat.com (ovpn-12-33.pek2.redhat.com [10.72.12.33]) by smtp.corp.redhat.com (Postfix) with ESMTPS id F05E71121324; Tue, 22 Mar 2022 08:10:16 +0000 (UTC) From: Gavin Shan To: kvmarm@lists.cs.columbia.edu Cc: linux-kernel@vger.kernel.org, eauger@redhat.com, shannon.zhaosl@gmail.com, maz@kernel.org, Jonathan.Cameron@huawei.com, will@kernel.org, pbonzini@redhat.com, james.morse@arm.com, mark.rutland@arm.com, drjones@redhat.com, vkuznets@redhat.com, shan.gavin@gmail.com Subject: [PATCH v5 17/22] KVM: arm64: Support SDEI event notifier Date: Tue, 22 Mar 2022 16:07:05 +0800 Message-Id: <20220322080710.51727-18-gshan@redhat.com> In-Reply-To: <20220322080710.51727-1-gshan@redhat.com> References: <20220322080710.51727-1-gshan@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" The owner of the SDEI event may want to know if the injected event has been delivered and handled. For example, Async PF cancels the injected SDEI event at early stage of the work, driven by the event has been completed asynchronously. This supports SDEI event state updating by introducing notifier mechanism. It's notable the notifier (handler) should be capable of migration. Signed-off-by: Gavin Shan --- arch/arm64/include/asm/kvm_sdei.h | 10 +++++++ arch/arm64/kvm/sdei.c | 45 +++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/arch/arm64/include/asm/kvm_sdei.h b/arch/arm64/include/asm/kvm= _sdei.h index 54c730acd298..2480ec0e9824 100644 --- a/arch/arm64/include/asm/kvm_sdei.h +++ b/arch/arm64/include/asm/kvm_sdei.h @@ -18,6 +18,14 @@ =20 struct kvm_vcpu; =20 +typedef void (*kvm_sdei_notifier)(struct kvm_vcpu *vcpu, + unsigned long num, + unsigned int state); +enum { + KVM_SDEI_NOTIFY_DELIVERED, + KVM_SDEI_NOTIFY_COMPLETED, +}; + struct kvm_sdei_exposed_event { struct kvm_sdei_exposed_event_state state; struct kvm *kvm; @@ -165,6 +173,8 @@ KVM_SDEI_REGISTERED_EVENT_FUNC(unregister_pending) void kvm_sdei_init_vm(struct kvm *kvm); void kvm_sdei_create_vcpu(struct kvm_vcpu *vcpu); int kvm_sdei_hypercall(struct kvm_vcpu *vcpu); +int kvm_sdei_register_event_notifier(struct kvm *kvm, unsigned long num, + kvm_sdei_notifier notifier); int kvm_sdei_inject_event(struct kvm_vcpu *vcpu, unsigned long num, bool immediate); int kvm_sdei_cancel_event(struct kvm_vcpu *vcpu, unsigned long num); diff --git a/arch/arm64/kvm/sdei.c b/arch/arm64/kvm/sdei.c index 3019ac196e76..9f1959653318 100644 --- a/arch/arm64/kvm/sdei.c +++ b/arch/arm64/kvm/sdei.c @@ -353,6 +353,7 @@ static unsigned long hypercall_complete(struct kvm_vcpu= *vcpu, bool resume) struct kvm_sdei_registered_event *registered_event; struct kvm_sdei_vcpu_event *vcpu_event; struct kvm_sdei_vcpu_regs_state *regs; + kvm_sdei_notifier notifier =3D NULL; unsigned long ret =3D SDEI_SUCCESS; int index; =20 @@ -397,6 +398,7 @@ static unsigned long hypercall_complete(struct kvm_vcpu= *vcpu, bool resume) */ registered_event =3D vcpu_event->registered_event; exposed_event =3D registered_event->exposed_event; + notifier =3D (kvm_sdei_notifier)(exposed_event->state.notifier); index =3D kvm_sdei_vcpu_index(vcpu, exposed_event); if (kvm_sdei_is_unregister_pending(registered_event, index)) { kvm_sdei_clear_enabled(registered_event, index); @@ -413,6 +415,12 @@ static unsigned long hypercall_complete(struct kvm_vcp= u *vcpu, bool resume) spin_unlock(&vsdei->lock); spin_unlock(&ksdei->lock); =20 + /* Notifier */ + if (notifier) { + notifier(vcpu, exposed_event->state.num, + KVM_SDEI_NOTIFY_COMPLETED); + } + return ret; } =20 @@ -986,6 +994,35 @@ int kvm_sdei_hypercall(struct kvm_vcpu *vcpu) return 1; } =20 +int kvm_sdei_register_event_notifier(struct kvm *kvm, + unsigned long num, + kvm_sdei_notifier notifier) +{ + struct kvm_sdei_kvm *ksdei =3D kvm->arch.sdei; + struct kvm_sdei_exposed_event *exposed_event =3D NULL; + int ret =3D 0; + + if (!ksdei) { + ret =3D -EPERM; + goto out; + } + + spin_lock(&ksdei->lock); + + exposed_event =3D find_exposed_event(kvm, num); + if (!exposed_event) { + ret =3D -EINVAL; + goto unlock; + } + + exposed_event->state.notifier =3D (unsigned long)notifier; + +unlock: + spin_unlock(&ksdei->lock); +out: + return ret; +} + int kvm_sdei_inject_event(struct kvm_vcpu *vcpu, unsigned long num, bool immediate) @@ -1100,6 +1137,7 @@ void kvm_sdei_deliver_event(struct kvm_vcpu *vcpu) struct kvm_sdei_registered_event *registered_event; struct kvm_sdei_vcpu_event *vcpu_event; struct kvm_sdei_vcpu_regs_state *regs; + kvm_sdei_notifier notifier =3D NULL; unsigned long pstate; int index; =20 @@ -1129,6 +1167,7 @@ void kvm_sdei_deliver_event(struct kvm_vcpu *vcpu) =20 registered_event =3D vcpu_event->registered_event; exposed_event =3D registered_event->exposed_event; + notifier =3D (kvm_sdei_notifier)(exposed_event->state.notifier); if (kvm_sdei_is_critical(exposed_event->state.priority)) { vsdei->critical_event =3D vcpu_event; vsdei->state.critical_num =3D vcpu_event->state.num; @@ -1179,6 +1218,12 @@ void kvm_sdei_deliver_event(struct kvm_vcpu *vcpu) =20 unlock: spin_unlock(&vsdei->lock); + + /* Notifier */ + if (notifier) { + notifier(vcpu, exposed_event->state.num, + KVM_SDEI_NOTIFY_DELIVERED); + } } =20 void kvm_sdei_init_vm(struct kvm *kvm) --=20 2.23.0 From nobody Mon Jun 22 14:25:00 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D7350C433EF for ; Tue, 22 Mar 2022 08:10:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230156AbiCVIMV (ORCPT ); Tue, 22 Mar 2022 04:12:21 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36264 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230161AbiCVIMS (ORCPT ); Tue, 22 Mar 2022 04:12:18 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 57118167E9 for ; Tue, 22 Mar 2022 01:10:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1647936647; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=nVcTHfrpc1eLanJnwIYziD/n9zbr8iiHwU6wRa4N1ZU=; b=VuLs9Ihj/mj3SI3andhlMdbGQbAEWQfBaGa8A9sNSlf3tDYxMD2r30R/uGib7ikYzJ+LW6 K23i7ee/8t7lKb/KivCUamH2cJb1BWBV+csfJZwdiWo1FT6O46EzBewvxBgr6gLy/1aGN+ 0KdaSMDaQ1a20InjcMneJsY4WpNSuNY= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-400-jQnDMaSINpmzb7YjdNjk1A-1; Tue, 22 Mar 2022 04:10:44 -0400 X-MC-Unique: jQnDMaSINpmzb7YjdNjk1A-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 95C0038041CF; Tue, 22 Mar 2022 08:10:43 +0000 (UTC) Received: from gshan.redhat.com (ovpn-12-33.pek2.redhat.com [10.72.12.33]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 96B0C1121324; Tue, 22 Mar 2022 08:10:31 +0000 (UTC) From: Gavin Shan To: kvmarm@lists.cs.columbia.edu Cc: linux-kernel@vger.kernel.org, eauger@redhat.com, shannon.zhaosl@gmail.com, maz@kernel.org, Jonathan.Cameron@huawei.com, will@kernel.org, pbonzini@redhat.com, james.morse@arm.com, mark.rutland@arm.com, drjones@redhat.com, vkuznets@redhat.com, shan.gavin@gmail.com Subject: [PATCH v5 18/22] KVM: arm64: Support SDEI ioctl commands on VM Date: Tue, 22 Mar 2022 16:07:06 +0800 Message-Id: <20220322080710.51727-19-gshan@redhat.com> In-Reply-To: <20220322080710.51727-1-gshan@redhat.com> References: <20220322080710.51727-1-gshan@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This supports ioctl commands on VM to manage the various objects. It's primarily used by VMM to accomplish migration. The ioctl commands introduced by this are highlighted as below: * KVM_SDEI_CMD_GET_VERSION Retrieve the version of current implementation. It's different from the version of the followed SDEI specification. This version is used to indicates what functionalities documented in the SDEI specification have been supported or not supported. * KVM_SDEI_CMD_GET_EXPOSED_EVENT_COUNT Return the total count of exposed events. * KVM_SDEI_CMD_GET_EXPOSED_EVENT * KVM_SDEI_CMD_SET_EXPOSED_EVENT Get or set exposed event * KVM_SDEI_CMD_GET_REGISTERED_EVENT_COUNT Return the total count of registered events. * KVM_SDEI_CMD_GET_REGISTERED_EVENT * KVM_SDEI_CMD_SET_REGISTERED_EVENT Get or set registered event. Signed-off-by: Gavin Shan --- arch/arm64/include/asm/kvm_sdei.h | 1 + arch/arm64/include/uapi/asm/kvm_sdei_state.h | 20 ++ arch/arm64/kvm/arm.c | 3 + arch/arm64/kvm/sdei.c | 302 +++++++++++++++++++ include/uapi/linux/kvm.h | 3 + 5 files changed, 329 insertions(+) diff --git a/arch/arm64/include/asm/kvm_sdei.h b/arch/arm64/include/asm/kvm= _sdei.h index 2480ec0e9824..64f00cc79162 100644 --- a/arch/arm64/include/asm/kvm_sdei.h +++ b/arch/arm64/include/asm/kvm_sdei.h @@ -179,6 +179,7 @@ int kvm_sdei_inject_event(struct kvm_vcpu *vcpu, unsigned long num, bool immediate); int kvm_sdei_cancel_event(struct kvm_vcpu *vcpu, unsigned long num); void kvm_sdei_deliver_event(struct kvm_vcpu *vcpu); +long kvm_sdei_vm_ioctl(struct kvm *kvm, unsigned long arg); void kvm_sdei_destroy_vcpu(struct kvm_vcpu *vcpu); void kvm_sdei_destroy_vm(struct kvm *kvm); =20 diff --git a/arch/arm64/include/uapi/asm/kvm_sdei_state.h b/arch/arm64/incl= ude/uapi/asm/kvm_sdei_state.h index b14844230117..2bd6d11627bc 100644 --- a/arch/arm64/include/uapi/asm/kvm_sdei_state.h +++ b/arch/arm64/include/uapi/asm/kvm_sdei_state.h @@ -68,5 +68,25 @@ struct kvm_sdei_vcpu_state { struct kvm_sdei_vcpu_regs_state normal_regs; }; =20 +#define KVM_SDEI_CMD_GET_VERSION 0 +#define KVM_SDEI_CMD_GET_EXPOSED_EVENT_COUNT 1 +#define KVM_SDEI_CMD_GET_EXPOSED_EVENT 2 +#define KVM_SDEI_CMD_SET_EXPOSED_EVENT 3 +#define KVM_SDEI_CMD_GET_REGISTERED_EVENT_COUNT 4 +#define KVM_SDEI_CMD_GET_REGISTERED_EVENT 5 +#define KVM_SDEI_CMD_SET_REGISTERED_EVENT 6 + +struct kvm_sdei_cmd { + __u32 cmd; + union { + __u32 version; + __u32 count; + }; + union { + struct kvm_sdei_exposed_event_state *exposed_event_state; + struct kvm_sdei_registered_event_state *registered_event_state; + }; +}; + #endif /* !__ASSEMBLY__ */ #endif /* _UAPI__ASM_KVM_SDEI_STATE_H */ diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 00c136a6e8df..ebfd504a1c08 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -1465,6 +1465,9 @@ long kvm_arch_vm_ioctl(struct file *filp, return -EFAULT; return kvm_vm_ioctl_mte_copy_tags(kvm, ©_tags); } + case KVM_ARM_SDEI_COMMAND: { + return kvm_sdei_vm_ioctl(kvm, arg); + } default: return -EINVAL; } diff --git a/arch/arm64/kvm/sdei.c b/arch/arm64/kvm/sdei.c index 9f1959653318..d9cf494990a9 100644 --- a/arch/arm64/kvm/sdei.c +++ b/arch/arm64/kvm/sdei.c @@ -1265,6 +1265,308 @@ void kvm_sdei_create_vcpu(struct kvm_vcpu *vcpu) vcpu->arch.sdei =3D vsdei; } =20 +static long vm_ioctl_get_exposed_event(struct kvm *kvm, + struct kvm_sdei_cmd *cmd) +{ + struct kvm_sdei_kvm *ksdei =3D kvm->arch.sdei; + struct kvm_sdei_exposed_event *exposed_event; + struct kvm_sdei_exposed_event_state *state; + void __user *user_state =3D (void __user *)(cmd->exposed_event_state); + unsigned int count, i; + long ret =3D 0; + + if (!cmd->count) + return 0; + + state =3D kcalloc(cmd->count, sizeof(*state), GFP_KERNEL_ACCOUNT); + if (!state) + return -ENOMEM; + + i =3D 0; + count =3D cmd->count; + list_for_each_entry(exposed_event, &ksdei->exposed_events, link) { + state[i++] =3D exposed_event->state; + if (!--count) + break; + } + + if (copy_to_user(user_state, state, sizeof(*state) * cmd->count)) + ret =3D -EFAULT; + + kfree(state); + return ret; +} + +static long vm_ioctl_set_exposed_event(struct kvm *kvm, + struct kvm_sdei_cmd *cmd) +{ + struct kvm_sdei_kvm *ksdei =3D kvm->arch.sdei; + struct kvm_sdei_exposed_event *exposed_event; + struct kvm_sdei_exposed_event_state *state; + void __user *user_state =3D (void __user *)(cmd->exposed_event_state); + unsigned int i, j; + long ret =3D 0; + + if (!cmd->count) + return 0; + + if ((ksdei->exposed_event_count + cmd->count) > KVM_SDEI_MAX_EVENTS) + return -ERANGE; + + state =3D kcalloc(cmd->count, sizeof(*state), GFP_KERNEL_ACCOUNT); + if (!state) + return -ENOMEM; + + if (copy_from_user(state, user_state, sizeof(*state) * cmd->count)) { + ret =3D -EFAULT; + goto out; + } + + for (i =3D 0; i < cmd->count; i++) { + if (!kvm_sdei_is_supported(state[i].num)) { + ret =3D -EINVAL; + goto out; + } + + if (!kvm_sdei_is_shared(state[i].type) && + !kvm_sdei_is_private(state[i].type)) { + ret =3D -EINVAL; + goto out; + } + + if (!kvm_sdei_is_critical(state[i].priority) && + !kvm_sdei_is_normal(state[i].priority)) { + ret =3D -EINVAL; + goto out; + } + + /* + * Check if the event has been exposed. The notifier is + * allowed to be changed. + */ + exposed_event =3D find_exposed_event(kvm, state[i].num); + if (exposed_event && + (state[i].num !=3D exposed_event->state.num || + state[i].type !=3D exposed_event->state.type || + state[i].signaled !=3D exposed_event->state.signaled || + state[i].priority !=3D exposed_event->state.priority)) { + ret =3D -EEXIST; + goto out; + } + + /* Avoid the duplicated event */ + for (j =3D 0; j < cmd->count; j++) { + if (i !=3D j && state[i].num =3D=3D state[j].num) { + ret =3D -EINVAL; + goto out; + } + } + } + + for (i =3D 0; i < cmd->count; i++) { + exposed_event =3D find_exposed_event(kvm, state[i].num); + if (exposed_event) { + exposed_event->state =3D state[i]; + continue; + } + + exposed_event =3D kzalloc(sizeof(*exposed_event), + GFP_KERNEL_ACCOUNT); + if (!exposed_event) { + ret =3D -ENOMEM; + goto out; + } + + exposed_event->state =3D state[i]; + exposed_event->kvm =3D kvm; + + ksdei->exposed_event_count++; + list_add_tail(&exposed_event->link, &ksdei->exposed_events); + } + +out: + kfree(state); + return ret; +} + +static long vm_ioctl_get_registered_event(struct kvm *kvm, + struct kvm_sdei_cmd *cmd) +{ + struct kvm_sdei_kvm *ksdei =3D kvm->arch.sdei; + struct kvm_sdei_registered_event *registered_event; + struct kvm_sdei_registered_event_state *state; + void __user *user_state =3D (void __user *)(cmd->registered_event_state); + unsigned int count, i; + long ret =3D 0; + + if (!cmd->count) + return 0; + + state =3D kcalloc(cmd->count, sizeof(*state), GFP_KERNEL_ACCOUNT); + if (!state) + return -ENOMEM; + + i =3D 0; + count =3D cmd->count; + list_for_each_entry(registered_event, + &ksdei->registered_events, link) { + state[i++] =3D registered_event->state; + if (!--count) + break; + } + + if (copy_to_user(user_state, state, sizeof(*state) * cmd->count)) + ret =3D -EFAULT; + + kfree(state); + return ret; +} + +static long vm_ioctl_set_registered_event(struct kvm *kvm, + struct kvm_sdei_cmd *cmd) +{ + struct kvm_sdei_kvm *ksdei =3D kvm->arch.sdei; + struct kvm_sdei_exposed_event *exposed_event; + struct kvm_sdei_registered_event *registered_event; + struct kvm_sdei_registered_event_state *state; + void __user *user_state =3D (void __user *)(cmd->registered_event_state); + unsigned int i, j; + long ret =3D 0; + + if (!cmd->count) + return 0; + + if ((ksdei->registered_event_count + cmd->count) > KVM_SDEI_MAX_EVENTS) + return -ERANGE; + + state =3D kcalloc(cmd->count, sizeof(*state), GFP_KERNEL_ACCOUNT); + if (!state) + return -ENOMEM; + + if (copy_from_user(state, user_state, sizeof(*state) * cmd->count)) { + ret =3D -EFAULT; + goto out; + } + + for (i =3D 0; i < cmd->count; i++) { + if (!kvm_sdei_is_supported(state[i].num)) { + ret =3D -EINVAL; + goto out; + } + + if (state[i].route_mode !=3D SDEI_EVENT_REGISTER_RM_ANY && + state[i].route_mode !=3D SDEI_EVENT_REGISTER_RM_PE) { + ret =3D -EINVAL; + goto out; + } + + /* Check if the event has been exposed */ + exposed_event =3D find_exposed_event(kvm, state[i].num); + if (!exposed_event) { + ret =3D -ENOENT; + goto out; + } + + /* Check if the event has been registered */ + registered_event =3D find_registered_event(kvm, state[i].num); + if (registered_event) { + ret =3D -EEXIST; + goto out; + } + + /* Avoid the duplicated event */ + for (j =3D 0; j < cmd->count; j++) { + if (i !=3D j && state[i].num =3D=3D state[j].num) { + ret =3D -EINVAL; + goto out; + } + } + } + + for (i =3D 0; i < cmd->count; i++) { + registered_event =3D kzalloc(sizeof(*registered_event), + GFP_KERNEL_ACCOUNT); + if (!registered_event) { + ret =3D -ENOMEM; + goto out; + } + + exposed_event =3D find_exposed_event(kvm, state[i].num); + registered_event->state =3D state[i]; + registered_event->kvm =3D kvm; + registered_event->exposed_event =3D exposed_event; + + ksdei->registered_event_count++; + exposed_event->registered_event_count++; + list_add_tail(®istered_event->link, + &ksdei->registered_events); + } + +out: + kfree(state); + return ret; +} + +long kvm_sdei_vm_ioctl(struct kvm *kvm, unsigned long arg) +{ + struct kvm_sdei_kvm *ksdei =3D kvm->arch.sdei; + struct kvm_sdei_cmd *cmd; + void __user *argp =3D (void __user *)arg; + long ret =3D 0; + + if (!ksdei) + return -EPERM; + + cmd =3D kzalloc(sizeof(*cmd), GFP_KERNEL_ACCOUNT); + if (!cmd) + return -ENOMEM; + + if (copy_from_user(cmd, argp, sizeof(*cmd))) { + ret =3D -EFAULT; + goto out; + } + + spin_lock(&ksdei->lock); + + switch (cmd->cmd) { + case KVM_SDEI_CMD_GET_VERSION: + cmd->version =3D (1 << 16); /* v1.0.0 */ + if (copy_to_user(argp, cmd, sizeof(*cmd))) + ret =3D -EFAULT; + break; + case KVM_SDEI_CMD_GET_EXPOSED_EVENT_COUNT: + cmd->count =3D ksdei->exposed_event_count; + if (copy_to_user(argp, cmd, sizeof(*cmd))) + ret =3D -EFAULT; + break; + case KVM_SDEI_CMD_GET_EXPOSED_EVENT: + ret =3D vm_ioctl_get_exposed_event(kvm, cmd); + break; + case KVM_SDEI_CMD_SET_EXPOSED_EVENT: + ret =3D vm_ioctl_set_exposed_event(kvm, cmd); + break; + case KVM_SDEI_CMD_GET_REGISTERED_EVENT_COUNT: + cmd->count =3D ksdei->registered_event_count; + if (copy_to_user(argp, cmd, sizeof(*cmd))) + ret =3D -EFAULT; + break; + case KVM_SDEI_CMD_GET_REGISTERED_EVENT: + ret =3D vm_ioctl_get_registered_event(kvm, cmd); + break; + case KVM_SDEI_CMD_SET_REGISTERED_EVENT: + ret =3D vm_ioctl_set_registered_event(kvm, cmd); + break; + default: + ret =3D -EINVAL; + } + + spin_unlock(&ksdei->lock); +out: + + kfree(cmd); + return ret; +} + void kvm_sdei_destroy_vcpu(struct kvm_vcpu *vcpu) { struct kvm *kvm =3D vcpu->kvm; diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 507ee1f2aa96..2d11c909ec42 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -2049,4 +2049,7 @@ struct kvm_stats_desc { /* Available with KVM_CAP_XSAVE2 */ #define KVM_GET_XSAVE2 _IOR(KVMIO, 0xcf, struct kvm_xsave) =20 +/* Available with KVM_CAP_ARM_SDEI */ +#define KVM_ARM_SDEI_COMMAND _IOWR(KVMIO, 0xd0, struct kvm_sdei_cmd) + #endif /* __LINUX_KVM_H */ --=20 2.23.0 From nobody Mon Jun 22 14:25:00 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7DFBCC433EF for ; Tue, 22 Mar 2022 08:11:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230161AbiCVIMa (ORCPT ); Tue, 22 Mar 2022 04:12:30 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37032 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230184AbiCVIM0 (ORCPT ); Tue, 22 Mar 2022 04:12:26 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 9C3891A817 for ; Tue, 22 Mar 2022 01:10:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1647936655; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=3UghuFZbDMRSZLidajgSjDvLEyY5ro+FG5IdVl25tP4=; b=JPBBty7mILfKmE9HhJ30rYXEvFsWTb1Q1KLKc/FjbwLFQ8PGNczttd2SZNFSbhFUtplqZX y6EPkHLcSfKdidKDfEwlaJ2XddoXPPQ19zKFhA70uEYxLABO1onVDLivjPHOncBwOpOev9 1HcXh8CzH7Lgt01dCwcXjGDv33wNXw8= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-417-J-WMDEvYOaG0bArrNjkg9g-1; Tue, 22 Mar 2022 04:10:52 -0400 X-MC-Unique: J-WMDEvYOaG0bArrNjkg9g-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 271D0801E67; Tue, 22 Mar 2022 08:10:52 +0000 (UTC) Received: from gshan.redhat.com (ovpn-12-33.pek2.redhat.com [10.72.12.33]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 4E39F1121324; Tue, 22 Mar 2022 08:10:43 +0000 (UTC) From: Gavin Shan To: kvmarm@lists.cs.columbia.edu Cc: linux-kernel@vger.kernel.org, eauger@redhat.com, shannon.zhaosl@gmail.com, maz@kernel.org, Jonathan.Cameron@huawei.com, will@kernel.org, pbonzini@redhat.com, james.morse@arm.com, mark.rutland@arm.com, drjones@redhat.com, vkuznets@redhat.com, shan.gavin@gmail.com Subject: [PATCH v5 19/22] KVM: arm64: Support SDEI ioctl commands on vCPU Date: Tue, 22 Mar 2022 16:07:07 +0800 Message-Id: <20220322080710.51727-20-gshan@redhat.com> In-Reply-To: <20220322080710.51727-1-gshan@redhat.com> References: <20220322080710.51727-1-gshan@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This supports ioctl commands on vCPU to manage the various object. It's primarily used by VMM to accomplish migration. The ioctl commands introduced by this are highlighted as below: * KVM_SDEI_CMD_GET_VCPU_EVENT_COUNT Return the total count of vCPU events, which have been queued on the target vCPU. * KVM_SDEI_CMD_GET_VCPU_EVENT * KVM_SDEI_CMD_SET_VCPU_EVENT Get or set vCPU events. * KVM_SDEI_CMD_GET_VCPU_STATE * KVM_SDEI_CMD_SET_VCPU_STATE Get or set vCPU state. * KVM_SDEI_CMD_INJECT_EVENT Inject SDEI event. Signed-off-by: Gavin Shan --- arch/arm64/include/asm/kvm_sdei.h | 1 + arch/arm64/include/uapi/asm/kvm_sdei_state.h | 9 + arch/arm64/kvm/arm.c | 3 + arch/arm64/kvm/sdei.c | 299 +++++++++++++++++++ 4 files changed, 312 insertions(+) diff --git a/arch/arm64/include/asm/kvm_sdei.h b/arch/arm64/include/asm/kvm= _sdei.h index 64f00cc79162..ea4f222cf73d 100644 --- a/arch/arm64/include/asm/kvm_sdei.h +++ b/arch/arm64/include/asm/kvm_sdei.h @@ -180,6 +180,7 @@ int kvm_sdei_inject_event(struct kvm_vcpu *vcpu, int kvm_sdei_cancel_event(struct kvm_vcpu *vcpu, unsigned long num); void kvm_sdei_deliver_event(struct kvm_vcpu *vcpu); long kvm_sdei_vm_ioctl(struct kvm *kvm, unsigned long arg); +long kvm_sdei_vcpu_ioctl(struct kvm_vcpu *vcpu, unsigned long arg); void kvm_sdei_destroy_vcpu(struct kvm_vcpu *vcpu); void kvm_sdei_destroy_vm(struct kvm *kvm); =20 diff --git a/arch/arm64/include/uapi/asm/kvm_sdei_state.h b/arch/arm64/incl= ude/uapi/asm/kvm_sdei_state.h index 2bd6d11627bc..149451c5584f 100644 --- a/arch/arm64/include/uapi/asm/kvm_sdei_state.h +++ b/arch/arm64/include/uapi/asm/kvm_sdei_state.h @@ -75,6 +75,12 @@ struct kvm_sdei_vcpu_state { #define KVM_SDEI_CMD_GET_REGISTERED_EVENT_COUNT 4 #define KVM_SDEI_CMD_GET_REGISTERED_EVENT 5 #define KVM_SDEI_CMD_SET_REGISTERED_EVENT 6 +#define KVM_SDEI_CMD_GET_VCPU_EVENT_COUNT 7 +#define KVM_SDEI_CMD_GET_VCPU_EVENT 8 +#define KVM_SDEI_CMD_SET_VCPU_EVENT 9 +#define KVM_SDEI_CMD_GET_VCPU_STATE 10 +#define KVM_SDEI_CMD_SET_VCPU_STATE 11 +#define KVM_SDEI_CMD_INJECT_EVENT 12 =20 struct kvm_sdei_cmd { __u32 cmd; @@ -85,6 +91,9 @@ struct kvm_sdei_cmd { union { struct kvm_sdei_exposed_event_state *exposed_event_state; struct kvm_sdei_registered_event_state *registered_event_state; + struct kvm_sdei_vcpu_event_state *vcpu_event_state; + struct kvm_sdei_vcpu_state *vcpu_state; + __u64 num; }; }; =20 diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index ebfd504a1c08..3f532e1c4a95 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -1387,6 +1387,9 @@ long kvm_arch_vcpu_ioctl(struct file *filp, =20 return kvm_arm_vcpu_finalize(vcpu, what); } + case KVM_ARM_SDEI_COMMAND: { + return kvm_sdei_vcpu_ioctl(vcpu, arg); + } default: r =3D -EINVAL; } diff --git a/arch/arm64/kvm/sdei.c b/arch/arm64/kvm/sdei.c index d9cf494990a9..06895ac73c24 100644 --- a/arch/arm64/kvm/sdei.c +++ b/arch/arm64/kvm/sdei.c @@ -1567,6 +1567,305 @@ long kvm_sdei_vm_ioctl(struct kvm *kvm, unsigned lo= ng arg) return ret; } =20 +static long vcpu_ioctl_get_vcpu_event(struct kvm_vcpu *vcpu, + struct kvm_sdei_cmd *cmd) +{ + struct kvm_sdei_vcpu *vsdei =3D vcpu->arch.sdei; + struct kvm_sdei_vcpu_event *vcpu_event; + struct kvm_sdei_vcpu_event_state *state; + void __user *user_state =3D (void __user *)(cmd->vcpu_event_state); + unsigned int count, i; + long ret =3D 0; + + if (!cmd->count) + return 0; + + state =3D kcalloc(cmd->count, sizeof(*state), GFP_KERNEL_ACCOUNT); + if (!state) + return -ENOMEM; + + i =3D 0; + count =3D cmd->count; + list_for_each_entry(vcpu_event, &vsdei->critical_events, link) { + state[i++] =3D vcpu_event->state; + if (!--count) + break; + } + + if (count) { + list_for_each_entry(vcpu_event, &vsdei->normal_events, link) { + state[i++] =3D vcpu_event->state; + if (!--count) + break; + } + } + + if (copy_to_user(user_state, state, sizeof(*state) * cmd->count)) + ret =3D -EFAULT; + + kfree(state); + return ret; +} + +static long vcpu_ioctl_set_vcpu_event(struct kvm_vcpu *vcpu, + struct kvm_sdei_cmd *cmd) +{ + struct kvm *kvm =3D vcpu->kvm; + struct kvm_sdei_vcpu *vsdei =3D vcpu->arch.sdei; + struct kvm_sdei_exposed_event *exposed_event; + struct kvm_sdei_registered_event *registered_event; + struct kvm_sdei_vcpu_event *vcpu_event; + struct kvm_sdei_vcpu_event_state *state; + void __user *user_state =3D (void __user *)(cmd->vcpu_event_state); + unsigned int vcpu_event_count, i, j; + long ret =3D 0; + + if (!cmd->count) + return 0; + + state =3D kcalloc(cmd->count, sizeof(*state), GFP_KERNEL_ACCOUNT); + if (!state) + return -ENOMEM; + + if (copy_from_user(state, user_state, sizeof(*state) * cmd->count)) { + ret =3D -EFAULT; + goto out; + } + + vcpu_event_count =3D vsdei->critical_event_count + + vsdei->normal_event_count; + for (i =3D 0; i < cmd->count; i++) { + if (!kvm_sdei_is_supported(state[i].num)) { + ret =3D -EINVAL; + goto out; + } + + /* Check if the event has been exposed */ + exposed_event =3D find_exposed_event(kvm, state[i].num); + if (!exposed_event) { + ret =3D -ENOENT; + goto out; + } + + /* Check if the event has been registered */ + registered_event =3D find_registered_event(kvm, state[i].num); + if (!registered_event) { + ret =3D -ENOENT; + goto out; + } + + /* + * Calculate the total count of the vcpu event instances. + * We needn't a new vcpu event instance if it is existing + * or a duplicated event. + */ + vcpu_event =3D find_vcpu_event(vcpu, state[i].num); + if (vcpu_event) + continue; + + for (j =3D 0; j < cmd->count; j++) { + if (j !=3D i && state[j].num =3D=3D state[i].num) + break; + } + + if (j >=3D cmd->count || i < j) + vcpu_event_count++; + } + + /* + * Check if the required count of vcpu event instances exceeds + * the limit. + */ + if (vcpu_event_count > KVM_SDEI_MAX_EVENTS) { + ret =3D -ERANGE; + goto out; + } + + for (i =3D 0; i < cmd->count; i++) { + /* The vcpu event might have been existing */ + vcpu_event =3D find_vcpu_event(vcpu, state[i].num); + if (vcpu_event) { + vcpu_event->state.event_count +=3D state[i].event_count; + continue; + } + + vcpu_event =3D kzalloc(sizeof(*vcpu_event), GFP_KERNEL_ACCOUNT); + if (!vcpu_event) { + ret =3D -ENOMEM; + goto out; + } + + registered_event =3D find_registered_event(kvm, state[i].num); + exposed_event =3D registered_event->exposed_event; + + vcpu_event->state =3D state[i]; + vcpu_event->registered_event =3D registered_event; + vcpu_event->vcpu =3D vcpu; + + registered_event->vcpu_event_count++; + if (kvm_sdei_is_critical(exposed_event->state.priority)) { + list_add_tail(&vcpu_event->link, + &vsdei->critical_events); + vsdei->critical_event_count++; + } else { + list_add_tail(&vcpu_event->link, + &vsdei->normal_events); + vsdei->normal_event_count++; + } + } + +out: + kfree(state); + return ret; +} + +static long vcpu_ioctl_set_vcpu_state(struct kvm_vcpu *vcpu, + struct kvm_sdei_cmd *cmd) +{ + struct kvm_sdei_vcpu *vsdei =3D vcpu->arch.sdei; + struct kvm_sdei_vcpu_event *critical_vcpu_event =3D NULL; + struct kvm_sdei_vcpu_event *normal_vcpu_event =3D NULL; + struct kvm_sdei_vcpu_state *state; + void __user *user_state =3D (void __user *)(cmd->vcpu_state); + long ret =3D 0; + + state =3D kzalloc(sizeof(*state), GFP_KERNEL_ACCOUNT); + if (!state) + return -ENOMEM; + + if (copy_from_user(state, user_state, sizeof(*state))) { + ret =3D -EFAULT; + goto out; + } + + if (kvm_sdei_is_supported(state->critical_num)) { + critical_vcpu_event =3D find_vcpu_event(vcpu, + state->critical_num); + if (!critical_vcpu_event) { + ret =3D -EINVAL; + goto out; + } + } + + if (kvm_sdei_is_supported(state->normal_num)) { + normal_vcpu_event =3D find_vcpu_event(vcpu, state->normal_num); + if (!normal_vcpu_event) { + ret =3D -EINVAL; + goto out; + } + } + + vsdei->state =3D *state; + vsdei->critical_event =3D critical_vcpu_event; + vsdei->normal_event =3D normal_vcpu_event; + + /* + * To deliver the vCPU events if we don't have a valid handler + * running. Otherwise, the vCPU events should be delivered when + * the running handler is completed. + */ + if (!vsdei->critical_event && !vsdei->normal_event && + (vsdei->critical_event_count + vsdei->normal_event_count) > 0) + kvm_make_request(KVM_REQ_SDEI, vcpu); + +out: + kfree(state); + return ret; +} + +static long vcpu_ioctl_inject_event(struct kvm_vcpu *vcpu, + struct kvm_sdei_cmd *cmd) +{ + struct kvm *kvm =3D vcpu->kvm; + struct kvm_sdei_vcpu *vsdei =3D vcpu->arch.sdei; + struct kvm_sdei_exposed_event *exposed_event; + struct kvm_sdei_registered_event *registered_event; + int index; + + if (!kvm_sdei_is_supported(cmd->num)) + return -EINVAL; + + registered_event =3D find_registered_event(kvm, cmd->num); + if (!registered_event) + return -ENOENT; + + exposed_event =3D registered_event->exposed_event; + index =3D kvm_sdei_vcpu_index(vcpu, exposed_event); + if (!kvm_sdei_is_registered(registered_event, index) || + !kvm_sdei_is_enabled(registered_event, index) || + kvm_sdei_is_unregister_pending(registered_event, index)) + return -EPERM; + + if (vsdei->state.masked) + return -EPERM; + + return do_inject_event(vcpu, registered_event, false); +} + +long kvm_sdei_vcpu_ioctl(struct kvm_vcpu *vcpu, unsigned long arg) +{ + struct kvm *kvm =3D vcpu->kvm; + struct kvm_sdei_kvm *ksdei =3D kvm->arch.sdei; + struct kvm_sdei_vcpu *vsdei =3D vcpu->arch.sdei; + struct kvm_sdei_cmd *cmd =3D NULL; + void __user *argp =3D (void __user *)arg; + long ret =3D 0; + + if (!(ksdei && vsdei)) { + ret =3D -EPERM; + goto out; + } + + cmd =3D kzalloc(sizeof(*cmd), GFP_KERNEL_ACCOUNT); + if (!cmd) { + ret =3D -ENOMEM; + goto out; + } + + if (copy_from_user(cmd, argp, sizeof(*cmd))) { + ret =3D -EFAULT; + goto out; + } + + spin_lock(&ksdei->lock); + spin_lock(&vsdei->lock); + + switch (cmd->cmd) { + case KVM_SDEI_CMD_GET_VCPU_EVENT_COUNT: + cmd->count =3D vsdei->critical_event_count + + vsdei->normal_event_count; + if (copy_to_user(argp, cmd, sizeof(*cmd))) + ret =3D -EFAULT; + break; + case KVM_SDEI_CMD_GET_VCPU_EVENT: + ret =3D vcpu_ioctl_get_vcpu_event(vcpu, cmd); + break; + case KVM_SDEI_CMD_SET_VCPU_EVENT: + ret =3D vcpu_ioctl_set_vcpu_event(vcpu, cmd); + break; + case KVM_SDEI_CMD_GET_VCPU_STATE: + if (copy_to_user(cmd->vcpu_state, &vsdei->state, + sizeof(vsdei->state))) + ret =3D -EFAULT; + break; + case KVM_SDEI_CMD_SET_VCPU_STATE: + ret =3D vcpu_ioctl_set_vcpu_state(vcpu, cmd); + break; + case KVM_SDEI_CMD_INJECT_EVENT: + ret =3D vcpu_ioctl_inject_event(vcpu, cmd); + break; + default: + ret =3D -EINVAL; + } + + spin_unlock(&vsdei->lock); + spin_unlock(&ksdei->lock); + +out: + kfree(cmd); + return ret; +} + void kvm_sdei_destroy_vcpu(struct kvm_vcpu *vcpu) { struct kvm *kvm =3D vcpu->kvm; --=20 2.23.0 From nobody Mon Jun 22 14:25:00 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B2E57C433EF for ; Tue, 22 Mar 2022 08:11:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230213AbiCVIMh (ORCPT ); Tue, 22 Mar 2022 04:12:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37518 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230181AbiCVIMb (ORCPT ); Tue, 22 Mar 2022 04:12:31 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 3E32C1A816 for ; Tue, 22 Mar 2022 01:11:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1647936662; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=njjwnGmzLURai6W3k0QTeK0O5fDkMxYNSy6QT89iDAo=; b=jM8eeUABS7botPkTe078lC0jrLmRLHH5jIWOCv0qB8nsbploHPnKPC+NQnvJIjptcf8Cb9 wb++4NrFa/N97hv7OSDiQZBBo8eEGOzTztRMtBeZzw95KYMSyXRWOEZrEfbXIoTEbsiSOt Q9PiM9F40IyqMkH9ZTEQWNq9IyDa58E= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-544-m6f8b7VAMv6Rt9_3hYWHEA-1; Tue, 22 Mar 2022 04:10:59 -0400 X-MC-Unique: m6f8b7VAMv6Rt9_3hYWHEA-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 8B98328035E3; Tue, 22 Mar 2022 08:10:58 +0000 (UTC) Received: from gshan.redhat.com (ovpn-12-33.pek2.redhat.com [10.72.12.33]) by smtp.corp.redhat.com (Postfix) with ESMTPS id E156A1121324; Tue, 22 Mar 2022 08:10:52 +0000 (UTC) From: Gavin Shan To: kvmarm@lists.cs.columbia.edu Cc: linux-kernel@vger.kernel.org, eauger@redhat.com, shannon.zhaosl@gmail.com, maz@kernel.org, Jonathan.Cameron@huawei.com, will@kernel.org, pbonzini@redhat.com, james.morse@arm.com, mark.rutland@arm.com, drjones@redhat.com, vkuznets@redhat.com, shan.gavin@gmail.com Subject: [PATCH v5 20/22] KVM: arm64: Export SDEI capability Date: Tue, 22 Mar 2022 16:07:08 +0800 Message-Id: <20220322080710.51727-21-gshan@redhat.com> In-Reply-To: <20220322080710.51727-1-gshan@redhat.com> References: <20220322080710.51727-1-gshan@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" The SDEI functionality is ready to be exported so far. This adds new capability (KVM_CAP_ARM_SDEI) and exports it. Signed-off-by: Gavin Shan --- Documentation/virt/kvm/api.rst | 10 ++++++++++ arch/arm64/kvm/arm.c | 3 +++ include/uapi/linux/kvm.h | 1 + 3 files changed, 14 insertions(+) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 9f3172376ec3..06cf27f37b4d 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -7575,3 +7575,13 @@ The argument to KVM_ENABLE_CAP is also a bitmask, an= d must be a subset of the result of KVM_CHECK_EXTENSION. KVM will forward to userspace the hypercalls whose corresponding bit is in the argument, and return ENOSYS for the others. + +8.35 KVM_CAP_ARM_SDEI +--------------------- + +:Capability: KVM_CAP_ARM_SDEI +:Architectures: arm64 + +This capability indicates that the SDEI virtual service is supported +in the host. A VMM can check whether the service is available to enable +it. diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 3f532e1c4a95..ae3b53dfe88f 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -282,6 +282,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long = ext) case KVM_CAP_ARM_PTRAUTH_GENERIC: r =3D system_has_full_ptr_auth(); break; + case KVM_CAP_ARM_SDEI: + r =3D 1; + break; default: r =3D 0; } diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 2d11c909ec42..5772385639b8 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1135,6 +1135,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_XSAVE2 208 #define KVM_CAP_SYS_ATTRIBUTES 209 #define KVM_CAP_PPC_AIL_MODE_3 210 +#define KVM_CAP_ARM_SDEI 211 =20 #ifdef KVM_CAP_IRQ_ROUTING =20 --=20 2.23.0 From nobody Mon Jun 22 14:25:00 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id DAF09C433F5 for ; Tue, 22 Mar 2022 08:11:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230189AbiCVINH (ORCPT ); Tue, 22 Mar 2022 04:13:07 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38840 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230242AbiCVIMy (ORCPT ); Tue, 22 Mar 2022 04:12:54 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 7BF20DF03 for ; Tue, 22 Mar 2022 01:11:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1647936686; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=fBBhLhLF48pyJ0vNP0OdtcJfMpQ+vVDcYKgHhm2JbtU=; b=fMBdRthti3KsY6mSVzah4Z6lSwJVlcf3UiVuZ+9G7Ow/mHlNj4i04yAMEllNDxZ/Ag7YWv gNJlc5qM9nqhhuXWIqYtwVcxSINSKPyGl3j3RmXWbZg+No3wfKzxC/eccPYo9TaDN4SJBM eM1wsOwxdcb+VbS1/bu9ABKvbA4BN2E= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-392-aspAOXk6Pe6Ssjy2ZTO9gg-1; Tue, 22 Mar 2022 04:11:23 -0400 X-MC-Unique: aspAOXk6Pe6Ssjy2ZTO9gg-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id B40B63C01C17; Tue, 22 Mar 2022 08:11:22 +0000 (UTC) Received: from gshan.redhat.com (ovpn-12-33.pek2.redhat.com [10.72.12.33]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 4212C1121324; Tue, 22 Mar 2022 08:10:58 +0000 (UTC) From: Gavin Shan To: kvmarm@lists.cs.columbia.edu Cc: linux-kernel@vger.kernel.org, eauger@redhat.com, shannon.zhaosl@gmail.com, maz@kernel.org, Jonathan.Cameron@huawei.com, will@kernel.org, pbonzini@redhat.com, james.morse@arm.com, mark.rutland@arm.com, drjones@redhat.com, vkuznets@redhat.com, shan.gavin@gmail.com Subject: [PATCH v5 21/22] KVM: arm64: Add SDEI document Date: Tue, 22 Mar 2022 16:07:09 +0800 Message-Id: <20220322080710.51727-22-gshan@redhat.com> In-Reply-To: <20220322080710.51727-1-gshan@redhat.com> References: <20220322080710.51727-1-gshan@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This adds one document to explain how virtualized SDEI service is implemented and supported. Signed-off-by: Gavin Shan --- Documentation/virt/kvm/arm/sdei.rst | 325 ++++++++++++++++++++++++++++ 1 file changed, 325 insertions(+) create mode 100644 Documentation/virt/kvm/arm/sdei.rst diff --git a/Documentation/virt/kvm/arm/sdei.rst b/Documentation/virt/kvm/a= rm/sdei.rst new file mode 100644 index 000000000000..61213e4b9aea --- /dev/null +++ b/Documentation/virt/kvm/arm/sdei.rst @@ -0,0 +1,325 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +SDEI Virtualization Support for ARM64 +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Arm specification DEN0054/C defines Software Delegated Exception Interface +(SDEI). It provides a mechanism for registering and servicing system events +from system firmware. The interface is offered by a higher exception level +to a lower exception level, in other words by a secure platform firmware +to hypervisor or hypervisor to OS or both. + +https://developer.arm.com/documentation/den0054/c + +KVM/arm64 implements the defined hypercalls in the specification so that +the system events can be registered and serviced from KVM hypervisor to +the guest OS. + +SDEI Event Management +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Each SDEI event is associated and identified with a 32-bit number. The +lower 24-bits is the event number, but other bits are reserved or used +for vendor defined events. In KVM/arm64 implementation, bit 22 and 23 +are further reserved to identify the events visible to the implementation. +Value 0x1 should be seen in this field for those KVM/arm64 visible events. +In the meanwhile, event number 0x0 is also supported since it is used by +SDEI_EVENT_SIGNAL hypercall. + +The SDEI event needs to be exposed through ioctl interface by VMM to +hypervisor before the guest is able to register it. The exposed event +is represented by ``struct kvm_sdei_exposed_event``. The registered event +is represented by ``struct kvm_sdei_registered_event``, whose instances +are created on SDEI_EVENT_REGISTER hypercall. There is only one registered +event instance in one particular VM no matter what event type is. The +registered event can be injected and delivered to one specific vcpu in +forms of vcpu event. ``struct kvm_sdei_vcpu_event`` describes vcpu events. +On the particular vcpu, one vcpu event instance can be shared by multiple +events. + +The execution runs into SDEI context when vcpu event is handled. The +interrupted or preempted context should be saved to vcpu state, which +is represented by ``struct kvm_sdei_vcpu``. After that, the SDEI event +handler, which was provided by SDEI_EVENT_REGISTER hypercall is invoked. +SDEI_EVENT_COMPLETE or SDEI_EVENT_COMPLETE_AND_RESUME hypercall must be +issued before the SDEI event handler is to complete. When one of these +two hypercalls is received, the interrupted or preempted context is +restored from vcpu state for execution. + +When migration happens, the status of one particular SDEI event is not +deterministic. So we need to support migration for the aforementioned +structures or objects. The information capable of migration in these +objects are put into separate data structures, which are the corresponding +state variant in kvm_sdei_state.h. Besides, ioctl command are introduced +to read and write them on the source and destination VM during migration. + +IOCTL Commands +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +KVM_ARM_SDEI_COMMAND +-------------------- + +:Capability: KVM_CAP_ARM_SDEI +:Type: vm ioctl, vcpu ioctl +:Parameters: struct kvm_sdei_cmd +:Returns: 0 on success, < 0 on error + +:: + + struct kvm_sdei_cmd { + __u32 cmd; + union { + __u32 version; + __u32 count; + }; + union { + struct kvm_sdei_exposed_event_state *exposed_event_state; + struct kvm_sdei_registered_event_state *registered_event_stat= e; + struct kvm_sdei_vcpu_event_state *vcpu_event_state; + struct kvm_sdei_vcpu_state *vcpu_state; + __u64 num; + }; + }; + +The SDEI ioctl command is identified by KVM_ARM_SDEI_COMMAND and ``cmd`` +in the argument ``struct kvm_sdei_cmd`` provides further command to be +executed. + +KVM_SDEI_CMD_GET_VERSION +------------------------ + +:Type: vm ioctl +:Parameters: struct kvm_sdei_cmd +:Returns: 0 on success, < 0 on error + +On success, the implementation version is returned in ``version`` of +``struct kvm_sdei_cmd``. This version is different from that of the +followed SDEI specification. The implementation version is used to tell +the coherence extent to the following specification. For example, the +SDEI interrupt binding event is defined in SDEI v1.1 specification, +but it is not supported in current implementation. + +KVM_SDEI_CMD_GET_EXPOSED_EVENT_COUNT +------------------------------------ + +:Type: vm ioctl +:Parameters: struct kvm_sdei_cmd +:Returns: 0 on success, < 0 on error + +This ioctl command is used prior to KVM_SDEI_CMD_GET_EXPOSED_EVENT, to +prepare ``exposed_event_state`` of ``struct kvm_sdei_cmd`` for that +command during migration. + +On success, the number of exposed events is returned by ``count`` +of ``struct kvm_sdei_cmd``. + +KVM_SDEI_CMD_GET_EXPOSED_EVENT +------------------------------ + +:Type: vm ioctl +:Parameters: struct kvm_sdei_cmd, struct kvm_sdei_exposed_event_state +:Returns: 0 on success, < 0 on error + +:: + + struct kvm_sdei_exposed_event_state { + __u64 num; + + __u8 type; + __u8 signaled; + __u8 priority; + __u8 padding[5]; + __u64 notifier; + }; + +This ioctl command is used to retrieve the exposed events on the source +VM during migration. + +The number of exposed events to be retrieved is specified by ``count`` +of ``struct kvm_sdei_cmd``. On success, the retrieved exposed events are +returned by ``exposed_event_state`` of ``struct kvm_sdei_state``. + +KVM_SDEI_CMD_SET_EXPOSED_EVENT +------------------------------ + +:Type: vm ioctl +:Parameters: struct kvm_sdei_cmd, struct kvm_sdei_exposed_event_state +:Returns: 0 on success, < 0 on error + +This ioctl command is used by VMM to expose SDEI events and migrate +them. The ``notifier`` of ``struct kvm_sdei_exposed_event_state`` +will be modified if the specified exposed event has been existing. + +The number of events to be exposed is specified by ``count`` of +``struct kvm_sdei_cmd``. The information about the exposed events is +passed by ``exposed_event_state`` of ``struct kvm_sdei_cmd``. + +KVM_SDEI_CMD_GET_REGISTERED_EVENT_COUNT +--------------------------------------- + +:Type: vm ioctl +:Parameters: struct kvm_sdei_cmd +:Returns: 0 on success, < 0 on error + +This ioctl command is used prior to KVM_SDEI_CMD_GET_REGISTERED_EVENT, +to prepare ``registered_event_state`` of ``struct kvm_sdei_cmd`` for +that command during migration. + +On success, the number of registered events is returned by ``count`` +of ``struct kvm_sdei_cmd``. + +KVM_SDEI_CMD_GET_REGISTERED_EVENT +--------------------------------- + +:Type: vm ioctl +:Parameters: struct kvm_sdei_cmd, struct kvm_sdei_registered_event_state +:Returns: 0 on success, < 0 on error + +:: + struct kvm_sdei_registered_event_state { + __u64 num; + + __u8 route_mode; + __u8 padding[3]; + __u64 route_affinity; + __u64 ep_address[KVM_SDEI_MAX_VCPUS]; + __u64 ep_arg[KVM_SDEI_MAX_VCPUS]; + __u64 registered[KVM_SDEI_MAX_VCPUS/64]; + __u64 enabled[KVM_SDEI_MAX_VCPUS/64]; + __u64 unregister_pending[KVM_SDEI_MAX_VCPUS/64]; + }; + +This ioctl command is used to retrieve the registered events on the +source VM during migration. + +The number of registered events to be retrieved is specified by ``count`` +of ``struct kvm_sdei_cmd``. On success, the retrieved registered events +are returned by ``registered_event_state`` of ``struct kvm_sdei_state``. + +KVM_SDEI_CMD_SET_REGISTERED_EVENT +--------------------------------- + +:Type: vm ioctl +:Parameters: struct kvm_sdei_cmd, struct kvm_sdei_registered_event_state +:Returns: 0 on success, < 0 on error + +This ioctl command is used by VMM to migrate the registered events +on the destination VM. + +The number of events to be registered is specified by ``count`` of +``struct kvm_sdei_cmd``. The information about the registered events +is passed by ``registered_event_state`` of ``struct kvm_sdei_cmd``. + +KVM_SDEI_CMD_GET_VCPU_EVENT_COUNT +--------------------------------- + +:Type: vcpu ioctl +:Parameters: struct kvm_sdei_cmd +:Returns: 0 on success, < 0 on error + +This ioctl command is used prior to KVM_SDEI_CMD_GET_VCPU_EVENT, to +prepare ``vcpu_event_state`` of ``struct kvm_sdei_cmd`` for that +command during migration. + +On success, the number of vcpu events is returned by ``count`` +of ``struct kvm_sdei_cmd``. + +KVM_SDEI_CMD_GET_VCPU_EVENT +--------------------------- + +:Type: vcpu ioctl +:Parameters: struct kvm_sdei_cmd, struct kvm_sdei_vcpu_event_state +:Returns: 0 on success, < 0 on error + +:: + + struct kvm_sdei_vcpu_event_state { + __u64 num; + + __u32 event_count; + __u32 padding; + }; + +This ioctl command is used to retrieve the vcpu events on the source +VM during migration. + +The number of vcpu events to be retrieved is specified by ``count`` of +``struct kvm_sdei_cmd``. On success, the retrieved exposed events are +returned by ``vcpu_event_state`` of ``struct kvm_sdei_state``. + +KVM_SDEI_CMD_SET_VCPU_EVENT +--------------------------- + +:Type: vcpu ioctl +:Parameters: struct kvm_sdei_cmd, struct kvm_sdei_vcpu_event_state +:Returns: 0 on success, < 0 on error + +This ioctl command is used by VMM to migrate the vcpu events on the +destination VM. + +The number of vcpu events to be added is specified by ``count`` of +``struct kvm_sdei_cmd``. The information about the vcpu events is +passed by ``vcpu_event_state`` of ``struct kvm_sdei_cmd``. + +KVM_SDEI_CMD_GET_VCPU_STATE +--------------------------- + +:Type: vcpu ioctl +:Parameters: struct kvm_sdei_cmd, struct kvm_sdei_vcpu_state +:Returns: 0 on success, < 0 on error + +:: + + struct kvm_sdei_vcpu_regs_state { + __u64 regs[18]; + __u64 pc; + __u64 pstate; + }; + + struct kvm_sdei_vcpu_state { + __u8 masked; + __u8 padding[7]; + __u64 critical_num; + __u64 normal_num; + struct kvm_sdei_vcpu_regs_state critical_regs; + struct kvm_sdei_vcpu_regs_state normal_regs; + }; + +This ioctl command is used to retrieve the vcpu state on the source VM +during migration. + +On success, the current vcpu state is returned by ``vcpu_state`` of +``struct kvm_sdei_cmd``. + +KVM_SDEI_CMD_SET_VCPU_STATE +--------------------------- + +:Type: vcpu ioctl +:Parameters: struct kvm_sdei_cmd, struct kvm_sdei_vcpu_state +:Returns: 0 on success, < 0 on error + +This ioctl command is used by VMM to migrate the vcpu state on the +destination VM. + +The vcpu state to be configured is passed by ``vcpu_state`` of +``struct kvm_sdei_cmd``. + +KVM_SDEI_CMD_INJECT_EVENT +------------------------- + +:Type: vcpu ioctl +:Parameters: struct kvm_sdei_cmd, struct kvm_sdei_vcpu_state +:Returns: 0 on success, < 0 on error + +This ioctl command is used by VMM to inject SDEI event to the specified +vcpu. + +The number of the SDEI event to be injected is passed by ``num`` of +``struct kvm_sdei_cmd``. + +Future Work +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +1. Support the routing mode and affinity for the shared events. +2. Support interrupt binding events. --=20 2.23.0 From nobody Mon Jun 22 14:25:00 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7FE06C4332F for ; Tue, 22 Mar 2022 08:12:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230232AbiCVIN0 (ORCPT ); Tue, 22 Mar 2022 04:13:26 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39352 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230199AbiCVINZ (ORCPT ); Tue, 22 Mar 2022 04:13:25 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 7E7CD16590 for ; Tue, 22 Mar 2022 01:11:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1647936716; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=SuoNHRzUPWWhkYa3DBe2wOhzLsIQa6xM5wffndPFSig=; b=SVLivOm1kZ/ca3JWgbmfdq1BI2Cb6pqJP55ehsW93fai4E+ELwwwCD+5YFOhWD0hGKQ/AG S2nfCeDTQBeOix+1jtpy4D5dhKsP0r0vn9/PWOEH0H6x3gtfvZ1Lnn+BO3P9Q7BBNZJXj6 zztK07sSH9SIF7Om5mkfcRMmGZHDiIQ= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-45-OgXkFtI9OKmju0xspCIjXQ-1; Tue, 22 Mar 2022 04:11:53 -0400 X-MC-Unique: OgXkFtI9OKmju0xspCIjXQ-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 0DB32802809; Tue, 22 Mar 2022 08:11:53 +0000 (UTC) Received: from gshan.redhat.com (ovpn-12-33.pek2.redhat.com [10.72.12.33]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 83A221121324; Tue, 22 Mar 2022 08:11:23 +0000 (UTC) From: Gavin Shan To: kvmarm@lists.cs.columbia.edu Cc: linux-kernel@vger.kernel.org, eauger@redhat.com, shannon.zhaosl@gmail.com, maz@kernel.org, Jonathan.Cameron@huawei.com, will@kernel.org, pbonzini@redhat.com, james.morse@arm.com, mark.rutland@arm.com, drjones@redhat.com, vkuznets@redhat.com, shan.gavin@gmail.com Subject: [PATCH v5 22/22] KVM: selftests: Add SDEI test case Date: Tue, 22 Mar 2022 16:07:10 +0800 Message-Id: <20220322080710.51727-23-gshan@redhat.com> In-Reply-To: <20220322080710.51727-1-gshan@redhat.com> References: <20220322080710.51727-1-gshan@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This adds SDEI self-test case where the various hypercalls are issued to default event (0x0). The default event is private, signaled and in normal priority. By default, two vCPUs are started and the following ioctl commands or hypercalls are sent to them in sequence, to simulate how they are used in VMM and the linux guest: kvm_check_cap(KVM_CAP_ARM_SDEI) KVM_SDEI_CMD_GET_VERSION KVM_SDEI_CMD_SET_EXPOSED_EVENT (expose event) SDEI_1_0_FN_SDEI_VERSION SDEI_1_1_FN_SDEI_FEATURES (SDEI capability probing) SDEI_1_0_FN_SDEI_SHARED_RESET (restart SDEI) SDEI_1_0_FN_SDEI_PE_UNMASK (CPU online) SDEI_1_0_FN_SDEI_EVENT_GET_INFO SDEI_1_0_FN_SDEI_EVENT_REGISTER (register event) SDEI_1_0_FN_SDEI_EVENT_ENABLE (enable event) SDEI_1_1_FN_SDEI_EVENT_SIGNAL (event injection) SDEI_1_0_FN_SDEI_EVENT_DISABLE (disable event) SDEI_1_0_FN_SDEI_EVENT_UNREGISTER (unregister event) SDEI_1_0_FN_SDEI_PE_MASK (CPU offline) Signed-off-by: Gavin Shan --- tools/testing/selftests/kvm/Makefile | 1 + tools/testing/selftests/kvm/aarch64/sdei.c | 525 +++++++++++++++++++++ 2 files changed, 526 insertions(+) create mode 100644 tools/testing/selftests/kvm/aarch64/sdei.c diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests= /kvm/Makefile index 17c3f0749f05..4e4c03cc316b 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -105,6 +105,7 @@ TEST_GEN_PROGS_aarch64 +=3D aarch64/get-reg-list TEST_GEN_PROGS_aarch64 +=3D aarch64/psci_cpu_on_test TEST_GEN_PROGS_aarch64 +=3D aarch64/vgic_init TEST_GEN_PROGS_aarch64 +=3D aarch64/vgic_irq +TEST_GEN_PROGS_aarch64 +=3D aarch64/sdei TEST_GEN_PROGS_aarch64 +=3D demand_paging_test TEST_GEN_PROGS_aarch64 +=3D dirty_log_test TEST_GEN_PROGS_aarch64 +=3D dirty_log_perf_test diff --git a/tools/testing/selftests/kvm/aarch64/sdei.c b/tools/testing/sel= ftests/kvm/aarch64/sdei.c new file mode 100644 index 000000000000..2a7d816ce438 --- /dev/null +++ b/tools/testing/selftests/kvm/aarch64/sdei.c @@ -0,0 +1,525 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ARM SDEI test + * + * Copyright (C) 2022 Red Hat, Inc. + * + * Author(s): Gavin Shan + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "kvm_util.h" +#include "processor.h" +#include "linux/arm_sdei.h" +#include "asm/kvm_sdei_state.h" + +#define NR_VCPUS 2 +#define SDEI_EVENT_NUM KVM_SDEI_DEFAULT_EVENT + +#define VCPU_COMMAND_IDLE 0 +#define VCPU_COMMAND_EXIT 1 + +struct vcpu_command { + const char *name; + uint64_t command; +}; + +struct sdei_feature { + uint16_t shared_slots; + uint16_t private_slots; + uint8_t relative_mode; +}; + +struct sdei_event_info { + uint8_t type; + uint8_t priority; + uint8_t signaled; +}; + +struct sdei_event_signal { + uint8_t handled; + uint8_t irq; + uint64_t status; + uint64_t pc; + uint64_t pstate; + uint64_t regs[18]; +}; + +struct sdei_state { + uint64_t command; + uint64_t num; + uint64_t status; + union { + uint64_t version; + struct sdei_feature feature; + struct sdei_event_info info; + struct sdei_event_signal signal; + }; + + uint8_t command_completed; +}; + +struct vcpu_state { + struct kvm_vm *vm; + uint32_t vcpu_id; + pthread_t thread; + struct sdei_state state; +}; + +static struct vcpu_state vcpu_states[NR_VCPUS]; +static struct vcpu_command vcpu_commands[] =3D { + { "VERSION", SDEI_1_0_FN_SDEI_VERSION }, + { "FEATURES", SDEI_1_1_FN_SDEI_FEATURES }, + { "PRIVATE_RESET", SDEI_1_0_FN_SDEI_PRIVATE_RESET }, + { "SHARED_RESET", SDEI_1_0_FN_SDEI_SHARED_RESET }, + { "PE_UNMASK", SDEI_1_0_FN_SDEI_PE_UNMASK }, + { "EVENT_GET_INFO", SDEI_1_0_FN_SDEI_EVENT_GET_INFO }, + { "EVENT_REGISTER", SDEI_1_0_FN_SDEI_EVENT_REGISTER }, + { "EVENT_ENABLE", SDEI_1_0_FN_SDEI_EVENT_ENABLE }, + { "EVENT_SIGNAL", SDEI_1_1_FN_SDEI_EVENT_SIGNAL }, + { "PE_MASK", SDEI_1_0_FN_SDEI_PE_MASK }, + { "EVENT_DISABLE", SDEI_1_0_FN_SDEI_EVENT_DISABLE }, + { "EVENT_UNREGISTER", SDEI_1_0_FN_SDEI_EVENT_UNREGISTER }, +}; + +static inline int64_t smccc(uint32_t func, uint64_t arg0, uint64_t arg1, + uint64_t arg2, uint64_t arg3, uint64_t arg4) +{ + int64_t ret; + + asm volatile ( + "mov x0, %1\n" + "mov x1, %2\n" + "mov x2, %3\n" + "mov x3, %4\n" + "mov x4, %5\n" + "mov x5, %6\n" + "hvc #0\n" + "mov %0, x0\n" + : "=3Dr" (ret) : "r" (func), "r" (arg0), "r" (arg1), + "r" (arg2), "r" (arg3), "r" (arg4) : + "x0", "x1", "x2", "x3", "x4", "x5"); + + return ret; +} + +static inline bool is_error(int64_t status) +{ + if (status =3D=3D SDEI_NOT_SUPPORTED || + status =3D=3D SDEI_INVALID_PARAMETERS || + status =3D=3D SDEI_DENIED || + status =3D=3D SDEI_PENDING || + status =3D=3D SDEI_OUT_OF_RESOURCE) + return true; + + return false; +} + +static void guest_irq_handler(struct ex_regs *regs) +{ + int vcpu_id =3D guest_get_vcpuid(); + struct sdei_state *state =3D &vcpu_states[vcpu_id].state; + + WRITE_ONCE(state->signal.irq, true); +} + +static void sdei_event_handler(uint64_t num, uint64_t arg, + uint64_t pc, uint64_t pstate) +{ + struct sdei_state *state =3D (struct sdei_state *)arg; + uint64_t status; + + status =3D smccc(SDEI_1_0_FN_SDEI_EVENT_STATUS, num, 0, 0, 0, 0); + WRITE_ONCE(state->signal.status, status); + + WRITE_ONCE(state->signal.pc, pc); + WRITE_ONCE(state->signal.pstate, pstate); + + status =3D smccc(SDEI_1_0_FN_SDEI_EVENT_CONTEXT, 0, 0, 0, 0, 0); + WRITE_ONCE(state->signal.regs[0], status); + status =3D smccc(SDEI_1_0_FN_SDEI_EVENT_CONTEXT, 1, 0, 0, 0, 0); + WRITE_ONCE(state->signal.regs[1], status); + status =3D smccc(SDEI_1_0_FN_SDEI_EVENT_CONTEXT, 2, 0, 0, 0, 0); + WRITE_ONCE(state->signal.regs[2], status); + status =3D smccc(SDEI_1_0_FN_SDEI_EVENT_CONTEXT, 3, 0, 0, 0, 0); + WRITE_ONCE(state->signal.regs[3], status); + + WRITE_ONCE(state->signal.handled, true); + smccc(SDEI_1_0_FN_SDEI_EVENT_COMPLETE_AND_RESUME, + num, 0, 0, 0, 0); +} + +static bool sdei_event_wait(struct sdei_state *state, + uint64_t timeout_in_seconds) +{ + uint64_t limit, count =3D 0; + + limit =3D (timeout_in_seconds * 1000000) / 10; + + while (1) { + if (READ_ONCE(state->signal.handled)) + return true; + + if (++count >=3D limit) + return false; + + /* + * We issues HVC calls here to ensure the injected + * event can be delivered in time. + */ + smccc(SDEI_1_0_FN_SDEI_EVENT_GET_INFO, + READ_ONCE(state->num), SDEI_EVENT_INFO_EV_TYPE, + 0, 0, 0); + + usleep(10); + } + + return false; +} + +static void guest_code(int vcpu_id) +{ + struct sdei_state *state; + uint64_t command, last_command =3D -1UL, num, status; + + state =3D &vcpu_states[vcpu_id].state; + + while (1) { + command =3D READ_ONCE(state->command); + if (command =3D=3D last_command) + continue; + + num =3D READ_ONCE(state->num); + switch (command) { + case VCPU_COMMAND_IDLE: + WRITE_ONCE(state->status, SDEI_SUCCESS); + break; + case SDEI_1_0_FN_SDEI_VERSION: + status =3D smccc(command, 0, 0, 0, 0, 0); + WRITE_ONCE(state->status, status); + if (is_error(status)) + break; + + WRITE_ONCE(state->version, status); + break; + case SDEI_1_0_FN_SDEI_PRIVATE_RESET: + case SDEI_1_0_FN_SDEI_SHARED_RESET: + case SDEI_1_0_FN_SDEI_PE_UNMASK: + case SDEI_1_0_FN_SDEI_PE_MASK: + status =3D smccc(command, 0, 0, 0, 0, 0); + WRITE_ONCE(state->status, status); + break; + case SDEI_1_1_FN_SDEI_FEATURES: + status =3D smccc(command, 0, 0, 0, 0, 0); + WRITE_ONCE(state->status, status); + if (is_error(status)) + break; + + WRITE_ONCE(state->feature.shared_slots, + (status & 0xffff0000) >> 16); + WRITE_ONCE(state->feature.private_slots, + (status & 0x0000ffff)); + status =3D smccc(command, 1, 0, 0, 0, 0); + WRITE_ONCE(state->status, status); + if (is_error(status)) + break; + + WRITE_ONCE(state->feature.relative_mode, status); + break; + case SDEI_1_0_FN_SDEI_EVENT_GET_INFO: + status =3D smccc(command, num, + SDEI_EVENT_INFO_EV_TYPE, 0, 0, 0); + WRITE_ONCE(state->status, status); + if (is_error(status)) + break; + + WRITE_ONCE(state->info.type, status); + status =3D smccc(command, num, + SDEI_EVENT_INFO_EV_PRIORITY, 0, 0, 0); + WRITE_ONCE(state->status, status); + if (is_error(status)) + break; + + WRITE_ONCE(state->info.priority, status); + status =3D smccc(command, num, + SDEI_EVENT_INFO_EV_SIGNALED, 0, 0, 0); + if (is_error(status)) + break; + + WRITE_ONCE(state->info.signaled, status); + break; + case SDEI_1_0_FN_SDEI_EVENT_REGISTER: + status =3D smccc(command, num, + (uint64_t)sdei_event_handler, + (uint64_t)state, + SDEI_EVENT_REGISTER_RM_ANY, 0); + WRITE_ONCE(state->status, status); + break; + case SDEI_1_0_FN_SDEI_EVENT_ENABLE: + case SDEI_1_0_FN_SDEI_EVENT_DISABLE: + case SDEI_1_0_FN_SDEI_EVENT_UNREGISTER: + status =3D smccc(command, num, 0, 0, 0, 0); + WRITE_ONCE(state->status, status); + break; + case SDEI_1_1_FN_SDEI_EVENT_SIGNAL: + status =3D smccc(command, num, (uint64_t)state, 0, 0, 0); + WRITE_ONCE(state->status, status); + if (is_error(status)) + break; + + if (!sdei_event_wait(state, 5)) + WRITE_ONCE(state->status, SDEI_DENIED); + + break; + case VCPU_COMMAND_EXIT: + WRITE_ONCE(state->status, SDEI_SUCCESS); + GUEST_DONE(); + break; + default: + WRITE_ONCE(state->status, SDEI_INVALID_PARAMETERS); + } + + last_command =3D command; + WRITE_ONCE(state->command_completed, true); + } +} + +static void *vcpu_thread(void *arg) +{ + struct vcpu_state *state =3D arg; + + vcpu_run(state->vm, state->vcpu_id); + + return NULL; +} + +static bool vcpu_wait(struct kvm_vm *vm, int timeout_in_seconds) +{ + unsigned long count, limit; + int i; + + count =3D 0; + limit =3D (timeout_in_seconds * 1000000) / 50; + while (1) { + for (i =3D 0; i < NR_VCPUS; i++) { + sync_global_from_guest(vm, vcpu_states[i].state); + if (!vcpu_states[i].state.command_completed) + break; + } + + if (i >=3D NR_VCPUS) + return true; + + if (++count > limit) + return false; + + usleep(50); + } + + return false; +} + +static void vcpu_send_command(struct kvm_vm *vm, uint64_t command) +{ + int i; + + for (i =3D 0; i < NR_VCPUS; i++) { + memset(&vcpu_states[i].state, 0, + sizeof(vcpu_states[0].state)); + vcpu_states[i].state.num =3D SDEI_EVENT_NUM; + vcpu_states[i].state.status =3D SDEI_SUCCESS; + vcpu_states[i].state.command =3D command; + vcpu_states[i].state.command_completed =3D false; + + sync_global_to_guest(vm, vcpu_states[i].state); + } +} + +static bool vcpu_check_state(struct kvm_vm *vm) +{ + int i, j, ret; + + for (i =3D 0; i < NR_VCPUS; i++) + sync_global_from_guest(vm, vcpu_states[i].state); + + for (i =3D 0; i < NR_VCPUS; i++) { + if (is_error(vcpu_states[i].state.status)) + return false; + + for (j =3D 0; j < NR_VCPUS; j++) { + ret =3D memcmp(&vcpu_states[i].state, + &vcpu_states[j].state, + sizeof(vcpu_states[0].state)); + if (ret) + return false; + } + } + + return true; +} + +static void vcpu_dump_state(int index) +{ + struct sdei_state *state =3D &vcpu_states[0].state; + + pr_info("--- %s\n", vcpu_commands[index].name); + switch (state->command) { + case SDEI_1_0_FN_SDEI_VERSION: + pr_info(" Version: %ld.%ld (vendor: 0x%lx)\n", + SDEI_VERSION_MAJOR(state->version), + SDEI_VERSION_MINOR(state->version), + SDEI_VERSION_VENDOR(state->version)); + break; + case SDEI_1_1_FN_SDEI_FEATURES: + pr_info(" Shared event slots: %d\n", + state->feature.shared_slots); + pr_info(" Private event slots: %d\n", + state->feature.private_slots); + pr_info(" Relative mode: %s\n", + state->feature.relative_mode ? "Yes" : "No"); + break; + case SDEI_1_0_FN_SDEI_EVENT_GET_INFO: + pr_info(" Type: %s\n", + state->info.type =3D=3D SDEI_EVENT_TYPE_SHARED ? + "Shared" : "Private"); + pr_info(" Priority: %s\n", + state->info.priority =3D=3D SDEI_EVENT_PRIORITY_NORMAL ? + "Normal" : "Critical"); + pr_info(" Signaled: %s\n", + state->info.signaled ? "Yes" : "No"); + break; + case SDEI_1_1_FN_SDEI_EVENT_SIGNAL: + pr_info(" Handled: %s\n", + state->signal.handled ? "Yes" : "No"); + pr_info(" IRQ: %s\n", + state->signal.irq ? "Yes" : "No"); + pr_info(" Status: %s-%s-%s\n", + state->signal.status & (1 << SDEI_EVENT_STATUS_REGISTERED) ? + "Registered" : "x", + state->signal.status & (1 << SDEI_EVENT_STATUS_ENABLED) ? + "Enabled" : "x", + state->signal.status & (1 << SDEI_EVENT_STATUS_RUNNING) ? + "Running" : "x"); + pr_info(" PC/PSTATE: %016lx %016lx\n", + state->signal.pc, state->signal.pstate); + pr_info(" Regs: %016lx %016lx %016lx %016lx\n", + state->signal.regs[0], state->signal.regs[1], + state->signal.regs[2], state->signal.regs[3]); + break; + } + + if (index =3D=3D ARRAY_SIZE(vcpu_commands)) + pr_info("\n"); +} + +int main(int argc, char **argv) +{ + struct kvm_vm *vm; + struct kvm_sdei_cmd cmd; + struct kvm_sdei_exposed_event_state exposed_event; + uint32_t vcpu_ids[NR_VCPUS]; + int i, ret; + + if (!kvm_check_cap(KVM_CAP_ARM_SDEI)) { + pr_info("SDEI not supported\n"); + return 0; + } + + /* Create VM */ + for (i =3D 0; i < NR_VCPUS; i++) { + vcpu_states[i].vcpu_id =3D i; + vcpu_ids[i] =3D i; + } + + vm =3D vm_create_default_with_vcpus(NR_VCPUS, 0, 0, + guest_code, vcpu_ids); + vm_init_descriptor_tables(vm); + vm_install_exception_handler(vm, VECTOR_IRQ_CURRENT, + guest_irq_handler); + + ucall_init(vm, NULL); + + /* Ensure the version is v1.0.0 */ + cmd.cmd =3D KVM_SDEI_CMD_GET_VERSION; + cmd.version =3D 0; + vm_ioctl(vm, KVM_ARM_SDEI_COMMAND, &cmd); + if (cmd.version !=3D 0x10000) { + pr_info("v%d.%d.%d doesn't match with v1.0.0\n", + (cmd.version & 0xFF0000) >> 16, + (cmd.version & 0xFF00) >> 8, + (cmd.version & 0xFF)); + return 0; + } + + /* Expose the default SDEI event */ + exposed_event.num =3D SDEI_EVENT_NUM; + exposed_event.type =3D SDEI_EVENT_TYPE_PRIVATE; + exposed_event.priority =3D SDEI_EVENT_PRIORITY_NORMAL; + exposed_event.signaled =3D 1; + exposed_event.notifier =3D 0; + cmd.cmd =3D KVM_SDEI_CMD_SET_EXPOSED_EVENT; + cmd.count =3D 1; + cmd.exposed_event_state =3D &exposed_event; + vm_ioctl(vm, KVM_ARM_SDEI_COMMAND, &cmd); + + /* Start the vCPUs */ + vcpu_send_command(vm, VCPU_COMMAND_IDLE); + for (i =3D 0; i < NR_VCPUS; i++) { + vcpu_states[i].vm =3D vm; + vcpu_args_set(vm, i, 1, i); + vcpu_init_descriptor_tables(vm, i); + + ret =3D pthread_create(&vcpu_states[i].thread, NULL, + vcpu_thread, &vcpu_states[i]); + TEST_ASSERT(!ret, "Failed to create vCPU-%d pthread\n", i); + } + + /* Wait the idle command to complete */ + ret =3D vcpu_wait(vm, 5); + TEST_ASSERT(ret, "Timeout to execute IDLE command\n"); + + /* Start the tests */ + pr_info("\n"); + pr_info(" NR_VCPUS: %d SDEI Event: 0x%08x\n\n", + NR_VCPUS, SDEI_EVENT_NUM); + for (i =3D 0; i < ARRAY_SIZE(vcpu_commands); i++) { + /* + * We depends on SDEI_1_1_FN_SDEI_EVENT_SIGNAL hypercall + * to inject SDEI event. The number of the injected event + * must be zero. So we have to skip the corresponding test + * if the SDEI event number isn't zero. + */ + if (SDEI_EVENT_NUM !=3D 0x0 && + vcpu_commands[i].command =3D=3D SDEI_1_1_FN_SDEI_EVENT_SIGNAL) + continue; + + vcpu_send_command(vm, vcpu_commands[i].command); + ret =3D vcpu_wait(vm, 5); + if (!ret) { + pr_info("%s: Timeout\n", vcpu_commands[i].name); + return -1; + } + + ret =3D vcpu_check_state(vm); + if (!ret) { + pr_info("%s: Fail\n", vcpu_commands[i].name); + return -1; + } + + vcpu_dump_state(i); + } + + /* Terminate the guests */ + pr_info("\n Result: OK\n\n"); + vcpu_send_command(vm, VCPU_COMMAND_EXIT); + sleep(1); + + return 0; +} --=20 2.23.0