Commit 24c7b0e330fdbfcfe87f515d79e67156c57cbc4f
1 parent
e69f67b6
Sanitize mips exception handling.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2546 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
8 changed files
with
66 additions
and
84 deletions
cpu-exec.c
... | ... | @@ -461,10 +461,10 @@ int cpu_exec(CPUState *env1) |
461 | 461 | } |
462 | 462 | #elif defined(TARGET_MIPS) |
463 | 463 | if ((interrupt_request & CPU_INTERRUPT_HARD) && |
464 | + (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) && | |
464 | 465 | (env->CP0_Status & (1 << CP0St_IE)) && |
465 | - (env->CP0_Status & env->CP0_Cause & 0x0000FF00) && | |
466 | - !(env->hflags & MIPS_HFLAG_EXL) && | |
467 | - !(env->hflags & MIPS_HFLAG_ERL) && | |
466 | + !(env->CP0_Status & (1 << CP0St_EXL)) && | |
467 | + !(env->CP0_Status & (1 << CP0St_ERL)) && | |
468 | 468 | !(env->hflags & MIPS_HFLAG_DM)) { |
469 | 469 | /* Raise it */ |
470 | 470 | env->exception_index = EXCP_EXT_INTERRUPT; | ... | ... |
dyngen-exec.h
hw/mips_int.c
... | ... | @@ -5,17 +5,16 @@ |
5 | 5 | IRQ may change */ |
6 | 6 | void cpu_mips_update_irq(CPUState *env) |
7 | 7 | { |
8 | - if ((env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) && | |
9 | - (env->CP0_Status & (1 << CP0St_IE)) && | |
10 | - !(env->hflags & MIPS_HFLAG_EXL) && | |
11 | - !(env->hflags & MIPS_HFLAG_ERL) && | |
12 | - !(env->hflags & MIPS_HFLAG_DM)) { | |
13 | - if (! (env->interrupt_request & CPU_INTERRUPT_HARD)) { | |
8 | + if ((env->CP0_Status & (1 << CP0St_IE)) && | |
9 | + !(env->CP0_Status & (1 << CP0St_EXL)) && | |
10 | + !(env->CP0_Status & (1 << CP0St_ERL)) && | |
11 | + !(env->hflags & MIPS_HFLAG_DM)) { | |
12 | + if ((env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) && | |
13 | + !(env->interrupt_request & CPU_INTERRUPT_HARD)) { | |
14 | 14 | cpu_interrupt(env, CPU_INTERRUPT_HARD); |
15 | 15 | } |
16 | - } else { | |
16 | + } else | |
17 | 17 | cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); |
18 | - } | |
19 | 18 | } |
20 | 19 | |
21 | 20 | void cpu_mips_irq_request(void *opaque, int irq, int level) | ... | ... |
target-mips/cpu.h
... | ... | @@ -248,8 +248,6 @@ struct CPUMIPSState { |
248 | 248 | #define MIPS_HFLAG_TMASK 0x007F |
249 | 249 | #define MIPS_HFLAG_MODE 0x001F /* execution modes */ |
250 | 250 | #define MIPS_HFLAG_UM 0x0001 /* user mode */ |
251 | -#define MIPS_HFLAG_ERL 0x0002 /* Error mode */ | |
252 | -#define MIPS_HFLAG_EXL 0x0004 /* Exception mode */ | |
253 | 251 | #define MIPS_HFLAG_DM 0x0008 /* Debug mode */ |
254 | 252 | #define MIPS_HFLAG_SM 0x0010 /* Supervisor mode */ |
255 | 253 | #define MIPS_HFLAG_RE 0x0040 /* Reversed endianness */ | ... | ... |
target-mips/helper.c
... | ... | @@ -90,7 +90,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical, |
90 | 90 | if (user_mode && address > 0x7FFFFFFFUL) |
91 | 91 | return TLBRET_BADADDR; |
92 | 92 | if (address < (int32_t)0x80000000UL) { |
93 | - if (!(env->hflags & MIPS_HFLAG_ERL)) { | |
93 | + if (!(env->CP0_Status & (1 << CP0St_ERL))) { | |
94 | 94 | #ifdef MIPS_USES_R4K_TLB |
95 | 95 | ret = map_address(env, physical, prot, address, rw, access_type); |
96 | 96 | #else |
... | ... | @@ -289,21 +289,18 @@ void do_interrupt (CPUState *env) |
289 | 289 | goto set_DEPC; |
290 | 290 | case EXCP_DDBL: |
291 | 291 | env->CP0_Debug |= 1 << CP0DB_DDBL; |
292 | - goto set_DEPC; | |
293 | 292 | set_DEPC: |
294 | 293 | if (env->hflags & MIPS_HFLAG_BMASK) { |
295 | 294 | /* If the exception was raised from a delay slot, |
296 | 295 | come back to the jump. */ |
297 | 296 | env->CP0_DEPC = env->PC - 4; |
298 | - if (!(env->hflags & MIPS_HFLAG_EXL)) | |
299 | - env->CP0_Cause |= (1 << CP0Ca_BD); | |
300 | 297 | env->hflags &= ~MIPS_HFLAG_BMASK; |
301 | 298 | } else { |
302 | 299 | env->CP0_DEPC = env->PC; |
303 | - env->CP0_Cause &= ~(1 << CP0Ca_BD); | |
304 | 300 | } |
305 | 301 | enter_debug_mode: |
306 | 302 | env->hflags |= MIPS_HFLAG_DM; |
303 | + env->hflags &= ~MIPS_HFLAG_UM; | |
307 | 304 | /* EJTAG probe trap enable is not implemented... */ |
308 | 305 | env->PC = (int32_t)0xBFC00480; |
309 | 306 | break; |
... | ... | @@ -311,25 +308,22 @@ void do_interrupt (CPUState *env) |
311 | 308 | cpu_reset(env); |
312 | 309 | break; |
313 | 310 | case EXCP_SRESET: |
314 | - env->CP0_Status = (1 << CP0St_SR); | |
311 | + env->CP0_Status |= (1 << CP0St_SR); | |
315 | 312 | env->CP0_WatchLo = 0; |
316 | 313 | goto set_error_EPC; |
317 | 314 | case EXCP_NMI: |
318 | - env->CP0_Status = (1 << CP0St_NMI); | |
315 | + env->CP0_Status |= (1 << CP0St_NMI); | |
319 | 316 | set_error_EPC: |
320 | 317 | if (env->hflags & MIPS_HFLAG_BMASK) { |
321 | 318 | /* If the exception was raised from a delay slot, |
322 | 319 | come back to the jump. */ |
323 | 320 | env->CP0_ErrorEPC = env->PC - 4; |
324 | - if (!(env->hflags & MIPS_HFLAG_EXL)) | |
325 | - env->CP0_Cause |= (1 << CP0Ca_BD); | |
326 | 321 | env->hflags &= ~MIPS_HFLAG_BMASK; |
327 | 322 | } else { |
328 | 323 | env->CP0_ErrorEPC = env->PC; |
329 | - env->CP0_Cause &= ~(1 << CP0Ca_BD); | |
330 | 324 | } |
331 | - env->hflags |= MIPS_HFLAG_ERL; | |
332 | - env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); | |
325 | + env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); | |
326 | + env->hflags &= ~MIPS_HFLAG_UM; | |
333 | 327 | env->PC = (int32_t)0xBFC00000; |
334 | 328 | break; |
335 | 329 | case EXCP_MCHECK: |
... | ... | @@ -350,7 +344,7 @@ void do_interrupt (CPUState *env) |
350 | 344 | goto set_EPC; |
351 | 345 | case EXCP_TLBL: |
352 | 346 | cause = 2; |
353 | - if (env->error_code == 1 && !(env->hflags & MIPS_HFLAG_EXL)) | |
347 | + if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) | |
354 | 348 | offset = 0x000; |
355 | 349 | goto set_EPC; |
356 | 350 | case EXCP_IBE: |
... | ... | @@ -384,28 +378,29 @@ void do_interrupt (CPUState *env) |
384 | 378 | goto set_EPC; |
385 | 379 | case EXCP_TLBS: |
386 | 380 | cause = 3; |
387 | - if (env->error_code == 1 && !(env->hflags & MIPS_HFLAG_EXL)) | |
381 | + if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) | |
388 | 382 | offset = 0x000; |
389 | - goto set_EPC; | |
390 | 383 | set_EPC: |
391 | - if (env->hflags & MIPS_HFLAG_BMASK) { | |
392 | - /* If the exception was raised from a delay slot, | |
393 | - come back to the jump. */ | |
394 | - env->CP0_EPC = env->PC - 4; | |
395 | - if (!(env->hflags & MIPS_HFLAG_EXL)) | |
384 | + if (!(env->CP0_Status & (1 << CP0St_EXL))) { | |
385 | + if (env->hflags & MIPS_HFLAG_BMASK) { | |
386 | + /* If the exception was raised from a delay slot, | |
387 | + come back to the jump. */ | |
388 | + env->CP0_EPC = env->PC - 4; | |
396 | 389 | env->CP0_Cause |= (1 << CP0Ca_BD); |
397 | - env->hflags &= ~MIPS_HFLAG_BMASK; | |
390 | + env->hflags &= ~MIPS_HFLAG_BMASK; | |
391 | + } else { | |
392 | + env->CP0_EPC = env->PC; | |
393 | + env->CP0_Cause &= ~(1 << CP0Ca_BD); | |
394 | + } | |
398 | 395 | } else { |
399 | - env->CP0_EPC = env->PC; | |
400 | - env->CP0_Cause &= ~(1 << CP0Ca_BD); | |
396 | + env->CP0_Status |= (1 << CP0St_EXL); | |
397 | + env->hflags &= ~MIPS_HFLAG_UM; | |
401 | 398 | } |
402 | 399 | if (env->CP0_Status & (1 << CP0St_BEV)) { |
403 | 400 | env->PC = (int32_t)0xBFC00200; |
404 | 401 | } else { |
405 | 402 | env->PC = (int32_t)0x80000000; |
406 | 403 | } |
407 | - env->hflags |= MIPS_HFLAG_EXL; | |
408 | - env->CP0_Status |= (1 << CP0St_EXL); | |
409 | 404 | env->PC += offset; |
410 | 405 | env->CP0_Cause = (env->CP0_Cause & ~0x7C) | (cause << 2); |
411 | 406 | break; | ... | ... |
target-mips/op.c
... | ... | @@ -1105,12 +1105,6 @@ void op_mfc0_compare (void) |
1105 | 1105 | void op_mfc0_status (void) |
1106 | 1106 | { |
1107 | 1107 | T0 = env->CP0_Status; |
1108 | - if (env->hflags & MIPS_HFLAG_UM) | |
1109 | - T0 |= (1 << CP0St_UM); | |
1110 | - if (env->hflags & MIPS_HFLAG_ERL) | |
1111 | - T0 |= (1 << CP0St_ERL); | |
1112 | - if (env->hflags & MIPS_HFLAG_EXL) | |
1113 | - T0 |= (1 << CP0St_EXL); | |
1114 | 1108 | RETURN(); |
1115 | 1109 | } |
1116 | 1110 | |
... | ... | @@ -1365,20 +1359,10 @@ void op_mtc0_status (void) |
1365 | 1359 | { |
1366 | 1360 | uint32_t val, old; |
1367 | 1361 | |
1368 | - val = (int32_t)T0 & 0xFA78FF01; | |
1362 | + /* No 64bit FPU, no reverse endianness, no MDMX/DSP, no 64bit ops, | |
1363 | + no 64bit addressing implemented. */ | |
1364 | + val = (int32_t)T0 & 0xF878FF17; | |
1369 | 1365 | old = env->CP0_Status; |
1370 | - if (T0 & (1 << CP0St_UM)) | |
1371 | - env->hflags |= MIPS_HFLAG_UM; | |
1372 | - else | |
1373 | - env->hflags &= ~MIPS_HFLAG_UM; | |
1374 | - if (T0 & (1 << CP0St_ERL)) | |
1375 | - env->hflags |= MIPS_HFLAG_ERL; | |
1376 | - else | |
1377 | - env->hflags &= ~MIPS_HFLAG_ERL; | |
1378 | - if (T0 & (1 << CP0St_EXL)) | |
1379 | - env->hflags |= MIPS_HFLAG_EXL; | |
1380 | - else | |
1381 | - env->hflags &= ~MIPS_HFLAG_EXL; | |
1382 | 1366 | env->CP0_Status = val; |
1383 | 1367 | if (loglevel & CPU_LOG_TB_IN_ASM) |
1384 | 1368 | CALL_FROM_TB2(do_mtc0_status_debug, old, val); |
... | ... | @@ -1662,6 +1646,15 @@ void op_dmtc0_errorepc (void) |
1662 | 1646 | # define DEBUG_FPU_STATE() do { } while(0) |
1663 | 1647 | #endif |
1664 | 1648 | |
1649 | +void op_cp0_enabled(void) | |
1650 | +{ | |
1651 | + if (!(env->CP0_Status & (1 << CP0St_CU0)) && | |
1652 | + (env->hflags & MIPS_HFLAG_UM)) { | |
1653 | + CALL_FROM_TB2(do_raise_exception_direct_err, EXCP_CpU, 0); | |
1654 | + } | |
1655 | + RETURN(); | |
1656 | +} | |
1657 | + | |
1665 | 1658 | void op_cp1_enabled(void) |
1666 | 1659 | { |
1667 | 1660 | if (!(env->CP0_Status & (1 << CP0St_CU1))) { |
... | ... | @@ -2091,15 +2084,18 @@ void debug_eret (void); |
2091 | 2084 | void op_eret (void) |
2092 | 2085 | { |
2093 | 2086 | CALL_FROM_TB0(debug_eret); |
2094 | - if (env->hflags & MIPS_HFLAG_ERL) { | |
2087 | + if (env->CP0_Status & (1 << CP0St_ERL)) { | |
2095 | 2088 | env->PC = env->CP0_ErrorEPC; |
2096 | - env->hflags &= ~MIPS_HFLAG_ERL; | |
2097 | - env->CP0_Status &= ~(1 << CP0St_ERL); | |
2089 | + env->CP0_Status &= ~(1 << CP0St_ERL); | |
2098 | 2090 | } else { |
2099 | 2091 | env->PC = env->CP0_EPC; |
2100 | - env->hflags &= ~MIPS_HFLAG_EXL; | |
2101 | - env->CP0_Status &= ~(1 << CP0St_EXL); | |
2092 | + env->CP0_Status &= ~(1 << CP0St_EXL); | |
2102 | 2093 | } |
2094 | + if (!(env->CP0_Status & (1 << CP0St_EXL)) && | |
2095 | + !(env->CP0_Status & (1 << CP0St_ERL)) && | |
2096 | + !(env->hflags & MIPS_HFLAG_DM) && | |
2097 | + (env->CP0_Status & (1 << CP0St_UM))) | |
2098 | + env->hflags |= MIPS_HFLAG_UM; | |
2103 | 2099 | env->CP0_LLAddr = 1; |
2104 | 2100 | RETURN(); |
2105 | 2101 | } |
... | ... | @@ -2108,6 +2104,13 @@ void op_deret (void) |
2108 | 2104 | { |
2109 | 2105 | CALL_FROM_TB0(debug_eret); |
2110 | 2106 | env->PC = env->CP0_DEPC; |
2107 | + env->hflags |= MIPS_HFLAG_DM; | |
2108 | + if (!(env->CP0_Status & (1 << CP0St_EXL)) && | |
2109 | + !(env->CP0_Status & (1 << CP0St_ERL)) && | |
2110 | + !(env->hflags & MIPS_HFLAG_DM) && | |
2111 | + (env->CP0_Status & (1 << CP0St_UM))) | |
2112 | + env->hflags |= MIPS_HFLAG_UM; | |
2113 | + env->CP0_LLAddr = 1; | |
2111 | 2114 | RETURN(); |
2112 | 2115 | } |
2113 | 2116 | ... | ... |
target-mips/op_helper.c
... | ... | @@ -509,9 +509,11 @@ void dump_sc (void) |
509 | 509 | void debug_eret (void) |
510 | 510 | { |
511 | 511 | if (loglevel) { |
512 | - fprintf(logfile, "ERET: pc " TARGET_FMT_lx " EPC " TARGET_FMT_lx " ErrorEPC " TARGET_FMT_lx " (%d)\n", | |
513 | - env->PC, env->CP0_EPC, env->CP0_ErrorEPC, | |
514 | - env->hflags & MIPS_HFLAG_ERL ? 1 : 0); | |
512 | + fprintf(logfile, "ERET: pc " TARGET_FMT_lx " EPC " TARGET_FMT_lx, | |
513 | + env->PC, env->CP0_EPC); | |
514 | + if (env->CP0_Status & (1 << CP0St_ERL)) | |
515 | + fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC); | |
516 | + fputs("\n", logfile); | |
515 | 517 | } |
516 | 518 | } |
517 | 519 | ... | ... |
target-mips/translate.c
... | ... | @@ -4022,17 +4022,6 @@ static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd) |
4022 | 4022 | { |
4023 | 4023 | const char *opn = "unk"; |
4024 | 4024 | |
4025 | - if ((!ctx->CP0_Status & (1 << CP0St_CU0) && | |
4026 | - (ctx->hflags & MIPS_HFLAG_UM)) && | |
4027 | - !(ctx->hflags & MIPS_HFLAG_ERL) && | |
4028 | - !(ctx->hflags & MIPS_HFLAG_EXL)) { | |
4029 | - if (loglevel & CPU_LOG_TB_IN_ASM) { | |
4030 | - fprintf(logfile, "CP0 is not usable\n"); | |
4031 | - } | |
4032 | - generate_exception (ctx, EXCP_CpU); | |
4033 | - return; | |
4034 | - } | |
4035 | - | |
4036 | 4025 | switch (opc) { |
4037 | 4026 | case OPC_MFC0: |
4038 | 4027 | if (rt == 0) { |
... | ... | @@ -4809,7 +4798,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) |
4809 | 4798 | gen_trap(ctx, op1, rs, -1, imm); |
4810 | 4799 | break; |
4811 | 4800 | case OPC_SYNCI: |
4812 | - /* treat as noop */ | |
4801 | + /* treat as noop */ | |
4813 | 4802 | break; |
4814 | 4803 | default: /* Invalid */ |
4815 | 4804 | MIPS_INVAL("REGIMM"); |
... | ... | @@ -4818,6 +4807,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx) |
4818 | 4807 | } |
4819 | 4808 | break; |
4820 | 4809 | case OPC_CP0: |
4810 | + gen_op_cp0_enabled(); | |
4821 | 4811 | op1 = MASK_CP0(ctx->opcode); |
4822 | 4812 | switch (op1) { |
4823 | 4813 | case OPC_MFC0: |
... | ... | @@ -5258,12 +5248,6 @@ void cpu_dump_state (CPUState *env, FILE *f, |
5258 | 5248 | } |
5259 | 5249 | |
5260 | 5250 | c0_status = env->CP0_Status; |
5261 | - if (env->hflags & MIPS_HFLAG_UM) | |
5262 | - c0_status |= (1 << CP0St_UM); | |
5263 | - if (env->hflags & MIPS_HFLAG_ERL) | |
5264 | - c0_status |= (1 << CP0St_ERL); | |
5265 | - if (env->hflags & MIPS_HFLAG_EXL) | |
5266 | - c0_status |= (1 << CP0St_EXL); | |
5267 | 5251 | |
5268 | 5252 | cpu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x" TARGET_FMT_lx "\n", |
5269 | 5253 | c0_status, env->CP0_Cause, env->CP0_EPC); |
... | ... | @@ -5304,6 +5288,7 @@ void cpu_reset (CPUMIPSState *env) |
5304 | 5288 | } else { |
5305 | 5289 | env->CP0_ErrorEPC = env->PC; |
5306 | 5290 | } |
5291 | + env->hflags = 0; | |
5307 | 5292 | env->PC = (int32_t)0xBFC00000; |
5308 | 5293 | #if defined (MIPS_USES_R4K_TLB) |
5309 | 5294 | env->CP0_Random = MIPS_TLB_NB - 1; |
... | ... | @@ -5314,7 +5299,6 @@ void cpu_reset (CPUMIPSState *env) |
5314 | 5299 | env->CP0_EBase = 0x80000000; |
5315 | 5300 | env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL); |
5316 | 5301 | env->CP0_WatchLo = 0; |
5317 | - env->hflags = MIPS_HFLAG_ERL; | |
5318 | 5302 | /* Count register increments in debug mode, EJTAG version 1 */ |
5319 | 5303 | env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER); |
5320 | 5304 | #endif | ... | ... |