162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2012-2015 - ARM Ltd 462306a36Sopenharmony_ci * Author: Marc Zyngier <marc.zyngier@arm.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <hyp/sysreg-sr.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/compiler.h> 1062306a36Sopenharmony_ci#include <linux/kvm_host.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <asm/kprobes.h> 1362306a36Sopenharmony_ci#include <asm/kvm_asm.h> 1462306a36Sopenharmony_ci#include <asm/kvm_emulate.h> 1562306a36Sopenharmony_ci#include <asm/kvm_hyp.h> 1662306a36Sopenharmony_ci#include <asm/kvm_nested.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/* 1962306a36Sopenharmony_ci * VHE: Host and guest must save mdscr_el1 and sp_el0 (and the PC and 2062306a36Sopenharmony_ci * pstate, which are handled as part of the el2 return state) on every 2162306a36Sopenharmony_ci * switch (sp_el0 is being dealt with in the assembly code). 2262306a36Sopenharmony_ci * tpidr_el0 and tpidrro_el0 only need to be switched when going 2362306a36Sopenharmony_ci * to host userspace or a different VCPU. EL1 registers only need to be 2462306a36Sopenharmony_ci * switched when potentially going to run a different VCPU. The latter two 2562306a36Sopenharmony_ci * classes are handled as part of kvm_arch_vcpu_load and kvm_arch_vcpu_put. 2662306a36Sopenharmony_ci */ 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_civoid sysreg_save_host_state_vhe(struct kvm_cpu_context *ctxt) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci __sysreg_save_common_state(ctxt); 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_ciNOKPROBE_SYMBOL(sysreg_save_host_state_vhe); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_civoid sysreg_save_guest_state_vhe(struct kvm_cpu_context *ctxt) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci __sysreg_save_common_state(ctxt); 3762306a36Sopenharmony_ci __sysreg_save_el2_return_state(ctxt); 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ciNOKPROBE_SYMBOL(sysreg_save_guest_state_vhe); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_civoid sysreg_restore_host_state_vhe(struct kvm_cpu_context *ctxt) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci __sysreg_restore_common_state(ctxt); 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ciNOKPROBE_SYMBOL(sysreg_restore_host_state_vhe); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_civoid sysreg_restore_guest_state_vhe(struct kvm_cpu_context *ctxt) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci __sysreg_restore_common_state(ctxt); 5062306a36Sopenharmony_ci __sysreg_restore_el2_return_state(ctxt); 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ciNOKPROBE_SYMBOL(sysreg_restore_guest_state_vhe); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/** 5562306a36Sopenharmony_ci * kvm_vcpu_load_sysregs_vhe - Load guest system registers to the physical CPU 5662306a36Sopenharmony_ci * 5762306a36Sopenharmony_ci * @vcpu: The VCPU pointer 5862306a36Sopenharmony_ci * 5962306a36Sopenharmony_ci * Load system registers that do not affect the host's execution, for 6062306a36Sopenharmony_ci * example EL1 system registers on a VHE system where the host kernel 6162306a36Sopenharmony_ci * runs at EL2. This function is called from KVM's vcpu_load() function 6262306a36Sopenharmony_ci * and loading system register state early avoids having to load them on 6362306a36Sopenharmony_ci * every entry to the VM. 6462306a36Sopenharmony_ci */ 6562306a36Sopenharmony_civoid kvm_vcpu_load_sysregs_vhe(struct kvm_vcpu *vcpu) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci struct kvm_cpu_context *guest_ctxt = &vcpu->arch.ctxt; 6862306a36Sopenharmony_ci struct kvm_cpu_context *host_ctxt; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci host_ctxt = &this_cpu_ptr(&kvm_host_data)->host_ctxt; 7162306a36Sopenharmony_ci __sysreg_save_user_state(host_ctxt); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci /* 7462306a36Sopenharmony_ci * When running a normal EL1 guest, we only load a new vcpu 7562306a36Sopenharmony_ci * after a context switch, which imvolves a DSB, so all 7662306a36Sopenharmony_ci * speculative EL1&0 walks will have already completed. 7762306a36Sopenharmony_ci * If running NV, the vcpu may transition between vEL1 and 7862306a36Sopenharmony_ci * vEL2 without a context switch, so make sure we complete 7962306a36Sopenharmony_ci * those walks before loading a new context. 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_ci if (vcpu_has_nv(vcpu)) 8262306a36Sopenharmony_ci dsb(nsh); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci /* 8562306a36Sopenharmony_ci * Load guest EL1 and user state 8662306a36Sopenharmony_ci * 8762306a36Sopenharmony_ci * We must restore the 32-bit state before the sysregs, thanks 8862306a36Sopenharmony_ci * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72). 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_ci __sysreg32_restore_state(vcpu); 9162306a36Sopenharmony_ci __sysreg_restore_user_state(guest_ctxt); 9262306a36Sopenharmony_ci __sysreg_restore_el1_state(guest_ctxt); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci vcpu_set_flag(vcpu, SYSREGS_ON_CPU); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci activate_traps_vhe_load(vcpu); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/** 10062306a36Sopenharmony_ci * kvm_vcpu_put_sysregs_vhe - Restore host system registers to the physical CPU 10162306a36Sopenharmony_ci * 10262306a36Sopenharmony_ci * @vcpu: The VCPU pointer 10362306a36Sopenharmony_ci * 10462306a36Sopenharmony_ci * Save guest system registers that do not affect the host's execution, for 10562306a36Sopenharmony_ci * example EL1 system registers on a VHE system where the host kernel 10662306a36Sopenharmony_ci * runs at EL2. This function is called from KVM's vcpu_put() function 10762306a36Sopenharmony_ci * and deferring saving system register state until we're no longer running the 10862306a36Sopenharmony_ci * VCPU avoids having to save them on every exit from the VM. 10962306a36Sopenharmony_ci */ 11062306a36Sopenharmony_civoid kvm_vcpu_put_sysregs_vhe(struct kvm_vcpu *vcpu) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci struct kvm_cpu_context *guest_ctxt = &vcpu->arch.ctxt; 11362306a36Sopenharmony_ci struct kvm_cpu_context *host_ctxt; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci host_ctxt = &this_cpu_ptr(&kvm_host_data)->host_ctxt; 11662306a36Sopenharmony_ci deactivate_traps_vhe_put(vcpu); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci __sysreg_save_el1_state(guest_ctxt); 11962306a36Sopenharmony_ci __sysreg_save_user_state(guest_ctxt); 12062306a36Sopenharmony_ci __sysreg32_save_state(vcpu); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci /* Restore host user state */ 12362306a36Sopenharmony_ci __sysreg_restore_user_state(host_ctxt); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci vcpu_clear_flag(vcpu, SYSREGS_ON_CPU); 12662306a36Sopenharmony_ci} 127