summaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2017-03-20 12:41:44 +0000
committerPeter Maydell <peter.maydell@linaro.org>2017-03-20 12:41:44 +0000
commit3d54026fb06d1aea7ebb4e9825970b06bebcacac (patch)
tree453529a1eaca7dd91ae1fd6a2936c0eb16c5c33d /target
parent43ac65742319ef5ac4461daf43316b189cd21e89 (diff)
downloadqemu-3d54026fb06d1aea7ebb4e9825970b06bebcacac.zip
arm: Enforce should-be-1 bits in MRS decoding
The MRS instruction requires that bits [19..16] are all 1s, and for A/R profile also that bits [7..0] are all 0s. At this point in the decode tree we have checked all of the rest of the instruction but were allowing these to be any value. If these bits are not set then the result is architecturally UNPREDICTABLE, but choosing to UNDEF is more helpful to the user and avoids unexpected odd behaviour if the encodings are used for some purpose in future architecture versions. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 1487616072-9226-4-git-send-email-peter.maydell@linaro.org
Diffstat (limited to 'target')
-rw-r--r--target/arm/translate.c14
1 files changed, 14 insertions, 0 deletions
diff --git a/target/arm/translate.c b/target/arm/translate.c
index a5f5a28ba4..c4acff5f99 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -10510,6 +10510,14 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
break;
}
+ if (extract32(insn, 16, 4) != 0xf) {
+ goto illegal_op;
+ }
+ if (!arm_dc_feature(s, ARM_FEATURE_M) &&
+ extract32(insn, 0, 8) != 0) {
+ goto illegal_op;
+ }
+
/* mrs cpsr */
tmp = tcg_temp_new_i32();
if (arm_dc_feature(s, ARM_FEATURE_M)) {
@@ -10537,6 +10545,12 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
if (IS_USER(s) || arm_dc_feature(s, ARM_FEATURE_M)) {
goto illegal_op;
}
+
+ if (extract32(insn, 16, 4) != 0xf ||
+ extract32(insn, 0, 8) != 0) {
+ goto illegal_op;
+ }
+
tmp = load_cpu_field(spsr);
store_reg(s, rd, tmp);
break;