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