18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2012-2015 - ARM Ltd
48c2ecf20Sopenharmony_ci * Author: Marc Zyngier <marc.zyngier@arm.com>
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <hyp/sysreg-sr.h>
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/compiler.h>
108c2ecf20Sopenharmony_ci#include <linux/kvm_host.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <asm/kprobes.h>
138c2ecf20Sopenharmony_ci#include <asm/kvm_asm.h>
148c2ecf20Sopenharmony_ci#include <asm/kvm_emulate.h>
158c2ecf20Sopenharmony_ci#include <asm/kvm_hyp.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/*
188c2ecf20Sopenharmony_ci * VHE: Host and guest must save mdscr_el1 and sp_el0 (and the PC and
198c2ecf20Sopenharmony_ci * pstate, which are handled as part of the el2 return state) on every
208c2ecf20Sopenharmony_ci * switch (sp_el0 is being dealt with in the assembly code).
218c2ecf20Sopenharmony_ci * tpidr_el0 and tpidrro_el0 only need to be switched when going
228c2ecf20Sopenharmony_ci * to host userspace or a different VCPU.  EL1 registers only need to be
238c2ecf20Sopenharmony_ci * switched when potentially going to run a different VCPU.  The latter two
248c2ecf20Sopenharmony_ci * classes are handled as part of kvm_arch_vcpu_load and kvm_arch_vcpu_put.
258c2ecf20Sopenharmony_ci */
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_civoid sysreg_save_host_state_vhe(struct kvm_cpu_context *ctxt)
288c2ecf20Sopenharmony_ci{
298c2ecf20Sopenharmony_ci	__sysreg_save_common_state(ctxt);
308c2ecf20Sopenharmony_ci}
318c2ecf20Sopenharmony_ciNOKPROBE_SYMBOL(sysreg_save_host_state_vhe);
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_civoid sysreg_save_guest_state_vhe(struct kvm_cpu_context *ctxt)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	__sysreg_save_common_state(ctxt);
368c2ecf20Sopenharmony_ci	__sysreg_save_el2_return_state(ctxt);
378c2ecf20Sopenharmony_ci}
388c2ecf20Sopenharmony_ciNOKPROBE_SYMBOL(sysreg_save_guest_state_vhe);
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_civoid sysreg_restore_host_state_vhe(struct kvm_cpu_context *ctxt)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	__sysreg_restore_common_state(ctxt);
438c2ecf20Sopenharmony_ci}
448c2ecf20Sopenharmony_ciNOKPROBE_SYMBOL(sysreg_restore_host_state_vhe);
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_civoid sysreg_restore_guest_state_vhe(struct kvm_cpu_context *ctxt)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	__sysreg_restore_common_state(ctxt);
498c2ecf20Sopenharmony_ci	__sysreg_restore_el2_return_state(ctxt);
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ciNOKPROBE_SYMBOL(sysreg_restore_guest_state_vhe);
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci/**
548c2ecf20Sopenharmony_ci * kvm_vcpu_load_sysregs_vhe - Load guest system registers to the physical CPU
558c2ecf20Sopenharmony_ci *
568c2ecf20Sopenharmony_ci * @vcpu: The VCPU pointer
578c2ecf20Sopenharmony_ci *
588c2ecf20Sopenharmony_ci * Load system registers that do not affect the host's execution, for
598c2ecf20Sopenharmony_ci * example EL1 system registers on a VHE system where the host kernel
608c2ecf20Sopenharmony_ci * runs at EL2.  This function is called from KVM's vcpu_load() function
618c2ecf20Sopenharmony_ci * and loading system register state early avoids having to load them on
628c2ecf20Sopenharmony_ci * every entry to the VM.
638c2ecf20Sopenharmony_ci */
648c2ecf20Sopenharmony_civoid kvm_vcpu_load_sysregs_vhe(struct kvm_vcpu *vcpu)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	struct kvm_cpu_context *guest_ctxt = &vcpu->arch.ctxt;
678c2ecf20Sopenharmony_ci	struct kvm_cpu_context *host_ctxt;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	host_ctxt = &this_cpu_ptr(&kvm_host_data)->host_ctxt;
708c2ecf20Sopenharmony_ci	__sysreg_save_user_state(host_ctxt);
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	/*
738c2ecf20Sopenharmony_ci	 * Load guest EL1 and user state
748c2ecf20Sopenharmony_ci	 *
758c2ecf20Sopenharmony_ci	 * We must restore the 32-bit state before the sysregs, thanks
768c2ecf20Sopenharmony_ci	 * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
778c2ecf20Sopenharmony_ci	 */
788c2ecf20Sopenharmony_ci	__sysreg32_restore_state(vcpu);
798c2ecf20Sopenharmony_ci	__sysreg_restore_user_state(guest_ctxt);
808c2ecf20Sopenharmony_ci	__sysreg_restore_el1_state(guest_ctxt);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	vcpu->arch.sysregs_loaded_on_cpu = true;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	activate_traps_vhe_load(vcpu);
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci/**
888c2ecf20Sopenharmony_ci * kvm_vcpu_put_sysregs_vhe - Restore host system registers to the physical CPU
898c2ecf20Sopenharmony_ci *
908c2ecf20Sopenharmony_ci * @vcpu: The VCPU pointer
918c2ecf20Sopenharmony_ci *
928c2ecf20Sopenharmony_ci * Save guest system registers that do not affect the host's execution, for
938c2ecf20Sopenharmony_ci * example EL1 system registers on a VHE system where the host kernel
948c2ecf20Sopenharmony_ci * runs at EL2.  This function is called from KVM's vcpu_put() function
958c2ecf20Sopenharmony_ci * and deferring saving system register state until we're no longer running the
968c2ecf20Sopenharmony_ci * VCPU avoids having to save them on every exit from the VM.
978c2ecf20Sopenharmony_ci */
988c2ecf20Sopenharmony_civoid kvm_vcpu_put_sysregs_vhe(struct kvm_vcpu *vcpu)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	struct kvm_cpu_context *guest_ctxt = &vcpu->arch.ctxt;
1018c2ecf20Sopenharmony_ci	struct kvm_cpu_context *host_ctxt;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	host_ctxt = &this_cpu_ptr(&kvm_host_data)->host_ctxt;
1048c2ecf20Sopenharmony_ci	deactivate_traps_vhe_put();
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	__sysreg_save_el1_state(guest_ctxt);
1078c2ecf20Sopenharmony_ci	__sysreg_save_user_state(guest_ctxt);
1088c2ecf20Sopenharmony_ci	__sysreg32_save_state(vcpu);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	/* Restore host user state */
1118c2ecf20Sopenharmony_ci	__sysreg_restore_user_state(host_ctxt);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	vcpu->arch.sysregs_loaded_on_cpu = false;
1148c2ecf20Sopenharmony_ci}
115