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 17 static void __debug_save_spe(u64 *pmscr_el1) 18 { 19 u64 reg; 20 21 /* Clear pmscr in case of early return */ 22 *pmscr_el1 = 0; 23 24 /* SPE present on this CPU? */ 25 if (!cpuid_feature_extract_unsigned_field(read_sysreg(id_aa64dfr0_el1), 26 ID_AA64DFR0_PMSVER_SHIFT)) 27 return; 28 29 /* Yes; is it owned by EL3? */ 30 reg = read_sysreg_s(SYS_PMBIDR_EL1); 31 if (reg & BIT(SYS_PMBIDR_EL1_P_SHIFT)) 32 return; 33 34 /* No; is the host actually using the thing? */ 35 reg = read_sysreg_s(SYS_PMBLIMITR_EL1); 36 if (!(reg & BIT(SYS_PMBLIMITR_EL1_E_SHIFT))) 37 return; 38 39 /* Yes; save the control register and disable data generation */ 40 *pmscr_el1 = read_sysreg_s(SYS_PMSCR_EL1); 41 write_sysreg_s(0, SYS_PMSCR_EL1); 42 isb(); 43 44 /* Now drain all buffered data to memory */ 45 psb_csync(); 46 dsb(nsh); 47 } 48 49 static void __debug_restore_spe(u64 pmscr_el1) 50 { 51 if (!pmscr_el1) 52 return; 53 54 /* The host page table is installed, but not yet synchronised */ 55 isb(); 56 57 /* Re-enable data generation */ 58 write_sysreg_s(pmscr_el1, SYS_PMSCR_EL1); 59 } 60 61 void __debug_switch_to_guest(struct kvm_vcpu *vcpu) 62 { 63 /* Disable and flush SPE data generation */ 64 __debug_save_spe(&vcpu->arch.host_debug_state.pmscr_el1); 65 __debug_switch_to_guest_common(vcpu); 66 } 67 68 void __debug_switch_to_host(struct kvm_vcpu *vcpu) 69 { 70 __debug_restore_spe(vcpu->arch.host_debug_state.pmscr_el1); 71 __debug_switch_to_host_common(vcpu); 72 } 73 74 u32 __kvm_get_mdcr_el2(void) 75 { 76 return read_sysreg(mdcr_el2); 77 } 78