On Mon, Jul 13, 2026 at 6:34 AM Inochi Amaoto <[email protected]> wrote: > > Add ssp context save/restore for guest VCPUs and also add it to the > ONE_REG interface to allow its access from user space. > > Signed-off-by: Inochi Amaoto <[email protected]>
LGTM. Reviewed-by: Anup Patel <[email protected]> Thanks, Anup > --- > arch/riscv/include/asm/kvm_host.h | 7 ++++ > arch/riscv/include/uapi/asm/kvm.h | 8 ++++ > arch/riscv/kvm/vcpu.c | 7 ++++ > arch/riscv/kvm/vcpu_onereg.c | 68 ++++++++++++++++++++++++++++++- > 4 files changed, 88 insertions(+), 2 deletions(-) > > diff --git a/arch/riscv/include/asm/kvm_host.h > b/arch/riscv/include/asm/kvm_host.h > index 60017ceec9d2..e5ed3b0e5a55 100644 > --- a/arch/riscv/include/asm/kvm_host.h > +++ b/arch/riscv/include/asm/kvm_host.h > @@ -163,6 +163,10 @@ struct kvm_vcpu_smstateen_csr { > unsigned long sstateen0; > }; > > +struct kvm_vcpu_zicfiss_csr { > + unsigned long ssp; > +}; > + > struct kvm_vcpu_reset_state { > spinlock_t lock; > unsigned long pc; > @@ -203,6 +207,9 @@ struct kvm_vcpu_arch { > /* CPU Smstateen CSR context of Guest VCPU */ > struct kvm_vcpu_smstateen_csr smstateen_csr; > > + /* CPU Zicfiss CSR context of Guest VCPU */ > + struct kvm_vcpu_zicfiss_csr zicfiss_csr; > + > /* CPU reset state of Guest VCPU */ > struct kvm_vcpu_reset_state reset_state; > > diff --git a/arch/riscv/include/uapi/asm/kvm.h > b/arch/riscv/include/uapi/asm/kvm.h > index a27de850fa4c..fd4c81697617 100644 > --- a/arch/riscv/include/uapi/asm/kvm.h > +++ b/arch/riscv/include/uapi/asm/kvm.h > @@ -102,6 +102,11 @@ struct kvm_riscv_smstateen_csr { > unsigned long sstateen0; > }; > > +/* Zicfiss CSR for KVM_GET_ONE_REG and KVM_SET_ONE_REG */ > +struct kvm_riscv_zicfiss_csr { > + unsigned long ssp; > +}; > + > /* TIMER registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG */ > struct kvm_riscv_timer { > __u64 frequency; > @@ -266,12 +271,15 @@ struct kvm_riscv_sbi_fwft { > #define KVM_REG_RISCV_CSR_GENERAL (0x0 << KVM_REG_RISCV_SUBTYPE_SHIFT) > #define KVM_REG_RISCV_CSR_AIA (0x1 << KVM_REG_RISCV_SUBTYPE_SHIFT) > #define KVM_REG_RISCV_CSR_SMSTATEEN (0x2 << KVM_REG_RISCV_SUBTYPE_SHIFT) > +#define KVM_REG_RISCV_CSR_ZICFISS (0x3 << KVM_REG_RISCV_SUBTYPE_SHIFT) > #define KVM_REG_RISCV_CSR_REG(name) \ > (offsetof(struct kvm_riscv_csr, name) / sizeof(unsigned long)) > #define KVM_REG_RISCV_CSR_AIA_REG(name) \ > (offsetof(struct kvm_riscv_aia_csr, name) / sizeof(unsigned long)) > #define KVM_REG_RISCV_CSR_SMSTATEEN_REG(name) \ > (offsetof(struct kvm_riscv_smstateen_csr, name) / sizeof(unsigned > long)) > +#define KVM_REG_RISCV_CSR_ZICFISS_REG(name) \ > + (offsetof(struct kvm_riscv_zicfiss_csr, name) / sizeof(unsigned long)) > > /* Timer registers are mapped as type 4 */ > #define KVM_REG_RISCV_TIMER (0x04 << KVM_REG_RISCV_TYPE_SHIFT) > diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c > index cf6e231e76e2..acdb12fcdb69 100644 > --- a/arch/riscv/kvm/vcpu.c > +++ b/arch/riscv/kvm/vcpu.c > @@ -63,6 +63,7 @@ static void kvm_riscv_vcpu_context_reset(struct kvm_vcpu > *vcpu, > memset(cntx, 0, sizeof(*cntx)); > memset(csr, 0, sizeof(*csr)); > memset(&vcpu->arch.smstateen_csr, 0, > sizeof(vcpu->arch.smstateen_csr)); > + memset(&vcpu->arch.zicfiss_csr, 0, sizeof(vcpu->arch.zicfiss_csr)); > > /* Restore datap as it's not a part of the guest context. */ > cntx->vector.datap = vector_datap; > @@ -720,6 +721,7 @@ static void kvm_riscv_update_hvip(struct kvm_vcpu *vcpu) > > static __always_inline void kvm_riscv_vcpu_swap_in_guest_state(struct > kvm_vcpu *vcpu) > { > + struct kvm_vcpu_zicfiss_csr *zicficsr = &vcpu->arch.zicfiss_csr; > struct kvm_vcpu_smstateen_csr *smcsr = &vcpu->arch.smstateen_csr; > struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; > > @@ -727,10 +729,13 @@ static __always_inline void > kvm_riscv_vcpu_swap_in_guest_state(struct kvm_vcpu * > vcpu->arch.host_senvcfg = csr_swap(CSR_SENVCFG, csr->senvcfg); > if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN)) > vcpu->arch.host_sstateen0 = csr_swap(CSR_SSTATEEN0, > smcsr->sstateen0); > + if (riscv_has_extension_unlikely(RISCV_ISA_EXT_ZICFISS)) > + csr_write(CSR_SSP, zicficsr->ssp); > } > > static __always_inline void kvm_riscv_vcpu_swap_in_host_state(struct > kvm_vcpu *vcpu) > { > + struct kvm_vcpu_zicfiss_csr *zicficsr = &vcpu->arch.zicfiss_csr; > struct kvm_vcpu_smstateen_csr *smcsr = &vcpu->arch.smstateen_csr; > struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; > > @@ -738,6 +743,8 @@ static __always_inline void > kvm_riscv_vcpu_swap_in_host_state(struct kvm_vcpu *v > csr->senvcfg = csr_swap(CSR_SENVCFG, vcpu->arch.host_senvcfg); > if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN)) > smcsr->sstateen0 = csr_swap(CSR_SSTATEEN0, > vcpu->arch.host_sstateen0); > + if (riscv_has_extension_unlikely(RISCV_ISA_EXT_ZICFISS)) > + zicficsr->ssp = csr_swap(CSR_SSP, 0); > } > > /* > diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c > index bb920e8923c9..dd9519438546 100644 > --- a/arch/riscv/kvm/vcpu_onereg.c > +++ b/arch/riscv/kvm/vcpu_onereg.c > @@ -355,6 +355,44 @@ static int kvm_riscv_vcpu_smstateen_get_csr(struct > kvm_vcpu *vcpu, > return 0; > } > > +static inline int kvm_riscv_vcpu_zicfiss_set_csr(struct kvm_vcpu *vcpu, > + unsigned long reg_num, > + unsigned long reg_val) > +{ > + struct kvm_vcpu_zicfiss_csr *csr = &vcpu->arch.zicfiss_csr; > + unsigned long regs_max = sizeof(struct kvm_vcpu_zicfiss_csr) / > + sizeof(unsigned long); > + > + if (!riscv_isa_extension_available(vcpu->arch.isa, ZICFISS)) > + return -ENOENT; > + if (reg_num >= regs_max) > + return -ENOENT; > + > + reg_num = array_index_nospec(reg_num, regs_max); > + > + ((unsigned long *)csr)[reg_num] = reg_val; > + return 0; > +} > + > +static int kvm_riscv_vcpu_zicfiss_get_csr(struct kvm_vcpu *vcpu, > + unsigned long reg_num, > + unsigned long *out_val) > +{ > + struct kvm_vcpu_zicfiss_csr *csr = &vcpu->arch.zicfiss_csr; > + unsigned long regs_max = sizeof(struct kvm_vcpu_zicfiss_csr) / > + sizeof(unsigned long); > + > + if (!riscv_isa_extension_available(vcpu->arch.isa, ZICFISS)) > + return -ENOENT; > + if (reg_num >= regs_max) > + return -ENOENT; > + > + reg_num = array_index_nospec(reg_num, regs_max); > + > + *out_val = ((unsigned long *)csr)[reg_num]; > + return 0; > +} > + > static int kvm_riscv_vcpu_get_reg_csr(struct kvm_vcpu *vcpu, > const struct kvm_one_reg *reg) > { > @@ -381,6 +419,9 @@ static int kvm_riscv_vcpu_get_reg_csr(struct kvm_vcpu > *vcpu, > case KVM_REG_RISCV_CSR_SMSTATEEN: > rc = kvm_riscv_vcpu_smstateen_get_csr(vcpu, reg_num, > ®_val); > break; > + case KVM_REG_RISCV_CSR_ZICFISS: > + rc = kvm_riscv_vcpu_zicfiss_get_csr(vcpu, reg_num, ®_val); > + break; > default: > rc = -ENOENT; > break; > @@ -423,6 +464,9 @@ static int kvm_riscv_vcpu_set_reg_csr(struct kvm_vcpu > *vcpu, > case KVM_REG_RISCV_CSR_SMSTATEEN: > rc = kvm_riscv_vcpu_smstateen_set_csr(vcpu, reg_num, reg_val); > break; > + case KVM_REG_RISCV_CSR_ZICFISS: > + rc = kvm_riscv_vcpu_zicfiss_set_csr(vcpu, reg_num, reg_val); > + break; > default: > rc = -ENOENT; > break; > @@ -680,6 +724,8 @@ static inline unsigned long num_csr_regs(const struct > kvm_vcpu *vcpu) > n += sizeof(struct kvm_riscv_aia_csr) / sizeof(unsigned long); > if (riscv_isa_extension_available(vcpu->arch.isa, SMSTATEEN)) > n += sizeof(struct kvm_riscv_smstateen_csr) / sizeof(unsigned > long); > + if (riscv_isa_extension_available(vcpu->arch.isa, ZICFISS)) > + n += sizeof(struct kvm_riscv_zicfiss_csr) / sizeof(unsigned > long); > > return n; > } > @@ -688,7 +734,7 @@ static int copy_csr_reg_indices(const struct kvm_vcpu > *vcpu, > u64 __user *uindices) > { > int n1 = sizeof(struct kvm_riscv_csr) / sizeof(unsigned long); > - int n2 = 0, n3 = 0; > + int n2 = 0, n3 = 0, n4 = 0; > > /* copy general csr regs */ > for (int i = 0; i < n1; i++) { > @@ -740,7 +786,25 @@ static int copy_csr_reg_indices(const struct kvm_vcpu > *vcpu, > } > } > > - return n1 + n2 + n3; > + /* copy Zicfiss csr regs */ > + if (riscv_isa_extension_available(vcpu->arch.isa, ZICFISS)) { > + n4 = sizeof(struct kvm_riscv_zicfiss_csr) / sizeof(unsigned > long); > + > + for (int i = 0; i < n4; i++) { > + u64 size = IS_ENABLED(CONFIG_32BIT) ? > + KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64; > + u64 reg = KVM_REG_RISCV | size | KVM_REG_RISCV_CSR | > + KVM_REG_RISCV_CSR_ZICFISS | i; > + > + if (uindices) { > + if (put_user(reg, uindices)) > + return -EFAULT; > + uindices++; > + } > + } > + } > + > + return n1 + n2 + n3 + n4; > } > > static inline unsigned long num_timer_regs(void) > -- > 2.55.0 >

