162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * VGIC system registers handling functions for AArch64 mode
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/irqchip/arm-gic-v3.h>
762306a36Sopenharmony_ci#include <linux/kvm.h>
862306a36Sopenharmony_ci#include <linux/kvm_host.h>
962306a36Sopenharmony_ci#include <asm/kvm_emulate.h>
1062306a36Sopenharmony_ci#include "vgic/vgic.h"
1162306a36Sopenharmony_ci#include "sys_regs.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistatic int set_gic_ctlr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
1462306a36Sopenharmony_ci			u64 val)
1562306a36Sopenharmony_ci{
1662306a36Sopenharmony_ci	u32 host_pri_bits, host_id_bits, host_seis, host_a3v, seis, a3v;
1762306a36Sopenharmony_ci	struct vgic_cpu *vgic_v3_cpu = &vcpu->arch.vgic_cpu;
1862306a36Sopenharmony_ci	struct vgic_vmcr vmcr;
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci	vgic_get_vmcr(vcpu, &vmcr);
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci	/*
2362306a36Sopenharmony_ci	 * Disallow restoring VM state if not supported by this
2462306a36Sopenharmony_ci	 * hardware.
2562306a36Sopenharmony_ci	 */
2662306a36Sopenharmony_ci	host_pri_bits = FIELD_GET(ICC_CTLR_EL1_PRI_BITS_MASK, val) + 1;
2762306a36Sopenharmony_ci	if (host_pri_bits > vgic_v3_cpu->num_pri_bits)
2862306a36Sopenharmony_ci		return -EINVAL;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	vgic_v3_cpu->num_pri_bits = host_pri_bits;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	host_id_bits = FIELD_GET(ICC_CTLR_EL1_ID_BITS_MASK, val);
3362306a36Sopenharmony_ci	if (host_id_bits > vgic_v3_cpu->num_id_bits)
3462306a36Sopenharmony_ci		return -EINVAL;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	vgic_v3_cpu->num_id_bits = host_id_bits;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	host_seis = FIELD_GET(ICH_VTR_SEIS_MASK, kvm_vgic_global_state.ich_vtr_el2);
3962306a36Sopenharmony_ci	seis = FIELD_GET(ICC_CTLR_EL1_SEIS_MASK, val);
4062306a36Sopenharmony_ci	if (host_seis != seis)
4162306a36Sopenharmony_ci		return -EINVAL;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	host_a3v = FIELD_GET(ICH_VTR_A3V_MASK, kvm_vgic_global_state.ich_vtr_el2);
4462306a36Sopenharmony_ci	a3v = FIELD_GET(ICC_CTLR_EL1_A3V_MASK, val);
4562306a36Sopenharmony_ci	if (host_a3v != a3v)
4662306a36Sopenharmony_ci		return -EINVAL;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	/*
4962306a36Sopenharmony_ci	 * Here set VMCR.CTLR in ICC_CTLR_EL1 layout.
5062306a36Sopenharmony_ci	 * The vgic_set_vmcr() will convert to ICH_VMCR layout.
5162306a36Sopenharmony_ci	 */
5262306a36Sopenharmony_ci	vmcr.cbpr = FIELD_GET(ICC_CTLR_EL1_CBPR_MASK, val);
5362306a36Sopenharmony_ci	vmcr.eoim = FIELD_GET(ICC_CTLR_EL1_EOImode_MASK, val);
5462306a36Sopenharmony_ci	vgic_set_vmcr(vcpu, &vmcr);
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	return 0;
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic int get_gic_ctlr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
6062306a36Sopenharmony_ci			u64 *valp)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	struct vgic_cpu *vgic_v3_cpu = &vcpu->arch.vgic_cpu;
6362306a36Sopenharmony_ci	struct vgic_vmcr vmcr;
6462306a36Sopenharmony_ci	u64 val;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	vgic_get_vmcr(vcpu, &vmcr);
6762306a36Sopenharmony_ci	val = 0;
6862306a36Sopenharmony_ci	val |= FIELD_PREP(ICC_CTLR_EL1_PRI_BITS_MASK, vgic_v3_cpu->num_pri_bits - 1);
6962306a36Sopenharmony_ci	val |= FIELD_PREP(ICC_CTLR_EL1_ID_BITS_MASK, vgic_v3_cpu->num_id_bits);
7062306a36Sopenharmony_ci	val |= FIELD_PREP(ICC_CTLR_EL1_SEIS_MASK,
7162306a36Sopenharmony_ci			  FIELD_GET(ICH_VTR_SEIS_MASK,
7262306a36Sopenharmony_ci				    kvm_vgic_global_state.ich_vtr_el2));
7362306a36Sopenharmony_ci	val |= FIELD_PREP(ICC_CTLR_EL1_A3V_MASK,
7462306a36Sopenharmony_ci			  FIELD_GET(ICH_VTR_A3V_MASK, kvm_vgic_global_state.ich_vtr_el2));
7562306a36Sopenharmony_ci	/*
7662306a36Sopenharmony_ci	 * The VMCR.CTLR value is in ICC_CTLR_EL1 layout.
7762306a36Sopenharmony_ci	 * Extract it directly using ICC_CTLR_EL1 reg definitions.
7862306a36Sopenharmony_ci	 */
7962306a36Sopenharmony_ci	val |= FIELD_PREP(ICC_CTLR_EL1_CBPR_MASK, vmcr.cbpr);
8062306a36Sopenharmony_ci	val |= FIELD_PREP(ICC_CTLR_EL1_EOImode_MASK, vmcr.eoim);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	*valp = val;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	return 0;
8562306a36Sopenharmony_ci}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic int set_gic_pmr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
8862306a36Sopenharmony_ci		       u64 val)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	struct vgic_vmcr vmcr;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	vgic_get_vmcr(vcpu, &vmcr);
9362306a36Sopenharmony_ci	vmcr.pmr = FIELD_GET(ICC_PMR_EL1_MASK, val);
9462306a36Sopenharmony_ci	vgic_set_vmcr(vcpu, &vmcr);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	return 0;
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic int get_gic_pmr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
10062306a36Sopenharmony_ci		       u64 *val)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	struct vgic_vmcr vmcr;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	vgic_get_vmcr(vcpu, &vmcr);
10562306a36Sopenharmony_ci	*val = FIELD_PREP(ICC_PMR_EL1_MASK, vmcr.pmr);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	return 0;
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic int set_gic_bpr0(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
11162306a36Sopenharmony_ci			u64 val)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	struct vgic_vmcr vmcr;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	vgic_get_vmcr(vcpu, &vmcr);
11662306a36Sopenharmony_ci	vmcr.bpr = FIELD_GET(ICC_BPR0_EL1_MASK, val);
11762306a36Sopenharmony_ci	vgic_set_vmcr(vcpu, &vmcr);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	return 0;
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic int get_gic_bpr0(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
12362306a36Sopenharmony_ci			u64 *val)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	struct vgic_vmcr vmcr;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	vgic_get_vmcr(vcpu, &vmcr);
12862306a36Sopenharmony_ci	*val = FIELD_PREP(ICC_BPR0_EL1_MASK, vmcr.bpr);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	return 0;
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic int set_gic_bpr1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
13462306a36Sopenharmony_ci			u64 val)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	struct vgic_vmcr vmcr;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	vgic_get_vmcr(vcpu, &vmcr);
13962306a36Sopenharmony_ci	if (!vmcr.cbpr) {
14062306a36Sopenharmony_ci		vmcr.abpr = FIELD_GET(ICC_BPR1_EL1_MASK, val);
14162306a36Sopenharmony_ci		vgic_set_vmcr(vcpu, &vmcr);
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	return 0;
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic int get_gic_bpr1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
14862306a36Sopenharmony_ci			u64 *val)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	struct vgic_vmcr vmcr;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	vgic_get_vmcr(vcpu, &vmcr);
15362306a36Sopenharmony_ci	if (!vmcr.cbpr)
15462306a36Sopenharmony_ci		*val = FIELD_PREP(ICC_BPR1_EL1_MASK, vmcr.abpr);
15562306a36Sopenharmony_ci	else
15662306a36Sopenharmony_ci		*val = min((vmcr.bpr + 1), 7U);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	return 0;
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic int set_gic_grpen0(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
16362306a36Sopenharmony_ci			  u64 val)
16462306a36Sopenharmony_ci{
16562306a36Sopenharmony_ci	struct vgic_vmcr vmcr;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	vgic_get_vmcr(vcpu, &vmcr);
16862306a36Sopenharmony_ci	vmcr.grpen0 = FIELD_GET(ICC_IGRPEN0_EL1_MASK, val);
16962306a36Sopenharmony_ci	vgic_set_vmcr(vcpu, &vmcr);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	return 0;
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_cistatic int get_gic_grpen0(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
17562306a36Sopenharmony_ci			  u64 *val)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	struct vgic_vmcr vmcr;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	vgic_get_vmcr(vcpu, &vmcr);
18062306a36Sopenharmony_ci	*val = FIELD_PREP(ICC_IGRPEN0_EL1_MASK, vmcr.grpen0);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	return 0;
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic int set_gic_grpen1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
18662306a36Sopenharmony_ci			  u64 val)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	struct vgic_vmcr vmcr;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	vgic_get_vmcr(vcpu, &vmcr);
19162306a36Sopenharmony_ci	vmcr.grpen1 = FIELD_GET(ICC_IGRPEN1_EL1_MASK, val);
19262306a36Sopenharmony_ci	vgic_set_vmcr(vcpu, &vmcr);
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	return 0;
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_cistatic int get_gic_grpen1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
19862306a36Sopenharmony_ci			  u64 *val)
19962306a36Sopenharmony_ci{
20062306a36Sopenharmony_ci	struct vgic_vmcr vmcr;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	vgic_get_vmcr(vcpu, &vmcr);
20362306a36Sopenharmony_ci	*val = FIELD_GET(ICC_IGRPEN1_EL1_MASK, vmcr.grpen1);
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	return 0;
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic void set_apr_reg(struct kvm_vcpu *vcpu, u64 val, u8 apr, u8 idx)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	if (apr)
21362306a36Sopenharmony_ci		vgicv3->vgic_ap1r[idx] = val;
21462306a36Sopenharmony_ci	else
21562306a36Sopenharmony_ci		vgicv3->vgic_ap0r[idx] = val;
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistatic u64 get_apr_reg(struct kvm_vcpu *vcpu, u8 apr, u8 idx)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	if (apr)
22362306a36Sopenharmony_ci		return vgicv3->vgic_ap1r[idx];
22462306a36Sopenharmony_ci	else
22562306a36Sopenharmony_ci		return vgicv3->vgic_ap0r[idx];
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic int set_gic_ap0r(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
22962306a36Sopenharmony_ci			u64 val)
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci{
23262306a36Sopenharmony_ci	u8 idx = r->Op2 & 3;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	if (idx > vgic_v3_max_apr_idx(vcpu))
23562306a36Sopenharmony_ci		return -EINVAL;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	set_apr_reg(vcpu, val, 0, idx);
23862306a36Sopenharmony_ci	return 0;
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic int get_gic_ap0r(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
24262306a36Sopenharmony_ci			u64 *val)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	u8 idx = r->Op2 & 3;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	if (idx > vgic_v3_max_apr_idx(vcpu))
24762306a36Sopenharmony_ci		return -EINVAL;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	*val = get_apr_reg(vcpu, 0, idx);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	return 0;
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic int set_gic_ap1r(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
25562306a36Sopenharmony_ci			u64 val)
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	u8 idx = r->Op2 & 3;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	if (idx > vgic_v3_max_apr_idx(vcpu))
26162306a36Sopenharmony_ci		return -EINVAL;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	set_apr_reg(vcpu, val, 1, idx);
26462306a36Sopenharmony_ci	return 0;
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic int get_gic_ap1r(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
26862306a36Sopenharmony_ci			u64 *val)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	u8 idx = r->Op2 & 3;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	if (idx > vgic_v3_max_apr_idx(vcpu))
27362306a36Sopenharmony_ci		return -EINVAL;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	*val = get_apr_reg(vcpu, 1, idx);
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	return 0;
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_cistatic int set_gic_sre(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
28162306a36Sopenharmony_ci		       u64 val)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	/* Validate SRE bit */
28462306a36Sopenharmony_ci	if (!(val & ICC_SRE_EL1_SRE))
28562306a36Sopenharmony_ci		return -EINVAL;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	return 0;
28862306a36Sopenharmony_ci}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_cistatic int get_gic_sre(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
29162306a36Sopenharmony_ci		       u64 *val)
29262306a36Sopenharmony_ci{
29362306a36Sopenharmony_ci	struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	*val = vgicv3->vgic_sre;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	return 0;
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic const struct sys_reg_desc gic_v3_icc_reg_descs[] = {
30162306a36Sopenharmony_ci	{ SYS_DESC(SYS_ICC_PMR_EL1),
30262306a36Sopenharmony_ci	  .set_user = set_gic_pmr, .get_user = get_gic_pmr, },
30362306a36Sopenharmony_ci	{ SYS_DESC(SYS_ICC_BPR0_EL1),
30462306a36Sopenharmony_ci	  .set_user = set_gic_bpr0, .get_user = get_gic_bpr0, },
30562306a36Sopenharmony_ci	{ SYS_DESC(SYS_ICC_AP0R0_EL1),
30662306a36Sopenharmony_ci	  .set_user = set_gic_ap0r, .get_user = get_gic_ap0r, },
30762306a36Sopenharmony_ci	{ SYS_DESC(SYS_ICC_AP0R1_EL1),
30862306a36Sopenharmony_ci	  .set_user = set_gic_ap0r, .get_user = get_gic_ap0r, },
30962306a36Sopenharmony_ci	{ SYS_DESC(SYS_ICC_AP0R2_EL1),
31062306a36Sopenharmony_ci	  .set_user = set_gic_ap0r, .get_user = get_gic_ap0r, },
31162306a36Sopenharmony_ci	{ SYS_DESC(SYS_ICC_AP0R3_EL1),
31262306a36Sopenharmony_ci	  .set_user = set_gic_ap0r, .get_user = get_gic_ap0r, },
31362306a36Sopenharmony_ci	{ SYS_DESC(SYS_ICC_AP1R0_EL1),
31462306a36Sopenharmony_ci	  .set_user = set_gic_ap1r, .get_user = get_gic_ap1r, },
31562306a36Sopenharmony_ci	{ SYS_DESC(SYS_ICC_AP1R1_EL1),
31662306a36Sopenharmony_ci	  .set_user = set_gic_ap1r, .get_user = get_gic_ap1r, },
31762306a36Sopenharmony_ci	{ SYS_DESC(SYS_ICC_AP1R2_EL1),
31862306a36Sopenharmony_ci	  .set_user = set_gic_ap1r, .get_user = get_gic_ap1r, },
31962306a36Sopenharmony_ci	{ SYS_DESC(SYS_ICC_AP1R3_EL1),
32062306a36Sopenharmony_ci	  .set_user = set_gic_ap1r, .get_user = get_gic_ap1r, },
32162306a36Sopenharmony_ci	{ SYS_DESC(SYS_ICC_BPR1_EL1),
32262306a36Sopenharmony_ci	  .set_user = set_gic_bpr1, .get_user = get_gic_bpr1, },
32362306a36Sopenharmony_ci	{ SYS_DESC(SYS_ICC_CTLR_EL1),
32462306a36Sopenharmony_ci	  .set_user = set_gic_ctlr, .get_user = get_gic_ctlr, },
32562306a36Sopenharmony_ci	{ SYS_DESC(SYS_ICC_SRE_EL1),
32662306a36Sopenharmony_ci	  .set_user = set_gic_sre, .get_user = get_gic_sre, },
32762306a36Sopenharmony_ci	{ SYS_DESC(SYS_ICC_IGRPEN0_EL1),
32862306a36Sopenharmony_ci	  .set_user = set_gic_grpen0, .get_user = get_gic_grpen0, },
32962306a36Sopenharmony_ci	{ SYS_DESC(SYS_ICC_IGRPEN1_EL1),
33062306a36Sopenharmony_ci	  .set_user = set_gic_grpen1, .get_user = get_gic_grpen1, },
33162306a36Sopenharmony_ci};
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_cistatic u64 attr_to_id(u64 attr)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	return ARM64_SYS_REG(FIELD_GET(KVM_REG_ARM_VGIC_SYSREG_OP0_MASK, attr),
33662306a36Sopenharmony_ci			     FIELD_GET(KVM_REG_ARM_VGIC_SYSREG_OP1_MASK, attr),
33762306a36Sopenharmony_ci			     FIELD_GET(KVM_REG_ARM_VGIC_SYSREG_CRN_MASK, attr),
33862306a36Sopenharmony_ci			     FIELD_GET(KVM_REG_ARM_VGIC_SYSREG_CRM_MASK, attr),
33962306a36Sopenharmony_ci			     FIELD_GET(KVM_REG_ARM_VGIC_SYSREG_OP2_MASK, attr));
34062306a36Sopenharmony_ci}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ciint vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
34362306a36Sopenharmony_ci{
34462306a36Sopenharmony_ci	if (get_reg_by_id(attr_to_id(attr->attr), gic_v3_icc_reg_descs,
34562306a36Sopenharmony_ci			  ARRAY_SIZE(gic_v3_icc_reg_descs)))
34662306a36Sopenharmony_ci		return 0;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	return -ENXIO;
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ciint vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu,
35262306a36Sopenharmony_ci				struct kvm_device_attr *attr,
35362306a36Sopenharmony_ci				bool is_write)
35462306a36Sopenharmony_ci{
35562306a36Sopenharmony_ci	struct kvm_one_reg reg = {
35662306a36Sopenharmony_ci		.id	= attr_to_id(attr->attr),
35762306a36Sopenharmony_ci		.addr	= attr->addr,
35862306a36Sopenharmony_ci	};
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	if (is_write)
36162306a36Sopenharmony_ci		return kvm_sys_reg_set_user(vcpu, &reg, gic_v3_icc_reg_descs,
36262306a36Sopenharmony_ci					    ARRAY_SIZE(gic_v3_icc_reg_descs));
36362306a36Sopenharmony_ci	else
36462306a36Sopenharmony_ci		return kvm_sys_reg_get_user(vcpu, &reg, gic_v3_icc_reg_descs,
36562306a36Sopenharmony_ci					    ARRAY_SIZE(gic_v3_icc_reg_descs));
36662306a36Sopenharmony_ci}
367