arch/arm64/kvm/vgic-sys-reg-v3.c

Source file repositories/reference/linux-study-clean/arch/arm64/kvm/vgic-sys-reg-v3.c

File Facts

System
Linux kernel
Corpus path
arch/arm64/kvm/vgic-sys-reg-v3.c
Extension
.c
Size
11840 bytes
Lines
490
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
/*
 * VGIC system registers handling functions for AArch64 mode
 */

#include <linux/irqchip/arm-gic-v3.h>
#include <linux/kvm.h>
#include <linux/kvm_host.h>
#include <asm/kvm_emulate.h>
#include "vgic/vgic.h"
#include "sys_regs.h"

static int set_gic_ctlr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
			u64 val)
{
	u32 host_pri_bits, host_id_bits, host_seis, host_a3v, seis, a3v;
	struct vgic_cpu *vgic_v3_cpu = &vcpu->arch.vgic_cpu;
	struct vgic_vmcr vmcr;

	vgic_get_vmcr(vcpu, &vmcr);

	/*
	 * Disallow restoring VM state if not supported by this
	 * hardware.
	 */
	host_pri_bits = FIELD_GET(ICC_CTLR_EL1_PRI_BITS_MASK, val) + 1;
	if (host_pri_bits > vgic_v3_cpu->num_pri_bits)
		return -EINVAL;

	vgic_v3_cpu->num_pri_bits = host_pri_bits;

	host_id_bits = FIELD_GET(ICC_CTLR_EL1_ID_BITS_MASK, val);
	if (host_id_bits > vgic_v3_cpu->num_id_bits)
		return -EINVAL;

	vgic_v3_cpu->num_id_bits = host_id_bits;

	host_seis = FIELD_GET(ICH_VTR_EL2_SEIS, kvm_vgic_global_state.ich_vtr_el2);
	seis = FIELD_GET(ICC_CTLR_EL1_SEIS_MASK, val);
	if (host_seis != seis)
		return -EINVAL;

	host_a3v = FIELD_GET(ICH_VTR_EL2_A3V, kvm_vgic_global_state.ich_vtr_el2);
	a3v = FIELD_GET(ICC_CTLR_EL1_A3V_MASK, val);
	if (host_a3v != a3v)
		return -EINVAL;

	/*
	 * Here set VMCR.CTLR in ICC_CTLR_EL1 layout.
	 * The vgic_set_vmcr() will convert to ICH_VMCR layout.
	 */
	vmcr.cbpr = FIELD_GET(ICC_CTLR_EL1_CBPR_MASK, val);
	vmcr.eoim = FIELD_GET(ICC_CTLR_EL1_EOImode_MASK, val);
	vgic_set_vmcr(vcpu, &vmcr);

	return 0;
}

static int get_gic_ctlr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
			u64 *valp)
{
	struct vgic_cpu *vgic_v3_cpu = &vcpu->arch.vgic_cpu;
	struct vgic_vmcr vmcr;
	u64 val;

	vgic_get_vmcr(vcpu, &vmcr);
	val = 0;
	val |= FIELD_PREP(ICC_CTLR_EL1_PRI_BITS_MASK, vgic_v3_cpu->num_pri_bits - 1);
	val |= FIELD_PREP(ICC_CTLR_EL1_ID_BITS_MASK, vgic_v3_cpu->num_id_bits);
	val |= FIELD_PREP(ICC_CTLR_EL1_SEIS_MASK,
			  FIELD_GET(ICH_VTR_EL2_SEIS,
				    kvm_vgic_global_state.ich_vtr_el2));
	val |= FIELD_PREP(ICC_CTLR_EL1_A3V_MASK,
			  FIELD_GET(ICH_VTR_EL2_A3V, kvm_vgic_global_state.ich_vtr_el2));
	/*
	 * The VMCR.CTLR value is in ICC_CTLR_EL1 layout.
	 * Extract it directly using ICC_CTLR_EL1 reg definitions.
	 */
	val |= FIELD_PREP(ICC_CTLR_EL1_CBPR_MASK, vmcr.cbpr);
	val |= FIELD_PREP(ICC_CTLR_EL1_EOImode_MASK, vmcr.eoim);

	*valp = val;

	return 0;
}

static int set_gic_pmr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
		       u64 val)
{
	struct vgic_vmcr vmcr;

Annotation

Implementation Notes