From 84cfedad9f5360576df48f2919c2cbb7ad226fea Mon Sep 17 00:00:00 2001 From: Quentin Perret Date: Wed, 7 Dec 2022 13:45:12 +0000 Subject: [PATCH] ANDROID: KVM: arm64: Allow handling illegal aborts from pKVM modules Introduce a new handler allowing to notify pKVM modules when pKVM detects an illegal access from the host. Bug: 244543039 Bug: 245034629 Change-Id: I62133a8d967d91437e5216b307e449f8c83dfab6 Signed-off-by: Quentin Perret --- arch/arm64/include/asm/kvm_pkvm_module.h | 1 + arch/arm64/kvm/hyp/include/nvhe/modules.h | 1 + arch/arm64/kvm/hyp/nvhe/mem_protect.c | 10 ++++++++++ arch/arm64/kvm/hyp/nvhe/modules.c | 1 + 4 files changed, 13 insertions(+) diff --git a/arch/arm64/include/asm/kvm_pkvm_module.h b/arch/arm64/include/asm/kvm_pkvm_module.h index f90c71f6c56b..1c36af10aa87 100644 --- a/arch/arm64/include/asm/kvm_pkvm_module.h +++ b/arch/arm64/include/asm/kvm_pkvm_module.h @@ -21,6 +21,7 @@ struct pkvm_module_ops { 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 *)); + int (*register_illegal_abt_notifier)(void (*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 4a6162512a79..48eae5f57321 100644 --- a/arch/arm64/kvm/hyp/include/nvhe/modules.h +++ b/arch/arm64/kvm/hyp/include/nvhe/modules.h @@ -4,6 +4,7 @@ #define HCALL_UNHANDLED -1 int __pkvm_register_host_smc_handler(bool (*cb)(struct kvm_cpu_context *)); +int __pkvm_register_illegal_abt_notifier(void (*cb)(struct kvm_cpu_context *)); #ifdef CONFIG_MODULES int __pkvm_init_module(void *module_init); diff --git a/arch/arm64/kvm/hyp/nvhe/mem_protect.c b/arch/arm64/kvm/hyp/nvhe/mem_protect.c index d3a1a8d84640..9ea3970ad293 100644 --- a/arch/arm64/kvm/hyp/nvhe/mem_protect.c +++ b/arch/arm64/kvm/hyp/nvhe/mem_protect.c @@ -710,12 +710,22 @@ static int host_stage2_idmap(u64 addr) return host_stage2_idmap_locked(range.start, range.end - range.start, prot, false); } +static void (*illegal_abt_notifier)(struct kvm_cpu_context *host_ctxt); + +int __pkvm_register_illegal_abt_notifier(void (*cb)(struct kvm_cpu_context *)) +{ + return cmpxchg(&illegal_abt_notifier, NULL, cb) ? -EBUSY : 0; +} + static void host_inject_abort(struct kvm_cpu_context *host_ctxt) { u64 spsr = read_sysreg_el2(SYS_SPSR); u64 esr = read_sysreg_el2(SYS_ESR); u64 ventry, ec; + if (READ_ONCE(illegal_abt_notifier)) + illegal_abt_notifier(host_ctxt); + /* Repaint the ESR to report a same-level fault if taken from EL1 */ if ((spsr & PSR_MODE_MASK) != PSR_MODE_EL0t) { ec = ESR_ELx_EC(esr); diff --git a/arch/arm64/kvm/hyp/nvhe/modules.c b/arch/arm64/kvm/hyp/nvhe/modules.c index 401159a2f526..47ee9b83a28c 100644 --- a/arch/arm64/kvm/hyp/nvhe/modules.c +++ b/arch/arm64/kvm/hyp/nvhe/modules.c @@ -64,6 +64,7 @@ const struct pkvm_module_ops module_ops = { .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, + .register_illegal_abt_notifier = __pkvm_register_illegal_abt_notifier, }; int __pkvm_init_module(void *module_init)