cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

fixedpoint-impl.c.inc (10161B)


      1/*
      2 * Power ISA decode for Fixed-Point Facility instructions
      3 *
      4 * Copyright (c) 2021 Instituto de Pesquisas Eldorado (eldorado.org.br)
      5 *
      6 * This library is free software; you can redistribute it and/or
      7 * modify it under the terms of the GNU Lesser General Public
      8 * License as published by the Free Software Foundation; either
      9 * version 2.1 of the License, or (at your option) any later version.
     10 *
     11 * This library is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14 * Lesser General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU Lesser General Public
     17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
     18 */
     19
     20/*
     21 * Incorporate CIA into the constant when R=1.
     22 * Validate that when R=1, RA=0.
     23 */
     24static bool resolve_PLS_D(DisasContext *ctx, arg_D *d, arg_PLS_D *a)
     25{
     26    d->rt = a->rt;
     27    d->ra = a->ra;
     28    d->si = a->si;
     29    if (a->r) {
     30        if (unlikely(a->ra != 0)) {
     31            gen_invalid(ctx);
     32            return false;
     33        }
     34        d->si += ctx->cia;
     35    }
     36    return true;
     37}
     38
     39/*
     40 * Fixed-Point Load/Store Instructions
     41 */
     42
     43static bool do_ldst(DisasContext *ctx, int rt, int ra, TCGv displ, bool update,
     44                    bool store, MemOp mop)
     45{
     46    TCGv ea;
     47
     48    if (update && (ra == 0 || (!store && ra == rt))) {
     49        gen_invalid(ctx);
     50        return true;
     51    }
     52    gen_set_access_type(ctx, ACCESS_INT);
     53
     54    ea = tcg_temp_new();
     55    if (ra) {
     56        tcg_gen_add_tl(ea, cpu_gpr[ra], displ);
     57    } else {
     58        tcg_gen_mov_tl(ea, displ);
     59    }
     60    if (NARROW_MODE(ctx)) {
     61        tcg_gen_ext32u_tl(ea, ea);
     62    }
     63    mop ^= ctx->default_tcg_memop_mask;
     64    if (store) {
     65        tcg_gen_qemu_st_tl(cpu_gpr[rt], ea, ctx->mem_idx, mop);
     66    } else {
     67        tcg_gen_qemu_ld_tl(cpu_gpr[rt], ea, ctx->mem_idx, mop);
     68    }
     69    if (update) {
     70        tcg_gen_mov_tl(cpu_gpr[ra], ea);
     71    }
     72    tcg_temp_free(ea);
     73
     74    return true;
     75}
     76
     77static bool do_ldst_D(DisasContext *ctx, arg_D *a, bool update, bool store,
     78                      MemOp mop)
     79{
     80    return do_ldst(ctx, a->rt, a->ra, tcg_constant_tl(a->si), update, store, mop);
     81}
     82
     83static bool do_ldst_PLS_D(DisasContext *ctx, arg_PLS_D *a, bool update,
     84                          bool store, MemOp mop)
     85{
     86    arg_D d;
     87    if (!resolve_PLS_D(ctx, &d, a)) {
     88        return true;
     89    }
     90    return do_ldst_D(ctx, &d, update, store, mop);
     91}
     92
     93static bool do_ldst_X(DisasContext *ctx, arg_X *a, bool update,
     94                      bool store, MemOp mop)
     95{
     96    return do_ldst(ctx, a->rt, a->ra, cpu_gpr[a->rb], update, store, mop);
     97}
     98
     99/* Load Byte and Zero */
    100TRANS(LBZ, do_ldst_D, false, false, MO_UB)
    101TRANS(LBZX, do_ldst_X, false, false, MO_UB)
    102TRANS(LBZU, do_ldst_D, true, false, MO_UB)
    103TRANS(LBZUX, do_ldst_X, true, false, MO_UB)
    104TRANS(PLBZ, do_ldst_PLS_D, false, false, MO_UB)
    105
    106/* Load Halfword and Zero */
    107TRANS(LHZ, do_ldst_D, false, false, MO_UW)
    108TRANS(LHZX, do_ldst_X, false, false, MO_UW)
    109TRANS(LHZU, do_ldst_D, true, false, MO_UW)
    110TRANS(LHZUX, do_ldst_X, true, false, MO_UW)
    111TRANS(PLHZ, do_ldst_PLS_D, false, false, MO_UW)
    112
    113/* Load Halfword Algebraic */
    114TRANS(LHA, do_ldst_D, false, false, MO_SW)
    115TRANS(LHAX, do_ldst_X, false, false, MO_SW)
    116TRANS(LHAU, do_ldst_D, true, false, MO_SW)
    117TRANS(LHAXU, do_ldst_X, true, false, MO_SW)
    118TRANS(PLHA, do_ldst_PLS_D, false, false, MO_SW)
    119
    120/* Load Word and Zero */
    121TRANS(LWZ, do_ldst_D, false, false, MO_UL)
    122TRANS(LWZX, do_ldst_X, false, false, MO_UL)
    123TRANS(LWZU, do_ldst_D, true, false, MO_UL)
    124TRANS(LWZUX, do_ldst_X, true, false, MO_UL)
    125TRANS(PLWZ, do_ldst_PLS_D, false, false, MO_UL)
    126
    127/* Load Word Algebraic */
    128TRANS64(LWA, do_ldst_D, false, false, MO_SL)
    129TRANS64(LWAX, do_ldst_X, false, false, MO_SL)
    130TRANS64(LWAUX, do_ldst_X, true, false, MO_SL)
    131TRANS64(PLWA, do_ldst_PLS_D, false, false, MO_SL)
    132
    133/* Load Doubleword */
    134TRANS64(LD, do_ldst_D, false, false, MO_Q)
    135TRANS64(LDX, do_ldst_X, false, false, MO_Q)
    136TRANS64(LDU, do_ldst_D, true, false, MO_Q)
    137TRANS64(LDUX, do_ldst_X, true, false, MO_Q)
    138TRANS64(PLD, do_ldst_PLS_D, false, false, MO_Q)
    139
    140/* Store Byte */
    141TRANS(STB, do_ldst_D, false, true, MO_UB)
    142TRANS(STBX, do_ldst_X, false, true, MO_UB)
    143TRANS(STBU, do_ldst_D, true, true, MO_UB)
    144TRANS(STBUX, do_ldst_X, true, true, MO_UB)
    145TRANS(PSTB, do_ldst_PLS_D, false, true, MO_UB)
    146
    147/* Store Halfword */
    148TRANS(STH, do_ldst_D, false, true, MO_UW)
    149TRANS(STHX, do_ldst_X, false, true, MO_UW)
    150TRANS(STHU, do_ldst_D, true, true, MO_UW)
    151TRANS(STHUX, do_ldst_X, true, true, MO_UW)
    152TRANS(PSTH, do_ldst_PLS_D, false, true, MO_UW)
    153
    154/* Store Word */
    155TRANS(STW, do_ldst_D, false, true, MO_UL)
    156TRANS(STWX, do_ldst_X, false, true, MO_UL)
    157TRANS(STWU, do_ldst_D, true, true, MO_UL)
    158TRANS(STWUX, do_ldst_X, true, true, MO_UL)
    159TRANS(PSTW, do_ldst_PLS_D, false, true, MO_UL)
    160
    161/* Store Doubleword */
    162TRANS64(STD, do_ldst_D, false, true, MO_Q)
    163TRANS64(STDX, do_ldst_X, false, true, MO_Q)
    164TRANS64(STDU, do_ldst_D, true, true, MO_Q)
    165TRANS64(STDUX, do_ldst_X, true, true, MO_Q)
    166TRANS64(PSTD, do_ldst_PLS_D, false, true, MO_Q)
    167
    168/*
    169 * Fixed-Point Compare Instructions
    170 */
    171
    172static bool do_cmp_X(DisasContext *ctx, arg_X_bfl *a, bool s)
    173{
    174    if ((ctx->insns_flags & PPC_64B) == 0) {
    175        /*
    176         * For 32-bit implementations, The Programming Environments Manual says
    177         * that "the L field must be cleared, otherwise the instruction form is
    178         * invalid." It seems, however, that most 32-bit CPUs ignore invalid
    179         * forms (e.g., section "Instruction Formats" of the 405 and 440
    180         * manuals, "Integer Compare Instructions" of the 601 manual), with the
    181         * notable exception of the e500 and e500mc, where L=1 was reported to
    182         * cause an exception.
    183         */
    184        if (a->l) {
    185            if ((ctx->insns_flags2 & PPC2_BOOKE206)) {
    186                /*
    187                 * For 32-bit Book E v2.06 implementations (i.e. e500/e500mc),
    188                 * generate an illegal instruction exception.
    189                 */
    190                return false;
    191            } else {
    192                qemu_log_mask(LOG_GUEST_ERROR,
    193                        "Invalid form of CMP%s at 0x" TARGET_FMT_lx ", L = 1\n",
    194                        s ? "" : "L", ctx->cia);
    195            }
    196        }
    197        gen_op_cmp32(cpu_gpr[a->ra], cpu_gpr[a->rb], s, a->bf);
    198        return true;
    199    }
    200
    201    /* For 64-bit implementations, deal with bit L accordingly. */
    202    if (a->l) {
    203        gen_op_cmp(cpu_gpr[a->ra], cpu_gpr[a->rb], s, a->bf);
    204    } else {
    205        gen_op_cmp32(cpu_gpr[a->ra], cpu_gpr[a->rb], s, a->bf);
    206    }
    207    return true;
    208}
    209
    210static bool do_cmp_D(DisasContext *ctx, arg_D_bf *a, bool s)
    211{
    212    if ((ctx->insns_flags & PPC_64B) == 0) {
    213        /*
    214         * For 32-bit implementations, The Programming Environments Manual says
    215         * that "the L field must be cleared, otherwise the instruction form is
    216         * invalid." It seems, however, that most 32-bit CPUs ignore invalid
    217         * forms (e.g., section "Instruction Formats" of the 405 and 440
    218         * manuals, "Integer Compare Instructions" of the 601 manual), with the
    219         * notable exception of the e500 and e500mc, where L=1 was reported to
    220         * cause an exception.
    221         */
    222        if (a->l) {
    223            if ((ctx->insns_flags2 & PPC2_BOOKE206)) {
    224                /*
    225                 * For 32-bit Book E v2.06 implementations (i.e. e500/e500mc),
    226                 * generate an illegal instruction exception.
    227                 */
    228                return false;
    229            } else {
    230                qemu_log_mask(LOG_GUEST_ERROR,
    231                        "Invalid form of CMP%s at 0x" TARGET_FMT_lx ", L = 1\n",
    232                        s ? "I" : "LI", ctx->cia);
    233            }
    234        }
    235        gen_op_cmp32(cpu_gpr[a->ra], tcg_constant_tl(a->imm), s, a->bf);
    236        return true;
    237    }
    238
    239    /* For 64-bit implementations, deal with bit L accordingly. */
    240    if (a->l) {
    241        gen_op_cmp(cpu_gpr[a->ra], tcg_constant_tl(a->imm), s, a->bf);
    242    } else {
    243        gen_op_cmp32(cpu_gpr[a->ra], tcg_constant_tl(a->imm), s, a->bf);
    244    }
    245    return true;
    246}
    247
    248TRANS(CMP, do_cmp_X, true);
    249TRANS(CMPL, do_cmp_X, false);
    250TRANS(CMPI, do_cmp_D, true);
    251TRANS(CMPLI, do_cmp_D, false);
    252
    253/*
    254 * Fixed-Point Arithmetic Instructions
    255 */
    256
    257static bool trans_ADDI(DisasContext *ctx, arg_D *a)
    258{
    259    if (a->ra) {
    260        tcg_gen_addi_tl(cpu_gpr[a->rt], cpu_gpr[a->ra], a->si);
    261    } else {
    262        tcg_gen_movi_tl(cpu_gpr[a->rt], a->si);
    263    }
    264    return true;
    265}
    266
    267static bool trans_PADDI(DisasContext *ctx, arg_PLS_D *a)
    268{
    269    arg_D d;
    270    if (!resolve_PLS_D(ctx, &d, a)) {
    271        return true;
    272    }
    273    return trans_ADDI(ctx, &d);
    274}
    275
    276static bool trans_ADDIS(DisasContext *ctx, arg_D *a)
    277{
    278    a->si <<= 16;
    279    return trans_ADDI(ctx, a);
    280}
    281
    282static bool trans_ADDPCIS(DisasContext *ctx, arg_DX *a)
    283{
    284    REQUIRE_INSNS_FLAGS2(ctx, ISA300);
    285    tcg_gen_movi_tl(cpu_gpr[a->rt], ctx->base.pc_next + (a->d << 16));
    286    return true;
    287}
    288
    289static bool trans_INVALID(DisasContext *ctx, arg_INVALID *a)
    290{
    291    gen_invalid(ctx);
    292    return true;
    293}
    294
    295static bool trans_PNOP(DisasContext *ctx, arg_PNOP *a)
    296{
    297    return true;
    298}
    299
    300static bool do_set_bool_cond(DisasContext *ctx, arg_X_bi *a, bool neg, bool rev)
    301{
    302    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
    303    uint32_t mask = 0x08 >> (a->bi & 0x03);
    304    TCGCond cond = rev ? TCG_COND_EQ : TCG_COND_NE;
    305    TCGv temp = tcg_temp_new();
    306
    307    tcg_gen_extu_i32_tl(temp, cpu_crf[a->bi >> 2]);
    308    tcg_gen_andi_tl(temp, temp, mask);
    309    tcg_gen_setcondi_tl(cond, cpu_gpr[a->rt], temp, 0);
    310    if (neg) {
    311        tcg_gen_neg_tl(cpu_gpr[a->rt], cpu_gpr[a->rt]);
    312    }
    313    tcg_temp_free(temp);
    314
    315    return true;
    316}
    317
    318TRANS(SETBC, do_set_bool_cond, false, false)
    319TRANS(SETBCR, do_set_bool_cond, false, true)
    320TRANS(SETNBC, do_set_bool_cond, true, false)
    321TRANS(SETNBCR, do_set_bool_cond, true, true)
    322
    323static bool trans_CFUGED(DisasContext *ctx, arg_X *a)
    324{
    325    REQUIRE_64BIT(ctx);
    326    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
    327#if defined(TARGET_PPC64)
    328    gen_helper_cfuged(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb]);
    329#else
    330    qemu_build_not_reached();
    331#endif
    332    return true;
    333}