Octeon firmware programs contiguous PageMask values that do not follow the generic R4K even maskbits rule.
Keep the generic validation rule for other MIPS CPUs, while allowing Octeon CPUs to use the contiguous masks accepted by hardware. Signed-off-by: Kirill A. Korinsky <[email protected]> --- target/mips/tcg/system/cp0_helper.c | 15 ++++++++++----- target/mips/tcg/system/tlb_helper.c | 2 +- target/mips/tcg/tcg-internal.h | 2 +- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/target/mips/tcg/system/cp0_helper.c b/target/mips/tcg/system/cp0_helper.c index 1c23d2a525..40a41805fa 100644 --- a/target/mips/tcg/system/cp0_helper.c +++ b/target/mips/tcg/system/cp0_helper.c @@ -882,14 +882,19 @@ void helper_mtc0_memorymapid(CPUMIPSState *env, target_ulong arg1) } } -uint32_t compute_pagemask(uint32_t val) +uint32_t compute_pagemask(CPUMIPSState *env, uint32_t val) { /* Don't care MASKX as we don't support 1KB page */ - uint32_t mask = extract32(val, CP0PM_MASK, 16); + uint32_t mask = val >> CP0PM_MASK; int maskbits = cto32(mask); - /* Ensure no more set bit after first zero, and maskbits even. */ - if ((mask >> maskbits) == 0 && maskbits % 2 == 0) { + /* + * Generic R4K PageMask values use two mask bits per size step. + * Octeon accepts contiguous byte masks such as 0x003fffff for + * two 2 MiB pages. + */ + if ((mask & (mask + 1)) == 0 && + ((env->insn_flags & INSN_OCTEON) || maskbits % 2 == 0)) { return mask << CP0PM_MASK; } else { /* When invalid, set to default target page size. */ @@ -899,7 +904,7 @@ uint32_t compute_pagemask(uint32_t val) void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1) { - env->CP0_PageMask = compute_pagemask(arg1); + env->CP0_PageMask = compute_pagemask(env, arg1); } void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1) diff --git a/target/mips/tcg/system/tlb_helper.c b/target/mips/tcg/system/tlb_helper.c index 4c0a25e622..ae805bff28 100644 --- a/target/mips/tcg/system/tlb_helper.c +++ b/target/mips/tcg/system/tlb_helper.c @@ -877,7 +877,7 @@ refill: } } pw_pagemask = m >> TARGET_PAGE_BITS; - pw_pagemask = compute_pagemask(pw_pagemask << CP0PM_MASK); + pw_pagemask = compute_pagemask(env, pw_pagemask << CP0PM_MASK); pw_entryhi = (address & ~0x1fff) | (env->CP0_EntryHi & 0xFF); { target_ulong tmp_entryhi = env->CP0_EntryHi; diff --git a/target/mips/tcg/tcg-internal.h b/target/mips/tcg/tcg-internal.h index 950e6afc3f..66ae39551e 100644 --- a/target/mips/tcg/tcg-internal.h +++ b/target/mips/tcg/tcg-internal.h @@ -47,7 +47,7 @@ bool mips_cpu_exec_interrupt(CPUState *cpu, int int_req); void mmu_init(CPUMIPSState *env, const mips_def_t *def); -uint32_t compute_pagemask(uint32_t val); +uint32_t compute_pagemask(CPUMIPSState *env, uint32_t val); void r4k_invalidate_tlb(CPUMIPSState *env, int idx, int use_extra); uint32_t cpu_mips_get_random(CPUMIPSState *env); -- 2.54.0
