X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=qemu%2Ftarget-mips%2Fop_helper.c;h=4417e6ba225f7fdabb957e06fb6e80e0e7a78e05;hb=a14b48d18a9ed03ec191cf16b162206998a895ce;hp=db4f6b946360d4c878b71001739f9c48b519a273;hpb=e44e3482bdb4d0ebde2d8b41830ac2cdb07948fb;p=kvmfornfv.git diff --git a/qemu/target-mips/op_helper.c b/qemu/target-mips/op_helper.c index db4f6b946..4417e6ba2 100644 --- a/qemu/target-mips/op_helper.c +++ b/qemu/target-mips/op_helper.c @@ -16,55 +16,33 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see . */ -#include +#include "qemu/osdep.h" #include "cpu.h" #include "qemu/host-utils.h" #include "exec/helper-proto.h" #include "exec/cpu_ldst.h" #include "sysemu/kvm.h" -#ifndef CONFIG_USER_ONLY -static inline void cpu_mips_tlb_flush (CPUMIPSState *env, int flush_global); -#endif - /*****************************************************************************/ /* Exceptions processing helpers */ -static inline void QEMU_NORETURN do_raise_exception_err(CPUMIPSState *env, - uint32_t exception, - int error_code, - uintptr_t pc) +void helper_raise_exception_err(CPUMIPSState *env, uint32_t exception, + int error_code) { - CPUState *cs = CPU(mips_env_get_cpu(env)); - - if (exception < EXCP_SC) { - qemu_log("%s: %d %d\n", __func__, exception, error_code); - } - cs->exception_index = exception; - env->error_code = error_code; - - if (pc) { - /* now we have a real cpu fault */ - cpu_restore_state(cs, pc); - } - - cpu_loop_exit(cs); + do_raise_exception_err(env, exception, error_code, 0); } -static inline void QEMU_NORETURN do_raise_exception(CPUMIPSState *env, - uint32_t exception, - uintptr_t pc) +void helper_raise_exception(CPUMIPSState *env, uint32_t exception) { - do_raise_exception_err(env, exception, 0, pc); + do_raise_exception(env, exception, GETPC()); } -void helper_raise_exception_err(CPUMIPSState *env, uint32_t exception, - int error_code) +void helper_raise_exception_debug(CPUMIPSState *env) { - do_raise_exception_err(env, exception, error_code, 0); + do_raise_exception(env, EXCP_DEBUG, 0); } -void helper_raise_exception(CPUMIPSState *env, uint32_t exception) +static void raise_exception(CPUMIPSState *env, uint32_t exception) { do_raise_exception(env, exception, 0); } @@ -72,21 +50,21 @@ void helper_raise_exception(CPUMIPSState *env, uint32_t exception) #if defined(CONFIG_USER_ONLY) #define HELPER_LD(name, insn, type) \ static inline type do_##name(CPUMIPSState *env, target_ulong addr, \ - int mem_idx) \ + int mem_idx, uintptr_t retaddr) \ { \ - return (type) cpu_##insn##_data(env, addr); \ + return (type) cpu_##insn##_data_ra(env, addr, retaddr); \ } #else #define HELPER_LD(name, insn, type) \ static inline type do_##name(CPUMIPSState *env, target_ulong addr, \ - int mem_idx) \ + int mem_idx, uintptr_t retaddr) \ { \ switch (mem_idx) \ { \ - case 0: return (type) cpu_##insn##_kernel(env, addr); break; \ - case 1: return (type) cpu_##insn##_super(env, addr); break; \ + case 0: return (type) cpu_##insn##_kernel_ra(env, addr, retaddr); \ + case 1: return (type) cpu_##insn##_super_ra(env, addr, retaddr); \ default: \ - case 2: return (type) cpu_##insn##_user(env, addr); break; \ + case 2: return (type) cpu_##insn##_user_ra(env, addr, retaddr); \ } \ } #endif @@ -99,21 +77,21 @@ HELPER_LD(ld, ldq, int64_t) #if defined(CONFIG_USER_ONLY) #define HELPER_ST(name, insn, type) \ static inline void do_##name(CPUMIPSState *env, target_ulong addr, \ - type val, int mem_idx) \ + type val, int mem_idx, uintptr_t retaddr) \ { \ - cpu_##insn##_data(env, addr, val); \ + cpu_##insn##_data_ra(env, addr, val, retaddr); \ } #else #define HELPER_ST(name, insn, type) \ static inline void do_##name(CPUMIPSState *env, target_ulong addr, \ - type val, int mem_idx) \ + type val, int mem_idx, uintptr_t retaddr) \ { \ switch (mem_idx) \ { \ - case 0: cpu_##insn##_kernel(env, addr, val); break; \ - case 1: cpu_##insn##_super(env, addr, val); break; \ + case 0: cpu_##insn##_kernel_ra(env, addr, val, retaddr); break; \ + case 1: cpu_##insn##_super_ra(env, addr, val, retaddr); break; \ default: \ - case 2: cpu_##insn##_user(env, addr, val); break; \ + case 2: cpu_##insn##_user_ra(env, addr, val, retaddr); break; \ } \ } #endif @@ -292,14 +270,15 @@ target_ulong helper_bitswap(target_ulong rt) static inline hwaddr do_translate_address(CPUMIPSState *env, target_ulong address, - int rw) + int rw, uintptr_t retaddr) { hwaddr lladdr; + CPUState *cs = CPU(mips_env_get_cpu(env)); lladdr = cpu_mips_translate_address(env, address, rw); if (lladdr == -1LL) { - cpu_loop_exit(CPU(mips_env_get_cpu(env))); + cpu_loop_exit_restore(cs, retaddr); } else { return lladdr; } @@ -310,10 +289,10 @@ target_ulong helper_##name(CPUMIPSState *env, target_ulong arg, int mem_idx) \ { \ if (arg & almask) { \ env->CP0_BadVAddr = arg; \ - helper_raise_exception(env, EXCP_AdEL); \ + do_raise_exception(env, EXCP_AdEL, GETPC()); \ } \ - env->lladdr = do_translate_address(env, arg, 0); \ - env->llval = do_##insn(env, arg, mem_idx); \ + env->lladdr = do_translate_address(env, arg, 0, GETPC()); \ + env->llval = do_##insn(env, arg, mem_idx, GETPC()); \ return env->llval; \ } HELPER_LD_ATOMIC(ll, lw, 0x3) @@ -330,12 +309,12 @@ target_ulong helper_##name(CPUMIPSState *env, target_ulong arg1, \ \ if (arg2 & almask) { \ env->CP0_BadVAddr = arg2; \ - helper_raise_exception(env, EXCP_AdES); \ + do_raise_exception(env, EXCP_AdES, GETPC()); \ } \ - if (do_translate_address(env, arg2, 1) == env->lladdr) { \ - tmp = do_##ld_insn(env, arg2, mem_idx); \ + if (do_translate_address(env, arg2, 1, GETPC()) == env->lladdr) { \ + tmp = do_##ld_insn(env, arg2, mem_idx, GETPC()); \ if (tmp == env->llval) { \ - do_##st_insn(env, arg2, arg1, mem_idx); \ + do_##st_insn(env, arg2, arg1, mem_idx, GETPC()); \ return 1; \ } \ } \ @@ -359,31 +338,43 @@ HELPER_ST_ATOMIC(scd, ld, sd, 0x7) void helper_swl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2, int mem_idx) { - do_sb(env, arg2, (uint8_t)(arg1 >> 24), mem_idx); + do_sb(env, arg2, (uint8_t)(arg1 >> 24), mem_idx, GETPC()); - if (GET_LMASK(arg2) <= 2) - do_sb(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16), mem_idx); + if (GET_LMASK(arg2) <= 2) { + do_sb(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16), mem_idx, + GETPC()); + } - if (GET_LMASK(arg2) <= 1) - do_sb(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8), mem_idx); + if (GET_LMASK(arg2) <= 1) { + do_sb(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8), mem_idx, + GETPC()); + } - if (GET_LMASK(arg2) == 0) - do_sb(env, GET_OFFSET(arg2, 3), (uint8_t)arg1, mem_idx); + if (GET_LMASK(arg2) == 0) { + do_sb(env, GET_OFFSET(arg2, 3), (uint8_t)arg1, mem_idx, + GETPC()); + } } void helper_swr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2, int mem_idx) { - do_sb(env, arg2, (uint8_t)arg1, mem_idx); + do_sb(env, arg2, (uint8_t)arg1, mem_idx, GETPC()); - if (GET_LMASK(arg2) >= 1) - do_sb(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx); + if (GET_LMASK(arg2) >= 1) { + do_sb(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx, + GETPC()); + } - if (GET_LMASK(arg2) >= 2) - do_sb(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx); + if (GET_LMASK(arg2) >= 2) { + do_sb(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx, + GETPC()); + } - if (GET_LMASK(arg2) == 3) - do_sb(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx); + if (GET_LMASK(arg2) == 3) { + do_sb(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx, + GETPC()); + } } #if defined(TARGET_MIPS64) @@ -399,55 +390,83 @@ void helper_swr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2, void helper_sdl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2, int mem_idx) { - do_sb(env, arg2, (uint8_t)(arg1 >> 56), mem_idx); + do_sb(env, arg2, (uint8_t)(arg1 >> 56), mem_idx, GETPC()); - if (GET_LMASK64(arg2) <= 6) - do_sb(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48), mem_idx); + if (GET_LMASK64(arg2) <= 6) { + do_sb(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48), mem_idx, + GETPC()); + } - if (GET_LMASK64(arg2) <= 5) - do_sb(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40), mem_idx); + if (GET_LMASK64(arg2) <= 5) { + do_sb(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40), mem_idx, + GETPC()); + } - if (GET_LMASK64(arg2) <= 4) - do_sb(env, GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32), mem_idx); + if (GET_LMASK64(arg2) <= 4) { + do_sb(env, GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32), mem_idx, + GETPC()); + } - if (GET_LMASK64(arg2) <= 3) - do_sb(env, GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24), mem_idx); + if (GET_LMASK64(arg2) <= 3) { + do_sb(env, GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24), mem_idx, + GETPC()); + } - if (GET_LMASK64(arg2) <= 2) - do_sb(env, GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16), mem_idx); + if (GET_LMASK64(arg2) <= 2) { + do_sb(env, GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16), mem_idx, + GETPC()); + } - if (GET_LMASK64(arg2) <= 1) - do_sb(env, GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8), mem_idx); + if (GET_LMASK64(arg2) <= 1) { + do_sb(env, GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8), mem_idx, + GETPC()); + } - if (GET_LMASK64(arg2) <= 0) - do_sb(env, GET_OFFSET(arg2, 7), (uint8_t)arg1, mem_idx); + if (GET_LMASK64(arg2) <= 0) { + do_sb(env, GET_OFFSET(arg2, 7), (uint8_t)arg1, mem_idx, + GETPC()); + } } void helper_sdr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2, int mem_idx) { - do_sb(env, arg2, (uint8_t)arg1, mem_idx); + do_sb(env, arg2, (uint8_t)arg1, mem_idx, GETPC()); - if (GET_LMASK64(arg2) >= 1) - do_sb(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx); + if (GET_LMASK64(arg2) >= 1) { + do_sb(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx, + GETPC()); + } - if (GET_LMASK64(arg2) >= 2) - do_sb(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx); + if (GET_LMASK64(arg2) >= 2) { + do_sb(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx, + GETPC()); + } - if (GET_LMASK64(arg2) >= 3) - do_sb(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx); + if (GET_LMASK64(arg2) >= 3) { + do_sb(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx, + GETPC()); + } - if (GET_LMASK64(arg2) >= 4) - do_sb(env, GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32), mem_idx); + if (GET_LMASK64(arg2) >= 4) { + do_sb(env, GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32), mem_idx, + GETPC()); + } - if (GET_LMASK64(arg2) >= 5) - do_sb(env, GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40), mem_idx); + if (GET_LMASK64(arg2) >= 5) { + do_sb(env, GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40), mem_idx, + GETPC()); + } - if (GET_LMASK64(arg2) >= 6) - do_sb(env, GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48), mem_idx); + if (GET_LMASK64(arg2) >= 6) { + do_sb(env, GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48), mem_idx, + GETPC()); + } - if (GET_LMASK64(arg2) == 7) - do_sb(env, GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56), mem_idx); + if (GET_LMASK64(arg2) == 7) { + do_sb(env, GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56), mem_idx, + GETPC()); + } } #endif /* TARGET_MIPS64 */ @@ -464,13 +483,14 @@ void helper_lwm(CPUMIPSState *env, target_ulong addr, target_ulong reglist, for (i = 0; i < base_reglist; i++) { env->active_tc.gpr[multiple_regs[i]] = - (target_long)do_lw(env, addr, mem_idx); + (target_long)do_lw(env, addr, mem_idx, GETPC()); addr += 4; } } if (do_r31) { - env->active_tc.gpr[31] = (target_long)do_lw(env, addr, mem_idx); + env->active_tc.gpr[31] = (target_long)do_lw(env, addr, mem_idx, + GETPC()); } } @@ -484,13 +504,14 @@ void helper_swm(CPUMIPSState *env, target_ulong addr, target_ulong reglist, target_ulong i; for (i = 0; i < base_reglist; i++) { - do_sw(env, addr, env->active_tc.gpr[multiple_regs[i]], mem_idx); + do_sw(env, addr, env->active_tc.gpr[multiple_regs[i]], mem_idx, + GETPC()); addr += 4; } } if (do_r31) { - do_sw(env, addr, env->active_tc.gpr[31], mem_idx); + do_sw(env, addr, env->active_tc.gpr[31], mem_idx, GETPC()); } } @@ -505,13 +526,14 @@ void helper_ldm(CPUMIPSState *env, target_ulong addr, target_ulong reglist, target_ulong i; for (i = 0; i < base_reglist; i++) { - env->active_tc.gpr[multiple_regs[i]] = do_ld(env, addr, mem_idx); + env->active_tc.gpr[multiple_regs[i]] = do_ld(env, addr, mem_idx, + GETPC()); addr += 8; } } if (do_r31) { - env->active_tc.gpr[31] = do_ld(env, addr, mem_idx); + env->active_tc.gpr[31] = do_ld(env, addr, mem_idx, GETPC()); } } @@ -525,13 +547,14 @@ void helper_sdm(CPUMIPSState *env, target_ulong addr, target_ulong reglist, target_ulong i; for (i = 0; i < base_reglist; i++) { - do_sd(env, addr, env->active_tc.gpr[multiple_regs[i]], mem_idx); + do_sd(env, addr, env->active_tc.gpr[multiple_regs[i]], mem_idx, + GETPC()); addr += 8; } } if (do_r31) { - do_sd(env, addr, env->active_tc.gpr[31], mem_idx); + do_sd(env, addr, env->active_tc.gpr[31], mem_idx, GETPC()); } } #endif @@ -548,6 +571,14 @@ static bool mips_vpe_is_wfi(MIPSCPU *c) return cpu->halted && mips_vpe_active(env); } +static bool mips_vp_is_wfi(MIPSCPU *c) +{ + CPUState *cpu = CPU(c); + CPUMIPSState *env = &c->env; + + return cpu->halted && mips_vp_active(env); +} + static inline void mips_vpe_wake(MIPSCPU *c) { /* Dont set ->halted = 0 directly, let it be done via cpu_has_work @@ -858,6 +889,16 @@ target_ulong helper_mfc0_lladdr(CPUMIPSState *env) return (int32_t)(env->lladdr >> env->CP0_LLAddr_shift); } +target_ulong helper_mfc0_maar(CPUMIPSState *env) +{ + return (int32_t) env->CP0_MAAR[env->CP0_MAARI]; +} + +target_ulong helper_mfhc0_maar(CPUMIPSState *env) +{ + return env->CP0_MAAR[env->CP0_MAARI] >> 32; +} + target_ulong helper_mfc0_watchlo(CPUMIPSState *env, uint32_t sel) { return (int32_t)env->CP0_WatchLo[sel]; @@ -924,6 +965,11 @@ target_ulong helper_dmfc0_lladdr(CPUMIPSState *env) return env->lladdr >> env->CP0_LLAddr_shift; } +target_ulong helper_dmfc0_maar(CPUMIPSState *env) +{ + return env->CP0_MAAR[env->CP0_MAARI]; +} + target_ulong helper_dmfc0_watchlo(CPUMIPSState *env, uint32_t sel) { return env->CP0_WatchLo[sel]; @@ -1330,6 +1376,13 @@ void helper_mtc0_hwrena(CPUMIPSState *env, target_ulong arg1) { uint32_t mask = 0x0000000F; + if ((env->CP0_Config1 & (1 << CP0C1_PC)) && + (env->insn_flags & ISA_MIPS32R6)) { + mask |= (1 << 4); + } + if (env->insn_flags & ISA_MIPS32R6) { + mask |= (1 << 5); + } if (env->CP0_Config3 & (1 << CP0C3_ULRI)) { mask |= (1 << 29); @@ -1540,6 +1593,36 @@ void helper_mtc0_lladdr(CPUMIPSState *env, target_ulong arg1) env->lladdr = (env->lladdr & ~mask) | (arg1 & mask); } +#define MTC0_MAAR_MASK(env) \ + ((0x1ULL << 63) | ((env->PAMask >> 4) & ~0xFFFull) | 0x3) + +void helper_mtc0_maar(CPUMIPSState *env, target_ulong arg1) +{ + env->CP0_MAAR[env->CP0_MAARI] = arg1 & MTC0_MAAR_MASK(env); +} + +void helper_mthc0_maar(CPUMIPSState *env, target_ulong arg1) +{ + env->CP0_MAAR[env->CP0_MAARI] = + (((uint64_t) arg1 << 32) & MTC0_MAAR_MASK(env)) | + (env->CP0_MAAR[env->CP0_MAARI] & 0x00000000ffffffffULL); +} + +void helper_mtc0_maari(CPUMIPSState *env, target_ulong arg1) +{ + int index = arg1 & 0x3f; + if (index == 0x3f) { + /* Software may write all ones to INDEX to determine the + maximum value supported. */ + env->CP0_MAARI = MIPS_MAAR_MAX - 1; + } else if (index < MIPS_MAAR_MAX) { + env->CP0_MAARI = index; + } + /* Other than the all ones, if the + value written is not supported, then INDEX is unchanged + from its previous value. */ +} + void helper_mtc0_watchlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel) { /* Watch exceptions for instructions, data loads, data stores @@ -1594,9 +1677,31 @@ void helper_mtc0_performance0(CPUMIPSState *env, target_ulong arg1) env->CP0_Performance0 = arg1 & 0x000007ff; } +void helper_mtc0_errctl(CPUMIPSState *env, target_ulong arg1) +{ + int32_t wst = arg1 & (1 << CP0EC_WST); + int32_t spr = arg1 & (1 << CP0EC_SPR); + int32_t itc = env->itc_tag ? (arg1 & (1 << CP0EC_ITC)) : 0; + + env->CP0_ErrCtl = wst | spr | itc; + + if (itc && !wst && !spr) { + env->hflags |= MIPS_HFLAG_ITC_CACHE; + } else { + env->hflags &= ~MIPS_HFLAG_ITC_CACHE; + } +} + void helper_mtc0_taglo(CPUMIPSState *env, target_ulong arg1) { - env->CP0_TagLo = arg1 & 0xFFFFFCF6; + if (env->hflags & MIPS_HFLAG_ITC_CACHE) { + /* If CACHE instruction is configured for ITC tags then make all + CP0.TagLo bits writable. The actual write to ITC Configuration + Tag will take care of the read-only bits. */ + env->CP0_TagLo = arg1; + } else { + env->CP0_TagLo = arg1 & 0xFFFFFCF6; + } } void helper_mtc0_datalo(CPUMIPSState *env, target_ulong arg1) @@ -1791,13 +1896,13 @@ target_ulong helper_yield(CPUMIPSState *env, target_ulong arg) env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) { env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT); env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT; - helper_raise_exception(env, EXCP_THREAD); + do_raise_exception(env, EXCP_THREAD, GETPC()); } } } else if (arg1 == 0) { if (0 /* TODO: TC underflow */) { env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT); - helper_raise_exception(env, EXCP_THREAD); + do_raise_exception(env, EXCP_THREAD, GETPC()); } else { // TODO: Deallocate TC } @@ -1805,22 +1910,53 @@ target_ulong helper_yield(CPUMIPSState *env, target_ulong arg) /* Yield qualifier inputs not implemented. */ env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT); env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT; - helper_raise_exception(env, EXCP_THREAD); + do_raise_exception(env, EXCP_THREAD, GETPC()); } return env->CP0_YQMask; } +/* R6 Multi-threading */ #ifndef CONFIG_USER_ONLY -/* TLB management */ -static void cpu_mips_tlb_flush (CPUMIPSState *env, int flush_global) +target_ulong helper_dvp(CPUMIPSState *env) { - MIPSCPU *cpu = mips_env_get_cpu(env); + CPUState *other_cs = first_cpu; + target_ulong prev = env->CP0_VPControl; + + if (!((env->CP0_VPControl >> CP0VPCtl_DIS) & 1)) { + CPU_FOREACH(other_cs) { + MIPSCPU *other_cpu = MIPS_CPU(other_cs); + /* Turn off all VPs except the one executing the dvp. */ + if (&other_cpu->env != env) { + mips_vpe_sleep(other_cpu); + } + } + env->CP0_VPControl |= (1 << CP0VPCtl_DIS); + } + return prev; +} - /* Flush qemu's TLB and discard all shadowed entries. */ - tlb_flush(CPU(cpu), flush_global); - env->tlb->tlb_in_use = env->tlb->nb_tlb; +target_ulong helper_evp(CPUMIPSState *env) +{ + CPUState *other_cs = first_cpu; + target_ulong prev = env->CP0_VPControl; + + if ((env->CP0_VPControl >> CP0VPCtl_DIS) & 1) { + CPU_FOREACH(other_cs) { + MIPSCPU *other_cpu = MIPS_CPU(other_cs); + if ((&other_cpu->env != env) && !mips_vp_is_wfi(other_cpu)) { + /* If the VP is WFI, don't disturb its sleep. + * Otherwise, wake it up. */ + mips_vpe_wake(other_cpu); + } + } + env->CP0_VPControl &= ~(1 << CP0VPCtl_DIS); + } + return prev; } +#endif /* !CONFIG_USER_ONLY */ +#ifndef CONFIG_USER_ONLY +/* TLB management */ static void r4k_mips_tlb_flush_extra (CPUMIPSState *env, int first) { /* Discard entries from env->tlb[first] onwards. */ @@ -2158,48 +2294,52 @@ void helper_deret(CPUMIPSState *env) } #endif /* !CONFIG_USER_ONLY */ -target_ulong helper_rdhwr_cpunum(CPUMIPSState *env) +static inline void check_hwrena(CPUMIPSState *env, int reg, uintptr_t pc) { - if ((env->hflags & MIPS_HFLAG_CP0) || - (env->CP0_HWREna & (1 << 0))) - return env->CP0_EBase & 0x3ff; - else - helper_raise_exception(env, EXCP_RI); + if ((env->hflags & MIPS_HFLAG_CP0) || (env->CP0_HWREna & (1 << reg))) { + return; + } + do_raise_exception(env, EXCP_RI, pc); +} - return 0; +target_ulong helper_rdhwr_cpunum(CPUMIPSState *env) +{ + check_hwrena(env, 0, GETPC()); + return env->CP0_EBase & 0x3ff; } target_ulong helper_rdhwr_synci_step(CPUMIPSState *env) { - if ((env->hflags & MIPS_HFLAG_CP0) || - (env->CP0_HWREna & (1 << 1))) - return env->SYNCI_Step; - else - helper_raise_exception(env, EXCP_RI); - - return 0; + check_hwrena(env, 1, GETPC()); + return env->SYNCI_Step; } target_ulong helper_rdhwr_cc(CPUMIPSState *env) { - if ((env->hflags & MIPS_HFLAG_CP0) || - (env->CP0_HWREna & (1 << 2))) - return env->CP0_Count; - else - helper_raise_exception(env, EXCP_RI); - - return 0; + check_hwrena(env, 2, GETPC()); +#ifdef CONFIG_USER_ONLY + return env->CP0_Count; +#else + return (int32_t)cpu_mips_get_count(env); +#endif } target_ulong helper_rdhwr_ccres(CPUMIPSState *env) { - if ((env->hflags & MIPS_HFLAG_CP0) || - (env->CP0_HWREna & (1 << 3))) - return env->CCRes; - else - helper_raise_exception(env, EXCP_RI); + check_hwrena(env, 3, GETPC()); + return env->CCRes; +} - return 0; +target_ulong helper_rdhwr_performance(CPUMIPSState *env) +{ + check_hwrena(env, 4, GETPC()); + return env->CP0_Performance0; +} + +target_ulong helper_rdhwr_xnp(CPUMIPSState *env) +{ + check_hwrena(env, 5, GETPC()); + return (env->CP0_Config5 >> CP0C5_XNP) & 1; } void helper_pmon(CPUMIPSState *env, int function) @@ -2234,7 +2374,9 @@ void helper_wait(CPUMIPSState *env) cs->halted = 1; cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE); - helper_raise_exception(env, EXCP_HLT); + /* Last instruction in the block, PC was updated before + - no need to recover PC and icount */ + raise_exception(env, EXCP_HLT); } #if !defined(CONFIG_USER_ONLY) @@ -2295,9 +2437,9 @@ void mips_cpu_unassigned_access(CPUState *cs, hwaddr addr, } if (is_exec) { - helper_raise_exception(env, EXCP_IBE); + raise_exception(env, EXCP_IBE); } else { - helper_raise_exception(env, EXCP_DBE); + raise_exception(env, EXCP_DBE); } } #endif /* !CONFIG_USER_ONLY */ @@ -2332,7 +2474,7 @@ target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg) arg1 = (int32_t) ((env->CP0_Status & (1 << CP0St_FR)) >> CP0St_FR); } else { - helper_raise_exception(env, EXCP_RI); + do_raise_exception(env, EXCP_RI, GETPC()); } } break; @@ -2375,7 +2517,7 @@ void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt) env->CP0_Status &= ~(1 << CP0St_FR); compute_hflags(env); } else { - helper_raise_exception(env, EXCP_RI); + do_raise_exception(env, EXCP_RI, GETPC()); } break; case 4: @@ -2387,7 +2529,7 @@ void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt) env->CP0_Status |= (1 << CP0St_FR); compute_hflags(env); } else { - helper_raise_exception(env, EXCP_RI); + do_raise_exception(env, EXCP_RI, GETPC()); } break; case 5: @@ -2518,6 +2660,7 @@ uint64_t helper_float_cvtd_s(CPUMIPSState *env, uint32_t fst0) uint64_t fdt2; fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status); + fdt2 = float64_maybe_silence_nan(fdt2); update_fcr31(env, GETPC()); return fdt2; } @@ -2607,6 +2750,7 @@ uint32_t helper_float_cvts_d(CPUMIPSState *env, uint64_t fdt0) uint32_t fst2; fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status); + fst2 = float32_maybe_silence_nan(fst2); update_fcr31(env, GETPC()); return fst2; } @@ -3628,7 +3772,7 @@ FOP_CONDN_S(sne, (float32_lt(fst1, fst0, &env->active_fpu.fp_status) #if !defined(CONFIG_USER_ONLY) #define MEMOP_IDX(DF) \ TCGMemOpIdx oi = make_memop_idx(MO_TE | DF | MO_UNALN, \ - cpu_mmu_index(env)); + cpu_mmu_index(env, false)); #else #define MEMOP_IDX(DF) #endif @@ -3684,7 +3828,7 @@ void helper_msa_st_ ## TYPE(CPUMIPSState *env, uint32_t wd, \ target_ulong addr) \ { \ wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \ - int mmu_idx = cpu_mmu_index(env); \ + int mmu_idx = cpu_mmu_index(env, false); \ int i; \ MEMOP_IDX(DF) \ ensure_writable_pages(env, addr, mmu_idx, GETRA()); \ @@ -3704,3 +3848,19 @@ MSA_ST_DF(DF_HALF, h, cpu_stw_data) MSA_ST_DF(DF_WORD, w, cpu_stl_data) MSA_ST_DF(DF_DOUBLE, d, cpu_stq_data) #endif + +void helper_cache(CPUMIPSState *env, target_ulong addr, uint32_t op) +{ +#ifndef CONFIG_USER_ONLY + target_ulong index = addr & 0x1fffffff; + if (op == 9) { + /* Index Store Tag */ + memory_region_dispatch_write(env->itc_tag, index, env->CP0_TagLo, + 8, MEMTXATTRS_UNSPECIFIED); + } else if (op == 5) { + /* Index Load Tag */ + memory_region_dispatch_read(env->itc_tag, index, &env->CP0_TagLo, + 8, MEMTXATTRS_UNSPECIFIED); + } +#endif +}