arch/arm64/kvm/inject_fault.c

Source file repositories/reference/linux-study-clean/arch/arm64/kvm/inject_fault.c

File Facts

System
Linux kernel
Corpus path
arch/arm64/kvm/inject_fault.c
Extension
.c
Size
10551 bytes
Lines
401
Domain
Architecture Layer
Bucket
arch/arm64
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Fault injection for both 32 and 64bit 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/kvm_host.h>
#include <asm/kvm_emulate.h>
#include <asm/kvm_nested.h>
#include <asm/esr.h>

static unsigned int exception_target_el(struct kvm_vcpu *vcpu)
{
	/* If not nesting, EL1 is the only possible exception target */
	if (likely(!vcpu_has_nv(vcpu)))
		return PSR_MODE_EL1h;

	/*
	 * With NV, we need to pick between EL1 and EL2. Note that we
	 * never deal with a nesting exception here, hence never
	 * changing context, and the exception itself can be delayed
	 * until the next entry.
	 */
	switch(*vcpu_cpsr(vcpu) & PSR_MODE_MASK) {
	case PSR_MODE_EL2h:
	case PSR_MODE_EL2t:
		return PSR_MODE_EL2h;
	case PSR_MODE_EL1h:
	case PSR_MODE_EL1t:
		return PSR_MODE_EL1h;
	case PSR_MODE_EL0t:
		return vcpu_el2_tge_is_set(vcpu) ? PSR_MODE_EL2h : PSR_MODE_EL1h;
	default:
		BUG();
	}
}

static enum vcpu_sysreg exception_esr_elx(struct kvm_vcpu *vcpu)
{
	if (exception_target_el(vcpu) == PSR_MODE_EL2h)
		return ESR_EL2;

	return ESR_EL1;
}

static enum vcpu_sysreg exception_far_elx(struct kvm_vcpu *vcpu)
{
	if (exception_target_el(vcpu) == PSR_MODE_EL2h)
		return FAR_EL2;

	return FAR_EL1;
}

static void pend_sync_exception(struct kvm_vcpu *vcpu)
{
	if (exception_target_el(vcpu) == PSR_MODE_EL1h)
		kvm_pend_exception(vcpu, EXCEPT_AA64_EL1_SYNC);
	else
		kvm_pend_exception(vcpu, EXCEPT_AA64_EL2_SYNC);
}

static void pend_serror_exception(struct kvm_vcpu *vcpu)
{
	if (exception_target_el(vcpu) == PSR_MODE_EL1h)
		kvm_pend_exception(vcpu, EXCEPT_AA64_EL1_SERR);
	else
		kvm_pend_exception(vcpu, EXCEPT_AA64_EL2_SERR);
}

static bool __effective_sctlr2_bit(struct kvm_vcpu *vcpu, unsigned int idx)
{
	u64 sctlr2;

	if (!kvm_has_sctlr2(vcpu->kvm))
		return false;

	if (is_nested_ctxt(vcpu) &&
	    !(__vcpu_sys_reg(vcpu, HCRX_EL2) & HCRX_EL2_SCTLR2En))
		return false;

	if (exception_target_el(vcpu) == PSR_MODE_EL1h)
		sctlr2 = vcpu_read_sys_reg(vcpu, SCTLR2_EL1);
	else
		sctlr2 = vcpu_read_sys_reg(vcpu, SCTLR2_EL2);

Annotation

Implementation Notes