diff options
author | Edgar E. Iglesias <edgar.iglesias@gmail.com> | 2009-09-11 10:35:27 +0200 |
---|---|---|
committer | Edgar E. Iglesias <edgar.iglesias@gmail.com> | 2009-09-11 10:35:27 +0200 |
commit | a12f65078105d5f280b39ddb72a6ebdfa3b2164c (patch) | |
tree | 634724790d06bb2a748dbecd4f3de8fdfe6a873a /target-microblaze | |
parent | 97f90cbfe810bb153fc44bde732d9639610783bb (diff) | |
download | qemu-a12f65078105d5f280b39ddb72a6ebdfa3b2164c.zip qemu-a12f65078105d5f280b39ddb72a6ebdfa3b2164c.tar.gz qemu-a12f65078105d5f280b39ddb72a6ebdfa3b2164c.tar.bz2 |
microblaze: Correct prio between MMU and unaligned exceptions.
The microblaze gives MMU faults priority. For stores we still
have a flaw that the value leaks to memory in the case of an
unaligned exception.
Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Diffstat (limited to 'target-microblaze')
-rw-r--r-- | target-microblaze/translate.c | 31 |
1 files changed, 25 insertions, 6 deletions
diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c index 79f1216..37d250f 100644 --- a/target-microblaze/translate.c +++ b/target-microblaze/translate.c @@ -819,14 +819,28 @@ static void dec_load(DisasContext *dc) /* Verify alignment if needed. */ if ((dc->env->pvr.regs[2] & PVR2_UNALIGNED_EXC_MASK) && size > 1) { + TCGv v = tcg_temp_new(); + + /* + * Microblaze gives MMU faults priority over faults due to + * unaligned addresses. That's why we speculatively do the load + * into v. If the load succeeds, we verify alignment of the + * address and if that succeeds we write into the destination reg. + */ + gen_load(dc, v, *addr, size); + + tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc); gen_helper_memalign(*addr, tcg_const_tl(dc->rd), tcg_const_tl(0), tcg_const_tl(size - 1)); - } - - if (dc->rd) { - gen_load(dc, cpu_R[dc->rd], *addr, size); + if (dc->rd) + tcg_gen_mov_tl(cpu_R[dc->rd], v); + tcg_temp_free(v); } else { - gen_load(dc, env_imm, *addr, size); + if (dc->rd) { + gen_load(dc, cpu_R[dc->rd], *addr, size); + } else { + gen_load(dc, env_imm, *addr, size); + } } if (addr == &t) @@ -868,13 +882,18 @@ static void dec_store(DisasContext *dc) sync_jmpstate(dc); addr = compute_ldst_addr(dc, &t); + gen_store(dc, *addr, cpu_R[dc->rd], size); + /* Verify alignment if needed. */ if ((dc->env->pvr.regs[2] & PVR2_UNALIGNED_EXC_MASK) && size > 1) { + tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc); + /* FIXME: if the alignment is wrong, we should restore the value + * in memory. + */ gen_helper_memalign(*addr, tcg_const_tl(dc->rd), tcg_const_tl(1), tcg_const_tl(size - 1)); } - gen_store(dc, *addr, cpu_R[dc->rd], size); if (addr == &t) tcg_temp_free(t); } |