RISC-V: KVM: Implement subtype for CSR ONE_REG interface
authorAnup Patel <apatel@ventanamicro.com>
Fri, 31 Mar 2023 14:26:56 +0000 (19:56 +0530)
committerAnup Patel <anup@brainfault.org>
Fri, 21 Apr 2023 12:15:51 +0000 (17:45 +0530)
To make the CSR ONE_REG interface extensible, we implement subtype
for the CSR ONE_REG IDs. The existing CSR ONE_REG IDs are treated
as subtype = 0 (aka General CSRs).

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Signed-off-by: Anup Patel <anup@brainfault.org>
arch/riscv/include/uapi/asm/kvm.h
arch/riscv/kvm/vcpu.c

index 47a7c3958229eff0955637377b72bdf74414eef4..182023dc9a51c4d7795b8ed2d7b4e4c933f2f8b2 100644 (file)
@@ -65,7 +65,7 @@ struct kvm_riscv_core {
 #define KVM_RISCV_MODE_S       1
 #define KVM_RISCV_MODE_U       0
 
-/* CSR registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG */
+/* General CSR registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG */
 struct kvm_riscv_csr {
        unsigned long sstatus;
        unsigned long sie;
@@ -152,6 +152,7 @@ enum KVM_RISCV_SBI_EXT_ID {
 
 /* Control and status registers are mapped as type 3 */
 #define KVM_REG_RISCV_CSR              (0x03 << KVM_REG_RISCV_TYPE_SHIFT)
+#define KVM_REG_RISCV_CSR_GENERAL      (0x0 << KVM_REG_RISCV_SUBTYPE_SHIFT)
 #define KVM_REG_RISCV_CSR_REG(name)    \
                (offsetof(struct kvm_riscv_csr, name) / sizeof(unsigned long))
 
index b46e9cc929389d6e159d379f7d6abbf614194e41..3394859c5f85f9cfc7d532bd00342b8879037cf8 100644 (file)
@@ -460,27 +460,72 @@ static int kvm_riscv_vcpu_set_reg_core(struct kvm_vcpu *vcpu,
        return 0;
 }
 
+static int kvm_riscv_vcpu_general_get_csr(struct kvm_vcpu *vcpu,
+                                         unsigned long reg_num,
+                                         unsigned long *out_val)
+{
+       struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
+
+       if (reg_num >= sizeof(struct kvm_riscv_csr) / sizeof(unsigned long))
+               return -EINVAL;
+
+       if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) {
+               kvm_riscv_vcpu_flush_interrupts(vcpu);
+               *out_val = (csr->hvip >> VSIP_TO_HVIP_SHIFT) & VSIP_VALID_MASK;
+       } else
+               *out_val = ((unsigned long *)csr)[reg_num];
+
+       return 0;
+}
+
+static inline int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu,
+                                                unsigned long reg_num,
+                                                unsigned long reg_val)
+{
+       struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
+
+       if (reg_num >= sizeof(struct kvm_riscv_csr) / sizeof(unsigned long))
+               return -EINVAL;
+
+       if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) {
+               reg_val &= VSIP_VALID_MASK;
+               reg_val <<= VSIP_TO_HVIP_SHIFT;
+       }
+
+       ((unsigned long *)csr)[reg_num] = reg_val;
+
+       if (reg_num == KVM_REG_RISCV_CSR_REG(sip))
+               WRITE_ONCE(vcpu->arch.irqs_pending_mask, 0);
+
+       return 0;
+}
+
 static int kvm_riscv_vcpu_get_reg_csr(struct kvm_vcpu *vcpu,
                                      const struct kvm_one_reg *reg)
 {
-       struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
+       int rc;
        unsigned long __user *uaddr =
                        (unsigned long __user *)(unsigned long)reg->addr;
        unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK |
                                            KVM_REG_SIZE_MASK |
                                            KVM_REG_RISCV_CSR);
-       unsigned long reg_val;
+       unsigned long reg_val, reg_subtype;
 
        if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long))
                return -EINVAL;
-       if (reg_num >= sizeof(struct kvm_riscv_csr) / sizeof(unsigned long))
-               return -EINVAL;
 
-       if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) {
-               kvm_riscv_vcpu_flush_interrupts(vcpu);
-               reg_val = (csr->hvip >> VSIP_TO_HVIP_SHIFT) & VSIP_VALID_MASK;
-       } else
-               reg_val = ((unsigned long *)csr)[reg_num];
+       reg_subtype = reg_num & KVM_REG_RISCV_SUBTYPE_MASK;
+       reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK;
+       switch (reg_subtype) {
+       case KVM_REG_RISCV_CSR_GENERAL:
+               rc = kvm_riscv_vcpu_general_get_csr(vcpu, reg_num, &reg_val);
+               break;
+       default:
+               rc = -EINVAL;
+               break;
+       }
+       if (rc)
+               return rc;
 
        if (copy_to_user(uaddr, &reg_val, KVM_REG_SIZE(reg->id)))
                return -EFAULT;
@@ -491,31 +536,32 @@ static int kvm_riscv_vcpu_get_reg_csr(struct kvm_vcpu *vcpu,
 static int kvm_riscv_vcpu_set_reg_csr(struct kvm_vcpu *vcpu,
                                      const struct kvm_one_reg *reg)
 {
-       struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
+       int rc;
        unsigned long __user *uaddr =
                        (unsigned long __user *)(unsigned long)reg->addr;
        unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK |
                                            KVM_REG_SIZE_MASK |
                                            KVM_REG_RISCV_CSR);
-       unsigned long reg_val;
+       unsigned long reg_val, reg_subtype;
 
        if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long))
                return -EINVAL;
-       if (reg_num >= sizeof(struct kvm_riscv_csr) / sizeof(unsigned long))
-               return -EINVAL;
 
        if (copy_from_user(&reg_val, uaddr, KVM_REG_SIZE(reg->id)))
                return -EFAULT;
 
-       if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) {
-               reg_val &= VSIP_VALID_MASK;
-               reg_val <<= VSIP_TO_HVIP_SHIFT;
+       reg_subtype = reg_num & KVM_REG_RISCV_SUBTYPE_MASK;
+       reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK;
+       switch (reg_subtype) {
+       case KVM_REG_RISCV_CSR_GENERAL:
+               rc = kvm_riscv_vcpu_general_set_csr(vcpu, reg_num, reg_val);
+               break;
+       default:
+               rc = -EINVAL;
+               break;
        }
-
-       ((unsigned long *)csr)[reg_num] = reg_val;
-
-       if (reg_num == KVM_REG_RISCV_CSR_REG(sip))
-               WRITE_ONCE(vcpu->arch.irqs_pending_mask, 0);
+       if (rc)
+               return rc;
 
        return 0;
 }