summaryrefslogtreecommitdiff
path: root/arch/arm64/kvm/hyp/nvhe/hyp-main.c
diff options
context:
space:
mode:
authorDavid Brazdil <dbrazdil@google.com>2020-12-02 21:41:11 +0300
committerMarc Zyngier <maz@kernel.org>2020-12-04 13:08:34 +0300
commita805e1fb30990e29b3174c39bf39015065e5dc19 (patch)
tree8dd343bd2f9f13986be4dc8e06a987fff09ba6d3 /arch/arm64/kvm/hyp/nvhe/hyp-main.c
parent94f5e8a4642aedb19ca73f534372d7ed65e1c84e (diff)
downloadlinux-a805e1fb30990e29b3174c39bf39015065e5dc19.tar.xz
KVM: arm64: Add SMC handler in nVHE EL2
Add handler of host SMCs in KVM nVHE trap handler. Forward all SMCs to EL3 and propagate the result back to EL1. This is done in preparation for validating host SMCs in KVM protected mode. The implementation assumes that firmware uses SMCCC v1.2 or older. That means x0-x17 can be used both for arguments and results, other GPRs are preserved. Signed-off-by: David Brazdil <dbrazdil@google.com> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20201202184122.26046-16-dbrazdil@google.com
Diffstat (limited to 'arch/arm64/kvm/hyp/nvhe/hyp-main.c')
-rw-r--r--arch/arm64/kvm/hyp/nvhe/hyp-main.c35
1 files changed, 32 insertions, 3 deletions
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index a4f1cac714d7..f25680ede080 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -18,6 +18,8 @@
DEFINE_PER_CPU(struct kvm_nvhe_init_params, kvm_init_params);
+void __kvm_hyp_host_forward_smc(struct kvm_cpu_context *host_ctxt);
+
static void handle___kvm_vcpu_run(struct kvm_cpu_context *host_ctxt)
{
DECLARE_REG(struct kvm_vcpu *, vcpu, host_ctxt, 1);
@@ -152,12 +154,39 @@ inval:
cpu_reg(host_ctxt, 0) = SMCCC_RET_NOT_SUPPORTED;
}
+static void default_host_smc_handler(struct kvm_cpu_context *host_ctxt)
+{
+ __kvm_hyp_host_forward_smc(host_ctxt);
+}
+
+static void skip_host_instruction(void)
+{
+ write_sysreg_el2(read_sysreg_el2(SYS_ELR) + 4, SYS_ELR);
+}
+
+static void handle_host_smc(struct kvm_cpu_context *host_ctxt)
+{
+ default_host_smc_handler(host_ctxt);
+
+ /*
+ * Unlike HVC, the return address of an SMC is the instruction's PC.
+ * Move the return address past the instruction.
+ */
+ skip_host_instruction();
+}
+
void handle_trap(struct kvm_cpu_context *host_ctxt)
{
u64 esr = read_sysreg_el2(SYS_ESR);
- if (unlikely(ESR_ELx_EC(esr) != ESR_ELx_EC_HVC64))
+ switch (ESR_ELx_EC(esr)) {
+ case ESR_ELx_EC_HVC64:
+ handle_host_hcall(host_ctxt);
+ break;
+ case ESR_ELx_EC_SMC64:
+ handle_host_smc(host_ctxt);
+ break;
+ default:
hyp_panic();
-
- handle_host_hcall(host_ctxt);
+ }
}