Commit 358bf29e802e7f03d32dd4ba2064e1bba23a11fa

Authored by pbrook
1 parent cdbdb648

Thumb prefetch abort fix.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1805 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 38 additions and 2 deletions
target-arm/translate.c
@@ -2295,8 +2295,21 @@ static void disas_thumb_insn(DisasContext *s) @@ -2295,8 +2295,21 @@ static void disas_thumb_insn(DisasContext *s)
2295 2295
2296 case 14: 2296 case 14:
2297 /* unconditional branch */ 2297 /* unconditional branch */
2298 - if (insn & (1 << 11))  
2299 - goto undef; /* Second half of a blx */ 2298 + if (insn & (1 << 11)) {
  2299 + /* Second half of blx. */
  2300 + offset = ((insn & 0x7ff) << 1);
  2301 + gen_movl_T0_reg(s, 14);
  2302 + gen_op_movl_T1_im(offset);
  2303 + gen_op_addl_T0_T1();
  2304 + gen_op_movl_T1_im(0xfffffffc);
  2305 + gen_op_andl_T0_T1();
  2306 +
  2307 + val = (uint32_t)s->pc;
  2308 + gen_op_movl_T1_im(val | 1);
  2309 + gen_movl_reg_T1(s, 14);
  2310 + gen_bx(s);
  2311 + break;
  2312 + }
2300 val = (uint32_t)s->pc; 2313 val = (uint32_t)s->pc;
2301 offset = ((int32_t)insn << 21) >> 21; 2314 offset = ((int32_t)insn << 21) >> 21;
2302 val += (offset << 1) + 2; 2315 val += (offset << 1) + 2;
@@ -2305,6 +2318,29 @@ static void disas_thumb_insn(DisasContext *s) @@ -2305,6 +2318,29 @@ static void disas_thumb_insn(DisasContext *s)
2305 2318
2306 case 15: 2319 case 15:
2307 /* branch and link [and switch to arm] */ 2320 /* branch and link [and switch to arm] */
  2321 + if ((s->pc & ~TARGET_PAGE_MASK) == 0) {
  2322 + /* Instruction spans a page boundary. Implement it as two
  2323 + 16-bit instructions in case the second half causes an
  2324 + prefetch abort. */
  2325 + offset = ((int32_t)insn << 21) >> 9;
  2326 + val = s->pc + 2 + offset;
  2327 + gen_op_movl_T0_im(val);
  2328 + gen_movl_reg_T0(s, 14);
  2329 + break;
  2330 + }
  2331 + if (insn & (1 << 11)) {
  2332 + /* Second half of bl. */
  2333 + offset = ((insn & 0x7ff) << 1) | 1;
  2334 + gen_movl_T0_reg(s, 14);
  2335 + gen_op_movl_T1_im(offset);
  2336 + gen_op_addl_T0_T1();
  2337 +
  2338 + val = (uint32_t)s->pc;
  2339 + gen_op_movl_T1_im(val | 1);
  2340 + gen_movl_reg_T1(s, 14);
  2341 + gen_bx(s);
  2342 + break;
  2343 + }
2308 offset = ((int32_t)insn << 21) >> 10; 2344 offset = ((int32_t)insn << 21) >> 10;
2309 insn = lduw_code(s->pc); 2345 insn = lduw_code(s->pc);
2310 offset |= insn & 0x7ff; 2346 offset |= insn & 0x7ff;