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