+ *v = kvm_read_sw_gcsr(csr, id);
+
+ return 0;
+}
+
+int _kvm_setcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 val)
+{
+ struct loongarch_csrs *csr = vcpu->arch.csr;
+ int ret = 0, gintc;
+
+ if (get_gcsr_flag(id) & INVALID_GCSR)
+ return -EINVAL;
+
+ if (id == LOONGARCH_CSR_ESTAT) {
+ /* estat IP0~IP7 inject through guestexcept */
+ gintc = (val >> 2) & 0xff;
+ write_csr_gintc(gintc);
+ kvm_set_sw_gcsr(csr, LOONGARCH_CSR_GINTC, gintc);
+
+ gintc = val & ~(0xffUL << 2);
+ write_gcsr_estat(gintc);
+ kvm_set_sw_gcsr(csr, LOONGARCH_CSR_ESTAT, gintc);
+
+ return ret;
+ }
+
+ if (get_gcsr_flag(id) & HW_GCSR) {
+ set_hw_gcsr(id, val);
+ /* write sw gcsr to keep consistent with hardware */
+ kvm_write_sw_gcsr(csr, id, val);
+ } else
+ kvm_write_sw_gcsr(csr, id, val);
+
+ return ret;
+}
+
+static int _kvm_get_one_reg(struct kvm_vcpu *vcpu,
+ const struct kvm_one_reg *reg, s64 *v)
+{
+ int reg_idx, ret = 0;
+
+ if ((reg->id & KVM_REG_LOONGARCH_MASK) ==
KVM_REG_LOONGARCH_CSR) {
+ reg_idx = KVM_GET_IOC_CSRIDX(reg->id);
+ ret = _kvm_getcsr(vcpu, reg_idx, v);
+ } else if (reg->id == KVM_REG_LOONGARCH_COUNTER)
+ *v = drdtime() + vcpu->kvm->arch.time_offset;
+ else
+ ret = -EINVAL;
+
+ return ret;
+}
+
+static int _kvm_get_reg(struct kvm_vcpu *vcpu, const struct
kvm_one_reg *reg)
+{
+ int ret = -EINVAL;
+ s64 v;
+
+ if ((reg->id & KVM_REG_SIZE_MASK) != KVM_REG_SIZE_U64)
+ return ret;
+
+ if (_kvm_get_one_reg(vcpu, reg, &v))
+ return ret;
+
+ return put_user(v, (u64 __user *)(long)reg->addr);
+}
+
+static int _kvm_set_one_reg(struct kvm_vcpu *vcpu,
+ const struct kvm_one_reg *reg,
+ s64 v)
+{
+ int ret = 0;
+ unsigned long flags;
+ u64 val;
+ int reg_idx;
+
+ val = v;
+ if ((reg->id & KVM_REG_LOONGARCH_MASK) ==
KVM_REG_LOONGARCH_CSR) {
+ reg_idx = KVM_GET_IOC_CSRIDX(reg->id);
+ ret = _kvm_setcsr(vcpu, reg_idx, val);
+ } else if (reg->id == KVM_REG_LOONGARCH_COUNTER) {
+ local_irq_save(flags);
+ /*
+ * gftoffset is relative with board, not vcpu
+ * only set for the first time for smp system
+ */
+ if (vcpu->vcpu_id == 0)
+ vcpu->kvm->arch.time_offset = (signed
long)(v - drdtime());
+ write_csr_gcntc((ulong)vcpu->kvm->arch.time_offset);
+ local_irq_restore(flags);
+ } else if (reg->id == KVM_REG_LOONGARCH_VCPU_RESET) {
+ kvm_reset_timer(vcpu);
+ memset(&vcpu->arch.irq_pending, 0,
sizeof(vcpu->arch.irq_pending));
+ memset(&vcpu->arch.irq_clear, 0,
sizeof(vcpu->arch.irq_clear));
+ } else
+ ret = -EINVAL;
+
+ return ret;
+}
+
+static int _kvm_set_reg(struct kvm_vcpu *vcpu, const struct
kvm_one_reg *reg)
+{
+ s64 v;
+ int ret = -EINVAL;
+
+ if ((reg->id & KVM_REG_SIZE_MASK) != KVM_REG_SIZE_U64)
+ return ret;
+
+ if (get_user(v, (u64 __user *)(long)reg->addr))
+ return ret;
+
+ return _kvm_set_one_reg(vcpu, reg, v);
+}
+
+int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
+ struct kvm_sregs *sregs)
+{
+ return -ENOIOCTLCMD;
+}
+
+int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
+ struct kvm_sregs *sregs)
+{
+ return -ENOIOCTLCMD;
+}
+
+int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct
kvm_regs *regs)
+{
+ int i;
+
+ vcpu_load(vcpu);
+
+ for (i = 0; i < ARRAY_SIZE(vcpu->arch.gprs); i++)
+ regs->gpr[i] = vcpu->arch.gprs[i];
+
+ regs->pc = vcpu->arch.pc;
+
+ vcpu_put(vcpu);
+ return 0;
+}
+
+int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct
kvm_regs *regs)
+{
+ int i;
+
+ vcpu_load(vcpu);
+
+ for (i = 1; i < ARRAY_SIZE(vcpu->arch.gprs); i++)
+ vcpu->arch.gprs[i] = regs->gpr[i];
+ vcpu->arch.gprs[0] = 0; /* zero is special, and cannot be
set. */
+ vcpu->arch.pc = regs->pc;
+
+ vcpu_put(vcpu);
+ return 0;
+}
+
+long kvm_arch_vcpu_ioctl(struct file *filp,
+ unsigned int ioctl, unsigned long arg)
+{
+ struct kvm_vcpu *vcpu = filp->private_data;
+ void __user *argp = (void __user *)arg;
+ long r;
+
+ vcpu_load(vcpu);
+
+ switch (ioctl) {
+ case KVM_SET_ONE_REG:
+ case KVM_GET_ONE_REG: {
+ struct kvm_one_reg reg;
+
+ r = -EFAULT;
+ if (copy_from_user(®, argp, sizeof(reg)))
+ break;
+ if (ioctl == KVM_SET_ONE_REG)
+ r = _kvm_set_reg(vcpu, ®);
+ else
+ r = _kvm_get_reg(vcpu, ®);
+ break;
+ }
+ default:
+ r = -ENOIOCTLCMD;
+ break;
+ }
+
+ vcpu_put(vcpu);
+ return r;
+}
+
int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
{
return 0;
--
2.27.0