Commit d0b26644 authored by Richard Henderson's avatar Richard Henderson Committed by Peter Maydell
Browse files

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.

Reviewed-by: default avatarPeter Maydell <peter.maydell@linaro.org>
Signed-off-by: default avatarRichard Henderson <richard.henderson@linaro.org>
Message-id: 20190904193059.26202-14-richard.henderson@linaro.org
Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parent 63130596
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -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
+34 −12
Original line number Diff line number Diff line
@@ -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
  }
}
+97 −129
Original line number Diff line number Diff line
@@ -8320,6 +8320,93 @@ 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)
{
    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(spsr);
    } else {
        tmp = tcg_temp_new_i32();
        gen_helper_cpsr_read(tmp, 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)
{
    TCGv_i32 tmp;

    if (!arm_dc_feature(s, ARM_FEATURE_M)) {
        return false;
    }
    tmp = tcg_const_i32(a->sysm);
    gen_helper_v7m_mrs(tmp, cpu_env, tmp);
    store_reg(s, a->rd, tmp);
    return true;
}

static bool trans_MSR_v7m(DisasContext *s, arg_MSR_v7m *a)
{
    TCGv_i32 addr, reg;

    if (!arm_dc_feature(s, ARM_FEATURE_M)) {
        return false;
    }
    addr = tcg_const_i32((a->mask << 10) | a->sysm);
    reg = load_reg(s, a->rn);
    gen_helper_v7m_msr(cpu_env, addr, reg);
    tcg_temp_free_i32(addr);
    tcg_temp_free_i32(reg);
    gen_lookup_tb(s);
    return true;
}

/*
 * Legacy decoder.
 */
@@ -8604,46 +8691,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(spsr);
                } else {
                    tmp = tcg_temp_new_i32();
                    gen_helper_cpsr_read(tmp, 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).  */
@@ -10513,40 +10564,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(insn & 0xfff);
                            gen_helper_v7m_msr(cpu_env, addr, tmp);
                            tcg_temp_free_i32(addr);
                            tcg_temp_free_i32(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.  */
@@ -10638,62 +10658,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) {
                            goto illegal_op;
                        }
                        if (!arm_dc_feature(s, ARM_FEATURE_M) &&
                            extract32(insn, 0, 8) != 0) {
                    case 6: /* MRS, in decodetree */
                    case 7: /* MSR, in decodetree */
                        goto illegal_op;
                    }

                        /* mrs cpsr */
                        tmp = tcg_temp_new_i32();
                        if (arm_dc_feature(s, ARM_FEATURE_M)) {
                            addr = tcg_const_i32(insn & 0xff);
                            gen_helper_v7m_mrs(tmp, cpu_env, addr);
                            tcg_temp_free_i32(addr);
                        } else {
                            gen_helper_cpsr_read(tmp, 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(spsr);
                        store_reg(s, rd, tmp);
                        break;
                    }
                }
            } else {
                /* Conditional branch.  */