This supports SDEI_1_0_FN_SDEI_EVENT_GET_INFO hypercall by adding kvm_sdei_hypercall_info(). On success, the requested information about the event is returned. Otherwise, the errno is returned. The required information is retrieved from the SDEI event if it has been created. Otherwise, it's retrieved from underly firmware if applicable. Signed-off-by: Gavin Shan <gshan@xxxxxxxxxx> --- arch/arm64/kvm/sdei.c | 125 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/arch/arm64/kvm/sdei.c b/arch/arm64/kvm/sdei.c index 2d2135a5c3ea..529505c4f0cf 100644 --- a/arch/arm64/kvm/sdei.c +++ b/arch/arm64/kvm/sdei.c @@ -38,6 +38,14 @@ static struct sdei_event *kvm_sdei_register_event(unsigned long event_num, cb, arg); } +static int kvm_sdei_get_event_info(unsigned long event_num, + unsigned int info, + unsigned long *result) +{ + return sdei_event_get_info(kvm_sdei_num_to_std(event_num), + info, (u64 *)result); +} + static int kvm_sdei_unregister_event(struct sdei_event *event) { return sdei_event_unregister(event); @@ -56,6 +64,14 @@ static inline struct sdei_event *kvm_sdei_register_event( return NULL; } +static inline int kvm_sdei_get_event_info(unsigned long event_num, + unsigned int info, + unsigned long *result) +{ + *result = SDEI_NOT_SUPPORTED; + return -EPERM; +} + static inline int kvm_sdei_unregister_event(struct sdei_event *event) { return -EPERM; @@ -462,6 +478,113 @@ static unsigned long kvm_sdei_hypercall_status(struct kvm_vcpu *vcpu) return ret; } +static unsigned long kvm_sdei_hypercall_info(struct kvm_vcpu *vcpu) +{ + struct kvm *kvm = vcpu->kvm; + struct kvm_sdei_event *event = NULL; + struct kvm_sdei_kvm_event *kevent = NULL; + struct kvm_sdei_priv *priv = NULL; + unsigned long event_num = smccc_get_arg1(vcpu); + unsigned long event_info = smccc_get_arg2(vcpu); + unsigned long event_type; + int index; + unsigned long ret = SDEI_SUCCESS; + + /* Validate event number */ + if (!kvm_sdei_num_is_valid(event_num)) { + ret = SDEI_INVALID_PARAMETERS; + goto out; + } + + if (!(kvm_sdei_data && kvm_sdei_data->supported) && + kvm_sdei_num_is_virt(event_num)) { + ret = SDEI_INVALID_PARAMETERS; + goto out; + } + + /* + * The requested information could be retrieved from the + * registered event, KVM private descriptor or underly + * firmware. + */ + spin_lock(&kvm_sdei_lock); + event = kvm_sdei_find_event(kvm, event_num, &kevent, NULL, NULL); + if (kevent) { + spin_lock(&event->lock); + + event_type = event->priv ? event->priv->type : + event->event->type; + index = (event_type == SDEI_EVENT_TYPE_PRIVATE) ? + vcpu->vcpu_idx : 0; + if (!test_bit(index, kevent->registered)) { + ret = SDEI_INVALID_PARAMETERS; + goto unlock; + } + + priv = event->priv; + } else if (kvm_sdei_num_is_priv(event_num)) { + priv = kvm_sdei_find_priv(event_num); + if (!priv) { + ret = SDEI_INVALID_PARAMETERS; + goto unlock; + } + } else if (kvm_sdei_num_is_virt(event_num)) { + if (event_info == SDEI_EVENT_INFO_EV_ROUTING_MODE || + event_info == SDEI_EVENT_INFO_EV_ROUTING_AFF) { + kvm_sdei_get_event_info(event_num, + SDEI_EVENT_INFO_EV_TYPE, + &event_type); + if (event_type != SDEI_EVENT_TYPE_SHARED) { + ret = SDEI_INVALID_PARAMETERS; + goto unlock; + } + } + + kvm_sdei_get_event_info(event_num, event_info, &ret); + goto unlock; + } + + switch (event_info) { + case SDEI_EVENT_INFO_EV_TYPE: + ret = priv ? priv->type : event->event->type; + break; + case SDEI_EVENT_INFO_EV_SIGNALED: + ret = priv ? priv->signaled : event->event->signaled; + break; + case SDEI_EVENT_INFO_EV_PRIORITY: + ret = priv ? priv->priority : event->event->priority; + break; + case SDEI_EVENT_INFO_EV_ROUTING_MODE: + event_type = priv ? priv->type : event->event->type; + if (event_type != SDEI_EVENT_TYPE_SHARED) { + ret = SDEI_INVALID_PARAMETERS; + break; + } + + ret = kevent ? kevent->route_mode : priv->route_mode; + break; + case SDEI_EVENT_INFO_EV_ROUTING_AFF: + event_type = priv ? priv->type : event->event->type; + if (event_type != SDEI_EVENT_TYPE_SHARED) { + ret = SDEI_INVALID_PARAMETERS; + break; + } + + ret = kevent ? kevent->route_affinity : priv->route_affinity; + break; + default: + ret = SDEI_INVALID_PARAMETERS; + } + +unlock: + if (kevent) + spin_unlock(&event->lock); + + spin_unlock(&kvm_sdei_lock); +out: + return ret; +} + static unsigned long kvm_sdei_reset(struct kvm *kvm, unsigned int types) { struct kvm_sdei_event *e, *event = NULL; @@ -554,6 +677,8 @@ int kvm_sdei_hypercall(struct kvm_vcpu *vcpu) ret = kvm_sdei_hypercall_status(vcpu); break; case SDEI_1_0_FN_SDEI_EVENT_GET_INFO: + ret = kvm_sdei_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: -- 2.23.0 _______________________________________________ kvmarm mailing list kvmarm@xxxxxxxxxxxxxxxxxxxxx https://lists.cs.columbia.edu/mailman/listinfo/kvmarm