target/arm: Convert MRS/MSR (banked, register)

The m-profile and a-profile decodings overlap. Only return false
for the case of wrong profile; handle UNDEFINED for permission failure
directly. This ensures that we don't accidentally pass an insn that
applies to the wrong profile.

Backports commit d0b26644502103ca97093ef67749812dc1df7eea from qemu
This commit is contained in:
Richard Henderson 2019-11-19 19:59:58 -05:00 committed by Lioncash
parent 571d879c49
commit fdd135c7d2
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
3 changed files with 145 additions and 138 deletions

View file

@ -29,6 +29,10 @@
&s_rrrr s rd rn rm ra
&rrrr rd rn rm ra
&rrr rd rn rm
&msr_reg rn r mask
&mrs_reg rd r
&msr_bank rn r sysm
&mrs_bank rd r sysm
# Data-processing (register)
@ -177,3 +181,13 @@ SMULTT .... 0001 0110 .... 0000 .... 1110 .... @rd0mn
MSR_imm .... 0011 0010 .... 1111 .... .... .... @msr_i r=0
}
MSR_imm .... 0011 0110 .... 1111 .... .... .... @msr_i r=1
# Miscellaneous instructions
%sysm 8:1 16:4
MRS_bank ---- 0001 0 r:1 00 .... rd:4 001. 0000 0000 &mrs_bank %sysm
MSR_bank ---- 0001 0 r:1 10 .... 1111 001. 0000 rn:4 &msr_bank %sysm
MRS_reg ---- 0001 0 r:1 00 1111 rd:4 0000 0000 0000 &mrs_reg
MSR_reg ---- 0001 0 r:1 10 mask:4 1111 0000 0000 rn:4 &msr_reg

View file

@ -26,6 +26,10 @@
&s_rrrr !extern s rd rn rm ra
&rrrr !extern rd rn rm ra
&rrr !extern rd rn rm
&msr_reg !extern rn r mask
&mrs_reg !extern rd r
&msr_bank !extern rn r sysm
&mrs_bank !extern rd r sysm
# Data-processing (register)
@ -170,6 +174,10 @@ QDSUB 1111 1010 1000 .... 1111 .... 1011 .... @rndm
# Branches and miscellaneous control
%msr_sysm 4:1 8:4
%mrs_sysm 4:1 16:4
{
{
YIELD 1111 0011 1010 1111 1000 0000 0000 0001
WFE 1111 0011 1010 1111 1000 0000 0000 0010
@ -183,3 +191,17 @@ QDSUB 1111 1010 1000 .... 1111 .... 1011 .... @rndm
# of the space is "reserved hint, behaves as nop".
NOP 1111 0011 1010 1111 1000 0000 ---- ----
}
# Note that the v7m insn overlaps both the normal and banked insn.
{
MRS_bank 1111 0011 111 r:1 .... 1000 rd:4 001. 0000 \
&mrs_bank sysm=%mrs_sysm
MRS_reg 1111 0011 111 r:1 1111 1000 rd:4 0000 0000 &mrs_reg
MRS_v7m 1111 0011 111 0 1111 1000 rd:4 sysm:8
}
{
MSR_bank 1111 0011 100 r:1 rn:4 1000 .... 001. 0000 \
&msr_bank sysm=%msr_sysm
MSR_reg 1111 0011 100 r:1 rn:4 1000 mask:4 0000 0000 &msr_reg
MSR_v7m 1111 0011 100 0 rn:4 1000 mask:2 00 sysm:8
}
}

View file

@ -8542,6 +8542,96 @@ static bool trans_MSR_imm(DisasContext *s, arg_MSR_imm *a)
return true;
}
/*
* Miscellaneous instructions
*/
static bool trans_MRS_bank(DisasContext *s, arg_MRS_bank *a)
{
if (arm_dc_feature(s, ARM_FEATURE_M)) {
return false;
}
gen_mrs_banked(s, a->r, a->sysm, a->rd);
return true;
}
static bool trans_MSR_bank(DisasContext *s, arg_MSR_bank *a)
{
if (arm_dc_feature(s, ARM_FEATURE_M)) {
return false;
}
gen_msr_banked(s, a->r, a->sysm, a->rn);
return true;
}
static bool trans_MRS_reg(DisasContext *s, arg_MRS_reg *a)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
TCGv_i32 tmp;
if (arm_dc_feature(s, ARM_FEATURE_M)) {
return false;
}
if (a->r) {
if (IS_USER(s)) {
unallocated_encoding(s);
return true;
}
tmp = load_cpu_field(s, spsr);
} else {
tmp = tcg_temp_new_i32(tcg_ctx);
gen_helper_cpsr_read(tcg_ctx, tmp, tcg_ctx->cpu_env);
}
store_reg(s, a->rd, tmp);
return true;
}
static bool trans_MSR_reg(DisasContext *s, arg_MSR_reg *a)
{
TCGv_i32 tmp;
uint32_t mask = msr_mask(s, a->mask, a->r);
if (arm_dc_feature(s, ARM_FEATURE_M)) {
return false;
}
tmp = load_reg(s, a->rn);
if (gen_set_psr(s, mask, a->r, tmp)) {
unallocated_encoding(s);
}
return true;
}
static bool trans_MRS_v7m(DisasContext *s, arg_MRS_v7m *a)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
TCGv_i32 tmp;
if (!arm_dc_feature(s, ARM_FEATURE_M)) {
return false;
}
tmp = tcg_const_i32(tcg_ctx, a->sysm);
gen_helper_v7m_mrs(tcg_ctx, tmp, tcg_ctx->cpu_env, tmp);
store_reg(s, a->rd, tmp);
return true;
}
static bool trans_MSR_v7m(DisasContext *s, arg_MSR_v7m *a)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
TCGv_i32 addr, reg;
if (!arm_dc_feature(s, ARM_FEATURE_M)) {
return false;
}
addr = tcg_const_i32(tcg_ctx, (a->mask << 10) | a->sysm);
reg = load_reg(s, a->rn);
gen_helper_v7m_msr(tcg_ctx, tcg_ctx->cpu_env, addr, reg);
tcg_temp_free_i32(tcg_ctx, addr);
tcg_temp_free_i32(tcg_ctx, reg);
gen_lookup_tb(s);
return true;
}
/*
* Legacy decoder.
*/
@ -8835,46 +8925,10 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
sh = (insn >> 4) & 0xf;
rm = insn & 0xf;
switch (sh) {
case 0x0: /* MSR, MRS */
if (insn & (1 << 9)) {
/* MSR (banked) and MRS (banked) */
int sysm = extract32(insn, 16, 4) |
(extract32(insn, 8, 1) << 4);
int r = extract32(insn, 22, 1);
if (op1 & 1) {
/* MSR (banked) */
gen_msr_banked(s, r, sysm, rm);
} else {
/* MRS (banked) */
int rd = extract32(insn, 12, 4);
gen_mrs_banked(s, r, sysm, rd);
}
break;
}
/* MSR, MRS (for PSRs) */
if (op1 & 1) {
/* PSR = reg */
tmp = load_reg(s, rm);
i = ((op1 & 2) != 0);
if (gen_set_psr(s, msr_mask(s, (insn >> 16) & 0xf, i), i, tmp))
goto illegal_op;
} else {
/* reg = PSR */
rd = (insn >> 12) & 0xf;
if (op1 & 2) {
if (IS_USER(s))
goto illegal_op;
tmp = load_cpu_field(s, spsr);
} else {
tmp = tcg_temp_new_i32(tcg_ctx);
gen_helper_cpsr_read(tcg_ctx, tmp, tcg_ctx->cpu_env);
}
store_reg(s, rd, tmp);
}
break;
case 0x0:
/* MSR/MRS (banked/register) */
/* All done in decodetree. Illegal ops already signalled. */
g_assert_not_reached();
case 0x1:
if (op1 == 1) {
/* branch/exchange thumb (bx). */
@ -10742,40 +10796,9 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
} else {
op = (insn >> 20) & 7;
switch (op) {
case 0: /* msr cpsr. */
if (arm_dc_feature(s, ARM_FEATURE_M)) {
tmp = load_reg(s, rn);
/* the constant is the mask and SYSm fields */
addr = tcg_const_i32(tcg_ctx, insn & 0xfff);
gen_helper_v7m_msr(tcg_ctx, tcg_ctx->cpu_env, addr, tmp);
tcg_temp_free_i32(tcg_ctx, addr);
tcg_temp_free_i32(tcg_ctx, tmp);
gen_lookup_tb(s);
break;
}
/* fall through */
case 1: /* msr spsr. */
if (arm_dc_feature(s, ARM_FEATURE_M)) {
case 0: /* msr cpsr, in decodetree */
case 1: /* msr spsr, in decodetree */
goto illegal_op;
}
if (extract32(insn, 5, 1)) {
/* MSR (banked) */
int sysm = extract32(insn, 8, 4) |
(extract32(insn, 4, 1) << 4);
int r = op & 1;
gen_msr_banked(s, r, sysm, rm);
break;
}
/* MSR (for PSRs) */
tmp = load_reg(s, rn);
if (gen_set_psr(s,
msr_mask(s, (insn >> 8) & 0xf, op == 1),
op == 1, tmp))
goto illegal_op;
break;
case 2: /* cps, nop-hint. */
/* nop hints in decodetree */
/* Implemented as NOP in user mode. */
@ -10867,62 +10890,10 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
}
gen_exception_return(s, tmp);
break;
case 6: /* MRS */
if (extract32(insn, 5, 1) &&
!arm_dc_feature(s, ARM_FEATURE_M)) {
/* MRS (banked) */
int sysm = extract32(insn, 16, 4) |
(extract32(insn, 4, 1) << 4);
gen_mrs_banked(s, 0, sysm, rd);
break;
}
if (extract32(insn, 16, 4) != 0xf) {
case 6: /* MRS, in decodetree */
case 7: /* MSR, in decodetree */
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(tcg_ctx);
if (arm_dc_feature(s, ARM_FEATURE_M)) {
addr = tcg_const_i32(tcg_ctx, insn & 0xff);
gen_helper_v7m_mrs(tcg_ctx, tmp, tcg_ctx->cpu_env, addr);
tcg_temp_free_i32(tcg_ctx, addr);
} else {
gen_helper_cpsr_read(tcg_ctx, tmp, tcg_ctx->cpu_env);
}
store_reg(s, rd, tmp);
break;
case 7: /* MRS */
if (extract32(insn, 5, 1) &&
!arm_dc_feature(s, ARM_FEATURE_M)) {
/* MRS (banked) */
int sysm = extract32(insn, 16, 4) |
(extract32(insn, 4, 1) << 4);
gen_mrs_banked(s, 1, sysm, rd);
break;
}
/* mrs spsr. */
/* Not accessible in user mode. */
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(s, spsr);
store_reg(s, rd, tmp);
break;
}
}
} else {
/* Conditional branch. */