18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Debug and Guest Debug support
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2015 - Linaro Ltd
68c2ecf20Sopenharmony_ci * Author: Alex Bennée <alex.bennee@linaro.org>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/kvm_host.h>
108c2ecf20Sopenharmony_ci#include <linux/hw_breakpoint.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <asm/debug-monitors.h>
138c2ecf20Sopenharmony_ci#include <asm/kvm_asm.h>
148c2ecf20Sopenharmony_ci#include <asm/kvm_arm.h>
158c2ecf20Sopenharmony_ci#include <asm/kvm_emulate.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include "trace.h"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/* These are the bits of MDSCR_EL1 we may manipulate */
208c2ecf20Sopenharmony_ci#define MDSCR_EL1_DEBUG_MASK	(DBG_MDSCR_SS | \
218c2ecf20Sopenharmony_ci				DBG_MDSCR_KDE | \
228c2ecf20Sopenharmony_ci				DBG_MDSCR_MDE)
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(u32, mdcr_el2);
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/**
278c2ecf20Sopenharmony_ci * save/restore_guest_debug_regs
288c2ecf20Sopenharmony_ci *
298c2ecf20Sopenharmony_ci * For some debug operations we need to tweak some guest registers. As
308c2ecf20Sopenharmony_ci * a result we need to save the state of those registers before we
318c2ecf20Sopenharmony_ci * make those modifications.
328c2ecf20Sopenharmony_ci *
338c2ecf20Sopenharmony_ci * Guest access to MDSCR_EL1 is trapped by the hypervisor and handled
348c2ecf20Sopenharmony_ci * after we have restored the preserved value to the main context.
358c2ecf20Sopenharmony_ci */
368c2ecf20Sopenharmony_cistatic void save_guest_debug_regs(struct kvm_vcpu *vcpu)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	u64 val = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	vcpu->arch.guest_debug_preserved.mdscr_el1 = val;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	trace_kvm_arm_set_dreg32("Saved MDSCR_EL1",
438c2ecf20Sopenharmony_ci				vcpu->arch.guest_debug_preserved.mdscr_el1);
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic void restore_guest_debug_regs(struct kvm_vcpu *vcpu)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	u64 val = vcpu->arch.guest_debug_preserved.mdscr_el1;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	vcpu_write_sys_reg(vcpu, val, MDSCR_EL1);
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	trace_kvm_arm_set_dreg32("Restored MDSCR_EL1",
538c2ecf20Sopenharmony_ci				vcpu_read_sys_reg(vcpu, MDSCR_EL1));
548c2ecf20Sopenharmony_ci}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci/**
578c2ecf20Sopenharmony_ci * kvm_arm_init_debug - grab what we need for debug
588c2ecf20Sopenharmony_ci *
598c2ecf20Sopenharmony_ci * Currently the sole task of this function is to retrieve the initial
608c2ecf20Sopenharmony_ci * value of mdcr_el2 so we can preserve MDCR_EL2.HPMN which has
618c2ecf20Sopenharmony_ci * presumably been set-up by some knowledgeable bootcode.
628c2ecf20Sopenharmony_ci *
638c2ecf20Sopenharmony_ci * It is called once per-cpu during CPU hyp initialisation.
648c2ecf20Sopenharmony_ci */
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_civoid kvm_arm_init_debug(void)
678c2ecf20Sopenharmony_ci{
688c2ecf20Sopenharmony_ci	__this_cpu_write(mdcr_el2, kvm_call_hyp_ret(__kvm_get_mdcr_el2));
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci/**
728c2ecf20Sopenharmony_ci * kvm_arm_setup_mdcr_el2 - configure vcpu mdcr_el2 value
738c2ecf20Sopenharmony_ci *
748c2ecf20Sopenharmony_ci * @vcpu:	the vcpu pointer
758c2ecf20Sopenharmony_ci *
768c2ecf20Sopenharmony_ci * This ensures we will trap access to:
778c2ecf20Sopenharmony_ci *  - Performance monitors (MDCR_EL2_TPM/MDCR_EL2_TPMCR)
788c2ecf20Sopenharmony_ci *  - Debug ROM Address (MDCR_EL2_TDRA)
798c2ecf20Sopenharmony_ci *  - OS related registers (MDCR_EL2_TDOSA)
808c2ecf20Sopenharmony_ci *  - Statistical profiler (MDCR_EL2_TPMS/MDCR_EL2_E2PB)
818c2ecf20Sopenharmony_ci *  - Self-hosted Trace Filter controls (MDCR_EL2_TTRF)
828c2ecf20Sopenharmony_ci */
838c2ecf20Sopenharmony_cistatic void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	/*
868c2ecf20Sopenharmony_ci	 * This also clears MDCR_EL2_E2PB_MASK to disable guest access
878c2ecf20Sopenharmony_ci	 * to the profiling buffer.
888c2ecf20Sopenharmony_ci	 */
898c2ecf20Sopenharmony_ci	vcpu->arch.mdcr_el2 = __this_cpu_read(mdcr_el2) & MDCR_EL2_HPMN_MASK;
908c2ecf20Sopenharmony_ci	vcpu->arch.mdcr_el2 |= (MDCR_EL2_TPM |
918c2ecf20Sopenharmony_ci				MDCR_EL2_TPMS |
928c2ecf20Sopenharmony_ci				MDCR_EL2_TTRF |
938c2ecf20Sopenharmony_ci				MDCR_EL2_TPMCR |
948c2ecf20Sopenharmony_ci				MDCR_EL2_TDRA |
958c2ecf20Sopenharmony_ci				MDCR_EL2_TDOSA);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	/* Is the VM being debugged by userspace? */
988c2ecf20Sopenharmony_ci	if (vcpu->guest_debug)
998c2ecf20Sopenharmony_ci		/* Route all software debug exceptions to EL2 */
1008c2ecf20Sopenharmony_ci		vcpu->arch.mdcr_el2 |= MDCR_EL2_TDE;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	/*
1038c2ecf20Sopenharmony_ci	 * Trap debug register access when one of the following is true:
1048c2ecf20Sopenharmony_ci	 *  - Userspace is using the hardware to debug the guest
1058c2ecf20Sopenharmony_ci	 *  (KVM_GUESTDBG_USE_HW is set).
1068c2ecf20Sopenharmony_ci	 *  - The guest is not using debug (KVM_ARM64_DEBUG_DIRTY is clear).
1078c2ecf20Sopenharmony_ci	 */
1088c2ecf20Sopenharmony_ci	if ((vcpu->guest_debug & KVM_GUESTDBG_USE_HW) ||
1098c2ecf20Sopenharmony_ci	    !(vcpu->arch.flags & KVM_ARM64_DEBUG_DIRTY))
1108c2ecf20Sopenharmony_ci		vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	trace_kvm_arm_set_dreg32("MDCR_EL2", vcpu->arch.mdcr_el2);
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci/**
1168c2ecf20Sopenharmony_ci * kvm_arm_vcpu_init_debug - setup vcpu debug traps
1178c2ecf20Sopenharmony_ci *
1188c2ecf20Sopenharmony_ci * @vcpu:	the vcpu pointer
1198c2ecf20Sopenharmony_ci *
1208c2ecf20Sopenharmony_ci * Set vcpu initial mdcr_el2 value.
1218c2ecf20Sopenharmony_ci */
1228c2ecf20Sopenharmony_civoid kvm_arm_vcpu_init_debug(struct kvm_vcpu *vcpu)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	preempt_disable();
1258c2ecf20Sopenharmony_ci	kvm_arm_setup_mdcr_el2(vcpu);
1268c2ecf20Sopenharmony_ci	preempt_enable();
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci/**
1308c2ecf20Sopenharmony_ci * kvm_arm_reset_debug_ptr - reset the debug ptr to point to the vcpu state
1318c2ecf20Sopenharmony_ci */
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_civoid kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	vcpu->arch.debug_ptr = &vcpu->arch.vcpu_debug_state;
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci/**
1398c2ecf20Sopenharmony_ci * kvm_arm_setup_debug - set up debug related stuff
1408c2ecf20Sopenharmony_ci *
1418c2ecf20Sopenharmony_ci * @vcpu:	the vcpu pointer
1428c2ecf20Sopenharmony_ci *
1438c2ecf20Sopenharmony_ci * This is called before each entry into the hypervisor to setup any
1448c2ecf20Sopenharmony_ci * debug related registers.
1458c2ecf20Sopenharmony_ci *
1468c2ecf20Sopenharmony_ci * Additionally, KVM only traps guest accesses to the debug registers if
1478c2ecf20Sopenharmony_ci * the guest is not actively using them (see the KVM_ARM64_DEBUG_DIRTY
1488c2ecf20Sopenharmony_ci * flag on vcpu->arch.flags).  Since the guest must not interfere
1498c2ecf20Sopenharmony_ci * with the hardware state when debugging the guest, we must ensure that
1508c2ecf20Sopenharmony_ci * trapping is enabled whenever we are debugging the guest using the
1518c2ecf20Sopenharmony_ci * debug registers.
1528c2ecf20Sopenharmony_ci */
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_civoid kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
1558c2ecf20Sopenharmony_ci{
1568c2ecf20Sopenharmony_ci	unsigned long mdscr, orig_mdcr_el2 = vcpu->arch.mdcr_el2;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	trace_kvm_arm_setup_debug(vcpu, vcpu->guest_debug);
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	kvm_arm_setup_mdcr_el2(vcpu);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	/* Is Guest debugging in effect? */
1638c2ecf20Sopenharmony_ci	if (vcpu->guest_debug) {
1648c2ecf20Sopenharmony_ci		/* Save guest debug state */
1658c2ecf20Sopenharmony_ci		save_guest_debug_regs(vcpu);
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci		/*
1688c2ecf20Sopenharmony_ci		 * Single Step (ARM ARM D2.12.3 The software step state
1698c2ecf20Sopenharmony_ci		 * machine)
1708c2ecf20Sopenharmony_ci		 *
1718c2ecf20Sopenharmony_ci		 * If we are doing Single Step we need to manipulate
1728c2ecf20Sopenharmony_ci		 * the guest's MDSCR_EL1.SS and PSTATE.SS. Once the
1738c2ecf20Sopenharmony_ci		 * step has occurred the hypervisor will trap the
1748c2ecf20Sopenharmony_ci		 * debug exception and we return to userspace.
1758c2ecf20Sopenharmony_ci		 *
1768c2ecf20Sopenharmony_ci		 * If the guest attempts to single step its userspace
1778c2ecf20Sopenharmony_ci		 * we would have to deal with a trapped exception
1788c2ecf20Sopenharmony_ci		 * while in the guest kernel. Because this would be
1798c2ecf20Sopenharmony_ci		 * hard to unwind we suppress the guest's ability to
1808c2ecf20Sopenharmony_ci		 * do so by masking MDSCR_EL.SS.
1818c2ecf20Sopenharmony_ci		 *
1828c2ecf20Sopenharmony_ci		 * This confuses guest debuggers which use
1838c2ecf20Sopenharmony_ci		 * single-step behind the scenes but everything
1848c2ecf20Sopenharmony_ci		 * returns to normal once the host is no longer
1858c2ecf20Sopenharmony_ci		 * debugging the system.
1868c2ecf20Sopenharmony_ci		 */
1878c2ecf20Sopenharmony_ci		if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
1888c2ecf20Sopenharmony_ci			*vcpu_cpsr(vcpu) |=  DBG_SPSR_SS;
1898c2ecf20Sopenharmony_ci			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
1908c2ecf20Sopenharmony_ci			mdscr |= DBG_MDSCR_SS;
1918c2ecf20Sopenharmony_ci			vcpu_write_sys_reg(vcpu, mdscr, MDSCR_EL1);
1928c2ecf20Sopenharmony_ci		} else {
1938c2ecf20Sopenharmony_ci			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
1948c2ecf20Sopenharmony_ci			mdscr &= ~DBG_MDSCR_SS;
1958c2ecf20Sopenharmony_ci			vcpu_write_sys_reg(vcpu, mdscr, MDSCR_EL1);
1968c2ecf20Sopenharmony_ci		}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci		trace_kvm_arm_set_dreg32("SPSR_EL2", *vcpu_cpsr(vcpu));
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci		/*
2018c2ecf20Sopenharmony_ci		 * HW Breakpoints and watchpoints
2028c2ecf20Sopenharmony_ci		 *
2038c2ecf20Sopenharmony_ci		 * We simply switch the debug_ptr to point to our new
2048c2ecf20Sopenharmony_ci		 * external_debug_state which has been populated by the
2058c2ecf20Sopenharmony_ci		 * debug ioctl. The existing KVM_ARM64_DEBUG_DIRTY
2068c2ecf20Sopenharmony_ci		 * mechanism ensures the registers are updated on the
2078c2ecf20Sopenharmony_ci		 * world switch.
2088c2ecf20Sopenharmony_ci		 */
2098c2ecf20Sopenharmony_ci		if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) {
2108c2ecf20Sopenharmony_ci			/* Enable breakpoints/watchpoints */
2118c2ecf20Sopenharmony_ci			mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
2128c2ecf20Sopenharmony_ci			mdscr |= DBG_MDSCR_MDE;
2138c2ecf20Sopenharmony_ci			vcpu_write_sys_reg(vcpu, mdscr, MDSCR_EL1);
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci			vcpu->arch.debug_ptr = &vcpu->arch.external_debug_state;
2168c2ecf20Sopenharmony_ci			vcpu->arch.flags |= KVM_ARM64_DEBUG_DIRTY;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci			trace_kvm_arm_set_regset("BKPTS", get_num_brps(),
2198c2ecf20Sopenharmony_ci						&vcpu->arch.debug_ptr->dbg_bcr[0],
2208c2ecf20Sopenharmony_ci						&vcpu->arch.debug_ptr->dbg_bvr[0]);
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci			trace_kvm_arm_set_regset("WAPTS", get_num_wrps(),
2238c2ecf20Sopenharmony_ci						&vcpu->arch.debug_ptr->dbg_wcr[0],
2248c2ecf20Sopenharmony_ci						&vcpu->arch.debug_ptr->dbg_wvr[0]);
2258c2ecf20Sopenharmony_ci		}
2268c2ecf20Sopenharmony_ci	}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	BUG_ON(!vcpu->guest_debug &&
2298c2ecf20Sopenharmony_ci		vcpu->arch.debug_ptr != &vcpu->arch.vcpu_debug_state);
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	/* If KDE or MDE are set, perform a full save/restore cycle. */
2328c2ecf20Sopenharmony_ci	if (vcpu_read_sys_reg(vcpu, MDSCR_EL1) & (DBG_MDSCR_KDE | DBG_MDSCR_MDE))
2338c2ecf20Sopenharmony_ci		vcpu->arch.flags |= KVM_ARM64_DEBUG_DIRTY;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	/* Write mdcr_el2 changes since vcpu_load on VHE systems */
2368c2ecf20Sopenharmony_ci	if (has_vhe() && orig_mdcr_el2 != vcpu->arch.mdcr_el2)
2378c2ecf20Sopenharmony_ci		write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	trace_kvm_arm_set_dreg32("MDSCR_EL1", vcpu_read_sys_reg(vcpu, MDSCR_EL1));
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_civoid kvm_arm_clear_debug(struct kvm_vcpu *vcpu)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	trace_kvm_arm_clear_debug(vcpu->guest_debug);
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	if (vcpu->guest_debug) {
2478c2ecf20Sopenharmony_ci		restore_guest_debug_regs(vcpu);
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci		/*
2508c2ecf20Sopenharmony_ci		 * If we were using HW debug we need to restore the
2518c2ecf20Sopenharmony_ci		 * debug_ptr to the guest debug state.
2528c2ecf20Sopenharmony_ci		 */
2538c2ecf20Sopenharmony_ci		if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) {
2548c2ecf20Sopenharmony_ci			kvm_arm_reset_debug_ptr(vcpu);
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci			trace_kvm_arm_set_regset("BKPTS", get_num_brps(),
2578c2ecf20Sopenharmony_ci						&vcpu->arch.debug_ptr->dbg_bcr[0],
2588c2ecf20Sopenharmony_ci						&vcpu->arch.debug_ptr->dbg_bvr[0]);
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci			trace_kvm_arm_set_regset("WAPTS", get_num_wrps(),
2618c2ecf20Sopenharmony_ci						&vcpu->arch.debug_ptr->dbg_wcr[0],
2628c2ecf20Sopenharmony_ci						&vcpu->arch.debug_ptr->dbg_wvr[0]);
2638c2ecf20Sopenharmony_ci		}
2648c2ecf20Sopenharmony_ci	}
2658c2ecf20Sopenharmony_ci}
266