static int vgic_v3_attr_regs_access()

in kvm/vgic/vgic-kvm-device.c [518:596]


static int vgic_v3_attr_regs_access(struct kvm_device *dev,
				    struct kvm_device_attr *attr,
				    u64 *reg, bool is_write)
{
	struct vgic_reg_attr reg_attr;
	gpa_t addr;
	struct kvm_vcpu *vcpu;
	int ret;
	u32 tmp32;

	ret = vgic_v3_parse_attr(dev, attr, &reg_attr);
	if (ret)
		return ret;

	vcpu = reg_attr.vcpu;
	addr = reg_attr.addr;

	mutex_lock(&dev->kvm->lock);

	if (unlikely(!vgic_initialized(dev->kvm))) {
		ret = -EBUSY;
		goto out;
	}

	if (!lock_all_vcpus(dev->kvm)) {
		ret = -EBUSY;
		goto out;
	}

	switch (attr->group) {
	case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
		if (is_write)
			tmp32 = *reg;

		ret = vgic_v3_dist_uaccess(vcpu, is_write, addr, &tmp32);
		if (!is_write)
			*reg = tmp32;
		break;
	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
		if (is_write)
			tmp32 = *reg;

		ret = vgic_v3_redist_uaccess(vcpu, is_write, addr, &tmp32);
		if (!is_write)
			*reg = tmp32;
		break;
	case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: {
		u64 regid;

		regid = (attr->attr & KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK);
		ret = vgic_v3_cpu_sysregs_uaccess(vcpu, is_write,
						  regid, reg);
		break;
	}
	case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
		unsigned int info, intid;

		info = (attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK) >>
			KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT;
		if (info == VGIC_LEVEL_INFO_LINE_LEVEL) {
			intid = attr->attr &
				KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK;
			ret = vgic_v3_line_level_info_uaccess(vcpu, is_write,
							      intid, reg);
		} else {
			ret = -EINVAL;
		}
		break;
	}
	default:
		ret = -EINVAL;
		break;
	}

	unlock_all_vcpus(dev->kvm);
out:
	mutex_unlock(&dev->kvm->lock);
	return ret;
}