[PATCH 10/18] arm64/kvm: Support SDEI_1_0_FN_SDEI_EVENT_GET_INFO hypercall

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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



[Index of Archives]     [Linux KVM]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux