From f48d1fe391c83d436fcb6bea4f9da86a067aae88 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 26 Feb 2018 05:02:23 -0500 Subject: [PATCH] target-arm: Correctly handle 'sub pc, pc, 1' for ARMv6 In the ARM v6 architecture, 'sub pc, pc, 1' is not an interworking branch, so the computed new value is written to r15 as a normal value. The architecture says that in this case, bits [1:0] of the value written must be ignored if we are in ARM mode (or bit [0] ignored if in Thumb mode); this is a change from the ARMv4/v5 specification that behaviour is UNPREDICTABLE. Use the correct mask on the PC value when doing a non-interworking store to PC. A popular library used on RaspberryPi uses this instruction as part of a trick to determine whether it is running on ARMv6 or ARMv7, and we were mishandling the sequence. Fixes bug: https://bugs.launchpad.net/bugs/1625295 Backports commit 9b6a3ea7a699594162ed3d11e4e04b98568dc5c0 from qemu --- qemu/target-arm/translate.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/qemu/target-arm/translate.c b/qemu/target-arm/translate.c index 38bda859..b1c0f0b9 100644 --- a/qemu/target-arm/translate.c +++ b/qemu/target-arm/translate.c @@ -172,7 +172,12 @@ static void store_reg(DisasContext *s, int reg, TCGv_i32 var) { TCGContext *tcg_ctx = s->uc->tcg_ctx; if (reg == 15) { - tcg_gen_andi_i32(tcg_ctx, var, var, ~1); + /* In Thumb mode, we must ignore bit 0. + * In ARM mode, for ARMv4 and ARMv5, it is UNPREDICTABLE if bits [1:0] + * are not 0b00, but for ARMv6 and above, we must ignore bits [1:0]. + * We choose to ignore [1:0] in ARM mode for all architecture versions. + */ + tcg_gen_andi_i32(tcg_ctx, var, var, s->thumb ? ~1 : ~3); s->is_jmp = DISAS_JUMP; } tcg_gen_mov_i32(tcg_ctx, tcg_ctx->cpu_R[reg], var);