Skip to content

Commit affa28e

Browse files
atishp04avpatel
authored andcommitted
RISC-V: KVM: Introduce ISA extension register
Currently, there is no provision for vmm (qemu-kvm or kvmtool) to query about multiple-letter ISA extensions. The config register is only used for base single letter ISA extensions. A new ISA extension register is added that will allow the vmm to query about any ISA extension one at a time. It is enabled for both single letter or multi-letter ISA extensions. The ISA extension register is useful to if the vmm requires to retrieve/set single extension while the config register should be used if all the base ISA extension required to retrieve or set. For any multi-letter ISA extensions, the new register interface must be used. Signed-off-by: Atish Patra <atishp@rivosinc.com> Signed-off-by: Anup Patel <anup@brainfault.org>
1 parent 92e4505 commit affa28e

2 files changed

Lines changed: 119 additions & 0 deletions

File tree

arch/riscv/include/uapi/asm/kvm.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,23 @@ struct kvm_riscv_timer {
8282
__u64 state;
8383
};
8484

85+
/*
86+
* ISA extension IDs specific to KVM. This is not the same as the host ISA
87+
* extension IDs as that is internal to the host and should not be exposed
88+
* to the guest. This should always be contiguous to keep the mapping simple
89+
* in KVM implementation.
90+
*/
91+
enum KVM_RISCV_ISA_EXT_ID {
92+
KVM_RISCV_ISA_EXT_A = 0,
93+
KVM_RISCV_ISA_EXT_C,
94+
KVM_RISCV_ISA_EXT_D,
95+
KVM_RISCV_ISA_EXT_F,
96+
KVM_RISCV_ISA_EXT_H,
97+
KVM_RISCV_ISA_EXT_I,
98+
KVM_RISCV_ISA_EXT_M,
99+
KVM_RISCV_ISA_EXT_MAX,
100+
};
101+
85102
/* Possible states for kvm_riscv_timer */
86103
#define KVM_RISCV_TIMER_STATE_OFF 0
87104
#define KVM_RISCV_TIMER_STATE_ON 1
@@ -123,6 +140,9 @@ struct kvm_riscv_timer {
123140
#define KVM_REG_RISCV_FP_D_REG(name) \
124141
(offsetof(struct __riscv_d_ext_state, name) / sizeof(__u64))
125142

143+
/* ISA Extension registers are mapped as type 7 */
144+
#define KVM_REG_RISCV_ISA_EXT (0x07 << KVM_REG_RISCV_TYPE_SHIFT)
145+
126146
#endif
127147

128148
#endif /* __LINUX_KVM_RISCV_H */

arch/riscv/kvm/vcpu.c

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,101 @@ static int kvm_riscv_vcpu_set_reg_csr(struct kvm_vcpu *vcpu,
374374
return 0;
375375
}
376376

377+
/* Mapping between KVM ISA Extension ID & Host ISA extension ID */
378+
static unsigned long kvm_isa_ext_arr[] = {
379+
RISCV_ISA_EXT_a,
380+
RISCV_ISA_EXT_c,
381+
RISCV_ISA_EXT_d,
382+
RISCV_ISA_EXT_f,
383+
RISCV_ISA_EXT_h,
384+
RISCV_ISA_EXT_i,
385+
RISCV_ISA_EXT_m,
386+
};
387+
388+
static int kvm_riscv_vcpu_get_reg_isa_ext(struct kvm_vcpu *vcpu,
389+
const struct kvm_one_reg *reg)
390+
{
391+
unsigned long __user *uaddr =
392+
(unsigned long __user *)(unsigned long)reg->addr;
393+
unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK |
394+
KVM_REG_SIZE_MASK |
395+
KVM_REG_RISCV_ISA_EXT);
396+
unsigned long reg_val = 0;
397+
unsigned long host_isa_ext;
398+
399+
if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long))
400+
return -EINVAL;
401+
402+
if (reg_num >= KVM_RISCV_ISA_EXT_MAX || reg_num >= ARRAY_SIZE(kvm_isa_ext_arr))
403+
return -EINVAL;
404+
405+
host_isa_ext = kvm_isa_ext_arr[reg_num];
406+
if (__riscv_isa_extension_available(&vcpu->arch.isa, host_isa_ext))
407+
reg_val = 1; /* Mark the given extension as available */
408+
409+
if (copy_to_user(uaddr, &reg_val, KVM_REG_SIZE(reg->id)))
410+
return -EFAULT;
411+
412+
return 0;
413+
}
414+
415+
static int kvm_riscv_vcpu_set_reg_isa_ext(struct kvm_vcpu *vcpu,
416+
const struct kvm_one_reg *reg)
417+
{
418+
unsigned long __user *uaddr =
419+
(unsigned long __user *)(unsigned long)reg->addr;
420+
unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK |
421+
KVM_REG_SIZE_MASK |
422+
KVM_REG_RISCV_ISA_EXT);
423+
unsigned long reg_val;
424+
unsigned long host_isa_ext;
425+
unsigned long host_isa_ext_mask;
426+
427+
if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long))
428+
return -EINVAL;
429+
430+
if (reg_num >= KVM_RISCV_ISA_EXT_MAX || reg_num >= ARRAY_SIZE(kvm_isa_ext_arr))
431+
return -EINVAL;
432+
433+
if (copy_from_user(&reg_val, uaddr, KVM_REG_SIZE(reg->id)))
434+
return -EFAULT;
435+
436+
host_isa_ext = kvm_isa_ext_arr[reg_num];
437+
if (!__riscv_isa_extension_available(NULL, host_isa_ext))
438+
return -EOPNOTSUPP;
439+
440+
if (host_isa_ext >= RISCV_ISA_EXT_BASE &&
441+
host_isa_ext < RISCV_ISA_EXT_MAX) {
442+
/*
443+
* Multi-letter ISA extension. Currently there is no provision
444+
* to enable/disable the multi-letter ISA extensions for guests.
445+
* Return success if the request is to enable any ISA extension
446+
* that is available in the hardware.
447+
* Return -EOPNOTSUPP otherwise.
448+
*/
449+
if (!reg_val)
450+
return -EOPNOTSUPP;
451+
else
452+
return 0;
453+
}
454+
455+
/* Single letter base ISA extension */
456+
if (!vcpu->arch.ran_atleast_once) {
457+
host_isa_ext_mask = BIT_MASK(host_isa_ext);
458+
if (!reg_val && (host_isa_ext_mask & KVM_RISCV_ISA_DISABLE_ALLOWED))
459+
vcpu->arch.isa &= ~host_isa_ext_mask;
460+
else
461+
vcpu->arch.isa |= host_isa_ext_mask;
462+
vcpu->arch.isa &= riscv_isa_extension_base(NULL);
463+
vcpu->arch.isa &= KVM_RISCV_ISA_ALLOWED;
464+
kvm_riscv_vcpu_fp_reset(vcpu);
465+
} else {
466+
return -EOPNOTSUPP;
467+
}
468+
469+
return 0;
470+
}
471+
377472
static int kvm_riscv_vcpu_set_reg(struct kvm_vcpu *vcpu,
378473
const struct kvm_one_reg *reg)
379474
{
@@ -391,6 +486,8 @@ static int kvm_riscv_vcpu_set_reg(struct kvm_vcpu *vcpu,
391486
else if ((reg->id & KVM_REG_RISCV_TYPE_MASK) == KVM_REG_RISCV_FP_D)
392487
return kvm_riscv_vcpu_set_reg_fp(vcpu, reg,
393488
KVM_REG_RISCV_FP_D);
489+
else if ((reg->id & KVM_REG_RISCV_TYPE_MASK) == KVM_REG_RISCV_ISA_EXT)
490+
return kvm_riscv_vcpu_set_reg_isa_ext(vcpu, reg);
394491

395492
return -EINVAL;
396493
}
@@ -412,6 +509,8 @@ static int kvm_riscv_vcpu_get_reg(struct kvm_vcpu *vcpu,
412509
else if ((reg->id & KVM_REG_RISCV_TYPE_MASK) == KVM_REG_RISCV_FP_D)
413510
return kvm_riscv_vcpu_get_reg_fp(vcpu, reg,
414511
KVM_REG_RISCV_FP_D);
512+
else if ((reg->id & KVM_REG_RISCV_TYPE_MASK) == KVM_REG_RISCV_ISA_EXT)
513+
return kvm_riscv_vcpu_get_reg_isa_ext(vcpu, reg);
415514

416515
return -EINVAL;
417516
}

0 commit comments

Comments
 (0)