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

cpu_loop.c (15400B)


      1/*
      2 *  qemu user cpu loop
      3 *
      4 *  Copyright (c) 2003-2008 Fabrice Bellard
      5 *
      6 *  This program is free software; you can redistribute it and/or modify
      7 *  it under the terms of the GNU General Public License as published by
      8 *  the Free Software Foundation; either version 2 of the License, or
      9 *  (at your option) any later version.
     10 *
     11 *  This program 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
     14 *  GNU General Public License for more details.
     15 *
     16 *  You should have received a copy of the GNU General Public License
     17 *  along with this program; if not, see <http://www.gnu.org/licenses/>.
     18 */
     19
     20#include "qemu/osdep.h"
     21#include "qemu-common.h"
     22#include "qemu.h"
     23#include "user-internals.h"
     24#include "cpu_loop-common.h"
     25#include "signal-common.h"
     26#include "elf.h"
     27#include "internal.h"
     28#include "fpu_helper.h"
     29
     30# ifdef TARGET_ABI_MIPSO32
     31#  define MIPS_SYSCALL_NUMBER_UNUSED -1
     32static const int8_t mips_syscall_args[] = {
     33#include "syscall-args-o32.c.inc"
     34};
     35# endif /* O32 */
     36
     37/* Break codes */
     38enum {
     39    BRK_OVERFLOW = 6,
     40    BRK_DIVZERO = 7
     41};
     42
     43static int do_break(CPUMIPSState *env, target_siginfo_t *info,
     44                    unsigned int code)
     45{
     46    int ret = -1;
     47
     48    switch (code) {
     49    case BRK_OVERFLOW:
     50    case BRK_DIVZERO:
     51        info->si_signo = TARGET_SIGFPE;
     52        info->si_errno = 0;
     53        info->si_code = (code == BRK_OVERFLOW) ? FPE_INTOVF : FPE_INTDIV;
     54        queue_signal(env, info->si_signo, QEMU_SI_FAULT, &*info);
     55        ret = 0;
     56        break;
     57    default:
     58        info->si_signo = TARGET_SIGTRAP;
     59        info->si_errno = 0;
     60        queue_signal(env, info->si_signo, QEMU_SI_FAULT, &*info);
     61        ret = 0;
     62        break;
     63    }
     64
     65    return ret;
     66}
     67
     68void cpu_loop(CPUMIPSState *env)
     69{
     70    CPUState *cs = env_cpu(env);
     71    target_siginfo_t info;
     72    int trapnr;
     73    abi_long ret;
     74# ifdef TARGET_ABI_MIPSO32
     75    unsigned int syscall_num;
     76# endif
     77
     78    for(;;) {
     79        cpu_exec_start(cs);
     80        trapnr = cpu_exec(cs);
     81        cpu_exec_end(cs);
     82        process_queued_cpu_work(cs);
     83
     84        switch(trapnr) {
     85        case EXCP_SYSCALL:
     86            env->active_tc.PC += 4;
     87# ifdef TARGET_ABI_MIPSO32
     88            syscall_num = env->active_tc.gpr[2] - 4000;
     89            if (syscall_num >= sizeof(mips_syscall_args)) {
     90                /* syscall_num is larger that any defined for MIPS O32 */
     91                ret = -TARGET_ENOSYS;
     92            } else if (mips_syscall_args[syscall_num] ==
     93                       MIPS_SYSCALL_NUMBER_UNUSED) {
     94                /* syscall_num belongs to the range not defined for MIPS O32 */
     95                ret = -TARGET_ENOSYS;
     96            } else {
     97                /* syscall_num is valid */
     98                int nb_args;
     99                abi_ulong sp_reg;
    100                abi_ulong arg5 = 0, arg6 = 0, arg7 = 0, arg8 = 0;
    101
    102                nb_args = mips_syscall_args[syscall_num];
    103                sp_reg = env->active_tc.gpr[29];
    104                switch (nb_args) {
    105                /* these arguments are taken from the stack */
    106                case 8:
    107                    if ((ret = get_user_ual(arg8, sp_reg + 28)) != 0) {
    108                        goto done_syscall;
    109                    }
    110                    /* fall through */
    111                case 7:
    112                    if ((ret = get_user_ual(arg7, sp_reg + 24)) != 0) {
    113                        goto done_syscall;
    114                    }
    115                    /* fall through */
    116                case 6:
    117                    if ((ret = get_user_ual(arg6, sp_reg + 20)) != 0) {
    118                        goto done_syscall;
    119                    }
    120                    /* fall through */
    121                case 5:
    122                    if ((ret = get_user_ual(arg5, sp_reg + 16)) != 0) {
    123                        goto done_syscall;
    124                    }
    125                    /* fall through */
    126                default:
    127                    break;
    128                }
    129                ret = do_syscall(env, env->active_tc.gpr[2],
    130                                 env->active_tc.gpr[4],
    131                                 env->active_tc.gpr[5],
    132                                 env->active_tc.gpr[6],
    133                                 env->active_tc.gpr[7],
    134                                 arg5, arg6, arg7, arg8);
    135            }
    136done_syscall:
    137# else
    138            ret = do_syscall(env, env->active_tc.gpr[2],
    139                             env->active_tc.gpr[4], env->active_tc.gpr[5],
    140                             env->active_tc.gpr[6], env->active_tc.gpr[7],
    141                             env->active_tc.gpr[8], env->active_tc.gpr[9],
    142                             env->active_tc.gpr[10], env->active_tc.gpr[11]);
    143# endif /* O32 */
    144            if (ret == -TARGET_ERESTARTSYS) {
    145                env->active_tc.PC -= 4;
    146                break;
    147            }
    148            if (ret == -TARGET_QEMU_ESIGRETURN) {
    149                /* Returning from a successful sigreturn syscall.
    150                   Avoid clobbering register state.  */
    151                break;
    152            }
    153            if ((abi_ulong)ret >= (abi_ulong)-1133) {
    154                env->active_tc.gpr[7] = 1; /* error flag */
    155                ret = -ret;
    156            } else {
    157                env->active_tc.gpr[7] = 0; /* error flag */
    158            }
    159            env->active_tc.gpr[2] = ret;
    160            break;
    161        case EXCP_TLBL:
    162        case EXCP_TLBS:
    163        case EXCP_AdEL:
    164        case EXCP_AdES:
    165            info.si_signo = TARGET_SIGSEGV;
    166            info.si_errno = 0;
    167            /* XXX: check env->error_code */
    168            info.si_code = TARGET_SEGV_MAPERR;
    169            info._sifields._sigfault._addr = env->CP0_BadVAddr;
    170            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
    171            break;
    172        case EXCP_CpU:
    173        case EXCP_RI:
    174            info.si_signo = TARGET_SIGILL;
    175            info.si_errno = 0;
    176            info.si_code = 0;
    177            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
    178            break;
    179        case EXCP_INTERRUPT:
    180            /* just indicate that signals should be handled asap */
    181            break;
    182        case EXCP_DEBUG:
    183            info.si_signo = TARGET_SIGTRAP;
    184            info.si_errno = 0;
    185            info.si_code = TARGET_TRAP_BRKPT;
    186            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
    187            break;
    188        case EXCP_DSPDIS:
    189            info.si_signo = TARGET_SIGILL;
    190            info.si_errno = 0;
    191            info.si_code = TARGET_ILL_ILLOPC;
    192            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
    193            break;
    194        case EXCP_FPE:
    195            info.si_signo = TARGET_SIGFPE;
    196            info.si_errno = 0;
    197            info.si_code = TARGET_FPE_FLTUNK;
    198            if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) {
    199                info.si_code = TARGET_FPE_FLTINV;
    200            } else if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_DIV0) {
    201                info.si_code = TARGET_FPE_FLTDIV;
    202            } else if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_OVERFLOW) {
    203                info.si_code = TARGET_FPE_FLTOVF;
    204            } else if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_UNDERFLOW) {
    205                info.si_code = TARGET_FPE_FLTUND;
    206            } else if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INEXACT) {
    207                info.si_code = TARGET_FPE_FLTRES;
    208            }
    209            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
    210            break;
    211        /* The code below was inspired by the MIPS Linux kernel trap
    212         * handling code in arch/mips/kernel/traps.c.
    213         */
    214        case EXCP_BREAK:
    215            {
    216                abi_ulong trap_instr;
    217                unsigned int code;
    218
    219                if (env->hflags & MIPS_HFLAG_M16) {
    220                    if (env->insn_flags & ASE_MICROMIPS) {
    221                        /* microMIPS mode */
    222                        ret = get_user_u16(trap_instr, env->active_tc.PC);
    223                        if (ret != 0) {
    224                            goto error;
    225                        }
    226
    227                        if ((trap_instr >> 10) == 0x11) {
    228                            /* 16-bit instruction */
    229                            code = trap_instr & 0xf;
    230                        } else {
    231                            /* 32-bit instruction */
    232                            abi_ulong instr_lo;
    233
    234                            ret = get_user_u16(instr_lo,
    235                                               env->active_tc.PC + 2);
    236                            if (ret != 0) {
    237                                goto error;
    238                            }
    239                            trap_instr = (trap_instr << 16) | instr_lo;
    240                            code = ((trap_instr >> 6) & ((1 << 20) - 1));
    241                            /* Unfortunately, microMIPS also suffers from
    242                               the old assembler bug...  */
    243                            if (code >= (1 << 10)) {
    244                                code >>= 10;
    245                            }
    246                        }
    247                    } else {
    248                        /* MIPS16e mode */
    249                        ret = get_user_u16(trap_instr, env->active_tc.PC);
    250                        if (ret != 0) {
    251                            goto error;
    252                        }
    253                        code = (trap_instr >> 6) & 0x3f;
    254                    }
    255                } else {
    256                    ret = get_user_u32(trap_instr, env->active_tc.PC);
    257                    if (ret != 0) {
    258                        goto error;
    259                    }
    260
    261                    /* As described in the original Linux kernel code, the
    262                     * below checks on 'code' are to work around an old
    263                     * assembly bug.
    264                     */
    265                    code = ((trap_instr >> 6) & ((1 << 20) - 1));
    266                    if (code >= (1 << 10)) {
    267                        code >>= 10;
    268                    }
    269                }
    270
    271                if (do_break(env, &info, code) != 0) {
    272                    goto error;
    273                }
    274            }
    275            break;
    276        case EXCP_TRAP:
    277            {
    278                abi_ulong trap_instr;
    279                unsigned int code = 0;
    280
    281                if (env->hflags & MIPS_HFLAG_M16) {
    282                    /* microMIPS mode */
    283                    abi_ulong instr[2];
    284
    285                    ret = get_user_u16(instr[0], env->active_tc.PC) ||
    286                          get_user_u16(instr[1], env->active_tc.PC + 2);
    287
    288                    trap_instr = (instr[0] << 16) | instr[1];
    289                } else {
    290                    ret = get_user_u32(trap_instr, env->active_tc.PC);
    291                }
    292
    293                if (ret != 0) {
    294                    goto error;
    295                }
    296
    297                /* The immediate versions don't provide a code.  */
    298                if (!(trap_instr & 0xFC000000)) {
    299                    if (env->hflags & MIPS_HFLAG_M16) {
    300                        /* microMIPS mode */
    301                        code = ((trap_instr >> 12) & ((1 << 4) - 1));
    302                    } else {
    303                        code = ((trap_instr >> 6) & ((1 << 10) - 1));
    304                    }
    305                }
    306
    307                if (do_break(env, &info, code) != 0) {
    308                    goto error;
    309                }
    310            }
    311            break;
    312        case EXCP_ATOMIC:
    313            cpu_exec_step_atomic(cs);
    314            break;
    315        default:
    316error:
    317            EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
    318            abort();
    319        }
    320        process_pending_signals(env);
    321    }
    322}
    323
    324void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
    325{
    326    CPUState *cpu = env_cpu(env);
    327    TaskState *ts = cpu->opaque;
    328    struct image_info *info = ts->info;
    329    int i;
    330
    331    struct mode_req {
    332        bool single;
    333        bool soft;
    334        bool fr1;
    335        bool frdefault;
    336        bool fre;
    337    };
    338
    339    static const struct mode_req fpu_reqs[] = {
    340        [MIPS_ABI_FP_ANY]    = { true,  true,  true,  true,  true  },
    341        [MIPS_ABI_FP_DOUBLE] = { false, false, false, true,  true  },
    342        [MIPS_ABI_FP_SINGLE] = { true,  false, false, false, false },
    343        [MIPS_ABI_FP_SOFT]   = { false, true,  false, false, false },
    344        [MIPS_ABI_FP_OLD_64] = { false, false, false, false, false },
    345        [MIPS_ABI_FP_XX]     = { false, false, true,  true,  true  },
    346        [MIPS_ABI_FP_64]     = { false, false, true,  false, false },
    347        [MIPS_ABI_FP_64A]    = { false, false, true,  false, true  }
    348    };
    349
    350    /*
    351     * Mode requirements when .MIPS.abiflags is not present in the ELF.
    352     * Not present means that everything is acceptable except FR1.
    353     */
    354    static struct mode_req none_req = { true, true, false, true, true };
    355
    356    struct mode_req prog_req;
    357    struct mode_req interp_req;
    358
    359    for(i = 0; i < 32; i++) {
    360        env->active_tc.gpr[i] = regs->regs[i];
    361    }
    362    env->active_tc.PC = regs->cp0_epc & ~(target_ulong)1;
    363    if (regs->cp0_epc & 1) {
    364        env->hflags |= MIPS_HFLAG_M16;
    365    }
    366
    367#ifdef TARGET_ABI_MIPSO32
    368# define MAX_FP_ABI MIPS_ABI_FP_64A
    369#else
    370# define MAX_FP_ABI MIPS_ABI_FP_SOFT
    371#endif
    372     if ((info->fp_abi > MAX_FP_ABI && info->fp_abi != MIPS_ABI_FP_UNKNOWN)
    373        || (info->interp_fp_abi > MAX_FP_ABI &&
    374            info->interp_fp_abi != MIPS_ABI_FP_UNKNOWN)) {
    375        fprintf(stderr, "qemu: Unexpected FPU mode\n");
    376        exit(1);
    377    }
    378
    379    prog_req = (info->fp_abi == MIPS_ABI_FP_UNKNOWN) ? none_req
    380                                            : fpu_reqs[info->fp_abi];
    381    interp_req = (info->interp_fp_abi == MIPS_ABI_FP_UNKNOWN) ? none_req
    382                                            : fpu_reqs[info->interp_fp_abi];
    383
    384    prog_req.single &= interp_req.single;
    385    prog_req.soft &= interp_req.soft;
    386    prog_req.fr1 &= interp_req.fr1;
    387    prog_req.frdefault &= interp_req.frdefault;
    388    prog_req.fre &= interp_req.fre;
    389
    390    bool cpu_has_mips_r2_r6 = env->insn_flags & ISA_MIPS_R2 ||
    391                              env->insn_flags & ISA_MIPS_R6;
    392
    393    if (prog_req.fre && !prog_req.frdefault && !prog_req.fr1) {
    394        env->CP0_Config5 |= (1 << CP0C5_FRE);
    395        if (env->active_fpu.fcr0 & (1 << FCR0_FREP)) {
    396            env->hflags |= MIPS_HFLAG_FRE;
    397        }
    398    } else if ((prog_req.fr1 && prog_req.frdefault) ||
    399         (prog_req.single && !prog_req.frdefault)) {
    400        if ((env->active_fpu.fcr0 & (1 << FCR0_F64)
    401            && cpu_has_mips_r2_r6) || prog_req.fr1) {
    402            env->CP0_Status |= (1 << CP0St_FR);
    403            env->hflags |= MIPS_HFLAG_F64;
    404        }
    405    } else  if (!prog_req.fre && !prog_req.frdefault &&
    406          !prog_req.fr1 && !prog_req.single && !prog_req.soft) {
    407        fprintf(stderr, "qemu: Can't find a matching FPU mode\n");
    408        exit(1);
    409    }
    410
    411    if (env->insn_flags & ISA_NANOMIPS32) {
    412        return;
    413    }
    414    if (((info->elf_flags & EF_MIPS_NAN2008) != 0) !=
    415        ((env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) != 0)) {
    416        if ((env->active_fpu.fcr31_rw_bitmask &
    417              (1 << FCR31_NAN2008)) == 0) {
    418            fprintf(stderr, "ELF binary's NaN mode not supported by CPU\n");
    419            exit(1);
    420        }
    421        if ((info->elf_flags & EF_MIPS_NAN2008) != 0) {
    422            env->active_fpu.fcr31 |= (1 << FCR31_NAN2008);
    423        } else {
    424            env->active_fpu.fcr31 &= ~(1 << FCR31_NAN2008);
    425        }
    426        restore_snan_bit_mode(env);
    427    }
    428}