xref: /linux/arch/arm64/kvm/hyp/nvhe/debug-sr.c (revision c759ec850df89f7235b08e468abb3190b6998d4e)
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);
30*c759ec85SRob Herring 	if (!(reg & BIT(PMBLIMITR_EL1_E_SHIFT)))
31d400c5b2SDavid Brazdil 		return;
32d400c5b2SDavid Brazdil 
33d400c5b2SDavid Brazdil 	/* Yes; save the control register and disable data generation */
34d400c5b2SDavid Brazdil 	*pmscr_el1 = read_sysreg_s(SYS_PMSCR_EL1);
35d400c5b2SDavid Brazdil 	write_sysreg_s(0, SYS_PMSCR_EL1);
36d400c5b2SDavid Brazdil 	isb();
37d400c5b2SDavid Brazdil 
38d400c5b2SDavid Brazdil 	/* Now drain all buffered data to memory */
39d400c5b2SDavid Brazdil 	psb_csync();
40d400c5b2SDavid Brazdil 	dsb(nsh);
41d400c5b2SDavid Brazdil }
42d400c5b2SDavid Brazdil 
43c50cb043SDavid Brazdil static void __debug_restore_spe(u64 pmscr_el1)
44d400c5b2SDavid Brazdil {
45d400c5b2SDavid Brazdil 	if (!pmscr_el1)
46d400c5b2SDavid Brazdil 		return;
47d400c5b2SDavid Brazdil 
48d400c5b2SDavid Brazdil 	/* The host page table is installed, but not yet synchronised */
49d400c5b2SDavid Brazdil 	isb();
50d400c5b2SDavid Brazdil 
51d400c5b2SDavid Brazdil 	/* Re-enable data generation */
52d400c5b2SDavid Brazdil 	write_sysreg_s(pmscr_el1, SYS_PMSCR_EL1);
53d400c5b2SDavid Brazdil }
54d400c5b2SDavid Brazdil 
55a1319260SSuzuki K Poulose static void __debug_save_trace(u64 *trfcr_el1)
56a1319260SSuzuki K Poulose {
57a1319260SSuzuki K Poulose 	*trfcr_el1 = 0;
58a1319260SSuzuki K Poulose 
59a1319260SSuzuki K Poulose 	/* Check if the TRBE is enabled */
60a1319260SSuzuki K Poulose 	if (!(read_sysreg_s(SYS_TRBLIMITR_EL1) & TRBLIMITR_ENABLE))
61a1319260SSuzuki K Poulose 		return;
62a1319260SSuzuki K Poulose 	/*
63a1319260SSuzuki K Poulose 	 * Prohibit trace generation while we are in guest.
64a1319260SSuzuki K Poulose 	 * Since access to TRFCR_EL1 is trapped, the guest can't
65a1319260SSuzuki K Poulose 	 * modify the filtering set by the host.
66a1319260SSuzuki K Poulose 	 */
67a1319260SSuzuki K Poulose 	*trfcr_el1 = read_sysreg_s(SYS_TRFCR_EL1);
68a1319260SSuzuki K Poulose 	write_sysreg_s(0, SYS_TRFCR_EL1);
69a1319260SSuzuki K Poulose 	isb();
70a1319260SSuzuki K Poulose 	/* Drain the trace buffer to memory */
71a1319260SSuzuki K Poulose 	tsb_csync();
72a1319260SSuzuki K Poulose 	dsb(nsh);
73a1319260SSuzuki K Poulose }
74a1319260SSuzuki K Poulose 
75a1319260SSuzuki K Poulose static void __debug_restore_trace(u64 trfcr_el1)
76a1319260SSuzuki K Poulose {
77a1319260SSuzuki K Poulose 	if (!trfcr_el1)
78a1319260SSuzuki K Poulose 		return;
79a1319260SSuzuki K Poulose 
80a1319260SSuzuki K Poulose 	/* Restore trace filter controls */
81a1319260SSuzuki K Poulose 	write_sysreg_s(trfcr_el1, SYS_TRFCR_EL1);
82a1319260SSuzuki K Poulose }
83a1319260SSuzuki K Poulose 
84b96b0c5dSSuzuki K Poulose void __debug_save_host_buffers_nvhe(struct kvm_vcpu *vcpu)
85d400c5b2SDavid Brazdil {
86d400c5b2SDavid Brazdil 	/* Disable and flush SPE data generation */
87b1da4908SMarc Zyngier 	if (vcpu_get_flag(vcpu, DEBUG_STATE_SAVE_SPE))
88d400c5b2SDavid Brazdil 		__debug_save_spe(&vcpu->arch.host_debug_state.pmscr_el1);
89a1319260SSuzuki K Poulose 	/* Disable and flush Self-Hosted Trace generation */
90b1da4908SMarc Zyngier 	if (vcpu_get_flag(vcpu, DEBUG_STATE_SAVE_TRBE))
91a1319260SSuzuki K Poulose 		__debug_save_trace(&vcpu->arch.host_debug_state.trfcr_el1);
92b96b0c5dSSuzuki K Poulose }
93b96b0c5dSSuzuki K Poulose 
94b96b0c5dSSuzuki K Poulose void __debug_switch_to_guest(struct kvm_vcpu *vcpu)
95b96b0c5dSSuzuki K Poulose {
96d400c5b2SDavid Brazdil 	__debug_switch_to_guest_common(vcpu);
97d400c5b2SDavid Brazdil }
98d400c5b2SDavid Brazdil 
99b96b0c5dSSuzuki K Poulose void __debug_restore_host_buffers_nvhe(struct kvm_vcpu *vcpu)
100b96b0c5dSSuzuki K Poulose {
101b1da4908SMarc Zyngier 	if (vcpu_get_flag(vcpu, DEBUG_STATE_SAVE_SPE))
102b96b0c5dSSuzuki K Poulose 		__debug_restore_spe(vcpu->arch.host_debug_state.pmscr_el1);
103b1da4908SMarc Zyngier 	if (vcpu_get_flag(vcpu, DEBUG_STATE_SAVE_TRBE))
104a1319260SSuzuki K Poulose 		__debug_restore_trace(vcpu->arch.host_debug_state.trfcr_el1);
105b96b0c5dSSuzuki K Poulose }
106b96b0c5dSSuzuki K Poulose 
107c50cb043SDavid Brazdil void __debug_switch_to_host(struct kvm_vcpu *vcpu)
108d400c5b2SDavid Brazdil {
109d400c5b2SDavid Brazdil 	__debug_switch_to_host_common(vcpu);
110d400c5b2SDavid Brazdil }
111d400c5b2SDavid Brazdil 
112d6c850ddSFuad Tabba u64 __kvm_get_mdcr_el2(void)
113d400c5b2SDavid Brazdil {
114d400c5b2SDavid Brazdil 	return read_sysreg(mdcr_el2);
115d400c5b2SDavid Brazdil }
116