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

ldst_helper.c (9463B)


      1/*
      2 *  MIPS emulation load/store helpers for QEMU.
      3 *
      4 *  Copyright (c) 2004-2005 Jocelyn Mayer
      5 *
      6 * SPDX-License-Identifier: LGPL-2.1-or-later
      7 *
      8 * This library is free software; you can redistribute it and/or
      9 * modify it under the terms of the GNU Lesser General Public
     10 * License as published by the Free Software Foundation; either
     11 * version 2.1 of the License, or (at your option) any later version.
     12 *
     13 * This library is distributed in the hope that it will be useful,
     14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     16 * Lesser General Public License for more details.
     17 *
     18 * You should have received a copy of the GNU Lesser General Public
     19 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
     20 *
     21 */
     22
     23#include "qemu/osdep.h"
     24#include "cpu.h"
     25#include "exec/helper-proto.h"
     26#include "exec/exec-all.h"
     27#include "exec/memop.h"
     28#include "internal.h"
     29
     30#ifndef CONFIG_USER_ONLY
     31
     32#define HELPER_LD_ATOMIC(name, insn, almask, do_cast)                         \
     33target_ulong helper_##name(CPUMIPSState *env, target_ulong arg, int mem_idx)  \
     34{                                                                             \
     35    if (arg & almask) {                                                       \
     36        if (!(env->hflags & MIPS_HFLAG_DM)) {                                 \
     37            env->CP0_BadVAddr = arg;                                          \
     38        }                                                                     \
     39        do_raise_exception(env, EXCP_AdEL, GETPC());                          \
     40    }                                                                         \
     41    env->CP0_LLAddr = cpu_mips_translate_address(env, arg, MMU_DATA_LOAD,     \
     42                                                 GETPC());                    \
     43    env->lladdr = arg;                                                        \
     44    env->llval = do_cast cpu_##insn##_mmuidx_ra(env, arg, mem_idx, GETPC());  \
     45    return env->llval;                                                        \
     46}
     47HELPER_LD_ATOMIC(ll, ldl, 0x3, (target_long)(int32_t))
     48#ifdef TARGET_MIPS64
     49HELPER_LD_ATOMIC(lld, ldq, 0x7, (target_ulong))
     50#endif
     51#undef HELPER_LD_ATOMIC
     52
     53#endif /* !CONFIG_USER_ONLY */
     54
     55static inline bool cpu_is_bigendian(CPUMIPSState *env)
     56{
     57    return extract32(env->CP0_Config0, CP0C0_BE, 1);
     58}
     59
     60static inline target_ulong get_lmask(CPUMIPSState *env,
     61                                     target_ulong value, unsigned bits)
     62{
     63    unsigned mask = (bits / BITS_PER_BYTE) - 1;
     64
     65    value &= mask;
     66
     67    if (!cpu_is_bigendian(env)) {
     68        value ^= mask;
     69    }
     70
     71    return value;
     72}
     73
     74void helper_swl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
     75                int mem_idx)
     76{
     77    target_ulong lmask = get_lmask(env, arg2, 32);
     78    int dir = cpu_is_bigendian(env) ? 1 : -1;
     79
     80    cpu_stb_mmuidx_ra(env, arg2, (uint8_t)(arg1 >> 24), mem_idx, GETPC());
     81
     82    if (lmask <= 2) {
     83        cpu_stb_mmuidx_ra(env, arg2 + 1 * dir, (uint8_t)(arg1 >> 16),
     84                          mem_idx, GETPC());
     85    }
     86
     87    if (lmask <= 1) {
     88        cpu_stb_mmuidx_ra(env, arg2 + 2 * dir, (uint8_t)(arg1 >> 8),
     89                          mem_idx, GETPC());
     90    }
     91
     92    if (lmask == 0) {
     93        cpu_stb_mmuidx_ra(env, arg2 + 3 * dir, (uint8_t)arg1,
     94                          mem_idx, GETPC());
     95    }
     96}
     97
     98void helper_swr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
     99                int mem_idx)
    100{
    101    target_ulong lmask = get_lmask(env, arg2, 32);
    102    int dir = cpu_is_bigendian(env) ? 1 : -1;
    103
    104    cpu_stb_mmuidx_ra(env, arg2, (uint8_t)arg1, mem_idx, GETPC());
    105
    106    if (lmask >= 1) {
    107        cpu_stb_mmuidx_ra(env, arg2 - 1 * dir, (uint8_t)(arg1 >> 8),
    108                          mem_idx, GETPC());
    109    }
    110
    111    if (lmask >= 2) {
    112        cpu_stb_mmuidx_ra(env, arg2 - 2 * dir, (uint8_t)(arg1 >> 16),
    113                          mem_idx, GETPC());
    114    }
    115
    116    if (lmask == 3) {
    117        cpu_stb_mmuidx_ra(env, arg2 - 3 * dir, (uint8_t)(arg1 >> 24),
    118                          mem_idx, GETPC());
    119    }
    120}
    121
    122#if defined(TARGET_MIPS64)
    123/*
    124 * "half" load and stores.  We must do the memory access inline,
    125 * or fault handling won't work.
    126 */
    127
    128void helper_sdl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
    129                int mem_idx)
    130{
    131    target_ulong lmask = get_lmask(env, arg2, 64);
    132    int dir = cpu_is_bigendian(env) ? 1 : -1;
    133
    134    cpu_stb_mmuidx_ra(env, arg2, (uint8_t)(arg1 >> 56), mem_idx, GETPC());
    135
    136    if (lmask <= 6) {
    137        cpu_stb_mmuidx_ra(env, arg2 + 1 * dir, (uint8_t)(arg1 >> 48),
    138                          mem_idx, GETPC());
    139    }
    140
    141    if (lmask <= 5) {
    142        cpu_stb_mmuidx_ra(env, arg2 + 2 * dir, (uint8_t)(arg1 >> 40),
    143                          mem_idx, GETPC());
    144    }
    145
    146    if (lmask <= 4) {
    147        cpu_stb_mmuidx_ra(env, arg2 + 3 * dir, (uint8_t)(arg1 >> 32),
    148                          mem_idx, GETPC());
    149    }
    150
    151    if (lmask <= 3) {
    152        cpu_stb_mmuidx_ra(env, arg2 + 4 * dir, (uint8_t)(arg1 >> 24),
    153                          mem_idx, GETPC());
    154    }
    155
    156    if (lmask <= 2) {
    157        cpu_stb_mmuidx_ra(env, arg2 + 5 * dir, (uint8_t)(arg1 >> 16),
    158                          mem_idx, GETPC());
    159    }
    160
    161    if (lmask <= 1) {
    162        cpu_stb_mmuidx_ra(env, arg2 + 6 * dir, (uint8_t)(arg1 >> 8),
    163                          mem_idx, GETPC());
    164    }
    165
    166    if (lmask <= 0) {
    167        cpu_stb_mmuidx_ra(env, arg2 + 7 * dir, (uint8_t)arg1,
    168                          mem_idx, GETPC());
    169    }
    170}
    171
    172void helper_sdr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
    173                int mem_idx)
    174{
    175    target_ulong lmask = get_lmask(env, arg2, 64);
    176    int dir = cpu_is_bigendian(env) ? 1 : -1;
    177
    178    cpu_stb_mmuidx_ra(env, arg2, (uint8_t)arg1, mem_idx, GETPC());
    179
    180    if (lmask >= 1) {
    181        cpu_stb_mmuidx_ra(env, arg2 - 1 * dir, (uint8_t)(arg1 >> 8),
    182                          mem_idx, GETPC());
    183    }
    184
    185    if (lmask >= 2) {
    186        cpu_stb_mmuidx_ra(env, arg2 - 2 * dir, (uint8_t)(arg1 >> 16),
    187                          mem_idx, GETPC());
    188    }
    189
    190    if (lmask >= 3) {
    191        cpu_stb_mmuidx_ra(env, arg2 - 3 * dir, (uint8_t)(arg1 >> 24),
    192                          mem_idx, GETPC());
    193    }
    194
    195    if (lmask >= 4) {
    196        cpu_stb_mmuidx_ra(env, arg2 - 4 * dir, (uint8_t)(arg1 >> 32),
    197                          mem_idx, GETPC());
    198    }
    199
    200    if (lmask >= 5) {
    201        cpu_stb_mmuidx_ra(env, arg2 - 5 * dir, (uint8_t)(arg1 >> 40),
    202                          mem_idx, GETPC());
    203    }
    204
    205    if (lmask >= 6) {
    206        cpu_stb_mmuidx_ra(env, arg2 - 6 * dir, (uint8_t)(arg1 >> 48),
    207                          mem_idx, GETPC());
    208    }
    209
    210    if (lmask == 7) {
    211        cpu_stb_mmuidx_ra(env, arg2 - 7 * dir, (uint8_t)(arg1 >> 56),
    212                          mem_idx, GETPC());
    213    }
    214}
    215#endif /* TARGET_MIPS64 */
    216
    217static const int multiple_regs[] = { 16, 17, 18, 19, 20, 21, 22, 23, 30 };
    218
    219void helper_lwm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
    220                uint32_t mem_idx)
    221{
    222    target_ulong base_reglist = reglist & 0xf;
    223    target_ulong do_r31 = reglist & 0x10;
    224
    225    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE(multiple_regs)) {
    226        target_ulong i;
    227
    228        for (i = 0; i < base_reglist; i++) {
    229            env->active_tc.gpr[multiple_regs[i]] =
    230                (target_long)cpu_ldl_mmuidx_ra(env, addr, mem_idx, GETPC());
    231            addr += 4;
    232        }
    233    }
    234
    235    if (do_r31) {
    236        env->active_tc.gpr[31] =
    237            (target_long)cpu_ldl_mmuidx_ra(env, addr, mem_idx, GETPC());
    238    }
    239}
    240
    241void helper_swm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
    242                uint32_t mem_idx)
    243{
    244    target_ulong base_reglist = reglist & 0xf;
    245    target_ulong do_r31 = reglist & 0x10;
    246
    247    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE(multiple_regs)) {
    248        target_ulong i;
    249
    250        for (i = 0; i < base_reglist; i++) {
    251            cpu_stw_mmuidx_ra(env, addr, env->active_tc.gpr[multiple_regs[i]],
    252                              mem_idx, GETPC());
    253            addr += 4;
    254        }
    255    }
    256
    257    if (do_r31) {
    258        cpu_stw_mmuidx_ra(env, addr, env->active_tc.gpr[31], mem_idx, GETPC());
    259    }
    260}
    261
    262#if defined(TARGET_MIPS64)
    263void helper_ldm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
    264                uint32_t mem_idx)
    265{
    266    target_ulong base_reglist = reglist & 0xf;
    267    target_ulong do_r31 = reglist & 0x10;
    268
    269    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE(multiple_regs)) {
    270        target_ulong i;
    271
    272        for (i = 0; i < base_reglist; i++) {
    273            env->active_tc.gpr[multiple_regs[i]] =
    274                cpu_ldq_mmuidx_ra(env, addr, mem_idx, GETPC());
    275            addr += 8;
    276        }
    277    }
    278
    279    if (do_r31) {
    280        env->active_tc.gpr[31] =
    281            cpu_ldq_mmuidx_ra(env, addr, mem_idx, GETPC());
    282    }
    283}
    284
    285void helper_sdm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
    286                uint32_t mem_idx)
    287{
    288    target_ulong base_reglist = reglist & 0xf;
    289    target_ulong do_r31 = reglist & 0x10;
    290
    291    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE(multiple_regs)) {
    292        target_ulong i;
    293
    294        for (i = 0; i < base_reglist; i++) {
    295            cpu_stq_mmuidx_ra(env, addr, env->active_tc.gpr[multiple_regs[i]],
    296                              mem_idx, GETPC());
    297            addr += 8;
    298        }
    299    }
    300
    301    if (do_r31) {
    302        cpu_stq_mmuidx_ra(env, addr, env->active_tc.gpr[31], mem_idx, GETPC());
    303    }
    304}
    305
    306#endif /* TARGET_MIPS64 */