mirror of
https://github.com/torvalds/linux.git
synced 2024-12-24 20:01:55 +00:00
0e5b9c085d
On systems with v8.2 we switch the 'vaxorcism' of guest SError with an alternative sequence that uses the ESB-instruction, then reads DISR_EL1. This saves the unmasking and remasking of asynchronous exceptions. We do this after we've saved the guest registers and restored the host's. Any SError that becomes pending due to this will be accounted to the guest, when it actually occurred during host-execution. Move the ESB-instruction as early as possible. Any guest SError will become pending due to this ESB-instruction and then consumed to DISR_EL1 before the host touches anything. This lets us account for host/guest SError precisely on the guest exit exception boundary. Because the ESB-instruction now lands in the preamble section of the vectors, we need to add it to the unpatched indirect vectors too, and to any sequence that may be patched in over the top. The ESB-instruction always lives in the head of the vectors, to be before any memory write. Whereas the register-store always lives in the tail. Signed-off-by: James Morse <james.morse@arm.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
119 lines
3.0 KiB
C
119 lines
3.0 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/*
|
|
* Copyright (C) 2012,2013 - ARM Ltd
|
|
* Author: Marc Zyngier <marc.zyngier@arm.com>
|
|
*/
|
|
|
|
#ifndef __ARM_KVM_ASM_H__
|
|
#define __ARM_KVM_ASM_H__
|
|
|
|
#include <asm/virt.h>
|
|
|
|
#define VCPU_WORKAROUND_2_FLAG_SHIFT 0
|
|
#define VCPU_WORKAROUND_2_FLAG (_AC(1, UL) << VCPU_WORKAROUND_2_FLAG_SHIFT)
|
|
|
|
#define ARM_EXIT_WITH_SERROR_BIT 31
|
|
#define ARM_EXCEPTION_CODE(x) ((x) & ~(1U << ARM_EXIT_WITH_SERROR_BIT))
|
|
#define ARM_EXCEPTION_IS_TRAP(x) (ARM_EXCEPTION_CODE((x)) == ARM_EXCEPTION_TRAP)
|
|
#define ARM_SERROR_PENDING(x) !!((x) & (1U << ARM_EXIT_WITH_SERROR_BIT))
|
|
|
|
#define ARM_EXCEPTION_IRQ 0
|
|
#define ARM_EXCEPTION_EL1_SERROR 1
|
|
#define ARM_EXCEPTION_TRAP 2
|
|
#define ARM_EXCEPTION_IL 3
|
|
/* The hyp-stub will return this for any kvm_call_hyp() call */
|
|
#define ARM_EXCEPTION_HYP_GONE HVC_STUB_ERR
|
|
|
|
#define kvm_arm_exception_type \
|
|
{ARM_EXCEPTION_IRQ, "IRQ" }, \
|
|
{ARM_EXCEPTION_EL1_SERROR, "SERROR" }, \
|
|
{ARM_EXCEPTION_TRAP, "TRAP" }, \
|
|
{ARM_EXCEPTION_HYP_GONE, "HYP_GONE" }
|
|
|
|
/*
|
|
* Size of the HYP vectors preamble. kvm_patch_vector_branch() generates code
|
|
* that jumps over this.
|
|
*/
|
|
#define KVM_VECTOR_PREAMBLE (2 * AARCH64_INSN_SIZE)
|
|
|
|
#ifndef __ASSEMBLY__
|
|
|
|
#include <linux/mm.h>
|
|
|
|
/* Translate a kernel address of @sym into its equivalent linear mapping */
|
|
#define kvm_ksym_ref(sym) \
|
|
({ \
|
|
void *val = &sym; \
|
|
if (!is_kernel_in_hyp_mode()) \
|
|
val = lm_alias(&sym); \
|
|
val; \
|
|
})
|
|
|
|
struct kvm;
|
|
struct kvm_vcpu;
|
|
|
|
extern char __kvm_hyp_init[];
|
|
extern char __kvm_hyp_init_end[];
|
|
|
|
extern char __kvm_hyp_vector[];
|
|
|
|
extern void __kvm_flush_vm_context(void);
|
|
extern void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
|
|
extern void __kvm_tlb_flush_vmid(struct kvm *kvm);
|
|
extern void __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu);
|
|
|
|
extern void __kvm_timer_set_cntvoff(u32 cntvoff_low, u32 cntvoff_high);
|
|
|
|
extern int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu);
|
|
|
|
extern int __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu);
|
|
|
|
extern u64 __vgic_v3_get_ich_vtr_el2(void);
|
|
extern u64 __vgic_v3_read_vmcr(void);
|
|
extern void __vgic_v3_write_vmcr(u32 vmcr);
|
|
extern void __vgic_v3_init_lrs(void);
|
|
|
|
extern u32 __kvm_get_mdcr_el2(void);
|
|
|
|
/* Home-grown __this_cpu_{ptr,read} variants that always work at HYP */
|
|
#define __hyp_this_cpu_ptr(sym) \
|
|
({ \
|
|
void *__ptr = hyp_symbol_addr(sym); \
|
|
__ptr += read_sysreg(tpidr_el2); \
|
|
(typeof(&sym))__ptr; \
|
|
})
|
|
|
|
#define __hyp_this_cpu_read(sym) \
|
|
({ \
|
|
*__hyp_this_cpu_ptr(sym); \
|
|
})
|
|
|
|
#else /* __ASSEMBLY__ */
|
|
|
|
.macro hyp_adr_this_cpu reg, sym, tmp
|
|
adr_l \reg, \sym
|
|
mrs \tmp, tpidr_el2
|
|
add \reg, \reg, \tmp
|
|
.endm
|
|
|
|
.macro hyp_ldr_this_cpu reg, sym, tmp
|
|
adr_l \reg, \sym
|
|
mrs \tmp, tpidr_el2
|
|
ldr \reg, [\reg, \tmp]
|
|
.endm
|
|
|
|
.macro get_host_ctxt reg, tmp
|
|
hyp_adr_this_cpu \reg, kvm_host_data, \tmp
|
|
add \reg, \reg, #HOST_DATA_CONTEXT
|
|
.endm
|
|
|
|
.macro get_vcpu_ptr vcpu, ctxt
|
|
get_host_ctxt \ctxt, \vcpu
|
|
ldr \vcpu, [\ctxt, #HOST_CONTEXT_VCPU]
|
|
kern_hyp_va \vcpu
|
|
.endm
|
|
|
|
#endif
|
|
|
|
#endif /* __ARM_KVM_ASM_H__ */
|