Commit dcfba399 authored by Marc Zyngier's avatar Marc Zyngier
Browse files

KVM: arm64: Consolidate exception injection



Move the AArch32 exception injection code back into the inject_fault.c
file, removing the need for a few non-static functions now that AArch32
host support is a thing of the past.

Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
parent 7d76b8a6
Loading
Loading
Loading
Loading
+0 −3
Original line number Diff line number Diff line
@@ -42,9 +42,6 @@ void kvm_inject_undefined(struct kvm_vcpu *vcpu);
void kvm_inject_vabt(struct kvm_vcpu *vcpu);
void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr);
void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr);
void kvm_inject_undef32(struct kvm_vcpu *vcpu);
void kvm_inject_dabt32(struct kvm_vcpu *vcpu, unsigned long addr);
void kvm_inject_pabt32(struct kvm_vcpu *vcpu, unsigned long addr);

static __always_inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)
{
+1 −1
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@ kvm-y := $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o $(KVM)/eventfd.o \
	 inject_fault.o regmap.o va_layout.o handle_exit.o \
	 guest.o debug.o reset.o sys_regs.o \
	 vgic-sys-reg-v3.o fpsimd.o pmu.o \
	 aarch32.o arch_timer.o \
	 arch_timer.o \
	 vgic/vgic.o vgic/vgic-init.o \
	 vgic/vgic-irqfd.o vgic/vgic-v2.o \
	 vgic/vgic-v3.o vgic/vgic-v4.o \

arch/arm64/kvm/aarch32.c

deleted100644 → 0
+0 −95
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * (not much of an) Emulation layer for 32bit guests.
 *
 * Copyright (C) 2012,2013 - ARM Ltd
 * Author: Marc Zyngier <marc.zyngier@arm.com>
 *
 * based on arch/arm/kvm/emulate.c
 * Copyright (C) 2012 - Virtual Open Systems and Columbia University
 * Author: Christoffer Dall <c.dall@virtualopensystems.com>
 */

#include <linux/bits.h>
#include <linux/kvm_host.h>
#include <asm/kvm_emulate.h>
#include <asm/kvm_hyp.h>

#define DFSR_FSC_EXTABT_LPAE	0x10
#define DFSR_FSC_EXTABT_nLPAE	0x08
#define DFSR_LPAE		BIT(9)

static bool pre_fault_synchronize(struct kvm_vcpu *vcpu)
{
	preempt_disable();
	if (vcpu->arch.sysregs_loaded_on_cpu) {
		kvm_arch_vcpu_put(vcpu);
		return true;
	}

	preempt_enable();
	return false;
}

static void post_fault_synchronize(struct kvm_vcpu *vcpu, bool loaded)
{
	if (loaded) {
		kvm_arch_vcpu_load(vcpu, smp_processor_id());
		preempt_enable();
	}
}

void kvm_inject_undef32(struct kvm_vcpu *vcpu)
{
	vcpu->arch.flags |= (KVM_ARM64_EXCEPT_AA32_UND |
			     KVM_ARM64_PENDING_EXCEPTION);
}

/*
 * Modelled after TakeDataAbortException() and TakePrefetchAbortException
 * pseudocode.
 */
static void inject_abt32(struct kvm_vcpu *vcpu, bool is_pabt,
			 unsigned long addr)
{
	u32 *far, *fsr;
	bool is_lpae;
	bool loaded;

	loaded = pre_fault_synchronize(vcpu);

	if (is_pabt) {
		vcpu->arch.flags |= (KVM_ARM64_EXCEPT_AA32_IABT |
				     KVM_ARM64_PENDING_EXCEPTION);
		far = &vcpu_cp15(vcpu, c6_IFAR);
		fsr = &vcpu_cp15(vcpu, c5_IFSR);
	} else { /* !iabt */
		vcpu->arch.flags |= (KVM_ARM64_EXCEPT_AA32_DABT |
				     KVM_ARM64_PENDING_EXCEPTION);
		far = &vcpu_cp15(vcpu, c6_DFAR);
		fsr = &vcpu_cp15(vcpu, c5_DFSR);
	}

	*far = addr;

	/* Give the guest an IMPLEMENTATION DEFINED exception */
	is_lpae = (vcpu_cp15(vcpu, c2_TTBCR) >> 31);
	if (is_lpae) {
		*fsr = DFSR_LPAE | DFSR_FSC_EXTABT_LPAE;
	} else {
		/* no need to shuffle FS[4] into DFSR[10] as its 0 */
		*fsr = DFSR_FSC_EXTABT_nLPAE;
	}

	post_fault_synchronize(vcpu, loaded);
}

void kvm_inject_dabt32(struct kvm_vcpu *vcpu, unsigned long addr)
{
	inject_abt32(vcpu, false, addr);
}

void kvm_inject_pabt32(struct kvm_vcpu *vcpu, unsigned long addr)
{
	inject_abt32(vcpu, true, addr);
}
+72 −3
Original line number Diff line number Diff line
@@ -66,6 +66,75 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
	vcpu_write_sys_reg(vcpu, esr, ESR_EL1);
}

#define DFSR_FSC_EXTABT_LPAE	0x10
#define DFSR_FSC_EXTABT_nLPAE	0x08
#define DFSR_LPAE		BIT(9)

static bool pre_fault_synchronize(struct kvm_vcpu *vcpu)
{
	preempt_disable();
	if (vcpu->arch.sysregs_loaded_on_cpu) {
		kvm_arch_vcpu_put(vcpu);
		return true;
	}

	preempt_enable();
	return false;
}

static void post_fault_synchronize(struct kvm_vcpu *vcpu, bool loaded)
{
	if (loaded) {
		kvm_arch_vcpu_load(vcpu, smp_processor_id());
		preempt_enable();
	}
}

static void inject_undef32(struct kvm_vcpu *vcpu)
{
	vcpu->arch.flags |= (KVM_ARM64_EXCEPT_AA32_UND |
			     KVM_ARM64_PENDING_EXCEPTION);
}

/*
 * Modelled after TakeDataAbortException() and TakePrefetchAbortException
 * pseudocode.
 */
static void inject_abt32(struct kvm_vcpu *vcpu, bool is_pabt,
			 unsigned long addr)
{
	u32 *far, *fsr;
	bool is_lpae;
	bool loaded;

	loaded = pre_fault_synchronize(vcpu);

	if (is_pabt) {
		vcpu->arch.flags |= (KVM_ARM64_EXCEPT_AA32_IABT |
				     KVM_ARM64_PENDING_EXCEPTION);
		far = &vcpu_cp15(vcpu, c6_IFAR);
		fsr = &vcpu_cp15(vcpu, c5_IFSR);
	} else { /* !iabt */
		vcpu->arch.flags |= (KVM_ARM64_EXCEPT_AA32_DABT |
				     KVM_ARM64_PENDING_EXCEPTION);
		far = &vcpu_cp15(vcpu, c6_DFAR);
		fsr = &vcpu_cp15(vcpu, c5_DFSR);
	}

	*far = addr;

	/* Give the guest an IMPLEMENTATION DEFINED exception */
	is_lpae = (vcpu_cp15(vcpu, c2_TTBCR) >> 31);
	if (is_lpae) {
		*fsr = DFSR_LPAE | DFSR_FSC_EXTABT_LPAE;
	} else {
		/* no need to shuffle FS[4] into DFSR[10] as its 0 */
		*fsr = DFSR_FSC_EXTABT_nLPAE;
	}

	post_fault_synchronize(vcpu, loaded);
}

/**
 * kvm_inject_dabt - inject a data abort into the guest
 * @vcpu: The VCPU to receive the data abort
@@ -77,7 +146,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr)
{
	if (vcpu_el1_is_32bit(vcpu))
		kvm_inject_dabt32(vcpu, addr);
		inject_abt32(vcpu, false, addr);
	else
		inject_abt64(vcpu, false, addr);
}
@@ -93,7 +162,7 @@ void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr)
void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr)
{
	if (vcpu_el1_is_32bit(vcpu))
		kvm_inject_pabt32(vcpu, addr);
		inject_abt32(vcpu, true, addr);
	else
		inject_abt64(vcpu, true, addr);
}
@@ -108,7 +177,7 @@ void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr)
void kvm_inject_undefined(struct kvm_vcpu *vcpu)
{
	if (vcpu_el1_is_32bit(vcpu))
		kvm_inject_undef32(vcpu);
		inject_undef32(vcpu);
	else
		inject_undef64(vcpu);
}