Commit 24c7b0e330fdbfcfe87f515d79e67156c57cbc4f

Authored by ths
1 parent e69f67b6

Sanitize mips exception handling.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2546 c046a42c-6fe2-441c-8c8c-71466251a162
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
... ... @@ -80,6 +80,7 @@ typedef void * host_reg_t;
80 80  
81 81 typedef struct FILE FILE;
82 82 extern int fprintf(FILE *, const char *, ...);
  83 +extern int fputs(const char *, FILE *);
83 84 extern int printf(const char *, ...);
84 85 #undef NULL
85 86 #define NULL 0
... ...
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
... ...