xref: /openbmc/linux/arch/arm64/kvm/hyp/nvhe/debug-sr.c (revision 31e67366)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2015 - ARM Ltd
4  * Author: Marc Zyngier <marc.zyngier@arm.com>
5  */
6 
7 #include <hyp/debug-sr.h>
8 
9 #include <linux/compiler.h>
10 #include <linux/kvm_host.h>
11 
12 #include <asm/debug-monitors.h>
13 #include <asm/kvm_asm.h>
14 #include <asm/kvm_hyp.h>
15 #include <asm/kvm_mmu.h>
16 
17 static void __debug_save_spe(u64 *pmscr_el1)
18 {
19 	u64 reg;
20 
21 	/* Clear pmscr in case of early return */
22 	*pmscr_el1 = 0;
23 
24 	/* SPE present on this CPU? */
25 	if (!cpuid_feature_extract_unsigned_field(read_sysreg(id_aa64dfr0_el1),
26 						  ID_AA64DFR0_PMSVER_SHIFT))
27 		return;
28 
29 	/* Yes; is it owned by EL3? */
30 	reg = read_sysreg_s(SYS_PMBIDR_EL1);
31 	if (reg & BIT(SYS_PMBIDR_EL1_P_SHIFT))
32 		return;
33 
34 	/* No; is the host actually using the thing? */
35 	reg = read_sysreg_s(SYS_PMBLIMITR_EL1);
36 	if (!(reg & BIT(SYS_PMBLIMITR_EL1_E_SHIFT)))
37 		return;
38 
39 	/* Yes; save the control register and disable data generation */
40 	*pmscr_el1 = read_sysreg_s(SYS_PMSCR_EL1);
41 	write_sysreg_s(0, SYS_PMSCR_EL1);
42 	isb();
43 
44 	/* Now drain all buffered data to memory */
45 	psb_csync();
46 	dsb(nsh);
47 }
48 
49 static void __debug_restore_spe(u64 pmscr_el1)
50 {
51 	if (!pmscr_el1)
52 		return;
53 
54 	/* The host page table is installed, but not yet synchronised */
55 	isb();
56 
57 	/* Re-enable data generation */
58 	write_sysreg_s(pmscr_el1, SYS_PMSCR_EL1);
59 }
60 
61 void __debug_switch_to_guest(struct kvm_vcpu *vcpu)
62 {
63 	/* Disable and flush SPE data generation */
64 	__debug_save_spe(&vcpu->arch.host_debug_state.pmscr_el1);
65 	__debug_switch_to_guest_common(vcpu);
66 }
67 
68 void __debug_switch_to_host(struct kvm_vcpu *vcpu)
69 {
70 	__debug_restore_spe(vcpu->arch.host_debug_state.pmscr_el1);
71 	__debug_switch_to_host_common(vcpu);
72 }
73 
74 u32 __kvm_get_mdcr_el2(void)
75 {
76 	return read_sysreg(mdcr_el2);
77 }
78