From: cdall@cs.columbia.edu (Christoffer Dall)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v3 17/32] arm64: KVM: HYP mode world switch implementation
Date: Tue, 23 Apr 2013 15:59:58 -0700 [thread overview]
Message-ID: <20130423225958.GF20569@gmail.com> (raw)
In-Reply-To: <1365437854-30214-18-git-send-email-marc.zyngier@arm.com>
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@codeaurora.org>
> Signed-off-by: Marc Zyngier <marc.zyngier@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@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
WARNING: multiple messages have this Message-ID (diff)
From: Christoffer Dall <cdall@cs.columbia.edu>
To: Marc Zyngier <marc.zyngier@arm.com>
Cc: linux-arm-kernel@lists.infradead.org,
kvmarm@lists.cs.columbia.edu, kvm@vger.kernel.org,
catalin.marinas@arm.com, will.deacon@arm.com,
Christopher Covington <cov@codeaurora.org>
Subject: Re: [PATCH v3 17/32] arm64: KVM: HYP mode world switch implementation
Date: Tue, 23 Apr 2013 15:59:58 -0700 [thread overview]
Message-ID: <20130423225958.GF20569@gmail.com> (raw)
In-Reply-To: <1365437854-30214-18-git-send-email-marc.zyngier@arm.com>
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@codeaurora.org>
> Signed-off-by: Marc Zyngier <marc.zyngier@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@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@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
next prev parent reply other threads:[~2013-04-23 22:59 UTC|newest]
Thread overview: 232+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-04-08 16:17 [PATCH v3 00/32] Port of KVM to arm64 Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-08 16:17 ` [PATCH v3 01/32] arm64: add explicit symbols to ESR_EL1 decoding Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-08 16:17 ` [PATCH v3 02/32] arm64: KVM: define HYP and Stage-2 translation page flags Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-10 14:07 ` Will Deacon
2013-04-10 14:07 ` Will Deacon
2013-04-12 15:22 ` Marc Zyngier
2013-04-12 15:22 ` Marc Zyngier
2013-04-26 17:01 ` Catalin Marinas
2013-04-26 17:01 ` Catalin Marinas
2013-04-26 17:11 ` Marc Zyngier
2013-04-26 17:11 ` Marc Zyngier
2013-04-08 16:17 ` [PATCH v3 03/32] arm64: KVM: HYP mode idmap support Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-23 22:57 ` Christoffer Dall
2013-04-23 22:57 ` Christoffer Dall
2013-04-24 9:36 ` Marc Zyngier
2013-04-24 9:36 ` Marc Zyngier
2013-04-08 16:17 ` [PATCH v3 04/32] arm64: KVM: EL2 register definitions Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-08 16:17 ` [PATCH v3 05/32] arm64: KVM: system register definitions for 64bit guests Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-08 16:17 ` [PATCH v3 06/32] arm64: KVM: Basic ESR_EL2 helpers and vcpu register access Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-08 16:17 ` [PATCH v3 07/32] arm64: KVM: fault injection into a guest Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-10 16:40 ` Will Deacon
2013-04-10 16:40 ` Will Deacon
2013-04-12 15:29 ` Marc Zyngier
2013-04-12 15:29 ` Marc Zyngier
2013-04-23 22:57 ` Christoffer Dall
2013-04-23 22:57 ` Christoffer Dall
2013-04-24 10:04 ` Marc Zyngier
2013-04-24 10:04 ` Marc Zyngier
2013-04-24 16:46 ` Christoffer Dall
2013-04-24 16:46 ` Christoffer Dall
2013-04-29 16:26 ` Catalin Marinas
2013-04-29 16:26 ` Catalin Marinas
2013-05-07 16:29 ` Marc Zyngier
2013-05-07 16:29 ` Marc Zyngier
2013-04-08 16:17 ` [PATCH v3 08/32] arm64: KVM: architecture specific MMU backend Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-23 22:58 ` Christoffer Dall
2013-04-23 22:58 ` Christoffer Dall
2013-04-24 11:03 ` Marc Zyngier
2013-04-24 11:03 ` Marc Zyngier
2013-04-24 11:10 ` Will Deacon
2013-04-24 11:10 ` Will Deacon
2013-04-24 16:50 ` Christoffer Dall
2013-04-24 16:50 ` Christoffer Dall
2013-04-24 16:55 ` Christoffer Dall
2013-04-24 16:55 ` Christoffer Dall
2013-04-25 12:59 ` Marc Zyngier
2013-04-25 12:59 ` Marc Zyngier
2013-04-25 15:13 ` Christoffer Dall
2013-04-25 15:13 ` Christoffer Dall
2013-04-29 17:35 ` Catalin Marinas
2013-04-29 17:35 ` Catalin Marinas
2013-04-30 10:23 ` Marc Zyngier
2013-04-30 10:23 ` Marc Zyngier
2013-04-08 16:17 ` [PATCH v3 09/32] arm64: KVM: user space interface Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-10 16:45 ` Will Deacon
2013-04-10 16:45 ` Will Deacon
2013-04-12 15:31 ` Marc Zyngier
2013-04-12 15:31 ` Marc Zyngier
2013-04-08 16:17 ` [PATCH v3 10/32] arm64: KVM: system register handling Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-10 17:04 ` Will Deacon
2013-04-10 17:04 ` Will Deacon
2013-04-12 15:48 ` Marc Zyngier
2013-04-12 15:48 ` Marc Zyngier
2013-04-23 23:01 ` Christoffer Dall
2013-04-23 23:01 ` Christoffer Dall
2013-04-24 13:37 ` Marc Zyngier
2013-04-24 13:37 ` Marc Zyngier
2013-04-08 16:17 ` [PATCH v3 11/32] arm64: KVM: CPU specific system registers handling Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-10 17:06 ` Will Deacon
2013-04-10 17:06 ` Will Deacon
2013-04-12 16:04 ` Marc Zyngier
2013-04-12 16:04 ` Marc Zyngier
2013-04-23 22:59 ` Christoffer Dall
2013-04-23 22:59 ` Christoffer Dall
2013-04-24 9:33 ` Marc Zyngier
2013-04-24 9:33 ` Marc Zyngier
2013-04-08 16:17 ` [PATCH v3 12/32] arm64: KVM: virtual CPU reset Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-10 17:07 ` Will Deacon
2013-04-10 17:07 ` Will Deacon
2013-04-12 16:04 ` Marc Zyngier
2013-04-12 16:04 ` Marc Zyngier
2013-04-08 16:17 ` [PATCH v3 13/32] arm64: KVM: kvm_arch and kvm_vcpu_arch definitions Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-08 16:17 ` [PATCH v3 14/32] arm64: KVM: MMIO access backend Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-08 16:17 ` [PATCH v3 15/32] arm64: KVM: guest one-reg interface Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-10 17:13 ` Will Deacon
2013-04-10 17:13 ` Will Deacon
2013-04-12 16:35 ` Marc Zyngier
2013-04-12 16:35 ` Marc Zyngier
2013-04-23 22:59 ` Christoffer Dall
2013-04-23 22:59 ` Christoffer Dall
2013-04-24 11:27 ` Marc Zyngier
2013-04-24 11:27 ` Marc Zyngier
2013-04-24 17:05 ` Christoffer Dall
2013-04-24 17:05 ` Christoffer Dall
2013-04-08 16:17 ` [PATCH v3 16/32] arm64: KVM: hypervisor initialization code Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-05-02 11:03 ` Catalin Marinas
2013-05-02 11:03 ` Catalin Marinas
2013-05-02 13:28 ` Marc Zyngier
2013-05-02 13:28 ` Marc Zyngier
2013-04-08 16:17 ` [PATCH v3 17/32] arm64: KVM: HYP mode world switch implementation Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-23 22:59 ` Christoffer Dall [this message]
2013-04-23 22:59 ` Christoffer Dall
2013-04-24 11:39 ` Marc Zyngier
2013-04-24 11:39 ` Marc Zyngier
2013-04-24 17:08 ` Christoffer Dall
2013-04-24 17:08 ` Christoffer Dall
2013-04-08 16:17 ` [PATCH v3 18/32] arm64: KVM: Exit handling Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-08 16:17 ` [PATCH v3 19/32] arm64: KVM: Plug the VGIC Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-23 23:00 ` Christoffer Dall
2013-04-23 23:00 ` Christoffer Dall
2013-04-24 11:43 ` Marc Zyngier
2013-04-24 11:43 ` Marc Zyngier
2013-05-02 14:38 ` Catalin Marinas
2013-05-02 14:38 ` Catalin Marinas
2013-04-08 16:17 ` [PATCH v3 20/32] arm64: KVM: Plug the arch timer Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-23 23:00 ` Christoffer Dall
2013-04-23 23:00 ` Christoffer Dall
2013-04-24 11:43 ` Marc Zyngier
2013-04-24 11:43 ` Marc Zyngier
2013-05-02 15:31 ` Catalin Marinas
2013-05-02 15:31 ` Catalin Marinas
2013-04-08 16:17 ` [PATCH v3 21/32] arm64: KVM: PSCI implementation Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-08 16:17 ` [PATCH v3 22/32] arm64: KVM: Build system integration Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-08 16:17 ` [PATCH v3 23/32] arm64: KVM: define 32bit specific registers Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-08 16:17 ` [PATCH v3 24/32] arm64: KVM: 32bit GP register access Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-23 23:00 ` Christoffer Dall
2013-04-23 23:00 ` Christoffer Dall
2013-04-24 13:06 ` Marc Zyngier
2013-04-24 13:06 ` Marc Zyngier
2013-04-24 17:09 ` Christoffer Dall
2013-04-24 17:09 ` Christoffer Dall
2013-05-02 16:09 ` Catalin Marinas
2013-05-02 16:09 ` Catalin Marinas
2013-05-07 16:28 ` Marc Zyngier
2013-05-07 16:28 ` Marc Zyngier
2013-05-07 16:33 ` Catalin Marinas
2013-05-07 16:33 ` Catalin Marinas
2013-05-11 0:36 ` Christoffer Dall
2013-05-11 0:36 ` Christoffer Dall
2013-05-11 7:51 ` Peter Maydell
2013-05-11 7:51 ` Peter Maydell
2013-05-11 9:43 ` Catalin Marinas
2013-05-11 9:43 ` Catalin Marinas
2013-05-12 18:51 ` Christoffer Dall
2013-05-12 18:51 ` Christoffer Dall
2013-04-08 16:17 ` [PATCH v3 25/32] arm64: KVM: 32bit conditional execution emulation Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-23 23:00 ` Christoffer Dall
2013-04-23 23:00 ` Christoffer Dall
2013-04-24 13:13 ` Marc Zyngier
2013-04-24 13:13 ` Marc Zyngier
2013-04-24 17:11 ` Christoffer Dall
2013-04-24 17:11 ` Christoffer Dall
2013-04-08 16:17 ` [PATCH v3 26/32] arm64: KVM: 32bit handling of coprocessor traps Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-23 23:01 ` Christoffer Dall
2013-04-23 23:01 ` Christoffer Dall
2013-04-24 13:42 ` Marc Zyngier
2013-04-24 13:42 ` Marc Zyngier
2013-04-24 17:14 ` Christoffer Dall
2013-04-24 17:14 ` Christoffer Dall
2013-04-08 16:17 ` [PATCH v3 27/32] arm64: KVM: CPU specific 32bit coprocessor access Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-08 16:17 ` [PATCH v3 28/32] arm64: KVM: 32bit specific register world switch Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-08 16:17 ` [PATCH v3 29/32] arm64: KVM: 32bit guest fault injection Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-23 23:02 ` Christoffer Dall
2013-04-23 23:02 ` Christoffer Dall
2013-04-24 13:46 ` Marc Zyngier
2013-04-24 13:46 ` Marc Zyngier
2013-04-24 17:15 ` Christoffer Dall
2013-04-24 17:15 ` Christoffer Dall
2013-04-08 16:17 ` [PATCH v3 30/32] arm64: KVM: enable initialization of a 32bit vcpu Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-23 23:02 ` Christoffer Dall
2013-04-23 23:02 ` Christoffer Dall
2013-04-24 13:49 ` Marc Zyngier
2013-04-24 13:49 ` Marc Zyngier
2013-04-24 17:17 ` Christoffer Dall
2013-04-24 17:17 ` Christoffer Dall
2013-05-07 16:36 ` Marc Zyngier
2013-05-07 16:36 ` Marc Zyngier
2013-05-11 0:38 ` Christoffer Dall
2013-05-11 0:38 ` Christoffer Dall
2013-05-11 8:04 ` Peter Maydell
2013-05-11 8:04 ` Peter Maydell
2013-05-11 16:26 ` Christoffer Dall
2013-05-11 16:26 ` Christoffer Dall
2013-05-11 16:31 ` Peter Maydell
2013-05-11 16:31 ` Peter Maydell
2013-05-13 9:01 ` Marc Zyngier
2013-05-13 9:01 ` Marc Zyngier
2013-05-13 15:46 ` Christoffer Dall
2013-05-13 15:46 ` Christoffer Dall
2013-04-08 16:17 ` [PATCH v3 31/32] arm64: KVM: userspace API documentation Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-23 23:02 ` Christoffer Dall
2013-04-23 23:02 ` Christoffer Dall
2013-04-24 13:52 ` Marc Zyngier
2013-04-24 13:52 ` Marc Zyngier
2013-04-08 16:17 ` [PATCH v3 32/32] arm64: KVM: MAINTAINERS update Marc Zyngier
2013-04-08 16:17 ` Marc Zyngier
2013-04-23 23:04 ` [PATCH v3 00/32] Port of KVM to arm64 Christoffer Dall
2013-04-23 23:04 ` Christoffer Dall
2013-05-03 13:17 ` Catalin Marinas
2013-05-03 13:17 ` Catalin Marinas
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20130423225958.GF20569@gmail.com \
--to=cdall@cs.columbia.edu \
--cc=linux-arm-kernel@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.