1537ba9daSTianrui Zhao /* SPDX-License-Identifier: GPL-2.0-or-later */ 2537ba9daSTianrui Zhao /* 3537ba9daSTianrui Zhao * QEMU LoongArch KVM 4537ba9daSTianrui Zhao * 5537ba9daSTianrui Zhao * Copyright (c) 2023 Loongson Technology Corporation Limited 6537ba9daSTianrui Zhao */ 7537ba9daSTianrui Zhao 8537ba9daSTianrui Zhao #include "qemu/osdep.h" 9537ba9daSTianrui Zhao #include <sys/ioctl.h> 10537ba9daSTianrui Zhao #include <linux/kvm.h> 11620d9bd0SBibo Mao #include "asm-loongarch/kvm_para.h" 12c23a53d8SBibo Mao #include "qapi/error.h" 13537ba9daSTianrui Zhao #include "qemu/timer.h" 14537ba9daSTianrui Zhao #include "qemu/error-report.h" 15537ba9daSTianrui Zhao #include "qemu/main-loop.h" 1632cad1ffSPhilippe Mathieu-Daudé #include "system/system.h" 1732cad1ffSPhilippe Mathieu-Daudé #include "system/kvm.h" 1832cad1ffSPhilippe Mathieu-Daudé #include "system/kvm_int.h" 19537ba9daSTianrui Zhao #include "hw/pci/pci.h" 20537ba9daSTianrui Zhao #include "exec/memattrs.h" 21537ba9daSTianrui Zhao #include "exec/address-spaces.h" 22537ba9daSTianrui Zhao #include "hw/boards.h" 23537ba9daSTianrui Zhao #include "hw/irq.h" 24*db369c11SBibo Mao #include "hw/loongarch/virt.h" 25537ba9daSTianrui Zhao #include "qemu/log.h" 26537ba9daSTianrui Zhao #include "hw/loader.h" 2732cad1ffSPhilippe Mathieu-Daudé #include "system/runstate.h" 28537ba9daSTianrui Zhao #include "cpu-csr.h" 29537ba9daSTianrui Zhao #include "kvm_loongarch.h" 30f8447436STianrui Zhao #include "trace.h" 31537ba9daSTianrui Zhao 32537ba9daSTianrui Zhao static bool cap_has_mp_state; 33d38e31efSBibo Mao static unsigned int brk_insn; 34537ba9daSTianrui Zhao const KVMCapabilityInfo kvm_arch_required_capabilities[] = { 35537ba9daSTianrui Zhao KVM_CAP_LAST_INFO 36537ba9daSTianrui Zhao }; 37537ba9daSTianrui Zhao 3847b54e15SBibo Mao static int kvm_get_stealtime(CPUState *cs) 3947b54e15SBibo Mao { 4047b54e15SBibo Mao CPULoongArchState *env = cpu_env(cs); 4147b54e15SBibo Mao int err; 4247b54e15SBibo Mao struct kvm_device_attr attr = { 4347b54e15SBibo Mao .group = KVM_LOONGARCH_VCPU_PVTIME_CTRL, 4447b54e15SBibo Mao .attr = KVM_LOONGARCH_VCPU_PVTIME_GPA, 4547b54e15SBibo Mao .addr = (uint64_t)&env->stealtime.guest_addr, 4647b54e15SBibo Mao }; 4747b54e15SBibo Mao 4847b54e15SBibo Mao err = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, attr); 4947b54e15SBibo Mao if (err) { 5047b54e15SBibo Mao return 0; 5147b54e15SBibo Mao } 5247b54e15SBibo Mao 5347b54e15SBibo Mao err = kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, attr); 5447b54e15SBibo Mao if (err) { 5547b54e15SBibo Mao error_report("PVTIME: KVM_GET_DEVICE_ATTR: %s", strerror(errno)); 5647b54e15SBibo Mao return err; 5747b54e15SBibo Mao } 5847b54e15SBibo Mao 5947b54e15SBibo Mao return 0; 6047b54e15SBibo Mao } 6147b54e15SBibo Mao 6247b54e15SBibo Mao static int kvm_set_stealtime(CPUState *cs) 6347b54e15SBibo Mao { 6447b54e15SBibo Mao CPULoongArchState *env = cpu_env(cs); 6547b54e15SBibo Mao int err; 6647b54e15SBibo Mao struct kvm_device_attr attr = { 6747b54e15SBibo Mao .group = KVM_LOONGARCH_VCPU_PVTIME_CTRL, 6847b54e15SBibo Mao .attr = KVM_LOONGARCH_VCPU_PVTIME_GPA, 6947b54e15SBibo Mao .addr = (uint64_t)&env->stealtime.guest_addr, 7047b54e15SBibo Mao }; 7147b54e15SBibo Mao 7247b54e15SBibo Mao err = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, attr); 7347b54e15SBibo Mao if (err) { 7447b54e15SBibo Mao return 0; 7547b54e15SBibo Mao } 7647b54e15SBibo Mao 7747b54e15SBibo Mao err = kvm_vcpu_ioctl(cs, KVM_SET_DEVICE_ATTR, attr); 7847b54e15SBibo Mao if (err) { 7947b54e15SBibo Mao error_report("PVTIME: KVM_SET_DEVICE_ATTR %s with gpa "TARGET_FMT_lx, 8047b54e15SBibo Mao strerror(errno), env->stealtime.guest_addr); 8147b54e15SBibo Mao return err; 8247b54e15SBibo Mao } 8347b54e15SBibo Mao 8447b54e15SBibo Mao return 0; 8547b54e15SBibo Mao } 8647b54e15SBibo Mao 872698cc7cSBibo Mao static int kvm_set_pv_features(CPUState *cs) 882698cc7cSBibo Mao { 892698cc7cSBibo Mao CPULoongArchState *env = cpu_env(cs); 902698cc7cSBibo Mao int err; 912698cc7cSBibo Mao uint64_t val; 922698cc7cSBibo Mao struct kvm_device_attr attr = { 932698cc7cSBibo Mao .group = KVM_LOONGARCH_VCPU_CPUCFG, 942698cc7cSBibo Mao .attr = CPUCFG_KVM_FEATURE, 952698cc7cSBibo Mao .addr = (uint64_t)&val, 962698cc7cSBibo Mao }; 972698cc7cSBibo Mao 982698cc7cSBibo Mao err = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, attr); 992698cc7cSBibo Mao if (err) { 1002698cc7cSBibo Mao return 0; 1012698cc7cSBibo Mao } 1022698cc7cSBibo Mao 1032698cc7cSBibo Mao val = env->pv_features; 1042698cc7cSBibo Mao err = kvm_vcpu_ioctl(cs, KVM_SET_DEVICE_ATTR, attr); 1052698cc7cSBibo Mao if (err) { 1062698cc7cSBibo Mao error_report("Fail to set pv feature "TARGET_FMT_lx " with error %s", 1072698cc7cSBibo Mao val, strerror(errno)); 1082698cc7cSBibo Mao return err; 1092698cc7cSBibo Mao } 1102698cc7cSBibo Mao 1112698cc7cSBibo Mao return 0; 1122698cc7cSBibo Mao } 1132698cc7cSBibo Mao 114f8447436STianrui Zhao static int kvm_loongarch_get_regs_core(CPUState *cs) 115f8447436STianrui Zhao { 116f8447436STianrui Zhao int ret = 0; 117f8447436STianrui Zhao int i; 118f8447436STianrui Zhao struct kvm_regs regs; 119f3b603b9SPhilippe Mathieu-Daudé CPULoongArchState *env = cpu_env(cs); 120f8447436STianrui Zhao 121f8447436STianrui Zhao /* Get the current register set as KVM seems it */ 122f8447436STianrui Zhao ret = kvm_vcpu_ioctl(cs, KVM_GET_REGS, ®s); 123f8447436STianrui Zhao if (ret < 0) { 124f8447436STianrui Zhao trace_kvm_failed_get_regs_core(strerror(errno)); 125f8447436STianrui Zhao return ret; 126f8447436STianrui Zhao } 127f8447436STianrui Zhao /* gpr[0] value is always 0 */ 128f8447436STianrui Zhao env->gpr[0] = 0; 129f8447436STianrui Zhao for (i = 1; i < 32; i++) { 130f8447436STianrui Zhao env->gpr[i] = regs.gpr[i]; 131f8447436STianrui Zhao } 132f8447436STianrui Zhao 133f8447436STianrui Zhao env->pc = regs.pc; 134f8447436STianrui Zhao return ret; 135f8447436STianrui Zhao } 136f8447436STianrui Zhao 137f8447436STianrui Zhao static int kvm_loongarch_put_regs_core(CPUState *cs) 138f8447436STianrui Zhao { 139f8447436STianrui Zhao int ret = 0; 140f8447436STianrui Zhao int i; 141f8447436STianrui Zhao struct kvm_regs regs; 142f3b603b9SPhilippe Mathieu-Daudé CPULoongArchState *env = cpu_env(cs); 143f8447436STianrui Zhao 144f8447436STianrui Zhao /* Set the registers based on QEMU's view of things */ 145f8447436STianrui Zhao for (i = 0; i < 32; i++) { 146f8447436STianrui Zhao regs.gpr[i] = env->gpr[i]; 147f8447436STianrui Zhao } 148f8447436STianrui Zhao 149f8447436STianrui Zhao regs.pc = env->pc; 150f8447436STianrui Zhao ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, ®s); 151f8447436STianrui Zhao if (ret < 0) { 152f8447436STianrui Zhao trace_kvm_failed_put_regs_core(strerror(errno)); 153f8447436STianrui Zhao } 154f8447436STianrui Zhao 155f8447436STianrui Zhao return ret; 156f8447436STianrui Zhao } 157f8447436STianrui Zhao 158f8447436STianrui Zhao static int kvm_loongarch_get_csr(CPUState *cs) 159f8447436STianrui Zhao { 160f8447436STianrui Zhao int ret = 0; 161f3b603b9SPhilippe Mathieu-Daudé CPULoongArchState *env = cpu_env(cs); 162f8447436STianrui Zhao 163f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CRMD), 164f8447436STianrui Zhao &env->CSR_CRMD); 165f8447436STianrui Zhao 166f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRMD), 167f8447436STianrui Zhao &env->CSR_PRMD); 168f8447436STianrui Zhao 169f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_EUEN), 170f8447436STianrui Zhao &env->CSR_EUEN); 171f8447436STianrui Zhao 172f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_MISC), 173f8447436STianrui Zhao &env->CSR_MISC); 174f8447436STianrui Zhao 175f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ECFG), 176f8447436STianrui Zhao &env->CSR_ECFG); 177f8447436STianrui Zhao 178f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ESTAT), 179f8447436STianrui Zhao &env->CSR_ESTAT); 180f8447436STianrui Zhao 181f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ERA), 182f8447436STianrui Zhao &env->CSR_ERA); 183f8447436STianrui Zhao 184f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_BADV), 185f8447436STianrui Zhao &env->CSR_BADV); 186f8447436STianrui Zhao 187f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_BADI), 188f8447436STianrui Zhao &env->CSR_BADI); 189f8447436STianrui Zhao 190f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_EENTRY), 191f8447436STianrui Zhao &env->CSR_EENTRY); 192f8447436STianrui Zhao 193f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBIDX), 194f8447436STianrui Zhao &env->CSR_TLBIDX); 195f8447436STianrui Zhao 196f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBEHI), 197f8447436STianrui Zhao &env->CSR_TLBEHI); 198f8447436STianrui Zhao 199f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBELO0), 200f8447436STianrui Zhao &env->CSR_TLBELO0); 201f8447436STianrui Zhao 202f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBELO1), 203f8447436STianrui Zhao &env->CSR_TLBELO1); 204f8447436STianrui Zhao 205f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ASID), 206f8447436STianrui Zhao &env->CSR_ASID); 207f8447436STianrui Zhao 208f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGDL), 209f8447436STianrui Zhao &env->CSR_PGDL); 210f8447436STianrui Zhao 211f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGDH), 212f8447436STianrui Zhao &env->CSR_PGDH); 213f8447436STianrui Zhao 214f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGD), 215f8447436STianrui Zhao &env->CSR_PGD); 216f8447436STianrui Zhao 217f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PWCL), 218f8447436STianrui Zhao &env->CSR_PWCL); 219f8447436STianrui Zhao 220f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PWCH), 221f8447436STianrui Zhao &env->CSR_PWCH); 222f8447436STianrui Zhao 223f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_STLBPS), 224f8447436STianrui Zhao &env->CSR_STLBPS); 225f8447436STianrui Zhao 226f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_RVACFG), 227f8447436STianrui Zhao &env->CSR_RVACFG); 228f8447436STianrui Zhao 229f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CPUID), 230f8447436STianrui Zhao &env->CSR_CPUID); 231f8447436STianrui Zhao 232f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG1), 233f8447436STianrui Zhao &env->CSR_PRCFG1); 234f8447436STianrui Zhao 235f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG2), 236f8447436STianrui Zhao &env->CSR_PRCFG2); 237f8447436STianrui Zhao 238f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG3), 239f8447436STianrui Zhao &env->CSR_PRCFG3); 240f8447436STianrui Zhao 241f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(0)), 242f8447436STianrui Zhao &env->CSR_SAVE[0]); 243f8447436STianrui Zhao 244f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(1)), 245f8447436STianrui Zhao &env->CSR_SAVE[1]); 246f8447436STianrui Zhao 247f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(2)), 248f8447436STianrui Zhao &env->CSR_SAVE[2]); 249f8447436STianrui Zhao 250f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(3)), 251f8447436STianrui Zhao &env->CSR_SAVE[3]); 252f8447436STianrui Zhao 253f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(4)), 254f8447436STianrui Zhao &env->CSR_SAVE[4]); 255f8447436STianrui Zhao 256f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(5)), 257f8447436STianrui Zhao &env->CSR_SAVE[5]); 258f8447436STianrui Zhao 259f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(6)), 260f8447436STianrui Zhao &env->CSR_SAVE[6]); 261f8447436STianrui Zhao 262f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(7)), 263f8447436STianrui Zhao &env->CSR_SAVE[7]); 264f8447436STianrui Zhao 265f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TID), 266f8447436STianrui Zhao &env->CSR_TID); 267f8447436STianrui Zhao 268f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CNTC), 269f8447436STianrui Zhao &env->CSR_CNTC); 270f8447436STianrui Zhao 271f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TICLR), 272f8447436STianrui Zhao &env->CSR_TICLR); 273f8447436STianrui Zhao 274f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_LLBCTL), 275f8447436STianrui Zhao &env->CSR_LLBCTL); 276f8447436STianrui Zhao 277f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_IMPCTL1), 278f8447436STianrui Zhao &env->CSR_IMPCTL1); 279f8447436STianrui Zhao 280f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_IMPCTL2), 281f8447436STianrui Zhao &env->CSR_IMPCTL2); 282f8447436STianrui Zhao 283f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRENTRY), 284f8447436STianrui Zhao &env->CSR_TLBRENTRY); 285f8447436STianrui Zhao 286f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRBADV), 287f8447436STianrui Zhao &env->CSR_TLBRBADV); 288f8447436STianrui Zhao 289f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRERA), 290f8447436STianrui Zhao &env->CSR_TLBRERA); 291f8447436STianrui Zhao 292f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRSAVE), 293f8447436STianrui Zhao &env->CSR_TLBRSAVE); 294f8447436STianrui Zhao 295f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRELO0), 296f8447436STianrui Zhao &env->CSR_TLBRELO0); 297f8447436STianrui Zhao 298f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRELO1), 299f8447436STianrui Zhao &env->CSR_TLBRELO1); 300f8447436STianrui Zhao 301f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBREHI), 302f8447436STianrui Zhao &env->CSR_TLBREHI); 303f8447436STianrui Zhao 304f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRPRMD), 305f8447436STianrui Zhao &env->CSR_TLBRPRMD); 306f8447436STianrui Zhao 307f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(0)), 308f8447436STianrui Zhao &env->CSR_DMW[0]); 309f8447436STianrui Zhao 310f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(1)), 311f8447436STianrui Zhao &env->CSR_DMW[1]); 312f8447436STianrui Zhao 313f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(2)), 314f8447436STianrui Zhao &env->CSR_DMW[2]); 315f8447436STianrui Zhao 316f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(3)), 317f8447436STianrui Zhao &env->CSR_DMW[3]); 318f8447436STianrui Zhao 319f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TVAL), 320f8447436STianrui Zhao &env->CSR_TVAL); 321f8447436STianrui Zhao 322f8447436STianrui Zhao ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TCFG), 323f8447436STianrui Zhao &env->CSR_TCFG); 324f8447436STianrui Zhao 325f8447436STianrui Zhao return ret; 326f8447436STianrui Zhao } 327f8447436STianrui Zhao 32861f6e150SBibo Mao static int kvm_loongarch_put_csr(CPUState *cs, int level) 329f8447436STianrui Zhao { 330f8447436STianrui Zhao int ret = 0; 331f3b603b9SPhilippe Mathieu-Daudé CPULoongArchState *env = cpu_env(cs); 332f8447436STianrui Zhao 333f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CRMD), 334f8447436STianrui Zhao &env->CSR_CRMD); 335f8447436STianrui Zhao 336f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRMD), 337f8447436STianrui Zhao &env->CSR_PRMD); 338f8447436STianrui Zhao 339f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_EUEN), 340f8447436STianrui Zhao &env->CSR_EUEN); 341f8447436STianrui Zhao 342f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_MISC), 343f8447436STianrui Zhao &env->CSR_MISC); 344f8447436STianrui Zhao 345f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ECFG), 346f8447436STianrui Zhao &env->CSR_ECFG); 347f8447436STianrui Zhao 348f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ESTAT), 349f8447436STianrui Zhao &env->CSR_ESTAT); 350f8447436STianrui Zhao 351f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ERA), 352f8447436STianrui Zhao &env->CSR_ERA); 353f8447436STianrui Zhao 354f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_BADV), 355f8447436STianrui Zhao &env->CSR_BADV); 356f8447436STianrui Zhao 357f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_BADI), 358f8447436STianrui Zhao &env->CSR_BADI); 359f8447436STianrui Zhao 360f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_EENTRY), 361f8447436STianrui Zhao &env->CSR_EENTRY); 362f8447436STianrui Zhao 363f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBIDX), 364f8447436STianrui Zhao &env->CSR_TLBIDX); 365f8447436STianrui Zhao 366f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBEHI), 367f8447436STianrui Zhao &env->CSR_TLBEHI); 368f8447436STianrui Zhao 369f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBELO0), 370f8447436STianrui Zhao &env->CSR_TLBELO0); 371f8447436STianrui Zhao 372f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBELO1), 373f8447436STianrui Zhao &env->CSR_TLBELO1); 374f8447436STianrui Zhao 375f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ASID), 376f8447436STianrui Zhao &env->CSR_ASID); 377f8447436STianrui Zhao 378f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGDL), 379f8447436STianrui Zhao &env->CSR_PGDL); 380f8447436STianrui Zhao 381f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGDH), 382f8447436STianrui Zhao &env->CSR_PGDH); 383f8447436STianrui Zhao 384f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGD), 385f8447436STianrui Zhao &env->CSR_PGD); 386f8447436STianrui Zhao 387f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PWCL), 388f8447436STianrui Zhao &env->CSR_PWCL); 389f8447436STianrui Zhao 390f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PWCH), 391f8447436STianrui Zhao &env->CSR_PWCH); 392f8447436STianrui Zhao 393f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_STLBPS), 394f8447436STianrui Zhao &env->CSR_STLBPS); 395f8447436STianrui Zhao 396f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_RVACFG), 397f8447436STianrui Zhao &env->CSR_RVACFG); 398f8447436STianrui Zhao 39961f6e150SBibo Mao /* CPUID is constant after poweron, it should be set only once */ 40061f6e150SBibo Mao if (level >= KVM_PUT_FULL_STATE) { 401f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CPUID), 402f8447436STianrui Zhao &env->CSR_CPUID); 40361f6e150SBibo Mao } 404f8447436STianrui Zhao 405f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG1), 406f8447436STianrui Zhao &env->CSR_PRCFG1); 407f8447436STianrui Zhao 408f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG2), 409f8447436STianrui Zhao &env->CSR_PRCFG2); 410f8447436STianrui Zhao 411f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG3), 412f8447436STianrui Zhao &env->CSR_PRCFG3); 413f8447436STianrui Zhao 414f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(0)), 415f8447436STianrui Zhao &env->CSR_SAVE[0]); 416f8447436STianrui Zhao 417f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(1)), 418f8447436STianrui Zhao &env->CSR_SAVE[1]); 419f8447436STianrui Zhao 420f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(2)), 421f8447436STianrui Zhao &env->CSR_SAVE[2]); 422f8447436STianrui Zhao 423f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(3)), 424f8447436STianrui Zhao &env->CSR_SAVE[3]); 425f8447436STianrui Zhao 426f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(4)), 427f8447436STianrui Zhao &env->CSR_SAVE[4]); 428f8447436STianrui Zhao 429f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(5)), 430f8447436STianrui Zhao &env->CSR_SAVE[5]); 431f8447436STianrui Zhao 432f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(6)), 433f8447436STianrui Zhao &env->CSR_SAVE[6]); 434f8447436STianrui Zhao 435f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(7)), 436f8447436STianrui Zhao &env->CSR_SAVE[7]); 437f8447436STianrui Zhao 438f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TID), 439f8447436STianrui Zhao &env->CSR_TID); 440f8447436STianrui Zhao 441f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CNTC), 442f8447436STianrui Zhao &env->CSR_CNTC); 443f8447436STianrui Zhao 444f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TICLR), 445f8447436STianrui Zhao &env->CSR_TICLR); 446f8447436STianrui Zhao 447f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_LLBCTL), 448f8447436STianrui Zhao &env->CSR_LLBCTL); 449f8447436STianrui Zhao 450f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_IMPCTL1), 451f8447436STianrui Zhao &env->CSR_IMPCTL1); 452f8447436STianrui Zhao 453f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_IMPCTL2), 454f8447436STianrui Zhao &env->CSR_IMPCTL2); 455f8447436STianrui Zhao 456f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRENTRY), 457f8447436STianrui Zhao &env->CSR_TLBRENTRY); 458f8447436STianrui Zhao 459f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRBADV), 460f8447436STianrui Zhao &env->CSR_TLBRBADV); 461f8447436STianrui Zhao 462f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRERA), 463f8447436STianrui Zhao &env->CSR_TLBRERA); 464f8447436STianrui Zhao 465f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRSAVE), 466f8447436STianrui Zhao &env->CSR_TLBRSAVE); 467f8447436STianrui Zhao 468f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRELO0), 469f8447436STianrui Zhao &env->CSR_TLBRELO0); 470f8447436STianrui Zhao 471f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRELO1), 472f8447436STianrui Zhao &env->CSR_TLBRELO1); 473f8447436STianrui Zhao 474f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBREHI), 475f8447436STianrui Zhao &env->CSR_TLBREHI); 476f8447436STianrui Zhao 477f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRPRMD), 478f8447436STianrui Zhao &env->CSR_TLBRPRMD); 479f8447436STianrui Zhao 480f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(0)), 481f8447436STianrui Zhao &env->CSR_DMW[0]); 482f8447436STianrui Zhao 483f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(1)), 484f8447436STianrui Zhao &env->CSR_DMW[1]); 485f8447436STianrui Zhao 486f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(2)), 487f8447436STianrui Zhao &env->CSR_DMW[2]); 488f8447436STianrui Zhao 489f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(3)), 490f8447436STianrui Zhao &env->CSR_DMW[3]); 491f8447436STianrui Zhao /* 492f8447436STianrui Zhao * timer cfg must be put at last since it is used to enable 493f8447436STianrui Zhao * guest timer 494f8447436STianrui Zhao */ 495f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TVAL), 496f8447436STianrui Zhao &env->CSR_TVAL); 497f8447436STianrui Zhao 498f8447436STianrui Zhao ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TCFG), 499f8447436STianrui Zhao &env->CSR_TCFG); 500f8447436STianrui Zhao return ret; 501f8447436STianrui Zhao } 502f8447436STianrui Zhao 503f8447436STianrui Zhao static int kvm_loongarch_get_regs_fp(CPUState *cs) 504f8447436STianrui Zhao { 505f8447436STianrui Zhao int ret, i; 506f8447436STianrui Zhao struct kvm_fpu fpu; 507f3b603b9SPhilippe Mathieu-Daudé CPULoongArchState *env = cpu_env(cs); 508f8447436STianrui Zhao 509f8447436STianrui Zhao ret = kvm_vcpu_ioctl(cs, KVM_GET_FPU, &fpu); 510f8447436STianrui Zhao if (ret < 0) { 511f8447436STianrui Zhao trace_kvm_failed_get_fpu(strerror(errno)); 512f8447436STianrui Zhao return ret; 513f8447436STianrui Zhao } 514f8447436STianrui Zhao 515f8447436STianrui Zhao env->fcsr0 = fpu.fcsr; 516f8447436STianrui Zhao for (i = 0; i < 32; i++) { 517f8447436STianrui Zhao env->fpr[i].vreg.UD[0] = fpu.fpr[i].val64[0]; 51807c08661SSong Gao env->fpr[i].vreg.UD[1] = fpu.fpr[i].val64[1]; 51907c08661SSong Gao env->fpr[i].vreg.UD[2] = fpu.fpr[i].val64[2]; 52007c08661SSong Gao env->fpr[i].vreg.UD[3] = fpu.fpr[i].val64[3]; 521f8447436STianrui Zhao } 522f8447436STianrui Zhao for (i = 0; i < 8; i++) { 523f8447436STianrui Zhao env->cf[i] = fpu.fcc & 0xFF; 524f8447436STianrui Zhao fpu.fcc = fpu.fcc >> 8; 525f8447436STianrui Zhao } 526f8447436STianrui Zhao 527f8447436STianrui Zhao return ret; 528f8447436STianrui Zhao } 529f8447436STianrui Zhao 530f8447436STianrui Zhao static int kvm_loongarch_put_regs_fp(CPUState *cs) 531f8447436STianrui Zhao { 532f8447436STianrui Zhao int ret, i; 533f8447436STianrui Zhao struct kvm_fpu fpu; 534f3b603b9SPhilippe Mathieu-Daudé CPULoongArchState *env = cpu_env(cs); 535f8447436STianrui Zhao 536f8447436STianrui Zhao fpu.fcsr = env->fcsr0; 537f8447436STianrui Zhao fpu.fcc = 0; 538f8447436STianrui Zhao for (i = 0; i < 32; i++) { 539f8447436STianrui Zhao fpu.fpr[i].val64[0] = env->fpr[i].vreg.UD[0]; 54007c08661SSong Gao fpu.fpr[i].val64[1] = env->fpr[i].vreg.UD[1]; 54107c08661SSong Gao fpu.fpr[i].val64[2] = env->fpr[i].vreg.UD[2]; 54207c08661SSong Gao fpu.fpr[i].val64[3] = env->fpr[i].vreg.UD[3]; 543f8447436STianrui Zhao } 544f8447436STianrui Zhao 545f8447436STianrui Zhao for (i = 0; i < 8; i++) { 546f8447436STianrui Zhao fpu.fcc |= env->cf[i] << (8 * i); 547f8447436STianrui Zhao } 548f8447436STianrui Zhao 549f8447436STianrui Zhao ret = kvm_vcpu_ioctl(cs, KVM_SET_FPU, &fpu); 550f8447436STianrui Zhao if (ret < 0) { 551f8447436STianrui Zhao trace_kvm_failed_put_fpu(strerror(errno)); 552f8447436STianrui Zhao } 553f8447436STianrui Zhao 554f8447436STianrui Zhao return ret; 555f8447436STianrui Zhao } 556f8447436STianrui Zhao 557a45df286SBibo Mao static int kvm_loongarch_put_lbt(CPUState *cs) 558a45df286SBibo Mao { 559a45df286SBibo Mao CPULoongArchState *env = cpu_env(cs); 560a45df286SBibo Mao uint64_t val; 561a45df286SBibo Mao int ret; 562a45df286SBibo Mao 563a45df286SBibo Mao /* check whether vm support LBT firstly */ 564a45df286SBibo Mao if (FIELD_EX32(env->cpucfg[2], CPUCFG2, LBT_ALL) != 7) { 565a45df286SBibo Mao return 0; 566a45df286SBibo Mao } 567a45df286SBibo Mao 568a45df286SBibo Mao /* set six LBT registers including scr0-scr3, eflags, ftop */ 569a45df286SBibo Mao ret = kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR0, &env->lbt.scr0); 570a45df286SBibo Mao ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR1, &env->lbt.scr1); 571a45df286SBibo Mao ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR2, &env->lbt.scr2); 572a45df286SBibo Mao ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR3, &env->lbt.scr3); 573a45df286SBibo Mao /* 574a45df286SBibo Mao * Be cautious, KVM_REG_LOONGARCH_LBT_FTOP is defined as 64-bit however 575a45df286SBibo Mao * lbt.ftop is 32-bit; the same with KVM_REG_LOONGARCH_LBT_EFLAGS register 576a45df286SBibo Mao */ 577a45df286SBibo Mao val = env->lbt.eflags; 578a45df286SBibo Mao ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_EFLAGS, &val); 579a45df286SBibo Mao val = env->lbt.ftop; 580a45df286SBibo Mao ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_FTOP, &val); 581a45df286SBibo Mao 582a45df286SBibo Mao return ret; 583a45df286SBibo Mao } 584a45df286SBibo Mao 585a45df286SBibo Mao static int kvm_loongarch_get_lbt(CPUState *cs) 586a45df286SBibo Mao { 587a45df286SBibo Mao CPULoongArchState *env = cpu_env(cs); 588a45df286SBibo Mao uint64_t val; 589a45df286SBibo Mao int ret; 590a45df286SBibo Mao 591a45df286SBibo Mao /* check whether vm support LBT firstly */ 592a45df286SBibo Mao if (FIELD_EX32(env->cpucfg[2], CPUCFG2, LBT_ALL) != 7) { 593a45df286SBibo Mao return 0; 594a45df286SBibo Mao } 595a45df286SBibo Mao 596a45df286SBibo Mao /* get six LBT registers including scr0-scr3, eflags, ftop */ 597a45df286SBibo Mao ret = kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR0, &env->lbt.scr0); 598a45df286SBibo Mao ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR1, &env->lbt.scr1); 599a45df286SBibo Mao ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR2, &env->lbt.scr2); 600a45df286SBibo Mao ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR3, &env->lbt.scr3); 601a45df286SBibo Mao ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_EFLAGS, &val); 602a45df286SBibo Mao env->lbt.eflags = (uint32_t)val; 603a45df286SBibo Mao ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_FTOP, &val); 604a45df286SBibo Mao env->lbt.ftop = (uint32_t)val; 605a45df286SBibo Mao 606a45df286SBibo Mao return ret; 607a45df286SBibo Mao } 608a45df286SBibo Mao 609a724f5a8SBibo Mao void kvm_arch_reset_vcpu(CPUState *cs) 610f8447436STianrui Zhao { 611a724f5a8SBibo Mao CPULoongArchState *env = cpu_env(cs); 612b61b9d89SXianglai Li int ret = 0; 613b61b9d89SXianglai Li uint64_t unused = 0; 614a724f5a8SBibo Mao 615f8447436STianrui Zhao env->mp_state = KVM_MP_STATE_RUNNABLE; 616b61b9d89SXianglai Li ret = kvm_set_one_reg(cs, KVM_REG_LOONGARCH_VCPU_RESET, &unused); 617b61b9d89SXianglai Li if (ret) { 618b61b9d89SXianglai Li error_report("Failed to set KVM_REG_LOONGARCH_VCPU_RESET: %s", 619b61b9d89SXianglai Li strerror(errno)); 620b61b9d89SXianglai Li exit(EXIT_FAILURE); 621b61b9d89SXianglai Li } 622f8447436STianrui Zhao } 623f8447436STianrui Zhao 624f8447436STianrui Zhao static int kvm_loongarch_get_mpstate(CPUState *cs) 625f8447436STianrui Zhao { 626f8447436STianrui Zhao int ret = 0; 627f8447436STianrui Zhao struct kvm_mp_state mp_state; 628f3b603b9SPhilippe Mathieu-Daudé CPULoongArchState *env = cpu_env(cs); 629f8447436STianrui Zhao 630f8447436STianrui Zhao if (cap_has_mp_state) { 631f8447436STianrui Zhao ret = kvm_vcpu_ioctl(cs, KVM_GET_MP_STATE, &mp_state); 632f8447436STianrui Zhao if (ret) { 633f8447436STianrui Zhao trace_kvm_failed_get_mpstate(strerror(errno)); 634f8447436STianrui Zhao return ret; 635f8447436STianrui Zhao } 636f8447436STianrui Zhao env->mp_state = mp_state.mp_state; 637f8447436STianrui Zhao } 638f8447436STianrui Zhao 639f8447436STianrui Zhao return ret; 640f8447436STianrui Zhao } 641f8447436STianrui Zhao 642f8447436STianrui Zhao static int kvm_loongarch_put_mpstate(CPUState *cs) 643f8447436STianrui Zhao { 644f8447436STianrui Zhao int ret = 0; 645f8447436STianrui Zhao struct kvm_mp_state mp_state = { 646f3b603b9SPhilippe Mathieu-Daudé .mp_state = cpu_env(cs)->mp_state 647f8447436STianrui Zhao }; 648f8447436STianrui Zhao 649f8447436STianrui Zhao if (cap_has_mp_state) { 650f8447436STianrui Zhao ret = kvm_vcpu_ioctl(cs, KVM_SET_MP_STATE, &mp_state); 651f8447436STianrui Zhao if (ret) { 652f8447436STianrui Zhao trace_kvm_failed_put_mpstate(strerror(errno)); 653f8447436STianrui Zhao } 654f8447436STianrui Zhao } 655f8447436STianrui Zhao 656f8447436STianrui Zhao return ret; 657f8447436STianrui Zhao } 658f8447436STianrui Zhao 659f8447436STianrui Zhao static int kvm_loongarch_get_cpucfg(CPUState *cs) 660f8447436STianrui Zhao { 661f8447436STianrui Zhao int i, ret = 0; 662f8447436STianrui Zhao uint64_t val; 663f3b603b9SPhilippe Mathieu-Daudé CPULoongArchState *env = cpu_env(cs); 664f8447436STianrui Zhao 665f8447436STianrui Zhao for (i = 0; i < 21; i++) { 666f8447436STianrui Zhao ret = kvm_get_one_reg(cs, KVM_IOC_CPUCFG(i), &val); 667f8447436STianrui Zhao if (ret < 0) { 668f8447436STianrui Zhao trace_kvm_failed_get_cpucfg(strerror(errno)); 669f8447436STianrui Zhao } 670f8447436STianrui Zhao env->cpucfg[i] = (uint32_t)val; 671f8447436STianrui Zhao } 672f8447436STianrui Zhao return ret; 673f8447436STianrui Zhao } 674f8447436STianrui Zhao 675fc700996SSong Gao static int kvm_check_cpucfg2(CPUState *cs) 676fc700996SSong Gao { 677fc700996SSong Gao int ret; 678fc700996SSong Gao uint64_t val; 679fc700996SSong Gao struct kvm_device_attr attr = { 680fc700996SSong Gao .group = KVM_LOONGARCH_VCPU_CPUCFG, 681fc700996SSong Gao .attr = 2, 682fc700996SSong Gao .addr = (uint64_t)&val, 683fc700996SSong Gao }; 684f3b603b9SPhilippe Mathieu-Daudé CPULoongArchState *env = cpu_env(cs); 685fc700996SSong Gao 686fc700996SSong Gao ret = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, &attr); 687fc700996SSong Gao 688fc700996SSong Gao if (!ret) { 689fc700996SSong Gao kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, &attr); 690fc700996SSong Gao env->cpucfg[2] &= val; 691fc700996SSong Gao 692fc700996SSong Gao if (FIELD_EX32(env->cpucfg[2], CPUCFG2, FP)) { 693fc700996SSong Gao /* The FP minimal version is 1. */ 694fc700996SSong Gao env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, FP_VER, 1); 695fc700996SSong Gao } 696fc700996SSong Gao 697fc700996SSong Gao if (FIELD_EX32(env->cpucfg[2], CPUCFG2, LLFTP)) { 698fc700996SSong Gao /* The LLFTP minimal version is 1. */ 699fc700996SSong Gao env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LLFTP_VER, 1); 700fc700996SSong Gao } 701fc700996SSong Gao } 702fc700996SSong Gao 703fc700996SSong Gao return ret; 704fc700996SSong Gao } 705fc700996SSong Gao 706f8447436STianrui Zhao static int kvm_loongarch_put_cpucfg(CPUState *cs) 707f8447436STianrui Zhao { 708f8447436STianrui Zhao int i, ret = 0; 709f3b603b9SPhilippe Mathieu-Daudé CPULoongArchState *env = cpu_env(cs); 710f8447436STianrui Zhao uint64_t val; 711f8447436STianrui Zhao 712f8447436STianrui Zhao for (i = 0; i < 21; i++) { 713f8447436STianrui Zhao if (i == 2) { 714fc700996SSong Gao ret = kvm_check_cpucfg2(cs); 715fc700996SSong Gao if (ret) { 716fc700996SSong Gao return ret; 717f8447436STianrui Zhao } 718fc700996SSong Gao } 719fc700996SSong Gao val = env->cpucfg[i]; 720f8447436STianrui Zhao ret = kvm_set_one_reg(cs, KVM_IOC_CPUCFG(i), &val); 721f8447436STianrui Zhao if (ret < 0) { 722f8447436STianrui Zhao trace_kvm_failed_put_cpucfg(strerror(errno)); 723f8447436STianrui Zhao } 724f8447436STianrui Zhao } 725f8447436STianrui Zhao return ret; 726f8447436STianrui Zhao } 727f8447436STianrui Zhao 728a1676bb3SJulia Suvorova int kvm_arch_get_registers(CPUState *cs, Error **errp) 729537ba9daSTianrui Zhao { 730f8447436STianrui Zhao int ret; 731f8447436STianrui Zhao 732f8447436STianrui Zhao ret = kvm_loongarch_get_regs_core(cs); 733f8447436STianrui Zhao if (ret) { 734f8447436STianrui Zhao return ret; 735537ba9daSTianrui Zhao } 736f8447436STianrui Zhao 7375872966dSBibo Mao ret = kvm_loongarch_get_cpucfg(cs); 7385872966dSBibo Mao if (ret) { 7395872966dSBibo Mao return ret; 7405872966dSBibo Mao } 7415872966dSBibo Mao 742f8447436STianrui Zhao ret = kvm_loongarch_get_csr(cs); 743f8447436STianrui Zhao if (ret) { 744f8447436STianrui Zhao return ret; 745f8447436STianrui Zhao } 746f8447436STianrui Zhao 747f8447436STianrui Zhao ret = kvm_loongarch_get_regs_fp(cs); 748f8447436STianrui Zhao if (ret) { 749f8447436STianrui Zhao return ret; 750f8447436STianrui Zhao } 751f8447436STianrui Zhao 752a45df286SBibo Mao ret = kvm_loongarch_get_lbt(cs); 753a45df286SBibo Mao if (ret) { 754a45df286SBibo Mao return ret; 755a45df286SBibo Mao } 756a45df286SBibo Mao 75747b54e15SBibo Mao ret = kvm_get_stealtime(cs); 75847b54e15SBibo Mao if (ret) { 75947b54e15SBibo Mao return ret; 76047b54e15SBibo Mao } 76147b54e15SBibo Mao 762f8447436STianrui Zhao ret = kvm_loongarch_get_mpstate(cs); 763f8447436STianrui Zhao return ret; 764f8447436STianrui Zhao } 765f8447436STianrui Zhao 766a1676bb3SJulia Suvorova int kvm_arch_put_registers(CPUState *cs, int level, Error **errp) 767537ba9daSTianrui Zhao { 768f8447436STianrui Zhao int ret; 7692698cc7cSBibo Mao static int once; 770f8447436STianrui Zhao 771f8447436STianrui Zhao ret = kvm_loongarch_put_regs_core(cs); 772f8447436STianrui Zhao if (ret) { 773f8447436STianrui Zhao return ret; 774f8447436STianrui Zhao } 775f8447436STianrui Zhao 7765872966dSBibo Mao ret = kvm_loongarch_put_cpucfg(cs); 7775872966dSBibo Mao if (ret) { 7785872966dSBibo Mao return ret; 7795872966dSBibo Mao } 7805872966dSBibo Mao 78161f6e150SBibo Mao ret = kvm_loongarch_put_csr(cs, level); 782f8447436STianrui Zhao if (ret) { 783f8447436STianrui Zhao return ret; 784f8447436STianrui Zhao } 785f8447436STianrui Zhao 786f8447436STianrui Zhao ret = kvm_loongarch_put_regs_fp(cs); 787f8447436STianrui Zhao if (ret) { 788f8447436STianrui Zhao return ret; 789f8447436STianrui Zhao } 790f8447436STianrui Zhao 791a45df286SBibo Mao ret = kvm_loongarch_put_lbt(cs); 792a45df286SBibo Mao if (ret) { 793a45df286SBibo Mao return ret; 794a45df286SBibo Mao } 795a45df286SBibo Mao 7962698cc7cSBibo Mao if (!once) { 7972698cc7cSBibo Mao ret = kvm_set_pv_features(cs); 7982698cc7cSBibo Mao if (ret) { 7992698cc7cSBibo Mao return ret; 8002698cc7cSBibo Mao } 8012698cc7cSBibo Mao once = 1; 8022698cc7cSBibo Mao } 8032698cc7cSBibo Mao 80447b54e15SBibo Mao if (level >= KVM_PUT_FULL_STATE) { 80547b54e15SBibo Mao /* 80647b54e15SBibo Mao * only KVM_PUT_FULL_STATE is required, kvm kernel will clear 80747b54e15SBibo Mao * guest_addr for KVM_PUT_RESET_STATE 80847b54e15SBibo Mao */ 80947b54e15SBibo Mao ret = kvm_set_stealtime(cs); 81047b54e15SBibo Mao if (ret) { 81147b54e15SBibo Mao return ret; 81247b54e15SBibo Mao } 81347b54e15SBibo Mao } 81447b54e15SBibo Mao 815f8447436STianrui Zhao ret = kvm_loongarch_put_mpstate(cs); 816f8447436STianrui Zhao return ret; 817537ba9daSTianrui Zhao } 818537ba9daSTianrui Zhao 819d11681c9STianrui Zhao static void kvm_loongarch_vm_stage_change(void *opaque, bool running, 820d11681c9STianrui Zhao RunState state) 821d11681c9STianrui Zhao { 822d11681c9STianrui Zhao int ret; 823d11681c9STianrui Zhao CPUState *cs = opaque; 824d11681c9STianrui Zhao LoongArchCPU *cpu = LOONGARCH_CPU(cs); 825d11681c9STianrui Zhao 826d11681c9STianrui Zhao if (running) { 827d11681c9STianrui Zhao ret = kvm_set_one_reg(cs, KVM_REG_LOONGARCH_COUNTER, 828d11681c9STianrui Zhao &cpu->kvm_state_counter); 829d11681c9STianrui Zhao if (ret < 0) { 830d11681c9STianrui Zhao trace_kvm_failed_put_counter(strerror(errno)); 831d11681c9STianrui Zhao } 832d11681c9STianrui Zhao } else { 833d11681c9STianrui Zhao ret = kvm_get_one_reg(cs, KVM_REG_LOONGARCH_COUNTER, 834d11681c9STianrui Zhao &cpu->kvm_state_counter); 835d11681c9STianrui Zhao if (ret < 0) { 836d11681c9STianrui Zhao trace_kvm_failed_get_counter(strerror(errno)); 837d11681c9STianrui Zhao } 838d11681c9STianrui Zhao } 839d11681c9STianrui Zhao } 840d11681c9STianrui Zhao 841c23a53d8SBibo Mao static bool kvm_feature_supported(CPUState *cs, enum loongarch_features feature) 842c23a53d8SBibo Mao { 843c23a53d8SBibo Mao int ret; 844c23a53d8SBibo Mao struct kvm_device_attr attr; 845936c3f4dSBibo Mao uint64_t val; 846c23a53d8SBibo Mao 847c23a53d8SBibo Mao switch (feature) { 848936c3f4dSBibo Mao case LOONGARCH_FEATURE_LSX: 849936c3f4dSBibo Mao attr.group = KVM_LOONGARCH_VM_FEAT_CTRL; 850936c3f4dSBibo Mao attr.attr = KVM_LOONGARCH_VM_FEAT_LSX; 851936c3f4dSBibo Mao ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr); 852936c3f4dSBibo Mao if (ret == 0) { 853936c3f4dSBibo Mao return true; 854936c3f4dSBibo Mao } 855936c3f4dSBibo Mao 856936c3f4dSBibo Mao /* Fallback to old kernel detect interface */ 857936c3f4dSBibo Mao val = 0; 858936c3f4dSBibo Mao attr.group = KVM_LOONGARCH_VCPU_CPUCFG; 859936c3f4dSBibo Mao /* Cpucfg2 */ 860936c3f4dSBibo Mao attr.attr = 2; 861936c3f4dSBibo Mao attr.addr = (uint64_t)&val; 862936c3f4dSBibo Mao ret = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, &attr); 863936c3f4dSBibo Mao if (!ret) { 864936c3f4dSBibo Mao ret = kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, &attr); 865936c3f4dSBibo Mao if (ret) { 866936c3f4dSBibo Mao return false; 867936c3f4dSBibo Mao } 868936c3f4dSBibo Mao 869936c3f4dSBibo Mao ret = FIELD_EX32((uint32_t)val, CPUCFG2, LSX); 870936c3f4dSBibo Mao return (ret != 0); 871936c3f4dSBibo Mao } 872936c3f4dSBibo Mao return false; 873936c3f4dSBibo Mao 8745e360dabSBibo Mao case LOONGARCH_FEATURE_LASX: 8755e360dabSBibo Mao attr.group = KVM_LOONGARCH_VM_FEAT_CTRL; 8765e360dabSBibo Mao attr.attr = KVM_LOONGARCH_VM_FEAT_LASX; 8775e360dabSBibo Mao ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr); 8785e360dabSBibo Mao if (ret == 0) { 8795e360dabSBibo Mao return true; 8805e360dabSBibo Mao } 8815e360dabSBibo Mao 8825e360dabSBibo Mao /* Fallback to old kernel detect interface */ 8835e360dabSBibo Mao val = 0; 8845e360dabSBibo Mao attr.group = KVM_LOONGARCH_VCPU_CPUCFG; 8855e360dabSBibo Mao /* Cpucfg2 */ 8865e360dabSBibo Mao attr.attr = 2; 8875e360dabSBibo Mao attr.addr = (uint64_t)&val; 8885e360dabSBibo Mao ret = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, &attr); 8895e360dabSBibo Mao if (!ret) { 8905e360dabSBibo Mao ret = kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, &attr); 8915e360dabSBibo Mao if (ret) { 8925e360dabSBibo Mao return false; 8935e360dabSBibo Mao } 8945e360dabSBibo Mao 8955e360dabSBibo Mao ret = FIELD_EX32((uint32_t)val, CPUCFG2, LASX); 8965e360dabSBibo Mao return (ret != 0); 8975e360dabSBibo Mao } 8985e360dabSBibo Mao return false; 8995e360dabSBibo Mao 900c23a53d8SBibo Mao case LOONGARCH_FEATURE_LBT: 901c23a53d8SBibo Mao /* 902c23a53d8SBibo Mao * Return all if all the LBT features are supported such as: 903c23a53d8SBibo Mao * KVM_LOONGARCH_VM_FEAT_X86BT 904c23a53d8SBibo Mao * KVM_LOONGARCH_VM_FEAT_ARMBT 905c23a53d8SBibo Mao * KVM_LOONGARCH_VM_FEAT_MIPSBT 906c23a53d8SBibo Mao */ 907c23a53d8SBibo Mao attr.group = KVM_LOONGARCH_VM_FEAT_CTRL; 908c23a53d8SBibo Mao attr.attr = KVM_LOONGARCH_VM_FEAT_X86BT; 909c23a53d8SBibo Mao ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr); 910c23a53d8SBibo Mao attr.attr = KVM_LOONGARCH_VM_FEAT_ARMBT; 911c23a53d8SBibo Mao ret |= kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr); 912c23a53d8SBibo Mao attr.attr = KVM_LOONGARCH_VM_FEAT_MIPSBT; 913c23a53d8SBibo Mao ret |= kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr); 914c23a53d8SBibo Mao return (ret == 0); 9156edd2a9bSBibo Mao 9166edd2a9bSBibo Mao case LOONGARCH_FEATURE_PMU: 9176edd2a9bSBibo Mao attr.group = KVM_LOONGARCH_VM_FEAT_CTRL; 9186edd2a9bSBibo Mao attr.attr = KVM_LOONGARCH_VM_FEAT_PMU; 9196edd2a9bSBibo Mao ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr); 9206edd2a9bSBibo Mao return (ret == 0); 9216edd2a9bSBibo Mao 922620d9bd0SBibo Mao case LOONGARCH_FEATURE_PV_IPI: 923620d9bd0SBibo Mao attr.group = KVM_LOONGARCH_VM_FEAT_CTRL; 924620d9bd0SBibo Mao attr.attr = KVM_LOONGARCH_VM_FEAT_PV_IPI; 925620d9bd0SBibo Mao ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr); 926620d9bd0SBibo Mao return (ret == 0); 927620d9bd0SBibo Mao 928954cc5c3SBibo Mao case LOONGARCH_FEATURE_STEALTIME: 929954cc5c3SBibo Mao attr.group = KVM_LOONGARCH_VM_FEAT_CTRL; 930954cc5c3SBibo Mao attr.attr = KVM_LOONGARCH_VM_FEAT_PV_STEALTIME; 931954cc5c3SBibo Mao ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr); 932954cc5c3SBibo Mao return (ret == 0); 933954cc5c3SBibo Mao 934c23a53d8SBibo Mao default: 935c23a53d8SBibo Mao return false; 936c23a53d8SBibo Mao } 9376edd2a9bSBibo Mao 9386edd2a9bSBibo Mao return false; 939c23a53d8SBibo Mao } 940c23a53d8SBibo Mao 941936c3f4dSBibo Mao static int kvm_cpu_check_lsx(CPUState *cs, Error **errp) 942936c3f4dSBibo Mao { 943936c3f4dSBibo Mao CPULoongArchState *env = cpu_env(cs); 944936c3f4dSBibo Mao LoongArchCPU *cpu = LOONGARCH_CPU(cs); 945936c3f4dSBibo Mao bool kvm_supported; 946936c3f4dSBibo Mao 947936c3f4dSBibo Mao kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_LSX); 948936c3f4dSBibo Mao env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LSX, 0); 949936c3f4dSBibo Mao if (cpu->lsx == ON_OFF_AUTO_ON) { 950936c3f4dSBibo Mao if (kvm_supported) { 951936c3f4dSBibo Mao env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LSX, 1); 952936c3f4dSBibo Mao } else { 953936c3f4dSBibo Mao error_setg(errp, "'lsx' feature not supported by KVM on this host"); 954936c3f4dSBibo Mao return -ENOTSUP; 955936c3f4dSBibo Mao } 956936c3f4dSBibo Mao } else if ((cpu->lsx == ON_OFF_AUTO_AUTO) && kvm_supported) { 957936c3f4dSBibo Mao env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LSX, 1); 958936c3f4dSBibo Mao } 959936c3f4dSBibo Mao 960936c3f4dSBibo Mao return 0; 961936c3f4dSBibo Mao } 962936c3f4dSBibo Mao 9635e360dabSBibo Mao static int kvm_cpu_check_lasx(CPUState *cs, Error **errp) 9645e360dabSBibo Mao { 9655e360dabSBibo Mao CPULoongArchState *env = cpu_env(cs); 9665e360dabSBibo Mao LoongArchCPU *cpu = LOONGARCH_CPU(cs); 9675e360dabSBibo Mao bool kvm_supported; 9685e360dabSBibo Mao 9695e360dabSBibo Mao kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_LASX); 9705e360dabSBibo Mao env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LASX, 0); 9715e360dabSBibo Mao if (cpu->lasx == ON_OFF_AUTO_ON) { 9725e360dabSBibo Mao if (kvm_supported) { 9735e360dabSBibo Mao env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LASX, 1); 9745e360dabSBibo Mao } else { 9755e360dabSBibo Mao error_setg(errp, "'lasx' feature not supported by KVM on host"); 9765e360dabSBibo Mao return -ENOTSUP; 9775e360dabSBibo Mao } 9785e360dabSBibo Mao } else if ((cpu->lasx == ON_OFF_AUTO_AUTO) && kvm_supported) { 9795e360dabSBibo Mao env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LASX, 1); 9805e360dabSBibo Mao } 9815e360dabSBibo Mao 9825e360dabSBibo Mao return 0; 9835e360dabSBibo Mao } 9845e360dabSBibo Mao 985c23a53d8SBibo Mao static int kvm_cpu_check_lbt(CPUState *cs, Error **errp) 986c23a53d8SBibo Mao { 987c23a53d8SBibo Mao CPULoongArchState *env = cpu_env(cs); 988c23a53d8SBibo Mao LoongArchCPU *cpu = LOONGARCH_CPU(cs); 989c23a53d8SBibo Mao bool kvm_supported; 990c23a53d8SBibo Mao 991c23a53d8SBibo Mao kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_LBT); 992c23a53d8SBibo Mao if (cpu->lbt == ON_OFF_AUTO_ON) { 993c23a53d8SBibo Mao if (kvm_supported) { 994c23a53d8SBibo Mao env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LBT_ALL, 7); 995c23a53d8SBibo Mao } else { 996c23a53d8SBibo Mao error_setg(errp, "'lbt' feature not supported by KVM on this host"); 997c23a53d8SBibo Mao return -ENOTSUP; 998c23a53d8SBibo Mao } 999c23a53d8SBibo Mao } else if ((cpu->lbt == ON_OFF_AUTO_AUTO) && kvm_supported) { 1000c23a53d8SBibo Mao env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LBT_ALL, 7); 1001c23a53d8SBibo Mao } 1002c23a53d8SBibo Mao 1003c23a53d8SBibo Mao return 0; 1004c23a53d8SBibo Mao } 1005c23a53d8SBibo Mao 10066edd2a9bSBibo Mao static int kvm_cpu_check_pmu(CPUState *cs, Error **errp) 10076edd2a9bSBibo Mao { 10086edd2a9bSBibo Mao LoongArchCPU *cpu = LOONGARCH_CPU(cs); 10096edd2a9bSBibo Mao CPULoongArchState *env = cpu_env(cs); 10106edd2a9bSBibo Mao bool kvm_supported; 10116edd2a9bSBibo Mao 10126edd2a9bSBibo Mao kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_PMU); 10136edd2a9bSBibo Mao if (cpu->pmu == ON_OFF_AUTO_ON) { 10146edd2a9bSBibo Mao if (!kvm_supported) { 10156edd2a9bSBibo Mao error_setg(errp, "'pmu' feature not supported by KVM on the host"); 10166edd2a9bSBibo Mao return -ENOTSUP; 10176edd2a9bSBibo Mao } 10186edd2a9bSBibo Mao } else if (cpu->pmu != ON_OFF_AUTO_AUTO) { 10196edd2a9bSBibo Mao /* disable pmu if ON_OFF_AUTO_OFF is set */ 10206edd2a9bSBibo Mao kvm_supported = false; 10216edd2a9bSBibo Mao } 10226edd2a9bSBibo Mao 10236edd2a9bSBibo Mao if (kvm_supported) { 10246edd2a9bSBibo Mao env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, PMP, 1); 10256edd2a9bSBibo Mao env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, PMNUM, 3); 10266edd2a9bSBibo Mao env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, PMBITS, 63); 10276edd2a9bSBibo Mao env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, UPM, 1); 10286edd2a9bSBibo Mao } 10296edd2a9bSBibo Mao return 0; 10306edd2a9bSBibo Mao } 10316edd2a9bSBibo Mao 1032620d9bd0SBibo Mao static int kvm_cpu_check_pv_features(CPUState *cs, Error **errp) 1033620d9bd0SBibo Mao { 1034*db369c11SBibo Mao MachineState *ms = MACHINE(qdev_get_machine()); 1035620d9bd0SBibo Mao LoongArchCPU *cpu = LOONGARCH_CPU(cs); 1036620d9bd0SBibo Mao CPULoongArchState *env = cpu_env(cs); 1037620d9bd0SBibo Mao bool kvm_supported; 1038620d9bd0SBibo Mao 1039620d9bd0SBibo Mao kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_PV_IPI); 1040620d9bd0SBibo Mao if (cpu->kvm_pv_ipi == ON_OFF_AUTO_ON) { 1041620d9bd0SBibo Mao if (!kvm_supported) { 1042620d9bd0SBibo Mao error_setg(errp, "'pv_ipi' feature not supported by KVM host"); 1043620d9bd0SBibo Mao return -ENOTSUP; 1044620d9bd0SBibo Mao } 1045620d9bd0SBibo Mao } else if (cpu->kvm_pv_ipi != ON_OFF_AUTO_AUTO) { 1046620d9bd0SBibo Mao kvm_supported = false; 1047620d9bd0SBibo Mao } 1048620d9bd0SBibo Mao 1049620d9bd0SBibo Mao if (kvm_supported) { 1050620d9bd0SBibo Mao env->pv_features |= BIT(KVM_FEATURE_IPI); 1051620d9bd0SBibo Mao } 1052620d9bd0SBibo Mao 1053954cc5c3SBibo Mao kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_STEALTIME); 1054954cc5c3SBibo Mao if (cpu->kvm_steal_time == ON_OFF_AUTO_ON) { 1055954cc5c3SBibo Mao if (!kvm_supported) { 1056954cc5c3SBibo Mao error_setg(errp, "'kvm stealtime' feature not supported by KVM host"); 1057954cc5c3SBibo Mao return -ENOTSUP; 1058954cc5c3SBibo Mao } 1059954cc5c3SBibo Mao } else if (cpu->kvm_steal_time != ON_OFF_AUTO_AUTO) { 1060954cc5c3SBibo Mao kvm_supported = false; 1061954cc5c3SBibo Mao } 1062954cc5c3SBibo Mao 1063954cc5c3SBibo Mao if (kvm_supported) { 1064954cc5c3SBibo Mao env->pv_features |= BIT(KVM_FEATURE_STEAL_TIME); 1065954cc5c3SBibo Mao } 1066954cc5c3SBibo Mao 1067*db369c11SBibo Mao if (object_dynamic_cast(OBJECT(ms), TYPE_LOONGARCH_VIRT_MACHINE)) { 1068*db369c11SBibo Mao LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(ms); 1069*db369c11SBibo Mao 1070*db369c11SBibo Mao if (virt_is_veiointc_enabled(lvms)) { 1071*db369c11SBibo Mao env->pv_features |= BIT(KVM_FEATURE_VIRT_EXTIOI); 1072*db369c11SBibo Mao } 1073*db369c11SBibo Mao } 1074*db369c11SBibo Mao 1075620d9bd0SBibo Mao return 0; 1076620d9bd0SBibo Mao } 1077620d9bd0SBibo Mao 1078537ba9daSTianrui Zhao int kvm_arch_init_vcpu(CPUState *cs) 1079537ba9daSTianrui Zhao { 1080d38e31efSBibo Mao uint64_t val; 1081c23a53d8SBibo Mao int ret; 1082c23a53d8SBibo Mao Error *local_err = NULL; 1083d38e31efSBibo Mao 1084c23a53d8SBibo Mao ret = 0; 1085d11681c9STianrui Zhao qemu_add_vm_change_state_handler(kvm_loongarch_vm_stage_change, cs); 1086d38e31efSBibo Mao 1087d38e31efSBibo Mao if (!kvm_get_one_reg(cs, KVM_REG_LOONGARCH_DEBUG_INST, &val)) { 1088d38e31efSBibo Mao brk_insn = val; 1089d38e31efSBibo Mao } 1090d38e31efSBibo Mao 1091936c3f4dSBibo Mao ret = kvm_cpu_check_lsx(cs, &local_err); 1092936c3f4dSBibo Mao if (ret < 0) { 1093936c3f4dSBibo Mao error_report_err(local_err); 1094936c3f4dSBibo Mao } 1095936c3f4dSBibo Mao 10965e360dabSBibo Mao ret = kvm_cpu_check_lasx(cs, &local_err); 10975e360dabSBibo Mao if (ret < 0) { 10985e360dabSBibo Mao error_report_err(local_err); 10995e360dabSBibo Mao } 11005e360dabSBibo Mao 1101c23a53d8SBibo Mao ret = kvm_cpu_check_lbt(cs, &local_err); 1102c23a53d8SBibo Mao if (ret < 0) { 1103c23a53d8SBibo Mao error_report_err(local_err); 1104c23a53d8SBibo Mao } 11056edd2a9bSBibo Mao 11066edd2a9bSBibo Mao ret = kvm_cpu_check_pmu(cs, &local_err); 11076edd2a9bSBibo Mao if (ret < 0) { 11086edd2a9bSBibo Mao error_report_err(local_err); 11096edd2a9bSBibo Mao } 11106edd2a9bSBibo Mao 1111620d9bd0SBibo Mao ret = kvm_cpu_check_pv_features(cs, &local_err); 1112620d9bd0SBibo Mao if (ret < 0) { 1113620d9bd0SBibo Mao error_report_err(local_err); 1114620d9bd0SBibo Mao } 1115620d9bd0SBibo Mao 1116c23a53d8SBibo Mao return ret; 1117537ba9daSTianrui Zhao } 1118537ba9daSTianrui Zhao 1119780a65bdSBibo Mao static bool loongarch_get_lbt(Object *obj, Error **errp) 1120780a65bdSBibo Mao { 1121780a65bdSBibo Mao return LOONGARCH_CPU(obj)->lbt != ON_OFF_AUTO_OFF; 1122780a65bdSBibo Mao } 1123780a65bdSBibo Mao 1124780a65bdSBibo Mao static void loongarch_set_lbt(Object *obj, bool value, Error **errp) 1125780a65bdSBibo Mao { 1126780a65bdSBibo Mao LoongArchCPU *cpu = LOONGARCH_CPU(obj); 1127780a65bdSBibo Mao 1128780a65bdSBibo Mao cpu->lbt = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF; 1129780a65bdSBibo Mao } 1130780a65bdSBibo Mao 1131780a65bdSBibo Mao static bool loongarch_get_pmu(Object *obj, Error **errp) 1132780a65bdSBibo Mao { 1133780a65bdSBibo Mao return LOONGARCH_CPU(obj)->pmu != ON_OFF_AUTO_OFF; 1134780a65bdSBibo Mao } 1135780a65bdSBibo Mao 1136780a65bdSBibo Mao static void loongarch_set_pmu(Object *obj, bool value, Error **errp) 1137780a65bdSBibo Mao { 1138780a65bdSBibo Mao LoongArchCPU *cpu = LOONGARCH_CPU(obj); 1139780a65bdSBibo Mao 1140780a65bdSBibo Mao cpu->pmu = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF; 1141780a65bdSBibo Mao } 1142780a65bdSBibo Mao 11435b0502c5SBibo Mao static bool kvm_pv_ipi_get(Object *obj, Error **errp) 11445b0502c5SBibo Mao { 11455b0502c5SBibo Mao return LOONGARCH_CPU(obj)->kvm_pv_ipi != ON_OFF_AUTO_OFF; 11465b0502c5SBibo Mao } 11475b0502c5SBibo Mao 11485b0502c5SBibo Mao static void kvm_pv_ipi_set(Object *obj, bool value, Error **errp) 11495b0502c5SBibo Mao { 11505b0502c5SBibo Mao LoongArchCPU *cpu = LOONGARCH_CPU(obj); 11515b0502c5SBibo Mao 11525b0502c5SBibo Mao cpu->kvm_pv_ipi = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF; 11535b0502c5SBibo Mao } 11545b0502c5SBibo Mao 1155610babceSBibo Mao static bool kvm_steal_time_get(Object *obj, Error **errp) 1156610babceSBibo Mao { 1157610babceSBibo Mao return LOONGARCH_CPU(obj)->kvm_steal_time != ON_OFF_AUTO_OFF; 1158610babceSBibo Mao } 1159610babceSBibo Mao 1160610babceSBibo Mao static void kvm_steal_time_set(Object *obj, bool value, Error **errp) 1161610babceSBibo Mao { 1162610babceSBibo Mao LoongArchCPU *cpu = LOONGARCH_CPU(obj); 1163610babceSBibo Mao 1164610babceSBibo Mao cpu->kvm_steal_time = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF; 1165610babceSBibo Mao } 1166610babceSBibo Mao 11673406b001SBibo Mao void kvm_loongarch_cpu_post_init(LoongArchCPU *cpu) 11683406b001SBibo Mao { 1169780a65bdSBibo Mao cpu->lbt = ON_OFF_AUTO_AUTO; 1170780a65bdSBibo Mao object_property_add_bool(OBJECT(cpu), "lbt", loongarch_get_lbt, 1171780a65bdSBibo Mao loongarch_set_lbt); 1172780a65bdSBibo Mao object_property_set_description(OBJECT(cpu), "lbt", 1173780a65bdSBibo Mao "Set off to disable Binary Tranlation."); 1174780a65bdSBibo Mao 1175780a65bdSBibo Mao cpu->pmu = ON_OFF_AUTO_AUTO; 1176780a65bdSBibo Mao object_property_add_bool(OBJECT(cpu), "pmu", loongarch_get_pmu, 1177780a65bdSBibo Mao loongarch_set_pmu); 1178780a65bdSBibo Mao object_property_set_description(OBJECT(cpu), "pmu", 1179780a65bdSBibo Mao "Set off to disable performance monitor unit."); 11805b0502c5SBibo Mao 11815b0502c5SBibo Mao cpu->kvm_pv_ipi = ON_OFF_AUTO_AUTO; 11825b0502c5SBibo Mao object_property_add_bool(OBJECT(cpu), "kvm-pv-ipi", kvm_pv_ipi_get, 11835b0502c5SBibo Mao kvm_pv_ipi_set); 11845b0502c5SBibo Mao object_property_set_description(OBJECT(cpu), "kvm-pv-ipi", 11855b0502c5SBibo Mao "Set off to disable KVM paravirt IPI."); 1186610babceSBibo Mao 1187610babceSBibo Mao cpu->kvm_steal_time = ON_OFF_AUTO_AUTO; 1188610babceSBibo Mao object_property_add_bool(OBJECT(cpu), "kvm-steal-time", kvm_steal_time_get, 1189610babceSBibo Mao kvm_steal_time_set); 1190610babceSBibo Mao object_property_set_description(OBJECT(cpu), "kvm-steal-time", 1191610babceSBibo Mao "Set off to disable KVM steal time."); 11923406b001SBibo Mao } 11933406b001SBibo Mao 1194537ba9daSTianrui Zhao int kvm_arch_destroy_vcpu(CPUState *cs) 1195537ba9daSTianrui Zhao { 1196537ba9daSTianrui Zhao return 0; 1197537ba9daSTianrui Zhao } 1198537ba9daSTianrui Zhao 1199537ba9daSTianrui Zhao unsigned long kvm_arch_vcpu_id(CPUState *cs) 1200537ba9daSTianrui Zhao { 1201537ba9daSTianrui Zhao return cs->cpu_index; 1202537ba9daSTianrui Zhao } 1203537ba9daSTianrui Zhao 1204537ba9daSTianrui Zhao int kvm_arch_release_virq_post(int virq) 1205537ba9daSTianrui Zhao { 1206537ba9daSTianrui Zhao return 0; 1207537ba9daSTianrui Zhao } 1208537ba9daSTianrui Zhao 1209537ba9daSTianrui Zhao int kvm_arch_msi_data_to_gsi(uint32_t data) 1210537ba9daSTianrui Zhao { 1211537ba9daSTianrui Zhao abort(); 1212537ba9daSTianrui Zhao } 1213537ba9daSTianrui Zhao 1214537ba9daSTianrui Zhao int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route, 1215537ba9daSTianrui Zhao uint64_t address, uint32_t data, PCIDevice *dev) 1216537ba9daSTianrui Zhao { 1217537ba9daSTianrui Zhao return 0; 1218537ba9daSTianrui Zhao } 1219537ba9daSTianrui Zhao 1220537ba9daSTianrui Zhao int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route, 1221537ba9daSTianrui Zhao int vector, PCIDevice *dev) 1222537ba9daSTianrui Zhao { 1223537ba9daSTianrui Zhao return 0; 1224537ba9daSTianrui Zhao } 1225537ba9daSTianrui Zhao 1226537ba9daSTianrui Zhao void kvm_arch_init_irq_routing(KVMState *s) 1227537ba9daSTianrui Zhao { 1228537ba9daSTianrui Zhao } 1229537ba9daSTianrui Zhao 1230537ba9daSTianrui Zhao int kvm_arch_get_default_type(MachineState *ms) 1231537ba9daSTianrui Zhao { 1232537ba9daSTianrui Zhao return 0; 1233537ba9daSTianrui Zhao } 1234537ba9daSTianrui Zhao 1235537ba9daSTianrui Zhao int kvm_arch_init(MachineState *ms, KVMState *s) 1236537ba9daSTianrui Zhao { 123741958c99STianrui Zhao cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE); 1238537ba9daSTianrui Zhao return 0; 1239537ba9daSTianrui Zhao } 1240537ba9daSTianrui Zhao 1241537ba9daSTianrui Zhao int kvm_arch_irqchip_create(KVMState *s) 1242537ba9daSTianrui Zhao { 1243537ba9daSTianrui Zhao return 0; 1244537ba9daSTianrui Zhao } 1245537ba9daSTianrui Zhao 1246537ba9daSTianrui Zhao void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) 1247537ba9daSTianrui Zhao { 1248537ba9daSTianrui Zhao } 1249537ba9daSTianrui Zhao 1250537ba9daSTianrui Zhao MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run) 1251537ba9daSTianrui Zhao { 1252537ba9daSTianrui Zhao return MEMTXATTRS_UNSPECIFIED; 1253537ba9daSTianrui Zhao } 1254537ba9daSTianrui Zhao 1255537ba9daSTianrui Zhao int kvm_arch_process_async_events(CPUState *cs) 1256537ba9daSTianrui Zhao { 1257537ba9daSTianrui Zhao return cs->halted; 1258537ba9daSTianrui Zhao } 1259537ba9daSTianrui Zhao 1260537ba9daSTianrui Zhao bool kvm_arch_stop_on_emulation_error(CPUState *cs) 1261537ba9daSTianrui Zhao { 1262537ba9daSTianrui Zhao return true; 1263537ba9daSTianrui Zhao } 1264537ba9daSTianrui Zhao 1265d38e31efSBibo Mao void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg) 1266d38e31efSBibo Mao { 1267d38e31efSBibo Mao if (kvm_sw_breakpoints_active(cpu)) { 1268d38e31efSBibo Mao dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP; 1269d38e31efSBibo Mao } 1270d38e31efSBibo Mao } 1271d38e31efSBibo Mao 1272d38e31efSBibo Mao int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) 1273d38e31efSBibo Mao { 1274d38e31efSBibo Mao if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) || 1275d38e31efSBibo Mao cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk_insn, 4, 1)) { 1276d38e31efSBibo Mao error_report("%s failed", __func__); 1277d38e31efSBibo Mao return -EINVAL; 1278d38e31efSBibo Mao } 1279d38e31efSBibo Mao return 0; 1280d38e31efSBibo Mao } 1281d38e31efSBibo Mao 1282d38e31efSBibo Mao int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) 1283d38e31efSBibo Mao { 1284d38e31efSBibo Mao static uint32_t brk; 1285d38e31efSBibo Mao 1286d38e31efSBibo Mao if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk, 4, 0) || 1287d38e31efSBibo Mao brk != brk_insn || 1288d38e31efSBibo Mao cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 1)) { 1289d38e31efSBibo Mao error_report("%s failed", __func__); 1290d38e31efSBibo Mao return -EINVAL; 1291d38e31efSBibo Mao } 1292d38e31efSBibo Mao return 0; 1293d38e31efSBibo Mao } 1294d38e31efSBibo Mao 1295d38e31efSBibo Mao int kvm_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type) 1296d38e31efSBibo Mao { 1297d38e31efSBibo Mao return -ENOSYS; 1298d38e31efSBibo Mao } 1299d38e31efSBibo Mao 1300d38e31efSBibo Mao int kvm_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type) 1301d38e31efSBibo Mao { 1302d38e31efSBibo Mao return -ENOSYS; 1303d38e31efSBibo Mao } 1304d38e31efSBibo Mao 1305d38e31efSBibo Mao void kvm_arch_remove_all_hw_breakpoints(void) 1306d38e31efSBibo Mao { 1307d38e31efSBibo Mao } 1308d38e31efSBibo Mao 1309d38e31efSBibo Mao static bool kvm_loongarch_handle_debug(CPUState *cs, struct kvm_run *run) 1310d38e31efSBibo Mao { 1311d38e31efSBibo Mao LoongArchCPU *cpu = LOONGARCH_CPU(cs); 1312d38e31efSBibo Mao CPULoongArchState *env = &cpu->env; 1313d38e31efSBibo Mao 1314d38e31efSBibo Mao kvm_cpu_synchronize_state(cs); 1315d38e31efSBibo Mao if (cs->singlestep_enabled) { 1316d38e31efSBibo Mao return true; 1317d38e31efSBibo Mao } 1318d38e31efSBibo Mao 1319d38e31efSBibo Mao if (kvm_find_sw_breakpoint(cs, env->pc)) { 1320d38e31efSBibo Mao return true; 1321d38e31efSBibo Mao } 1322d38e31efSBibo Mao 1323d38e31efSBibo Mao return false; 1324d38e31efSBibo Mao } 1325d38e31efSBibo Mao 1326537ba9daSTianrui Zhao int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) 1327537ba9daSTianrui Zhao { 1328a05a950fSTianrui Zhao int ret = 0; 1329f3b603b9SPhilippe Mathieu-Daudé CPULoongArchState *env = cpu_env(cs); 1330a05a950fSTianrui Zhao MemTxAttrs attrs = {}; 1331a05a950fSTianrui Zhao 1332a05a950fSTianrui Zhao attrs.requester_id = env_cpu(env)->cpu_index; 1333a05a950fSTianrui Zhao 1334a05a950fSTianrui Zhao trace_kvm_arch_handle_exit(run->exit_reason); 1335a05a950fSTianrui Zhao switch (run->exit_reason) { 1336a05a950fSTianrui Zhao case KVM_EXIT_LOONGARCH_IOCSR: 13375e90b8dbSBibo Mao address_space_rw(env->address_space_iocsr, 1338a05a950fSTianrui Zhao run->iocsr_io.phys_addr, 1339a05a950fSTianrui Zhao attrs, 1340a05a950fSTianrui Zhao run->iocsr_io.data, 1341a05a950fSTianrui Zhao run->iocsr_io.len, 1342a05a950fSTianrui Zhao run->iocsr_io.is_write); 1343a05a950fSTianrui Zhao break; 1344d38e31efSBibo Mao 1345d38e31efSBibo Mao case KVM_EXIT_DEBUG: 1346d38e31efSBibo Mao if (kvm_loongarch_handle_debug(cs, run)) { 1347d38e31efSBibo Mao ret = EXCP_DEBUG; 1348d38e31efSBibo Mao } 1349d38e31efSBibo Mao break; 1350d38e31efSBibo Mao 1351a05a950fSTianrui Zhao default: 1352a05a950fSTianrui Zhao ret = -1; 1353a05a950fSTianrui Zhao warn_report("KVM: unknown exit reason %d", run->exit_reason); 1354a05a950fSTianrui Zhao break; 1355a05a950fSTianrui Zhao } 1356a05a950fSTianrui Zhao return ret; 1357537ba9daSTianrui Zhao } 1358537ba9daSTianrui Zhao 13598dcbad51STianrui Zhao int kvm_loongarch_set_interrupt(LoongArchCPU *cpu, int irq, int level) 13608dcbad51STianrui Zhao { 13618dcbad51STianrui Zhao struct kvm_interrupt intr; 13628dcbad51STianrui Zhao CPUState *cs = CPU(cpu); 13638dcbad51STianrui Zhao 13648dcbad51STianrui Zhao if (level) { 13658dcbad51STianrui Zhao intr.irq = irq; 13668dcbad51STianrui Zhao } else { 13678dcbad51STianrui Zhao intr.irq = -irq; 13688dcbad51STianrui Zhao } 13698dcbad51STianrui Zhao 13708dcbad51STianrui Zhao trace_kvm_set_intr(irq, level); 13718dcbad51STianrui Zhao return kvm_vcpu_ioctl(cs, KVM_INTERRUPT, &intr); 13728dcbad51STianrui Zhao } 13738dcbad51STianrui Zhao 1374537ba9daSTianrui Zhao void kvm_arch_accel_class_init(ObjectClass *oc) 1375537ba9daSTianrui Zhao { 1376537ba9daSTianrui Zhao } 1377