ANDROID: KVM: arm64: Allow tweaking HCR_EL2 from modules

pKVM modules may need to enable additional traps on top of what pKVM
already enables. To allow this use-case, expose a function allowing to
manipulate HCR_EL2 on the current CPU. This configuration will be
persistent across power management cycles and such as it is propagated
all the way to the init params per-cpu struct.

Bug: 458241298
Signed-off-by: Quentin Perret <qperret@google.com>
Signed-off-by: Fuad Tabba <tabba@google.com>
Change-Id: I21d596bd1d01f4edc48a188cc3c2eb78dc9a4444
(cherry picked from commit 69365c8419b4d206b862c05c008ba61336d36fdc)
diff --git a/arch/arm64/include/asm/kvm_pkvm_module.h b/arch/arm64/include/asm/kvm_pkvm_module.h
index c404d7a..826279c 100644
--- a/arch/arm64/include/asm/kvm_pkvm_module.h
+++ b/arch/arm64/include/asm/kvm_pkvm_module.h
@@ -28,6 +28,7 @@ struct pkvm_module_ops {
 	void *(*linear_map_early)(phys_addr_t phys, size_t size, enum kvm_pgtable_prot prot);
 	void (*linear_unmap_early)(void *addr, size_t size);
 	void (*flush_dcache_to_poc)(void *addr, size_t size);
+	void (*update_hcr_el2)(unsigned long set_mask, unsigned long clear_mask);
 	int (*register_host_perm_fault_handler)(int (*cb)(struct user_pt_regs *regs, u64 esr, u64 addr));
 	int (*register_host_smc_handler)(bool (*cb)(struct user_pt_regs *));
 	int (*register_default_trap_handler)(bool (*cb)(struct user_pt_regs *));
diff --git a/arch/arm64/kvm/hyp/nvhe/modules.c b/arch/arm64/kvm/hyp/nvhe/modules.c
index e2f4e0e..d7b6d63 100644
--- a/arch/arm64/kvm/hyp/nvhe/modules.c
+++ b/arch/arm64/kvm/hyp/nvhe/modules.c
@@ -35,6 +35,16 @@ bool pkvm_modules_enabled(void)
 	return __pkvm_modules_enabled;
 }
 
+static void __update_hcr_el2(unsigned long set_mask, unsigned long clear_mask)
+{
+	struct kvm_nvhe_init_params *params = this_cpu_ptr(&kvm_init_params);
+
+	params->hcr_el2 |= set_mask;
+	params->hcr_el2 &= ~clear_mask;
+	__kvm_flush_dcache_to_poc(params, sizeof(*params));
+	write_sysreg(params->hcr_el2, hcr_el2);
+}
+
 static atomic_t early_lm_pages;
 static void *__pkvm_linear_map_early(phys_addr_t phys, size_t size, enum kvm_pgtable_prot prot)
 {
@@ -101,6 +111,7 @@ const struct pkvm_module_ops module_ops = {
 	.linear_map_early = __pkvm_linear_map_early,
 	.linear_unmap_early = __pkvm_linear_unmap_early,
 	.flush_dcache_to_poc = __kvm_flush_dcache_to_poc,
+	.update_hcr_el2 = __update_hcr_el2,
 	.register_host_perm_fault_handler = hyp_register_host_perm_fault_handler,
 	.register_host_smc_handler = __pkvm_register_host_smc_handler,
 	.register_default_trap_handler = __pkvm_register_default_trap_handler,