int kvm_riscv_vcpu_set_reg_timer()

in kvm/vcpu_timer.c [131:173]


int kvm_riscv_vcpu_set_reg_timer(struct kvm_vcpu *vcpu,
				 const struct kvm_one_reg *reg)
{
	struct kvm_vcpu_timer *t = &vcpu->arch.timer;
	struct kvm_guest_timer *gt = &vcpu->kvm->arch.timer;
	u64 __user *uaddr = (u64 __user *)(unsigned long)reg->addr;
	unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK |
					    KVM_REG_SIZE_MASK |
					    KVM_REG_RISCV_TIMER);
	u64 reg_val;
	int ret = 0;

	if (KVM_REG_SIZE(reg->id) != sizeof(u64))
		return -EINVAL;
	if (reg_num >= sizeof(struct kvm_riscv_timer) / sizeof(u64))
		return -EINVAL;

	if (copy_from_user(&reg_val, uaddr, KVM_REG_SIZE(reg->id)))
		return -EFAULT;

	switch (reg_num) {
	case KVM_REG_RISCV_TIMER_REG(frequency):
		ret = -EOPNOTSUPP;
		break;
	case KVM_REG_RISCV_TIMER_REG(time):
		gt->time_delta = reg_val - get_cycles64();
		break;
	case KVM_REG_RISCV_TIMER_REG(compare):
		t->next_cycles = reg_val;
		break;
	case KVM_REG_RISCV_TIMER_REG(state):
		if (reg_val == KVM_RISCV_TIMER_STATE_ON)
			ret = kvm_riscv_vcpu_timer_next_event(vcpu, reg_val);
		else
			ret = kvm_riscv_vcpu_timer_cancel(t);
		break;
	default:
		ret = -EINVAL;
		break;
	}

	return ret;
}