KVM: arm64: nvhe: Synchronise with page table walker on vcpu run
[linux-2.6-block.git] / arch / arm64 / kvm / hyp / nvhe / debug-sr.c
CommitLineData
d400c5b2
DB
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
c50cb043 17static void __debug_save_spe(u64 *pmscr_el1)
d400c5b2
DB
18{
19 u64 reg;
20
21 /* Clear pmscr in case of early return */
22 *pmscr_el1 = 0;
23
d2602bb4
SP
24 /*
25 * At this point, we know that this CPU implements
26 * SPE and is available to the host.
27 * Check if the host is actually using it ?
28 */
d400c5b2 29 reg = read_sysreg_s(SYS_PMBLIMITR_EL1);
c759ec85 30 if (!(reg & BIT(PMBLIMITR_EL1_E_SHIFT)))
d400c5b2
DB
31 return;
32
33 /* Yes; save the control register and disable data generation */
34 *pmscr_el1 = read_sysreg_s(SYS_PMSCR_EL1);
35 write_sysreg_s(0, SYS_PMSCR_EL1);
36 isb();
37
38 /* Now drain all buffered data to memory */
39 psb_csync();
d400c5b2
DB
40}
41
c50cb043 42static void __debug_restore_spe(u64 pmscr_el1)
d400c5b2
DB
43{
44 if (!pmscr_el1)
45 return;
46
47 /* The host page table is installed, but not yet synchronised */
48 isb();
49
50 /* Re-enable data generation */
51 write_sysreg_s(pmscr_el1, SYS_PMSCR_EL1);
52}
53
a1319260
SP
54static void __debug_save_trace(u64 *trfcr_el1)
55{
56 *trfcr_el1 = 0;
57
58 /* Check if the TRBE is enabled */
59 if (!(read_sysreg_s(SYS_TRBLIMITR_EL1) & TRBLIMITR_ENABLE))
60 return;
61 /*
62 * Prohibit trace generation while we are in guest.
63 * Since access to TRFCR_EL1 is trapped, the guest can't
64 * modify the filtering set by the host.
65 */
66 *trfcr_el1 = read_sysreg_s(SYS_TRFCR_EL1);
67 write_sysreg_s(0, SYS_TRFCR_EL1);
68 isb();
69 /* Drain the trace buffer to memory */
70 tsb_csync();
a1319260
SP
71}
72
73static void __debug_restore_trace(u64 trfcr_el1)
74{
75 if (!trfcr_el1)
76 return;
77
78 /* Restore trace filter controls */
79 write_sysreg_s(trfcr_el1, SYS_TRFCR_EL1);
80}
81
b96b0c5d 82void __debug_save_host_buffers_nvhe(struct kvm_vcpu *vcpu)
d400c5b2
DB
83{
84 /* Disable and flush SPE data generation */
b1da4908 85 if (vcpu_get_flag(vcpu, DEBUG_STATE_SAVE_SPE))
d2602bb4 86 __debug_save_spe(&vcpu->arch.host_debug_state.pmscr_el1);
a1319260 87 /* Disable and flush Self-Hosted Trace generation */
b1da4908 88 if (vcpu_get_flag(vcpu, DEBUG_STATE_SAVE_TRBE))
a1319260 89 __debug_save_trace(&vcpu->arch.host_debug_state.trfcr_el1);
b96b0c5d
SP
90}
91
92void __debug_switch_to_guest(struct kvm_vcpu *vcpu)
93{
d400c5b2
DB
94 __debug_switch_to_guest_common(vcpu);
95}
96
b96b0c5d 97void __debug_restore_host_buffers_nvhe(struct kvm_vcpu *vcpu)
d400c5b2 98{
b1da4908 99 if (vcpu_get_flag(vcpu, DEBUG_STATE_SAVE_SPE))
d2602bb4 100 __debug_restore_spe(vcpu->arch.host_debug_state.pmscr_el1);
b1da4908 101 if (vcpu_get_flag(vcpu, DEBUG_STATE_SAVE_TRBE))
a1319260 102 __debug_restore_trace(vcpu->arch.host_debug_state.trfcr_el1);
b96b0c5d
SP
103}
104
105void __debug_switch_to_host(struct kvm_vcpu *vcpu)
106{
d400c5b2
DB
107 __debug_switch_to_host_common(vcpu);
108}
109
d6c850dd 110u64 __kvm_get_mdcr_el2(void)
d400c5b2
DB
111{
112 return read_sysreg(mdcr_el2);
113}