On 8/15/21 2:13 AM, Gavin Shan wrote: > This supports SDEI event injection by implementing kvm_sdei_inject(). > It's called by kernel directly or VMM through ioctl command to inject > SDEI event to the specific vCPU. > > Signed-off-by: Gavin Shan <gshan@xxxxxxxxxx> > --- > arch/arm64/include/asm/kvm_sdei.h | 2 + > arch/arm64/include/uapi/asm/kvm_sdei.h | 1 + > arch/arm64/kvm/sdei.c | 108 +++++++++++++++++++++++++ > 3 files changed, 111 insertions(+) > > diff --git a/arch/arm64/include/asm/kvm_sdei.h b/arch/arm64/include/asm/kvm_sdei.h > index a997989bab77..51087fe971ba 100644 > --- a/arch/arm64/include/asm/kvm_sdei.h > +++ b/arch/arm64/include/asm/kvm_sdei.h > @@ -124,6 +124,8 @@ void kvm_sdei_create_vcpu(struct kvm_vcpu *vcpu); > int kvm_sdei_hypercall(struct kvm_vcpu *vcpu); > int kvm_sdei_register_notifier(struct kvm *kvm, unsigned long num, > kvm_sdei_notifier notifier); > +int kvm_sdei_inject(struct kvm_vcpu *vcpu, > + unsigned long num, bool immediate); > void kvm_sdei_deliver(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); > diff --git a/arch/arm64/include/uapi/asm/kvm_sdei.h b/arch/arm64/include/uapi/asm/kvm_sdei.h > index b916c3435646..f7a6b2b22b50 100644 > --- a/arch/arm64/include/uapi/asm/kvm_sdei.h > +++ b/arch/arm64/include/uapi/asm/kvm_sdei.h > @@ -67,6 +67,7 @@ struct kvm_sdei_vcpu_state { > #define KVM_SDEI_CMD_SET_VEVENT 7 > #define KVM_SDEI_CMD_GET_VCPU_STATE 8 > #define KVM_SDEI_CMD_SET_VCPU_STATE 9 > +#define KVM_SDEI_CMD_INJECT_EVENT 10 > > struct kvm_sdei_cmd { > __u32 cmd; > diff --git a/arch/arm64/kvm/sdei.c b/arch/arm64/kvm/sdei.c > index 79315b77f24b..7c2789cd1421 100644 > --- a/arch/arm64/kvm/sdei.c > +++ b/arch/arm64/kvm/sdei.c > @@ -802,6 +802,111 @@ int kvm_sdei_register_notifier(struct kvm *kvm, > return ret; > } > > +int kvm_sdei_inject(struct kvm_vcpu *vcpu, > + unsigned long num, > + bool immediate) don't get the immediate param. > +{ > + struct kvm *kvm = vcpu->kvm; > + struct kvm_sdei_kvm *ksdei = kvm->arch.sdei; > + struct kvm_sdei_vcpu *vsdei = vcpu->arch.sdei; > + struct kvm_sdei_event *kse = NULL; > + struct kvm_sdei_kvm_event *kske = NULL; > + struct kvm_sdei_vcpu_event *ksve = NULL; > + int index, ret = 0; > + > + /* Sanity check */ > + if (!(ksdei && vsdei)) { > + ret = -EPERM; > + goto out; > + } > + > + if (!kvm_sdei_is_valid_event_num(num)) { > + ret = -EINVAL; > + goto out; > + } > + > + /* Check the kvm event */ > + spin_lock(&ksdei->lock); > + kske = kvm_sdei_find_kvm_event(kvm, num); > + if (!kske) { > + ret = -ENOENT; > + goto unlock_kvm; > + } > + > + kse = kske->kse; > + index = (kse->state.type == SDEI_EVENT_TYPE_PRIVATE) ? > + vcpu->vcpu_idx : 0; > + if (!(kvm_sdei_is_registered(kske, index) && > + kvm_sdei_is_enabled(kske, index))) { > + ret = -EPERM; > + goto unlock_kvm; > + } > + > + /* Check the vcpu state */ > + spin_lock(&vsdei->lock); > + if (vsdei->state.masked) { > + ret = -EPERM; > + goto unlock_vcpu; > + } > + > + /* Check if the event can be delivered immediately */ > + if (immediate) { According to the dispatcher pseudo code this should be always checked? > + if (kse->state.priority == SDEI_EVENT_PRIORITY_CRITICAL && > + !list_empty(&vsdei->critical_events)) { > + ret = -ENOSPC; > + goto unlock_vcpu; > + } > + > + if (kse->state.priority == SDEI_EVENT_PRIORITY_NORMAL && > + (!list_empty(&vsdei->critical_events) || > + !list_empty(&vsdei->normal_events))) { > + ret = -ENOSPC; > + goto unlock_vcpu; > + } > + } What about shared event dispatching. I don't see the afficinity checked anywhere? > + > + /* Check if the vcpu event exists */ > + ksve = kvm_sdei_find_vcpu_event(vcpu, num); > + if (ksve) { > + kske->state.refcount++; > + ksve->state.refcount++; why this double refcount increment?? > + kvm_make_request(KVM_REQ_SDEI, vcpu); > + goto unlock_vcpu; > + } > + > + /* Allocate vcpu event */ > + ksve = kzalloc(sizeof(*ksve), GFP_KERNEL); > + if (!ksve) { > + ret = -ENOMEM; > + goto unlock_vcpu; > + } > + > + /* > + * We should take lock to update KVM event state because its > + * reference count might be zero. In that case, the KVM event > + * could be destroyed. > + */ > + kske->state.refcount++; > + ksve->state.num = num; > + ksve->state.refcount = 1; > + ksve->kske = kske; > + ksve->vcpu = vcpu; > + > + if (kse->state.priority == SDEI_EVENT_PRIORITY_CRITICAL) > + list_add_tail(&ksve->link, &vsdei->critical_events); > + else > + list_add_tail(&ksve->link, &vsdei->normal_events); > + > + kvm_make_request(KVM_REQ_SDEI, vcpu); > + > +unlock_vcpu: > + spin_unlock(&vsdei->lock); > +unlock_kvm: > + spin_unlock(&ksdei->lock); > +out: > + return ret; > +} > + > void kvm_sdei_deliver(struct kvm_vcpu *vcpu) > { > struct kvm *kvm = vcpu->kvm; > @@ -1317,6 +1422,9 @@ long kvm_sdei_vcpu_ioctl(struct kvm_vcpu *vcpu, unsigned long arg) > case KVM_SDEI_CMD_SET_VCPU_STATE: > ret = kvm_sdei_set_vcpu_state(vcpu, &cmd->ksv_state); > break; > + case KVM_SDEI_CMD_INJECT_EVENT: > + ret = kvm_sdei_inject(vcpu, cmd->num, false); > + break; > default: > ret = -EINVAL; > } > Eric _______________________________________________ kvmarm mailing list kvmarm@xxxxxxxxxxxxxxxxxxxxx https://lists.cs.columbia.edu/mailman/listinfo/kvmarm