KVM: arm64: vgic-v3: Push user access into vgic_v3_cpu_sysregs_uaccess()

In order to start making the vgic sysreg access from userspace
similar to all the other sysregs, push the userspace memory
access one level down into vgic_v3_cpu_sysregs_uaccess().

The next step will be to rely on the sysreg infrastructure
to perform this task.

Reviewed-by: Reiji Watanabe <reijiw@google.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
This commit is contained in:
Marc Zyngier 2022-07-04 08:07:44 +01:00
parent b61fc0857a
commit db25081e14
3 changed files with 24 additions and 35 deletions

View file

@ -278,15 +278,21 @@ int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *
return -ENXIO; return -ENXIO;
} }
int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write, u64 id, int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu,
u64 *reg) struct kvm_device_attr *attr,
bool is_write)
{ {
u64 __user *uaddr = (u64 __user *)(long)attr->addr;
struct sys_reg_params params; struct sys_reg_params params;
const struct sys_reg_desc *r; const struct sys_reg_desc *r;
u64 sysreg = (id & KVM_DEV_ARM_VGIC_SYSREG_MASK) | KVM_REG_SIZE_U64; u64 sysreg;
if (is_write) sysreg = attr_to_id(attr->attr);
params.regval = *reg;
if (is_write) {
if (get_user(params.regval, uaddr))
return -EFAULT;
}
params.is_write = is_write; params.is_write = is_write;
r = find_reg_by_id(sysreg, &params, gic_v3_icc_reg_descs, r = find_reg_by_id(sysreg, &params, gic_v3_icc_reg_descs,
@ -297,8 +303,10 @@ int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write, u64 id,
if (!r->access(vcpu, &params, r)) if (!r->access(vcpu, &params, r))
return -EINVAL; return -EINVAL;
if (!is_write) if (!is_write) {
*reg = params.regval; if (put_user(params.regval, uaddr))
return -EFAULT;
}
return 0; return 0;
} }

View file

@ -512,7 +512,7 @@ int vgic_v3_parse_attr(struct kvm_device *dev, struct kvm_device_attr *attr,
* *
* @dev: kvm device handle * @dev: kvm device handle
* @attr: kvm device attribute * @attr: kvm device attribute
* @reg: address the value is read or written * @reg: address the value is read or written, NULL for sysregs
* @is_write: true if userspace is writing a register * @is_write: true if userspace is writing a register
*/ */
static int vgic_v3_attr_regs_access(struct kvm_device *dev, static int vgic_v3_attr_regs_access(struct kvm_device *dev,
@ -561,14 +561,9 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
if (!is_write) if (!is_write)
*reg = tmp32; *reg = tmp32;
break; break;
case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: { case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS:
u64 regid; ret = vgic_v3_cpu_sysregs_uaccess(vcpu, attr, is_write);
regid = (attr->attr & KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK);
ret = vgic_v3_cpu_sysregs_uaccess(vcpu, is_write,
regid, reg);
break; break;
}
case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: { case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
unsigned int info, intid; unsigned int info, intid;
@ -617,15 +612,8 @@ static int vgic_v3_set_attr(struct kvm_device *dev,
reg = tmp32; reg = tmp32;
return vgic_v3_attr_regs_access(dev, attr, &reg, true); return vgic_v3_attr_regs_access(dev, attr, &reg, true);
} }
case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: { case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS:
u64 __user *uaddr = (u64 __user *)(long)attr->addr; return vgic_v3_attr_regs_access(dev, attr, NULL, true);
u64 reg;
if (get_user(reg, uaddr))
return -EFAULT;
return vgic_v3_attr_regs_access(dev, attr, &reg, true);
}
case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: { case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
u32 __user *uaddr = (u32 __user *)(long)attr->addr; u32 __user *uaddr = (u32 __user *)(long)attr->addr;
u64 reg; u64 reg;
@ -681,15 +669,8 @@ static int vgic_v3_get_attr(struct kvm_device *dev,
tmp32 = reg; tmp32 = reg;
return put_user(tmp32, uaddr); return put_user(tmp32, uaddr);
} }
case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: { case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS:
u64 __user *uaddr = (u64 __user *)(long)attr->addr; return vgic_v3_attr_regs_access(dev, attr, NULL, false);
u64 reg;
ret = vgic_v3_attr_regs_access(dev, attr, &reg, false);
if (ret)
return ret;
return put_user(reg, uaddr);
}
case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: { case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
u32 __user *uaddr = (u32 __user *)(long)attr->addr; u32 __user *uaddr = (u32 __user *)(long)attr->addr;
u64 reg; u64 reg;

View file

@ -245,8 +245,8 @@ int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
int offset, u32 *val); int offset, u32 *val);
int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write, int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
int offset, u32 *val); int offset, u32 *val);
int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write, int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu,
u64 id, u64 *val); struct kvm_device_attr *attr, bool is_write);
int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr); int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr);
int vgic_v3_line_level_info_uaccess(struct kvm_vcpu *vcpu, bool is_write, int vgic_v3_line_level_info_uaccess(struct kvm_vcpu *vcpu, bool is_write,
u32 intid, u64 *val); u32 intid, u64 *val);