diff options
author | YuYeon Oh <yuyeon.oh@samsung.com> | 2011-04-25 01:23:58 +0000 |
---|---|---|
committer | Aurelien Jarno <aurelien@aurel32.net> | 2011-04-27 20:13:26 +0200 |
commit | 5856d44eb592e05bb266fb2c7db42926faa22144 (patch) | |
tree | 2631cdfad2f3c606bd13cdaf761a5c081b5179d7 /target-arm/translate.c | |
parent | 47f7be394aa7baf7855fe78f56b8ba4c69bf75d9 (diff) |
target-arm: fix LDMIA bug on page boundary
target-arm: fix LDMIA bug on page boundary
When consecutive memory locations are on page boundary, a base register may be
loaded before page fault occurs. After page fault handling, it losts the memory
location information. To solve this problem, loading a base register has to put back.
Signed-off-by: Yuyeon Oh <yuyeon.oh@samsung.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Diffstat (limited to 'target-arm/translate.c')
-rw-r--r-- | target-arm/translate.c | 10 |
1 files changed, 9 insertions, 1 deletions
diff --git a/target-arm/translate.c b/target-arm/translate.c index 8b309d48b8..d8da514599 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -8016,7 +8016,8 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1) } } } else { - int i; + int i, loaded_base = 0; + TCGv loaded_var; /* Load/store multiple. */ addr = load_reg(s, rn); offset = 0; @@ -8028,6 +8029,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1) tcg_gen_addi_i32(addr, addr, -offset); } + TCGV_UNUSED(loaded_var); for (i = 0; i < 16; i++) { if ((insn & (1 << i)) == 0) continue; @@ -8036,6 +8038,9 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1) tmp = gen_ld32(addr, IS_USER(s)); if (i == 15) { gen_bx(s, tmp); + } else if (i == rn) { + loaded_var = tmp; + loaded_base = 1; } else { store_reg(s, i, tmp); } @@ -8046,6 +8051,9 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1) } tcg_gen_addi_i32(addr, addr, 4); } + if (loaded_base) { + store_reg(s, rn, loaded_var); + } if (insn & (1 << 21)) { /* Base register writeback. */ if (insn & (1 << 24)) { |