summaryrefslogtreecommitdiff
path: root/arch/arm64/kvm/hypercalls.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm64/kvm/hypercalls.c')
-rw-r--r--arch/arm64/kvm/hypercalls.c16
1 files changed, 16 insertions, 0 deletions
diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
index ba7cd84c6668..2db53709bec1 100644
--- a/arch/arm64/kvm/hypercalls.c
+++ b/arch/arm64/kvm/hypercalls.c
@@ -180,6 +180,19 @@ static u8 kvm_smccc_get_action(struct kvm_vcpu *vcpu, u32 func_id)
return KVM_SMCCC_FILTER_DENY;
}
+static void kvm_prepare_hypercall_exit(struct kvm_vcpu *vcpu, u32 func_id)
+{
+ u8 ec = ESR_ELx_EC(kvm_vcpu_get_esr(vcpu));
+ struct kvm_run *run = vcpu->run;
+
+ run->exit_reason = KVM_EXIT_HYPERCALL;
+ run->hypercall.nr = func_id;
+ run->hypercall.flags = 0;
+
+ if (ec == ESR_ELx_EC_SMC32 || ec == ESR_ELx_EC_SMC64)
+ run->hypercall.flags |= KVM_HYPERCALL_EXIT_SMC;
+}
+
int kvm_smccc_call_handler(struct kvm_vcpu *vcpu)
{
struct kvm_smccc_features *smccc_feat = &vcpu->kvm->arch.smccc_feat;
@@ -195,6 +208,9 @@ int kvm_smccc_call_handler(struct kvm_vcpu *vcpu)
break;
case KVM_SMCCC_FILTER_DENY:
goto out;
+ case KVM_SMCCC_FILTER_FWD_TO_USER:
+ kvm_prepare_hypercall_exit(vcpu, func_id);
+ return 0;
default:
WARN_RATELIMIT(1, "Unhandled SMCCC filter action: %d\n", action);
goto out;