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 | ... | ... |