From a3040de297f4dca2983c59d38ea7f9d5d9fc589f Mon Sep 17 00:00:00 2001 From: Vincent Donnefort Date: Tue, 14 Jan 2025 19:14:22 +0000 Subject: [PATCH] ANDROID: KVM: arm64: Allow 16 host_smc handlers Allow pKVM modules to register up to 16 host_smc handlers. The SMC will be considered has handled on the first one returning True. Unhandled SMC will be forwarded. Bug: 357781595 Bug: 382397533 Change-Id: I58717927d7b47b8af5532ec2bfe57e022186e1d3 Signed-off-by: Vincent Donnefort --- arch/arm64/include/asm/kvm_pkvm_module.h | 7 +++++-- arch/arm64/kvm/hyp/include/nvhe/modules.h | 2 ++ arch/arm64/kvm/hyp/nvhe/hyp-main.c | 15 ++------------- arch/arm64/kvm/hyp/nvhe/modules.c | 21 ++++++++++++++++++++- 4 files changed, 29 insertions(+), 16 deletions(-) diff --git a/arch/arm64/include/asm/kvm_pkvm_module.h b/arch/arm64/include/asm/kvm_pkvm_module.h index d2178244a0fa..325bbfabfd22 100644 --- a/arch/arm64/include/asm/kvm_pkvm_module.h +++ b/arch/arm64/include/asm/kvm_pkvm_module.h @@ -93,8 +93,11 @@ enum pkvm_psci_notification { * @host_stage2_get_leaf: Query the host's stage2 page-table entry for * the page @phys. * @register_host_smc_handler: @cb is called whenever the host issues an SMC - * pKVM couldn't handle. If @cb returns false, the - * SMC will be forwarded to EL3. + * pKVM couldn't handle. + * Up-to 16 handlers can be registered. The handler + * order depends on the registration order. If no + * handler return True, the SMC is forwarded to + * EL3. * @register_default_trap_handler: * @cb is called whenever EL2 traps EL1 and pKVM * has not handled it. If @cb returns false, the diff --git a/arch/arm64/kvm/hyp/include/nvhe/modules.h b/arch/arm64/kvm/hyp/include/nvhe/modules.h index 57674285609d..f5d39e733ba6 100644 --- a/arch/arm64/kvm/hyp/include/nvhe/modules.h +++ b/arch/arm64/kvm/hyp/include/nvhe/modules.h @@ -18,6 +18,7 @@ int __pkvm_register_hcall(unsigned long hfn_hyp_va); int handle_host_dynamic_hcall(struct user_pt_regs *regs, int id); void __pkvm_close_module_registration(void); bool module_handle_host_perm_fault(struct user_pt_regs *regs, u64 esr, u64 addr); +bool module_handle_host_smc(struct user_pt_regs *regs); #else static inline int __pkvm_init_module(void *module_init) { return -EOPNOTSUPP; } static inline int @@ -29,4 +30,5 @@ handle_host_dynamic_hcall(struct kvm_cpu_context *host_ctxt, int id) } static inline void __pkvm_close_module_registration(void) { } bool module_handle_host_perm_fault(struct user_pt_regs *regs, u64 esr, u64 addr) { return false; } +bool module_handle_host_smc(struct user_pt_regs *regs) { return false; } #endif diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c index 222a7c8e143f..1bd962eb4af5 100644 --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c @@ -63,21 +63,10 @@ static inline void hyp_reqs_smccc_encode(unsigned long ret, struct kvm_cpu_conte void __kvm_hyp_host_forward_smc(struct kvm_cpu_context *host_ctxt); -static bool (*default_host_smc_handler)(struct user_pt_regs *regs); static bool (*default_trap_handler)(struct user_pt_regs *regs); static bool (*unmask_serror)(void); static void (*mask_serror)(void); -int __pkvm_register_host_smc_handler(bool (*cb)(struct user_pt_regs *)) -{ - /* - * Paired with smp_load_acquire(&default_host_smc_handler) in - * handle_host_smc(). Ensure memory stores happening during a pKVM module - * init are observed before executing the callback. - */ - return cmpxchg_release(&default_host_smc_handler, NULL, cb) ? -EBUSY : 0; -} - int __pkvm_register_default_trap_handler(bool (*cb)(struct user_pt_regs *)) { return cmpxchg(&default_trap_handler, NULL, cb) ? -EBUSY : 0; @@ -1856,8 +1845,8 @@ static void handle_host_smc(struct kvm_cpu_context *host_ctxt) handled = kvm_host_ffa_handler(host_ctxt, func_id); if (!handled) handled = kvm_host_scmi_handler(host_ctxt); - if (!handled && smp_load_acquire(&default_host_smc_handler)) - handled = default_host_smc_handler(&host_ctxt->regs); + if (!handled) + handled = module_handle_host_smc(&host_ctxt->regs); if (!handled) { __hyp_exit(); __kvm_hyp_host_forward_smc(host_ctxt); diff --git a/arch/arm64/kvm/hyp/nvhe/modules.c b/arch/arm64/kvm/hyp/nvhe/modules.c index 53f0b8da357c..a3b16031d3ca 100644 --- a/arch/arm64/kvm/hyp/nvhe/modules.c +++ b/arch/arm64/kvm/hyp/nvhe/modules.c @@ -132,6 +132,7 @@ static int __hyp_smp_processor_id(void) enum mod_handler_type { HOST_FAULT_HANDLER = 0, + HOST_SMC_HANDLER, NUM_MOD_HANDLER_TYPES, }; @@ -173,6 +174,11 @@ __register_host_perm_fault_handler(int (*cb)(struct user_pt_regs *regs, u64 esr, return mod_handler_register(HOST_FAULT_HANDLER, cb); } +static int __register_host_smc_handler(bool (*cb)(struct user_pt_regs *)) +{ + return mod_handler_register(HOST_SMC_HANDLER, cb); +} + bool module_handle_host_perm_fault(struct user_pt_regs *regs, u64 esr, u64 addr) { int (*cb)(struct user_pt_regs *regs, u64 esr, u64 addr); @@ -186,6 +192,19 @@ bool module_handle_host_perm_fault(struct user_pt_regs *regs, u64 esr, u64 addr) return false; } +bool module_handle_host_smc(struct user_pt_regs *regs) +{ + bool (*cb)(struct user_pt_regs *regs); + int i; + + for_each_mod_handler(HOST_SMC_HANDLER, cb, i) { + if (cb(regs)) + return true; + } + + return false; +} + const struct pkvm_module_ops module_ops = { .create_private_mapping = __pkvm_create_private_mapping, .alloc_module_va = __pkvm_alloc_module_va, @@ -206,7 +225,7 @@ const struct pkvm_module_ops module_ops = { .host_stage2_get_leaf = host_stage2_get_leaf, .host_stage2_enable_lazy_pte = host_stage2_enable_lazy_pte, .host_stage2_disable_lazy_pte = host_stage2_disable_lazy_pte, - .register_host_smc_handler = __pkvm_register_host_smc_handler, + .register_host_smc_handler = __register_host_smc_handler, .register_default_trap_handler = __pkvm_register_default_trap_handler, .register_illegal_abt_notifier = __pkvm_register_illegal_abt_notifier, .register_psci_notifier = __pkvm_register_psci_notifier,