|
From: | Yongbok Kim |
Subject: | Re: [Qemu-devel] [PATCH 4/6] target-mips: add restrictions for possible values in registers |
Date: | Mon, 20 Oct 2014 11:19:55 +0100 |
User-agent: | Mozilla/5.0 (Windows NT 6.1; WOW64; rv:31.0) Gecko/20100101 Thunderbird/31.2.0 |
On 14/07/2014 17:19, Leon Alrae
wrote:
In Release 6 not all the values are allowed to be written to a register. If the value is not valid or unsupported then it should stay unchanged. For pre-R6 the existing behaviour has been changed only for CP0_Index register as the current implementation does not seem to be correct - it looks like it tries to limit the input value but the limit is higher than the actual number of tlb entries. Signed-off-by: Leon Alrae <address@hidden> --- target-mips/op_helper.c | 63 ++++++++++++++++++++++++++++++++++------------ 1 files changed, 46 insertions(+), 17 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 431f3a1..4be435c 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -959,14 +959,14 @@ target_ulong helper_dmfc0_watchlo(CPUMIPSState *env, uint32_t sel) void helper_mtc0_index(CPUMIPSState *env, target_ulong arg1) { - int num = 1; - unsigned int tmp = env->tlb->nb_tlb; - - do { - tmp >>= 1; - num <<= 1; - } while (tmp); - env->CP0_Index = (env->CP0_Index & 0x80000000) | (arg1 & (num - 1)); + uint32_t index_p = env->CP0_Index & 0x80000000; + uint32_t tlb_index = arg1 & 0x7fffffff; + if (tlb_index < env->tlb->nb_tlb) { + if (env->insn_flags & ISA_MIPS32R6) { + index_p |= arg1 & 0x80000000; + } + env->CP0_Index = index_p | tlb_index; + } Agree to restrict index for pre R6 as well. It is UNDEFINED and software shouldn't rely on the undefined behaviour. } void helper_mtc0_mvpcontrol(CPUMIPSState *env, target_ulong arg1) @@ -1294,8 +1294,13 @@ void helper_mtc0_context(CPUMIPSState *env, target_ulong arg1) void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1) { - /* 1k pages not implemented */ This comment is still valid but it is appeared several times in the code already. Agreed to remove the comment here. - env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1)); + uint64_t mask = arg1 >> (TARGET_PAGE_BITS + 1); + if (!(env->insn_flags & ISA_MIPS32R6) || (arg1 == ~0) || + (mask == 0x0000 || mask == 0x0003 || mask == 0x000F || + mask == 0x003F || mask == 0x00FF || mask == 0x03FF || + mask == 0x0FFF || mask == 0x3FFF || mask == 0xFFFF)) { + env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1)); + } } void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1) @@ -1309,7 +1314,13 @@ void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1) void helper_mtc0_wired(CPUMIPSState *env, target_ulong arg1) { - env->CP0_Wired = arg1 % env->tlb->nb_tlb; + if (env->insn_flags & ISA_MIPS32R6) { + if (arg1 < env->tlb->nb_tlb) { + env->CP0_Wired = arg1; Wired field should be compared with Limit field (and as a result, number of entries in the TLB). + } + } else { + env->CP0_Wired = arg1 % env->tlb->nb_tlb; + } } void helper_mtc0_srsconf0(CPUMIPSState *env, target_ulong arg1) @@ -1368,11 +1379,14 @@ void helper_mtc0_entryhi(CPUMIPSState *env, target_ulong arg1) } /* 1k pages not implemented */ - val = arg1 & mask; #if defined(TARGET_MIPS64) - val &= env->SEGMask; + if ((env->insn_flags & ISA_MIPS32R6) && extract64(arg1, 62, 2) == 0x2) { + mask &= ~(0x3ull << 62); If Config0_AT = 1, R field is restricted for 1 as well. + } + mask &= env->SEGMask; #endif old = env->CP0_EntryHi; + val = (arg1 & mask) | (old & ~mask); env->CP0_EntryHi = val; if (env->CP0_Config3 & (1 << CP0C3_MT)) { sync_c0_entryhi(env, env->current_tc); @@ -1402,6 +1416,13 @@ void helper_mtc0_status(CPUMIPSState *env, target_ulong arg1) uint32_t val, old; uint32_t mask = env->CP0_Status_rw_bitmask; + if (env->insn_flags & ISA_MIPS32R6) { + if (extract32(env->CP0_Status, CP0St_KSU, 2) == 0x3) { + mask &= ~(3 << CP0St_KSU); + } + mask &= ~(0x00180000 & arg1); + } + val = arg1 & mask; old = env->CP0_Status; env->CP0_Status = (env->CP0_Status & ~mask) | val; @@ -1457,6 +1478,9 @@ static void mtc0_cause(CPUMIPSState *cpu, target_ulong arg1) if (cpu->insn_flags & ISA_MIPS32R2) { mask |= 1 << CP0Ca_DC; } + if (cpu->insn_flags & ISA_MIPS32R6) { + mask &= ~((1 << CP0Ca_WP) & arg1); + } cpu->CP0_Cause = (cpu->CP0_Cause & ~mask) | (arg1 & mask); @@ -2381,8 +2405,9 @@ void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt) } break; case 25: - if (arg1 & 0xffffff00) + if (env->insn_flags & ISA_MIPS32R6 || arg1 & 0xffffff00) { return; + } env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((arg1 & 0xfe) << 24) | ((arg1 & 0x1) << 23); break; @@ -2398,9 +2423,13 @@ void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt) ((arg1 & 0x4) << 22); break; case 31: - if (arg1 & 0x007c0000) - return; - env->active_fpu.fcr31 = arg1; + if (env->insn_flags & ISA_MIPS32R6) { + uint32_t mask = 0xfefc0000; + env->active_fpu.fcr31 = (arg1 & ~mask) | + (env->active_fpu.fcr31 & mask); + } else if (!(arg1 & 0x007c0000)) { + env->active_fpu.fcr31 = arg1; + } break; default: return; Regards, Yongbok |
[Prev in Thread] | Current Thread | [Next in Thread] |