Commit a7f49a9b authored by Oliver Upton's avatar Oliver Upton
Browse files

Merge branch 'kvm-arm64/el2-reg-visibility' into kvmarm/next



* kvm-arm64/el2-reg-visibility:
  : Fixes to EL2 register visibility, courtesy of Marc Zyngier
  :
  :  - Expose EL2 VGICv3 registers via the VGIC attributes accessor, not the
  :    KVM_{GET,SET}_ONE_REG ioctls
  :
  :  - Condition visibility of FGT registers on the presence of FEAT_FGT in
  :    the VM
  KVM: arm64: selftest: vgic-v3: Add basic GICv3 sysreg userspace access test
  KVM: arm64: Enforce the sorting of the GICv3 system register table
  KVM: arm64: Clarify the check for reset callback in check_sysreg_table()
  KVM: arm64: vgic-v3: Fix ordering of ICH_HCR_EL2
  KVM: arm64: Document registers exposed via KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS
  KVM: arm64: selftests: get-reg-list: Add base EL2 registers
  KVM: arm64: selftests: get-reg-list: Simplify feature dependency
  KVM: arm64: Advertise FGT2 registers to userspace
  KVM: arm64: Condition FGT registers on feature availability
  KVM: arm64: Expose GICv3 EL2 registers via KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS
  KVM: arm64: Let GICv3 save/restore honor visibility attribute
  KVM: arm64: Define helper for ICH_VTR_EL2
  KVM: arm64: Define constant value for ICC_SRE_EL2
  KVM: arm64: Don't advertise ICH_*_EL2 registers through GET_ONE_REG
  KVM: arm64: Make RVBAR_EL2 accesses UNDEF

Signed-off-by: default avatarOliver Upton <oliver.upton@linux.dev>
parents d9b9fa2c 3435bd79
Loading
Loading
Loading
Loading
+58 −5
Original line number Diff line number Diff line
@@ -202,16 +202,69 @@ Groups:
    KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS accesses the CPU interface registers for the
    CPU specified by the mpidr field.

    CPU interface registers access is not implemented for AArch32 mode.
    Error -ENXIO is returned when accessed in AArch32 mode.
    The available registers are:

    ===============  ====================================================
    ICC_PMR_EL1
    ICC_BPR0_EL1
    ICC_AP0R0_EL1
    ICC_AP0R1_EL1    when the host implements at least 6 bits of priority
    ICC_AP0R2_EL1    when the host implements 7 bits of priority
    ICC_AP0R3_EL1    when the host implements 7 bits of priority
    ICC_AP1R0_EL1
    ICC_AP1R1_EL1    when the host implements at least 6 bits of priority
    ICC_AP1R2_EL1    when the host implements 7 bits of priority
    ICC_AP1R3_EL1    when the host implements 7 bits of priority
    ICC_BPR1_EL1
    ICC_CTLR_EL1
    ICC_SRE_EL1
    ICC_IGRPEN0_EL1
    ICC_IGRPEN1_EL1
    ===============  ====================================================

    When EL2 is available for the guest, these registers are also available:

    =============  ====================================================
    ICH_AP0R0_EL2
    ICH_AP0R1_EL2  when the host implements at least 6 bits of priority
    ICH_AP0R2_EL2  when the host implements 7 bits of priority
    ICH_AP0R3_EL2  when the host implements 7 bits of priority
    ICH_AP1R0_EL2
    ICH_AP1R1_EL2  when the host implements at least 6 bits of priority
    ICH_AP1R2_EL2  when the host implements 7 bits of priority
    ICH_AP1R3_EL2  when the host implements 7 bits of priority
    ICH_HCR_EL2
    ICC_SRE_EL2
    ICH_VTR_EL2
    ICH_VMCR_EL2
    ICH_LR0_EL2
    ICH_LR1_EL2
    ICH_LR2_EL2
    ICH_LR3_EL2
    ICH_LR4_EL2
    ICH_LR5_EL2
    ICH_LR6_EL2
    ICH_LR7_EL2
    ICH_LR8_EL2
    ICH_LR9_EL2
    ICH_LR10_EL2
    ICH_LR11_EL2
    ICH_LR12_EL2
    ICH_LR13_EL2
    ICH_LR14_EL2
    ICH_LR15_EL2
    =============  ====================================================

    CPU interface registers are only described using the AArch64
    encoding.

  Errors:

    =======  =====================================================
    -ENXIO   Getting or setting this register is not yet supported
    =======  =================================================
    -ENXIO   Getting or setting this register is not supported
    -EBUSY   VCPU is running
    -EINVAL  Invalid mpidr or register value supplied
    =======  =====================================================
    =======  =================================================


  KVM_DEV_ARM_VGIC_GRP_NR_IRQS
+82 −49
Original line number Diff line number Diff line
@@ -108,7 +108,6 @@ static bool get_el2_to_el1_mapping(unsigned int reg,
		PURE_EL2_SYSREG(  HACR_EL2	);
		PURE_EL2_SYSREG(  VTTBR_EL2	);
		PURE_EL2_SYSREG(  VTCR_EL2	);
		PURE_EL2_SYSREG(  RVBAR_EL2	);
		PURE_EL2_SYSREG(  TPIDR_EL2	);
		PURE_EL2_SYSREG(  HPFAR_EL2	);
		PURE_EL2_SYSREG(  HCRX_EL2	);
@@ -534,8 +533,7 @@ static bool access_gic_sre(struct kvm_vcpu *vcpu,
		return ignore_write(vcpu, p);

	if (p->Op1 == 4) {	/* ICC_SRE_EL2 */
		p->regval = (ICC_SRE_EL2_ENABLE | ICC_SRE_EL2_SRE |
			     ICC_SRE_EL1_DIB | ICC_SRE_EL1_DFB);
		p->regval = KVM_ICC_SRE_EL2;
	} else {		/* ICC_SRE_EL1 */
		p->regval = vcpu->arch.vgic_cpu.vgic_v3.vgic_sre;
	}
@@ -774,6 +772,12 @@ static u64 reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
	return mpidr;
}

static unsigned int hidden_visibility(const struct kvm_vcpu *vcpu,
				      const struct sys_reg_desc *r)
{
	return REG_HIDDEN;
}

static unsigned int pmu_visibility(const struct kvm_vcpu *vcpu,
				   const struct sys_reg_desc *r)
{
@@ -2335,6 +2339,10 @@ static bool bad_redir_trap(struct kvm_vcpu *vcpu,
	EL2_REG_FILTERED(name, acc, rst, v, el2_visibility)

#define EL2_REG_VNCR(name, rst, v)	EL2_REG(name, bad_vncr_trap, rst, v)
#define EL2_REG_VNCR_FILT(name, vis)			\
	EL2_REG_FILTERED(name, bad_vncr_trap, reset_val, 0, vis)
#define EL2_REG_VNCR_GICv3(name)			\
	EL2_REG_VNCR_FILT(name, hidden_visibility)
#define EL2_REG_REDIR(name, rst, v)	EL2_REG(name, bad_redir_trap, rst, v)

/*
@@ -2538,11 +2546,7 @@ static bool access_gic_vtr(struct kvm_vcpu *vcpu,
	if (p->is_write)
		return write_to_read_only(vcpu, p, r);

	p->regval = kvm_vgic_global_state.ich_vtr_el2;
	p->regval &= ~(ICH_VTR_EL2_DVIM 	|
		       ICH_VTR_EL2_A3V		|
		       ICH_VTR_EL2_IDbits);
	p->regval |= ICH_VTR_EL2_nV4;
	p->regval = kvm_get_guest_vtr_el2();

	return true;
}
@@ -2613,6 +2617,26 @@ static unsigned int tcr2_el2_visibility(const struct kvm_vcpu *vcpu,
	return __el2_visibility(vcpu, rd, tcr2_visibility);
}

static unsigned int fgt2_visibility(const struct kvm_vcpu *vcpu,
				    const struct sys_reg_desc *rd)
{
	if (el2_visibility(vcpu, rd) == 0 &&
	    kvm_has_feat(vcpu->kvm, ID_AA64MMFR0_EL1, FGT, FGT2))
		return 0;

	return REG_HIDDEN;
}

static unsigned int fgt_visibility(const struct kvm_vcpu *vcpu,
				   const struct sys_reg_desc *rd)
{
	if (el2_visibility(vcpu, rd) == 0 &&
	    kvm_has_feat(vcpu->kvm, ID_AA64MMFR0_EL1, FGT, IMP))
		return 0;

	return REG_HIDDEN;
}

static unsigned int s1pie_visibility(const struct kvm_vcpu *vcpu,
				     const struct sys_reg_desc *rd)
{
@@ -3352,8 +3376,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
	EL2_REG(MDCR_EL2, access_mdcr, reset_mdcr, 0),
	EL2_REG(CPTR_EL2, access_rw, reset_val, CPTR_NVHE_EL2_RES1),
	EL2_REG_VNCR(HSTR_EL2, reset_val, 0),
	EL2_REG_VNCR(HFGRTR_EL2, reset_val, 0),
	EL2_REG_VNCR(HFGWTR_EL2, reset_val, 0),
	EL2_REG_VNCR_FILT(HFGRTR_EL2, fgt_visibility),
	EL2_REG_VNCR_FILT(HFGWTR_EL2, fgt_visibility),
	EL2_REG_VNCR(HFGITR_EL2, reset_val, 0),
	EL2_REG_VNCR(HACR_EL2, reset_val, 0),

@@ -3373,9 +3397,14 @@ static const struct sys_reg_desc sys_reg_descs[] = {
			 vncr_el2_visibility),

	{ SYS_DESC(SYS_DACR32_EL2), undef_access, reset_unknown, DACR32_EL2 },
	EL2_REG_VNCR(HDFGRTR_EL2, reset_val, 0),
	EL2_REG_VNCR(HDFGWTR_EL2, reset_val, 0),
	EL2_REG_VNCR(HAFGRTR_EL2, reset_val, 0),
	EL2_REG_VNCR_FILT(HDFGRTR2_EL2, fgt2_visibility),
	EL2_REG_VNCR_FILT(HDFGWTR2_EL2, fgt2_visibility),
	EL2_REG_VNCR_FILT(HFGRTR2_EL2, fgt2_visibility),
	EL2_REG_VNCR_FILT(HFGWTR2_EL2, fgt2_visibility),
	EL2_REG_VNCR_FILT(HDFGRTR_EL2, fgt_visibility),
	EL2_REG_VNCR_FILT(HDFGWTR_EL2, fgt_visibility),
	EL2_REG_VNCR_FILT(HAFGRTR_EL2, fgt_visibility),
	EL2_REG_VNCR_FILT(HFGITR2_EL2, fgt2_visibility),
	EL2_REG_REDIR(SPSR_EL2, reset_val, 0),
	EL2_REG_REDIR(ELR_EL2, reset_val, 0),
	{ SYS_DESC(SYS_SP_EL1), access_sp_el1},
@@ -3417,44 +3446,44 @@ static const struct sys_reg_desc sys_reg_descs[] = {
	{ SYS_DESC(SYS_MPAMVPM7_EL2), undef_access },

	EL2_REG(VBAR_EL2, access_rw, reset_val, 0),
	EL2_REG(RVBAR_EL2, access_rw, reset_val, 0),
	{ SYS_DESC(SYS_RVBAR_EL2), undef_access },
	{ SYS_DESC(SYS_RMR_EL2), undef_access },
	EL2_REG_VNCR(VDISR_EL2, reset_unknown, 0),

	EL2_REG_VNCR(ICH_AP0R0_EL2, reset_val, 0),
	EL2_REG_VNCR(ICH_AP0R1_EL2, reset_val, 0),
	EL2_REG_VNCR(ICH_AP0R2_EL2, reset_val, 0),
	EL2_REG_VNCR(ICH_AP0R3_EL2, reset_val, 0),
	EL2_REG_VNCR(ICH_AP1R0_EL2, reset_val, 0),
	EL2_REG_VNCR(ICH_AP1R1_EL2, reset_val, 0),
	EL2_REG_VNCR(ICH_AP1R2_EL2, reset_val, 0),
	EL2_REG_VNCR(ICH_AP1R3_EL2, reset_val, 0),
	EL2_REG_VNCR_GICv3(ICH_AP0R0_EL2),
	EL2_REG_VNCR_GICv3(ICH_AP0R1_EL2),
	EL2_REG_VNCR_GICv3(ICH_AP0R2_EL2),
	EL2_REG_VNCR_GICv3(ICH_AP0R3_EL2),
	EL2_REG_VNCR_GICv3(ICH_AP1R0_EL2),
	EL2_REG_VNCR_GICv3(ICH_AP1R1_EL2),
	EL2_REG_VNCR_GICv3(ICH_AP1R2_EL2),
	EL2_REG_VNCR_GICv3(ICH_AP1R3_EL2),

	{ SYS_DESC(SYS_ICC_SRE_EL2), access_gic_sre },

	EL2_REG_VNCR(ICH_HCR_EL2, reset_val, 0),
	EL2_REG_VNCR_GICv3(ICH_HCR_EL2),
	{ SYS_DESC(SYS_ICH_VTR_EL2), access_gic_vtr },
	{ SYS_DESC(SYS_ICH_MISR_EL2), access_gic_misr },
	{ SYS_DESC(SYS_ICH_EISR_EL2), access_gic_eisr },
	{ SYS_DESC(SYS_ICH_ELRSR_EL2), access_gic_elrsr },
	EL2_REG_VNCR(ICH_VMCR_EL2, reset_val, 0),

	EL2_REG_VNCR(ICH_LR0_EL2, reset_val, 0),
	EL2_REG_VNCR(ICH_LR1_EL2, reset_val, 0),
	EL2_REG_VNCR(ICH_LR2_EL2, reset_val, 0),
	EL2_REG_VNCR(ICH_LR3_EL2, reset_val, 0),
	EL2_REG_VNCR(ICH_LR4_EL2, reset_val, 0),
	EL2_REG_VNCR(ICH_LR5_EL2, reset_val, 0),
	EL2_REG_VNCR(ICH_LR6_EL2, reset_val, 0),
	EL2_REG_VNCR(ICH_LR7_EL2, reset_val, 0),
	EL2_REG_VNCR(ICH_LR8_EL2, reset_val, 0),
	EL2_REG_VNCR(ICH_LR9_EL2, reset_val, 0),
	EL2_REG_VNCR(ICH_LR10_EL2, reset_val, 0),
	EL2_REG_VNCR(ICH_LR11_EL2, reset_val, 0),
	EL2_REG_VNCR(ICH_LR12_EL2, reset_val, 0),
	EL2_REG_VNCR(ICH_LR13_EL2, reset_val, 0),
	EL2_REG_VNCR(ICH_LR14_EL2, reset_val, 0),
	EL2_REG_VNCR(ICH_LR15_EL2, reset_val, 0),
	EL2_REG_VNCR_GICv3(ICH_VMCR_EL2),

	EL2_REG_VNCR_GICv3(ICH_LR0_EL2),
	EL2_REG_VNCR_GICv3(ICH_LR1_EL2),
	EL2_REG_VNCR_GICv3(ICH_LR2_EL2),
	EL2_REG_VNCR_GICv3(ICH_LR3_EL2),
	EL2_REG_VNCR_GICv3(ICH_LR4_EL2),
	EL2_REG_VNCR_GICv3(ICH_LR5_EL2),
	EL2_REG_VNCR_GICv3(ICH_LR6_EL2),
	EL2_REG_VNCR_GICv3(ICH_LR7_EL2),
	EL2_REG_VNCR_GICv3(ICH_LR8_EL2),
	EL2_REG_VNCR_GICv3(ICH_LR9_EL2),
	EL2_REG_VNCR_GICv3(ICH_LR10_EL2),
	EL2_REG_VNCR_GICv3(ICH_LR11_EL2),
	EL2_REG_VNCR_GICv3(ICH_LR12_EL2),
	EL2_REG_VNCR_GICv3(ICH_LR13_EL2),
	EL2_REG_VNCR_GICv3(ICH_LR14_EL2),
	EL2_REG_VNCR_GICv3(ICH_LR15_EL2),

	EL2_REG(CONTEXTIDR_EL2, access_rw, reset_val, 0),
	EL2_REG(TPIDR_EL2, access_rw, reset_val, 0),
@@ -4323,12 +4352,12 @@ static const struct sys_reg_desc cp15_64_regs[] = {
};

static bool check_sysreg_table(const struct sys_reg_desc *table, unsigned int n,
			       bool is_32)
			       bool reset_check)
{
	unsigned int i;

	for (i = 0; i < n; i++) {
		if (!is_32 && table[i].reg && !table[i].reset) {
		if (reset_check && table[i].reg && !table[i].reset) {
			kvm_err("sys_reg table %pS entry %d (%s) lacks reset\n",
				&table[i], i, table[i].name);
			return false;
@@ -5317,18 +5346,22 @@ int kvm_finalize_sys_regs(struct kvm_vcpu *vcpu)

int __init kvm_sys_reg_table_init(void)
{
	const struct sys_reg_desc *gicv3_regs;
	bool valid = true;
	unsigned int i;
	unsigned int i, sz;
	int ret = 0;

	/* Make sure tables are unique and in order. */
	valid &= check_sysreg_table(sys_reg_descs, ARRAY_SIZE(sys_reg_descs), false);
	valid &= check_sysreg_table(cp14_regs, ARRAY_SIZE(cp14_regs), true);
	valid &= check_sysreg_table(cp14_64_regs, ARRAY_SIZE(cp14_64_regs), true);
	valid &= check_sysreg_table(cp15_regs, ARRAY_SIZE(cp15_regs), true);
	valid &= check_sysreg_table(cp15_64_regs, ARRAY_SIZE(cp15_64_regs), true);
	valid &= check_sysreg_table(sys_reg_descs, ARRAY_SIZE(sys_reg_descs), true);
	valid &= check_sysreg_table(cp14_regs, ARRAY_SIZE(cp14_regs), false);
	valid &= check_sysreg_table(cp14_64_regs, ARRAY_SIZE(cp14_64_regs), false);
	valid &= check_sysreg_table(cp15_regs, ARRAY_SIZE(cp15_regs), false);
	valid &= check_sysreg_table(cp15_64_regs, ARRAY_SIZE(cp15_64_regs), false);
	valid &= check_sysreg_table(sys_insn_descs, ARRAY_SIZE(sys_insn_descs), false);

	gicv3_regs = vgic_v3_get_sysreg_table(&sz);
	valid &= check_sysreg_table(gicv3_regs, sz, false);

	if (!valid)
		return -EINVAL;

+125 −2
Original line number Diff line number Diff line
@@ -297,6 +297,91 @@ static int get_gic_sre(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
	return 0;
}

static int set_gic_ich_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
			   u64 val)
{
	__vcpu_assign_sys_reg(vcpu, r->reg, val);
	return 0;
}

static int get_gic_ich_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
			    u64 *val)
{
	*val = __vcpu_sys_reg(vcpu, r->reg);
	return 0;
}

static int set_gic_ich_apr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
			   u64 val)
{
	u8 idx = r->Op2 & 3;

	if (idx > vgic_v3_max_apr_idx(vcpu))
		return -EINVAL;

	return set_gic_ich_reg(vcpu, r, val);
}

static int get_gic_ich_apr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
			    u64 *val)
{
	u8 idx = r->Op2 & 3;

	if (idx > vgic_v3_max_apr_idx(vcpu))
		return -EINVAL;

	return get_gic_ich_reg(vcpu, r, val);
}

static int set_gic_icc_sre(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
			   u64 val)
{
	if (val != KVM_ICC_SRE_EL2)
		return -EINVAL;
	return 0;
}

static int get_gic_icc_sre(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
			   u64 *val)
{
	*val = KVM_ICC_SRE_EL2;
	return 0;
}

static int set_gic_ich_vtr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
			   u64 val)
{
	if (val != kvm_get_guest_vtr_el2())
		return -EINVAL;
	return 0;
}

static int get_gic_ich_vtr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
			   u64 *val)
{
	*val = kvm_get_guest_vtr_el2();
	return 0;
}

static unsigned int el2_visibility(const struct kvm_vcpu *vcpu,
				   const struct sys_reg_desc *rd)
{
	return vcpu_has_nv(vcpu) ? 0 : REG_HIDDEN;
}

#define __EL2_REG(r, acc, i)			\
	{					\
		SYS_DESC(SYS_ ## r),		\
		.get_user = get_gic_ ## acc,	\
		.set_user = set_gic_ ## acc,	\
		.reg = i,			\
		.visibility = el2_visibility,	\
	}

#define EL2_REG(r, acc)		__EL2_REG(r, acc, r)

#define EL2_REG_RO(r, acc)	__EL2_REG(r, acc, 0)

static const struct sys_reg_desc gic_v3_icc_reg_descs[] = {
	{ SYS_DESC(SYS_ICC_PMR_EL1),
	  .set_user = set_gic_pmr, .get_user = get_gic_pmr, },
@@ -328,8 +413,42 @@ static const struct sys_reg_desc gic_v3_icc_reg_descs[] = {
	  .set_user = set_gic_grpen0, .get_user = get_gic_grpen0, },
	{ SYS_DESC(SYS_ICC_IGRPEN1_EL1),
	  .set_user = set_gic_grpen1, .get_user = get_gic_grpen1, },
	EL2_REG(ICH_AP0R0_EL2, ich_apr),
	EL2_REG(ICH_AP0R1_EL2, ich_apr),
	EL2_REG(ICH_AP0R2_EL2, ich_apr),
	EL2_REG(ICH_AP0R3_EL2, ich_apr),
	EL2_REG(ICH_AP1R0_EL2, ich_apr),
	EL2_REG(ICH_AP1R1_EL2, ich_apr),
	EL2_REG(ICH_AP1R2_EL2, ich_apr),
	EL2_REG(ICH_AP1R3_EL2, ich_apr),
	EL2_REG_RO(ICC_SRE_EL2, icc_sre),
	EL2_REG(ICH_HCR_EL2, ich_reg),
	EL2_REG_RO(ICH_VTR_EL2, ich_vtr),
	EL2_REG(ICH_VMCR_EL2, ich_reg),
	EL2_REG(ICH_LR0_EL2, ich_reg),
	EL2_REG(ICH_LR1_EL2, ich_reg),
	EL2_REG(ICH_LR2_EL2, ich_reg),
	EL2_REG(ICH_LR3_EL2, ich_reg),
	EL2_REG(ICH_LR4_EL2, ich_reg),
	EL2_REG(ICH_LR5_EL2, ich_reg),
	EL2_REG(ICH_LR6_EL2, ich_reg),
	EL2_REG(ICH_LR7_EL2, ich_reg),
	EL2_REG(ICH_LR8_EL2, ich_reg),
	EL2_REG(ICH_LR9_EL2, ich_reg),
	EL2_REG(ICH_LR10_EL2, ich_reg),
	EL2_REG(ICH_LR11_EL2, ich_reg),
	EL2_REG(ICH_LR12_EL2, ich_reg),
	EL2_REG(ICH_LR13_EL2, ich_reg),
	EL2_REG(ICH_LR14_EL2, ich_reg),
	EL2_REG(ICH_LR15_EL2, ich_reg),
};

const struct sys_reg_desc *vgic_v3_get_sysreg_table(unsigned int *sz)
{
	*sz = ARRAY_SIZE(gic_v3_icc_reg_descs);
	return gic_v3_icc_reg_descs;
}

static u64 attr_to_id(u64 attr)
{
	return ARM64_SYS_REG(FIELD_GET(KVM_REG_ARM_VGIC_SYSREG_OP0_MASK, attr),
@@ -341,8 +460,12 @@ static u64 attr_to_id(u64 attr)

int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
{
	if (get_reg_by_id(attr_to_id(attr->attr), gic_v3_icc_reg_descs,
			  ARRAY_SIZE(gic_v3_icc_reg_descs)))
	const struct sys_reg_desc *r;

	r = get_reg_by_id(attr_to_id(attr->attr), gic_v3_icc_reg_descs,
			  ARRAY_SIZE(gic_v3_icc_reg_descs));

	if (r && !sysreg_hidden(vcpu, r))
		return 0;

	return -ENXIO;
+19 −0
Original line number Diff line number Diff line
@@ -64,6 +64,24 @@
				      KVM_REG_ARM_VGIC_SYSREG_CRM_MASK | \
				      KVM_REG_ARM_VGIC_SYSREG_OP2_MASK)

#define KVM_ICC_SRE_EL2		(ICC_SRE_EL2_ENABLE | ICC_SRE_EL2_SRE |	\
				 ICC_SRE_EL1_DIB | ICC_SRE_EL1_DFB)
#define KVM_ICH_VTR_EL2_RES0	(ICH_VTR_EL2_DVIM 	|	\
				 ICH_VTR_EL2_A3V	|	\
				 ICH_VTR_EL2_IDbits)
#define KVM_ICH_VTR_EL2_RES1	ICH_VTR_EL2_nV4

static inline u64 kvm_get_guest_vtr_el2(void)
{
	u64 vtr;

	vtr  = kvm_vgic_global_state.ich_vtr_el2;
	vtr &= ~KVM_ICH_VTR_EL2_RES0;
	vtr |= KVM_ICH_VTR_EL2_RES1;

	return vtr;
}

/*
 * As per Documentation/virt/kvm/devices/arm-vgic-its.rst,
 * below macros are defined for ITS table entry encoding.
@@ -297,6 +315,7 @@ int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu,
				struct kvm_device_attr *attr, bool is_write);
int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr);
const struct sys_reg_desc *vgic_v3_get_sysreg_table(unsigned int *sz);
int vgic_v3_line_level_info_uaccess(struct kvm_vcpu *vcpu, bool is_write,
				    u32 intid, u32 *val);
int kvm_register_vgic_device(unsigned long type);
+168 −36
Original line number Diff line number Diff line
@@ -15,6 +15,12 @@
#include "test_util.h"
#include "processor.h"

#define SYS_REG(r)	ARM64_SYS_REG(sys_reg_Op0(SYS_ ## r),	\
				      sys_reg_Op1(SYS_ ## r),	\
				      sys_reg_CRn(SYS_ ## r),	\
				      sys_reg_CRm(SYS_ ## r),	\
				      sys_reg_Op2(SYS_ ## r))

struct feature_id_reg {
	__u64 reg;
	__u64 id_reg;
@@ -22,43 +28,41 @@ struct feature_id_reg {
	__u64 feat_min;
};

static struct feature_id_reg feat_id_regs[] = {
	{
		ARM64_SYS_REG(3, 0, 2, 0, 3),	/* TCR2_EL1 */
		ARM64_SYS_REG(3, 0, 0, 7, 3),	/* ID_AA64MMFR3_EL1 */
		0,
		1
	},
	{
		ARM64_SYS_REG(3, 0, 10, 2, 2),	/* PIRE0_EL1 */
		ARM64_SYS_REG(3, 0, 0, 7, 3),	/* ID_AA64MMFR3_EL1 */
		8,
		1
	},
	{
		ARM64_SYS_REG(3, 0, 10, 2, 3),	/* PIR_EL1 */
		ARM64_SYS_REG(3, 0, 0, 7, 3),	/* ID_AA64MMFR3_EL1 */
		8,
		1
	},
	{
		ARM64_SYS_REG(3, 0, 10, 2, 4),	/* POR_EL1 */
		ARM64_SYS_REG(3, 0, 0, 7, 3),	/* ID_AA64MMFR3_EL1 */
		16,
		1
	},
	{
		ARM64_SYS_REG(3, 3, 10, 2, 4),	/* POR_EL0 */
		ARM64_SYS_REG(3, 0, 0, 7, 3),	/* ID_AA64MMFR3_EL1 */
		16,
		1
	},
	{
		KVM_ARM64_SYS_REG(SYS_SCTLR2_EL1),
		KVM_ARM64_SYS_REG(SYS_ID_AA64MMFR3_EL1),
		ID_AA64MMFR3_EL1_SCTLRX_SHIFT,
		ID_AA64MMFR3_EL1_SCTLRX_IMP
#define FEAT(id, f, v)					\
	.id_reg		= SYS_REG(id),			\
	.feat_shift	= id ## _ ## f ## _SHIFT,	\
	.feat_min	= id ## _ ## f ## _ ## v

#define REG_FEAT(r, id, f, v)			\
	{					\
		.reg = SYS_REG(r),		\
		FEAT(id, f, v)			\
	}

static struct feature_id_reg feat_id_regs[] = {
	REG_FEAT(TCR2_EL1,	ID_AA64MMFR3_EL1, TCRX, IMP),
	REG_FEAT(TCR2_EL2,	ID_AA64MMFR3_EL1, TCRX, IMP),
	REG_FEAT(PIRE0_EL1,	ID_AA64MMFR3_EL1, S1PIE, IMP),
	REG_FEAT(PIRE0_EL2,	ID_AA64MMFR3_EL1, S1PIE, IMP),
	REG_FEAT(PIR_EL1,	ID_AA64MMFR3_EL1, S1PIE, IMP),
	REG_FEAT(PIR_EL2,	ID_AA64MMFR3_EL1, S1PIE, IMP),
	REG_FEAT(POR_EL1,	ID_AA64MMFR3_EL1, S1POE, IMP),
	REG_FEAT(POR_EL0,	ID_AA64MMFR3_EL1, S1POE, IMP),
	REG_FEAT(POR_EL2,	ID_AA64MMFR3_EL1, S1POE, IMP),
	REG_FEAT(HCRX_EL2,	ID_AA64MMFR1_EL1, HCX, IMP),
	REG_FEAT(HFGRTR_EL2,	ID_AA64MMFR0_EL1, FGT, IMP),
	REG_FEAT(HFGWTR_EL2,	ID_AA64MMFR0_EL1, FGT, IMP),
	REG_FEAT(HFGITR_EL2,	ID_AA64MMFR0_EL1, FGT, IMP),
	REG_FEAT(HDFGRTR_EL2,	ID_AA64MMFR0_EL1, FGT, IMP),
	REG_FEAT(HDFGWTR_EL2,	ID_AA64MMFR0_EL1, FGT, IMP),
	REG_FEAT(HAFGRTR_EL2,	ID_AA64MMFR0_EL1, FGT, IMP),
	REG_FEAT(HFGRTR2_EL2,	ID_AA64MMFR0_EL1, FGT, FGT2),
	REG_FEAT(HFGWTR2_EL2,	ID_AA64MMFR0_EL1, FGT, FGT2),
	REG_FEAT(HFGITR2_EL2,	ID_AA64MMFR0_EL1, FGT, FGT2),
	REG_FEAT(HDFGRTR2_EL2,	ID_AA64MMFR0_EL1, FGT, FGT2),
	REG_FEAT(HDFGWTR2_EL2,	ID_AA64MMFR0_EL1, FGT, FGT2),
	REG_FEAT(ZCR_EL2,	ID_AA64PFR0_EL1, SVE, IMP),
	REG_FEAT(SCTLR2_EL1,	ID_AA64MMFR3_EL1, SCTLRX, IMP),
};

bool filter_reg(__u64 reg)
@@ -693,6 +697,60 @@ static __u64 pauth_generic_regs[] = {
	ARM64_SYS_REG(3, 0, 2, 3, 1),	/* APGAKEYHI_EL1 */
};

static __u64 el2_regs[] = {
	SYS_REG(VPIDR_EL2),
	SYS_REG(VMPIDR_EL2),
	SYS_REG(SCTLR_EL2),
	SYS_REG(ACTLR_EL2),
	SYS_REG(HCR_EL2),
	SYS_REG(MDCR_EL2),
	SYS_REG(CPTR_EL2),
	SYS_REG(HSTR_EL2),
	SYS_REG(HFGRTR_EL2),
	SYS_REG(HFGWTR_EL2),
	SYS_REG(HFGITR_EL2),
	SYS_REG(HACR_EL2),
	SYS_REG(ZCR_EL2),
	SYS_REG(HCRX_EL2),
	SYS_REG(TTBR0_EL2),
	SYS_REG(TTBR1_EL2),
	SYS_REG(TCR_EL2),
	SYS_REG(TCR2_EL2),
	SYS_REG(VTTBR_EL2),
	SYS_REG(VTCR_EL2),
	SYS_REG(VNCR_EL2),
	SYS_REG(HDFGRTR2_EL2),
	SYS_REG(HDFGWTR2_EL2),
	SYS_REG(HFGRTR2_EL2),
	SYS_REG(HFGWTR2_EL2),
	SYS_REG(HDFGRTR_EL2),
	SYS_REG(HDFGWTR_EL2),
	SYS_REG(HAFGRTR_EL2),
	SYS_REG(HFGITR2_EL2),
	SYS_REG(SPSR_EL2),
	SYS_REG(ELR_EL2),
	SYS_REG(AFSR0_EL2),
	SYS_REG(AFSR1_EL2),
	SYS_REG(ESR_EL2),
	SYS_REG(FAR_EL2),
	SYS_REG(HPFAR_EL2),
	SYS_REG(MAIR_EL2),
	SYS_REG(PIRE0_EL2),
	SYS_REG(PIR_EL2),
	SYS_REG(POR_EL2),
	SYS_REG(AMAIR_EL2),
	SYS_REG(VBAR_EL2),
	SYS_REG(CONTEXTIDR_EL2),
	SYS_REG(TPIDR_EL2),
	SYS_REG(CNTVOFF_EL2),
	SYS_REG(CNTHCTL_EL2),
	SYS_REG(CNTHP_CTL_EL2),
	SYS_REG(CNTHP_CVAL_EL2),
	SYS_REG(CNTHV_CTL_EL2),
	SYS_REG(CNTHV_CVAL_EL2),
	SYS_REG(SP_EL2),
};

#define BASE_SUBLIST \
	{ "base", .regs = base_regs, .regs_n = ARRAY_SIZE(base_regs), }
#define VREGS_SUBLIST \
@@ -719,6 +777,14 @@ static __u64 pauth_generic_regs[] = {
		.regs		= pauth_generic_regs,			\
		.regs_n		= ARRAY_SIZE(pauth_generic_regs),	\
	}
#define EL2_SUBLIST						\
	{							\
		.name 		= "EL2",			\
		.capability	= KVM_CAP_ARM_EL2,		\
		.feature	= KVM_ARM_VCPU_HAS_EL2,		\
		.regs		= el2_regs,			\
		.regs_n		= ARRAY_SIZE(el2_regs),		\
	}

static struct vcpu_reg_list vregs_config = {
	.sublists = {
@@ -768,6 +834,65 @@ static struct vcpu_reg_list pauth_pmu_config = {
	},
};

static struct vcpu_reg_list el2_vregs_config = {
	.sublists = {
	BASE_SUBLIST,
	EL2_SUBLIST,
	VREGS_SUBLIST,
	{0},
	},
};

static struct vcpu_reg_list el2_vregs_pmu_config = {
	.sublists = {
	BASE_SUBLIST,
	EL2_SUBLIST,
	VREGS_SUBLIST,
	PMU_SUBLIST,
	{0},
	},
};

static struct vcpu_reg_list el2_sve_config = {
	.sublists = {
	BASE_SUBLIST,
	EL2_SUBLIST,
	SVE_SUBLIST,
	{0},
	},
};

static struct vcpu_reg_list el2_sve_pmu_config = {
	.sublists = {
	BASE_SUBLIST,
	EL2_SUBLIST,
	SVE_SUBLIST,
	PMU_SUBLIST,
	{0},
	},
};

static struct vcpu_reg_list el2_pauth_config = {
	.sublists = {
	BASE_SUBLIST,
	EL2_SUBLIST,
	VREGS_SUBLIST,
	PAUTH_SUBLIST,
	{0},
	},
};

static struct vcpu_reg_list el2_pauth_pmu_config = {
	.sublists = {
	BASE_SUBLIST,
	EL2_SUBLIST,
	VREGS_SUBLIST,
	PAUTH_SUBLIST,
	PMU_SUBLIST,
	{0},
	},
};

struct vcpu_reg_list *vcpu_configs[] = {
	&vregs_config,
	&vregs_pmu_config,
@@ -775,5 +900,12 @@ struct vcpu_reg_list *vcpu_configs[] = {
	&sve_pmu_config,
	&pauth_config,
	&pauth_pmu_config,

	&el2_vregs_config,
	&el2_vregs_pmu_config,
	&el2_sve_config,
	&el2_sve_pmu_config,
	&el2_pauth_config,
	&el2_pauth_pmu_config,
};
int vcpu_configs_n = ARRAY_SIZE(vcpu_configs);
Loading