1d400c5b2SDavid Brazdil // SPDX-License-Identifier: GPL-2.0-only
2d400c5b2SDavid Brazdil /*
3d400c5b2SDavid Brazdil * Copyright (C) 2015 - ARM Ltd
4d400c5b2SDavid Brazdil * Author: Marc Zyngier <marc.zyngier@arm.com>
5d400c5b2SDavid Brazdil */
6d400c5b2SDavid Brazdil
7d400c5b2SDavid Brazdil #include <hyp/debug-sr.h>
8d400c5b2SDavid Brazdil
9d400c5b2SDavid Brazdil #include <linux/compiler.h>
10d400c5b2SDavid Brazdil #include <linux/kvm_host.h>
11d400c5b2SDavid Brazdil
12d400c5b2SDavid Brazdil #include <asm/debug-monitors.h>
13d400c5b2SDavid Brazdil #include <asm/kvm_asm.h>
14d400c5b2SDavid Brazdil #include <asm/kvm_hyp.h>
15d400c5b2SDavid Brazdil #include <asm/kvm_mmu.h>
16d400c5b2SDavid Brazdil
__debug_save_spe(u64 * pmscr_el1)17c50cb043SDavid Brazdil static void __debug_save_spe(u64 *pmscr_el1)
18d400c5b2SDavid Brazdil {
19d400c5b2SDavid Brazdil u64 reg;
20d400c5b2SDavid Brazdil
21d400c5b2SDavid Brazdil /* Clear pmscr in case of early return */
22d400c5b2SDavid Brazdil *pmscr_el1 = 0;
23d400c5b2SDavid Brazdil
24d2602bb4SSuzuki K Poulose /*
25d2602bb4SSuzuki K Poulose * At this point, we know that this CPU implements
26d2602bb4SSuzuki K Poulose * SPE and is available to the host.
27d2602bb4SSuzuki K Poulose * Check if the host is actually using it ?
28d2602bb4SSuzuki K Poulose */
29d400c5b2SDavid Brazdil reg = read_sysreg_s(SYS_PMBLIMITR_EL1);
30c759ec85SRob Herring if (!(reg & BIT(PMBLIMITR_EL1_E_SHIFT)))
31d400c5b2SDavid Brazdil return;
32d400c5b2SDavid Brazdil
33d400c5b2SDavid Brazdil /* Yes; save the control register and disable data generation */
349a3bfb27SMarc Zyngier *pmscr_el1 = read_sysreg_el1(SYS_PMSCR);
359a3bfb27SMarc Zyngier write_sysreg_el1(0, SYS_PMSCR);
36d400c5b2SDavid Brazdil isb();
37d400c5b2SDavid Brazdil
38d400c5b2SDavid Brazdil /* Now drain all buffered data to memory */
39d400c5b2SDavid Brazdil psb_csync();
40d400c5b2SDavid Brazdil }
41d400c5b2SDavid Brazdil
__debug_restore_spe(u64 pmscr_el1)42c50cb043SDavid Brazdil static void __debug_restore_spe(u64 pmscr_el1)
43d400c5b2SDavid Brazdil {
44d400c5b2SDavid Brazdil if (!pmscr_el1)
45d400c5b2SDavid Brazdil return;
46d400c5b2SDavid Brazdil
47d400c5b2SDavid Brazdil /* The host page table is installed, but not yet synchronised */
48d400c5b2SDavid Brazdil isb();
49d400c5b2SDavid Brazdil
50d400c5b2SDavid Brazdil /* Re-enable data generation */
519a3bfb27SMarc Zyngier write_sysreg_el1(pmscr_el1, SYS_PMSCR);
52d400c5b2SDavid Brazdil }
53d400c5b2SDavid Brazdil
__debug_save_trace(u64 * trfcr_el1)54a1319260SSuzuki K Poulose static void __debug_save_trace(u64 *trfcr_el1)
55a1319260SSuzuki K Poulose {
56a1319260SSuzuki K Poulose *trfcr_el1 = 0;
57a1319260SSuzuki K Poulose
58a1319260SSuzuki K Poulose /* Check if the TRBE is enabled */
5992b1efcdSAnshuman Khandual if (!(read_sysreg_s(SYS_TRBLIMITR_EL1) & TRBLIMITR_EL1_E))
60a1319260SSuzuki K Poulose return;
61a1319260SSuzuki K Poulose /*
62a1319260SSuzuki K Poulose * Prohibit trace generation while we are in guest.
63a1319260SSuzuki K Poulose * Since access to TRFCR_EL1 is trapped, the guest can't
64a1319260SSuzuki K Poulose * modify the filtering set by the host.
65a1319260SSuzuki K Poulose */
669a3bfb27SMarc Zyngier *trfcr_el1 = read_sysreg_el1(SYS_TRFCR);
679a3bfb27SMarc Zyngier write_sysreg_el1(0, SYS_TRFCR);
68a1319260SSuzuki K Poulose isb();
69a1319260SSuzuki K Poulose /* Drain the trace buffer to memory */
70a1319260SSuzuki K Poulose tsb_csync();
71a1319260SSuzuki K Poulose }
72a1319260SSuzuki K Poulose
__debug_restore_trace(u64 trfcr_el1)73a1319260SSuzuki K Poulose static void __debug_restore_trace(u64 trfcr_el1)
74a1319260SSuzuki K Poulose {
75a1319260SSuzuki K Poulose if (!trfcr_el1)
76a1319260SSuzuki K Poulose return;
77a1319260SSuzuki K Poulose
78a1319260SSuzuki K Poulose /* Restore trace filter controls */
799a3bfb27SMarc Zyngier write_sysreg_el1(trfcr_el1, SYS_TRFCR);
80a1319260SSuzuki K Poulose }
81a1319260SSuzuki K Poulose
__debug_save_host_buffers_nvhe(struct kvm_vcpu * vcpu)82b96b0c5dSSuzuki K Poulose void __debug_save_host_buffers_nvhe(struct kvm_vcpu *vcpu)
83d400c5b2SDavid Brazdil {
84d400c5b2SDavid Brazdil /* Disable and flush SPE data generation */
85b1da4908SMarc Zyngier if (vcpu_get_flag(vcpu, DEBUG_STATE_SAVE_SPE))
86*6db55734SMarc Zyngier __debug_save_spe(host_data_ptr(host_debug_state.pmscr_el1));
87a1319260SSuzuki K Poulose /* Disable and flush Self-Hosted Trace generation */
88b1da4908SMarc Zyngier if (vcpu_get_flag(vcpu, DEBUG_STATE_SAVE_TRBE))
89*6db55734SMarc Zyngier __debug_save_trace(host_data_ptr(host_debug_state.trfcr_el1));
90b96b0c5dSSuzuki K Poulose }
91b96b0c5dSSuzuki K Poulose
__debug_switch_to_guest(struct kvm_vcpu * vcpu)92b96b0c5dSSuzuki K Poulose void __debug_switch_to_guest(struct kvm_vcpu *vcpu)
93b96b0c5dSSuzuki K Poulose {
94d400c5b2SDavid Brazdil __debug_switch_to_guest_common(vcpu);
95d400c5b2SDavid Brazdil }
96d400c5b2SDavid Brazdil
__debug_restore_host_buffers_nvhe(struct kvm_vcpu * vcpu)97b96b0c5dSSuzuki K Poulose void __debug_restore_host_buffers_nvhe(struct kvm_vcpu *vcpu)
98b96b0c5dSSuzuki K Poulose {
99b1da4908SMarc Zyngier if (vcpu_get_flag(vcpu, DEBUG_STATE_SAVE_SPE))
100*6db55734SMarc Zyngier __debug_restore_spe(*host_data_ptr(host_debug_state.pmscr_el1));
101b1da4908SMarc Zyngier if (vcpu_get_flag(vcpu, DEBUG_STATE_SAVE_TRBE))
102*6db55734SMarc Zyngier __debug_restore_trace(*host_data_ptr(host_debug_state.trfcr_el1));
103b96b0c5dSSuzuki K Poulose }
104b96b0c5dSSuzuki K Poulose
__debug_switch_to_host(struct kvm_vcpu * vcpu)105c50cb043SDavid Brazdil void __debug_switch_to_host(struct kvm_vcpu *vcpu)
106d400c5b2SDavid Brazdil {
107d400c5b2SDavid Brazdil __debug_switch_to_host_common(vcpu);
108d400c5b2SDavid Brazdil }
109d400c5b2SDavid Brazdil
__kvm_get_mdcr_el2(void)110d6c850ddSFuad Tabba u64 __kvm_get_mdcr_el2(void)
111d400c5b2SDavid Brazdil {
112d400c5b2SDavid Brazdil return read_sysreg(mdcr_el2);
113d400c5b2SDavid Brazdil }
114