diff options
Diffstat (limited to 'target')
57 files changed, 2375 insertions, 1039 deletions
diff --git a/target/arm/cpu.c b/target/arm/cpu.c index a211804fd3..cdbc4cdd01 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1380,17 +1380,10 @@ void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp) return; } - /* - * KVM does not support modifications to this feature. - * We have not registered the cpu properties when KVM - * is in use, so the user will not be able to set them. - */ - if (!kvm_enabled()) { - arm_cpu_pauth_finalize(cpu, &local_err); - if (local_err != NULL) { - error_propagate(errp, local_err); - return; - } + arm_cpu_pauth_finalize(cpu, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; } } @@ -2091,6 +2084,7 @@ static void arm_host_initfn(Object *obj) kvm_arm_set_cpu_features_from_host(cpu); if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { aarch64_add_sve_properties(obj); + aarch64_add_pauth_properties(obj); } #else hvf_arm_set_cpu_features_from_host(cpu); diff --git a/target/arm/cpu.h b/target/arm/cpu.h index e33f37b70a..c6a4d50e82 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1076,6 +1076,7 @@ void aarch64_sve_narrow_vq(CPUARMState *env, unsigned vq); void aarch64_sve_change_el(CPUARMState *env, int old_el, int new_el, bool el0_a64); void aarch64_add_sve_properties(Object *obj); +void aarch64_add_pauth_properties(Object *obj); /* * SVE registers are encoded in KVM's memory in an endianness-invariant format. diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 15245a60a8..8786be7783 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -630,6 +630,15 @@ void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp) int arch_val = 0, impdef_val = 0; uint64_t t; + /* Exit early if PAuth is enabled, and fall through to disable it */ + if (kvm_enabled() && cpu->prop_pauth) { + if (!cpu_isar_feature(aa64_pauth, cpu)) { + error_setg(errp, "'pauth' feature not supported by KVM on this host"); + } + + return; + } + /* TODO: Handle HaveEnhancedPAC, HaveEnhancedPAC2, HaveFPAC. */ if (cpu->prop_pauth) { if (cpu->prop_pauth_impdef) { @@ -655,6 +664,23 @@ static Property arm_cpu_pauth_property = static Property arm_cpu_pauth_impdef_property = DEFINE_PROP_BOOL("pauth-impdef", ARMCPU, prop_pauth_impdef, false); +void aarch64_add_pauth_properties(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + /* Default to PAUTH on, with the architected algorithm on TCG. */ + qdev_property_add_static(DEVICE(obj), &arm_cpu_pauth_property); + if (kvm_enabled()) { + /* + * Mirror PAuth support from the probed sysregs back into the + * property for KVM. Is it just a bit backward? Yes it is! + */ + cpu->prop_pauth = cpu_isar_feature(aa64_pauth, cpu); + } else { + qdev_property_add_static(DEVICE(obj), &arm_cpu_pauth_impdef_property); + } +} + /* -cpu max: if KVM is enabled, like -cpu host (best possible with this host); * otherwise, a CPU with as many features enabled as our emulation supports. * The version of '-cpu max' for qemu-system-arm is defined in cpu.c; @@ -829,13 +855,10 @@ static void aarch64_max_initfn(Object *obj) cpu->dcz_blocksize = 7; /* 512 bytes */ #endif - /* Default to PAUTH on, with the architected algorithm. */ - qdev_property_add_static(DEVICE(obj), &arm_cpu_pauth_property); - qdev_property_add_static(DEVICE(obj), &arm_cpu_pauth_impdef_property); - bitmap_fill(cpu->sve_vq_supported, ARM_MAX_VQ); } + aarch64_add_pauth_properties(obj); aarch64_add_sve_properties(obj); object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq, cpu_max_set_sve_max_vq, NULL, NULL); diff --git a/target/arm/helper.c b/target/arm/helper.c index cfca0f5ba6..6dd241fbef 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -9317,8 +9317,10 @@ uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx, return target_el; } -void arm_log_exception(int idx) +void arm_log_exception(CPUState *cs) { + int idx = cs->exception_index; + if (qemu_loglevel_mask(CPU_LOG_INT)) { const char *exc = NULL; static const char * const excnames[] = { @@ -9352,7 +9354,8 @@ void arm_log_exception(int idx) if (!exc) { exc = "unknown"; } - qemu_log_mask(CPU_LOG_INT, "Taking exception %d [%s]\n", idx, exc); + qemu_log_mask(CPU_LOG_INT, "Taking exception %d [%s] on CPU %d\n", + idx, exc, cs->cpu_index); } } @@ -9655,7 +9658,7 @@ static void arm_cpu_do_interrupt_aarch32_hyp(CPUState *cs) * separately here. * * The vector table entry used is always the 0x14 Hyp mode entry point, - * unless this is an UNDEF/HVC/abort taken from Hyp to Hyp. + * unless this is an UNDEF/SVC/HVC/abort taken from Hyp to Hyp. * The offset applied to the preferred return address is always zero * (see DDI0487C.a section G1.12.3). * PSTATE A/I/F masks are set based only on the SCR.EA/IRQ/FIQ values. @@ -9669,7 +9672,7 @@ static void arm_cpu_do_interrupt_aarch32_hyp(CPUState *cs) addr = 0x04; break; case EXCP_SWI: - addr = 0x14; + addr = 0x08; break; case EXCP_BKPT: /* Fall through to prefetch abort. */ @@ -10185,7 +10188,7 @@ void arm_cpu_do_interrupt(CPUState *cs) assert(!arm_feature(env, ARM_FEATURE_M)); - arm_log_exception(cs->exception_index); + arm_log_exception(cs); qemu_log_mask(CPU_LOG_INT, "...from EL%d to EL%d\n", arm_current_el(env), new_el); if (qemu_loglevel_mask(CPU_LOG_INT) diff --git a/target/arm/internals.h b/target/arm/internals.h index 89f7610ebc..3f05748ea4 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1130,7 +1130,7 @@ bool get_phys_addr(CPUARMState *env, target_ulong address, ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs) __attribute__((nonnull)); -void arm_log_exception(int idx); +void arm_log_exception(CPUState *cs); #endif /* !CONFIG_USER_ONLY */ diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c index e790d6c9a5..71c3ca6971 100644 --- a/target/arm/kvm64.c +++ b/target/arm/kvm64.c @@ -491,6 +491,12 @@ static int read_sys_reg64(int fd, uint64_t *pret, uint64_t id) return ioctl(fd, KVM_GET_ONE_REG, &idreg); } +static bool kvm_arm_pauth_supported(void) +{ + return (kvm_check_extension(kvm_state, KVM_CAP_ARM_PTRAUTH_ADDRESS) && + kvm_check_extension(kvm_state, KVM_CAP_ARM_PTRAUTH_GENERIC)); +} + bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) { /* Identify the feature bits corresponding to the host CPU, and @@ -521,6 +527,17 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) */ struct kvm_vcpu_init init = { .target = -1, }; + /* + * Ask for Pointer Authentication if supported. We can't play the + * SVE trick of synthesising the ID reg as KVM won't tell us + * whether we have the architected or IMPDEF version of PAuth, so + * we have to use the actual ID regs. + */ + if (kvm_arm_pauth_supported()) { + init.features[0] |= (1 << KVM_ARM_VCPU_PTRAUTH_ADDRESS | + 1 << KVM_ARM_VCPU_PTRAUTH_GENERIC); + } + if (!kvm_arm_create_scratch_host_vcpu(cpus_to_try, fdarray, &init)) { return false; } @@ -865,6 +882,10 @@ int kvm_arch_init_vcpu(CPUState *cs) assert(kvm_arm_sve_supported()); cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_SVE; } + if (cpu_isar_feature(aa64_pauth, cpu)) { + cpu->kvm_init_features[0] |= (1 << KVM_ARM_VCPU_PTRAUTH_ADDRESS | + 1 << KVM_ARM_VCPU_PTRAUTH_GENERIC); + } /* Do KVM_ARM_VCPU_INIT ioctl */ ret = kvm_arm_vcpu_init(cs); diff --git a/target/arm/m_helper.c b/target/arm/m_helper.c index 2c9922dc29..b11e927df1 100644 --- a/target/arm/m_helper.c +++ b/target/arm/m_helper.c @@ -2206,7 +2206,7 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs) uint32_t lr; bool ignore_stackfaults; - arm_log_exception(cs->exception_index); + arm_log_exception(cs); /* * For exceptions we just mark as pending on the NVIC, and let that diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 04f2b790c9..9911d7c871 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1455,6 +1455,9 @@ typedef struct CPUX86State { SegmentCache idt; /* only base and limit are used */ target_ulong cr[5]; /* NOTE: cr1 is unused */ + + bool pdptrs_valid; + uint64_t pdptrs[4]; int32_t a20_mask; BNDReg bnd_regs[4]; diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 13f8e30c2a..2c8feb4a6f 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -124,6 +124,7 @@ static uint32_t num_architectural_pmu_fixed_counters; static int has_xsave; static int has_xcrs; static int has_pit_state2; +static int has_sregs2; static int has_exception_payload; static bool has_msr_mcg_ext_ctl; @@ -2324,6 +2325,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) has_xsave = kvm_check_extension(s, KVM_CAP_XSAVE); has_xcrs = kvm_check_extension(s, KVM_CAP_XCRS); has_pit_state2 = kvm_check_extension(s, KVM_CAP_PIT_STATE2); + has_sregs2 = kvm_check_extension(s, KVM_CAP_SREGS2) > 0; hv_vpindex_settable = kvm_check_extension(s, KVM_CAP_HYPERV_VP_INDEX); @@ -2605,11 +2607,11 @@ static int kvm_put_sregs(X86CPU *cpu) CPUX86State *env = &cpu->env; struct kvm_sregs sregs; + /* + * The interrupt_bitmap is ignored because KVM_SET_SREGS is + * always followed by KVM_SET_VCPU_EVENTS. + */ memset(sregs.interrupt_bitmap, 0, sizeof(sregs.interrupt_bitmap)); - if (env->interrupt_injected >= 0) { - sregs.interrupt_bitmap[env->interrupt_injected / 64] |= - (uint64_t)1 << (env->interrupt_injected % 64); - } if ((env->eflags & VM_MASK)) { set_v8086_seg(&sregs.cs, &env->segs[R_CS]); @@ -2650,6 +2652,61 @@ static int kvm_put_sregs(X86CPU *cpu) return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_SREGS, &sregs); } +static int kvm_put_sregs2(X86CPU *cpu) +{ + CPUX86State *env = &cpu->env; + struct kvm_sregs2 sregs; + int i; + + sregs.flags = 0; + + if ((env->eflags & VM_MASK)) { + set_v8086_seg(&sregs.cs, &env->segs[R_CS]); + set_v8086_seg(&sregs.ds, &env->segs[R_DS]); + set_v8086_seg(&sregs.es, &env->segs[R_ES]); + set_v8086_seg(&sregs.fs, &env->segs[R_FS]); + set_v8086_seg(&sregs.gs, &env->segs[R_GS]); + set_v8086_seg(&sregs.ss, &env->segs[R_SS]); + } else { + set_seg(&sregs.cs, &env->segs[R_CS]); + set_seg(&sregs.ds, &env->segs[R_DS]); + set_seg(&sregs.es, &env->segs[R_ES]); + set_seg(&sregs.fs, &env->segs[R_FS]); + set_seg(&sregs.gs, &env->segs[R_GS]); + set_seg(&sregs.ss, &env->segs[R_SS]); + } + + set_seg(&sregs.tr, &env->tr); + set_seg(&sregs.ldt, &env->ldt); + + sregs.idt.limit = env->idt.limit; + sregs.idt.base = env->idt.base; + memset(sregs.idt.padding, 0, sizeof sregs.idt.padding); + sregs.gdt.limit = env->gdt.limit; + sregs.gdt.base = env->gdt.base; + memset(sregs.gdt.padding, 0, sizeof sregs.gdt.padding); + + sregs.cr0 = env->cr[0]; + sregs.cr2 = env->cr[2]; + sregs.cr3 = env->cr[3]; + sregs.cr4 = env->cr[4]; + + sregs.cr8 = cpu_get_apic_tpr(cpu->apic_state); + sregs.apic_base = cpu_get_apic_base(cpu->apic_state); + + sregs.efer = env->efer; + + if (env->pdptrs_valid) { + for (i = 0; i < 4; i++) { + sregs.pdptrs[i] = env->pdptrs[i]; + } + sregs.flags |= KVM_SREGS2_FLAGS_PDPTRS_VALID; + } + + return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_SREGS2, &sregs); +} + + static void kvm_msr_buf_reset(X86CPU *cpu) { memset(cpu->kvm_msr_buf, 0, MSR_BUF_SIZE); @@ -3284,22 +3341,55 @@ static int kvm_get_sregs(X86CPU *cpu) { CPUX86State *env = &cpu->env; struct kvm_sregs sregs; - int bit, i, ret; + int ret; ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_SREGS, &sregs); if (ret < 0) { return ret; } - /* There can only be one pending IRQ set in the bitmap at a time, so try - to find it and save its number instead (-1 for none). */ - env->interrupt_injected = -1; - for (i = 0; i < ARRAY_SIZE(sregs.interrupt_bitmap); i++) { - if (sregs.interrupt_bitmap[i]) { - bit = ctz64(sregs.interrupt_bitmap[i]); - env->interrupt_injected = i * 64 + bit; - break; - } + /* + * The interrupt_bitmap is ignored because KVM_GET_SREGS is + * always preceded by KVM_GET_VCPU_EVENTS. + */ + + get_seg(&env->segs[R_CS], &sregs.cs); + get_seg(&env->segs[R_DS], &sregs.ds); + get_seg(&env->segs[R_ES], &sregs.es); + get_seg(&env->segs[R_FS], &sregs.fs); + get_seg(&env->segs[R_GS], &sregs.gs); + get_seg(&env->segs[R_SS], &sregs.ss); + + get_seg(&env->tr, &sregs.tr); + get_seg(&env->ldt, &sregs.ldt); + + env->idt.limit = sregs.idt.limit; + env->idt.base = sregs.idt.base; + env->gdt.limit = sregs.gdt.limit; + env->gdt.base = sregs.gdt.base; + + env->cr[0] = sregs.cr0; + env->cr[2] = sregs.cr2; + env->cr[3] = sregs.cr3; + env->cr[4] = sregs.cr4; + + env->efer = sregs.efer; + + /* changes to apic base and cr8/tpr are read back via kvm_arch_post_run */ + x86_update_hflags(env); + + return 0; +} + +static int kvm_get_sregs2(X86CPU *cpu) +{ + CPUX86State *env = &cpu->env; + struct kvm_sregs2 sregs; + int i, ret; + + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_SREGS2, &sregs); + if (ret < 0) { + return ret; } get_seg(&env->segs[R_CS], &sregs.cs); @@ -3324,6 +3414,14 @@ static int kvm_get_sregs(X86CPU *cpu) env->efer = sregs.efer; + env->pdptrs_valid = sregs.flags & KVM_SREGS2_FLAGS_PDPTRS_VALID; + + if (env->pdptrs_valid) { + for (i = 0; i < 4; i++) { + env->pdptrs[i] = sregs.pdptrs[i]; + } + } + /* changes to apic base and cr8/tpr are read back via kvm_arch_post_run */ x86_update_hflags(env); @@ -4173,7 +4271,7 @@ int kvm_arch_put_registers(CPUState *cpu, int level) assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu)); /* must be before kvm_put_nested_state so that EFER.SVME is set */ - ret = kvm_put_sregs(x86_cpu); + ret = has_sregs2 ? kvm_put_sregs2(x86_cpu) : kvm_put_sregs(x86_cpu); if (ret < 0) { return ret; } @@ -4278,7 +4376,7 @@ int kvm_arch_get_registers(CPUState *cs) if (ret < 0) { goto out; } - ret = kvm_get_sregs(cpu); + ret = has_sregs2 ? kvm_get_sregs2(cpu) : kvm_get_sregs(cpu); if (ret < 0) { goto out; } diff --git a/target/i386/machine.c b/target/i386/machine.c index 83c2b91529..6202f47793 100644 --- a/target/i386/machine.c +++ b/target/i386/machine.c @@ -1451,6 +1451,34 @@ static const VMStateDescription vmstate_msr_intel_sgx = { .needed = intel_sgx_msrs_needed, .fields = (VMStateField[]) { VMSTATE_UINT64_ARRAY(env.msr_ia32_sgxlepubkeyhash, X86CPU, 4), + VMSTATE_END_OF_LIST() + } + }; + +static bool pdptrs_needed(void *opaque) +{ + X86CPU *cpu = opaque; + CPUX86State *env = &cpu->env; + return env->pdptrs_valid; +} + +static int pdptrs_post_load(void *opaque, int version_id) +{ + X86CPU *cpu = opaque; + CPUX86State *env = &cpu->env; + env->pdptrs_valid = true; + return 0; +} + + +static const VMStateDescription vmstate_pdptrs = { + .name = "cpu/pdptrs", + .version_id = 1, + .minimum_version_id = 1, + .needed = pdptrs_needed, + .post_load = pdptrs_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT64_ARRAY(env.pdptrs, X86CPU, 4), VMSTATE_END_OF_LIST() } }; @@ -1593,6 +1621,7 @@ const VMStateDescription vmstate_x86_cpu = { #endif &vmstate_msr_tsx_ctrl, &vmstate_msr_intel_sgx, + &vmstate_pdptrs, NULL } }; diff --git a/target/openrisc/machine.c b/target/openrisc/machine.c index 6239725c4f..b7d7388640 100644 --- a/target/openrisc/machine.c +++ b/target/openrisc/machine.c @@ -25,7 +25,6 @@ static const VMStateDescription vmstate_tlb_entry = { .name = "tlb_entry", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINTTL(mr, OpenRISCTLBEntry), VMSTATE_UINTTL(tr, OpenRISCTLBEntry), diff --git a/target/ppc/arch_dump.c b/target/ppc/arch_dump.c index bb392f6d88..993740897d 100644 --- a/target/ppc/arch_dump.c +++ b/target/ppc/arch_dump.c @@ -237,7 +237,7 @@ int cpu_get_dump_info(ArchDumpInfo *info, info->d_machine = PPC_ELF_MACHINE; info->d_class = ELFCLASS; - if (ppc_interrupts_little_endian(cpu)) { + if (ppc_interrupts_little_endian(cpu, cpu->env.has_hv_mode)) { info->d_endian = ELFDATA2LSB; } else { info->d_endian = ELFDATA2MSB; diff --git a/target/ppc/cpu-models.c b/target/ppc/cpu-models.c index c9fcb6119f..a2c720cc4d 100644 --- a/target/ppc/cpu-models.c +++ b/target/ppc/cpu-models.c @@ -428,8 +428,6 @@ "PowerPC 601v1") POWERPC_DEF("601_v2", CPU_POWERPC_601_v2, 601v, "PowerPC 601v2") - POWERPC_DEF("602", CPU_POWERPC_602, 602, - "PowerPC 602") POWERPC_DEF("603", CPU_POWERPC_603, 603, "PowerPC 603") POWERPC_DEF("603e_v1.1", CPU_POWERPC_603E_v11, 603E, @@ -636,13 +634,13 @@ "PowerPC 7410 v1.3 (G4)") POWERPC_DEF("7410_v1.4", CPU_POWERPC_7410_v14, 7410, "PowerPC 7410 v1.4 (G4)") - POWERPC_DEF("7448_v1.0", CPU_POWERPC_7448_v10, 7400, + POWERPC_DEF("7448_v1.0", CPU_POWERPC_7448_v10, 7445, "PowerPC 7448 v1.0 (G4)") - POWERPC_DEF("7448_v1.1", CPU_POWERPC_7448_v11, 7400, + POWERPC_DEF("7448_v1.1", CPU_POWERPC_7448_v11, 7445, "PowerPC 7448 v1.1 (G4)") - POWERPC_DEF("7448_v2.0", CPU_POWERPC_7448_v20, 7400, + POWERPC_DEF("7448_v2.0", CPU_POWERPC_7448_v20, 7445, "PowerPC 7448 v2.0 (G4)") - POWERPC_DEF("7448_v2.1", CPU_POWERPC_7448_v21, 7400, + POWERPC_DEF("7448_v2.1", CPU_POWERPC_7448_v21, 7445, "PowerPC 7448 v2.1 (G4)") POWERPC_DEF("7450_v1.0", CPU_POWERPC_7450_v10, 7450, "PowerPC 7450 v1.0 (G4)") @@ -750,7 +748,6 @@ /* PowerPC CPU aliases */ PowerPCCPUAlias ppc_cpu_aliases[] = { - { "403", "403gc" }, { "405", "405d4" }, { "405cr", "405crc" }, { "405gp", "405gpd" }, diff --git a/target/ppc/cpu-models.h b/target/ppc/cpu-models.h index bf1dc7e5ca..612978a3fb 100644 --- a/target/ppc/cpu-models.h +++ b/target/ppc/cpu-models.h @@ -208,7 +208,6 @@ enum { CPU_POWERPC_601_v0 = 0x00010001, CPU_POWERPC_601_v1 = 0x00010001, CPU_POWERPC_601_v2 = 0x00010002, - CPU_POWERPC_602 = 0x00050100, CPU_POWERPC_603 = 0x00030100, CPU_POWERPC_603E_v11 = 0x00060101, CPU_POWERPC_603E_v12 = 0x00060102, diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index f20d4ffa6d..dcd83b503c 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -321,12 +321,11 @@ typedef enum { #define MSR_UCLE 26 /* User-mode cache lock enable for BookE */ #define MSR_VR 25 /* altivec available x hflags */ #define MSR_SPE 25 /* SPE enable for BookE x hflags */ -#define MSR_AP 23 /* Access privilege state on 602 hflags */ #define MSR_VSX 23 /* Vector Scalar Extension (ISA 2.06 and later) x hflags */ -#define MSR_SA 22 /* Supervisor access mode on 602 hflags */ #define MSR_S 22 /* Secure state */ #define MSR_KEY 19 /* key bit on 603e */ #define MSR_POW 18 /* Power management */ +#define MSR_WE 18 /* Wait State Enable on 405 */ #define MSR_TGPR 17 /* TGPR usage on 602/603 x */ #define MSR_CE 17 /* Critical interrupt enable on embedded PowerPC x */ #define MSR_ILE 16 /* Interrupt little-endian mode */ @@ -476,9 +475,7 @@ typedef enum { #define msr_ucle ((env->msr >> MSR_UCLE) & 1) #define msr_vr ((env->msr >> MSR_VR) & 1) #define msr_spe ((env->msr >> MSR_SPE) & 1) -#define msr_ap ((env->msr >> MSR_AP) & 1) #define msr_vsx ((env->msr >> MSR_VSX) & 1) -#define msr_sa ((env->msr >> MSR_SA) & 1) #define msr_key ((env->msr >> MSR_KEY) & 1) #define msr_pow ((env->msr >> MSR_POW) & 1) #define msr_tgpr ((env->msr >> MSR_TGPR) & 1) @@ -1133,7 +1130,6 @@ struct CPUPPCState { int nb_pids; /* Number of available PID registers */ int tlb_type; /* Type of TLB we're dealing with */ ppc_tlb_t tlb; /* TLB is optional. Allocate them only if needed */ - target_ulong pb[4]; /* 403 dedicated access protection registers */ bool tlb_dirty; /* Set to non-zero when modifying TLB */ bool kvm_sw_tlb; /* non-zero if KVM SW TLB API is active */ uint32_t tlb_need_flush; /* Delayed flush needed */ @@ -2142,8 +2138,6 @@ enum { PPC_MFTB = 0x0000000000000200ULL, /* Fixed-point unit extensions */ - /* PowerPC 602 specific */ - PPC_602_SPEC = 0x0000000000000400ULL, /* isel instruction */ PPC_ISEL = 0x0000000000000800ULL, /* popcntb instruction */ @@ -2245,7 +2239,7 @@ enum { #define PPC_TCG_INSNS (PPC_INSNS_BASE | PPC_POWER | PPC_POWER2 \ | PPC_POWER_RTC | PPC_POWER_BR | PPC_64B \ | PPC_64BX | PPC_64H | PPC_WAIT | PPC_MFTB \ - | PPC_602_SPEC | PPC_ISEL | PPC_POPCNTB \ + | PPC_ISEL | PPC_POPCNTB \ | PPC_STRING | PPC_FLOAT | PPC_FLOAT_EXT \ | PPC_FLOAT_FSQRT | PPC_FLOAT_FRES \ | PPC_FLOAT_FRSQRTE | PPC_FLOAT_FRSQRTES \ @@ -2728,20 +2722,29 @@ static inline bool ppc_has_spr(PowerPCCPU *cpu, int spr) return cpu->env.spr_cb[spr].name != NULL; } -static inline bool ppc_interrupts_little_endian(PowerPCCPU *cpu) +#if !defined(CONFIG_USER_ONLY) +static inline bool ppc_interrupts_little_endian(PowerPCCPU *cpu, bool hv) { PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); + CPUPPCState *env = &cpu->env; + bool ile; + + if (hv && env->has_hv_mode) { + if (is_isa300(pcc)) { + ile = !!(env->spr[SPR_HID0] & HID0_POWER9_HILE); + } else { + ile = !!(env->spr[SPR_HID0] & HID0_HILE); + } - /* - * Only models that have an LPCR and know about LPCR_ILE can do little - * endian. - */ - if (pcc->lpcr_mask & LPCR_ILE) { - return !!(cpu->env.spr[SPR_LPCR] & LPCR_ILE); + } else if (pcc->lpcr_mask & LPCR_ILE) { + ile = !!(env->spr[SPR_LPCR] & LPCR_ILE); + } else { + ile = !!(msr_ile); } - return false; + return ile; } +#endif void dump_mmu(CPUPPCState *env); diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index cc93bff3fa..bf60529d37 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -749,54 +749,6 @@ static void register_G2_sprs(CPUPPCState *env) 0x00000000); } -/* SPR specific to PowerPC 602 implementation */ -static void register_602_sprs(CPUPPCState *env) -{ - /* ESA registers */ - /* XXX : not implemented */ - spr_register(env, SPR_SER, "SER", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_SEBR, "SEBR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_ESASRR, "ESASRR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Floating point status */ - /* XXX : not implemented */ - spr_register(env, SPR_SP, "SP", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_LT, "LT", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Watchdog timer */ - /* XXX : not implemented */ - spr_register(env, SPR_TCR, "TCR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Interrupt base */ - spr_register(env, SPR_IBR, "IBR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_IABR, "IABR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); -} - /* SPR specific to PowerPC 601 implementation */ static void register_601_sprs(CPUPPCState *env) { @@ -2128,33 +2080,6 @@ static void init_excp_601(CPUPPCState *env) #endif } -static void init_excp_602(CPUPPCState *env) -{ -#if !defined(CONFIG_USER_ONLY) - /* XXX: exception prefix has a special behavior on 602 */ - env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100; - env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200; - env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300; - env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400; - env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500; - env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600; - env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700; - env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800; - env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900; - env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; - env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00; - env->excp_vectors[POWERPC_EXCP_IFTLB] = 0x00001000; - env->excp_vectors[POWERPC_EXCP_DLTLB] = 0x00001100; - env->excp_vectors[POWERPC_EXCP_DSTLB] = 0x00001200; - env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; - env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; - env->excp_vectors[POWERPC_EXCP_WDT] = 0x00001500; - env->excp_vectors[POWERPC_EXCP_EMUL] = 0x00001600; - /* Hardware reset vector */ - env->hreset_vector = 0x00000100UL; -#endif -} - static void init_excp_603(CPUPPCState *env) { #if !defined(CONFIG_USER_ONLY) @@ -2535,11 +2460,12 @@ POWERPC_FAMILY(405)(ObjectClass *oc, void *data) PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | PPC_4xx_COMMON | PPC_405_MAC | PPC_40x_EXCP; - pcc->msr_mask = (1ull << MSR_POW) | + pcc->msr_mask = (1ull << MSR_WE) | (1ull << MSR_CE) | (1ull << MSR_EE) | (1ull << MSR_PR) | (1ull << MSR_FP) | + (1ull << MSR_ME) | (1ull << MSR_DWE) | (1ull << MSR_DE) | (1ull << MSR_IR) | @@ -4080,76 +4006,6 @@ POWERPC_FAMILY(601v)(ObjectClass *oc, void *data) pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK | POWERPC_FLAG_HID0_LE; } -static void init_proc_602(CPUPPCState *env) -{ - register_ne_601_sprs(env); - register_sdr1_sprs(env); - register_602_sprs(env); - /* Time base */ - register_tbl(env); - /* hardware implementation registers */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Memory management */ - register_low_BATs(env); - register_6xx_7xx_soft_tlb(env, 64, 2); - init_excp_602(env); - env->dcache_line_size = 32; - env->icache_line_size = 32; - /* Allocate hardware IRQ controller */ - ppc6xx_irq_init(env_archcpu(env)); -} - -POWERPC_FAMILY(602)(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); - - dc->desc = "PowerPC 602"; - pcc->init_proc = init_proc_602; - pcc->check_pow = check_pow_hid0; - pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | - PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | - PPC_MEM_SYNC | PPC_MEM_EIEIO | - PPC_MEM_TLBIE | PPC_6xx_TLB | PPC_MEM_TLBSYNC | - PPC_SEGMENT | PPC_602_SPEC; - pcc->msr_mask = (1ull << MSR_VSX) | - (1ull << MSR_SA) | - (1ull << MSR_POW) | - (1ull << MSR_TGPR) | - (1ull << MSR_ILE) | - (1ull << MSR_EE) | - (1ull << MSR_PR) | - (1ull << MSR_FP) | - (1ull << MSR_ME) | - (1ull << MSR_FE0) | - (1ull << MSR_SE) | - (1ull << MSR_DE) | - (1ull << MSR_FE1) | - (1ull << MSR_EP) | - (1ull << MSR_IR) | - (1ull << MSR_DR) | - (1ull << MSR_RI) | - (1ull << MSR_LE); - /* XXX: 602 MMU is quite specific. Should add a special case */ - pcc->mmu_model = POWERPC_MMU_SOFT_6xx; - pcc->excp_model = POWERPC_EXCP_602; - pcc->bus_model = PPC_FLAGS_INPUT_6xx; - pcc->bfd_mach = bfd_mach_ppc_602; - pcc->flags = POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | - POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK; -} - static void init_proc_603(CPUPPCState *env) { register_ne_601_sprs(env); @@ -6953,10 +6809,12 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data) PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | + PPC_FLOAT_EXT | PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_64B | + PPC_POPCNTB | PPC_SEGMENT_64B | PPC_SLBI; pcc->insns_flags2 = PPC2_FP_CVT_S64; pcc->msr_mask = (1ull << MSR_SF) | @@ -8268,8 +8126,6 @@ static void ppc_cpu_reset(DeviceState *dev) msr = (target_ulong)0; msr |= (target_ulong)MSR_HVB; - msr |= (target_ulong)0 << MSR_AP; /* TO BE CHECKED */ - msr |= (target_ulong)0 << MSR_SA; /* TO BE CHECKED */ msr |= (target_ulong)1 << MSR_EP; #if defined(DO_SINGLE_STEP) && 0 /* Single step trace mode */ diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index a779dc936a..c107953dec 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -30,8 +30,6 @@ #include "exec/cpu_ldst.h" #endif -/* #define DEBUG_SOFTWARE_TLB */ - /*****************************************************************************/ /* Exception processing */ #if !defined(CONFIG_USER_ONLY) @@ -135,6 +133,39 @@ static void dump_hcall(CPUPPCState *env) env->nip); } +static void ppc_excp_debug_sw_tlb(CPUPPCState *env, int excp) +{ + const char *es; + target_ulong *miss, *cmp; + int en; + + if (!qemu_loglevel_mask(CPU_LOG_MMU)) { + return; + } + + if (excp == POWERPC_EXCP_IFTLB) { + es = "I"; + en = 'I'; + miss = &env->spr[SPR_IMISS]; + cmp = &env->spr[SPR_ICMP]; + } else { + if (excp == POWERPC_EXCP_DLTLB) { + es = "DL"; + } else { + es = "DS"; + } + en = 'D'; + miss = &env->spr[SPR_DMISS]; + cmp = &env->spr[SPR_DCMP]; + } + qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC " + TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 " + TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp, + env->spr[SPR_HASH1], env->spr[SPR_HASH2], + env->error_code); +} + + static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp, target_ulong *msr) { @@ -361,11 +392,665 @@ static void powerpc_set_excp_state(PowerPCCPU *cpu, check_tlb_flush(env, false); } +static void powerpc_excp_40x(PowerPCCPU *cpu, int excp) +{ + CPUState *cs = CPU(cpu); + CPUPPCState *env = &cpu->env; + target_ulong msr, new_msr, vector; + int srr0, srr1; + + if (excp <= POWERPC_EXCP_NONE || excp >= POWERPC_EXCP_NB) { + cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp); + } + + qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx + " => %s (%d) error=%02x\n", env->nip, powerpc_excp_name(excp), + excp, env->error_code); + + /* new srr1 value excluding must-be-zero bits */ + msr = env->msr & ~0x783f0000ULL; + + /* + * new interrupt handler msr preserves existing ME unless + * explicitly overriden. + */ + new_msr = env->msr & (((target_ulong)1 << MSR_ME)); + + /* target registers */ + srr0 = SPR_SRR0; + srr1 = SPR_SRR1; + + /* + * Hypervisor emulation assistance interrupt only exists on server + * arch 2.05 server or later. + */ + if (excp == POWERPC_EXCP_HV_EMU) { + excp = POWERPC_EXCP_PROGRAM; + } + + vector = env->excp_vectors[excp]; + if (vector == (target_ulong)-1ULL) { + cpu_abort(cs, "Raised an exception without defined vector %d\n", + excp); + } + + vector |= env->excp_prefix; + + switch (excp) { + case POWERPC_EXCP_CRITICAL: /* Critical input */ + srr0 = SPR_40x_SRR2; + srr1 = SPR_40x_SRR3; + break; + case POWERPC_EXCP_MCHECK: /* Machine check exception */ + if (msr_me == 0) { + /* + * Machine check exception is not enabled. Enter + * checkstop state. + */ + fprintf(stderr, "Machine check while not allowed. " + "Entering checkstop state\n"); + if (qemu_log_separate()) { + qemu_log("Machine check while not allowed. " + "Entering checkstop state\n"); + } + cs->halted = 1; + cpu_interrupt_exittb(cs); + } + + /* machine check exceptions don't have ME set */ + new_msr &= ~((target_ulong)1 << MSR_ME); + + srr0 = SPR_40x_SRR2; + srr1 = SPR_40x_SRR3; + break; + case POWERPC_EXCP_DSI: /* Data storage exception */ + trace_ppc_excp_dsi(env->spr[SPR_40x_ESR], env->spr[SPR_40x_DEAR]); + break; + case POWERPC_EXCP_ISI: /* Instruction storage exception */ + trace_ppc_excp_isi(msr, env->nip); + break; + case POWERPC_EXCP_EXTERNAL: /* External input */ + break; + case POWERPC_EXCP_ALIGN: /* Alignment exception */ + break; + case POWERPC_EXCP_PROGRAM: /* Program exception */ + switch (env->error_code & ~0xF) { + case POWERPC_EXCP_FP: + if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { + trace_ppc_excp_fp_ignore(); + cs->exception_index = POWERPC_EXCP_NONE; + env->error_code = 0; + return; + } + env->spr[SPR_40x_ESR] = ESR_FP; + break; + case POWERPC_EXCP_INVAL: + trace_ppc_excp_inval(env->nip); + env->spr[SPR_40x_ESR] = ESR_PIL; + break; + case POWERPC_EXCP_PRIV: + env->spr[SPR_40x_ESR] = ESR_PPR; + break; + case POWERPC_EXCP_TRAP: + env->spr[SPR_40x_ESR] = ESR_PTR; + break; + default: + cpu_abort(cs, "Invalid program exception %d. Aborting\n", + env->error_code); + break; + } + break; + case POWERPC_EXCP_SYSCALL: /* System call exception */ + dump_syscall(env); + + /* + * We need to correct the NIP which in this case is supposed + * to point to the next instruction + */ + env->nip += 4; + break; + case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */ + trace_ppc_excp_print("FIT"); + break; + case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */ + trace_ppc_excp_print("WDT"); + break; + case POWERPC_EXCP_DTLB: /* Data TLB error */ + case POWERPC_EXCP_ITLB: /* Instruction TLB error */ + break; + case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */ + trace_ppc_excp_print("PIT"); + break; + case POWERPC_EXCP_DEBUG: /* Debug interrupt */ + cpu_abort(cs, "%s exception not implemented\n", + powerpc_excp_name(excp)); + break; + default: + cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp); + break; + } + + /* Sanity check */ + if (!(env->msr_mask & MSR_HVB)) { + if (new_msr & MSR_HVB) { + cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with " + "no HV support\n", excp); + } + if (srr0 == SPR_HSRR0) { + cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with " + "no HV support\n", excp); + } + } + + /* Save PC */ + env->spr[srr0] = env->nip; + + /* Save MSR */ + env->spr[srr1] = msr; + + powerpc_set_excp_state(cpu, vector, new_msr); +} + +static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp) +{ + CPUState *cs = CPU(cpu); + CPUPPCState *env = &cpu->env; + target_ulong msr, new_msr, vector; + + if (excp <= POWERPC_EXCP_NONE || excp >= POWERPC_EXCP_NB) { + cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp); + } + + qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx + " => %s (%d) error=%02x\n", env->nip, powerpc_excp_name(excp), + excp, env->error_code); + + /* new srr1 value excluding must-be-zero bits */ + msr = env->msr & ~0x783f0000ULL; + + /* + * new interrupt handler msr preserves existing ME unless + * explicitly overriden + */ + new_msr = env->msr & ((target_ulong)1 << MSR_ME); + + /* + * Hypervisor emulation assistance interrupt only exists on server + * arch 2.05 server or later. + */ + if (excp == POWERPC_EXCP_HV_EMU) { + excp = POWERPC_EXCP_PROGRAM; + } + + vector = env->excp_vectors[excp]; + if (vector == (target_ulong)-1ULL) { + cpu_abort(cs, "Raised an exception without defined vector %d\n", + excp); + } + + vector |= env->excp_prefix; + + switch (excp) { + case POWERPC_EXCP_MCHECK: /* Machine check exception */ + if (msr_me == 0) { + /* + * Machine check exception is not enabled. Enter + * checkstop state. + */ + fprintf(stderr, "Machine check while not allowed. " + "Entering checkstop state\n"); + if (qemu_log_separate()) { + qemu_log("Machine check while not allowed. " + "Entering checkstop state\n"); + } + cs->halted = 1; + cpu_interrupt_exittb(cs); + } + + /* machine check exceptions don't have ME set */ + new_msr &= ~((target_ulong)1 << MSR_ME); + + break; + case POWERPC_EXCP_DSI: /* Data storage exception */ + trace_ppc_excp_dsi(env->spr[SPR_DSISR], env->spr[SPR_DAR]); + break; + case POWERPC_EXCP_ISI: /* Instruction storage exception */ + trace_ppc_excp_isi(msr, env->nip); + msr |= env->error_code; + break; + case POWERPC_EXCP_EXTERNAL: /* External input */ + break; + case POWERPC_EXCP_ALIGN: /* Alignment exception */ + /* Get rS/rD and rA from faulting opcode */ + /* + * Note: the opcode fields will not be set properly for a + * direct store load/store, but nobody cares as nobody + * actually uses direct store segments. + */ + env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16; + break; + case POWERPC_EXCP_PROGRAM: /* Program exception */ + switch (env->error_code & ~0xF) { + case POWERPC_EXCP_FP: + if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { + trace_ppc_excp_fp_ignore(); + cs->exception_index = POWERPC_EXCP_NONE; + env->error_code = 0; + return; + } + + /* + * FP exceptions always have NIP pointing to the faulting + * instruction, so always use store_next and claim we are + * precise in the MSR. + */ + msr |= 0x00100000; + break; + case POWERPC_EXCP_INVAL: + trace_ppc_excp_inval(env->nip); + msr |= 0x00080000; + break; + case POWERPC_EXCP_PRIV: + msr |= 0x00040000; + break; + case POWERPC_EXCP_TRAP: + msr |= 0x00020000; + break; + default: + /* Should never occur */ + cpu_abort(cs, "Invalid program exception %d. Aborting\n", + env->error_code); + break; + } + break; + case POWERPC_EXCP_SYSCALL: /* System call exception */ + { + int lev = env->error_code; + + if ((lev == 1) && cpu->vhyp) { + dump_hcall(env); + } else { + dump_syscall(env); + } + + /* + * We need to correct the NIP which in this case is supposed + * to point to the next instruction + */ + env->nip += 4; + + /* + * The Virtual Open Firmware (VOF) relies on the 'sc 1' + * instruction to communicate with QEMU. The pegasos2 machine + * uses VOF and the 74xx CPUs, so although the 74xx don't have + * HV mode, we need to keep hypercall support. + */ + if ((lev == 1) && cpu->vhyp) { + PPCVirtualHypervisorClass *vhc = + PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); + vhc->hypercall(cpu->vhyp, cpu); + return; + } + + break; + } + case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ + case POWERPC_EXCP_DECR: /* Decrementer exception */ + break; + case POWERPC_EXCP_RESET: /* System reset exception */ + if (msr_pow) { + cpu_abort(cs, "Trying to deliver power-saving system reset " + "exception %d with no HV support\n", excp); + } + break; + case POWERPC_EXCP_TRACE: /* Trace exception */ + break; + case POWERPC_EXCP_VPU: /* Vector unavailable exception */ + break; + case POWERPC_EXCP_IABR: /* Instruction address breakpoint */ + case POWERPC_EXCP_SMI: /* System management interrupt */ + case POWERPC_EXCP_THERM: /* Thermal interrupt */ + case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */ + case POWERPC_EXCP_VPUA: /* Vector assist exception */ + cpu_abort(cs, "%s exception not implemented\n", + powerpc_excp_name(excp)); + break; + default: + cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp); + break; + } + + /* Sanity check */ + if (!(env->msr_mask & MSR_HVB)) { + if (new_msr & MSR_HVB) { + cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with " + "no HV support\n", excp); + } + } + + /* + * Sort out endianness of interrupt, this differs depending on the + * CPU, the HV mode, etc... + */ + if (ppc_interrupts_little_endian(cpu, !!(new_msr & MSR_HVB))) { + new_msr |= (target_ulong)1 << MSR_LE; + } + + /* Save PC */ + env->spr[SPR_SRR0] = env->nip; + + /* Save MSR */ + env->spr[SPR_SRR1] = msr; + + powerpc_set_excp_state(cpu, vector, new_msr); +} + +#ifdef TARGET_PPC64 +static void powerpc_excp_books(PowerPCCPU *cpu, int excp) +{ + CPUState *cs = CPU(cpu); + CPUPPCState *env = &cpu->env; + int excp_model = env->excp_model; + target_ulong msr, new_msr, vector; + int srr0, srr1, lev = -1; + + if (excp <= POWERPC_EXCP_NONE || excp >= POWERPC_EXCP_NB) { + cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp); + } + + qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx + " => %s (%d) error=%02x\n", env->nip, powerpc_excp_name(excp), + excp, env->error_code); + + /* new srr1 value excluding must-be-zero bits */ + msr = env->msr & ~0x783f0000ULL; + + /* + * new interrupt handler msr preserves existing HV and ME unless + * explicitly overriden + */ + new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB); + + /* target registers */ + srr0 = SPR_SRR0; + srr1 = SPR_SRR1; + + /* + * check for special resume at 0x100 from doze/nap/sleep/winkle on + * P7/P8/P9 + */ + if (env->resume_as_sreset) { + excp = powerpc_reset_wakeup(cs, env, excp, &msr); + } + + /* + * We don't want to generate a Hypervisor Emulation Assistance + * Interrupt if we don't have HVB in msr_mask (PAPR mode). + */ + if (excp == POWERPC_EXCP_HV_EMU && !(env->msr_mask & MSR_HVB)) { + excp = POWERPC_EXCP_PROGRAM; + } + + vector = env->excp_vectors[excp]; + if (vector == (target_ulong)-1ULL) { + cpu_abort(cs, "Raised an exception without defined vector %d\n", + excp); + } + + vector |= env->excp_prefix; + + switch (excp) { + case POWERPC_EXCP_MCHECK: /* Machine check exception */ + if (msr_me == 0) { + /* + * Machine check exception is not enabled. Enter + * checkstop state. + */ + fprintf(stderr, "Machine check while not allowed. " + "Entering checkstop state\n"); + if (qemu_log_separate()) { + qemu_log("Machine check while not allowed. " + "Entering checkstop state\n"); + } + cs->halted = 1; + cpu_interrupt_exittb(cs); + } + if (env->msr_mask & MSR_HVB) { + /* + * ISA specifies HV, but can be delivered to guest with HV + * clear (e.g., see FWNMI in PAPR). + */ + new_msr |= (target_ulong)MSR_HVB; + } + + /* machine check exceptions don't have ME set */ + new_msr &= ~((target_ulong)1 << MSR_ME); + + break; + case POWERPC_EXCP_DSI: /* Data storage exception */ + trace_ppc_excp_dsi(env->spr[SPR_DSISR], env->spr[SPR_DAR]); + break; + case POWERPC_EXCP_ISI: /* Instruction storage exception */ + trace_ppc_excp_isi(msr, env->nip); + msr |= env->error_code; + break; + case POWERPC_EXCP_EXTERNAL: /* External input */ + { + bool lpes0; + + /* + * LPES0 is only taken into consideration if we support HV + * mode for this CPU. + */ + if (!env->has_hv_mode) { + break; + } + + lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); + + if (!lpes0) { + new_msr |= (target_ulong)MSR_HVB; + new_msr |= env->msr & ((target_ulong)1 << MSR_RI); + srr0 = SPR_HSRR0; + srr1 = SPR_HSRR1; + } + + break; + } + case POWERPC_EXCP_ALIGN: /* Alignment exception */ + /* Get rS/rD and rA from faulting opcode */ + /* + * Note: the opcode fields will not be set properly for a + * direct store load/store, but nobody cares as nobody + * actually uses direct store segments. + */ + env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16; + break; + case POWERPC_EXCP_PROGRAM: /* Program exception */ + switch (env->error_code & ~0xF) { + case POWERPC_EXCP_FP: + if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { + trace_ppc_excp_fp_ignore(); + cs->exception_index = POWERPC_EXCP_NONE; + env->error_code = 0; + return; + } + + /* + * FP exceptions always have NIP pointing to the faulting + * instruction, so always use store_next and claim we are + * precise in the MSR. + */ + msr |= 0x00100000; + break; + case POWERPC_EXCP_INVAL: + trace_ppc_excp_inval(env->nip); + msr |= 0x00080000; + break; + case POWERPC_EXCP_PRIV: + msr |= 0x00040000; + break; + case POWERPC_EXCP_TRAP: + msr |= 0x00020000; + break; + default: + /* Should never occur */ + cpu_abort(cs, "Invalid program exception %d. Aborting\n", + env->error_code); + break; + } + break; + case POWERPC_EXCP_SYSCALL: /* System call exception */ + lev = env->error_code; + + if ((lev == 1) && cpu->vhyp) { + dump_hcall(env); + } else { + dump_syscall(env); + } + + /* + * We need to correct the NIP which in this case is supposed + * to point to the next instruction + */ + env->nip += 4; + + /* "PAPR mode" built-in hypercall emulation */ + if ((lev == 1) && cpu->vhyp) { + PPCVirtualHypervisorClass *vhc = + PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); + vhc->hypercall(cpu->vhyp, cpu); + return; + } + if (lev == 1) { + new_msr |= (target_ulong)MSR_HVB; + } + break; + case POWERPC_EXCP_SYSCALL_VECTORED: /* scv exception */ + lev = env->error_code; + dump_syscall(env); + env->nip += 4; + new_msr |= env->msr & ((target_ulong)1 << MSR_EE); + new_msr |= env->msr & ((target_ulong)1 << MSR_RI); + + vector += lev * 0x20; + + env->lr = env->nip; + env->ctr = msr; + break; + case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ + case POWERPC_EXCP_DECR: /* Decrementer exception */ + break; + case POWERPC_EXCP_RESET: /* System reset exception */ + /* A power-saving exception sets ME, otherwise it is unchanged */ + if (msr_pow) { + /* indicate that we resumed from power save mode */ + msr |= 0x10000; + new_msr |= ((target_ulong)1 << MSR_ME); + } + if (env->msr_mask & MSR_HVB) { + /* + * ISA specifies HV, but can be delivered to guest with HV + * clear (e.g., see FWNMI in PAPR, NMI injection in QEMU). + */ + new_msr |= (target_ulong)MSR_HVB; + } else { + if (msr_pow) { + cpu_abort(cs, "Trying to deliver power-saving system reset " + "exception %d with no HV support\n", excp); + } + } + break; + case POWERPC_EXCP_DSEG: /* Data segment exception */ + case POWERPC_EXCP_ISEG: /* Instruction segment exception */ + case POWERPC_EXCP_TRACE: /* Trace exception */ + break; + case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */ + msr |= env->error_code; + /* fall through */ + case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ + case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ + case POWERPC_EXCP_SDOOR_HV: /* Hypervisor Doorbell interrupt */ + case POWERPC_EXCP_HV_EMU: + case POWERPC_EXCP_HVIRT: /* Hypervisor virtualization */ + srr0 = SPR_HSRR0; + srr1 = SPR_HSRR1; + new_msr |= (target_ulong)MSR_HVB; + new_msr |= env->msr & ((target_ulong)1 << MSR_RI); + break; + case POWERPC_EXCP_VPU: /* Vector unavailable exception */ + case POWERPC_EXCP_VSXU: /* VSX unavailable exception */ + case POWERPC_EXCP_FU: /* Facility unavailable exception */ + env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56); + break; + case POWERPC_EXCP_HV_FU: /* Hypervisor Facility Unavailable Exception */ + env->spr[SPR_HFSCR] |= ((target_ulong)env->error_code << FSCR_IC_POS); + srr0 = SPR_HSRR0; + srr1 = SPR_HSRR1; + new_msr |= (target_ulong)MSR_HVB; + new_msr |= env->msr & ((target_ulong)1 << MSR_RI); + break; + case POWERPC_EXCP_THERM: /* Thermal interrupt */ + case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */ + case POWERPC_EXCP_VPUA: /* Vector assist exception */ + case POWERPC_EXCP_MAINT: /* Maintenance exception */ + case POWERPC_EXCP_SDOOR: /* Doorbell interrupt */ + case POWERPC_EXCP_HV_MAINT: /* Hypervisor Maintenance exception */ + cpu_abort(cs, "%s exception not implemented\n", + powerpc_excp_name(excp)); + break; + default: + cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp); + break; + } + + /* Sanity check */ + if (!(env->msr_mask & MSR_HVB)) { + if (new_msr & MSR_HVB) { + cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with " + "no HV support\n", excp); + } + if (srr0 == SPR_HSRR0) { + cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with " + "no HV support\n", excp); + } + } + + /* + * Sort out endianness of interrupt, this differs depending on the + * CPU, the HV mode, etc... + */ + if (ppc_interrupts_little_endian(cpu, !!(new_msr & MSR_HVB))) { + new_msr |= (target_ulong)1 << MSR_LE; + } + + new_msr |= (target_ulong)1 << MSR_SF; + + if (excp != POWERPC_EXCP_SYSCALL_VECTORED) { + /* Save PC */ + env->spr[srr0] = env->nip; + + /* Save MSR */ + env->spr[srr1] = msr; + } + + /* This can update new_msr and vector if AIL applies */ + ppc_excp_apply_ail(cpu, excp_model, excp, msr, &new_msr, &vector); + + powerpc_set_excp_state(cpu, vector, new_msr); +} +#else +static inline void powerpc_excp_books(PowerPCCPU *cpu, int excp) +{ + g_assert_not_reached(); +} +#endif + /* * Note that this function should be greatly optimized when called * with a constant excp, from ppc_hw_interrupt */ -static void powerpc_excp(PowerPCCPU *cpu, int excp) +static inline void powerpc_excp_legacy(PowerPCCPU *cpu, int excp) { CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; @@ -669,23 +1354,6 @@ static void powerpc_excp(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable/VPU */ env->spr[SPR_BOOKE_ESR] = ESR_SPV; break; - case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */ - /* XXX: TODO */ - cpu_abort(cs, "Embedded floating point data exception " - "is not implemented yet !\n"); - env->spr[SPR_BOOKE_ESR] = ESR_SPV; - break; - case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */ - /* XXX: TODO */ - cpu_abort(cs, "Embedded floating point round exception " - "is not implemented yet !\n"); - env->spr[SPR_BOOKE_ESR] = ESR_SPV; - break; - case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */ - /* XXX: TODO */ - cpu_abort(cs, - "Performance counter exception is not implemented yet !\n"); - break; case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */ break; case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */ @@ -750,24 +1418,10 @@ static void powerpc_excp(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */ trace_ppc_excp_print("PIT"); break; - case POWERPC_EXCP_IO: /* IO error exception */ - /* XXX: TODO */ - cpu_abort(cs, "601 IO error exception is not implemented yet !\n"); - break; - case POWERPC_EXCP_RUNM: /* Run mode exception */ - /* XXX: TODO */ - cpu_abort(cs, "601 run mode exception is not implemented yet !\n"); - break; - case POWERPC_EXCP_EMUL: /* Emulation trap exception */ - /* XXX: TODO */ - cpu_abort(cs, "602 emulation trap exception " - "is not implemented yet !\n"); - break; case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */ case POWERPC_EXCP_DLTLB: /* Data load TLB miss */ case POWERPC_EXCP_DSTLB: /* Data store TLB miss */ switch (excp_model) { - case POWERPC_EXCP_602: case POWERPC_EXCP_603: case POWERPC_EXCP_G2: /* Swap temporary saved registers with GPRs */ @@ -777,34 +1431,8 @@ static void powerpc_excp(PowerPCCPU *cpu, int excp) } /* fall through */ case POWERPC_EXCP_7x5: -#if defined(DEBUG_SOFTWARE_TLB) - if (qemu_log_enabled()) { - const char *es; - target_ulong *miss, *cmp; - int en; - - if (excp == POWERPC_EXCP_IFTLB) { - es = "I"; - en = 'I'; - miss = &env->spr[SPR_IMISS]; - cmp = &env->spr[SPR_ICMP]; - } else { - if (excp == POWERPC_EXCP_DLTLB) { - es = "DL"; - } else { - es = "DS"; - } - en = 'D'; - miss = &env->spr[SPR_DMISS]; - cmp = &env->spr[SPR_DCMP]; - } - qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC " - TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 " - TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp, - env->spr[SPR_HASH1], env->spr[SPR_HASH2], - env->error_code); - } -#endif + ppc_excp_debug_sw_tlb(env, excp); + msr |= env->crf[0] << 28; msr |= env->error_code; /* key, D/I, S/L bits */ /* Set way using a LRU mechanism */ @@ -815,56 +1443,25 @@ static void powerpc_excp(PowerPCCPU *cpu, int excp) break; } break; + case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */ + case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */ + case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */ + case POWERPC_EXCP_IO: /* IO error exception */ + case POWERPC_EXCP_RUNM: /* Run mode exception */ + case POWERPC_EXCP_EMUL: /* Emulation trap exception */ case POWERPC_EXCP_FPA: /* Floating-point assist exception */ - /* XXX: TODO */ - cpu_abort(cs, "Floating point assist exception " - "is not implemented yet !\n"); - break; case POWERPC_EXCP_DABR: /* Data address breakpoint */ - /* XXX: TODO */ - cpu_abort(cs, "DABR exception is not implemented yet !\n"); - break; case POWERPC_EXCP_IABR: /* Instruction address breakpoint */ - /* XXX: TODO */ - cpu_abort(cs, "IABR exception is not implemented yet !\n"); - break; case POWERPC_EXCP_SMI: /* System management interrupt */ - /* XXX: TODO */ - cpu_abort(cs, "SMI exception is not implemented yet !\n"); - break; case POWERPC_EXCP_THERM: /* Thermal interrupt */ - /* XXX: TODO */ - cpu_abort(cs, "Thermal management exception " - "is not implemented yet !\n"); - break; case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */ - /* XXX: TODO */ - cpu_abort(cs, - "Performance counter exception is not implemented yet !\n"); - break; case POWERPC_EXCP_VPUA: /* Vector assist exception */ - /* XXX: TODO */ - cpu_abort(cs, "VPU assist exception is not implemented yet !\n"); - break; case POWERPC_EXCP_SOFTP: /* Soft patch exception */ - /* XXX: TODO */ - cpu_abort(cs, - "970 soft-patch exception is not implemented yet !\n"); - break; case POWERPC_EXCP_MAINT: /* Maintenance exception */ - /* XXX: TODO */ - cpu_abort(cs, - "970 maintenance exception is not implemented yet !\n"); - break; case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */ - /* XXX: TODO */ - cpu_abort(cs, "Maskable external exception " - "is not implemented yet !\n"); - break; case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */ - /* XXX: TODO */ - cpu_abort(cs, "Non maskable external exception " - "is not implemented yet !\n"); + cpu_abort(cs, "%s exception not implemented\n", + powerpc_excp_name(excp)); break; default: excp_invalid: @@ -888,36 +1485,9 @@ static void powerpc_excp(PowerPCCPU *cpu, int excp) * Sort out endianness of interrupt, this differs depending on the * CPU, the HV mode, etc... */ -#ifdef TARGET_PPC64 - if (excp_model == POWERPC_EXCP_POWER7) { - if (!(new_msr & MSR_HVB) && (env->spr[SPR_LPCR] & LPCR_ILE)) { - new_msr |= (target_ulong)1 << MSR_LE; - } - } else if (excp_model == POWERPC_EXCP_POWER8) { - if (new_msr & MSR_HVB) { - if (env->spr[SPR_HID0] & HID0_HILE) { - new_msr |= (target_ulong)1 << MSR_LE; - } - } else if (env->spr[SPR_LPCR] & LPCR_ILE) { - new_msr |= (target_ulong)1 << MSR_LE; - } - } else if (excp_model == POWERPC_EXCP_POWER9 || - excp_model == POWERPC_EXCP_POWER10) { - if (new_msr & MSR_HVB) { - if (env->spr[SPR_HID0] & HID0_POWER9_HILE) { - new_msr |= (target_ulong)1 << MSR_LE; - } - } else if (env->spr[SPR_LPCR] & LPCR_ILE) { - new_msr |= (target_ulong)1 << MSR_LE; - } - } else if (msr_ile) { - new_msr |= (target_ulong)1 << MSR_LE; - } -#else - if (msr_ile) { + if (ppc_interrupts_little_endian(cpu, !!(new_msr & MSR_HVB))) { new_msr |= (target_ulong)1 << MSR_LE; } -#endif #if defined(TARGET_PPC64) if (excp_model == POWERPC_EXCP_BOOKE) { @@ -950,6 +1520,29 @@ static void powerpc_excp(PowerPCCPU *cpu, int excp) powerpc_set_excp_state(cpu, vector, new_msr); } +static void powerpc_excp(PowerPCCPU *cpu, int excp) +{ + CPUPPCState *env = &cpu->env; + + switch (env->excp_model) { + case POWERPC_EXCP_40x: + powerpc_excp_40x(cpu, excp); + break; + case POWERPC_EXCP_74xx: + powerpc_excp_74xx(cpu, excp); + break; + case POWERPC_EXCP_970: + case POWERPC_EXCP_POWER7: + case POWERPC_EXCP_POWER8: + case POWERPC_EXCP_POWER9: + case POWERPC_EXCP_POWER10: + powerpc_excp_books(cpu, excp); + break; + default: + powerpc_excp_legacy(cpu, excp); + } +} + void ppc_cpu_do_interrupt(CPUState *cs) { PowerPCCPU *cpu = POWERPC_CPU(cs); @@ -1126,7 +1719,7 @@ void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector) */ msr = (1ULL << MSR_ME); msr |= env->msr & (1ULL << MSR_SF); - if (ppc_interrupts_little_endian(cpu)) { + if (ppc_interrupts_little_endian(cpu, false)) { msr |= (1ULL << MSR_LE); } @@ -1228,7 +1821,6 @@ void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn) (env->spr[SPR_PSSCR] & PSSCR_EC); } #endif /* defined(TARGET_PPC64) */ -#endif /* CONFIG_TCG */ static void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr) { @@ -1237,6 +1829,10 @@ static void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr) /* MSR:POW cannot be set by any form of rfi */ msr &= ~(1ULL << MSR_POW); + /* MSR:TGPR cannot be set by any form of rfi */ + if (env->flags & POWERPC_FLAG_TGPR) + msr &= ~(1ULL << MSR_TGPR); + #if defined(TARGET_PPC64) /* Switching to 32-bit ? Crop the nip */ if (!msr_is_64bit(env, msr)) { @@ -1261,7 +1857,6 @@ static void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr) check_tlb_flush(env, false); } -#ifdef CONFIG_TCG void helper_rfi(CPUPPCState *env) { do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1] & 0xfffffffful); diff --git a/target/ppc/helper.h b/target/ppc/helper.h index f9c72dcd50..f2e5060910 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -646,7 +646,6 @@ DEF_HELPER_FLAGS_2(slbieg, TCG_CALL_NO_RWG, void, env, tl) DEF_HELPER_FLAGS_2(load_sr, TCG_CALL_NO_RWG, tl, env, tl) DEF_HELPER_FLAGS_3(store_sr, TCG_CALL_NO_RWG, void, env, tl, tl) -DEF_HELPER_FLAGS_1(602_mfrom, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_1(msgsnd, void, tl) DEF_HELPER_2(msgclr, void, env, tl) DEF_HELPER_1(book3s_msgsnd, void, tl) @@ -703,11 +702,11 @@ DEF_HELPER_FLAGS_2(store_hdecr, TCG_CALL_NO_RWG, void, env, tl) DEF_HELPER_FLAGS_2(store_vtb, TCG_CALL_NO_RWG, void, env, tl) DEF_HELPER_FLAGS_2(store_tbu40, TCG_CALL_NO_RWG, void, env, tl) DEF_HELPER_2(store_hid0_601, void, env, tl) -DEF_HELPER_3(store_403_pbr, void, env, i32, tl) DEF_HELPER_FLAGS_1(load_40x_pit, TCG_CALL_NO_RWG, tl, env) DEF_HELPER_FLAGS_2(store_40x_pit, TCG_CALL_NO_RWG, void, env, tl) DEF_HELPER_FLAGS_2(store_40x_tcr, TCG_CALL_NO_RWG, void, env, tl) DEF_HELPER_FLAGS_2(store_40x_tsr, TCG_CALL_NO_RWG, void, env, tl) +DEF_HELPER_2(store_40x_pid, void, env, tl) DEF_HELPER_2(store_40x_dbcr0, void, env, tl) DEF_HELPER_2(store_40x_sler, void, env, tl) DEF_HELPER_FLAGS_2(store_booke_tcr, TCG_CALL_NO_RWG, void, env, tl) diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c index 8671b7bb69..5b12cb03c9 100644 --- a/target/ppc/helper_regs.c +++ b/target/ppc/helper_regs.c @@ -156,7 +156,8 @@ static uint32_t hreg_compute_hflags_value(CPUPPCState *env) */ unsigned immu_idx, dmmu_idx; dmmu_idx = msr & (1 << MSR_PR) ? 0 : 1; - if (env->mmu_model & POWERPC_MMU_BOOKE) { + if (env->mmu_model == POWERPC_MMU_BOOKE || + env->mmu_model == POWERPC_MMU_BOOKE206) { dmmu_idx |= msr & (1 << MSR_GS) ? 4 : 0; immu_idx = dmmu_idx; immu_idx |= msr & (1 << MSR_IS) ? 2 : 0; @@ -201,7 +202,11 @@ void cpu_get_tb_cpu_state(CPUPPCState *env, target_ulong *pc, void cpu_interrupt_exittb(CPUState *cs) { - if (!kvm_enabled()) { + /* + * We don't need to worry about translation blocks + * when running with KVM. + */ + if (kvm_enabled()) { return; } @@ -233,7 +238,8 @@ int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv) ((value >> MSR_DR) & 1) != msr_dr) { cpu_interrupt_exittb(cs); } - if ((env->mmu_model & POWERPC_MMU_BOOKE) && + if ((env->mmu_model == POWERPC_MMU_BOOKE || + env->mmu_model == POWERPC_MMU_BOOKE206) && ((value >> MSR_GS) & 1) != msr_gs) { cpu_interrupt_exittb(cs); } diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c index 9bc327bcba..d7765fd3e3 100644 --- a/target/ppc/int_helper.c +++ b/target/ppc/int_helper.c @@ -489,27 +489,6 @@ target_ulong helper_divso(CPUPPCState *env, target_ulong arg1, } /*****************************************************************************/ -/* 602 specific instructions */ -/* mfrom is the most crazy instruction ever seen, imho ! */ -/* Real implementation uses a ROM table. Do the same */ -/* - * Extremely decomposed: - * -arg / 256 - * return 256 * log10(10 + 1.0) + 0.5 - */ -#if !defined(CONFIG_USER_ONLY) -target_ulong helper_602_mfrom(target_ulong arg) -{ - if (likely(arg < 602)) { -#include "mfrom_table.c.inc" - return mfrom_ROM_table[arg]; - } else { - return 0; - } -} -#endif - -/*****************************************************************************/ /* Altivec extension helpers */ #if defined(HOST_WORDS_BIGENDIAN) #define VECTOR_FOR_INORDER_I(index, element) \ diff --git a/target/ppc/machine.c b/target/ppc/machine.c index 756d8de5d8..a503e00ddc 100644 --- a/target/ppc/machine.c +++ b/target/ppc/machine.c @@ -23,117 +23,6 @@ static void post_load_update_msr(CPUPPCState *env) pmu_update_summaries(env); } -static int cpu_load_old(QEMUFile *f, void *opaque, int version_id) -{ - PowerPCCPU *cpu = opaque; - CPUPPCState *env = &cpu->env; - unsigned int i, j; - target_ulong sdr1; - uint32_t fpscr, vscr; -#if defined(TARGET_PPC64) - int32_t slb_nr; -#endif - target_ulong xer; - - for (i = 0; i < 32; i++) { - qemu_get_betls(f, &env->gpr[i]); - } -#if !defined(TARGET_PPC64) - for (i = 0; i < 32; i++) { - qemu_get_betls(f, &env->gprh[i]); - } -#endif - qemu_get_betls(f, &env->lr); - qemu_get_betls(f, &env->ctr); - for (i = 0; i < 8; i++) { - qemu_get_be32s(f, &env->crf[i]); - } - qemu_get_betls(f, &xer); - cpu_write_xer(env, xer); - qemu_get_betls(f, &env->reserve_addr); - qemu_get_betls(f, &env->msr); - for (i = 0; i < 4; i++) { - qemu_get_betls(f, &env->tgpr[i]); - } - for (i = 0; i < 32; i++) { - union { - float64 d; - uint64_t l; - } u; - u.l = qemu_get_be64(f); - *cpu_fpr_ptr(env, i) = u.d; - } - qemu_get_be32s(f, &fpscr); - env->fpscr = fpscr; - qemu_get_sbe32s(f, &env->access_type); -#if defined(TARGET_PPC64) - qemu_get_betls(f, &env->spr[SPR_ASR]); - qemu_get_sbe32s(f, &slb_nr); -#endif - qemu_get_betls(f, &sdr1); - for (i = 0; i < 32; i++) { - qemu_get_betls(f, &env->sr[i]); - } - for (i = 0; i < 2; i++) { - for (j = 0; j < 8; j++) { - qemu_get_betls(f, &env->DBAT[i][j]); - } - } - for (i = 0; i < 2; i++) { - for (j = 0; j < 8; j++) { - qemu_get_betls(f, &env->IBAT[i][j]); - } - } - qemu_get_sbe32s(f, &env->nb_tlb); - qemu_get_sbe32s(f, &env->tlb_per_way); - qemu_get_sbe32s(f, &env->nb_ways); - qemu_get_sbe32s(f, &env->last_way); - qemu_get_sbe32s(f, &env->id_tlbs); - qemu_get_sbe32s(f, &env->nb_pids); - if (env->tlb.tlb6) { - /* XXX assumes 6xx */ - for (i = 0; i < env->nb_tlb; i++) { - qemu_get_betls(f, &env->tlb.tlb6[i].pte0); - qemu_get_betls(f, &env->tlb.tlb6[i].pte1); - qemu_get_betls(f, &env->tlb.tlb6[i].EPN); - } - } - for (i = 0; i < 4; i++) { - qemu_get_betls(f, &env->pb[i]); - } - for (i = 0; i < 1024; i++) { - qemu_get_betls(f, &env->spr[i]); - } - if (!cpu->vhyp) { - ppc_store_sdr1(env, sdr1); - } - qemu_get_be32s(f, &vscr); - ppc_store_vscr(env, vscr); - qemu_get_be64s(f, &env->spe_acc); - qemu_get_be32s(f, &env->spe_fscr); - qemu_get_betls(f, &env->msr_mask); - qemu_get_be32s(f, &env->flags); - qemu_get_sbe32s(f, &env->error_code); - qemu_get_be32s(f, &env->pending_interrupts); - qemu_get_be32s(f, &env->irq_input_state); - for (i = 0; i < POWERPC_EXCP_NB; i++) { - qemu_get_betls(f, &env->excp_vectors[i]); - } - qemu_get_betls(f, &env->excp_prefix); - qemu_get_betls(f, &env->ivor_mask); - qemu_get_betls(f, &env->ivpr_mask); - qemu_get_betls(f, &env->hreset_vector); - qemu_get_betls(f, &env->nip); - qemu_get_sbetl(f); /* Discard unused hflags */ - qemu_get_sbetl(f); /* Discard unused hflags_nmsr */ - qemu_get_sbe32(f); /* Discard unused mmu_idx */ - qemu_get_sbe32(f); /* Discard unused power_mode */ - - post_load_update_msr(env); - - return 0; -} - static int get_avr(QEMUFile *f, void *pv, size_t size, const VMStateField *field) { @@ -532,7 +421,6 @@ static const VMStateDescription vmstate_tm = { .name = "cpu/tm", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .needed = tm_needed, .fields = (VMStateField []) { VMSTATE_UINTTL_ARRAY(env.tm_gpr, PowerPCCPU, 32), @@ -709,25 +597,6 @@ static bool tlbemb_needed(void *opaque) return env->nb_tlb && (env->tlb_type == TLB_EMB); } -static bool pbr403_needed(void *opaque) -{ - PowerPCCPU *cpu = opaque; - uint32_t pvr = cpu->env.spr[SPR_PVR]; - - return (pvr & 0xffff0000) == 0x00200000; -} - -static const VMStateDescription vmstate_pbr403 = { - .name = "cpu/pbr403", - .version_id = 1, - .minimum_version_id = 1, - .needed = pbr403_needed, - .fields = (VMStateField[]) { - VMSTATE_UINTTL_ARRAY(env.pb, PowerPCCPU, 4), - VMSTATE_END_OF_LIST() - }, -}; - static const VMStateDescription vmstate_tlbemb = { .name = "cpu/tlb6xx", .version_id = 1, @@ -739,13 +608,8 @@ static const VMStateDescription vmstate_tlbemb = { env.nb_tlb, vmstate_tlbemb_entry, ppcemb_tlb_t), - /* 403 protection registers */ VMSTATE_END_OF_LIST() }, - .subsections = (const VMStateDescription*[]) { - &vmstate_pbr403, - NULL - } }; static const VMStateDescription vmstate_tlbmas_entry = { @@ -807,8 +671,6 @@ const VMStateDescription vmstate_ppc_cpu = { .name = "cpu", .version_id = 5, .minimum_version_id = 5, - .minimum_version_id_old = 4, - .load_state_old = cpu_load_old, .pre_save = cpu_pre_save, .post_load = cpu_post_load, .fields = (VMStateField[]) { diff --git a/target/ppc/mfrom_table.c.inc b/target/ppc/mfrom_table.c.inc deleted file mode 100644 index 1653b974a4..0000000000 --- a/target/ppc/mfrom_table.c.inc +++ /dev/null @@ -1,78 +0,0 @@ -static const uint8_t mfrom_ROM_table[602] = { - 77, 77, 76, 76, 75, 75, 74, 74, - 73, 73, 72, 72, 71, 71, 70, 70, - 69, 69, 68, 68, 68, 67, 67, 66, - 66, 65, 65, 64, 64, 64, 63, 63, - 62, 62, 61, 61, 61, 60, 60, 59, - 59, 58, 58, 58, 57, 57, 56, 56, - 56, 55, 55, 54, 54, 54, 53, 53, - 53, 52, 52, 51, 51, 51, 50, 50, - 50, 49, 49, 49, 48, 48, 47, 47, - 47, 46, 46, 46, 45, 45, 45, 44, - 44, 44, 43, 43, 43, 42, 42, 42, - 42, 41, 41, 41, 40, 40, 40, 39, - 39, 39, 39, 38, 38, 38, 37, 37, - 37, 37, 36, 36, 36, 35, 35, 35, - 35, 34, 34, 34, 34, 33, 33, 33, - 33, 32, 32, 32, 32, 31, 31, 31, - 31, 30, 30, 30, 30, 29, 29, 29, - 29, 28, 28, 28, 28, 28, 27, 27, - 27, 27, 26, 26, 26, 26, 26, 25, - 25, 25, 25, 25, 24, 24, 24, 24, - 24, 23, 23, 23, 23, 23, 23, 22, - 22, 22, 22, 22, 21, 21, 21, 21, - 21, 21, 20, 20, 20, 20, 20, 20, - 19, 19, 19, 19, 19, 19, 19, 18, - 18, 18, 18, 18, 18, 17, 17, 17, - 17, 17, 17, 17, 16, 16, 16, 16, - 16, 16, 16, 16, 15, 15, 15, 15, - 15, 15, 15, 15, 14, 14, 14, 14, - 14, 14, 14, 14, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 11, - 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, - 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, - 7, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 0, -}; diff --git a/target/ppc/mfrom_table_gen.c b/target/ppc/mfrom_table_gen.c deleted file mode 100644 index f96c4268ba..0000000000 --- a/target/ppc/mfrom_table_gen.c +++ /dev/null @@ -1,34 +0,0 @@ -#define _GNU_SOURCE -#include "qemu/osdep.h" -#include <math.h> - -int main(void) -{ - double d; - uint8_t n; - int i; - - printf("static const uint8_t mfrom_ROM_table[602] =\n{\n "); - for (i = 0; i < 602; i++) { - /* - * Extremely decomposed: - * -T0 / 256 - * T0 = 256 * log10(10 + 1.0) + 0.5 - */ - d = -i; - d /= 256.0; - d = exp10(d); - d += 1.0; - d = log10(d); - d *= 256; - d += 0.5; - n = d; - printf("%3d, ", n); - if ((i & 7) == 7) { - printf("\n "); - } - } - printf("\n};\n"); - - return 0; -} diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c index c33f5f39b9..1bcefa7c84 100644 --- a/target/ppc/misc_helper.c +++ b/target/ppc/misc_helper.c @@ -226,15 +226,6 @@ void helper_store_hid0_601(CPUPPCState *env, target_ulong val) } } -void helper_store_403_pbr(CPUPPCState *env, uint32_t num, target_ulong value) -{ - if (likely(env->pb[num] != value)) { - env->pb[num] = value; - /* Should be optimized */ - tlb_flush(env_cpu(env)); - } -} - void helper_store_40x_dbcr0(CPUPPCState *env, target_ulong val) { /* Bits 26 & 27 affect single-stepping. */ diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c index 91270c1f17..6512ee031c 100644 --- a/target/ppc/mmu_common.c +++ b/target/ppc/mmu_common.c @@ -1367,22 +1367,34 @@ static bool ppc_jumbo_xlate(PowerPCCPU *cpu, vaddr eaddr, case -2: /* Access rights violation */ cs->exception_index = POWERPC_EXCP_ISI; - env->error_code = 0x08000000; + if ((env->mmu_model == POWERPC_MMU_BOOKE) || + (env->mmu_model == POWERPC_MMU_BOOKE206)) { + env->error_code = 0; + } else { + env->error_code = 0x08000000; + } break; case -3: /* No execute protection violation */ if ((env->mmu_model == POWERPC_MMU_BOOKE) || (env->mmu_model == POWERPC_MMU_BOOKE206)) { env->spr[SPR_BOOKE_ESR] = 0x00000000; + env->error_code = 0; + } else { + env->error_code = 0x10000000; } cs->exception_index = POWERPC_EXCP_ISI; - env->error_code = 0x10000000; break; case -4: /* Direct store exception */ /* No code fetch is allowed in direct-store areas */ cs->exception_index = POWERPC_EXCP_ISI; - env->error_code = 0x10000000; + if ((env->mmu_model == POWERPC_MMU_BOOKE) || + (env->mmu_model == POWERPC_MMU_BOOKE206)) { + env->error_code = 0; + } else { + env->error_code = 0x10000000; + } break; } } else { diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c index 59df6952ae..a2a52a12c3 100644 --- a/target/ppc/mmu_helper.c +++ b/target/ppc/mmu_helper.c @@ -664,6 +664,14 @@ static inline int booke_page_size_to_tlb(target_ulong page_size) #define PPC4XX_TLBLO_ATTR_MASK 0x000000FF #define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00 +void helper_store_40x_pid(CPUPPCState *env, target_ulong val) +{ + if (env->spr[SPR_40x_PID] != val) { + env->spr[SPR_40x_PID] = val; + env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH; + } +} + target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry) { ppcemb_tlb_t *tlb; @@ -681,7 +689,7 @@ target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry) size = PPC4XX_TLBHI_SIZE_DEFAULT; } ret |= size << PPC4XX_TLBHI_SIZE_SHIFT; - env->spr[SPR_40x_PID] = tlb->PID; + helper_store_40x_pid(env, tlb->PID); return ret; } @@ -794,6 +802,8 @@ void helper_4xx_tlbwe_lo(CPUPPCState *env, target_ulong entry, tlb->prot & PAGE_WRITE ? 'w' : '-', tlb->prot & PAGE_EXEC ? 'x' : '-', tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID); + + env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH; } target_ulong helper_4xx_tlbsx(CPUPPCState *env, target_ulong address) diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 40232201bb..c2f436f8d3 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -894,7 +894,7 @@ void spr_write_40x_pid(DisasContext *ctx, int sprn, int gprn) { TCGv t0 = tcg_temp_new(); tcg_gen_andi_tl(t0, cpu_gpr[gprn], 0xFF); - gen_store_spr(SPR_40x_PID, t0); + gen_helper_store_40x_pid(cpu_env, t0); tcg_temp_free(t0); } @@ -911,22 +911,8 @@ void spr_write_booke_tsr(DisasContext *ctx, int sprn, int gprn) } #endif -/* PowerPC 403 specific registers */ -/* PBL1 / PBU1 / PBL2 / PBU2 */ +/* PIR */ #if !defined(CONFIG_USER_ONLY) -void spr_read_403_pbr(DisasContext *ctx, int gprn, int sprn) -{ - tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, - offsetof(CPUPPCState, pb[sprn - SPR_403_PBL1])); -} - -void spr_write_403_pbr(DisasContext *ctx, int sprn, int gprn) -{ - TCGv_i32 t0 = tcg_const_i32(sprn - SPR_403_PBL1); - gen_helper_store_403_pbr(cpu_env, t0, cpu_gpr[gprn]); - tcg_temp_free_i32(t0); -} - void spr_write_pir(DisasContext *ctx, int sprn, int gprn) { TCGv t0 = tcg_temp_new(); @@ -6286,33 +6272,6 @@ static void gen_srq(DisasContext *ctx) } } -/* PowerPC 602 specific instructions */ - -/* dsa */ -static void gen_dsa(DisasContext *ctx) -{ - /* XXX: TODO */ - gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); -} - -/* esa */ -static void gen_esa(DisasContext *ctx) -{ - /* XXX: TODO */ - gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); -} - -/* mfrom */ -static void gen_mfrom(DisasContext *ctx) -{ -#if defined(CONFIG_USER_ONLY) - GEN_PRIV; -#else - CHK_SV; - gen_helper_602_mfrom(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); -#endif /* defined(CONFIG_USER_ONLY) */ -} - /* 602 - 603 - G2 TLB management */ /* tlbld */ @@ -7793,9 +7752,6 @@ GEN_HANDLER(sriq, 0x1F, 0x18, 0x15, 0x00000000, PPC_POWER_BR), GEN_HANDLER(srliq, 0x1F, 0x18, 0x17, 0x00000000, PPC_POWER_BR), GEN_HANDLER(srlq, 0x1F, 0x18, 0x16, 0x00000000, PPC_POWER_BR), GEN_HANDLER(srq, 0x1F, 0x18, 0x14, 0x00000000, PPC_POWER_BR), -GEN_HANDLER(dsa, 0x1F, 0x14, 0x13, 0x03FFF801, PPC_602_SPEC), -GEN_HANDLER(esa, 0x1F, 0x14, 0x12, 0x03FFF801, PPC_602_SPEC), -GEN_HANDLER(mfrom, 0x1F, 0x09, 0x08, 0x03E0F801, PPC_602_SPEC), GEN_HANDLER2(tlbld_6xx, "tlbld", 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB), GEN_HANDLER2(tlbli_6xx, "tlbli", 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB), GEN_HANDLER(clf, 0x1F, 0x16, 0x03, 0x03E00000, PPC_POWER), diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 9bc25d3055..1cb0436187 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -29,6 +29,8 @@ #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "fpu/softfloat-helpers.h" +#include "sysemu/kvm.h" +#include "kvm_riscv.h" /* RISC-V CPU definitions */ @@ -233,6 +235,18 @@ static void rv32_imafcu_nommu_cpu_init(Object *obj) } #endif +#if defined(CONFIG_KVM) +static void riscv_host_cpu_init(Object *obj) +{ + CPURISCVState *env = &RISCV_CPU(obj)->env; +#if defined(TARGET_RISCV32) + set_misa(env, MXL_RV32, 0); +#elif defined(TARGET_RISCV64) + set_misa(env, MXL_RV64, 0); +#endif +} +#endif + static ObjectClass *riscv_cpu_class_by_name(const char *cpu_model) { ObjectClass *oc; @@ -341,7 +355,12 @@ static void riscv_cpu_set_pc(CPUState *cs, vaddr value) { RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; - env->pc = value; + + if (env->xl == MXL_RV32) { + env->pc = (int32_t)value; + } else { + env->pc = value; + } } static void riscv_cpu_synchronize_from_tb(CPUState *cs, @@ -349,7 +368,13 @@ static void riscv_cpu_synchronize_from_tb(CPUState *cs, { RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; - env->pc = tb->pc; + RISCVMXL xl = FIELD_EX32(tb->flags, TB_FLAGS, XL); + + if (xl == MXL_RV32) { + env->pc = (int32_t)tb->pc; + } else { + env->pc = tb->pc; + } } static bool riscv_cpu_has_work(CPUState *cs) @@ -370,7 +395,12 @@ static bool riscv_cpu_has_work(CPUState *cs) void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb, target_ulong *data) { - env->pc = data[0]; + RISCVMXL xl = FIELD_EX32(tb->flags, TB_FLAGS, XL); + if (xl == MXL_RV32) { + env->pc = (int32_t)data[0]; + } else { + env->pc = data[0]; + } } static void riscv_cpu_reset(DeviceState *dev) @@ -392,6 +422,16 @@ static void riscv_cpu_reset(DeviceState *dev) */ env->mstatus = set_field(env->mstatus, MSTATUS64_SXL, env->misa_mxl); env->mstatus = set_field(env->mstatus, MSTATUS64_UXL, env->misa_mxl); + if (riscv_has_ext(env, RVH)) { + env->vsstatus = set_field(env->vsstatus, + MSTATUS64_SXL, env->misa_mxl); + env->vsstatus = set_field(env->vsstatus, + MSTATUS64_UXL, env->misa_mxl); + env->mstatus_hs = set_field(env->mstatus_hs, + MSTATUS64_SXL, env->misa_mxl); + env->mstatus_hs = set_field(env->mstatus_hs, + MSTATUS64_UXL, env->misa_mxl); + } } env->mcause = 0; env->pc = env->resetvec; @@ -399,9 +439,17 @@ static void riscv_cpu_reset(DeviceState *dev) /* mmte is supposed to have pm.current hardwired to 1 */ env->mmte |= (PM_EXT_INITIAL | MMTE_M_PM_CURRENT); #endif + env->xl = riscv_cpu_mxl(env); + riscv_cpu_update_mask(env); cs->exception_index = RISCV_EXCP_NONE; env->load_res = -1; set_default_nan_mode(1, &env->fp_status); + +#ifndef CONFIG_USER_ONLY + if (kvm_enabled()) { + kvm_riscv_reset_vcpu(cpu); + } +#endif } static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info) @@ -429,6 +477,7 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) RISCVCPU *cpu = RISCV_CPU(dev); CPURISCVState *env = &cpu->env; RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(dev); + CPUClass *cc = CPU_CLASS(mcc); int priv_version = 0; Error *local_err = NULL; @@ -479,11 +528,13 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) switch (env->misa_mxl_max) { #ifdef TARGET_RISCV64 case MXL_RV64: + cc->gdb_core_xml_file = "riscv-64bit-cpu.xml"; break; case MXL_RV128: break; #endif case MXL_RV32: + cc->gdb_core_xml_file = "riscv-32bit-cpu.xml"; break; default: g_assert_not_reached(); @@ -589,6 +640,10 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) } set_vext_version(env, vext_version); } + if ((cpu->cfg.ext_zve32f || cpu->cfg.ext_zve64f) && !cpu->cfg.ext_f) { + error_setg(errp, "Zve32f/Zve64f extension depends upon RVF."); + return; + } if (cpu->cfg.ext_j) { ext |= RVJ; } @@ -622,7 +677,11 @@ static void riscv_cpu_set_irq(void *opaque, int irq, int level) case IRQ_S_EXT: case IRQ_VS_EXT: case IRQ_M_EXT: - riscv_cpu_update_mip(cpu, 1 << irq, BOOL_TO_MASK(level)); + if (kvm_enabled()) { + kvm_riscv_set_irq(cpu, irq, level); + } else { + riscv_cpu_update_mip(cpu, 1 << irq, BOOL_TO_MASK(level)); + } break; default: g_assert_not_reached(); @@ -660,6 +719,8 @@ static Property riscv_cpu_properties[] = { DEFINE_PROP_BOOL("Zicsr", RISCVCPU, cfg.ext_icsr, true), DEFINE_PROP_BOOL("Zfh", RISCVCPU, cfg.ext_zfh, false), DEFINE_PROP_BOOL("Zfhmin", RISCVCPU, cfg.ext_zfhmin, false), + DEFINE_PROP_BOOL("Zve32f", RISCVCPU, cfg.ext_zve32f, false), + DEFINE_PROP_BOOL("Zve64f", RISCVCPU, cfg.ext_zve64f, false), DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true), DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true), @@ -755,11 +816,6 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data) cc->gdb_read_register = riscv_cpu_gdb_read_register; cc->gdb_write_register = riscv_cpu_gdb_write_register; cc->gdb_num_core_regs = 33; -#if defined(TARGET_RISCV32) - cc->gdb_core_xml_file = "riscv-32bit-cpu.xml"; -#elif defined(TARGET_RISCV64) - cc->gdb_core_xml_file = "riscv-64bit-cpu.xml"; -#endif cc->gdb_stop_before_watchpoint = true; cc->disas_set_info = riscv_cpu_disas_set_info; #ifndef CONFIG_USER_ONLY @@ -835,6 +891,9 @@ static const TypeInfo riscv_cpu_type_infos[] = { .class_init = riscv_cpu_class_init, }, DEFINE_CPU(TYPE_RISCV_CPU_ANY, riscv_any_cpu_init), +#if defined(CONFIG_KVM) + DEFINE_CPU(TYPE_RISCV_CPU_HOST, riscv_host_cpu_init), +#endif #if defined(TARGET_RISCV32) DEFINE_CPU(TYPE_RISCV_CPU_BASE32, rv32_base_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_IBEX, rv32_ibex_cpu_init), diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 4d63086765..55635d68d5 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -47,6 +47,7 @@ #define TYPE_RISCV_CPU_SIFIVE_E51 RISCV_CPU_TYPE_NAME("sifive-e51") #define TYPE_RISCV_CPU_SIFIVE_U34 RISCV_CPU_TYPE_NAME("sifive-u34") #define TYPE_RISCV_CPU_SIFIVE_U54 RISCV_CPU_TYPE_NAME("sifive-u54") +#define TYPE_RISCV_CPU_HOST RISCV_CPU_TYPE_NAME("host") #if defined(TARGET_RISCV32) # define TYPE_RISCV_CPU_BASE TYPE_RISCV_CPU_BASE32 @@ -110,7 +111,6 @@ FIELD(VTYPE, VTA, 6, 1) FIELD(VTYPE, VMA, 7, 1) FIELD(VTYPE, VEDIV, 8, 2) FIELD(VTYPE, RESERVED, 10, sizeof(target_ulong) * 8 - 11) -FIELD(VTYPE, VILL, sizeof(target_ulong) * 8 - 1, 1) struct CPURISCVState { target_ulong gpr[32]; @@ -124,6 +124,7 @@ struct CPURISCVState { target_ulong vl; target_ulong vstart; target_ulong vtype; + bool vill; target_ulong pc; target_ulong load_res; @@ -145,6 +146,7 @@ struct CPURISCVState { uint32_t misa_mxl_max; /* max mxl for this cpu */ uint32_t misa_ext; /* current extensions */ uint32_t misa_ext_mask; /* max ext for this cpu */ + uint32_t xl; /* current xlen */ /* 128-bit helpers upper part return value */ target_ulong retxh; @@ -264,11 +266,23 @@ struct CPURISCVState { target_ulong upmmask; target_ulong upmbase; #endif + target_ulong cur_pmmask; + target_ulong cur_pmbase; float_status fp_status; /* Fields from here on are preserved across CPU reset. */ QEMUTimer *timer; /* Internal timer */ + + hwaddr kernel_addr; + hwaddr fdt_addr; + + /* kvm timer */ + bool kvm_timer_dirty; + uint64_t kvm_timer_time; + uint64_t kvm_timer_compare; + uint64_t kvm_timer_state; + uint64_t kvm_timer_frequency; }; OBJECT_DECLARE_TYPE(RISCVCPU, RISCVCPUClass, @@ -329,6 +343,8 @@ struct RISCVCPU { bool ext_icsr; bool ext_zfh; bool ext_zfhmin; + bool ext_zve32f; + bool ext_zve64f; char *priv_spec; char *user_spec; @@ -432,7 +448,8 @@ FIELD(TB_FLAGS, MSTATUS_HS_VS, 18, 2) /* The combination of MXL/SXL/UXL that applies to the current cpu mode. */ FIELD(TB_FLAGS, XL, 20, 2) /* If PointerMasking should be applied */ -FIELD(TB_FLAGS, PM_ENABLED, 22, 1) +FIELD(TB_FLAGS, PM_MASK_ENABLED, 22, 1) +FIELD(TB_FLAGS, PM_BASE_ENABLED, 23, 1) #ifdef TARGET_RISCV32 #define riscv_cpu_mxl(env) ((void)(env), MXL_RV32) @@ -443,6 +460,41 @@ static inline RISCVMXL riscv_cpu_mxl(CPURISCVState *env) } #endif +#if defined(TARGET_RISCV32) +#define cpu_recompute_xl(env) ((void)(env), MXL_RV32) +#else +static inline RISCVMXL cpu_recompute_xl(CPURISCVState *env) +{ + RISCVMXL xl = env->misa_mxl; +#if !defined(CONFIG_USER_ONLY) + /* + * When emulating a 32-bit-only cpu, use RV32. + * When emulating a 64-bit cpu, and MXL has been reduced to RV32, + * MSTATUSH doesn't have UXL/SXL, therefore XLEN cannot be widened + * back to RV64 for lower privs. + */ + if (xl != MXL_RV32) { + switch (env->priv) { + case PRV_M: + break; + case PRV_U: + xl = get_field(env->mstatus, MSTATUS64_UXL); + break; + default: /* PRV_S | PRV_H */ + xl = get_field(env->mstatus, MSTATUS64_SXL); + break; + } + } +#endif + return xl; +} +#endif + +static inline int riscv_cpu_xlen(CPURISCVState *env) +{ + return 16 << env->xl; +} + /* * Encode LMUL to lmul as follows: * LMUL vlmul lmul @@ -471,6 +523,8 @@ static inline uint32_t vext_get_vlmax(RISCVCPU *cpu, target_ulong vtype) void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc, target_ulong *cs_base, uint32_t *pflags); +void riscv_cpu_update_mask(CPURISCVState *env); + RISCVException riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value, target_ulong new_value, target_ulong write_mask); diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index 5a6d49aa64..7c87433645 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -449,6 +449,9 @@ typedef enum { #define COUNTEREN_IR (1 << 2) #define COUNTEREN_HPM3 (1 << 3) +/* vsstatus CSR bits */ +#define VSSTATUS64_UXL 0x0000000300000000ULL + /* Privilege modes */ #define PRV_U 0 #define PRV_S 1 diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 434a83e66a..327a2c4f1d 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -35,46 +35,18 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch) #endif } -static RISCVMXL cpu_get_xl(CPURISCVState *env) -{ -#if defined(TARGET_RISCV32) - return MXL_RV32; -#elif defined(CONFIG_USER_ONLY) - return MXL_RV64; -#else - RISCVMXL xl = riscv_cpu_mxl(env); - - /* - * When emulating a 32-bit-only cpu, use RV32. - * When emulating a 64-bit cpu, and MXL has been reduced to RV32, - * MSTATUSH doesn't have UXL/SXL, therefore XLEN cannot be widened - * back to RV64 for lower privs. - */ - if (xl != MXL_RV32) { - switch (env->priv) { - case PRV_M: - break; - case PRV_U: - xl = get_field(env->mstatus, MSTATUS64_UXL); - break; - default: /* PRV_S | PRV_H */ - xl = get_field(env->mstatus, MSTATUS64_SXL); - break; - } - } - return xl; -#endif -} - void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc, target_ulong *cs_base, uint32_t *pflags) { + CPUState *cs = env_cpu(env); + RISCVCPU *cpu = RISCV_CPU(cs); + uint32_t flags = 0; - *pc = env->pc; + *pc = env->xl == MXL_RV32 ? env->pc & UINT32_MAX : env->pc; *cs_base = 0; - if (riscv_has_ext(env, RVV)) { + if (riscv_has_ext(env, RVV) || cpu->cfg.ext_zve32f || cpu->cfg.ext_zve64f) { /* * If env->vl equals to VLMAX, we can use generic vector operation * expanders (GVEC) to accerlate the vector operations. @@ -88,8 +60,7 @@ void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc, uint32_t maxsz = vlmax << sew; bool vl_eq_vlmax = (env->vstart == 0) && (vlmax == env->vl) && (maxsz >= 8); - flags = FIELD_DP32(flags, TB_FLAGS, VILL, - FIELD_EX64(env->vtype, VTYPE, VILL)); + flags = FIELD_DP32(flags, TB_FLAGS, VILL, env->vill); flags = FIELD_DP32(flags, TB_FLAGS, SEW, sew); flags = FIELD_DP32(flags, TB_FLAGS, LMUL, FIELD_EX64(env->vtype, VTYPE, VLMUL)); @@ -125,29 +96,59 @@ void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc, flags = FIELD_DP32(flags, TB_FLAGS, MSTATUS_HS_VS, get_field(env->mstatus_hs, MSTATUS_VS)); } +#endif + + flags = FIELD_DP32(flags, TB_FLAGS, XL, env->xl); + if (env->cur_pmmask < (env->xl == MXL_RV32 ? UINT32_MAX : UINT64_MAX)) { + flags = FIELD_DP32(flags, TB_FLAGS, PM_MASK_ENABLED, 1); + } + if (env->cur_pmbase != 0) { + flags = FIELD_DP32(flags, TB_FLAGS, PM_BASE_ENABLED, 1); + } + + *pflags = flags; +} + +void riscv_cpu_update_mask(CPURISCVState *env) +{ + target_ulong mask = -1, base = 0; + /* + * TODO: Current RVJ spec does not specify + * how the extension interacts with XLEN. + */ +#ifndef CONFIG_USER_ONLY if (riscv_has_ext(env, RVJ)) { - int priv = flags & TB_FLAGS_PRIV_MMU_MASK; - bool pm_enabled = false; - switch (priv) { - case PRV_U: - pm_enabled = env->mmte & U_PM_ENABLE; + switch (env->priv) { + case PRV_M: + if (env->mmte & M_PM_ENABLE) { + mask = env->mpmmask; + base = env->mpmbase; + } break; case PRV_S: - pm_enabled = env->mmte & S_PM_ENABLE; + if (env->mmte & S_PM_ENABLE) { + mask = env->spmmask; + base = env->spmbase; + } break; - case PRV_M: - pm_enabled = env->mmte & M_PM_ENABLE; + case PRV_U: + if (env->mmte & U_PM_ENABLE) { + mask = env->upmmask; + base = env->upmbase; + } break; default: g_assert_not_reached(); } - flags = FIELD_DP32(flags, TB_FLAGS, PM_ENABLED, pm_enabled); } #endif - - flags = FIELD_DP32(flags, TB_FLAGS, XL, cpu_get_xl(env)); - - *pflags = flags; + if (env->xl == MXL_RV32) { + env->cur_pmmask = mask & UINT32_MAX; + env->cur_pmbase = base & UINT32_MAX; + } else { + env->cur_pmmask = mask; + env->cur_pmbase = base; + } } #ifndef CONFIG_USER_ONLY @@ -361,6 +362,8 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv) } /* tlb_flush is unnecessary as mode is contained in mmu_idx */ env->priv = newpriv; + env->xl = cpu_recompute_xl(env); + riscv_cpu_update_mask(env); /* * Clear the load reservation - otherwise a reservation placed in one diff --git a/target/riscv/csr.c b/target/riscv/csr.c index adb3d4381d..e5f9d4ef93 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -47,7 +47,11 @@ static RISCVException fs(CPURISCVState *env, int csrno) static RISCVException vs(CPURISCVState *env, int csrno) { - if (env->misa_ext & RVV) { + CPUState *cs = env_cpu(env); + RISCVCPU *cpu = RISCV_CPU(cs); + + if (env->misa_ext & RVV || + cpu->cfg.ext_zve32f || cpu->cfg.ext_zve64f) { #if !defined(CONFIG_USER_ONLY) if (!env->debugger && !riscv_cpu_vector_enabled(env)) { return RISCV_EXCP_ILLEGAL_INST; @@ -279,7 +283,18 @@ static RISCVException write_fcsr(CPURISCVState *env, int csrno, static RISCVException read_vtype(CPURISCVState *env, int csrno, target_ulong *val) { - *val = env->vtype; + uint64_t vill; + switch (env->xl) { + case MXL_RV32: + vill = (uint32_t)env->vill << 31; + break; + case MXL_RV64: + vill = (uint64_t)env->vill << 63; + break; + default: + g_assert_not_reached(); + } + *val = (target_ulong)vill | env->vtype; return RISCV_EXCP_NONE; } @@ -481,7 +496,7 @@ static const target_ulong vs_delegable_excps = DELEGABLE_EXCPS & (1ULL << (RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT))); static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS | - SSTATUS_SUM | SSTATUS_MXR | SSTATUS_VS | (target_ulong)SSTATUS64_UXL; + SSTATUS_SUM | SSTATUS_MXR | SSTATUS_VS; static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP; static const target_ulong hip_writable_mask = MIP_VSSIP; static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP; @@ -557,6 +572,7 @@ static RISCVException write_mstatus(CPURISCVState *env, int csrno, { uint64_t mstatus = env->mstatus; uint64_t mask = 0; + RISCVMXL xl = riscv_cpu_mxl(env); /* flush tlb on mstatus fields that affect VM */ if ((val ^ mstatus) & (MSTATUS_MXR | MSTATUS_MPP | MSTATUS_MPV | @@ -568,23 +584,25 @@ static RISCVException write_mstatus(CPURISCVState *env, int csrno, MSTATUS_MPP | MSTATUS_MXR | MSTATUS_TVM | MSTATUS_TSR | MSTATUS_TW | MSTATUS_VS; - if (riscv_cpu_mxl(env) != MXL_RV32) { + if (xl != MXL_RV32 || env->debugger) { /* * RV32: MPV and GVA are not in mstatus. The current plan is to * add them to mstatush. For now, we just don't support it. */ mask |= MSTATUS_MPV | MSTATUS_GVA; + if ((val & MSTATUS64_UXL) != 0) { + mask |= MSTATUS64_UXL; + } } mstatus = (mstatus & ~mask) | (val & mask); - RISCVMXL xl = riscv_cpu_mxl(env); if (xl > MXL_RV32) { - /* SXL and UXL fields are for now read only */ + /* SXL field is for now read only */ mstatus = set_field(mstatus, MSTATUS64_SXL, xl); - mstatus = set_field(mstatus, MSTATUS64_UXL, xl); } env->mstatus = mstatus; + env->xl = cpu_recompute_xl(env); return RISCV_EXCP_NONE; } @@ -700,6 +718,7 @@ static RISCVException write_misa(CPURISCVState *env, int csrno, /* flush translation cache */ tb_flush(env_cpu(env)); env->misa_ext = val; + env->xl = riscv_cpu_mxl(env); return RISCV_EXCP_NONE; } @@ -881,6 +900,9 @@ static RISCVException read_sstatus_i128(CPURISCVState *env, int csrno, { uint64_t mask = sstatus_v1_10_mask; uint64_t sstatus = env->mstatus & mask; + if (env->xl != MXL_RV32 || env->debugger) { + mask |= SSTATUS64_UXL; + } *val = int128_make128(sstatus, add_status_sd(MXL_RV128, sstatus)); return RISCV_EXCP_NONE; @@ -890,7 +912,9 @@ static RISCVException read_sstatus(CPURISCVState *env, int csrno, target_ulong *val) { target_ulong mask = (sstatus_v1_10_mask); - + if (env->xl != MXL_RV32 || env->debugger) { + mask |= SSTATUS64_UXL; + } /* TODO: Use SXL not MXL. */ *val = add_status_sd(riscv_cpu_mxl(env), env->mstatus & mask); return RISCV_EXCP_NONE; @@ -900,6 +924,12 @@ static RISCVException write_sstatus(CPURISCVState *env, int csrno, target_ulong val) { target_ulong mask = (sstatus_v1_10_mask); + + if (env->xl != MXL_RV32 || env->debugger) { + if ((val & SSTATUS64_UXL) != 0) { + mask |= SSTATUS64_UXL; + } + } target_ulong newval = (env->mstatus & ~mask) | (val & mask); return write_mstatus(env, CSR_MSTATUS, newval); } @@ -1363,6 +1393,9 @@ static RISCVException write_vsstatus(CPURISCVState *env, int csrno, target_ulong val) { uint64_t mask = (target_ulong)-1; + if ((val & VSSTATUS64_UXL) == 0) { + mask &= ~VSSTATUS64_UXL; + } env->vsstatus = (env->vsstatus & ~mask) | (uint64_t)val; return RISCV_EXCP_NONE; } @@ -1493,9 +1526,23 @@ static RISCVException write_mseccfg(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } +static bool check_pmp_reg_index(CPURISCVState *env, uint32_t reg_index) +{ + /* TODO: RV128 restriction check */ + if ((reg_index & 1) && (riscv_cpu_mxl(env) == MXL_RV64)) { + return false; + } + return true; +} + static RISCVException read_pmpcfg(CPURISCVState *env, int csrno, target_ulong *val) { + uint32_t reg_index = csrno - CSR_PMPCFG0; + + if (!check_pmp_reg_index(env, reg_index)) { + return RISCV_EXCP_ILLEGAL_INST; + } *val = pmpcfg_csr_read(env, csrno - CSR_PMPCFG0); return RISCV_EXCP_NONE; } @@ -1503,6 +1550,11 @@ static RISCVException read_pmpcfg(CPURISCVState *env, int csrno, static RISCVException write_pmpcfg(CPURISCVState *env, int csrno, target_ulong val) { + uint32_t reg_index = csrno - CSR_PMPCFG0; + + if (!check_pmp_reg_index(env, reg_index)) { + return RISCV_EXCP_ILLEGAL_INST; + } pmpcfg_csr_write(env, csrno - CSR_PMPCFG0, val); return RISCV_EXCP_NONE; } @@ -1531,6 +1583,9 @@ static bool check_pm_current_disabled(CPURISCVState *env, int csrno) int csr_priv = get_field(csrno, 0x300); int pm_current; + if (env->debugger) { + return false; + } /* * If priv lvls differ that means we're accessing csr from higher priv lvl, * so allow the access @@ -1579,6 +1634,7 @@ static RISCVException write_mmte(CPURISCVState *env, int csrno, /* hardwiring pm.instruction bit to 0, since it's not supported yet */ wpri_val &= ~(MMTE_M_PM_INSN | MMTE_S_PM_INSN | MMTE_U_PM_INSN); env->mmte = wpri_val | PM_EXT_DIRTY; + riscv_cpu_update_mask(env); /* Set XS and SD bits, since PM CSRs are dirty */ mstatus = env->mstatus | MSTATUS_XS; @@ -1654,6 +1710,9 @@ static RISCVException write_mpmmask(CPURISCVState *env, int csrno, uint64_t mstatus; env->mpmmask = val; + if ((env->priv == PRV_M) && (env->mmte & M_PM_ENABLE)) { + env->cur_pmmask = val; + } env->mmte |= PM_EXT_DIRTY; /* Set XS and SD bits, since PM CSRs are dirty */ @@ -1679,6 +1738,9 @@ static RISCVException write_spmmask(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } env->spmmask = val; + if ((env->priv == PRV_S) && (env->mmte & S_PM_ENABLE)) { + env->cur_pmmask = val; + } env->mmte |= PM_EXT_DIRTY; /* Set XS and SD bits, since PM CSRs are dirty */ @@ -1704,6 +1766,9 @@ static RISCVException write_upmmask(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } env->upmmask = val; + if ((env->priv == PRV_U) && (env->mmte & U_PM_ENABLE)) { + env->cur_pmmask = val; + } env->mmte |= PM_EXT_DIRTY; /* Set XS and SD bits, since PM CSRs are dirty */ @@ -1725,6 +1790,9 @@ static RISCVException write_mpmbase(CPURISCVState *env, int csrno, uint64_t mstatus; env->mpmbase = val; + if ((env->priv == PRV_M) && (env->mmte & M_PM_ENABLE)) { + env->cur_pmbase = val; + } env->mmte |= PM_EXT_DIRTY; /* Set XS and SD bits, since PM CSRs are dirty */ @@ -1750,6 +1818,9 @@ static RISCVException write_spmbase(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } env->spmbase = val; + if ((env->priv == PRV_S) && (env->mmte & S_PM_ENABLE)) { + env->cur_pmbase = val; + } env->mmte |= PM_EXT_DIRTY; /* Set XS and SD bits, since PM CSRs are dirty */ @@ -1775,6 +1846,9 @@ static RISCVException write_upmbase(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } env->upmbase = val; + if ((env->priv == PRV_U) && (env->mmte & U_PM_ENABLE)) { + env->cur_pmbase = val; + } env->mmte |= PM_EXT_DIRTY; /* Set XS and SD bits, since PM CSRs are dirty */ diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c index a5429b92d4..f531a74c2f 100644 --- a/target/riscv/gdbstub.c +++ b/target/riscv/gdbstub.c @@ -50,11 +50,23 @@ int riscv_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) { RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; + target_ulong tmp; if (n < 32) { - return gdb_get_regl(mem_buf, env->gpr[n]); + tmp = env->gpr[n]; } else if (n == 32) { - return gdb_get_regl(mem_buf, env->pc); + tmp = env->pc; + } else { + return 0; + } + + switch (env->misa_mxl_max) { + case MXL_RV32: + return gdb_get_reg32(mem_buf, tmp); + case MXL_RV64: + return gdb_get_reg64(mem_buf, tmp); + default: + g_assert_not_reached(); } return 0; } @@ -63,18 +75,32 @@ int riscv_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) { RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; - - if (n == 0) { - /* discard writes to x0 */ - return sizeof(target_ulong); - } else if (n < 32) { - env->gpr[n] = ldtul_p(mem_buf); - return sizeof(target_ulong); + int length = 0; + target_ulong tmp; + + switch (env->misa_mxl_max) { + case MXL_RV32: + tmp = (int32_t)ldl_p(mem_buf); + length = 4; + break; + case MXL_RV64: + if (env->xl < MXL_RV64) { + tmp = (int32_t)ldq_p(mem_buf); + } else { + tmp = ldq_p(mem_buf); + } + length = 8; + break; + default: + g_assert_not_reached(); + } + if (n > 0 && n < 32) { + env->gpr[n] = tmp; } else if (n == 32) { - env->pc = ldtul_p(mem_buf); - return sizeof(target_ulong); + env->pc = tmp; } - return 0; + + return length; } static int riscv_gdb_get_fpu(CPURISCVState *env, GByteArray *buf, int n) @@ -387,13 +413,20 @@ void riscv_cpu_register_gdb_regs_for_features(CPUState *cs) cs->gdb_num_regs), "riscv-vector.xml", 0); } -#if defined(TARGET_RISCV32) - gdb_register_coprocessor(cs, riscv_gdb_get_virtual, riscv_gdb_set_virtual, - 1, "riscv-32bit-virtual.xml", 0); -#elif defined(TARGET_RISCV64) - gdb_register_coprocessor(cs, riscv_gdb_get_virtual, riscv_gdb_set_virtual, - 1, "riscv-64bit-virtual.xml", 0); -#endif + switch (env->misa_mxl_max) { + case MXL_RV32: + gdb_register_coprocessor(cs, riscv_gdb_get_virtual, + riscv_gdb_set_virtual, + 1, "riscv-32bit-virtual.xml", 0); + break; + case MXL_RV64: + gdb_register_coprocessor(cs, riscv_gdb_get_virtual, + riscv_gdb_set_virtual, + 1, "riscv-64bit-virtual.xml", 0); + break; + default: + g_assert_not_reached(); + } gdb_register_coprocessor(cs, riscv_gdb_get_csr, riscv_gdb_set_csr, riscv_gen_dynamic_csr_xml(cs, cs->gdb_num_regs), diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 6cf6d6ce98..72cc2582f4 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -100,8 +100,8 @@ DEF_HELPER_2(csrr_i128, tl, env, int) DEF_HELPER_4(csrw_i128, void, env, int, tl, tl) DEF_HELPER_6(csrrw_i128, tl, env, int, tl, tl, tl, tl) #ifndef CONFIG_USER_ONLY -DEF_HELPER_2(sret, tl, env, tl) -DEF_HELPER_2(mret, tl, env, tl) +DEF_HELPER_1(sret, tl, env) +DEF_HELPER_1(mret, tl, env) DEF_HELPER_1(wfi, void, env) DEF_HELPER_1(tlb_flush, void, env) #endif diff --git a/target/riscv/insn_trans/trans_privileged.c.inc b/target/riscv/insn_trans/trans_privileged.c.inc index 75c6ef80a6..53613682e8 100644 --- a/target/riscv/insn_trans/trans_privileged.c.inc +++ b/target/riscv/insn_trans/trans_privileged.c.inc @@ -74,10 +74,8 @@ static bool trans_uret(DisasContext *ctx, arg_uret *a) static bool trans_sret(DisasContext *ctx, arg_sret *a) { #ifndef CONFIG_USER_ONLY - tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); - if (has_ext(ctx, RVS)) { - gen_helper_sret(cpu_pc, cpu_env, cpu_pc); + gen_helper_sret(cpu_pc, cpu_env); tcg_gen_exit_tb(NULL, 0); /* no chaining */ ctx->base.is_jmp = DISAS_NORETURN; } else { @@ -92,8 +90,7 @@ static bool trans_sret(DisasContext *ctx, arg_sret *a) static bool trans_mret(DisasContext *ctx, arg_mret *a) { #ifndef CONFIG_USER_ONLY - tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); - gen_helper_mret(cpu_pc, cpu_env, cpu_pc); + gen_helper_mret(cpu_pc, cpu_env); tcg_gen_exit_tb(NULL, 0); /* no chaining */ ctx->base.is_jmp = DISAS_NORETURN; return true; @@ -105,7 +102,7 @@ static bool trans_mret(DisasContext *ctx, arg_mret *a) static bool trans_wfi(DisasContext *ctx, arg_wfi *a) { #ifndef CONFIG_USER_ONLY - tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn); + gen_set_pc_imm(ctx, ctx->pc_succ_insn); gen_helper_wfi(cpu_env); return true; #else diff --git a/target/riscv/insn_trans/trans_rva.c.inc b/target/riscv/insn_trans/trans_rva.c.inc index 86032fa9a7..45db82c9be 100644 --- a/target/riscv/insn_trans/trans_rva.c.inc +++ b/target/riscv/insn_trans/trans_rva.c.inc @@ -20,12 +20,11 @@ static bool gen_lr(DisasContext *ctx, arg_atomic *a, MemOp mop) { - TCGv src1 = get_gpr(ctx, a->rs1, EXT_ZERO); + TCGv src1 = get_address(ctx, a->rs1, 0); if (a->rl) { tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); } - src1 = gen_pm_adjust_address(ctx, src1); tcg_gen_qemu_ld_tl(load_val, src1, ctx->mem_idx, mop); if (a->aq) { tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ); @@ -44,8 +43,7 @@ static bool gen_sc(DisasContext *ctx, arg_atomic *a, MemOp mop) TCGLabel *l1 = gen_new_label(); TCGLabel *l2 = gen_new_label(); - src1 = get_gpr(ctx, a->rs1, EXT_ZERO); - src1 = gen_pm_adjust_address(ctx, src1); + src1 = get_address(ctx, a->rs1, 0); tcg_gen_brcond_tl(TCG_COND_NE, load_res, src1, l1); /* @@ -83,10 +81,9 @@ static bool gen_amo(DisasContext *ctx, arg_atomic *a, MemOp mop) { TCGv dest = dest_gpr(ctx, a->rd); - TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE); + TCGv src1 = get_address(ctx, a->rs1, 0); TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE); - src1 = gen_pm_adjust_address(ctx, src1); func(dest, src1, src2, ctx->mem_idx, mop); gen_set_gpr(ctx, a->rd, dest); diff --git a/target/riscv/insn_trans/trans_rvd.c.inc b/target/riscv/insn_trans/trans_rvd.c.inc index ed444b042a..091ed3a8ad 100644 --- a/target/riscv/insn_trans/trans_rvd.c.inc +++ b/target/riscv/insn_trans/trans_rvd.c.inc @@ -25,14 +25,7 @@ static bool trans_fld(DisasContext *ctx, arg_fld *a) REQUIRE_FPU; REQUIRE_EXT(ctx, RVD); - addr = get_gpr(ctx, a->rs1, EXT_NONE); - if (a->imm) { - TCGv temp = temp_new(ctx); - tcg_gen_addi_tl(temp, addr, a->imm); - addr = temp; - } - addr = gen_pm_adjust_address(ctx, addr); - + addr = get_address(ctx, a->rs1, a->imm); tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], addr, ctx->mem_idx, MO_TEUQ); mark_fs_dirty(ctx); @@ -46,16 +39,8 @@ static bool trans_fsd(DisasContext *ctx, arg_fsd *a) REQUIRE_FPU; REQUIRE_EXT(ctx, RVD); - addr = get_gpr(ctx, a->rs1, EXT_NONE); - if (a->imm) { - TCGv temp = temp_new(ctx); - tcg_gen_addi_tl(temp, addr, a->imm); - addr = temp; - } - addr = gen_pm_adjust_address(ctx, addr); - + addr = get_address(ctx, a->rs1, a->imm); tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], addr, ctx->mem_idx, MO_TEUQ); - return true; } diff --git a/target/riscv/insn_trans/trans_rvf.c.inc b/target/riscv/insn_trans/trans_rvf.c.inc index b5459249c4..0aac87f7db 100644 --- a/target/riscv/insn_trans/trans_rvf.c.inc +++ b/target/riscv/insn_trans/trans_rvf.c.inc @@ -31,14 +31,7 @@ static bool trans_flw(DisasContext *ctx, arg_flw *a) REQUIRE_FPU; REQUIRE_EXT(ctx, RVF); - addr = get_gpr(ctx, a->rs1, EXT_NONE); - if (a->imm) { - TCGv temp = temp_new(ctx); - tcg_gen_addi_tl(temp, addr, a->imm); - addr = temp; - } - addr = gen_pm_adjust_address(ctx, addr); - + addr = get_address(ctx, a->rs1, a->imm); dest = cpu_fpr[a->rd]; tcg_gen_qemu_ld_i64(dest, addr, ctx->mem_idx, MO_TEUL); gen_nanbox_s(dest, dest); @@ -54,16 +47,8 @@ static bool trans_fsw(DisasContext *ctx, arg_fsw *a) REQUIRE_FPU; REQUIRE_EXT(ctx, RVF); - addr = get_gpr(ctx, a->rs1, EXT_NONE); - if (a->imm) { - TCGv temp = tcg_temp_new(); - tcg_gen_addi_tl(temp, addr, a->imm); - addr = temp; - } - addr = gen_pm_adjust_address(ctx, addr); - + addr = get_address(ctx, a->rs1, a->imm); tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], addr, ctx->mem_idx, MO_TEUL); - return true; } diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_trans/trans_rvi.c.inc index 3a0ae28fef..3cd1b3f877 100644 --- a/target/riscv/insn_trans/trans_rvi.c.inc +++ b/target/riscv/insn_trans/trans_rvi.c.inc @@ -59,6 +59,7 @@ static bool trans_jalr(DisasContext *ctx, arg_jalr *a) tcg_gen_addi_tl(cpu_pc, get_gpr(ctx, a->rs1, EXT_NONE), a->imm); tcg_gen_andi_tl(cpu_pc, cpu_pc, (target_ulong)-2); + gen_set_pc(ctx, cpu_pc); if (!has_ext(ctx, RVC)) { TCGv t0 = tcg_temp_new(); @@ -68,9 +69,7 @@ static bool trans_jalr(DisasContext *ctx, arg_jalr *a) tcg_temp_free(t0); } - if (a->rd != 0) { - tcg_gen_movi_tl(cpu_gpr[a->rd], ctx->pc_succ_insn); - } + gen_set_gpri(ctx, a->rd, ctx->pc_succ_insn); tcg_gen_lookup_and_goto_ptr(); if (misaligned) { @@ -227,14 +226,7 @@ static bool trans_bgeu(DisasContext *ctx, arg_bgeu *a) static bool gen_load_tl(DisasContext *ctx, arg_lb *a, MemOp memop) { TCGv dest = dest_gpr(ctx, a->rd); - TCGv addr = get_gpr(ctx, a->rs1, EXT_NONE); - - if (a->imm) { - TCGv temp = temp_new(ctx); - tcg_gen_addi_tl(temp, addr, a->imm); - addr = temp; - } - addr = gen_pm_adjust_address(ctx, addr); + TCGv addr = get_address(ctx, a->rs1, a->imm); tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, memop); gen_set_gpr(ctx, a->rd, dest); @@ -331,16 +323,9 @@ static bool trans_ldu(DisasContext *ctx, arg_ldu *a) static bool gen_store_tl(DisasContext *ctx, arg_sb *a, MemOp memop) { - TCGv addr = get_gpr(ctx, a->rs1, EXT_NONE); + TCGv addr = get_address(ctx, a->rs1, a->imm); TCGv data = get_gpr(ctx, a->rs2, EXT_NONE); - if (a->imm) { - TCGv temp = temp_new(ctx); - tcg_gen_addi_tl(temp, addr, a->imm); - addr = temp; - } - addr = gen_pm_adjust_address(ctx, addr); - tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, memop); return true; } @@ -829,7 +814,7 @@ static bool trans_fence_i(DisasContext *ctx, arg_fence_i *a) * FENCE_I is a no-op in QEMU, * however we need to end the translation block */ - tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn); + gen_set_pc_imm(ctx, ctx->pc_succ_insn); tcg_gen_exit_tb(NULL, 0); ctx->base.is_jmp = DISAS_NORETURN; return true; @@ -838,7 +823,7 @@ static bool trans_fence_i(DisasContext *ctx, arg_fence_i *a) static bool do_csr_post(DisasContext *ctx) { /* We may have changed important cpu state -- exit to main loop. */ - tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn); + gen_set_pc_imm(ctx, ctx->pc_succ_insn); tcg_gen_exit_tb(NULL, 0); ctx->base.is_jmp = DISAS_NORETURN; return true; @@ -925,7 +910,8 @@ static bool do_csrrw_i128(DisasContext *ctx, int rd, int rc, static bool trans_csrrw(DisasContext *ctx, arg_csrrw *a) { - if (get_xl(ctx) < MXL_RV128) { + RISCVMXL xl = get_xl(ctx); + if (xl < MXL_RV128) { TCGv src = get_gpr(ctx, a->rs1, EXT_NONE); /* @@ -936,7 +922,8 @@ static bool trans_csrrw(DisasContext *ctx, arg_csrrw *a) return do_csrw(ctx, a->csr, src); } - TCGv mask = tcg_constant_tl(-1); + TCGv mask = tcg_constant_tl(xl == MXL_RV32 ? UINT32_MAX : + (target_ulong)-1); return do_csrrw(ctx, a->rd, a->csr, src, mask); } else { TCGv srcl = get_gpr(ctx, a->rs1, EXT_NONE); @@ -1014,7 +1001,8 @@ static bool trans_csrrc(DisasContext *ctx, arg_csrrc *a) static bool trans_csrrwi(DisasContext *ctx, arg_csrrwi *a) { - if (get_xl(ctx) < MXL_RV128) { + RISCVMXL xl = get_xl(ctx); + if (xl < MXL_RV128) { TCGv src = tcg_constant_tl(a->rs1); /* @@ -1025,7 +1013,8 @@ static bool trans_csrrwi(DisasContext *ctx, arg_csrrwi *a) return do_csrw(ctx, a->csr, src); } - TCGv mask = tcg_constant_tl(-1); + TCGv mask = tcg_constant_tl(xl == MXL_RV32 ? UINT32_MAX : + (target_ulong)-1); return do_csrrw(ctx, a->rd, a->csr, src, mask); } else { TCGv src = tcg_constant_tl(a->rs1); diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index 6c285c958b..f85a9e83b4 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -66,6 +66,50 @@ static bool require_scale_rvf(DisasContext *s) } } +static bool require_zve32f(DisasContext *s) +{ + /* RVV + Zve32f = RVV. */ + if (has_ext(s, RVV)) { + return true; + } + + /* Zve32f doesn't support FP64. (Section 18.2) */ + return s->ext_zve32f ? s->sew <= MO_32 : true; +} + +static bool require_scale_zve32f(DisasContext *s) +{ + /* RVV + Zve32f = RVV. */ + if (has_ext(s, RVV)) { + return true; + } + + /* Zve32f doesn't support FP64. (Section 18.2) */ + return s->ext_zve64f ? s->sew <= MO_16 : true; +} + +static bool require_zve64f(DisasContext *s) +{ + /* RVV + Zve64f = RVV. */ + if (has_ext(s, RVV)) { + return true; + } + + /* Zve64f doesn't support FP64. (Section 18.2) */ + return s->ext_zve64f ? s->sew <= MO_32 : true; +} + +static bool require_scale_zve64f(DisasContext *s) +{ + /* RVV + Zve64f = RVV. */ + if (has_ext(s, RVV)) { + return true; + } + + /* Zve64f doesn't support FP64. (Section 18.2) */ + return s->ext_zve64f ? s->sew <= MO_16 : true; +} + /* Destination vector register group cannot overlap source mask register. */ static bool require_vm(int vm, int vd) { @@ -129,7 +173,8 @@ static bool do_vsetvl(DisasContext *s, int rd, int rs1, TCGv s2) { TCGv s1, dst; - if (!require_rvv(s) || !has_ext(s, RVV)) { + if (!require_rvv(s) || + !(has_ext(s, RVV) || s->ext_zve32f || s->ext_zve64f)) { return false; } @@ -149,7 +194,7 @@ static bool do_vsetvl(DisasContext *s, int rd, int rs1, TCGv s2) gen_set_gpr(s, rd, dst); mark_vs_dirty(s); - tcg_gen_movi_tl(cpu_pc, s->pc_succ_insn); + gen_set_pc_imm(s, s->pc_succ_insn); tcg_gen_lookup_and_goto_ptr(); s->base.is_jmp = DISAS_NORETURN; @@ -164,7 +209,8 @@ static bool do_vsetivli(DisasContext *s, int rd, TCGv s1, TCGv s2) { TCGv dst; - if (!require_rvv(s) || !has_ext(s, RVV)) { + if (!require_rvv(s) || + !(has_ext(s, RVV) || s->ext_zve32f || s->ext_zve64f)) { return false; } @@ -173,7 +219,7 @@ static bool do_vsetivli(DisasContext *s, int rd, TCGv s1, TCGv s2) gen_helper_vsetvl(dst, cpu_env, s1, s2); gen_set_gpr(s, rd, dst); mark_vs_dirty(s); - tcg_gen_movi_tl(cpu_pc, s->pc_succ_insn); + gen_set_pc_imm(s, s->pc_succ_insn); tcg_gen_lookup_and_goto_ptr(); s->base.is_jmp = DISAS_NORETURN; @@ -261,10 +307,21 @@ static bool vext_check_st_index(DisasContext *s, int vd, int vs2, int nf, uint8_t eew) { int8_t emul = eew - s->sew + s->lmul; - return (emul >= -3 && emul <= 3) && - require_align(vs2, emul) && - require_align(vd, s->lmul) && - require_nf(vd, nf, s->lmul); + bool ret = (emul >= -3 && emul <= 3) && + require_align(vs2, emul) && + require_align(vd, s->lmul) && + require_nf(vd, nf, s->lmul); + + /* + * All Zve* extensions support all vector load and store instructions, + * except Zve64* extensions do not support EEW=64 for index values + * when XLEN=32. (Section 18.2) + */ + if (get_xl(s) == MXL_RV32) { + ret &= (!has_ext(s, RVV) && s->ext_zve64f ? eew != MO_64 : true); + } + + return ret; } /* @@ -1201,7 +1258,7 @@ static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm, dest = tcg_temp_new_ptr(); mask = tcg_temp_new_ptr(); src2 = tcg_temp_new_ptr(); - src1 = get_gpr(s, rs1, EXT_NONE); + src1 = get_gpr(s, rs1, EXT_SIGN); data = FIELD_DP32(data, VDATA, VM, vm); data = FIELD_DP32(data, VDATA, LMUL, s->lmul); @@ -1895,14 +1952,41 @@ GEN_OPIVX_TRANS(vmaxu_vx, opivx_check) GEN_OPIVX_TRANS(vmax_vx, opivx_check) /* Vector Single-Width Integer Multiply Instructions */ + +static bool vmulh_vv_check(DisasContext *s, arg_rmrr *a) +{ + /* + * All Zve* extensions support all vector integer instructions, + * except that the vmulh integer multiply variants + * that return the high word of the product + * (vmulh.vv, vmulh.vx, vmulhu.vv, vmulhu.vx, vmulhsu.vv, vmulhsu.vx) + * are not included for EEW=64 in Zve64*. (Section 18.2) + */ + return opivv_check(s, a) && + (!has_ext(s, RVV) && s->ext_zve64f ? s->sew != MO_64 : true); +} + +static bool vmulh_vx_check(DisasContext *s, arg_rmrr *a) +{ + /* + * All Zve* extensions support all vector integer instructions, + * except that the vmulh integer multiply variants + * that return the high word of the product + * (vmulh.vv, vmulh.vx, vmulhu.vv, vmulhu.vx, vmulhsu.vv, vmulhsu.vx) + * are not included for EEW=64 in Zve64*. (Section 18.2) + */ + return opivx_check(s, a) && + (!has_ext(s, RVV) && s->ext_zve64f ? s->sew != MO_64 : true); +} + GEN_OPIVV_GVEC_TRANS(vmul_vv, mul) -GEN_OPIVV_TRANS(vmulh_vv, opivv_check) -GEN_OPIVV_TRANS(vmulhu_vv, opivv_check) -GEN_OPIVV_TRANS(vmulhsu_vv, opivv_check) +GEN_OPIVV_TRANS(vmulh_vv, vmulh_vv_check) +GEN_OPIVV_TRANS(vmulhu_vv, vmulh_vv_check) +GEN_OPIVV_TRANS(vmulhsu_vv, vmulh_vv_check) GEN_OPIVX_GVEC_TRANS(vmul_vx, muls) -GEN_OPIVX_TRANS(vmulh_vx, opivx_check) -GEN_OPIVX_TRANS(vmulhu_vx, opivx_check) -GEN_OPIVX_TRANS(vmulhsu_vx, opivx_check) +GEN_OPIVX_TRANS(vmulh_vx, vmulh_vx_check) +GEN_OPIVX_TRANS(vmulhu_vx, vmulh_vx_check) +GEN_OPIVX_TRANS(vmulhsu_vx, vmulh_vx_check) /* Vector Integer Divide Instructions */ GEN_OPIVV_TRANS(vdivu_vv, opivv_check) @@ -2083,8 +2167,31 @@ GEN_OPIVX_TRANS(vasub_vx, opivx_check) GEN_OPIVX_TRANS(vasubu_vx, opivx_check) /* Vector Single-Width Fractional Multiply with Rounding and Saturation */ -GEN_OPIVV_TRANS(vsmul_vv, opivv_check) -GEN_OPIVX_TRANS(vsmul_vx, opivx_check) + +static bool vsmul_vv_check(DisasContext *s, arg_rmrr *a) +{ + /* + * All Zve* extensions support all vector fixed-point arithmetic + * instructions, except that vsmul.vv and vsmul.vx are not supported + * for EEW=64 in Zve64*. (Section 18.2) + */ + return opivv_check(s, a) && + (!has_ext(s, RVV) && s->ext_zve64f ? s->sew != MO_64 : true); +} + +static bool vsmul_vx_check(DisasContext *s, arg_rmrr *a) +{ + /* + * All Zve* extensions support all vector fixed-point arithmetic + * instructions, except that vsmul.vv and vsmul.vx are not supported + * for EEW=64 in Zve64*. (Section 18.2) + */ + return opivx_check(s, a) && + (!has_ext(s, RVV) && s->ext_zve64f ? s->sew != MO_64 : true); +} + +GEN_OPIVV_TRANS(vsmul_vv, vsmul_vv_check) +GEN_OPIVX_TRANS(vsmul_vx, vsmul_vx_check) /* Vector Single-Width Scaling Shift Instructions */ GEN_OPIVV_TRANS(vssrl_vv, opivv_check) @@ -2143,7 +2250,9 @@ static bool opfvv_check(DisasContext *s, arg_rmrr *a) return require_rvv(s) && require_rvf(s) && vext_check_isa_ill(s) && - vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm); + vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm) && + require_zve32f(s) && + require_zve64f(s); } /* OPFVV without GVEC IR */ @@ -2223,7 +2332,9 @@ static bool opfvf_check(DisasContext *s, arg_rmrr *a) return require_rvv(s) && require_rvf(s) && vext_check_isa_ill(s) && - vext_check_ss(s, a->rd, a->rs2, a->vm); + vext_check_ss(s, a->rd, a->rs2, a->vm) && + require_zve32f(s) && + require_zve64f(s); } /* OPFVF without GVEC IR */ @@ -2257,7 +2368,9 @@ static bool opfvv_widen_check(DisasContext *s, arg_rmrr *a) require_scale_rvf(s) && (s->sew != MO_8) && vext_check_isa_ill(s) && - vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm); + vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm) && + require_scale_zve32f(s) && + require_scale_zve64f(s); } /* OPFVV with WIDEN */ @@ -2296,7 +2409,9 @@ static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a) require_scale_rvf(s) && (s->sew != MO_8) && vext_check_isa_ill(s) && - vext_check_ds(s, a->rd, a->rs2, a->vm); + vext_check_ds(s, a->rd, a->rs2, a->vm) && + require_scale_zve32f(s) && + require_scale_zve64f(s); } /* OPFVF with WIDEN */ @@ -2326,7 +2441,9 @@ static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a) require_scale_rvf(s) && (s->sew != MO_8) && vext_check_isa_ill(s) && - vext_check_dds(s, a->rd, a->rs1, a->rs2, a->vm); + vext_check_dds(s, a->rd, a->rs1, a->rs2, a->vm) && + require_scale_zve32f(s) && + require_scale_zve64f(s); } /* WIDEN OPFVV with WIDEN */ @@ -2365,7 +2482,9 @@ static bool opfwf_widen_check(DisasContext *s, arg_rmrr *a) require_scale_rvf(s) && (s->sew != MO_8) && vext_check_isa_ill(s) && - vext_check_dd(s, a->rd, a->rs2, a->vm); + vext_check_dd(s, a->rd, a->rs2, a->vm) && + require_scale_zve32f(s) && + require_scale_zve64f(s); } /* WIDEN OPFVF with WIDEN */ @@ -2440,7 +2559,9 @@ static bool opfv_check(DisasContext *s, arg_rmr *a) require_rvf(s) && vext_check_isa_ill(s) && /* OPFV instructions ignore vs1 check */ - vext_check_ss(s, a->rd, a->rs2, a->vm); + vext_check_ss(s, a->rd, a->rs2, a->vm) && + require_zve32f(s) && + require_zve64f(s); } static bool do_opfv(DisasContext *s, arg_rmr *a, @@ -2505,7 +2626,9 @@ static bool opfvv_cmp_check(DisasContext *s, arg_rmrr *a) return require_rvv(s) && require_rvf(s) && vext_check_isa_ill(s) && - vext_check_mss(s, a->rd, a->rs1, a->rs2); + vext_check_mss(s, a->rd, a->rs1, a->rs2) && + require_zve32f(s) && + require_zve64f(s); } GEN_OPFVV_TRANS(vmfeq_vv, opfvv_cmp_check) @@ -2518,7 +2641,9 @@ static bool opfvf_cmp_check(DisasContext *s, arg_rmrr *a) return require_rvv(s) && require_rvf(s) && vext_check_isa_ill(s) && - vext_check_ms(s, a->rd, a->rs2); + vext_check_ms(s, a->rd, a->rs2) && + require_zve32f(s) && + require_zve64f(s); } GEN_OPFVF_TRANS(vmfeq_vf, opfvf_cmp_check) @@ -2539,7 +2664,9 @@ static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a) if (require_rvv(s) && require_rvf(s) && vext_check_isa_ill(s) && - require_align(a->rd, s->lmul)) { + require_align(a->rd, s->lmul) && + require_zve32f(s) && + require_zve64f(s)) { gen_set_rm(s, RISCV_FRM_DYN); TCGv_i64 t1; @@ -2620,14 +2747,18 @@ static bool opfv_widen_check(DisasContext *s, arg_rmr *a) static bool opxfv_widen_check(DisasContext *s, arg_rmr *a) { return opfv_widen_check(s, a) && - require_rvf(s); + require_rvf(s) && + require_zve32f(s) && + require_zve64f(s); } static bool opffv_widen_check(DisasContext *s, arg_rmr *a) { return opfv_widen_check(s, a) && require_scale_rvf(s) && - (s->sew != MO_8); + (s->sew != MO_8) && + require_scale_zve32f(s) && + require_scale_zve64f(s); } #define GEN_OPFV_WIDEN_TRANS(NAME, CHECK, HELPER, FRM) \ @@ -2678,7 +2809,9 @@ static bool opfxv_widen_check(DisasContext *s, arg_rmr *a) require_scale_rvf(s) && vext_check_isa_ill(s) && /* OPFV widening instructions ignore vs1 check */ - vext_check_ds(s, a->rd, a->rs2, a->vm); + vext_check_ds(s, a->rd, a->rs2, a->vm) && + require_scale_zve32f(s) && + require_scale_zve64f(s); } #define GEN_OPFXV_WIDEN_TRANS(NAME) \ @@ -2728,14 +2861,18 @@ static bool opfxv_narrow_check(DisasContext *s, arg_rmr *a) { return opfv_narrow_check(s, a) && require_rvf(s) && - (s->sew != MO_64); + (s->sew != MO_64) && + require_zve32f(s) && + require_zve64f(s); } static bool opffv_narrow_check(DisasContext *s, arg_rmr *a) { return opfv_narrow_check(s, a) && require_scale_rvf(s) && - (s->sew != MO_8); + (s->sew != MO_8) && + require_scale_zve32f(s) && + require_scale_zve64f(s); } #define GEN_OPFV_NARROW_TRANS(NAME, CHECK, HELPER, FRM) \ @@ -2784,7 +2921,9 @@ static bool opxfv_narrow_check(DisasContext *s, arg_rmr *a) require_scale_rvf(s) && vext_check_isa_ill(s) && /* OPFV narrowing instructions ignore vs1 check */ - vext_check_sd(s, a->rd, a->rs2, a->vm); + vext_check_sd(s, a->rd, a->rs2, a->vm) && + require_scale_zve32f(s) && + require_scale_zve64f(s); } #define GEN_OPXFV_NARROW_TRANS(NAME, HELPER, FRM) \ @@ -2857,7 +2996,9 @@ GEN_OPIVV_WIDEN_TRANS(vwredsumu_vs, reduction_widen_check) static bool freduction_check(DisasContext *s, arg_rmrr *a) { return reduction_check(s, a) && - require_rvf(s); + require_rvf(s) && + require_zve32f(s) && + require_zve64f(s); } GEN_OPFVV_TRANS(vfredsum_vs, freduction_check) @@ -3265,7 +3406,9 @@ static bool trans_vfmv_f_s(DisasContext *s, arg_vfmv_f_s *a) { if (require_rvv(s) && require_rvf(s) && - vext_check_isa_ill(s)) { + vext_check_isa_ill(s) && + require_zve32f(s) && + require_zve64f(s)) { gen_set_rm(s, RISCV_FRM_DYN); unsigned int ofs = (8 << s->sew); @@ -3291,7 +3434,9 @@ static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a) { if (require_rvv(s) && require_rvf(s) && - vext_check_isa_ill(s)) { + vext_check_isa_ill(s) && + require_zve32f(s) && + require_zve64f(s)) { gen_set_rm(s, RISCV_FRM_DYN); /* The instructions ignore LMUL and vector register group. */ @@ -3342,13 +3487,17 @@ GEN_OPIVI_TRANS(vslidedown_vi, IMM_ZX, vslidedown_vx, slidedown_check) static bool fslideup_check(DisasContext *s, arg_rmrr *a) { return slideup_check(s, a) && - require_rvf(s); + require_rvf(s) && + require_zve32f(s) && + require_zve64f(s); } static bool fslidedown_check(DisasContext *s, arg_rmrr *a) { return slidedown_check(s, a) && - require_rvf(s); + require_rvf(s) && + require_zve32f(s) && + require_zve64f(s); } GEN_OPFVF_TRANS(vfslide1up_vf, fslideup_check) diff --git a/target/riscv/kvm-stub.c b/target/riscv/kvm-stub.c new file mode 100644 index 0000000000..4e8fc31a21 --- /dev/null +++ b/target/riscv/kvm-stub.c @@ -0,0 +1,30 @@ +/* + * QEMU KVM RISC-V specific function stubs + * + * Copyright (c) 2020 Huawei Technologies Co., Ltd + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include "qemu/osdep.h" +#include "cpu.h" +#include "kvm_riscv.h" + +void kvm_riscv_reset_vcpu(RISCVCPU *cpu) +{ + abort(); +} + +void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level) +{ + abort(); +} diff --git a/target/riscv/kvm.c b/target/riscv/kvm.c new file mode 100644 index 0000000000..e6b7cb6d4d --- /dev/null +++ b/target/riscv/kvm.c @@ -0,0 +1,535 @@ +/* + * RISC-V implementation of KVM hooks + * + * Copyright (c) 2020 Huawei Technologies Co., Ltd + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include <sys/ioctl.h> + +#include <linux/kvm.h> + +#include "qemu-common.h" +#include "qemu/timer.h" +#include "qemu/error-report.h" +#include "qemu/main-loop.h" +#include "sysemu/sysemu.h" +#include "sysemu/kvm.h" +#include "sysemu/kvm_int.h" +#include "cpu.h" +#include "trace.h" +#include "hw/pci/pci.h" +#include "exec/memattrs.h" +#include "exec/address-spaces.h" +#include "hw/boards.h" +#include "hw/irq.h" +#include "qemu/log.h" +#include "hw/loader.h" +#include "kvm_riscv.h" +#include "sbi_ecall_interface.h" +#include "chardev/char-fe.h" +#include "migration/migration.h" +#include "sysemu/runstate.h" + +static uint64_t kvm_riscv_reg_id(CPURISCVState *env, uint64_t type, + uint64_t idx) +{ + uint64_t id = KVM_REG_RISCV | type | idx; + + switch (riscv_cpu_mxl(env)) { + case MXL_RV32: + id |= KVM_REG_SIZE_U32; + break; + case MXL_RV64: + id |= KVM_REG_SIZE_U64; + break; + default: + g_assert_not_reached(); + } + return id; +} + +#define RISCV_CORE_REG(env, name) kvm_riscv_reg_id(env, KVM_REG_RISCV_CORE, \ + KVM_REG_RISCV_CORE_REG(name)) + +#define RISCV_CSR_REG(env, name) kvm_riscv_reg_id(env, KVM_REG_RISCV_CSR, \ + KVM_REG_RISCV_CSR_REG(name)) + +#define RISCV_TIMER_REG(env, name) kvm_riscv_reg_id(env, KVM_REG_RISCV_TIMER, \ + KVM_REG_RISCV_TIMER_REG(name)) + +#define RISCV_FP_F_REG(env, idx) kvm_riscv_reg_id(env, KVM_REG_RISCV_FP_F, idx) + +#define RISCV_FP_D_REG(env, idx) kvm_riscv_reg_id(env, KVM_REG_RISCV_FP_D, idx) + +#define KVM_RISCV_GET_CSR(cs, env, csr, reg) \ + do { \ + int ret = kvm_get_one_reg(cs, RISCV_CSR_REG(env, csr), ®); \ + if (ret) { \ + return ret; \ + } \ + } while (0) + +#define KVM_RISCV_SET_CSR(cs, env, csr, reg) \ + do { \ + int ret = kvm_set_one_reg(cs, RISCV_CSR_REG(env, csr), ®); \ + if (ret) { \ + return ret; \ + } \ + } while (0) + +#define KVM_RISCV_GET_TIMER(cs, env, name, reg) \ + do { \ + int ret = kvm_get_one_reg(cs, RISCV_TIMER_REG(env, name), ®); \ + if (ret) { \ + abort(); \ + } \ + } while (0) + +#define KVM_RISCV_SET_TIMER(cs, env, name, reg) \ + do { \ + int ret = kvm_set_one_reg(cs, RISCV_TIMER_REG(env, time), ®); \ + if (ret) { \ + abort(); \ + } \ + } while (0) + +static int kvm_riscv_get_regs_core(CPUState *cs) +{ + int ret = 0; + int i; + target_ulong reg; + CPURISCVState *env = &RISCV_CPU(cs)->env; + + ret = kvm_get_one_reg(cs, RISCV_CORE_REG(env, regs.pc), ®); + if (ret) { + return ret; + } + env->pc = reg; + + for (i = 1; i < 32; i++) { + uint64_t id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CORE, i); + ret = kvm_get_one_reg(cs, id, ®); + if (ret) { + return ret; + } + env->gpr[i] = reg; + } + + return ret; +} + +static int kvm_riscv_put_regs_core(CPUState *cs) +{ + int ret = 0; + int i; + target_ulong reg; + CPURISCVState *env = &RISCV_CPU(cs)->env; + + reg = env->pc; + ret = kvm_set_one_reg(cs, RISCV_CORE_REG(env, regs.pc), ®); + if (ret) { + return ret; + } + + for (i = 1; i < 32; i++) { + uint64_t id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CORE, i); + reg = env->gpr[i]; + ret = kvm_set_one_reg(cs, id, ®); + if (ret) { + return ret; + } + } + + return ret; +} + +static int kvm_riscv_get_regs_csr(CPUState *cs) +{ + int ret = 0; + CPURISCVState *env = &RISCV_CPU(cs)->env; + + KVM_RISCV_GET_CSR(cs, env, sstatus, env->mstatus); + KVM_RISCV_GET_CSR(cs, env, sie, env->mie); + KVM_RISCV_GET_CSR(cs, env, stvec, env->stvec); + KVM_RISCV_GET_CSR(cs, env, sscratch, env->sscratch); + KVM_RISCV_GET_CSR(cs, env, sepc, env->sepc); + KVM_RISCV_GET_CSR(cs, env, scause, env->scause); + KVM_RISCV_GET_CSR(cs, env, stval, env->stval); + KVM_RISCV_GET_CSR(cs, env, sip, env->mip); + KVM_RISCV_GET_CSR(cs, env, satp, env->satp); + return ret; +} + +static int kvm_riscv_put_regs_csr(CPUState *cs) +{ + int ret = 0; + CPURISCVState *env = &RISCV_CPU(cs)->env; + + KVM_RISCV_SET_CSR(cs, env, sstatus, env->mstatus); + KVM_RISCV_SET_CSR(cs, env, sie, env->mie); + KVM_RISCV_SET_CSR(cs, env, stvec, env->stvec); + KVM_RISCV_SET_CSR(cs, env, sscratch, env->sscratch); + KVM_RISCV_SET_CSR(cs, env, sepc, env->sepc); + KVM_RISCV_SET_CSR(cs, env, scause, env->scause); + KVM_RISCV_SET_CSR(cs, env, stval, env->stval); + KVM_RISCV_SET_CSR(cs, env, sip, env->mip); + KVM_RISCV_SET_CSR(cs, env, satp, env->satp); + + return ret; +} + +static int kvm_riscv_get_regs_fp(CPUState *cs) +{ + int ret = 0; + int i; + CPURISCVState *env = &RISCV_CPU(cs)->env; + + if (riscv_has_ext(env, RVD)) { + uint64_t reg; + for (i = 0; i < 32; i++) { + ret = kvm_get_one_reg(cs, RISCV_FP_D_REG(env, i), ®); + if (ret) { + return ret; + } + env->fpr[i] = reg; + } + return ret; + } + + if (riscv_has_ext(env, RVF)) { + uint32_t reg; + for (i = 0; i < 32; i++) { + ret = kvm_get_one_reg(cs, RISCV_FP_F_REG(env, i), ®); + if (ret) { + return ret; + } + env->fpr[i] = reg; + } + return ret; + } + + return ret; +} + +static int kvm_riscv_put_regs_fp(CPUState *cs) +{ + int ret = 0; + int i; + CPURISCVState *env = &RISCV_CPU(cs)->env; + + if (riscv_has_ext(env, RVD)) { + uint64_t reg; + for (i = 0; i < 32; i++) { + reg = env->fpr[i]; + ret = kvm_set_one_reg(cs, RISCV_FP_D_REG(env, i), ®); + if (ret) { + return ret; + } + } + return ret; + } + + if (riscv_has_ext(env, RVF)) { + uint32_t reg; + for (i = 0; i < 32; i++) { + reg = env->fpr[i]; + ret = kvm_set_one_reg(cs, RISCV_FP_F_REG(env, i), ®); + if (ret) { + return ret; + } + } + return ret; + } + + return ret; +} + +static void kvm_riscv_get_regs_timer(CPUState *cs) +{ + CPURISCVState *env = &RISCV_CPU(cs)->env; + + if (env->kvm_timer_dirty) { + return; + } + + KVM_RISCV_GET_TIMER(cs, env, time, env->kvm_timer_time); + KVM_RISCV_GET_TIMER(cs, env, compare, env->kvm_timer_compare); + KVM_RISCV_GET_TIMER(cs, env, state, env->kvm_timer_state); + KVM_RISCV_GET_TIMER(cs, env, frequency, env->kvm_timer_frequency); + + env->kvm_timer_dirty = true; +} + +static void kvm_riscv_put_regs_timer(CPUState *cs) +{ + uint64_t reg; + CPURISCVState *env = &RISCV_CPU(cs)->env; + + if (!env->kvm_timer_dirty) { + return; + } + + KVM_RISCV_SET_TIMER(cs, env, time, env->kvm_timer_time); + KVM_RISCV_SET_TIMER(cs, env, compare, env->kvm_timer_compare); + + /* + * To set register of RISCV_TIMER_REG(state) will occur a error from KVM + * on env->kvm_timer_state == 0, It's better to adapt in KVM, but it + * doesn't matter that adaping in QEMU now. + * TODO If KVM changes, adapt here. + */ + if (env->kvm_timer_state) { + KVM_RISCV_SET_TIMER(cs, env, state, env->kvm_timer_state); + } + + /* + * For now, migration will not work between Hosts with different timer + * frequency. Therefore, we should check whether they are the same here + * during the migration. + */ + if (migration_is_running(migrate_get_current()->state)) { + KVM_RISCV_GET_TIMER(cs, env, frequency, reg); + if (reg != env->kvm_timer_frequency) { + error_report("Dst Hosts timer frequency != Src Hosts"); + } + } + + env->kvm_timer_dirty = false; +} + +const KVMCapabilityInfo kvm_arch_required_capabilities[] = { + KVM_CAP_LAST_INFO +}; + +int kvm_arch_get_registers(CPUState *cs) +{ + int ret = 0; + + ret = kvm_riscv_get_regs_core(cs); + if (ret) { + return ret; + } + + ret = kvm_riscv_get_regs_csr(cs); + if (ret) { + return ret; + } + + ret = kvm_riscv_get_regs_fp(cs); + if (ret) { + return ret; + } + + return ret; +} + +int kvm_arch_put_registers(CPUState *cs, int level) +{ + int ret = 0; + + ret = kvm_riscv_put_regs_core(cs); + if (ret) { + return ret; + } + + ret = kvm_riscv_put_regs_csr(cs); + if (ret) { + return ret; + } + + ret = kvm_riscv_put_regs_fp(cs); + if (ret) { + return ret; + } + + return ret; +} + +int kvm_arch_release_virq_post(int virq) +{ + return 0; +} + +int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route, + uint64_t address, uint32_t data, PCIDevice *dev) +{ + return 0; +} + +int kvm_arch_destroy_vcpu(CPUState *cs) +{ + return 0; +} + +unsigned long kvm_arch_vcpu_id(CPUState *cpu) +{ + return cpu->cpu_index; +} + +static void kvm_riscv_vm_state_change(void *opaque, bool running, + RunState state) +{ + CPUState *cs = opaque; + + if (running) { + kvm_riscv_put_regs_timer(cs); + } else { + kvm_riscv_get_regs_timer(cs); + } +} + +void kvm_arch_init_irq_routing(KVMState *s) +{ +} + +int kvm_arch_init_vcpu(CPUState *cs) +{ + int ret = 0; + target_ulong isa; + RISCVCPU *cpu = RISCV_CPU(cs); + CPURISCVState *env = &cpu->env; + uint64_t id; + + qemu_add_vm_change_state_handler(kvm_riscv_vm_state_change, cs); + + id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG, + KVM_REG_RISCV_CONFIG_REG(isa)); + ret = kvm_get_one_reg(cs, id, &isa); + if (ret) { + return ret; + } + env->misa_ext = isa; + + return ret; +} + +int kvm_arch_msi_data_to_gsi(uint32_t data) +{ + abort(); +} + +int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route, + int vector, PCIDevice *dev) +{ + return 0; +} + +int kvm_arch_init(MachineState *ms, KVMState *s) +{ + return 0; +} + +int kvm_arch_irqchip_create(KVMState *s) +{ + return 0; +} + +int kvm_arch_process_async_events(CPUState *cs) +{ + return 0; +} + +void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) +{ +} + +MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run) +{ + return MEMTXATTRS_UNSPECIFIED; +} + +bool kvm_arch_stop_on_emulation_error(CPUState *cs) +{ + return true; +} + +static int kvm_riscv_handle_sbi(CPUState *cs, struct kvm_run *run) +{ + int ret = 0; + unsigned char ch; + switch (run->riscv_sbi.extension_id) { + case SBI_EXT_0_1_CONSOLE_PUTCHAR: + ch = run->riscv_sbi.args[0]; + qemu_chr_fe_write(serial_hd(0)->be, &ch, sizeof(ch)); + break; + case SBI_EXT_0_1_CONSOLE_GETCHAR: + ret = qemu_chr_fe_read_all(serial_hd(0)->be, &ch, sizeof(ch)); + if (ret == sizeof(ch)) { + run->riscv_sbi.args[0] = ch; + } else { + run->riscv_sbi.args[0] = -1; + } + break; + default: + qemu_log_mask(LOG_UNIMP, + "%s: un-handled SBI EXIT, specific reasons is %lu\n", + __func__, run->riscv_sbi.extension_id); + ret = -1; + break; + } + return ret; +} + +int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) +{ + int ret = 0; + switch (run->exit_reason) { + case KVM_EXIT_RISCV_SBI: + ret = kvm_riscv_handle_sbi(cs, run); + break; + default: + qemu_log_mask(LOG_UNIMP, "%s: un-handled exit reason %d\n", + __func__, run->exit_reason); + ret = -1; + break; + } + return ret; +} + +void kvm_riscv_reset_vcpu(RISCVCPU *cpu) +{ + CPURISCVState *env = &cpu->env; + + if (!kvm_enabled()) { + return; + } + env->pc = cpu->env.kernel_addr; + env->gpr[10] = kvm_arch_vcpu_id(CPU(cpu)); /* a0 */ + env->gpr[11] = cpu->env.fdt_addr; /* a1 */ + env->satp = 0; +} + +void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level) +{ + int ret; + unsigned virq = level ? KVM_INTERRUPT_SET : KVM_INTERRUPT_UNSET; + + if (irq != IRQ_S_EXT) { + perror("kvm riscv set irq != IRQ_S_EXT\n"); + abort(); + } + + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_INTERRUPT, &virq); + if (ret < 0) { + perror("Set irq failed"); + abort(); + } +} + +bool kvm_arch_cpu_check_are_resettable(void) +{ + return true; +} diff --git a/target/riscv/kvm_riscv.h b/target/riscv/kvm_riscv.h new file mode 100644 index 0000000000..ed281bdce0 --- /dev/null +++ b/target/riscv/kvm_riscv.h @@ -0,0 +1,25 @@ +/* + * QEMU KVM support -- RISC-V specific functions. + * + * Copyright (c) 2020 Huawei Technologies Co., Ltd + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef QEMU_KVM_RISCV_H +#define QEMU_KVM_RISCV_H + +void kvm_riscv_reset_vcpu(RISCVCPU *cpu); +void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level); + +#endif diff --git a/target/riscv/machine.c b/target/riscv/machine.c index 13b9ab375b..740e11fcff 100644 --- a/target/riscv/machine.c +++ b/target/riscv/machine.c @@ -124,8 +124,8 @@ static bool vector_needed(void *opaque) static const VMStateDescription vmstate_vector = { .name = "cpu/vector", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .needed = vector_needed, .fields = (VMStateField[]) { VMSTATE_UINT64_ARRAY(env.vreg, RISCVCPU, 32 * RV_VLEN_MAX / 64), @@ -134,6 +134,7 @@ static const VMStateDescription vmstate_vector = { VMSTATE_UINTTL(env.vl, RISCVCPU), VMSTATE_UINTTL(env.vstart, RISCVCPU), VMSTATE_UINTTL(env.vtype, RISCVCPU), + VMSTATE_BOOL(env.vill, RISCVCPU), VMSTATE_END_OF_LIST() } }; @@ -185,10 +186,50 @@ static const VMStateDescription vmstate_rv128 = { } }; +static bool kvmtimer_needed(void *opaque) +{ + return kvm_enabled(); +} + +static int cpu_post_load(void *opaque, int version_id) +{ + RISCVCPU *cpu = opaque; + CPURISCVState *env = &cpu->env; + + env->kvm_timer_dirty = true; + return 0; +} + +static const VMStateDescription vmstate_kvmtimer = { + .name = "cpu/kvmtimer", + .version_id = 1, + .minimum_version_id = 1, + .needed = kvmtimer_needed, + .post_load = cpu_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT64(env.kvm_timer_time, RISCVCPU), + VMSTATE_UINT64(env.kvm_timer_compare, RISCVCPU), + VMSTATE_UINT64(env.kvm_timer_state, RISCVCPU), + + VMSTATE_END_OF_LIST() + } +}; + +static int riscv_cpu_post_load(void *opaque, int version_id) +{ + RISCVCPU *cpu = opaque; + CPURISCVState *env = &cpu->env; + + env->xl = cpu_recompute_xl(env); + riscv_cpu_update_mask(env); + return 0; +} + const VMStateDescription vmstate_riscv_cpu = { .name = "cpu", .version_id = 3, .minimum_version_id = 3, + .post_load = riscv_cpu_post_load, .fields = (VMStateField[]) { VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32), VMSTATE_UINT64_ARRAY(env.fpr, RISCVCPU, 32), @@ -240,6 +281,7 @@ const VMStateDescription vmstate_riscv_cpu = { &vmstate_vector, &vmstate_pointermasking, &vmstate_rv128, + &vmstate_kvmtimer, NULL } }; diff --git a/target/riscv/meson.build b/target/riscv/meson.build index a32158da93..a3997ed580 100644 --- a/target/riscv/meson.build +++ b/target/riscv/meson.build @@ -20,6 +20,7 @@ riscv_ss.add(files( 'translate.c', 'm128_helper.c' )) +riscv_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c'), if_false: files('kvm-stub.c')) riscv_softmmu_ss = ss.source_set() riscv_softmmu_ss.add(files( diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index 6f040f2fb9..1a75ba11e6 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -50,7 +50,8 @@ target_ulong helper_csrr(CPURISCVState *env, int csr) void helper_csrw(CPURISCVState *env, int csr, target_ulong src) { - RISCVException ret = riscv_csrrw(env, csr, NULL, src, -1); + target_ulong mask = env->xl == MXL_RV32 ? UINT32_MAX : (target_ulong)-1; + RISCVException ret = riscv_csrrw(env, csr, NULL, src, mask); if (ret != RISCV_EXCP_NONE) { riscv_raise_exception(env, ret, GETPC()); @@ -115,7 +116,7 @@ target_ulong helper_csrrw_i128(CPURISCVState *env, int csr, #ifndef CONFIG_USER_ONLY -target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb) +target_ulong helper_sret(CPURISCVState *env) { uint64_t mstatus; target_ulong prev_priv, prev_virt; @@ -176,7 +177,7 @@ target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb) return retpc; } -target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb) +target_ulong helper_mret(CPURISCVState *env) { if (!(env->priv >= PRV_M)) { riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c index 54abf42583..81b61bb65c 100644 --- a/target/riscv/pmp.c +++ b/target/riscv/pmp.c @@ -463,16 +463,11 @@ void pmpcfg_csr_write(CPURISCVState *env, uint32_t reg_index, { int i; uint8_t cfg_val; + int pmpcfg_nums = 2 << riscv_cpu_mxl(env); trace_pmpcfg_csr_write(env->mhartid, reg_index, val); - if ((reg_index & 1) && (sizeof(target_ulong) == 8)) { - qemu_log_mask(LOG_GUEST_ERROR, - "ignoring pmpcfg write - incorrect address\n"); - return; - } - - for (i = 0; i < sizeof(target_ulong); i++) { + for (i = 0; i < pmpcfg_nums; i++) { cfg_val = (val >> 8 * i) & 0xff; pmp_write_cfg(env, (reg_index * 4) + i, cfg_val); } @@ -490,8 +485,9 @@ target_ulong pmpcfg_csr_read(CPURISCVState *env, uint32_t reg_index) int i; target_ulong cfg_val = 0; target_ulong val = 0; + int pmpcfg_nums = 2 << riscv_cpu_mxl(env); - for (i = 0; i < sizeof(target_ulong); i++) { + for (i = 0; i < pmpcfg_nums; i++) { val = pmp_read_cfg(env, (reg_index * 4) + i); cfg_val |= (val << (i * 8)); } diff --git a/target/riscv/sbi_ecall_interface.h b/target/riscv/sbi_ecall_interface.h new file mode 100644 index 0000000000..fb1a3fa8f2 --- /dev/null +++ b/target/riscv/sbi_ecall_interface.h @@ -0,0 +1,72 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2019 Western Digital Corporation or its affiliates. + * + * Authors: + * Anup Patel <anup.patel@wdc.com> + */ + +#ifndef __SBI_ECALL_INTERFACE_H__ +#define __SBI_ECALL_INTERFACE_H__ + +/* clang-format off */ + +/* SBI Extension IDs */ +#define SBI_EXT_0_1_SET_TIMER 0x0 +#define SBI_EXT_0_1_CONSOLE_PUTCHAR 0x1 +#define SBI_EXT_0_1_CONSOLE_GETCHAR 0x2 +#define SBI_EXT_0_1_CLEAR_IPI 0x3 +#define SBI_EXT_0_1_SEND_IPI 0x4 +#define SBI_EXT_0_1_REMOTE_FENCE_I 0x5 +#define SBI_EXT_0_1_REMOTE_SFENCE_VMA 0x6 +#define SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID 0x7 +#define SBI_EXT_0_1_SHUTDOWN 0x8 +#define SBI_EXT_BASE 0x10 +#define SBI_EXT_TIME 0x54494D45 +#define SBI_EXT_IPI 0x735049 +#define SBI_EXT_RFENCE 0x52464E43 +#define SBI_EXT_HSM 0x48534D + +/* SBI function IDs for BASE extension*/ +#define SBI_EXT_BASE_GET_SPEC_VERSION 0x0 +#define SBI_EXT_BASE_GET_IMP_ID 0x1 +#define SBI_EXT_BASE_GET_IMP_VERSION 0x2 +#define SBI_EXT_BASE_PROBE_EXT 0x3 +#define SBI_EXT_BASE_GET_MVENDORID 0x4 +#define SBI_EXT_BASE_GET_MARCHID 0x5 +#define SBI_EXT_BASE_GET_MIMPID 0x6 + +/* SBI function IDs for TIME extension*/ +#define SBI_EXT_TIME_SET_TIMER 0x0 + +/* SBI function IDs for IPI extension*/ +#define SBI_EXT_IPI_SEND_IPI 0x0 + +/* SBI function IDs for RFENCE extension*/ +#define SBI_EXT_RFENCE_REMOTE_FENCE_I 0x0 +#define SBI_EXT_RFENCE_REMOTE_SFENCE_VMA 0x1 +#define SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID 0x2 +#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA 0x3 +#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID 0x4 +#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA 0x5 +#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID 0x6 + +/* SBI function IDs for HSM extension */ +#define SBI_EXT_HSM_HART_START 0x0 +#define SBI_EXT_HSM_HART_STOP 0x1 +#define SBI_EXT_HSM_HART_GET_STATUS 0x2 + +#define SBI_HSM_HART_STATUS_STARTED 0x0 +#define SBI_HSM_HART_STATUS_STOPPED 0x1 +#define SBI_HSM_HART_STATUS_START_PENDING 0x2 +#define SBI_HSM_HART_STATUS_STOP_PENDING 0x3 + +#define SBI_SPEC_VERSION_MAJOR_OFFSET 24 +#define SBI_SPEC_VERSION_MAJOR_MASK 0x7f +#define SBI_SPEC_VERSION_MINOR_MASK 0xffffff +#define SBI_EXT_VENDOR_START 0x09000000 +#define SBI_EXT_VENDOR_END 0x09FFFFFF +/* clang-format on */ + +#endif diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 615048ec87..f0bbe80875 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -38,8 +38,8 @@ static TCGv_i64 cpu_fpr[32]; /* assume F and D extensions */ static TCGv load_res; static TCGv load_val; /* globals for PM CSRs */ -static TCGv pm_mask[4]; -static TCGv pm_base[4]; +static TCGv pm_mask; +static TCGv pm_base; #include "exec/gen-icount.h" @@ -79,6 +79,8 @@ typedef struct DisasContext { bool ext_ifencei; bool ext_zfh; bool ext_zfhmin; + bool ext_zve32f; + bool ext_zve64f; bool hlsx; /* vector extension */ bool vill; @@ -106,9 +108,8 @@ typedef struct DisasContext { /* Space for 3 operands plus 1 extra for address computation. */ TCGv temp[4]; /* PointerMasking extension */ - bool pm_enabled; - TCGv pm_mask; - TCGv pm_base; + bool pm_mask_enabled; + bool pm_base_enabled; } DisasContext; static inline bool has_ext(DisasContext *ctx, uint32_t ext) @@ -191,16 +192,33 @@ static void gen_check_nanbox_s(TCGv_i64 out, TCGv_i64 in) tcg_gen_movcond_i64(TCG_COND_GEU, out, in, t_max, in, t_nan); } +static void gen_set_pc_imm(DisasContext *ctx, target_ulong dest) +{ + if (get_xl(ctx) == MXL_RV32) { + dest = (int32_t)dest; + } + tcg_gen_movi_tl(cpu_pc, dest); +} + +static void gen_set_pc(DisasContext *ctx, TCGv dest) +{ + if (get_xl(ctx) == MXL_RV32) { + tcg_gen_ext32s_tl(cpu_pc, dest); + } else { + tcg_gen_mov_tl(cpu_pc, dest); + } +} + static void generate_exception(DisasContext *ctx, int excp) { - tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); + gen_set_pc_imm(ctx, ctx->base.pc_next); gen_helper_raise_exception(cpu_env, tcg_constant_i32(excp)); ctx->base.is_jmp = DISAS_NORETURN; } static void generate_exception_mtval(DisasContext *ctx, int excp) { - tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); + gen_set_pc_imm(ctx, ctx->base.pc_next); tcg_gen_st_tl(cpu_pc, cpu_env, offsetof(CPURISCVState, badaddr)); gen_helper_raise_exception(cpu_env, tcg_constant_i32(excp)); ctx->base.is_jmp = DISAS_NORETURN; @@ -223,10 +241,10 @@ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) { if (translator_use_goto_tb(&ctx->base, dest)) { tcg_gen_goto_tb(n); - tcg_gen_movi_tl(cpu_pc, dest); + gen_set_pc_imm(ctx, dest); tcg_gen_exit_tb(ctx->base.tb, n); } else { - tcg_gen_movi_tl(cpu_pc, dest); + gen_set_pc_imm(ctx, dest); tcg_gen_lookup_and_goto_ptr(); } } @@ -367,29 +385,28 @@ static void gen_jal(DisasContext *ctx, int rd, target_ulong imm) return; } } - if (rd != 0) { - tcg_gen_movi_tl(cpu_gpr[rd], ctx->pc_succ_insn); - } + gen_set_gpri(ctx, rd, ctx->pc_succ_insn); gen_goto_tb(ctx, 0, ctx->base.pc_next + imm); /* must use this for safety */ ctx->base.is_jmp = DISAS_NORETURN; } -/* - * Generates address adjustment for PointerMasking - */ -static TCGv gen_pm_adjust_address(DisasContext *s, TCGv src) +/* Compute a canonical address from a register plus offset. */ +static TCGv get_address(DisasContext *ctx, int rs1, int imm) { - TCGv temp; - if (!s->pm_enabled) { - /* Load unmodified address */ - return src; - } else { - temp = temp_new(s); - tcg_gen_andc_tl(temp, src, s->pm_mask); - tcg_gen_or_tl(temp, temp, s->pm_base); - return temp; + TCGv addr = temp_new(ctx); + TCGv src1 = get_gpr(ctx, rs1, EXT_NONE); + + tcg_gen_addi_tl(addr, src1, imm); + if (ctx->pm_mask_enabled) { + tcg_gen_and_tl(addr, addr, pm_mask); + } else if (get_xl(ctx) == MXL_RV32) { + tcg_gen_ext32u_tl(addr, addr); } + if (ctx->pm_base_enabled) { + tcg_gen_or_tl(addr, addr, pm_base); + } + return addr; } #ifndef CONFIG_USER_ONLY @@ -894,6 +911,8 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->ext_ifencei = cpu->cfg.ext_ifencei; ctx->ext_zfh = cpu->cfg.ext_zfh; ctx->ext_zfhmin = cpu->cfg.ext_zfhmin; + ctx->ext_zve32f = cpu->cfg.ext_zve32f; + ctx->ext_zve64f = cpu->cfg.ext_zve64f; ctx->vlen = cpu->cfg.vlen; ctx->elen = cpu->cfg.elen; ctx->mstatus_hs_fs = FIELD_EX32(tb_flags, TB_FLAGS, MSTATUS_HS_FS); @@ -909,11 +928,8 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->cs = cs; ctx->ntemp = 0; memset(ctx->temp, 0, sizeof(ctx->temp)); - ctx->pm_enabled = FIELD_EX32(tb_flags, TB_FLAGS, PM_ENABLED); - int priv = tb_flags & TB_FLAGS_PRIV_MMU_MASK; - ctx->pm_mask = pm_mask[priv]; - ctx->pm_base = pm_base[priv]; - + ctx->pm_mask_enabled = FIELD_EX32(tb_flags, TB_FLAGS, PM_MASK_ENABLED); + ctx->pm_base_enabled = FIELD_EX32(tb_flags, TB_FLAGS, PM_BASE_ENABLED); ctx->zero = tcg_constant_tl(0); } @@ -1031,19 +1047,9 @@ void riscv_translate_init(void) "load_res"); load_val = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, load_val), "load_val"); -#ifndef CONFIG_USER_ONLY /* Assign PM CSRs to tcg globals */ - pm_mask[PRV_U] = - tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, upmmask), "upmmask"); - pm_base[PRV_U] = - tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, upmbase), "upmbase"); - pm_mask[PRV_S] = - tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, spmmask), "spmmask"); - pm_base[PRV_S] = - tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, spmbase), "spmbase"); - pm_mask[PRV_M] = - tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, mpmmask), "mpmmask"); - pm_base[PRV_M] = - tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, mpmbase), "mpmbase"); -#endif + pm_mask = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, cur_pmmask), + "pmmask"); + pm_base = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, cur_pmbase), + "pmbase"); } diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index ad505ec9b2..020d2e841f 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -36,8 +36,11 @@ target_ulong HELPER(vsetvl)(CPURISCVState *env, target_ulong s1, uint64_t lmul = FIELD_EX64(s2, VTYPE, VLMUL); uint16_t sew = 8 << FIELD_EX64(s2, VTYPE, VSEW); uint8_t ediv = FIELD_EX64(s2, VTYPE, VEDIV); - bool vill = FIELD_EX64(s2, VTYPE, VILL); - target_ulong reserved = FIELD_EX64(s2, VTYPE, RESERVED); + int xlen = riscv_cpu_xlen(env); + bool vill = (s2 >> (xlen - 1)) & 0x1; + target_ulong reserved = s2 & + MAKE_64BIT_MASK(R_VTYPE_RESERVED_SHIFT, + xlen - 1 - R_VTYPE_RESERVED_SHIFT); if (lmul & 4) { /* Fractional LMUL. */ @@ -52,7 +55,8 @@ target_ulong HELPER(vsetvl)(CPURISCVState *env, target_ulong s1, || (ediv != 0) || (reserved != 0)) { /* only set vill bit. */ - env->vtype = FIELD_DP64(0, VTYPE, VILL, 1); + env->vill = 1; + env->vtype = 0; env->vl = 0; env->vstart = 0; return 0; @@ -135,6 +139,11 @@ static inline uint32_t vext_max_elems(uint32_t desc, uint32_t esz) return scale < 0 ? vlenb >> -scale : vlenb << scale; } +static inline target_ulong adjust_addr(CPURISCVState *env, target_ulong addr) +{ + return (addr & env->cur_pmmask) | env->cur_pmbase; +} + /* * This function checks watchpoint before real load operation. * @@ -152,12 +161,12 @@ static void probe_pages(CPURISCVState *env, target_ulong addr, target_ulong pagelen = -(addr | TARGET_PAGE_MASK); target_ulong curlen = MIN(pagelen, len); - probe_access(env, addr, curlen, access_type, + probe_access(env, adjust_addr(env, addr), curlen, access_type, cpu_mmu_index(env, false), ra); if (len > curlen) { addr += curlen; curlen = len - curlen; - probe_access(env, addr, curlen, access_type, + probe_access(env, adjust_addr(env, addr), curlen, access_type, cpu_mmu_index(env, false), ra); } } @@ -235,7 +244,7 @@ vext_ldst_stride(void *vd, void *v0, target_ulong base, k = 0; while (k < nf) { target_ulong addr = base + stride * i + (k << esz); - ldst_elem(env, addr, i + k * max_elems, vd, ra); + ldst_elem(env, adjust_addr(env, addr), i + k * max_elems, vd, ra); k++; } } @@ -291,7 +300,7 @@ vext_ldst_us(void *vd, target_ulong base, CPURISCVState *env, uint32_t desc, k = 0; while (k < nf) { target_ulong addr = base + ((i * nf + k) << esz); - ldst_elem(env, addr, i + k * max_elems, vd, ra); + ldst_elem(env, adjust_addr(env, addr), i + k * max_elems, vd, ra); k++; } } @@ -405,7 +414,7 @@ vext_ldst_index(void *vd, void *v0, target_ulong base, k = 0; while (k < nf) { abi_ptr addr = get_index_addr(base, i, vs2) + (k << esz); - ldst_elem(env, addr, i + k * max_elems, vd, ra); + ldst_elem(env, adjust_addr(env, addr), i + k * max_elems, vd, ra); k++; } } @@ -484,7 +493,7 @@ vext_ldff(void *vd, void *v0, target_ulong base, if (!vm && !vext_elem_mask(v0, i)) { continue; } - addr = base + i * (nf << esz); + addr = adjust_addr(env, base + i * (nf << esz)); if (i == 0) { probe_pages(env, addr, nf << esz, ra, MMU_DATA_LOAD); } else { @@ -496,12 +505,12 @@ vext_ldff(void *vd, void *v0, target_ulong base, cpu_mmu_index(env, false)); if (host) { #ifdef CONFIG_USER_ONLY - if (page_check_range(addr, nf << esz, PAGE_READ) < 0) { + if (page_check_range(addr, offset, PAGE_READ) < 0) { vl = i; goto ProbeSuccess; } #else - probe_pages(env, addr, nf << esz, ra, MMU_DATA_LOAD); + probe_pages(env, addr, offset, ra, MMU_DATA_LOAD); #endif } else { vl = i; @@ -511,7 +520,7 @@ vext_ldff(void *vd, void *v0, target_ulong base, break; } remain -= offset; - addr += offset; + addr = adjust_addr(env, addr + offset); } } } @@ -527,7 +536,7 @@ ProbeSuccess: } while (k < nf) { target_ulong addr = base + ((i * nf + k) << esz); - ldst_elem(env, addr, i + k * max_elems, vd, ra); + ldst_elem(env, adjust_addr(env, addr), i + k * max_elems, vd, ra); k++; } } @@ -581,7 +590,7 @@ vext_ldst_whole(void *vd, target_ulong base, CPURISCVState *env, uint32_t desc, /* load/store rest of elements of current segment pointed by vstart */ for (pos = off; pos < max_elems; pos++, env->vstart++) { target_ulong addr = base + ((pos + k * max_elems) << esz); - ldst_elem(env, addr, pos + k * max_elems, vd, ra); + ldst_elem(env, adjust_addr(env, addr), pos + k * max_elems, vd, ra); } k++; } @@ -590,7 +599,7 @@ vext_ldst_whole(void *vd, target_ulong base, CPURISCVState *env, uint32_t desc, for (; k < nf; k++) { for (i = 0; i < max_elems; i++, env->vstart++) { target_ulong addr = base + ((i + k * max_elems) << esz); - ldst_elem(env, addr, i + k * max_elems, vd, ra); + ldst_elem(env, adjust_addr(env, addr), i + k * max_elems, vd, ra); } } diff --git a/target/s390x/cpu-dump.c b/target/s390x/cpu-dump.c index 0f5c062994..ffa9e94d84 100644 --- a/target/s390x/cpu-dump.c +++ b/target/s390x/cpu-dump.c @@ -121,8 +121,7 @@ const char *cc_name(enum cc_op cc_op) [CC_OP_NZ_F64] = "CC_OP_NZ_F64", [CC_OP_NZ_F128] = "CC_OP_NZ_F128", [CC_OP_ICM] = "CC_OP_ICM", - [CC_OP_SLA_32] = "CC_OP_SLA_32", - [CC_OP_SLA_64] = "CC_OP_SLA_64", + [CC_OP_SLA] = "CC_OP_SLA", [CC_OP_FLOGR] = "CC_OP_FLOGR", [CC_OP_LCBB] = "CC_OP_LCBB", [CC_OP_VC] = "CC_OP_VC", diff --git a/target/s390x/s390x-internal.h b/target/s390x/s390x-internal.h index 1a178aed41..6fc8cad2d5 100644 --- a/target/s390x/s390x-internal.h +++ b/target/s390x/s390x-internal.h @@ -193,8 +193,7 @@ enum cc_op { CC_OP_NZ_F128, /* FP dst != 0 (128bit) */ CC_OP_ICM, /* insert characters under mask */ - CC_OP_SLA_32, /* Calculate shift left signed (32bit) */ - CC_OP_SLA_64, /* Calculate shift left signed (64bit) */ + CC_OP_SLA, /* Calculate shift left signed */ CC_OP_FLOGR, /* find leftmost one */ CC_OP_LCBB, /* load count to block boundary */ CC_OP_VC, /* vector compare result */ diff --git a/target/s390x/sigp.c b/target/s390x/sigp.c index 51c727834c..9dd977349a 100644 --- a/target/s390x/sigp.c +++ b/target/s390x/sigp.c @@ -139,7 +139,7 @@ static void sigp_stop_and_store_status(CPUState *cs, run_on_cpu_data arg) case S390_CPU_STATE_OPERATING: cpu->env.sigp_order = SIGP_STOP_STORE_STATUS; cpu_inject_stop(cpu); - /* store will be performed in do_stop_interrup() */ + /* store will be performed in do_stop_interrupt() */ break; case S390_CPU_STATE_STOPPED: /* already stopped, just store the status */ @@ -479,13 +479,17 @@ void do_stop_interrupt(CPUS390XState *env) { S390CPU *cpu = env_archcpu(env); - if (s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu) == 0) { - qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); - } + /* + * Complete the STOP operation before exposing the CPU as + * STOPPED to the system. + */ if (cpu->env.sigp_order == SIGP_STOP_STORE_STATUS) { s390_store_status(cpu, S390_STORE_STATUS_DEF_ADDR, true); } env->sigp_order = 0; + if (s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu) == 0) { + qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); + } env->pending_int &= ~INTERRUPT_STOP; } diff --git a/target/s390x/tcg/cc_helper.c b/target/s390x/tcg/cc_helper.c index c2c96c3a3c..8d04097f78 100644 --- a/target/s390x/tcg/cc_helper.c +++ b/target/s390x/tcg/cc_helper.c @@ -268,36 +268,9 @@ static uint32_t cc_calc_icm(uint64_t mask, uint64_t val) } } -static uint32_t cc_calc_sla_32(uint32_t src, int shift) +static uint32_t cc_calc_sla(uint64_t src, int shift) { - uint32_t mask = ((1U << shift) - 1U) << (32 - shift); - uint32_t sign = 1U << 31; - uint32_t match; - int32_t r; - - /* Check if the sign bit stays the same. */ - if (src & sign) { - match = mask; - } else { - match = 0; - } - if ((src & mask) != match) { - /* Overflow. */ - return 3; - } - - r = ((src << shift) & ~sign) | (src & sign); - if (r == 0) { - return 0; - } else if (r < 0) { - return 1; - } - return 2; -} - -static uint32_t cc_calc_sla_64(uint64_t src, int shift) -{ - uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift); + uint64_t mask = -1ULL << (63 - shift); uint64_t sign = 1ULL << 63; uint64_t match; int64_t r; @@ -459,11 +432,8 @@ static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, case CC_OP_ICM: r = cc_calc_icm(src, dst); break; - case CC_OP_SLA_32: - r = cc_calc_sla_32(src, dst); - break; - case CC_OP_SLA_64: - r = cc_calc_sla_64(src, dst); + case CC_OP_SLA: + r = cc_calc_sla(src, dst); break; case CC_OP_FLOGR: r = cc_calc_flogr(dst); diff --git a/target/s390x/tcg/insn-data.def b/target/s390x/tcg/insn-data.def index f0af458aee..1c3e115712 100644 --- a/target/s390x/tcg/insn-data.def +++ b/target/s390x/tcg/insn-data.def @@ -747,8 +747,8 @@ C(0xb9e1, POPCNT, RRE, PC, 0, r2_o, r1, 0, popcnt, nz64) /* ROTATE LEFT SINGLE LOGICAL */ - C(0xeb1d, RLL, RSY_a, Z, r3_o, sh32, new, r1_32, rll32, 0) - C(0xeb1c, RLLG, RSY_a, Z, r3_o, sh64, r1, 0, rll64, 0) + C(0xeb1d, RLL, RSY_a, Z, r3_o, sh, new, r1_32, rll32, 0) + C(0xeb1c, RLLG, RSY_a, Z, r3_o, sh, r1, 0, rll64, 0) /* ROTATE THEN INSERT SELECTED BITS */ C(0xec55, RISBG, RIE_f, GIE, 0, r2, r1, 0, risbg, s64) @@ -784,29 +784,29 @@ C(0x0400, SPM, RR_a, Z, r1, 0, 0, 0, spm, 0) /* SHIFT LEFT SINGLE */ - D(0x8b00, SLA, RS_a, Z, r1, sh32, new, r1_32, sla, 0, 31) - D(0xebdd, SLAK, RSY_a, DO, r3, sh32, new, r1_32, sla, 0, 31) - D(0xeb0b, SLAG, RSY_a, Z, r3, sh64, r1, 0, sla, 0, 63) + D(0x8b00, SLA, RS_a, Z, r1, sh, new, r1_32, sla, 0, 31) + D(0xebdd, SLAK, RSY_a, DO, r3, sh, new, r1_32, sla, 0, 31) + D(0xeb0b, SLAG, RSY_a, Z, r3, sh, r1, 0, sla, 0, 63) /* SHIFT LEFT SINGLE LOGICAL */ - C(0x8900, SLL, RS_a, Z, r1_o, sh32, new, r1_32, sll, 0) - C(0xebdf, SLLK, RSY_a, DO, r3_o, sh32, new, r1_32, sll, 0) - C(0xeb0d, SLLG, RSY_a, Z, r3_o, sh64, r1, 0, sll, 0) + C(0x8900, SLL, RS_a, Z, r1_o, sh, new, r1_32, sll, 0) + C(0xebdf, SLLK, RSY_a, DO, r3_o, sh, new, r1_32, sll, 0) + C(0xeb0d, SLLG, RSY_a, Z, r3_o, sh, r1, 0, sll, 0) /* SHIFT RIGHT SINGLE */ - C(0x8a00, SRA, RS_a, Z, r1_32s, sh32, new, r1_32, sra, s32) - C(0xebdc, SRAK, RSY_a, DO, r3_32s, sh32, new, r1_32, sra, s32) - C(0xeb0a, SRAG, RSY_a, Z, r3_o, sh64, r1, 0, sra, s64) + C(0x8a00, SRA, RS_a, Z, r1_32s, sh, new, r1_32, sra, s32) + C(0xebdc, SRAK, RSY_a, DO, r3_32s, sh, new, r1_32, sra, s32) + C(0xeb0a, SRAG, RSY_a, Z, r3_o, sh, r1, 0, sra, s64) /* SHIFT RIGHT SINGLE LOGICAL */ - C(0x8800, SRL, RS_a, Z, r1_32u, sh32, new, r1_32, srl, 0) - C(0xebde, SRLK, RSY_a, DO, r3_32u, sh32, new, r1_32, srl, 0) - C(0xeb0c, SRLG, RSY_a, Z, r3_o, sh64, r1, 0, srl, 0) + C(0x8800, SRL, RS_a, Z, r1_32u, sh, new, r1_32, srl, 0) + C(0xebde, SRLK, RSY_a, DO, r3_32u, sh, new, r1_32, srl, 0) + C(0xeb0c, SRLG, RSY_a, Z, r3_o, sh, r1, 0, srl, 0) /* SHIFT LEFT DOUBLE */ - D(0x8f00, SLDA, RS_a, Z, r1_D32, sh64, new, r1_D32, sla, 0, 31) + D(0x8f00, SLDA, RS_a, Z, r1_D32, sh, new, r1_D32, sla, 0, 63) /* SHIFT LEFT DOUBLE LOGICAL */ - C(0x8d00, SLDL, RS_a, Z, r1_D32, sh64, new, r1_D32, sll, 0) + C(0x8d00, SLDL, RS_a, Z, r1_D32, sh, new, r1_D32, sll, 0) /* SHIFT RIGHT DOUBLE */ - C(0x8e00, SRDA, RS_a, Z, r1_D32, sh64, new, r1_D32, sra, s64) + C(0x8e00, SRDA, RS_a, Z, r1_D32, sh, new, r1_D32, sra, s64) /* SHIFT RIGHT DOUBLE LOGICAL */ - C(0x8c00, SRDL, RS_a, Z, r1_D32, sh64, new, r1_D32, srl, 0) + C(0x8c00, SRDL, RS_a, Z, r1_D32, sh, new, r1_D32, srl, 0) /* SQUARE ROOT */ F(0xb314, SQEBR, RRE, Z, 0, e2, new, e1, sqeb, 0, IF_BFP) diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c index f180853e7a..46dea73357 100644 --- a/target/s390x/tcg/translate.c +++ b/target/s390x/tcg/translate.c @@ -636,8 +636,7 @@ static void gen_op_calc_cc(DisasContext *s) case CC_OP_LTUGTU_64: case CC_OP_TM_32: case CC_OP_TM_64: - case CC_OP_SLA_32: - case CC_OP_SLA_64: + case CC_OP_SLA: case CC_OP_SUBU: case CC_OP_NZ_F128: case CC_OP_VC: @@ -1178,19 +1177,6 @@ struct DisasInsn { /* ====================================================================== */ /* Miscellaneous helpers, used by several operations. */ -static void help_l2_shift(DisasContext *s, DisasOps *o, int mask) -{ - int b2 = get_field(s, b2); - int d2 = get_field(s, d2); - - if (b2 == 0) { - o->in2 = tcg_const_i64(d2 & mask); - } else { - o->in2 = get_address(s, 0, b2, d2); - tcg_gen_andi_i64(o->in2, o->in2, mask); - } -} - static DisasJumpType help_goto_direct(DisasContext *s, uint64_t dest) { if (dest == s->pc_tmp) { @@ -4113,9 +4099,18 @@ static DisasJumpType op_soc(DisasContext *s, DisasOps *o) static DisasJumpType op_sla(DisasContext *s, DisasOps *o) { + TCGv_i64 t; uint64_t sign = 1ull << s->insn->data; - enum cc_op cco = s->insn->data == 31 ? CC_OP_SLA_32 : CC_OP_SLA_64; - gen_op_update2_cc_i64(s, cco, o->in1, o->in2); + if (s->insn->data == 31) { + t = tcg_temp_new_i64(); + tcg_gen_shli_i64(t, o->in1, 32); + } else { + t = o->in1; + } + gen_op_update2_cc_i64(s, CC_OP_SLA, t, o->in2); + if (s->insn->data == 31) { + tcg_temp_free_i64(t); + } tcg_gen_shl_i64(o->out, o->in1, o->in2); /* The arithmetic left shift is curious in that it does not affect the sign bit. Copy that over from the source unchanged. */ @@ -5420,9 +5415,11 @@ static void wout_r1_P32(DisasContext *s, DisasOps *o) static void wout_r1_D32(DisasContext *s, DisasOps *o) { int r1 = get_field(s, r1); + TCGv_i64 t = tcg_temp_new_i64(); store_reg32_i64(r1 + 1, o->out); - tcg_gen_shri_i64(o->out, o->out, 32); - store_reg32_i64(r1, o->out); + tcg_gen_shri_i64(t, o->out, 32); + store_reg32_i64(r1, t); + tcg_temp_free_i64(t); } #define SPEC_wout_r1_D32 SPEC_r1_even @@ -5922,17 +5919,19 @@ static void in2_ri2(DisasContext *s, DisasOps *o) } #define SPEC_in2_ri2 0 -static void in2_sh32(DisasContext *s, DisasOps *o) +static void in2_sh(DisasContext *s, DisasOps *o) { - help_l2_shift(s, o, 31); -} -#define SPEC_in2_sh32 0 + int b2 = get_field(s, b2); + int d2 = get_field(s, d2); -static void in2_sh64(DisasContext *s, DisasOps *o) -{ - help_l2_shift(s, o, 63); + if (b2 == 0) { + o->in2 = tcg_const_i64(d2 & 0x3f); + } else { + o->in2 = get_address(s, 0, b2, d2); + tcg_gen_andi_i64(o->in2, o->in2, 0x3f); + } } -#define SPEC_in2_sh64 0 +#define SPEC_in2_sh 0 static void in2_m2_8u(DisasContext *s, DisasOps *o) { diff --git a/target/sparc/machine.c b/target/sparc/machine.c index 917375c3a1..44b9e7d75d 100644 --- a/target/sparc/machine.c +++ b/target/sparc/machine.c @@ -10,7 +10,6 @@ static const VMStateDescription vmstate_cpu_timer = { .name = "cpu_timer", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(frequency, CPUTimer), VMSTATE_UINT32(disabled, CPUTimer), @@ -30,7 +29,6 @@ static const VMStateDescription vmstate_trap_state = { .name = "trap_state", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT64(tpc, trap_state), VMSTATE_UINT64(tnpc, trap_state), @@ -44,7 +42,6 @@ static const VMStateDescription vmstate_tlb_entry = { .name = "tlb_entry", .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_UINT64(tag, SparcTLBEntry), VMSTATE_UINT64(tte, SparcTLBEntry), @@ -113,7 +110,6 @@ const VMStateDescription vmstate_sparc_cpu = { .name = "cpu", .version_id = SPARC_VMSTATE_VER, .minimum_version_id = SPARC_VMSTATE_VER, - .minimum_version_id_old = SPARC_VMSTATE_VER, .pre_save = cpu_pre_save, .fields = (VMStateField[]) { VMSTATE_UINTTL_ARRAY(env.gregs, SPARCCPU, 8), |