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

op_helper.c (15548B)


      1/*
      2 *  CRIS helper routines
      3 *
      4 *  Copyright (c) 2007 AXIS Communications
      5 *  Written by Edgar E. Iglesias
      6 *
      7 * This library is free software; you can redistribute it and/or
      8 * modify it under the terms of the GNU Lesser General Public
      9 * License as published by the Free Software Foundation; either
     10 * version 2.1 of the License, or (at your option) any later version.
     11 *
     12 * This library is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15 * Lesser General Public License for more details.
     16 *
     17 * You should have received a copy of the GNU Lesser General Public
     18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
     19 */
     20
     21#include "qemu/osdep.h"
     22#include "cpu.h"
     23#include "mmu.h"
     24#include "exec/helper-proto.h"
     25#include "qemu/host-utils.h"
     26#include "exec/exec-all.h"
     27#include "exec/cpu_ldst.h"
     28
     29//#define CRIS_OP_HELPER_DEBUG
     30
     31
     32#ifdef CRIS_OP_HELPER_DEBUG
     33#define D(x) x
     34#define D_LOG(...) qemu_log(__VA_ARGS__)
     35#else
     36#define D(x)
     37#define D_LOG(...) do { } while (0)
     38#endif
     39
     40void helper_raise_exception(CPUCRISState *env, uint32_t index)
     41{
     42    CPUState *cs = env_cpu(env);
     43
     44    cs->exception_index = index;
     45    cpu_loop_exit(cs);
     46}
     47
     48void helper_tlb_flush_pid(CPUCRISState *env, uint32_t pid)
     49{
     50#if !defined(CONFIG_USER_ONLY)
     51    pid &= 0xff;
     52    if (pid != (env->pregs[PR_PID] & 0xff)) {
     53        cris_mmu_flush_pid(env, env->pregs[PR_PID]);
     54    }
     55#endif
     56}
     57
     58void helper_spc_write(CPUCRISState *env, uint32_t new_spc)
     59{
     60#if !defined(CONFIG_USER_ONLY)
     61    CPUState *cs = env_cpu(env);
     62
     63    tlb_flush_page(cs, env->pregs[PR_SPC]);
     64    tlb_flush_page(cs, new_spc);
     65#endif
     66}
     67
     68/* Used by the tlb decoder.  */
     69#define EXTRACT_FIELD(src, start, end)                  \
     70    (((src) >> start) & ((1 << (end - start + 1)) - 1))
     71
     72void helper_movl_sreg_reg(CPUCRISState *env, uint32_t sreg, uint32_t reg)
     73{
     74    uint32_t srs;
     75    srs = env->pregs[PR_SRS];
     76    srs &= 3;
     77    env->sregs[srs][sreg] = env->regs[reg];
     78
     79#if !defined(CONFIG_USER_ONLY)
     80    if (srs == 1 || srs == 2) {
     81        if (sreg == 6) {
     82            /* Writes to tlb-hi write to mm_cause as a side effect.  */
     83            env->sregs[SFR_RW_MM_TLB_HI] = env->regs[reg];
     84            env->sregs[SFR_R_MM_CAUSE] = env->regs[reg];
     85        } else if (sreg == 5) {
     86            uint32_t set;
     87            uint32_t idx;
     88            uint32_t lo, hi;
     89            uint32_t vaddr;
     90            int tlb_v;
     91
     92            idx = set = env->sregs[SFR_RW_MM_TLB_SEL];
     93            set >>= 4;
     94            set &= 3;
     95
     96            idx &= 15;
     97            /* We've just made a write to tlb_lo.  */
     98            lo = env->sregs[SFR_RW_MM_TLB_LO];
     99            /* Writes are done via r_mm_cause.  */
    100            hi = env->sregs[SFR_R_MM_CAUSE];
    101
    102            vaddr = EXTRACT_FIELD(env->tlbsets[srs - 1][set][idx].hi, 13, 31);
    103            vaddr <<= TARGET_PAGE_BITS;
    104            tlb_v = EXTRACT_FIELD(env->tlbsets[srs - 1][set][idx].lo, 3, 3);
    105            env->tlbsets[srs - 1][set][idx].lo = lo;
    106            env->tlbsets[srs - 1][set][idx].hi = hi;
    107
    108            D_LOG("tlb flush vaddr=%x v=%d pc=%x\n",
    109                  vaddr, tlb_v, env->pc);
    110            if (tlb_v) {
    111                tlb_flush_page(env_cpu(env), vaddr);
    112            }
    113        }
    114    }
    115#endif
    116}
    117
    118void helper_movl_reg_sreg(CPUCRISState *env, uint32_t reg, uint32_t sreg)
    119{
    120    uint32_t srs;
    121    env->pregs[PR_SRS] &= 3;
    122    srs = env->pregs[PR_SRS];
    123
    124#if !defined(CONFIG_USER_ONLY)
    125    if (srs == 1 || srs == 2) {
    126        uint32_t set;
    127        uint32_t idx;
    128        uint32_t lo, hi;
    129
    130        idx = set = env->sregs[SFR_RW_MM_TLB_SEL];
    131        set >>= 4;
    132        set &= 3;
    133        idx &= 15;
    134
    135        /* Update the mirror regs.  */
    136        hi = env->tlbsets[srs - 1][set][idx].hi;
    137        lo = env->tlbsets[srs - 1][set][idx].lo;
    138        env->sregs[SFR_RW_MM_TLB_HI] = hi;
    139        env->sregs[SFR_RW_MM_TLB_LO] = lo;
    140    }
    141#endif
    142    env->regs[reg] = env->sregs[srs][sreg];
    143}
    144
    145static void cris_ccs_rshift(CPUCRISState *env)
    146{
    147    uint32_t ccs;
    148
    149    /* Apply the ccs shift.  */
    150    ccs = env->pregs[PR_CCS];
    151    ccs = (ccs & 0xc0000000) | ((ccs & 0x0fffffff) >> 10);
    152    if (ccs & U_FLAG) {
    153        /* Enter user mode.  */
    154        env->ksp = env->regs[R_SP];
    155        env->regs[R_SP] = env->pregs[PR_USP];
    156    }
    157
    158    env->pregs[PR_CCS] = ccs;
    159}
    160
    161void helper_rfe(CPUCRISState *env)
    162{
    163    int rflag = env->pregs[PR_CCS] & R_FLAG;
    164
    165    D_LOG("rfe: erp=%x pid=%x ccs=%x btarget=%x\n",
    166          env->pregs[PR_ERP], env->pregs[PR_PID],
    167          env->pregs[PR_CCS],
    168          env->btarget);
    169
    170    cris_ccs_rshift(env);
    171
    172    /* RFE sets the P_FLAG only if the R_FLAG is not set.  */
    173    if (!rflag) {
    174        env->pregs[PR_CCS] |= P_FLAG;
    175    }
    176}
    177
    178void helper_rfn(CPUCRISState *env)
    179{
    180    int rflag = env->pregs[PR_CCS] & R_FLAG;
    181
    182    D_LOG("rfn: erp=%x pid=%x ccs=%x btarget=%x\n",
    183          env->pregs[PR_ERP], env->pregs[PR_PID],
    184          env->pregs[PR_CCS],
    185          env->btarget);
    186
    187    cris_ccs_rshift(env);
    188
    189    /* Set the P_FLAG only if the R_FLAG is not set.  */
    190    if (!rflag) {
    191        env->pregs[PR_CCS] |= P_FLAG;
    192    }
    193
    194    /* Always set the M flag.  */
    195    env->pregs[PR_CCS] |= M_FLAG_V32;
    196}
    197
    198uint32_t helper_btst(CPUCRISState *env, uint32_t t0, uint32_t t1, uint32_t ccs)
    199{
    200    /* FIXME: clean this up.  */
    201
    202    /*
    203     * des ref:
    204     *  The N flag is set according to the selected bit in the dest reg.
    205     *  The Z flag is set if the selected bit and all bits to the right are
    206     *  zero.
    207     *  The X flag is cleared.
    208     *  Other flags are left untouched.
    209     *  The destination reg is not affected.
    210     */
    211    unsigned int fz, sbit, bset, mask, masked_t0;
    212
    213    sbit = t1 & 31;
    214    bset = !!(t0 & (1 << sbit));
    215    mask = sbit == 31 ? -1 : (1 << (sbit + 1)) - 1;
    216    masked_t0 = t0 & mask;
    217    fz = !(masked_t0 | bset);
    218
    219    /* Clear the X, N and Z flags.  */
    220    ccs = ccs & ~(X_FLAG | N_FLAG | Z_FLAG);
    221    if (env->pregs[PR_VR] < 32) {
    222        ccs &= ~(V_FLAG | C_FLAG);
    223    }
    224    /* Set the N and Z flags accordingly.  */
    225    ccs |= (bset << 3) | (fz << 2);
    226    return ccs;
    227}
    228
    229static inline uint32_t evaluate_flags_writeback(CPUCRISState *env,
    230                                                uint32_t flags, uint32_t ccs)
    231{
    232    unsigned int x, z, mask;
    233
    234    /* Extended arithmetics, leave the z flag alone.  */
    235    x = env->cc_x;
    236    mask = env->cc_mask | X_FLAG;
    237    if (x) {
    238        z = flags & Z_FLAG;
    239        mask = mask & ~z;
    240    }
    241    flags &= mask;
    242
    243    /* all insn clear the x-flag except setf or clrf.  */
    244    ccs &= ~mask;
    245    ccs |= flags;
    246    return ccs;
    247}
    248
    249uint32_t helper_evaluate_flags_muls(CPUCRISState *env,
    250                                    uint32_t ccs, uint32_t res, uint32_t mof)
    251{
    252    uint32_t flags = 0;
    253    int64_t tmp;
    254    int dneg;
    255
    256    dneg = ((int32_t)res) < 0;
    257
    258    tmp = mof;
    259    tmp <<= 32;
    260    tmp |= res;
    261    if (tmp == 0) {
    262        flags |= Z_FLAG;
    263    } else if (tmp < 0) {
    264        flags |= N_FLAG;
    265    }
    266    if ((dneg && mof != -1) || (!dneg && mof != 0)) {
    267        flags |= V_FLAG;
    268    }
    269    return evaluate_flags_writeback(env, flags, ccs);
    270}
    271
    272uint32_t helper_evaluate_flags_mulu(CPUCRISState *env,
    273                                    uint32_t ccs, uint32_t res, uint32_t mof)
    274{
    275    uint32_t flags = 0;
    276    uint64_t tmp;
    277
    278    tmp = mof;
    279    tmp <<= 32;
    280    tmp |= res;
    281    if (tmp == 0) {
    282        flags |= Z_FLAG;
    283    } else if (tmp >> 63) {
    284        flags |= N_FLAG;
    285    }
    286    if (mof) {
    287        flags |= V_FLAG;
    288    }
    289
    290    return evaluate_flags_writeback(env, flags, ccs);
    291}
    292
    293uint32_t helper_evaluate_flags_mcp(CPUCRISState *env, uint32_t ccs,
    294				   uint32_t src, uint32_t dst, uint32_t res)
    295{
    296    uint32_t flags = 0;
    297
    298    src = src & 0x80000000;
    299    dst = dst & 0x80000000;
    300
    301    if ((res & 0x80000000L) != 0L) {
    302        flags |= N_FLAG;
    303        if (!src && !dst) {
    304            flags |= V_FLAG;
    305        } else if (src & dst) {
    306            flags |= R_FLAG;
    307        }
    308    } else {
    309        if (res == 0L) {
    310            flags |= Z_FLAG;
    311        }
    312        if (src & dst) {
    313            flags |= V_FLAG;
    314        }
    315        if (dst | src) {
    316            flags |= R_FLAG;
    317        }
    318    }
    319
    320    return evaluate_flags_writeback(env, flags, ccs);
    321}
    322
    323uint32_t helper_evaluate_flags_alu_4(CPUCRISState *env, uint32_t ccs,
    324				     uint32_t src, uint32_t dst, uint32_t res)
    325{
    326    uint32_t flags = 0;
    327
    328    src = src & 0x80000000;
    329    dst = dst & 0x80000000;
    330
    331    if ((res & 0x80000000L) != 0L) {
    332        flags |= N_FLAG;
    333        if (!src && !dst) {
    334            flags |= V_FLAG;
    335        } else if (src & dst) {
    336            flags |= C_FLAG;
    337        }
    338    } else {
    339        if (res == 0L) {
    340            flags |= Z_FLAG;
    341        }
    342        if (src & dst) {
    343            flags |= V_FLAG;
    344        }
    345        if (dst | src) {
    346            flags |= C_FLAG;
    347        }
    348    }
    349
    350    return evaluate_flags_writeback(env, flags, ccs);
    351}
    352
    353uint32_t helper_evaluate_flags_sub_4(CPUCRISState *env, uint32_t ccs,
    354				     uint32_t src, uint32_t dst, uint32_t res)
    355{
    356    uint32_t flags = 0;
    357
    358    src = (~src) & 0x80000000;
    359    dst = dst & 0x80000000;
    360
    361    if ((res & 0x80000000L) != 0L) {
    362        flags |= N_FLAG;
    363        if (!src && !dst) {
    364            flags |= V_FLAG;
    365        } else if (src & dst) {
    366            flags |= C_FLAG;
    367        }
    368    } else {
    369        if (res == 0L) {
    370            flags |= Z_FLAG;
    371        }
    372        if (src & dst) {
    373            flags |= V_FLAG;
    374        }
    375        if (dst | src) {
    376            flags |= C_FLAG;
    377        }
    378    }
    379
    380    flags ^= C_FLAG;
    381    return evaluate_flags_writeback(env, flags, ccs);
    382}
    383
    384uint32_t helper_evaluate_flags_move_4(CPUCRISState *env,
    385                                      uint32_t ccs, uint32_t res)
    386{
    387    uint32_t flags = 0;
    388
    389    if ((int32_t)res < 0) {
    390        flags |= N_FLAG;
    391    } else if (res == 0L) {
    392        flags |= Z_FLAG;
    393    }
    394
    395    return evaluate_flags_writeback(env, flags, ccs);
    396}
    397
    398uint32_t helper_evaluate_flags_move_2(CPUCRISState *env,
    399                                      uint32_t ccs, uint32_t res)
    400{
    401    uint32_t flags = 0;
    402
    403    if ((int16_t)res < 0L) {
    404        flags |= N_FLAG;
    405    } else if (res == 0) {
    406        flags |= Z_FLAG;
    407    }
    408
    409    return evaluate_flags_writeback(env, flags, ccs);
    410}
    411
    412/*
    413 * TODO: This is expensive. We could split things up and only evaluate part of
    414 * CCR on a need to know basis. For now, we simply re-evaluate everything.
    415 */
    416void helper_evaluate_flags(CPUCRISState *env)
    417{
    418    uint32_t src, dst, res;
    419    uint32_t flags = 0;
    420
    421    src = env->cc_src;
    422    dst = env->cc_dest;
    423    res = env->cc_result;
    424
    425    if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP) {
    426        src = ~src;
    427    }
    428
    429    /*
    430     * Now, evaluate the flags. This stuff is based on
    431     * Per Zander's CRISv10 simulator.
    432     */
    433    switch (env->cc_size) {
    434    case 1:
    435        if ((res & 0x80L) != 0L) {
    436            flags |= N_FLAG;
    437            if (((src & 0x80L) == 0L) && ((dst & 0x80L) == 0L)) {
    438                flags |= V_FLAG;
    439            } else if (((src & 0x80L) != 0L) && ((dst & 0x80L) != 0L)) {
    440                flags |= C_FLAG;
    441            }
    442        } else {
    443            if ((res & 0xFFL) == 0L) {
    444                flags |= Z_FLAG;
    445            }
    446            if (((src & 0x80L) != 0L) && ((dst & 0x80L) != 0L)) {
    447                flags |= V_FLAG;
    448            }
    449            if ((dst & 0x80L) != 0L || (src & 0x80L) != 0L) {
    450                flags |= C_FLAG;
    451            }
    452        }
    453        break;
    454    case 2:
    455        if ((res & 0x8000L) != 0L) {
    456            flags |= N_FLAG;
    457            if (((src & 0x8000L) == 0L) && ((dst & 0x8000L) == 0L)) {
    458                flags |= V_FLAG;
    459            } else if (((src & 0x8000L) != 0L) && ((dst & 0x8000L) != 0L)) {
    460                flags |= C_FLAG;
    461            }
    462        } else {
    463            if ((res & 0xFFFFL) == 0L) {
    464                flags |= Z_FLAG;
    465            }
    466            if (((src & 0x8000L) != 0L) && ((dst & 0x8000L) != 0L)) {
    467                flags |= V_FLAG;
    468            }
    469            if ((dst & 0x8000L) != 0L || (src & 0x8000L) != 0L) {
    470                flags |= C_FLAG;
    471            }
    472        }
    473        break;
    474    case 4:
    475        if ((res & 0x80000000L) != 0L) {
    476            flags |= N_FLAG;
    477            if (((src & 0x80000000L) == 0L) && ((dst & 0x80000000L) == 0L)) {
    478                flags |= V_FLAG;
    479            } else if (((src & 0x80000000L) != 0L) &&
    480                       ((dst & 0x80000000L) != 0L)) {
    481                flags |= C_FLAG;
    482            }
    483        } else {
    484            if (res == 0L) {
    485                flags |= Z_FLAG;
    486            }
    487            if (((src & 0x80000000L) != 0L) && ((dst & 0x80000000L) != 0L)) {
    488                flags |= V_FLAG;
    489            }
    490            if ((dst & 0x80000000L) != 0L || (src & 0x80000000L) != 0L) {
    491                flags |= C_FLAG;
    492            }
    493        }
    494        break;
    495    default:
    496        break;
    497    }
    498
    499    if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP) {
    500        flags ^= C_FLAG;
    501    }
    502
    503    env->pregs[PR_CCS] = evaluate_flags_writeback(env, flags,
    504                                                  env->pregs[PR_CCS]);
    505}
    506
    507void helper_top_evaluate_flags(CPUCRISState *env)
    508{
    509    switch (env->cc_op) {
    510    case CC_OP_MCP:
    511        env->pregs[PR_CCS]
    512            = helper_evaluate_flags_mcp(env, env->pregs[PR_CCS],
    513                                        env->cc_src, env->cc_dest,
    514                                        env->cc_result);
    515        break;
    516    case CC_OP_MULS:
    517        env->pregs[PR_CCS]
    518            = helper_evaluate_flags_muls(env, env->pregs[PR_CCS],
    519                                         env->cc_result, env->pregs[PR_MOF]);
    520        break;
    521    case CC_OP_MULU:
    522        env->pregs[PR_CCS]
    523            = helper_evaluate_flags_mulu(env, env->pregs[PR_CCS],
    524                                         env->cc_result, env->pregs[PR_MOF]);
    525        break;
    526    case CC_OP_MOVE:
    527    case CC_OP_AND:
    528    case CC_OP_OR:
    529    case CC_OP_XOR:
    530    case CC_OP_ASR:
    531    case CC_OP_LSR:
    532    case CC_OP_LSL:
    533        switch (env->cc_size) {
    534        case 4:
    535            env->pregs[PR_CCS] =
    536                helper_evaluate_flags_move_4(env,
    537                                             env->pregs[PR_CCS],
    538                                             env->cc_result);
    539            break;
    540        case 2:
    541            env->pregs[PR_CCS] =
    542                helper_evaluate_flags_move_2(env,
    543                                             env->pregs[PR_CCS],
    544                                             env->cc_result);
    545            break;
    546        default:
    547            helper_evaluate_flags(env);
    548            break;
    549        }
    550        break;
    551    case CC_OP_FLAGS:
    552        /* live.  */
    553        break;
    554    case CC_OP_SUB:
    555    case CC_OP_CMP:
    556        if (env->cc_size == 4) {
    557            env->pregs[PR_CCS] =
    558                helper_evaluate_flags_sub_4(env,
    559                                            env->pregs[PR_CCS],
    560                                            env->cc_src, env->cc_dest,
    561                                            env->cc_result);
    562        } else {
    563            helper_evaluate_flags(env);
    564        }
    565        break;
    566    default:
    567        switch (env->cc_size) {
    568        case 4:
    569            env->pregs[PR_CCS] =
    570                helper_evaluate_flags_alu_4(env,
    571                                            env->pregs[PR_CCS],
    572                                            env->cc_src, env->cc_dest,
    573                                            env->cc_result);
    574            break;
    575        default:
    576            helper_evaluate_flags(env);
    577            break;
    578        }
    579        break;
    580    }
    581}