summaryrefslogtreecommitdiff
path: root/target-arm
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2014-02-20 10:35:55 +0000
committerPeter Maydell <peter.maydell@linaro.org>2014-02-20 10:35:55 +0000
commitd324b36ad93b84509aeee41f05ee17a6c5de7826 (patch)
tree36aa45030eee629f92efa7a05e3bf1d7ac5e00ab /target-arm
parent7900e9f1f963184967594f4518c97ea682a9605f (diff)
downloadqemu-d324b36ad93b84509aeee41f05ee17a6c5de7826.tar.gz
target-arm: A64: Implement store-exclusive for system mode
System mode store-exclusive use a different code path to usermode ones; implement this missing code, in a similar way to the 32 bit version. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <rth@twiddle.net>
Diffstat (limited to 'target-arm')
-rw-r--r--target-arm/translate-a64.c68
1 files changed, 62 insertions, 6 deletions
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index ef305e3fa2..3de9cad367 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -1487,12 +1487,68 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
}
#else
static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
- TCGv_i64 addr, int size, int is_pair)
-{
- qemu_log_mask(LOG_UNIMP,
- "%s:%d: system mode store_exclusive unsupported "
- "at pc=%016" PRIx64 "\n",
- __FILE__, __LINE__, s->pc - 4);
+ TCGv_i64 inaddr, int size, int is_pair)
+{
+ /* if (env->exclusive_addr == addr && env->exclusive_val == [addr]
+ * && (!is_pair || env->exclusive_high == [addr + datasize])) {
+ * [addr] = {Rt};
+ * if (is_pair) {
+ * [addr + datasize] = {Rt2};
+ * }
+ * {Rd} = 0;
+ * } else {
+ * {Rd} = 1;
+ * }
+ * env->exclusive_addr = -1;
+ */
+ int fail_label = gen_new_label();
+ int done_label = gen_new_label();
+ TCGv_i64 addr = tcg_temp_local_new_i64();
+ TCGv_i64 tmp;
+
+ /* Copy input into a local temp so it is not trashed when the
+ * basic block ends at the branch insn.
+ */
+ tcg_gen_mov_i64(addr, inaddr);
+ tcg_gen_brcond_i64(TCG_COND_NE, addr, cpu_exclusive_addr, fail_label);
+
+ tmp = tcg_temp_new_i64();
+ tcg_gen_qemu_ld_i64(tmp, addr, get_mem_index(s), MO_TE + size);
+ tcg_gen_brcond_i64(TCG_COND_NE, tmp, cpu_exclusive_val, fail_label);
+ tcg_temp_free_i64(tmp);
+
+ if (is_pair) {
+ TCGv_i64 addrhi = tcg_temp_new_i64();
+ TCGv_i64 tmphi = tcg_temp_new_i64();
+
+ tcg_gen_addi_i64(addrhi, addr, 1 << size);
+ tcg_gen_qemu_ld_i64(tmphi, addrhi, get_mem_index(s), MO_TE + size);
+ tcg_gen_brcond_i64(TCG_COND_NE, tmphi, cpu_exclusive_high, fail_label);
+
+ tcg_temp_free_i64(tmphi);
+ tcg_temp_free_i64(addrhi);
+ }
+
+ /* We seem to still have the exclusive monitor, so do the store */
+ tcg_gen_qemu_st_i64(cpu_reg(s, rt), addr, get_mem_index(s), MO_TE + size);
+ if (is_pair) {
+ TCGv_i64 addrhi = tcg_temp_new_i64();
+
+ tcg_gen_addi_i64(addrhi, addr, 1 << size);
+ tcg_gen_qemu_st_i64(cpu_reg(s, rt2), addrhi,
+ get_mem_index(s), MO_TE + size);
+ tcg_temp_free_i64(addrhi);
+ }
+
+ tcg_temp_free_i64(addr);
+
+ tcg_gen_movi_i64(cpu_reg(s, rd), 0);
+ tcg_gen_br(done_label);
+ gen_set_label(fail_label);
+ tcg_gen_movi_i64(cpu_reg(s, rd), 1);
+ gen_set_label(done_label);
+ tcg_gen_movi_i64(cpu_exclusive_addr, -1);
+
}
#endif