Message ID | 20231228084051.3235354-5-zhaotianrui@loongson.cn |
---|---|
State | New |
Headers | show |
Series | Add loongarch kvm accel support | expand |
在 2023/12/28 下午4:40, Tianrui Zhao 写道: > Implement kvm_arch_get/set_registers interfaces, many regs > can be get/set in the function, such as core regs, csr regs, > fpu regs, mp state, etc. > > Signed-off-by: Tianrui Zhao <zhaotianrui@loongson.cn> > Signed-off-by: xianglai li <lixianglai@loongson.cn> > --- > meson.build | 1 + > target/loongarch/cpu.c | 3 + > target/loongarch/cpu.h | 1 + > target/loongarch/fpu_helper.c | 2 + > target/loongarch/internals.h | 5 +- > target/loongarch/kvm.c | 580 +++++++++++++++++++++++++++++++++- > target/loongarch/trace-events | 11 + > target/loongarch/trace.h | 1 + > 8 files changed, 601 insertions(+), 3 deletions(-) > create mode 100644 target/loongarch/trace-events > create mode 100644 target/loongarch/trace.h Reviewed-by: Song Gao <gaosong@loongson.cn> Thanks. Song Gao > diff --git a/meson.build b/meson.build > index 6c77d9687d..445f2b7c2b 100644 > --- a/meson.build > +++ b/meson.build > @@ -3358,6 +3358,7 @@ if have_system or have_user > 'target/hppa', > 'target/i386', > 'target/i386/kvm', > + 'target/loongarch', > 'target/mips/tcg', > 'target/nios2', > 'target/ppc', > diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c > index 4432a0081d..83899c673f 100644 > --- a/target/loongarch/cpu.c > +++ b/target/loongarch/cpu.c > @@ -555,6 +555,9 @@ static void loongarch_cpu_reset_hold(Object *obj) > #ifndef CONFIG_USER_ONLY > env->pc = 0x1c000000; > memset(env->tlb, 0, sizeof(env->tlb)); > + if (kvm_enabled()) { > + kvm_arch_reset_vcpu(env); > + } > #endif > > restore_fp_status(env); > diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h > index f6d5ef0852..f4a89bd626 100644 > --- a/target/loongarch/cpu.h > +++ b/target/loongarch/cpu.h > @@ -360,6 +360,7 @@ typedef struct CPUArchState { > MemoryRegion iocsr_mem; > bool load_elf; > uint64_t elf_address; > + uint32_t mp_state; > /* Store ipistate to access from this struct */ > DeviceState *ipistate; > #endif > diff --git a/target/loongarch/fpu_helper.c b/target/loongarch/fpu_helper.c > index f6753c5875..1b71ea46d3 100644 > --- a/target/loongarch/fpu_helper.c > +++ b/target/loongarch/fpu_helper.c > @@ -9,7 +9,9 @@ > #include "cpu.h" > #include "exec/helper-proto.h" > #include "exec/exec-all.h" > +#ifdef CONFIG_TCG > #include "exec/cpu_ldst.h" > +#endif > #include "fpu/softfloat.h" > #include "internals.h" > > diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h > index c492863cc5..0beb034748 100644 > --- a/target/loongarch/internals.h > +++ b/target/loongarch/internals.h > @@ -31,8 +31,10 @@ void G_NORETURN do_raise_exception(CPULoongArchState *env, > > const char *loongarch_exception_name(int32_t exception); > > +#ifdef CONFIG_TCG > int ieee_ex_to_loongarch(int xcpt); > void restore_fp_status(CPULoongArchState *env); > +#endif > > #ifndef CONFIG_USER_ONLY > extern const VMStateDescription vmstate_loongarch_cpu; > @@ -44,12 +46,13 @@ uint64_t cpu_loongarch_get_constant_timer_counter(LoongArchCPU *cpu); > uint64_t cpu_loongarch_get_constant_timer_ticks(LoongArchCPU *cpu); > void cpu_loongarch_store_constant_timer_config(LoongArchCPU *cpu, > uint64_t value); > - > +#ifdef CONFIG_TCG > bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size, > MMUAccessType access_type, int mmu_idx, > bool probe, uintptr_t retaddr); > > hwaddr loongarch_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); > +#endif > #endif /* !CONFIG_USER_ONLY */ > > uint64_t read_fcc(CPULoongArchState *env); > diff --git a/target/loongarch/kvm.c b/target/loongarch/kvm.c > index 0d67322fd9..e7c9ef830c 100644 > --- a/target/loongarch/kvm.c > +++ b/target/loongarch/kvm.c > @@ -26,19 +26,595 @@ > #include "sysemu/runstate.h" > #include "cpu-csr.h" > #include "kvm_loongarch.h" > +#include "trace.h" > > static bool cap_has_mp_state; > const KVMCapabilityInfo kvm_arch_required_capabilities[] = { > KVM_CAP_LAST_INFO > }; > > +static int kvm_loongarch_get_regs_core(CPUState *cs) > +{ > + int ret = 0; > + int i; > + struct kvm_regs regs; > + LoongArchCPU *cpu = LOONGARCH_CPU(cs); > + CPULoongArchState *env = &cpu->env; > + > + /* Get the current register set as KVM seems it */ > + ret = kvm_vcpu_ioctl(cs, KVM_GET_REGS, ®s); > + if (ret < 0) { > + trace_kvm_failed_get_regs_core(strerror(errno)); > + return ret; > + } > + /* gpr[0] value is always 0 */ > + env->gpr[0] = 0; > + for (i = 1; i < 32; i++) { > + env->gpr[i] = regs.gpr[i]; > + } > + > + env->pc = regs.pc; > + return ret; > +} > + > +static int kvm_loongarch_put_regs_core(CPUState *cs) > +{ > + int ret = 0; > + int i; > + struct kvm_regs regs; > + LoongArchCPU *cpu = LOONGARCH_CPU(cs); > + CPULoongArchState *env = &cpu->env; > + > + /* Set the registers based on QEMU's view of things */ > + for (i = 0; i < 32; i++) { > + regs.gpr[i] = env->gpr[i]; > + } > + > + regs.pc = env->pc; > + ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, ®s); > + if (ret < 0) { > + trace_kvm_failed_put_regs_core(strerror(errno)); > + } > + > + return ret; > +} > + > +static int kvm_loongarch_get_csr(CPUState *cs) > +{ > + int ret = 0; > + LoongArchCPU *cpu = LOONGARCH_CPU(cs); > + CPULoongArchState *env = &cpu->env; > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CRMD), > + &env->CSR_CRMD); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRMD), > + &env->CSR_PRMD); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_EUEN), > + &env->CSR_EUEN); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_MISC), > + &env->CSR_MISC); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ECFG), > + &env->CSR_ECFG); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ESTAT), > + &env->CSR_ESTAT); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ERA), > + &env->CSR_ERA); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_BADV), > + &env->CSR_BADV); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_BADI), > + &env->CSR_BADI); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_EENTRY), > + &env->CSR_EENTRY); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBIDX), > + &env->CSR_TLBIDX); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBEHI), > + &env->CSR_TLBEHI); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBELO0), > + &env->CSR_TLBELO0); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBELO1), > + &env->CSR_TLBELO1); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ASID), > + &env->CSR_ASID); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGDL), > + &env->CSR_PGDL); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGDH), > + &env->CSR_PGDH); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGD), > + &env->CSR_PGD); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PWCL), > + &env->CSR_PWCL); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PWCH), > + &env->CSR_PWCH); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_STLBPS), > + &env->CSR_STLBPS); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_RVACFG), > + &env->CSR_RVACFG); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CPUID), > + &env->CSR_CPUID); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG1), > + &env->CSR_PRCFG1); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG2), > + &env->CSR_PRCFG2); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG3), > + &env->CSR_PRCFG3); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(0)), > + &env->CSR_SAVE[0]); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(1)), > + &env->CSR_SAVE[1]); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(2)), > + &env->CSR_SAVE[2]); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(3)), > + &env->CSR_SAVE[3]); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(4)), > + &env->CSR_SAVE[4]); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(5)), > + &env->CSR_SAVE[5]); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(6)), > + &env->CSR_SAVE[6]); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(7)), > + &env->CSR_SAVE[7]); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TID), > + &env->CSR_TID); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CNTC), > + &env->CSR_CNTC); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TICLR), > + &env->CSR_TICLR); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_LLBCTL), > + &env->CSR_LLBCTL); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_IMPCTL1), > + &env->CSR_IMPCTL1); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_IMPCTL2), > + &env->CSR_IMPCTL2); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRENTRY), > + &env->CSR_TLBRENTRY); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRBADV), > + &env->CSR_TLBRBADV); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRERA), > + &env->CSR_TLBRERA); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRSAVE), > + &env->CSR_TLBRSAVE); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRELO0), > + &env->CSR_TLBRELO0); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRELO1), > + &env->CSR_TLBRELO1); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBREHI), > + &env->CSR_TLBREHI); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRPRMD), > + &env->CSR_TLBRPRMD); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(0)), > + &env->CSR_DMW[0]); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(1)), > + &env->CSR_DMW[1]); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(2)), > + &env->CSR_DMW[2]); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(3)), > + &env->CSR_DMW[3]); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TVAL), > + &env->CSR_TVAL); > + > + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TCFG), > + &env->CSR_TCFG); > + > + return ret; > +} > + > +static int kvm_loongarch_put_csr(CPUState *cs) > +{ > + int ret = 0; > + LoongArchCPU *cpu = LOONGARCH_CPU(cs); > + CPULoongArchState *env = &cpu->env; > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CRMD), > + &env->CSR_CRMD); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRMD), > + &env->CSR_PRMD); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_EUEN), > + &env->CSR_EUEN); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_MISC), > + &env->CSR_MISC); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ECFG), > + &env->CSR_ECFG); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ESTAT), > + &env->CSR_ESTAT); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ERA), > + &env->CSR_ERA); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_BADV), > + &env->CSR_BADV); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_BADI), > + &env->CSR_BADI); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_EENTRY), > + &env->CSR_EENTRY); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBIDX), > + &env->CSR_TLBIDX); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBEHI), > + &env->CSR_TLBEHI); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBELO0), > + &env->CSR_TLBELO0); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBELO1), > + &env->CSR_TLBELO1); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ASID), > + &env->CSR_ASID); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGDL), > + &env->CSR_PGDL); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGDH), > + &env->CSR_PGDH); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGD), > + &env->CSR_PGD); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PWCL), > + &env->CSR_PWCL); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PWCH), > + &env->CSR_PWCH); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_STLBPS), > + &env->CSR_STLBPS); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_RVACFG), > + &env->CSR_RVACFG); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CPUID), > + &env->CSR_CPUID); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG1), > + &env->CSR_PRCFG1); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG2), > + &env->CSR_PRCFG2); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG3), > + &env->CSR_PRCFG3); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(0)), > + &env->CSR_SAVE[0]); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(1)), > + &env->CSR_SAVE[1]); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(2)), > + &env->CSR_SAVE[2]); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(3)), > + &env->CSR_SAVE[3]); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(4)), > + &env->CSR_SAVE[4]); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(5)), > + &env->CSR_SAVE[5]); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(6)), > + &env->CSR_SAVE[6]); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(7)), > + &env->CSR_SAVE[7]); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TID), > + &env->CSR_TID); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CNTC), > + &env->CSR_CNTC); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TICLR), > + &env->CSR_TICLR); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_LLBCTL), > + &env->CSR_LLBCTL); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_IMPCTL1), > + &env->CSR_IMPCTL1); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_IMPCTL2), > + &env->CSR_IMPCTL2); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRENTRY), > + &env->CSR_TLBRENTRY); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRBADV), > + &env->CSR_TLBRBADV); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRERA), > + &env->CSR_TLBRERA); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRSAVE), > + &env->CSR_TLBRSAVE); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRELO0), > + &env->CSR_TLBRELO0); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRELO1), > + &env->CSR_TLBRELO1); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBREHI), > + &env->CSR_TLBREHI); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRPRMD), > + &env->CSR_TLBRPRMD); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(0)), > + &env->CSR_DMW[0]); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(1)), > + &env->CSR_DMW[1]); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(2)), > + &env->CSR_DMW[2]); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(3)), > + &env->CSR_DMW[3]); > + /* > + * timer cfg must be put at last since it is used to enable > + * guest timer > + */ > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TVAL), > + &env->CSR_TVAL); > + > + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TCFG), > + &env->CSR_TCFG); > + return ret; > +} > + > +static int kvm_loongarch_get_regs_fp(CPUState *cs) > +{ > + int ret, i; > + struct kvm_fpu fpu; > + > + LoongArchCPU *cpu = LOONGARCH_CPU(cs); > + CPULoongArchState *env = &cpu->env; > + > + ret = kvm_vcpu_ioctl(cs, KVM_GET_FPU, &fpu); > + if (ret < 0) { > + trace_kvm_failed_get_fpu(strerror(errno)); > + return ret; > + } > + > + env->fcsr0 = fpu.fcsr; > + for (i = 0; i < 32; i++) { > + env->fpr[i].vreg.UD[0] = fpu.fpr[i].val64[0]; > + } > + for (i = 0; i < 8; i++) { > + env->cf[i] = fpu.fcc & 0xFF; > + fpu.fcc = fpu.fcc >> 8; > + } > + > + return ret; > +} > + > +static int kvm_loongarch_put_regs_fp(CPUState *cs) > +{ > + int ret, i; > + struct kvm_fpu fpu; > + > + LoongArchCPU *cpu = LOONGARCH_CPU(cs); > + CPULoongArchState *env = &cpu->env; > + > + fpu.fcsr = env->fcsr0; > + fpu.fcc = 0; > + for (i = 0; i < 32; i++) { > + fpu.fpr[i].val64[0] = env->fpr[i].vreg.UD[0]; > + } > + > + for (i = 0; i < 8; i++) { > + fpu.fcc |= env->cf[i] << (8 * i); > + } > + > + ret = kvm_vcpu_ioctl(cs, KVM_SET_FPU, &fpu); > + if (ret < 0) { > + trace_kvm_failed_put_fpu(strerror(errno)); > + } > + > + return ret; > +} > + > +void kvm_arch_reset_vcpu(CPULoongArchState *env) > +{ > + env->mp_state = KVM_MP_STATE_RUNNABLE; > +} > + > +static int kvm_loongarch_get_mpstate(CPUState *cs) > +{ > + int ret = 0; > + struct kvm_mp_state mp_state; > + LoongArchCPU *cpu = LOONGARCH_CPU(cs); > + CPULoongArchState *env = &cpu->env; > + > + if (cap_has_mp_state) { > + ret = kvm_vcpu_ioctl(cs, KVM_GET_MP_STATE, &mp_state); > + if (ret) { > + trace_kvm_failed_get_mpstate(strerror(errno)); > + return ret; > + } > + env->mp_state = mp_state.mp_state; > + } > + > + return ret; > +} > + > +static int kvm_loongarch_put_mpstate(CPUState *cs) > +{ > + int ret = 0; > + > + LoongArchCPU *cpu = LOONGARCH_CPU(cs); > + CPULoongArchState *env = &cpu->env; > + > + struct kvm_mp_state mp_state = { > + .mp_state = env->mp_state > + }; > + > + if (cap_has_mp_state) { > + ret = kvm_vcpu_ioctl(cs, KVM_SET_MP_STATE, &mp_state); > + if (ret) { > + trace_kvm_failed_put_mpstate(strerror(errno)); > + } > + } > + > + return ret; > +} > + > +static int kvm_loongarch_get_cpucfg(CPUState *cs) > +{ > + int i, ret = 0; > + uint64_t val; > + LoongArchCPU *cpu = LOONGARCH_CPU(cs); > + CPULoongArchState *env = &cpu->env; > + > + for (i = 0; i < 21; i++) { > + ret = kvm_get_one_reg(cs, KVM_IOC_CPUCFG(i), &val); > + if (ret < 0) { > + trace_kvm_failed_get_cpucfg(strerror(errno)); > + } > + env->cpucfg[i] = (uint32_t)val; > + } > + return ret; > +} > + > +static int kvm_loongarch_put_cpucfg(CPUState *cs) > +{ > + int i, ret = 0; > + LoongArchCPU *cpu = LOONGARCH_CPU(cs); > + CPULoongArchState *env = &cpu->env; > + uint64_t val; > + > + for (i = 0; i < 21; i++) { > + val = env->cpucfg[i]; > + /* LSX and LASX and LBT are not supported in kvm now */ > + if (i == 2) { > + val &= ~(BIT(R_CPUCFG2_LSX_SHIFT) | BIT(R_CPUCFG2_LASX_SHIFT)); > + val &= ~(BIT(R_CPUCFG2_LBT_X86_SHIFT) | > + BIT(R_CPUCFG2_LBT_ARM_SHIFT) | > + BIT(R_CPUCFG2_LBT_MIPS_SHIFT)); > + } > + ret = kvm_set_one_reg(cs, KVM_IOC_CPUCFG(i), &val); > + if (ret < 0) { > + trace_kvm_failed_put_cpucfg(strerror(errno)); > + } > + } > + return ret; > +} > + > int kvm_arch_get_registers(CPUState *cs) > { > - return 0; > + int ret; > + > + ret = kvm_loongarch_get_regs_core(cs); > + if (ret) { > + return ret; > + } > + > + ret = kvm_loongarch_get_csr(cs); > + if (ret) { > + return ret; > + } > + > + ret = kvm_loongarch_get_regs_fp(cs); > + if (ret) { > + return ret; > + } > + > + ret = kvm_loongarch_get_mpstate(cs); > + if (ret) { > + return ret; > + } > + > + ret = kvm_loongarch_get_cpucfg(cs); > + return ret; > } > + > int kvm_arch_put_registers(CPUState *cs, int level) > { > - return 0; > + int ret; > + > + ret = kvm_loongarch_put_regs_core(cs); > + if (ret) { > + return ret; > + } > + > + ret = kvm_loongarch_put_csr(cs); > + if (ret) { > + return ret; > + } > + > + ret = kvm_loongarch_put_regs_fp(cs); > + if (ret) { > + return ret; > + } > + > + ret = kvm_loongarch_put_mpstate(cs); > + if (ret) { > + return ret; > + } > + > + ret = kvm_loongarch_put_cpucfg(cs); > + return ret; > } > > int kvm_arch_init_vcpu(CPUState *cs) > diff --git a/target/loongarch/trace-events b/target/loongarch/trace-events > new file mode 100644 > index 0000000000..6827ab566a > --- /dev/null > +++ b/target/loongarch/trace-events > @@ -0,0 +1,11 @@ > +# See docs/devel/tracing.rst for syntax documentation. > + > +#kvm.c > +kvm_failed_get_regs_core(const char *msg) "Failed to get core regs from KVM: %s" > +kvm_failed_put_regs_core(const char *msg) "Failed to put core regs into KVM: %s" > +kvm_failed_get_fpu(const char *msg) "Failed to get fpu from KVM: %s" > +kvm_failed_put_fpu(const char *msg) "Failed to put fpu into KVM: %s" > +kvm_failed_get_mpstate(const char *msg) "Failed to get mp_state from KVM: %s" > +kvm_failed_put_mpstate(const char *msg) "Failed to put mp_state into KVM: %s" > +kvm_failed_get_cpucfg(const char *msg) "Failed to get cpucfg from KVM: %s" > +kvm_failed_put_cpucfg(const char *msg) "Failed to put cpucfg into KVM: %s" > diff --git a/target/loongarch/trace.h b/target/loongarch/trace.h > new file mode 100644 > index 0000000000..c2ecb78f08 > --- /dev/null > +++ b/target/loongarch/trace.h > @@ -0,0 +1 @@ > +#include "trace/trace-target_loongarch.h"
在 2023/12/28 下午4:40, Tianrui Zhao 写道: > +static int kvm_loongarch_get_regs_fp(CPUState *cs) > +{ > + int ret, i; > + struct kvm_fpu fpu; > + > + LoongArchCPU *cpu = LOONGARCH_CPU(cs); > + CPULoongArchState *env = &cpu->env; > + > + ret = kvm_vcpu_ioctl(cs, KVM_GET_FPU, &fpu); > + if (ret < 0) { > + trace_kvm_failed_get_fpu(strerror(errno)); > + return ret; > + } > + > + env->fcsr0 = fpu.fcsr; > + for (i = 0; i < 32; i++) { > + env->fpr[i].vreg.UD[0] = fpu.fpr[i].val64[0]; > + } > + for (i = 0; i < 8; i++) { > + env->cf[i] = fpu.fcc & 0xFF; > + fpu.fcc = fpu.fcc >> 8; > + } > + Use write_fcc(env, fpu.fcc) > + return ret; > +} > + > +static int kvm_loongarch_put_regs_fp(CPUState *cs) > +{ > + int ret, i; > + struct kvm_fpu fpu; > + > + LoongArchCPU *cpu = LOONGARCH_CPU(cs); > + CPULoongArchState *env = &cpu->env; > + > + fpu.fcsr = env->fcsr0; > + fpu.fcc = 0; > + for (i = 0; i < 32; i++) { > + fpu.fpr[i].val64[0] = env->fpr[i].vreg.UD[0]; > + } > + > + for (i = 0; i < 8; i++) { > + fpu.fcc |= env->cf[i] << (8 * i); > + } > + Use fpu.fcc = read_fcc(env) > + ret = kvm_vcpu_ioctl(cs, KVM_SET_FPU, &fpu); > + if (ret < 0) { > + trace_kvm_failed_put_fpu(strerror(errno)); > + } > + > + return ret; > +}
diff --git a/meson.build b/meson.build index 6c77d9687d..445f2b7c2b 100644 --- a/meson.build +++ b/meson.build @@ -3358,6 +3358,7 @@ if have_system or have_user 'target/hppa', 'target/i386', 'target/i386/kvm', + 'target/loongarch', 'target/mips/tcg', 'target/nios2', 'target/ppc', diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 4432a0081d..83899c673f 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -555,6 +555,9 @@ static void loongarch_cpu_reset_hold(Object *obj) #ifndef CONFIG_USER_ONLY env->pc = 0x1c000000; memset(env->tlb, 0, sizeof(env->tlb)); + if (kvm_enabled()) { + kvm_arch_reset_vcpu(env); + } #endif restore_fp_status(env); diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index f6d5ef0852..f4a89bd626 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -360,6 +360,7 @@ typedef struct CPUArchState { MemoryRegion iocsr_mem; bool load_elf; uint64_t elf_address; + uint32_t mp_state; /* Store ipistate to access from this struct */ DeviceState *ipistate; #endif diff --git a/target/loongarch/fpu_helper.c b/target/loongarch/fpu_helper.c index f6753c5875..1b71ea46d3 100644 --- a/target/loongarch/fpu_helper.c +++ b/target/loongarch/fpu_helper.c @@ -9,7 +9,9 @@ #include "cpu.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" +#ifdef CONFIG_TCG #include "exec/cpu_ldst.h" +#endif #include "fpu/softfloat.h" #include "internals.h" diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h index c492863cc5..0beb034748 100644 --- a/target/loongarch/internals.h +++ b/target/loongarch/internals.h @@ -31,8 +31,10 @@ void G_NORETURN do_raise_exception(CPULoongArchState *env, const char *loongarch_exception_name(int32_t exception); +#ifdef CONFIG_TCG int ieee_ex_to_loongarch(int xcpt); void restore_fp_status(CPULoongArchState *env); +#endif #ifndef CONFIG_USER_ONLY extern const VMStateDescription vmstate_loongarch_cpu; @@ -44,12 +46,13 @@ uint64_t cpu_loongarch_get_constant_timer_counter(LoongArchCPU *cpu); uint64_t cpu_loongarch_get_constant_timer_ticks(LoongArchCPU *cpu); void cpu_loongarch_store_constant_timer_config(LoongArchCPU *cpu, uint64_t value); - +#ifdef CONFIG_TCG bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr); hwaddr loongarch_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); +#endif #endif /* !CONFIG_USER_ONLY */ uint64_t read_fcc(CPULoongArchState *env); diff --git a/target/loongarch/kvm.c b/target/loongarch/kvm.c index 0d67322fd9..e7c9ef830c 100644 --- a/target/loongarch/kvm.c +++ b/target/loongarch/kvm.c @@ -26,19 +26,595 @@ #include "sysemu/runstate.h" #include "cpu-csr.h" #include "kvm_loongarch.h" +#include "trace.h" static bool cap_has_mp_state; const KVMCapabilityInfo kvm_arch_required_capabilities[] = { KVM_CAP_LAST_INFO }; +static int kvm_loongarch_get_regs_core(CPUState *cs) +{ + int ret = 0; + int i; + struct kvm_regs regs; + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + + /* Get the current register set as KVM seems it */ + ret = kvm_vcpu_ioctl(cs, KVM_GET_REGS, ®s); + if (ret < 0) { + trace_kvm_failed_get_regs_core(strerror(errno)); + return ret; + } + /* gpr[0] value is always 0 */ + env->gpr[0] = 0; + for (i = 1; i < 32; i++) { + env->gpr[i] = regs.gpr[i]; + } + + env->pc = regs.pc; + return ret; +} + +static int kvm_loongarch_put_regs_core(CPUState *cs) +{ + int ret = 0; + int i; + struct kvm_regs regs; + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + + /* Set the registers based on QEMU's view of things */ + for (i = 0; i < 32; i++) { + regs.gpr[i] = env->gpr[i]; + } + + regs.pc = env->pc; + ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, ®s); + if (ret < 0) { + trace_kvm_failed_put_regs_core(strerror(errno)); + } + + return ret; +} + +static int kvm_loongarch_get_csr(CPUState *cs) +{ + int ret = 0; + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CRMD), + &env->CSR_CRMD); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRMD), + &env->CSR_PRMD); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_EUEN), + &env->CSR_EUEN); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_MISC), + &env->CSR_MISC); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ECFG), + &env->CSR_ECFG); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ESTAT), + &env->CSR_ESTAT); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ERA), + &env->CSR_ERA); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_BADV), + &env->CSR_BADV); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_BADI), + &env->CSR_BADI); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_EENTRY), + &env->CSR_EENTRY); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBIDX), + &env->CSR_TLBIDX); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBEHI), + &env->CSR_TLBEHI); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBELO0), + &env->CSR_TLBELO0); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBELO1), + &env->CSR_TLBELO1); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ASID), + &env->CSR_ASID); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGDL), + &env->CSR_PGDL); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGDH), + &env->CSR_PGDH); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGD), + &env->CSR_PGD); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PWCL), + &env->CSR_PWCL); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PWCH), + &env->CSR_PWCH); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_STLBPS), + &env->CSR_STLBPS); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_RVACFG), + &env->CSR_RVACFG); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CPUID), + &env->CSR_CPUID); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG1), + &env->CSR_PRCFG1); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG2), + &env->CSR_PRCFG2); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG3), + &env->CSR_PRCFG3); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(0)), + &env->CSR_SAVE[0]); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(1)), + &env->CSR_SAVE[1]); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(2)), + &env->CSR_SAVE[2]); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(3)), + &env->CSR_SAVE[3]); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(4)), + &env->CSR_SAVE[4]); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(5)), + &env->CSR_SAVE[5]); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(6)), + &env->CSR_SAVE[6]); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(7)), + &env->CSR_SAVE[7]); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TID), + &env->CSR_TID); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CNTC), + &env->CSR_CNTC); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TICLR), + &env->CSR_TICLR); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_LLBCTL), + &env->CSR_LLBCTL); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_IMPCTL1), + &env->CSR_IMPCTL1); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_IMPCTL2), + &env->CSR_IMPCTL2); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRENTRY), + &env->CSR_TLBRENTRY); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRBADV), + &env->CSR_TLBRBADV); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRERA), + &env->CSR_TLBRERA); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRSAVE), + &env->CSR_TLBRSAVE); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRELO0), + &env->CSR_TLBRELO0); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRELO1), + &env->CSR_TLBRELO1); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBREHI), + &env->CSR_TLBREHI); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRPRMD), + &env->CSR_TLBRPRMD); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(0)), + &env->CSR_DMW[0]); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(1)), + &env->CSR_DMW[1]); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(2)), + &env->CSR_DMW[2]); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(3)), + &env->CSR_DMW[3]); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TVAL), + &env->CSR_TVAL); + + ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TCFG), + &env->CSR_TCFG); + + return ret; +} + +static int kvm_loongarch_put_csr(CPUState *cs) +{ + int ret = 0; + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CRMD), + &env->CSR_CRMD); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRMD), + &env->CSR_PRMD); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_EUEN), + &env->CSR_EUEN); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_MISC), + &env->CSR_MISC); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ECFG), + &env->CSR_ECFG); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ESTAT), + &env->CSR_ESTAT); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ERA), + &env->CSR_ERA); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_BADV), + &env->CSR_BADV); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_BADI), + &env->CSR_BADI); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_EENTRY), + &env->CSR_EENTRY); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBIDX), + &env->CSR_TLBIDX); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBEHI), + &env->CSR_TLBEHI); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBELO0), + &env->CSR_TLBELO0); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBELO1), + &env->CSR_TLBELO1); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ASID), + &env->CSR_ASID); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGDL), + &env->CSR_PGDL); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGDH), + &env->CSR_PGDH); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGD), + &env->CSR_PGD); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PWCL), + &env->CSR_PWCL); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PWCH), + &env->CSR_PWCH); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_STLBPS), + &env->CSR_STLBPS); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_RVACFG), + &env->CSR_RVACFG); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CPUID), + &env->CSR_CPUID); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG1), + &env->CSR_PRCFG1); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG2), + &env->CSR_PRCFG2); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG3), + &env->CSR_PRCFG3); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(0)), + &env->CSR_SAVE[0]); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(1)), + &env->CSR_SAVE[1]); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(2)), + &env->CSR_SAVE[2]); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(3)), + &env->CSR_SAVE[3]); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(4)), + &env->CSR_SAVE[4]); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(5)), + &env->CSR_SAVE[5]); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(6)), + &env->CSR_SAVE[6]); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(7)), + &env->CSR_SAVE[7]); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TID), + &env->CSR_TID); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CNTC), + &env->CSR_CNTC); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TICLR), + &env->CSR_TICLR); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_LLBCTL), + &env->CSR_LLBCTL); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_IMPCTL1), + &env->CSR_IMPCTL1); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_IMPCTL2), + &env->CSR_IMPCTL2); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRENTRY), + &env->CSR_TLBRENTRY); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRBADV), + &env->CSR_TLBRBADV); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRERA), + &env->CSR_TLBRERA); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRSAVE), + &env->CSR_TLBRSAVE); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRELO0), + &env->CSR_TLBRELO0); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRELO1), + &env->CSR_TLBRELO1); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBREHI), + &env->CSR_TLBREHI); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRPRMD), + &env->CSR_TLBRPRMD); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(0)), + &env->CSR_DMW[0]); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(1)), + &env->CSR_DMW[1]); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(2)), + &env->CSR_DMW[2]); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(3)), + &env->CSR_DMW[3]); + /* + * timer cfg must be put at last since it is used to enable + * guest timer + */ + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TVAL), + &env->CSR_TVAL); + + ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TCFG), + &env->CSR_TCFG); + return ret; +} + +static int kvm_loongarch_get_regs_fp(CPUState *cs) +{ + int ret, i; + struct kvm_fpu fpu; + + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + + ret = kvm_vcpu_ioctl(cs, KVM_GET_FPU, &fpu); + if (ret < 0) { + trace_kvm_failed_get_fpu(strerror(errno)); + return ret; + } + + env->fcsr0 = fpu.fcsr; + for (i = 0; i < 32; i++) { + env->fpr[i].vreg.UD[0] = fpu.fpr[i].val64[0]; + } + for (i = 0; i < 8; i++) { + env->cf[i] = fpu.fcc & 0xFF; + fpu.fcc = fpu.fcc >> 8; + } + + return ret; +} + +static int kvm_loongarch_put_regs_fp(CPUState *cs) +{ + int ret, i; + struct kvm_fpu fpu; + + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + + fpu.fcsr = env->fcsr0; + fpu.fcc = 0; + for (i = 0; i < 32; i++) { + fpu.fpr[i].val64[0] = env->fpr[i].vreg.UD[0]; + } + + for (i = 0; i < 8; i++) { + fpu.fcc |= env->cf[i] << (8 * i); + } + + ret = kvm_vcpu_ioctl(cs, KVM_SET_FPU, &fpu); + if (ret < 0) { + trace_kvm_failed_put_fpu(strerror(errno)); + } + + return ret; +} + +void kvm_arch_reset_vcpu(CPULoongArchState *env) +{ + env->mp_state = KVM_MP_STATE_RUNNABLE; +} + +static int kvm_loongarch_get_mpstate(CPUState *cs) +{ + int ret = 0; + struct kvm_mp_state mp_state; + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + + if (cap_has_mp_state) { + ret = kvm_vcpu_ioctl(cs, KVM_GET_MP_STATE, &mp_state); + if (ret) { + trace_kvm_failed_get_mpstate(strerror(errno)); + return ret; + } + env->mp_state = mp_state.mp_state; + } + + return ret; +} + +static int kvm_loongarch_put_mpstate(CPUState *cs) +{ + int ret = 0; + + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + + struct kvm_mp_state mp_state = { + .mp_state = env->mp_state + }; + + if (cap_has_mp_state) { + ret = kvm_vcpu_ioctl(cs, KVM_SET_MP_STATE, &mp_state); + if (ret) { + trace_kvm_failed_put_mpstate(strerror(errno)); + } + } + + return ret; +} + +static int kvm_loongarch_get_cpucfg(CPUState *cs) +{ + int i, ret = 0; + uint64_t val; + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + + for (i = 0; i < 21; i++) { + ret = kvm_get_one_reg(cs, KVM_IOC_CPUCFG(i), &val); + if (ret < 0) { + trace_kvm_failed_get_cpucfg(strerror(errno)); + } + env->cpucfg[i] = (uint32_t)val; + } + return ret; +} + +static int kvm_loongarch_put_cpucfg(CPUState *cs) +{ + int i, ret = 0; + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + uint64_t val; + + for (i = 0; i < 21; i++) { + val = env->cpucfg[i]; + /* LSX and LASX and LBT are not supported in kvm now */ + if (i == 2) { + val &= ~(BIT(R_CPUCFG2_LSX_SHIFT) | BIT(R_CPUCFG2_LASX_SHIFT)); + val &= ~(BIT(R_CPUCFG2_LBT_X86_SHIFT) | + BIT(R_CPUCFG2_LBT_ARM_SHIFT) | + BIT(R_CPUCFG2_LBT_MIPS_SHIFT)); + } + ret = kvm_set_one_reg(cs, KVM_IOC_CPUCFG(i), &val); + if (ret < 0) { + trace_kvm_failed_put_cpucfg(strerror(errno)); + } + } + return ret; +} + int kvm_arch_get_registers(CPUState *cs) { - return 0; + int ret; + + ret = kvm_loongarch_get_regs_core(cs); + if (ret) { + return ret; + } + + ret = kvm_loongarch_get_csr(cs); + if (ret) { + return ret; + } + + ret = kvm_loongarch_get_regs_fp(cs); + if (ret) { + return ret; + } + + ret = kvm_loongarch_get_mpstate(cs); + if (ret) { + return ret; + } + + ret = kvm_loongarch_get_cpucfg(cs); + return ret; } + int kvm_arch_put_registers(CPUState *cs, int level) { - return 0; + int ret; + + ret = kvm_loongarch_put_regs_core(cs); + if (ret) { + return ret; + } + + ret = kvm_loongarch_put_csr(cs); + if (ret) { + return ret; + } + + ret = kvm_loongarch_put_regs_fp(cs); + if (ret) { + return ret; + } + + ret = kvm_loongarch_put_mpstate(cs); + if (ret) { + return ret; + } + + ret = kvm_loongarch_put_cpucfg(cs); + return ret; } int kvm_arch_init_vcpu(CPUState *cs) diff --git a/target/loongarch/trace-events b/target/loongarch/trace-events new file mode 100644 index 0000000000..6827ab566a --- /dev/null +++ b/target/loongarch/trace-events @@ -0,0 +1,11 @@ +# See docs/devel/tracing.rst for syntax documentation. + +#kvm.c +kvm_failed_get_regs_core(const char *msg) "Failed to get core regs from KVM: %s" +kvm_failed_put_regs_core(const char *msg) "Failed to put core regs into KVM: %s" +kvm_failed_get_fpu(const char *msg) "Failed to get fpu from KVM: %s" +kvm_failed_put_fpu(const char *msg) "Failed to put fpu into KVM: %s" +kvm_failed_get_mpstate(const char *msg) "Failed to get mp_state from KVM: %s" +kvm_failed_put_mpstate(const char *msg) "Failed to put mp_state into KVM: %s" +kvm_failed_get_cpucfg(const char *msg) "Failed to get cpucfg from KVM: %s" +kvm_failed_put_cpucfg(const char *msg) "Failed to put cpucfg into KVM: %s" diff --git a/target/loongarch/trace.h b/target/loongarch/trace.h new file mode 100644 index 0000000000..c2ecb78f08 --- /dev/null +++ b/target/loongarch/trace.h @@ -0,0 +1 @@ +#include "trace/trace-target_loongarch.h"