xref: /linux/arch/arm64/kvm/hyp/nvhe/debug-sr.c (revision 9a3bfb27ef65ad41d994765c031ca18217afb058)
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 
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 */
34*9a3bfb27SMarc Zyngier 	*pmscr_el1 = read_sysreg_el1(SYS_PMSCR);
35*9a3bfb27SMarc 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 
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 */
51*9a3bfb27SMarc Zyngier 	write_sysreg_el1(pmscr_el1, SYS_PMSCR);
52d400c5b2SDavid Brazdil }
53d400c5b2SDavid Brazdil 
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 	 */
66*9a3bfb27SMarc Zyngier 	*trfcr_el1 = read_sysreg_el1(SYS_TRFCR);
67*9a3bfb27SMarc 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 
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 */
79*9a3bfb27SMarc Zyngier 	write_sysreg_el1(trfcr_el1, SYS_TRFCR);
80a1319260SSuzuki K Poulose }
81a1319260SSuzuki K Poulose 
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))
86d400c5b2SDavid Brazdil 		__debug_save_spe(&vcpu->arch.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))
89a1319260SSuzuki K Poulose 		__debug_save_trace(&vcpu->arch.host_debug_state.trfcr_el1);
90b96b0c5dSSuzuki K Poulose }
91b96b0c5dSSuzuki K Poulose 
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 
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))
100b96b0c5dSSuzuki K Poulose 		__debug_restore_spe(vcpu->arch.host_debug_state.pmscr_el1);
101b1da4908SMarc Zyngier 	if (vcpu_get_flag(vcpu, DEBUG_STATE_SAVE_TRBE))
102a1319260SSuzuki K Poulose 		__debug_restore_trace(vcpu->arch.host_debug_state.trfcr_el1);
103b96b0c5dSSuzuki K Poulose }
104b96b0c5dSSuzuki K Poulose 
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 
110d6c850ddSFuad Tabba u64 __kvm_get_mdcr_el2(void)
111d400c5b2SDavid Brazdil {
112d400c5b2SDavid Brazdil 	return read_sysreg(mdcr_el2);
113d400c5b2SDavid Brazdil }
114