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); 30d400c5b2SDavid Brazdil if (!(reg & BIT(SYS_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 */ 87*b1da4908SMarc 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 */ 90*b1da4908SMarc 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 { 101*b1da4908SMarc Zyngier if (vcpu_get_flag(vcpu, DEBUG_STATE_SAVE_SPE)) 102b96b0c5dSSuzuki K Poulose __debug_restore_spe(vcpu->arch.host_debug_state.pmscr_el1); 103*b1da4908SMarc 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