Skip to content

Commit ba801af

Browse files
author
Leon Alrae
committed
target-mips: add restrictions for possible values in registers
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 <[email protected]> Reviewed-by: Yongbok Kim <[email protected]>
1 parent a63eb0c commit ba801af

File tree

1 file changed

+53
-17
lines changed

1 file changed

+53
-17
lines changed

target-mips/op_helper.c

+53-17
Original file line numberDiff line numberDiff line change
@@ -959,14 +959,14 @@ target_ulong helper_dmfc0_watchlo(CPUMIPSState *env, uint32_t sel)
959959

960960
void helper_mtc0_index(CPUMIPSState *env, target_ulong arg1)
961961
{
962-
int num = 1;
963-
unsigned int tmp = env->tlb->nb_tlb;
964-
965-
do {
966-
tmp >>= 1;
967-
num <<= 1;
968-
} while (tmp);
969-
env->CP0_Index = (env->CP0_Index & 0x80000000) | (arg1 & (num - 1));
962+
uint32_t index_p = env->CP0_Index & 0x80000000;
963+
uint32_t tlb_index = arg1 & 0x7fffffff;
964+
if (tlb_index < env->tlb->nb_tlb) {
965+
if (env->insn_flags & ISA_MIPS32R6) {
966+
index_p |= arg1 & 0x80000000;
967+
}
968+
env->CP0_Index = index_p | tlb_index;
969+
}
970970
}
971971

972972
void helper_mtc0_mvpcontrol(CPUMIPSState *env, target_ulong arg1)
@@ -1294,8 +1294,13 @@ void helper_mtc0_context(CPUMIPSState *env, target_ulong arg1)
12941294

12951295
void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1)
12961296
{
1297-
/* 1k pages not implemented */
1298-
env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1));
1297+
uint64_t mask = arg1 >> (TARGET_PAGE_BITS + 1);
1298+
if (!(env->insn_flags & ISA_MIPS32R6) || (arg1 == ~0) ||
1299+
(mask == 0x0000 || mask == 0x0003 || mask == 0x000F ||
1300+
mask == 0x003F || mask == 0x00FF || mask == 0x03FF ||
1301+
mask == 0x0FFF || mask == 0x3FFF || mask == 0xFFFF)) {
1302+
env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1));
1303+
}
12991304
}
13001305

13011306
void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1)
@@ -1309,7 +1314,13 @@ void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1)
13091314

13101315
void helper_mtc0_wired(CPUMIPSState *env, target_ulong arg1)
13111316
{
1312-
env->CP0_Wired = arg1 % env->tlb->nb_tlb;
1317+
if (env->insn_flags & ISA_MIPS32R6) {
1318+
if (arg1 < env->tlb->nb_tlb) {
1319+
env->CP0_Wired = arg1;
1320+
}
1321+
} else {
1322+
env->CP0_Wired = arg1 % env->tlb->nb_tlb;
1323+
}
13131324
}
13141325

13151326
void helper_mtc0_srsconf0(CPUMIPSState *env, target_ulong arg1)
@@ -1368,11 +1379,21 @@ void helper_mtc0_entryhi(CPUMIPSState *env, target_ulong arg1)
13681379
}
13691380

13701381
/* 1k pages not implemented */
1371-
val = arg1 & mask;
13721382
#if defined(TARGET_MIPS64)
1373-
val &= env->SEGMask;
1383+
if (env->insn_flags & ISA_MIPS32R6) {
1384+
int entryhi_r = extract64(arg1, 62, 2);
1385+
int config0_at = extract32(env->CP0_Config0, 13, 2);
1386+
bool no_supervisor = (env->CP0_Status_rw_bitmask & 0x8) == 0;
1387+
if ((entryhi_r == 2) ||
1388+
(entryhi_r == 1 && (no_supervisor || config0_at == 1))) {
1389+
/* skip EntryHi.R field if new value is reserved */
1390+
mask &= ~(0x3ull << 62);
1391+
}
1392+
}
1393+
mask &= env->SEGMask;
13741394
#endif
13751395
old = env->CP0_EntryHi;
1396+
val = (arg1 & mask) | (old & ~mask);
13761397
env->CP0_EntryHi = val;
13771398
if (env->CP0_Config3 & (1 << CP0C3_MT)) {
13781399
sync_c0_entryhi(env, env->current_tc);
@@ -1402,6 +1423,13 @@ void helper_mtc0_status(CPUMIPSState *env, target_ulong arg1)
14021423
uint32_t val, old;
14031424
uint32_t mask = env->CP0_Status_rw_bitmask;
14041425

1426+
if (env->insn_flags & ISA_MIPS32R6) {
1427+
if (extract32(env->CP0_Status, CP0St_KSU, 2) == 0x3) {
1428+
mask &= ~(3 << CP0St_KSU);
1429+
}
1430+
mask &= ~(0x00180000 & arg1);
1431+
}
1432+
14051433
val = arg1 & mask;
14061434
old = env->CP0_Status;
14071435
env->CP0_Status = (env->CP0_Status & ~mask) | val;
@@ -1457,6 +1485,9 @@ static void mtc0_cause(CPUMIPSState *cpu, target_ulong arg1)
14571485
if (cpu->insn_flags & ISA_MIPS32R2) {
14581486
mask |= 1 << CP0Ca_DC;
14591487
}
1488+
if (cpu->insn_flags & ISA_MIPS32R6) {
1489+
mask &= ~((1 << CP0Ca_WP) & arg1);
1490+
}
14601491

14611492
cpu->CP0_Cause = (cpu->CP0_Cause & ~mask) | (arg1 & mask);
14621493

@@ -2391,8 +2422,9 @@ void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt)
23912422
}
23922423
break;
23932424
case 25:
2394-
if (arg1 & 0xffffff00)
2425+
if ((env->insn_flags & ISA_MIPS32R6) || (arg1 & 0xffffff00)) {
23952426
return;
2427+
}
23962428
env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((arg1 & 0xfe) << 24) |
23972429
((arg1 & 0x1) << 23);
23982430
break;
@@ -2408,9 +2440,13 @@ void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt)
24082440
((arg1 & 0x4) << 22);
24092441
break;
24102442
case 31:
2411-
if (arg1 & 0x007c0000)
2412-
return;
2413-
env->active_fpu.fcr31 = arg1;
2443+
if (env->insn_flags & ISA_MIPS32R6) {
2444+
uint32_t mask = 0xfefc0000;
2445+
env->active_fpu.fcr31 = (arg1 & ~mask) |
2446+
(env->active_fpu.fcr31 & mask);
2447+
} else if (!(arg1 & 0x007c0000)) {
2448+
env->active_fpu.fcr31 = arg1;
2449+
}
24142450
break;
24152451
default:
24162452
return;

0 commit comments

Comments
 (0)