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