Re: [PATCH v3 14/29] LoongArch: KVM: Implement vcpu load and vcpu put operations

From: maobibo
Date: Mon Mar 06 2023 - 21:04:02 EST




在 2023/2/28 15:00, Tianrui Zhao 写道:
> Implement loongarch vcpu load and vcpu put operations, including
> load csr value into hardware and save csr value into vcpu structure.
>
> Signed-off-by: Tianrui Zhao <zhaotianrui@xxxxxxxxxxx>
> ---
> arch/loongarch/kvm/vcpu.c | 192 ++++++++++++++++++++++++++++++++++++++
> 1 file changed, 192 insertions(+)
>
> diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
> index 615f68d082f8..14c89208936f 100644
> --- a/arch/loongarch/kvm/vcpu.c
> +++ b/arch/loongarch/kvm/vcpu.c
> @@ -771,6 +771,198 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
> }
> }
>
> +static int _kvm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
> +{
> + struct kvm_context *context;
> + struct loongarch_csrs *csr = vcpu->arch.csr;
> + bool migrated, all;
> +
> + /*
> + * Have we migrated to a different CPU?
> + * If so, any old guest TLB state may be stale.
> + */
> + migrated = (vcpu->arch.last_sched_cpu != cpu);
> +
> + /*
> + * Was this the last VCPU to run on this CPU?
> + * If not, any old guest state from this VCPU will have been clobbered.
> + */
> + context = per_cpu_ptr(vcpu->kvm->arch.vmcs, cpu);
> + all = migrated || (context->last_vcpu != vcpu);
> + context->last_vcpu = vcpu;
> +
> + /*
> + * Restore timer state regardless
> + */
> + kvm_restore_timer(vcpu);
> +
> + /* Control guest page CCA attribute */
> + change_csr_gcfg(CSR_GCFG_MATC_MASK, CSR_GCFG_MATC_ROOT);
> + /* Don't bother restoring registers multiple times unless necessary */
> + if (!all)
> + return 0;
> +
> + write_csr_gcntc((ulong)vcpu->kvm->arch.time_offset);
> + /*
> + * Restore guest CSR registers
> + */
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_CRMD);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_PRMD);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_EUEN);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_MISC);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_ECFG);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_ERA);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_BADV);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_BADI);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_EENTRY);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBIDX);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBEHI);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBELO0);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBELO1);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_ASID);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_PGDL);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_PGDH);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_PWCTL0);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_PWCTL1);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_STLBPGSIZE);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_RVACFG);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_CPUID);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_KS0);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_KS1);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_KS2);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_KS3);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_KS4);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_KS5);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_KS6);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_KS7);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TMID);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_CNTC);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBRENTRY);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBRBADV);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBRERA);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBRSAVE);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBRELO0);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBRELO1);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBREHI);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBRPRMD);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_DMWIN0);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_DMWIN1);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_DMWIN2);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_DMWIN3);
> + kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_LLBCTL);
> +
> + /* restore Root.Guestexcept from unused Guest guestexcept register */
> + write_csr_gintc(csr->csrs[LOONGARCH_CSR_GINTC]);
> +
> + /*
> + * We should clear linked load bit to break interrupted atomics. This
> + * prevents a SC on the next VCPU from succeeding by matching a LL on
> + * the previous VCPU.
> + */
> + if (vcpu->kvm->created_vcpus > 1)
> + set_gcsr_llbctl(CSR_LLBCTL_WCLLB);
> +
> + return 0;
> +}
> +
> +void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
> +{
> + unsigned long flags;
> +
> + local_irq_save(flags);
> + vcpu->cpu = cpu;
> + if (vcpu->arch.last_sched_cpu != cpu) {
> + kvm_debug("[%d->%d]KVM VCPU[%d] switch\n",
> + vcpu->arch.last_sched_cpu, cpu, vcpu->vcpu_id);
> + /*
> + * Migrate the timer interrupt to the current CPU so that it
> + * always interrupts the guest and synchronously triggers a
> + * guest timer interrupt.
> + */
> + kvm_migrate_count(vcpu);
> + }
> +
> + /* restore guest state to registers */
> + _kvm_vcpu_load(vcpu, cpu);
> + local_irq_restore(flags);
> +}
> +
> +static int _kvm_vcpu_put(struct kvm_vcpu *vcpu, int cpu)
> +{
> + struct loongarch_csrs *csr = vcpu->arch.csr;
> +
> + kvm_lose_fpu(vcpu);
Hi Tianrui,

Can we add KVM_LARCH_CSR bit in vcpu->arch.aux_inuse similiar with
KVM_LARCH_FPU? It means that sw csr is consistent with hw csr registers.

And clear this bit when returning to guest, set this bit in this function
_kvm_vcpu_put. If it is true, we need not copy to sw csr from hw, and for
SET_ONE_REG function, both sw/hw csr register will be set.


Regards
Bibo, Mao

> +
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_CRMD);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_PRMD);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_EUEN);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_MISC);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_ECFG);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_ERA);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_BADV);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_BADI);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_EENTRY);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBIDX);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBEHI);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBELO0);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBELO1);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_ASID);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_PGDL);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_PGDH);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_PGD);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_PWCTL0);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_PWCTL1);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_STLBPGSIZE);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_RVACFG);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_CPUID);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_PRCFG1);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_PRCFG2);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_PRCFG3);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_KS0);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_KS1);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_KS2);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_KS3);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_KS4);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_KS5);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_KS6);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_KS7);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TMID);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_CNTC);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_LLBCTL);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBRENTRY);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBRBADV);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBRERA);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBRSAVE);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBRELO0);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBRELO1);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBREHI);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBRPRMD);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_DMWIN0);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_DMWIN1);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_DMWIN2);
> + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_DMWIN3);
> +
> + /* save Root.Guestexcept in unused Guest guestexcept register */
> + kvm_save_timer(vcpu);
> + csr->csrs[LOONGARCH_CSR_GINTC] = read_csr_gintc();
> + return 0;
> +}
> +
> +void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
> +{
> + unsigned long flags;
> + int cpu;
> +
> + local_irq_save(flags);
> + cpu = smp_processor_id();
> + vcpu->arch.last_sched_cpu = cpu;
> + vcpu->cpu = -1;
> +
> + /* save guest state in registers */
> + _kvm_vcpu_put(vcpu, cpu);
> + local_irq_restore(flags);
> +}
> +
> int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
> {
> int r = -EINTR;