diff --git a/arch/arm64/include/asm/kvm_pkvm_module.h b/arch/arm64/include/asm/kvm_pkvm_module.h index 1916fb01e7cb..f90c71f6c56b 100644 --- a/arch/arm64/include/asm/kvm_pkvm_module.h +++ b/arch/arm64/include/asm/kvm_pkvm_module.h @@ -20,6 +20,7 @@ struct pkvm_module_ops { void (*flush_dcache_to_poc)(void *addr, size_t size); int (*register_host_perm_fault_handler)(int (*cb)(struct kvm_cpu_context *ctxt, u64 esr, u64 addr)); int (*protect_host_page)(u64 pfn, enum kvm_pgtable_prot prot); + int (*register_host_smc_handler)(bool (*cb)(struct kvm_cpu_context *)); }; struct pkvm_module_section { diff --git a/arch/arm64/kvm/hyp/include/nvhe/modules.h b/arch/arm64/kvm/hyp/include/nvhe/modules.h index d69aa744b82f..4a6162512a79 100644 --- a/arch/arm64/kvm/hyp/include/nvhe/modules.h +++ b/arch/arm64/kvm/hyp/include/nvhe/modules.h @@ -3,6 +3,8 @@ #define HCALL_HANDLED 0 #define HCALL_UNHANDLED -1 +int __pkvm_register_host_smc_handler(bool (*cb)(struct kvm_cpu_context *)); + #ifdef CONFIG_MODULES int __pkvm_init_module(void *module_init); int __pkvm_register_hcall(unsigned long hfn_hyp_va); diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c index f15232433454..f3b75cd4e98b 100644 --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c @@ -40,6 +40,13 @@ DEFINE_PER_CPU(struct kvm_nvhe_init_params, kvm_init_params); void __kvm_hyp_host_forward_smc(struct kvm_cpu_context *host_ctxt); +static bool (*default_host_smc_handler)(struct kvm_cpu_context *host_ctxt); + +int __pkvm_register_host_smc_handler(bool (*cb)(struct kvm_cpu_context *)) +{ + return cmpxchg(&default_host_smc_handler, NULL, cb) ? -EBUSY : 0; +} + static int pkvm_refill_memcache(struct pkvm_hyp_vcpu *hyp_vcpu) { struct pkvm_hyp_vm *hyp_vm = pkvm_hyp_vcpu_to_hyp_vm(hyp_vcpu); @@ -1283,11 +1290,6 @@ 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 handle_host_smc(struct kvm_cpu_context *host_ctxt) { bool handled; @@ -1295,8 +1297,10 @@ static void handle_host_smc(struct kvm_cpu_context *host_ctxt) handled = kvm_host_psci_handler(host_ctxt); if (!handled) handled = kvm_host_ffa_handler(host_ctxt); + if (!handled && READ_ONCE(default_host_smc_handler)) + handled = default_host_smc_handler(host_ctxt); if (!handled) - default_host_smc_handler(host_ctxt); + __kvm_hyp_host_forward_smc(host_ctxt); /* SMC was trapped, move ELR past the current PC. */ kvm_skip_host_instr(); diff --git a/arch/arm64/kvm/hyp/nvhe/modules.c b/arch/arm64/kvm/hyp/nvhe/modules.c index b71ce3880f3b..401159a2f526 100644 --- a/arch/arm64/kvm/hyp/nvhe/modules.c +++ b/arch/arm64/kvm/hyp/nvhe/modules.c @@ -63,6 +63,7 @@ const struct pkvm_module_ops module_ops = { .flush_dcache_to_poc = __kvm_flush_dcache_to_poc, .register_host_perm_fault_handler = hyp_register_host_perm_fault_handler, .protect_host_page = hyp_protect_host_page, + .register_host_smc_handler = __pkvm_register_host_smc_handler, }; int __pkvm_init_module(void *module_init)