18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2015 - ARM Ltd 48c2ecf20Sopenharmony_ci * Author: Marc Zyngier <marc.zyngier@arm.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <hyp/debug-sr.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/compiler.h> 108c2ecf20Sopenharmony_ci#include <linux/kvm_host.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <asm/debug-monitors.h> 138c2ecf20Sopenharmony_ci#include <asm/kvm_asm.h> 148c2ecf20Sopenharmony_ci#include <asm/kvm_hyp.h> 158c2ecf20Sopenharmony_ci#include <asm/kvm_mmu.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistatic void __debug_save_spe(u64 *pmscr_el1) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci u64 reg; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci /* Clear pmscr in case of early return */ 228c2ecf20Sopenharmony_ci *pmscr_el1 = 0; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci /* SPE present on this CPU? */ 258c2ecf20Sopenharmony_ci if (!cpuid_feature_extract_unsigned_field(read_sysreg(id_aa64dfr0_el1), 268c2ecf20Sopenharmony_ci ID_AA64DFR0_PMSVER_SHIFT)) 278c2ecf20Sopenharmony_ci return; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci /* Yes; is it owned by EL3? */ 308c2ecf20Sopenharmony_ci reg = read_sysreg_s(SYS_PMBIDR_EL1); 318c2ecf20Sopenharmony_ci if (reg & BIT(SYS_PMBIDR_EL1_P_SHIFT)) 328c2ecf20Sopenharmony_ci return; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci /* No; is the host actually using the thing? */ 358c2ecf20Sopenharmony_ci reg = read_sysreg_s(SYS_PMBLIMITR_EL1); 368c2ecf20Sopenharmony_ci if (!(reg & BIT(SYS_PMBLIMITR_EL1_E_SHIFT))) 378c2ecf20Sopenharmony_ci return; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci /* Yes; save the control register and disable data generation */ 408c2ecf20Sopenharmony_ci *pmscr_el1 = read_sysreg_s(SYS_PMSCR_EL1); 418c2ecf20Sopenharmony_ci write_sysreg_s(0, SYS_PMSCR_EL1); 428c2ecf20Sopenharmony_ci isb(); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci /* Now drain all buffered data to memory */ 458c2ecf20Sopenharmony_ci psb_csync(); 468c2ecf20Sopenharmony_ci dsb(nsh); 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic void __debug_restore_spe(u64 pmscr_el1) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci if (!pmscr_el1) 528c2ecf20Sopenharmony_ci return; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci /* The host page table is installed, but not yet synchronised */ 558c2ecf20Sopenharmony_ci isb(); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci /* Re-enable data generation */ 588c2ecf20Sopenharmony_ci write_sysreg_s(pmscr_el1, SYS_PMSCR_EL1); 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_civoid __debug_save_host_buffers_nvhe(struct kvm_vcpu *vcpu) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci /* Disable and flush SPE data generation */ 648c2ecf20Sopenharmony_ci __debug_save_spe(&vcpu->arch.host_debug_state.pmscr_el1); 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_civoid __debug_switch_to_guest(struct kvm_vcpu *vcpu) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci __debug_switch_to_guest_common(vcpu); 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_civoid __debug_restore_host_buffers_nvhe(struct kvm_vcpu *vcpu) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci __debug_restore_spe(vcpu->arch.host_debug_state.pmscr_el1); 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_civoid __debug_switch_to_host(struct kvm_vcpu *vcpu) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci __debug_switch_to_host_common(vcpu); 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ciu32 __kvm_get_mdcr_el2(void) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci return read_sysreg(mdcr_el2); 858c2ecf20Sopenharmony_ci} 86