[PATCH v3 17/32] arm64: KVM: HYP mode world switch implementation
Christoffer Dall
cdall at cs.columbia.edu
Tue Apr 23 18:59:58 EDT 2013
On Mon, Apr 08, 2013 at 05:17:19PM +0100, Marc Zyngier wrote:
> The HYP mode world switch in all its glory.
>
> Implements save/restore of host/guest registers, EL2 trapping,
> IPA resolution, and additional services (tlb invalidation).
>
> Reviewed-by: Christopher Covington <cov at codeaurora.org>
> Signed-off-by: Marc Zyngier <marc.zyngier at arm.com>
> ---
> arch/arm64/kernel/asm-offsets.c | 34 +++
> arch/arm64/kvm/hyp.S | 602 ++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 636 insertions(+)
> create mode 100644 arch/arm64/kvm/hyp.S
>
> diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
> index a2a4d81..666e231 100644
> --- a/arch/arm64/kernel/asm-offsets.c
> +++ b/arch/arm64/kernel/asm-offsets.c
> @@ -21,6 +21,7 @@
> #include <linux/sched.h>
> #include <linux/mm.h>
> #include <linux/dma-mapping.h>
> +#include <linux/kvm_host.h>
> #include <asm/thread_info.h>
> #include <asm/memory.h>
> #include <asm/cputable.h>
> @@ -104,5 +105,38 @@ int main(void)
> BLANK();
> DEFINE(TZ_MINWEST, offsetof(struct timezone, tz_minuteswest));
> DEFINE(TZ_DSTTIME, offsetof(struct timezone, tz_dsttime));
> + BLANK();
> +#ifdef CONFIG_KVM_ARM_HOST
> + DEFINE(VCPU_CONTEXT, offsetof(struct kvm_vcpu, arch.ctxt));
> + DEFINE(CPU_GP_REGS, offsetof(struct kvm_cpu_context, gp_regs));
> + DEFINE(CPU_USER_PT_REGS, offsetof(struct kvm_regs, regs));
> + DEFINE(CPU_FP_REGS, offsetof(struct kvm_regs, fp_regs));
> + DEFINE(CPU_SP_EL1, offsetof(struct kvm_regs, sp_el1));
> + DEFINE(CPU_ELR_EL1, offsetof(struct kvm_regs, elr_el1));
> + DEFINE(CPU_SPSR, offsetof(struct kvm_regs, spsr));
> + DEFINE(CPU_SYSREGS, offsetof(struct kvm_cpu_context, sys_regs));
> + DEFINE(VCPU_ESR_EL2, offsetof(struct kvm_vcpu, arch.fault.esr_el2));
> + DEFINE(VCPU_FAR_EL2, offsetof(struct kvm_vcpu, arch.fault.far_el2));
> + DEFINE(VCPU_HPFAR_EL2, offsetof(struct kvm_vcpu, arch.fault.hpfar_el2));
> + DEFINE(VCPU_HCR_EL2, offsetof(struct kvm_vcpu, arch.hcr_el2));
> + DEFINE(VCPU_IRQ_LINES, offsetof(struct kvm_vcpu, arch.irq_lines));
> + DEFINE(VCPU_HOST_CONTEXT, offsetof(struct kvm_vcpu, arch.host_cpu_context));
> + DEFINE(VCPU_TIMER_CNTV_CTL, offsetof(struct kvm_vcpu, arch.timer_cpu.cntv_ctl));
> + DEFINE(VCPU_TIMER_CNTV_CVAL, offsetof(struct kvm_vcpu, arch.timer_cpu.cntv_cval));
> + DEFINE(KVM_TIMER_CNTVOFF, offsetof(struct kvm, arch.timer.cntvoff));
> + DEFINE(KVM_TIMER_ENABLED, offsetof(struct kvm, arch.timer.enabled));
> + DEFINE(VCPU_KVM, offsetof(struct kvm_vcpu, kvm));
> + DEFINE(VCPU_VGIC_CPU, offsetof(struct kvm_vcpu, arch.vgic_cpu));
> + DEFINE(VGIC_CPU_HCR, offsetof(struct vgic_cpu, vgic_hcr));
> + DEFINE(VGIC_CPU_VMCR, offsetof(struct vgic_cpu, vgic_vmcr));
> + DEFINE(VGIC_CPU_MISR, offsetof(struct vgic_cpu, vgic_misr));
> + DEFINE(VGIC_CPU_EISR, offsetof(struct vgic_cpu, vgic_eisr));
> + DEFINE(VGIC_CPU_ELRSR, offsetof(struct vgic_cpu, vgic_elrsr));
> + DEFINE(VGIC_CPU_APR, offsetof(struct vgic_cpu, vgic_apr));
> + DEFINE(VGIC_CPU_LR, offsetof(struct vgic_cpu, vgic_lr));
> + DEFINE(VGIC_CPU_NR_LR, offsetof(struct vgic_cpu, nr_lr));
> + DEFINE(KVM_VTTBR, offsetof(struct kvm, arch.vttbr));
> + DEFINE(KVM_VGIC_VCTRL, offsetof(struct kvm, arch.vgic.vctrl_base));
> +#endif
> return 0;
> }
> diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S
> new file mode 100644
> index 0000000..c745d20
> --- /dev/null
> +++ b/arch/arm64/kvm/hyp.S
> @@ -0,0 +1,602 @@
> +/*
> + * Copyright (C) 2012,2013 - ARM Ltd
> + * Author: Marc Zyngier <marc.zyngier at arm.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/linkage.h>
> +#include <linux/irqchip/arm-gic.h>
> +
> +#include <asm/assembler.h>
> +#include <asm/memory.h>
> +#include <asm/asm-offsets.h>
> +#include <asm/fpsimdmacros.h>
> +#include <asm/kvm.h>
> +#include <asm/kvm_asm.h>
> +#include <asm/kvm_arm.h>
> +#include <asm/kvm_mmu.h>
> +
> +#define CPU_GP_REG_OFFSET(x) (CPU_GP_REGS + x)
> +#define CPU_XREG_OFFSET(x) CPU_GP_REG_OFFSET(CPU_USER_PT_REGS + 8*x)
> +#define CPU_SPSR_OFFSET(x) CPU_GP_REG_OFFSET(CPU_SPSR + 8*x)
> +#define CPU_SYSREG_OFFSET(x) (CPU_SYSREGS + 8*x)
> +
> + .text
> + .pushsection .hyp.text, "ax"
> + .align PAGE_SHIFT
> +
> +__kvm_hyp_code_start:
> + .globl __kvm_hyp_code_start
> +
> +.macro save_common_regs
> + // x2: base address for cpu context
> + // x3: tmp register
what's with the C99 style comments? Standard for arm64 assembly?
> +
> + add x3, x2, #CPU_XREG_OFFSET(19)
> + stp x19, x20, [x3]
> + stp x21, x22, [x3, #16]
> + stp x23, x24, [x3, #32]
> + stp x25, x26, [x3, #48]
> + stp x27, x28, [x3, #64]
> + stp x29, lr, [x3, #80]
> +
> + mrs x19, sp_el0
> + mrs x20, elr_el2 // EL1 PC
> + mrs x21, spsr_el2 // EL1 pstate
> +
> + stp x19, x20, [x3, #96]
> + str x21, [x3, #112]
> +
> + mrs x22, sp_el1
> + mrs x23, elr_el1
> + mrs x24, spsr_el1
> +
> + str x22, [x2, #CPU_GP_REG_OFFSET(CPU_SP_EL1)]
> + str x23, [x2, #CPU_GP_REG_OFFSET(CPU_ELR_EL1)]
> + str x24, [x2, #CPU_SPSR_OFFSET(KVM_SPSR_EL1)]
> +.endm
> +
> +.macro restore_common_regs
> + // x2: base address for cpu context
> + // x3: tmp register
> +
> + ldr x22, [x2, #CPU_GP_REG_OFFSET(CPU_SP_EL1)]
> + ldr x23, [x2, #CPU_GP_REG_OFFSET(CPU_ELR_EL1)]
> + ldr x24, [x2, #CPU_SPSR_OFFSET(KVM_SPSR_EL1)]
> +
> + msr sp_el1, x22
> + msr elr_el1, x23
> + msr spsr_el1, x24
> +
> + add x3, x2, #CPU_XREG_OFFSET(31) // SP_EL0
> + ldp x19, x20, [x3]
> + ldr x21, [x3, #16]
> +
> + msr sp_el0, x19
> + msr elr_el2, x20 // EL1 PC
> + msr spsr_el2, x21 // EL1 pstate
> +
> + add x3, x2, #CPU_XREG_OFFSET(19)
> + ldp x19, x20, [x3]
> + ldp x21, x22, [x3, #16]
> + ldp x23, x24, [x3, #32]
> + ldp x25, x26, [x3, #48]
> + ldp x27, x28, [x3, #64]
> + ldp x29, lr, [x3, #80]
> +.endm
> +
> +.macro save_host_regs
> + save_common_regs
> +.endm
> +
> +.macro restore_host_regs
> + restore_common_regs
> +.endm
> +
> +.macro save_fpsimd
> + // x2: cpu context address
> + // x3, x4: tmp regs
> + add x3, x2, #CPU_GP_REG_OFFSET(CPU_FP_REGS)
> + fpsimd_save x3, 4
> +.endm
> +
> +.macro restore_fpsimd
> + // x2: cpu context address
> + // x3, x4: tmp regs
> + add x3, x2, #CPU_GP_REG_OFFSET(CPU_FP_REGS)
> + fpsimd_restore x3, 4
> +.endm
> +
> +.macro save_guest_regs
> + // x0 is the vcpu address
> + // x1 is the return code, do not corrupt!
> + // x2 is the cpu context
> + // x3 is a tmp register
> + // Guest's x0-x3 are on the stack
> +
> + // Compute base to save registers
> + add x3, x2, #CPU_XREG_OFFSET(4)
> + stp x4, x5, [x3]
> + stp x6, x7, [x3, #16]
> + stp x8, x9, [x3, #32]
> + stp x10, x11, [x3, #48]
> + stp x12, x13, [x3, #64]
> + stp x14, x15, [x3, #80]
> + stp x16, x17, [x3, #96]
> + str x18, [x3, #112]
> +
> + pop x6, x7 // x2, x3
> + pop x4, x5 // x0, x1
> +
> + add x3, x2, #CPU_XREG_OFFSET(0)
> + stp x4, x5, [x3]
> + stp x6, x7, [x3, #16]
> +
> + save_common_regs
> +.endm
> +
> +.macro restore_guest_regs
> + // x0 is the vcpu address.
> + // x2 is the cpu context
> + // x3 is a tmp register
> +
> + // Prepare x0-x3 for later restore
> + add x3, x2, #CPU_XREG_OFFSET(0)
> + ldp x4, x5, [x3]
> + ldp x6, x7, [x3, #16]
> + push x4, x5 // Push x0-x3 on the stack
> + push x6, x7
> +
> + // x4-x18
> + ldp x4, x5, [x3, #32]
> + ldp x6, x7, [x3, #48]
> + ldp x8, x9, [x3, #64]
> + ldp x10, x11, [x3, #80]
> + ldp x12, x13, [x3, #96]
> + ldp x14, x15, [x3, #112]
> + ldp x16, x17, [x3, #128]
> + ldr x18, [x3, #144]
> +
> + // x19-x29, lr, sp*, elr*, spsr*
> + restore_common_regs
> +
> + // Last bits of the 64bit state
> + pop x2, x3
> + pop x0, x1
> +
> + // Do not touch any register after this!
> +.endm
> +
> +/*
> + * Macros to perform system register save/restore.
> + *
> + * Ordering here is absolutely critical, and must be kept consistent
> + * in {save,restore}_sysregs, {save,restore}_guest_32bit_state,
> + * and in kvm_asm.h.
> + *
> + * In other words, don't touch any of these unless you know what
> + * you are doing.
> + */
> +.macro save_sysregs
> + // x2: base address for cpu context
> + // x3: tmp register
> +
> + add x3, x2, #CPU_SYSREG_OFFSET(MPIDR_EL1)
> +
> + mrs x4, vmpidr_el2
> + mrs x5, csselr_el1
> + mrs x6, sctlr_el1
> + mrs x7, actlr_el1
> + mrs x8, cpacr_el1
> + mrs x9, ttbr0_el1
> + mrs x10, ttbr1_el1
> + mrs x11, tcr_el1
> + mrs x12, esr_el1
> + mrs x13, afsr0_el1
> + mrs x14, afsr1_el1
> + mrs x15, far_el1
> + mrs x16, mair_el1
> + mrs x17, vbar_el1
> + mrs x18, contextidr_el1
> + mrs x19, tpidr_el0
> + mrs x20, tpidrro_el0
> + mrs x21, tpidr_el1
> + mrs x22, amair_el1
> + mrs x23, cntkctl_el1
> +
> + stp x4, x5, [x3]
> + stp x6, x7, [x3, #16]
> + stp x8, x9, [x3, #32]
> + stp x10, x11, [x3, #48]
> + stp x12, x13, [x3, #64]
> + stp x14, x15, [x3, #80]
> + stp x16, x17, [x3, #96]
> + stp x18, x19, [x3, #112]
> + stp x20, x21, [x3, #128]
> + stp x22, x23, [x3, #144]
> +.endm
> +
> +.macro restore_sysregs
> + // x2: base address for cpu context
> + // x3: tmp register
> +
> + add x3, x2, #CPU_SYSREG_OFFSET(MPIDR_EL1)
> +
> + ldp x4, x5, [x3]
> + ldp x6, x7, [x3, #16]
> + ldp x8, x9, [x3, #32]
> + ldp x10, x11, [x3, #48]
> + ldp x12, x13, [x3, #64]
> + ldp x14, x15, [x3, #80]
> + ldp x16, x17, [x3, #96]
> + ldp x18, x19, [x3, #112]
> + ldp x20, x21, [x3, #128]
> + ldp x22, x23, [x3, #144]
> +
> + msr vmpidr_el2, x4
> + msr csselr_el1, x5
> + msr sctlr_el1, x6
> + msr actlr_el1, x7
> + msr cpacr_el1, x8
> + msr ttbr0_el1, x9
> + msr ttbr1_el1, x10
> + msr tcr_el1, x11
> + msr esr_el1, x12
> + msr afsr0_el1, x13
> + msr afsr1_el1, x14
> + msr far_el1, x15
> + msr mair_el1, x16
> + msr vbar_el1, x17
> + msr contextidr_el1, x18
> + msr tpidr_el0, x19
> + msr tpidrro_el0, x20
> + msr tpidr_el1, x21
> + msr amair_el1, x22
> + msr cntkctl_el1, x23
> +.endm
> +
> +.macro activate_traps
> + ldr x2, [x0, #VCPU_IRQ_LINES]
> + ldr x1, [x0, #VCPU_HCR_EL2]
> + orr x2, x2, x1
> + msr hcr_el2, x2
> +
> + ldr x2, =(CPTR_EL2_TTA)
> + msr cptr_el2, x2
> +
> + ldr x2, =(1 << 15) // Trap CP15 Cr=15
> + msr hstr_el2, x2
> +
> + mrs x2, mdcr_el2
> + and x2, x2, #MDCR_EL2_HPMN_MASK
> + orr x2, x2, #(MDCR_EL2_TPM | MDCR_EL2_TPMCR)
> + msr mdcr_el2, x2
> +.endm
> +
> +.macro deactivate_traps
> + mov x2, #HCR_RW
> + msr hcr_el2, x2
> + msr cptr_el2, xzr
> + msr hstr_el2, xzr
> +
> + mrs x2, mdcr_el2
> + and x2, x2, #MDCR_EL2_HPMN_MASK
> + msr mdcr_el2, x2
> +.endm
> +
> +.macro activate_vm
> + ldr x1, [x0, #VCPU_KVM]
> + kern_hyp_va x1
> + ldr x2, [x1, #KVM_VTTBR]
> + msr vttbr_el2, x2
> +.endm
> +
> +.macro deactivate_vm
> + msr vttbr_el2, xzr
> +.endm
> +
> +__save_sysregs:
> + save_sysregs
> + ret
> +
> +__restore_sysregs:
> + restore_sysregs
> + ret
> +
> +__save_fpsimd:
> + save_fpsimd
> + ret
> +
> +__restore_fpsimd:
> + restore_fpsimd
> + ret
> +
> +/*
> + * u64 __kvm_vcpu_run(struct kvm_vcpu *vcpu);
> + *
> + * This is the world switch. The first half of the function
> + * deals with entering the guest, and anything from __kvm_vcpu_return
> + * to the end of the function deals with reentering the host.
> + * On the enter path, only x0 (vcpu pointer) must be preserved until
> + * the last moment. On the exit path, x0 (vcpu pointer) and x1 (exception
> + * code) must both be preserved until the epilogue.
> + * In both cases, x2 points to the CPU context we're saving/restoring from/to.
> + */
> +ENTRY(__kvm_vcpu_run)
> + kern_hyp_va x0
> + msr tpidr_el2, x0 // Save the vcpu register
> +
> + // Host context
> + ldr x2, [x0, #VCPU_HOST_CONTEXT]
> + kern_hyp_va x2
> +
> + save_host_regs
> + bl __save_fpsimd
> + bl __save_sysregs
> +
> + activate_traps
> + activate_vm
> +
> + // Guest context
> + add x2, x0, #VCPU_CONTEXT
> +
> + bl __restore_sysregs
> + bl __restore_fpsimd
> + restore_guest_regs
> +
> + // That's it, no more messing around.
> + clrex
> + eret
> +
> +__kvm_vcpu_return:
> + // Assume x0 is the vcpu pointer, x1 the return code
> + // Guest's x0-x3 are on the stack
> +
> + // Guest context
> + add x2, x0, #VCPU_CONTEXT
> +
> + save_guest_regs
> + bl __save_fpsimd
> + bl __save_sysregs
> +
> + deactivate_traps
> + deactivate_vm
> +
> + // Host context
> + ldr x2, [x0, #VCPU_HOST_CONTEXT]
> + kern_hyp_va x2
> +
> + bl __restore_sysregs
> + bl __restore_fpsimd
> + restore_host_regs
> + mov x0, x1
> + clrex
> + ret
> +END(__kvm_vcpu_run)
> +
> +// void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
> +ENTRY(__kvm_tlb_flush_vmid_ipa)
> + kern_hyp_va x0
> + ldr x2, [x0, #KVM_VTTBR]
> + msr vttbr_el2, x2
> + isb
> +
> + /*
> + * We could do so much better if we had the VA as well.
> + * Instead, we invalidate Stage-2 for this IPA, and the
> + * whole of Stage-1. Weep...
> + */
> + tlbi ipas2e1is, x1
> + dsb sy
> + tlbi vmalle1is
> + dsb sy
> + isb
> +
> + msr vttbr_el2, xzr
> + isb
> + ret
> +ENDPROC(__kvm_tlb_flush_vmid_ipa)
> +
> +ENTRY(__kvm_flush_vm_context)
> + tlbi alle1is
> + ic ialluis
> + dsb sy
> + isb
> + ret
> +ENDPROC(__kvm_flush_vm_context)
> +
> +__kvm_hyp_panic:
> + adr x0, __hyp_panic_str
> + adr x1, 1f
> + ldp x2, x3, [x1]
> + sub x0, x0, x2
> + add x0, x0, x3
> + mrs x1, spsr_el2
> + mrs x2, elr_el2
> + mrs x3, esr_el2
> + mrs x4, far_el2
> + mrs x5, hpfar_el2
> + mrs x6, tpidr_el2
> +
> + mov lr, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\
> + PSR_MODE_EL1h)
> + msr spsr_el2, lr
> + ldr lr, =panic
> + msr elr_el2, lr
> + eret
> +
> + .align 3
> +1: .quad HYP_PAGE_OFFSET
> + .quad PAGE_OFFSET
> +ENDPROC(__kvm_hyp_panic)
> +
> +__hyp_panic_str:
> + .ascii "HYP panic:\nPS:%08x PC:%p ESR:%p\nFAR:%p HPFAR:%p VCPU:%p\n\0"
> +
> + .align 2
> +
> +ENTRY(kvm_call_hyp)
> + hvc #0
> + ret
> +ENDPROC(kvm_call_hyp)
> +
> +.macro invalid_vector label, target
> + .align 2
> +\label:
> + b \target
> +ENDPROC(\label)
> +.endm
> +
> + /* None of these should ever happen */
> + invalid_vector el2t_sync_invalid, __kvm_hyp_panic
> + invalid_vector el2t_irq_invalid, __kvm_hyp_panic
> + invalid_vector el2t_fiq_invalid, __kvm_hyp_panic
> + invalid_vector el2t_error_invalid, __kvm_hyp_panic
> + invalid_vector el2h_sync_invalid, __kvm_hyp_panic
> + invalid_vector el2h_irq_invalid, __kvm_hyp_panic
> + invalid_vector el2h_fiq_invalid, __kvm_hyp_panic
> + invalid_vector el2h_error_invalid, __kvm_hyp_panic
> + invalid_vector el1_sync_invalid, __kvm_hyp_panic
> + invalid_vector el1_irq_invalid, __kvm_hyp_panic
> + invalid_vector el1_fiq_invalid, __kvm_hyp_panic
> + invalid_vector el1_error_invalid, __kvm_hyp_panic
> +
> +el1_sync: // Guest trapped into EL2
> + push x0, x1
> + push x2, x3
> +
> + mrs x1, esr_el2
> + lsr x2, x1, #ESR_EL2_EC_SHIFT
> +
> + cmp x2, #ESR_EL2_EC_HVC64
> + b.ne el1_trap
> +
> + mrs x3, vttbr_el2 // If vttbr is valid, the 64bit guest
> + cbnz x3, el1_trap // called HVC
> +
> + /* Here, we're pretty sure the host called HVC. */
> + pop x2, x3
> + pop x0, x1
> +
> + push lr, xzr
> +
> + /*
> + * Compute the function address in EL2, and shuffle the parameters.
> + */
> + kern_hyp_va x0
> + mov lr, x0
> + mov x0, x1
> + mov x1, x2
> + mov x2, x3
> + blr lr
> +
> + pop lr, xzr
> + eret
> +
> +el1_trap:
> + /*
> + * x1: ESR
> + * x2: ESR_EC
> + */
> + cmp x2, #ESR_EL2_EC_DABT
> + mov x0, #ESR_EL2_EC_IABT
> + ccmp x2, x0, #4, ne
> + b.ne 1f // Not an abort we care about
why do we get the hpfar_el2 if it's not an abort (or is this for a
special type of abort) ?
> +
> + /* This is an abort. Check for permission fault */
> + and x2, x1, #ESR_EL2_FSC_TYPE
> + cmp x2, #FSC_PERM
> + b.ne 1f // Not a permission fault
> +
> + /*
> + * Check for Stage-1 page table walk, which is guaranteed
> + * to give a valid HPFAR_EL2.
> + */
> + tbnz x1, #7, 1f // S1PTW is set
> +
> + /*
> + * Permission fault, HPFAR_EL2 is invalid.
> + * Resolve the IPA the hard way using the guest VA.
> + * We always perform an EL1 lookup, as we already
> + * went through Stage-1.
> + */
What does the last sentence mean exactly?
> + mrs x3, far_el2
> + at s1e1r, x3
> + isb
> +
> + /* Read result */
> + mrs x3, par_el1
> + tbnz x3, #1, 3f // Bail out if we failed the translation
> + ubfx x3, x3, #12, #36 // Extract IPA
> + lsl x3, x3, #4 // and present it like HPFAR
> + b 2f
> +
> +1: mrs x3, hpfar_el2
> +
> +2: mrs x0, tpidr_el2
> + mrs x2, far_el2
> + str x1, [x0, #VCPU_ESR_EL2]
> + str x2, [x0, #VCPU_FAR_EL2]
> + str x3, [x0, #VCPU_HPFAR_EL2]
> +
> + mov x1, #ARM_EXCEPTION_TRAP
> + b __kvm_vcpu_return
> +
> + /*
> + * Translation failed. Just return to the guest and
> + * let it fault again. Another CPU is probably playing
> + * behind our back.
> + */
This actually makes me wonder if this is a potential DOS attack from
guests (on the 32-bit code as well), or are we sure that an asynchronous
timer interrupt to the host will always creep in between e.g. a tight
loop playing this trick on us?
> +3: pop x2, x3
> + pop x0, x1
> +
> + eret
> +
> +el1_irq:
> + push x0, x1
> + push x2, x3
> + mrs x0, tpidr_el2
> + mov x1, #ARM_EXCEPTION_IRQ
> + b __kvm_vcpu_return
> +
> + .ltorg
> +
> + .align 11
> +
> +ENTRY(__kvm_hyp_vector)
> + ventry el2t_sync_invalid // Synchronous EL2t
> + ventry el2t_irq_invalid // IRQ EL2t
> + ventry el2t_fiq_invalid // FIQ EL2t
> + ventry el2t_error_invalid // Error EL2t
> +
> + ventry el2h_sync_invalid // Synchronous EL2h
> + ventry el2h_irq_invalid // IRQ EL2h
> + ventry el2h_fiq_invalid // FIQ EL2h
> + ventry el2h_error_invalid // Error EL2h
> +
> + ventry el1_sync // Synchronous 64-bit EL1
> + ventry el1_irq // IRQ 64-bit EL1
> + ventry el1_fiq_invalid // FIQ 64-bit EL1
> + ventry el1_error_invalid // Error 64-bit EL1
> +
> + ventry el1_sync // Synchronous 32-bit EL1
> + ventry el1_irq // IRQ 32-bit EL1
> + ventry el1_fiq_invalid // FIQ 32-bit EL1
> + ventry el1_error_invalid // Error 32-bit EL1
> +ENDPROC(__kvm_hyp_vector)
> +
> +__kvm_hyp_code_end:
> + .globl __kvm_hyp_code_end
> +
> + .popsection
> --
> 1.8.1.4
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
More information about the linux-arm-kernel
mailing list