Commit cbcf14dd authored by Marc Zyngier's avatar Marc Zyngier

KVM: arm64: vgic-v3: Make the userspace accessors use sysreg API

The vgic-v3 sysreg accessors have been ignored as the rest of the
sysreg internal API was evolving, and are stuck with the .access
method (which is normally reserved to the guest's own access)
for the userspace accesses (which should use the .set/.get_user()
methods).

Catch up with the program and repaint all the accessors so that
they fit into the normal userspace model, and plug the result into
the helpers that have been introduced earlier.
Reviewed-by: default avatarReiji Watanabe <reijiw@google.com>
Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
parent db25081e
...@@ -10,254 +10,330 @@ ...@@ -10,254 +10,330 @@
#include "vgic/vgic.h" #include "vgic/vgic.h"
#include "sys_regs.h" #include "sys_regs.h"
static bool access_gic_ctlr(struct kvm_vcpu *vcpu, struct sys_reg_params *p, static int set_gic_ctlr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
const struct sys_reg_desc *r) u64 val)
{ {
u32 host_pri_bits, host_id_bits, host_seis, host_a3v, seis, a3v; 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_cpu *vgic_v3_cpu = &vcpu->arch.vgic_cpu;
struct vgic_vmcr vmcr; struct vgic_vmcr vmcr;
vgic_get_vmcr(vcpu, &vmcr);
/*
* Disallow restoring VM state if not supported by this
* hardware.
*/
host_pri_bits = ((val & ICC_CTLR_EL1_PRI_BITS_MASK) >>
ICC_CTLR_EL1_PRI_BITS_SHIFT) + 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 = (val & ICC_CTLR_EL1_ID_BITS_MASK) >>
ICC_CTLR_EL1_ID_BITS_SHIFT;
if (host_id_bits > vgic_v3_cpu->num_id_bits)
return -EINVAL;
vgic_v3_cpu->num_id_bits = host_id_bits;
host_seis = ((kvm_vgic_global_state.ich_vtr_el2 &
ICH_VTR_SEIS_MASK) >> ICH_VTR_SEIS_SHIFT);
seis = (val & ICC_CTLR_EL1_SEIS_MASK) >>
ICC_CTLR_EL1_SEIS_SHIFT;
if (host_seis != seis)
return -EINVAL;
host_a3v = ((kvm_vgic_global_state.ich_vtr_el2 &
ICH_VTR_A3V_MASK) >> ICH_VTR_A3V_SHIFT);
a3v = (val & ICC_CTLR_EL1_A3V_MASK) >> ICC_CTLR_EL1_A3V_SHIFT;
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 = (val & ICC_CTLR_EL1_CBPR_MASK) >> ICC_CTLR_EL1_CBPR_SHIFT;
vmcr.eoim = (val & ICC_CTLR_EL1_EOImode_MASK) >> ICC_CTLR_EL1_EOImode_SHIFT;
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; u64 val;
vgic_get_vmcr(vcpu, &vmcr); vgic_get_vmcr(vcpu, &vmcr);
if (p->is_write) { val = 0;
val = p->regval; val |= (vgic_v3_cpu->num_pri_bits - 1) << ICC_CTLR_EL1_PRI_BITS_SHIFT;
val |= vgic_v3_cpu->num_id_bits << ICC_CTLR_EL1_ID_BITS_SHIFT;
/* val |= ((kvm_vgic_global_state.ich_vtr_el2 &
* Disallow restoring VM state if not supported by this ICH_VTR_SEIS_MASK) >> ICH_VTR_SEIS_SHIFT) <<
* hardware. ICC_CTLR_EL1_SEIS_SHIFT;
*/ val |= ((kvm_vgic_global_state.ich_vtr_el2 &
host_pri_bits = ((val & ICC_CTLR_EL1_PRI_BITS_MASK) >> ICH_VTR_A3V_MASK) >> ICH_VTR_A3V_SHIFT) <<
ICC_CTLR_EL1_PRI_BITS_SHIFT) + 1; ICC_CTLR_EL1_A3V_SHIFT;
if (host_pri_bits > vgic_v3_cpu->num_pri_bits) /*
return false; * The VMCR.CTLR value is in ICC_CTLR_EL1 layout.
* Extract it directly using ICC_CTLR_EL1 reg definitions.
vgic_v3_cpu->num_pri_bits = host_pri_bits; */
val |= (vmcr.cbpr << ICC_CTLR_EL1_CBPR_SHIFT) & ICC_CTLR_EL1_CBPR_MASK;
host_id_bits = (val & ICC_CTLR_EL1_ID_BITS_MASK) >> val |= (vmcr.eoim << ICC_CTLR_EL1_EOImode_SHIFT) & ICC_CTLR_EL1_EOImode_MASK;
ICC_CTLR_EL1_ID_BITS_SHIFT;
if (host_id_bits > vgic_v3_cpu->num_id_bits) *valp = val;
return false;
vgic_v3_cpu->num_id_bits = host_id_bits;
host_seis = ((kvm_vgic_global_state.ich_vtr_el2 &
ICH_VTR_SEIS_MASK) >> ICH_VTR_SEIS_SHIFT);
seis = (val & ICC_CTLR_EL1_SEIS_MASK) >>
ICC_CTLR_EL1_SEIS_SHIFT;
if (host_seis != seis)
return false;
host_a3v = ((kvm_vgic_global_state.ich_vtr_el2 &
ICH_VTR_A3V_MASK) >> ICH_VTR_A3V_SHIFT);
a3v = (val & ICC_CTLR_EL1_A3V_MASK) >> ICC_CTLR_EL1_A3V_SHIFT;
if (host_a3v != a3v)
return false;
/*
* Here set VMCR.CTLR in ICC_CTLR_EL1 layout.
* The vgic_set_vmcr() will convert to ICH_VMCR layout.
*/
vmcr.cbpr = (val & ICC_CTLR_EL1_CBPR_MASK) >> ICC_CTLR_EL1_CBPR_SHIFT;
vmcr.eoim = (val & ICC_CTLR_EL1_EOImode_MASK) >> ICC_CTLR_EL1_EOImode_SHIFT;
vgic_set_vmcr(vcpu, &vmcr);
} else {
val = 0;
val |= (vgic_v3_cpu->num_pri_bits - 1) <<
ICC_CTLR_EL1_PRI_BITS_SHIFT;
val |= vgic_v3_cpu->num_id_bits << ICC_CTLR_EL1_ID_BITS_SHIFT;
val |= ((kvm_vgic_global_state.ich_vtr_el2 &
ICH_VTR_SEIS_MASK) >> ICH_VTR_SEIS_SHIFT) <<
ICC_CTLR_EL1_SEIS_SHIFT;
val |= ((kvm_vgic_global_state.ich_vtr_el2 &
ICH_VTR_A3V_MASK) >> ICH_VTR_A3V_SHIFT) <<
ICC_CTLR_EL1_A3V_SHIFT;
/*
* The VMCR.CTLR value is in ICC_CTLR_EL1 layout.
* Extract it directly using ICC_CTLR_EL1 reg definitions.
*/
val |= (vmcr.cbpr << ICC_CTLR_EL1_CBPR_SHIFT) & ICC_CTLR_EL1_CBPR_MASK;
val |= (vmcr.eoim << ICC_CTLR_EL1_EOImode_SHIFT) & ICC_CTLR_EL1_EOImode_MASK;
p->regval = val;
}
return true; return 0;
} }
static bool access_gic_pmr(struct kvm_vcpu *vcpu, struct sys_reg_params *p, static int set_gic_pmr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
const struct sys_reg_desc *r) u64 val)
{ {
struct vgic_vmcr vmcr; struct vgic_vmcr vmcr;
vgic_get_vmcr(vcpu, &vmcr); vgic_get_vmcr(vcpu, &vmcr);
if (p->is_write) { vmcr.pmr = (val & ICC_PMR_EL1_MASK) >> ICC_PMR_EL1_SHIFT;
vmcr.pmr = (p->regval & ICC_PMR_EL1_MASK) >> ICC_PMR_EL1_SHIFT; vgic_set_vmcr(vcpu, &vmcr);
vgic_set_vmcr(vcpu, &vmcr);
} else {
p->regval = (vmcr.pmr << ICC_PMR_EL1_SHIFT) & ICC_PMR_EL1_MASK;
}
return true; return 0;
} }
static bool access_gic_bpr0(struct kvm_vcpu *vcpu, struct sys_reg_params *p, static int get_gic_pmr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
const struct sys_reg_desc *r) u64 *val)
{ {
struct vgic_vmcr vmcr; struct vgic_vmcr vmcr;
vgic_get_vmcr(vcpu, &vmcr); vgic_get_vmcr(vcpu, &vmcr);
if (p->is_write) { *val = (vmcr.pmr << ICC_PMR_EL1_SHIFT) & ICC_PMR_EL1_MASK;
vmcr.bpr = (p->regval & ICC_BPR0_EL1_MASK) >>
ICC_BPR0_EL1_SHIFT;
vgic_set_vmcr(vcpu, &vmcr);
} else {
p->regval = (vmcr.bpr << ICC_BPR0_EL1_SHIFT) &
ICC_BPR0_EL1_MASK;
}
return true; return 0;
} }
static bool access_gic_bpr1(struct kvm_vcpu *vcpu, struct sys_reg_params *p, static int set_gic_bpr0(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
const struct sys_reg_desc *r) u64 val)
{ {
struct vgic_vmcr vmcr; struct vgic_vmcr vmcr;
if (!p->is_write) vgic_get_vmcr(vcpu, &vmcr);
p->regval = 0; vmcr.bpr = (val & ICC_BPR0_EL1_MASK) >> ICC_BPR0_EL1_SHIFT;
vgic_set_vmcr(vcpu, &vmcr);
return 0;
}
static int get_gic_bpr0(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
u64 *val)
{
struct vgic_vmcr vmcr;
vgic_get_vmcr(vcpu, &vmcr); vgic_get_vmcr(vcpu, &vmcr);
if (!vmcr.cbpr) { *val = (vmcr.bpr << ICC_BPR0_EL1_SHIFT) & ICC_BPR0_EL1_MASK;
if (p->is_write) {
vmcr.abpr = (p->regval & ICC_BPR1_EL1_MASK) >>
ICC_BPR1_EL1_SHIFT;
vgic_set_vmcr(vcpu, &vmcr);
} else {
p->regval = (vmcr.abpr << ICC_BPR1_EL1_SHIFT) &
ICC_BPR1_EL1_MASK;
}
} else {
if (!p->is_write)
p->regval = min((vmcr.bpr + 1), 7U);
}
return true; return 0;
} }
static bool access_gic_grpen0(struct kvm_vcpu *vcpu, struct sys_reg_params *p, static int set_gic_bpr1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
const struct sys_reg_desc *r) u64 val)
{ {
struct vgic_vmcr vmcr; struct vgic_vmcr vmcr;
vgic_get_vmcr(vcpu, &vmcr); vgic_get_vmcr(vcpu, &vmcr);
if (p->is_write) { if (!vmcr.cbpr) {
vmcr.grpen0 = (p->regval & ICC_IGRPEN0_EL1_MASK) >> vmcr.abpr = (val & ICC_BPR1_EL1_MASK) >> ICC_BPR1_EL1_SHIFT;
ICC_IGRPEN0_EL1_SHIFT;
vgic_set_vmcr(vcpu, &vmcr); vgic_set_vmcr(vcpu, &vmcr);
} else {
p->regval = (vmcr.grpen0 << ICC_IGRPEN0_EL1_SHIFT) &
ICC_IGRPEN0_EL1_MASK;
} }
return true; return 0;
} }
static bool access_gic_grpen1(struct kvm_vcpu *vcpu, struct sys_reg_params *p, static int get_gic_bpr1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
const struct sys_reg_desc *r) u64 *val)
{ {
struct vgic_vmcr vmcr; struct vgic_vmcr vmcr;
vgic_get_vmcr(vcpu, &vmcr); vgic_get_vmcr(vcpu, &vmcr);
if (p->is_write) { if (!vmcr.cbpr)
vmcr.grpen1 = (p->regval & ICC_IGRPEN1_EL1_MASK) >> *val = (vmcr.abpr << ICC_BPR1_EL1_SHIFT) & ICC_BPR1_EL1_MASK;
ICC_IGRPEN1_EL1_SHIFT; else
vgic_set_vmcr(vcpu, &vmcr); *val = min((vmcr.bpr + 1), 7U);
} else {
p->regval = (vmcr.grpen1 << ICC_IGRPEN1_EL1_SHIFT) &
ICC_IGRPEN1_EL1_MASK; return 0;
} }
static int set_gic_grpen0(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
u64 val)
{
struct vgic_vmcr vmcr;
vgic_get_vmcr(vcpu, &vmcr);
vmcr.grpen0 = (val & ICC_IGRPEN0_EL1_MASK) >> ICC_IGRPEN0_EL1_SHIFT;
vgic_set_vmcr(vcpu, &vmcr);
return 0;
}
static int get_gic_grpen0(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
u64 *val)
{
struct vgic_vmcr vmcr;
vgic_get_vmcr(vcpu, &vmcr);
*val = (vmcr.grpen0 << ICC_IGRPEN0_EL1_SHIFT) & ICC_IGRPEN0_EL1_MASK;
return 0;
}
static int set_gic_grpen1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
u64 val)
{
struct vgic_vmcr vmcr;
return true; vgic_get_vmcr(vcpu, &vmcr);
vmcr.grpen1 = (val & ICC_IGRPEN1_EL1_MASK) >> ICC_IGRPEN1_EL1_SHIFT;
vgic_set_vmcr(vcpu, &vmcr);
return 0;
} }
static void vgic_v3_access_apr_reg(struct kvm_vcpu *vcpu, static int get_gic_grpen1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
struct sys_reg_params *p, u8 apr, u8 idx) u64 *val)
{
struct vgic_vmcr vmcr;
vgic_get_vmcr(vcpu, &vmcr);
*val = (vmcr.grpen1 << ICC_IGRPEN1_EL1_SHIFT) & ICC_IGRPEN1_EL1_MASK;
return 0;
}
static void set_apr_reg(struct kvm_vcpu *vcpu, u64 val, u8 apr, u8 idx)
{ {
struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3; struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
uint32_t *ap_reg;
if (apr) if (apr)
ap_reg = &vgicv3->vgic_ap1r[idx]; vgicv3->vgic_ap1r[idx] = val;
else else
ap_reg = &vgicv3->vgic_ap0r[idx]; vgicv3->vgic_ap0r[idx] = val;
}
static u64 get_apr_reg(struct kvm_vcpu *vcpu, u8 apr, u8 idx)
{
struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
if (p->is_write) if (apr)
*ap_reg = p->regval; return vgicv3->vgic_ap1r[idx];
else else
p->regval = *ap_reg; return vgicv3->vgic_ap0r[idx];
}
static int set_gic_ap0r(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;
set_apr_reg(vcpu, val, 0, idx);
return 0;
} }
static bool access_gic_aprn(struct kvm_vcpu *vcpu, struct sys_reg_params *p, static int get_gic_ap0r(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
const struct sys_reg_desc *r, u8 apr) u64 *val)
{ {
u8 idx = r->Op2 & 3; u8 idx = r->Op2 & 3;
if (idx > vgic_v3_max_apr_idx(vcpu)) if (idx > vgic_v3_max_apr_idx(vcpu))
goto err; return -EINVAL;
vgic_v3_access_apr_reg(vcpu, p, apr, idx); *val = get_apr_reg(vcpu, 0, idx);
return true;
err:
if (!p->is_write)
p->regval = 0;
return false; return 0;
} }
static bool access_gic_ap0r(struct kvm_vcpu *vcpu, struct sys_reg_params *p, static int set_gic_ap1r(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
const struct sys_reg_desc *r) u64 val)
{ {
return access_gic_aprn(vcpu, p, r, 0); u8 idx = r->Op2 & 3;
if (idx > vgic_v3_max_apr_idx(vcpu))
return -EINVAL;
set_apr_reg(vcpu, val, 1, idx);
return 0;
}
static int get_gic_ap1r(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;
*val = get_apr_reg(vcpu, 1, idx);
return 0;
} }
static bool access_gic_ap1r(struct kvm_vcpu *vcpu, struct sys_reg_params *p, static int set_gic_sre(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
const struct sys_reg_desc *r) u64 val)
{ {
return access_gic_aprn(vcpu, p, r, 1); /* Validate SRE bit */
if (!(val & ICC_SRE_EL1_SRE))
return -EINVAL;
return 0;
} }
static bool access_gic_sre(struct kvm_vcpu *vcpu, struct sys_reg_params *p, static int get_gic_sre(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
const struct sys_reg_desc *r) u64 *val)
{ {
struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3; struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3;
/* Validate SRE bit */ *val = vgicv3->vgic_sre;
if (p->is_write) {
if (!(p->regval & ICC_SRE_EL1_SRE))
return false;
} else {
p->regval = vgicv3->vgic_sre;
}
return true; return 0;
} }
static const struct sys_reg_desc gic_v3_icc_reg_descs[] = { static const struct sys_reg_desc gic_v3_icc_reg_descs[] = {
{ SYS_DESC(SYS_ICC_PMR_EL1), access_gic_pmr }, { SYS_DESC(SYS_ICC_PMR_EL1),
{ SYS_DESC(SYS_ICC_BPR0_EL1), access_gic_bpr0 }, .set_user = set_gic_pmr, .get_user = get_gic_pmr, },
{ SYS_DESC(SYS_ICC_AP0R0_EL1), access_gic_ap0r }, { SYS_DESC(SYS_ICC_BPR0_EL1),
{ SYS_DESC(SYS_ICC_AP0R1_EL1), access_gic_ap0r }, .set_user = set_gic_bpr0, .get_user = get_gic_bpr0, },
{ SYS_DESC(SYS_ICC_AP0R2_EL1), access_gic_ap0r }, { SYS_DESC(SYS_ICC_AP0R0_EL1),
{ SYS_DESC(SYS_ICC_AP0R3_EL1), access_gic_ap0r }, .set_user = set_gic_ap0r, .get_user = get_gic_ap0r, },
{ SYS_DESC(SYS_ICC_AP1R0_EL1), access_gic_ap1r }, { SYS_DESC(SYS_ICC_AP0R1_EL1),
{ SYS_DESC(SYS_ICC_AP1R1_EL1), access_gic_ap1r }, .set_user = set_gic_ap0r, .get_user = get_gic_ap0r, },
{ SYS_DESC(SYS_ICC_AP1R2_EL1), access_gic_ap1r }, { SYS_DESC(SYS_ICC_AP0R2_EL1),
{ SYS_DESC(SYS_ICC_AP1R3_EL1), access_gic_ap1r }, .set_user = set_gic_ap0r, .get_user = get_gic_ap0r, },
{ SYS_DESC(SYS_ICC_BPR1_EL1), access_gic_bpr1 }, { SYS_DESC(SYS_ICC_AP0R3_EL1),
{ SYS_DESC(SYS_ICC_CTLR_EL1), access_gic_ctlr }, .set_user = set_gic_ap0r, .get_user = get_gic_ap0r, },
{ SYS_DESC(SYS_ICC_SRE_EL1), access_gic_sre }, { SYS_DESC(SYS_ICC_AP1R0_EL1),
{ SYS_DESC(SYS_ICC_IGRPEN0_EL1), access_gic_grpen0 }, .set_user = set_gic_ap1r, .get_user = get_gic_ap1r, },
{ SYS_DESC(SYS_ICC_IGRPEN1_EL1), access_gic_grpen1 }, { SYS_DESC(SYS_ICC_AP1R1_EL1),
.set_user = set_gic_ap1r, .get_user = get_gic_ap1r, },
{ SYS_DESC(SYS_ICC_AP1R2_EL1),
.set_user = set_gic_ap1r, .get_user = get_gic_ap1r, },
{ SYS_DESC(SYS_ICC_AP1R3_EL1),
.set_user = set_gic_ap1r, .get_user = get_gic_ap1r, },
{ SYS_DESC(SYS_ICC_BPR1_EL1),
.set_user = set_gic_bpr1, .get_user = get_gic_bpr1, },
{ SYS_DESC(SYS_ICC_CTLR_EL1),
.set_user = set_gic_ctlr, .get_user = get_gic_ctlr, },
{ SYS_DESC(SYS_ICC_SRE_EL1),
.set_user = set_gic_sre, .get_user = get_gic_sre, },
{ SYS_DESC(SYS_ICC_IGRPEN0_EL1),
.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, },
}; };
static u64 attr_to_id(u64 attr) static u64 attr_to_id(u64 attr)
...@@ -282,31 +358,15 @@ int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, ...@@ -282,31 +358,15 @@ int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu,
struct kvm_device_attr *attr, struct kvm_device_attr *attr,
bool is_write) bool is_write)
{ {
u64 __user *uaddr = (u64 __user *)(long)attr->addr; struct kvm_one_reg reg = {
struct sys_reg_params params; .id = attr_to_id(attr->attr),
const struct sys_reg_desc *r; .addr = attr->addr,
u64 sysreg; };
sysreg = attr_to_id(attr->attr); if (is_write)
return kvm_sys_reg_set_user(vcpu, &reg, gic_v3_icc_reg_descs,
if (is_write) { ARRAY_SIZE(gic_v3_icc_reg_descs));
if (get_user(params.regval, uaddr)) else
return -EFAULT; return kvm_sys_reg_get_user(vcpu, &reg, gic_v3_icc_reg_descs,
} ARRAY_SIZE(gic_v3_icc_reg_descs));
params.is_write = is_write;
r = find_reg_by_id(sysreg, &params, gic_v3_icc_reg_descs,
ARRAY_SIZE(gic_v3_icc_reg_descs));
if (!r)
return -ENXIO;
if (!r->access(vcpu, &params, r))
return -EINVAL;
if (!is_write) {
if (put_user(params.regval, uaddr))
return -EFAULT;
}
return 0;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment