qemu/linux-user/ppc/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
  25static inline uint64_t cpu_ppc_get_tb(CPUPPCState *env)
  26{
  27    return cpu_get_host_ticks();
  28}
  29
  30uint64_t cpu_ppc_load_tbl(CPUPPCState *env)
  31{
  32    return cpu_ppc_get_tb(env);
  33}
  34
  35uint32_t cpu_ppc_load_tbu(CPUPPCState *env)
  36{
  37    return cpu_ppc_get_tb(env) >> 32;
  38}
  39
  40uint64_t cpu_ppc_load_atbl(CPUPPCState *env)
  41{
  42    return cpu_ppc_get_tb(env);
  43}
  44
  45uint32_t cpu_ppc_load_atbu(CPUPPCState *env)
  46{
  47    return cpu_ppc_get_tb(env) >> 32;
  48}
  49
  50uint32_t cpu_ppc601_load_rtcu(CPUPPCState *env)
  51__attribute__ (( alias ("cpu_ppc_load_tbu") ));
  52
  53uint32_t cpu_ppc601_load_rtcl(CPUPPCState *env)
  54{
  55    return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
  56}
  57
  58/* XXX: to be fixed */
  59int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp)
  60{
  61    return -1;
  62}
  63
  64int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val)
  65{
  66    return -1;
  67}
  68
  69void cpu_loop(CPUPPCState *env)
  70{
  71    CPUState *cs = env_cpu(env);
  72    target_siginfo_t info;
  73    int trapnr;
  74    target_ulong ret;
  75
  76    for(;;) {
  77        bool arch_interrupt;
  78
  79        cpu_exec_start(cs);
  80        trapnr = cpu_exec(cs);
  81        cpu_exec_end(cs);
  82        process_queued_cpu_work(cs);
  83
  84        arch_interrupt = true;
  85        switch (trapnr) {
  86        case POWERPC_EXCP_NONE:
  87            /* Just go on */
  88            break;
  89        case POWERPC_EXCP_CRITICAL: /* Critical input                        */
  90            cpu_abort(cs, "Critical interrupt while in user mode. "
  91                      "Aborting\n");
  92            break;
  93        case POWERPC_EXCP_MCHECK:   /* Machine check exception               */
  94            cpu_abort(cs, "Machine check exception while in user mode. "
  95                      "Aborting\n");
  96            break;
  97        case POWERPC_EXCP_DSI:      /* Data storage exception                */
  98            /* XXX: check this. Seems bugged */
  99            switch (env->error_code & 0xFF000000) {
 100            case 0x40000000:
 101            case 0x42000000:
 102                info.si_signo = TARGET_SIGSEGV;
 103                info.si_errno = 0;
 104                info.si_code = TARGET_SEGV_MAPERR;
 105                break;
 106            case 0x04000000:
 107                info.si_signo = TARGET_SIGILL;
 108                info.si_errno = 0;
 109                info.si_code = TARGET_ILL_ILLADR;
 110                break;
 111            case 0x08000000:
 112                info.si_signo = TARGET_SIGSEGV;
 113                info.si_errno = 0;
 114                info.si_code = TARGET_SEGV_ACCERR;
 115                break;
 116            default:
 117                /* Let's send a regular segfault... */
 118                EXCP_DUMP(env, "Invalid segfault errno (%02x)\n",
 119                          env->error_code);
 120                info.si_signo = TARGET_SIGSEGV;
 121                info.si_errno = 0;
 122                info.si_code = TARGET_SEGV_MAPERR;
 123                break;
 124            }
 125            info._sifields._sigfault._addr = env->spr[SPR_DAR];
 126            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 127            break;
 128        case POWERPC_EXCP_ISI:      /* Instruction storage exception         */
 129            /* XXX: check this */
 130            switch (env->error_code & 0xFF000000) {
 131            case 0x40000000:
 132                info.si_signo = TARGET_SIGSEGV;
 133            info.si_errno = 0;
 134                info.si_code = TARGET_SEGV_MAPERR;
 135                break;
 136            case 0x10000000:
 137            case 0x08000000:
 138                info.si_signo = TARGET_SIGSEGV;
 139                info.si_errno = 0;
 140                info.si_code = TARGET_SEGV_ACCERR;
 141                break;
 142            default:
 143                /* Let's send a regular segfault... */
 144                EXCP_DUMP(env, "Invalid segfault errno (%02x)\n",
 145                          env->error_code);
 146                info.si_signo = TARGET_SIGSEGV;
 147                info.si_errno = 0;
 148                info.si_code = TARGET_SEGV_MAPERR;
 149                break;
 150            }
 151            info._sifields._sigfault._addr = env->nip - 4;
 152            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 153            break;
 154        case POWERPC_EXCP_EXTERNAL: /* External input                        */
 155            cpu_abort(cs, "External interrupt while in user mode. "
 156                      "Aborting\n");
 157            break;
 158        case POWERPC_EXCP_ALIGN:    /* Alignment exception                   */
 159            /* XXX: check this */
 160            info.si_signo = TARGET_SIGBUS;
 161            info.si_errno = 0;
 162            info.si_code = TARGET_BUS_ADRALN;
 163            info._sifields._sigfault._addr = env->nip;
 164            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 165            break;
 166        case POWERPC_EXCP_PROGRAM:  /* Program exception                     */
 167        case POWERPC_EXCP_HV_EMU:   /* HV emulation                          */
 168            /* XXX: check this */
 169            switch (env->error_code & ~0xF) {
 170            case POWERPC_EXCP_FP:
 171                info.si_signo = TARGET_SIGFPE;
 172                info.si_errno = 0;
 173                switch (env->error_code & 0xF) {
 174                case POWERPC_EXCP_FP_OX:
 175                    info.si_code = TARGET_FPE_FLTOVF;
 176                    break;
 177                case POWERPC_EXCP_FP_UX:
 178                    info.si_code = TARGET_FPE_FLTUND;
 179                    break;
 180                case POWERPC_EXCP_FP_ZX:
 181                case POWERPC_EXCP_FP_VXZDZ:
 182                    info.si_code = TARGET_FPE_FLTDIV;
 183                    break;
 184                case POWERPC_EXCP_FP_XX:
 185                    info.si_code = TARGET_FPE_FLTRES;
 186                    break;
 187                case POWERPC_EXCP_FP_VXSOFT:
 188                    info.si_code = TARGET_FPE_FLTINV;
 189                    break;
 190                case POWERPC_EXCP_FP_VXSNAN:
 191                case POWERPC_EXCP_FP_VXISI:
 192                case POWERPC_EXCP_FP_VXIDI:
 193                case POWERPC_EXCP_FP_VXIMZ:
 194                case POWERPC_EXCP_FP_VXVC:
 195                case POWERPC_EXCP_FP_VXSQRT:
 196                case POWERPC_EXCP_FP_VXCVI:
 197                    info.si_code = TARGET_FPE_FLTSUB;
 198                    break;
 199                default:
 200                    EXCP_DUMP(env, "Unknown floating point exception (%02x)\n",
 201                              env->error_code);
 202                    break;
 203                }
 204                break;
 205            case POWERPC_EXCP_INVAL:
 206                info.si_signo = TARGET_SIGILL;
 207                info.si_errno = 0;
 208                switch (env->error_code & 0xF) {
 209                case POWERPC_EXCP_INVAL_INVAL:
 210                    info.si_code = TARGET_ILL_ILLOPC;
 211                    break;
 212                case POWERPC_EXCP_INVAL_LSWX:
 213                    info.si_code = TARGET_ILL_ILLOPN;
 214                    break;
 215                case POWERPC_EXCP_INVAL_SPR:
 216                    info.si_code = TARGET_ILL_PRVREG;
 217                    break;
 218                case POWERPC_EXCP_INVAL_FP:
 219                    info.si_code = TARGET_ILL_COPROC;
 220                    break;
 221                default:
 222                    EXCP_DUMP(env, "Unknown invalid operation (%02x)\n",
 223                              env->error_code & 0xF);
 224                    info.si_code = TARGET_ILL_ILLADR;
 225                    break;
 226                }
 227                break;
 228            case POWERPC_EXCP_PRIV:
 229                info.si_signo = TARGET_SIGILL;
 230                info.si_errno = 0;
 231                switch (env->error_code & 0xF) {
 232                case POWERPC_EXCP_PRIV_OPC:
 233                    info.si_code = TARGET_ILL_PRVOPC;
 234                    break;
 235                case POWERPC_EXCP_PRIV_REG:
 236                    info.si_code = TARGET_ILL_PRVREG;
 237                    break;
 238                default:
 239                    EXCP_DUMP(env, "Unknown privilege violation (%02x)\n",
 240                              env->error_code & 0xF);
 241                    info.si_code = TARGET_ILL_PRVOPC;
 242                    break;
 243                }
 244                break;
 245            case POWERPC_EXCP_TRAP:
 246                cpu_abort(cs, "Tried to call a TRAP\n");
 247                break;
 248            default:
 249                /* Should not happen ! */
 250                cpu_abort(cs, "Unknown program exception (%02x)\n",
 251                          env->error_code);
 252                break;
 253            }
 254            info._sifields._sigfault._addr = env->nip;
 255            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 256            break;
 257        case POWERPC_EXCP_FPU:      /* Floating-point unavailable exception  */
 258            info.si_signo = TARGET_SIGILL;
 259            info.si_errno = 0;
 260            info.si_code = TARGET_ILL_COPROC;
 261            info._sifields._sigfault._addr = env->nip;
 262            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 263            break;
 264        case POWERPC_EXCP_SYSCALL:  /* System call exception                 */
 265            cpu_abort(cs, "Syscall exception while in user mode. "
 266                      "Aborting\n");
 267            break;
 268        case POWERPC_EXCP_APU:      /* Auxiliary processor unavailable       */
 269            info.si_signo = TARGET_SIGILL;
 270            info.si_errno = 0;
 271            info.si_code = TARGET_ILL_COPROC;
 272            info._sifields._sigfault._addr = env->nip;
 273            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 274            break;
 275        case POWERPC_EXCP_DECR:     /* Decrementer exception                 */
 276            cpu_abort(cs, "Decrementer interrupt while in user mode. "
 277                      "Aborting\n");
 278            break;
 279        case POWERPC_EXCP_FIT:      /* Fixed-interval timer interrupt        */
 280            cpu_abort(cs, "Fix interval timer interrupt while in user mode. "
 281                      "Aborting\n");
 282            break;
 283        case POWERPC_EXCP_WDT:      /* Watchdog timer interrupt              */
 284            cpu_abort(cs, "Watchdog timer interrupt while in user mode. "
 285                      "Aborting\n");
 286            break;
 287        case POWERPC_EXCP_DTLB:     /* Data TLB error                        */
 288            cpu_abort(cs, "Data TLB exception while in user mode. "
 289                      "Aborting\n");
 290            break;
 291        case POWERPC_EXCP_ITLB:     /* Instruction TLB error                 */
 292            cpu_abort(cs, "Instruction TLB exception while in user mode. "
 293                      "Aborting\n");
 294            break;
 295        case POWERPC_EXCP_SPEU:     /* SPE/embedded floating-point unavail.  */
 296            info.si_signo = TARGET_SIGILL;
 297            info.si_errno = 0;
 298            info.si_code = TARGET_ILL_COPROC;
 299            info._sifields._sigfault._addr = env->nip;
 300            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 301            break;
 302        case POWERPC_EXCP_EFPDI:    /* Embedded floating-point data IRQ      */
 303            cpu_abort(cs, "Embedded floating-point data IRQ not handled\n");
 304            break;
 305        case POWERPC_EXCP_EFPRI:    /* Embedded floating-point round IRQ     */
 306            cpu_abort(cs, "Embedded floating-point round IRQ not handled\n");
 307            break;
 308        case POWERPC_EXCP_EPERFM:   /* Embedded performance monitor IRQ      */
 309            cpu_abort(cs, "Performance monitor exception not handled\n");
 310            break;
 311        case POWERPC_EXCP_DOORI:    /* Embedded doorbell interrupt           */
 312            cpu_abort(cs, "Doorbell interrupt while in user mode. "
 313                       "Aborting\n");
 314            break;
 315        case POWERPC_EXCP_DOORCI:   /* Embedded doorbell critical interrupt  */
 316            cpu_abort(cs, "Doorbell critical interrupt while in user mode. "
 317                      "Aborting\n");
 318            break;
 319        case POWERPC_EXCP_RESET:    /* System reset exception                */
 320            cpu_abort(cs, "Reset interrupt while in user mode. "
 321                      "Aborting\n");
 322            break;
 323        case POWERPC_EXCP_DSEG:     /* Data segment exception                */
 324            cpu_abort(cs, "Data segment exception while in user mode. "
 325                      "Aborting\n");
 326            break;
 327        case POWERPC_EXCP_ISEG:     /* Instruction segment exception         */
 328            cpu_abort(cs, "Instruction segment exception "
 329                      "while in user mode. Aborting\n");
 330            break;
 331        /* PowerPC 64 with hypervisor mode support */
 332        case POWERPC_EXCP_HDECR:    /* Hypervisor decrementer exception      */
 333            cpu_abort(cs, "Hypervisor decrementer interrupt "
 334                      "while in user mode. Aborting\n");
 335            break;
 336        case POWERPC_EXCP_TRACE:    /* Trace exception                       */
 337            /* Nothing to do:
 338             * we use this exception to emulate step-by-step execution mode.
 339             */
 340            break;
 341        /* PowerPC 64 with hypervisor mode support */
 342        case POWERPC_EXCP_HDSI:     /* Hypervisor data storage exception     */
 343            cpu_abort(cs, "Hypervisor data storage exception "
 344                      "while in user mode. Aborting\n");
 345            break;
 346        case POWERPC_EXCP_HISI:     /* Hypervisor instruction storage excp   */
 347            cpu_abort(cs, "Hypervisor instruction storage exception "
 348                      "while in user mode. Aborting\n");
 349            break;
 350        case POWERPC_EXCP_HDSEG:    /* Hypervisor data segment exception     */
 351            cpu_abort(cs, "Hypervisor data segment exception "
 352                      "while in user mode. Aborting\n");
 353            break;
 354        case POWERPC_EXCP_HISEG:    /* Hypervisor instruction segment excp   */
 355            cpu_abort(cs, "Hypervisor instruction segment exception "
 356                      "while in user mode. Aborting\n");
 357            break;
 358        case POWERPC_EXCP_VPU:      /* Vector unavailable exception          */
 359            info.si_signo = TARGET_SIGILL;
 360            info.si_errno = 0;
 361            info.si_code = TARGET_ILL_COPROC;
 362            info._sifields._sigfault._addr = env->nip;
 363            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 364            break;
 365        case POWERPC_EXCP_PIT:      /* Programmable interval timer IRQ       */
 366            cpu_abort(cs, "Programmable interval timer interrupt "
 367                      "while in user mode. Aborting\n");
 368            break;
 369        case POWERPC_EXCP_IO:       /* IO error exception                    */
 370            cpu_abort(cs, "IO error exception while in user mode. "
 371                      "Aborting\n");
 372            break;
 373        case POWERPC_EXCP_RUNM:     /* Run mode exception                    */
 374            cpu_abort(cs, "Run mode exception while in user mode. "
 375                      "Aborting\n");
 376            break;
 377        case POWERPC_EXCP_EMUL:     /* Emulation trap exception              */
 378            cpu_abort(cs, "Emulation trap exception not handled\n");
 379            break;
 380        case POWERPC_EXCP_IFTLB:    /* Instruction fetch TLB error           */
 381            cpu_abort(cs, "Instruction fetch TLB exception "
 382                      "while in user-mode. Aborting");
 383            break;
 384        case POWERPC_EXCP_DLTLB:    /* Data load TLB miss                    */
 385            cpu_abort(cs, "Data load TLB exception while in user-mode. "
 386                      "Aborting");
 387            break;
 388        case POWERPC_EXCP_DSTLB:    /* Data store TLB miss                   */
 389            cpu_abort(cs, "Data store TLB exception while in user-mode. "
 390                      "Aborting");
 391            break;
 392        case POWERPC_EXCP_FPA:      /* Floating-point assist exception       */
 393            cpu_abort(cs, "Floating-point assist exception not handled\n");
 394            break;
 395        case POWERPC_EXCP_IABR:     /* Instruction address breakpoint        */
 396            cpu_abort(cs, "Instruction address breakpoint exception "
 397                      "not handled\n");
 398            break;
 399        case POWERPC_EXCP_SMI:      /* System management interrupt           */
 400            cpu_abort(cs, "System management interrupt while in user mode. "
 401                      "Aborting\n");
 402            break;
 403        case POWERPC_EXCP_THERM:    /* Thermal interrupt                     */
 404            cpu_abort(cs, "Thermal interrupt interrupt while in user mode. "
 405                      "Aborting\n");
 406            break;
 407        case POWERPC_EXCP_PERFM:   /* Embedded performance monitor IRQ      */
 408            cpu_abort(cs, "Performance monitor exception not handled\n");
 409            break;
 410        case POWERPC_EXCP_VPUA:     /* Vector assist exception               */
 411            cpu_abort(cs, "Vector assist exception not handled\n");
 412            break;
 413        case POWERPC_EXCP_SOFTP:    /* Soft patch exception                  */
 414            cpu_abort(cs, "Soft patch exception not handled\n");
 415            break;
 416        case POWERPC_EXCP_MAINT:    /* Maintenance exception                 */
 417            cpu_abort(cs, "Maintenance exception while in user mode. "
 418                      "Aborting\n");
 419            break;
 420        case POWERPC_EXCP_STOP:     /* stop translation                      */
 421            /* We did invalidate the instruction cache. Go on */
 422            break;
 423        case POWERPC_EXCP_BRANCH:   /* branch instruction:                   */
 424            /* We just stopped because of a branch. Go on */
 425            break;
 426        case POWERPC_EXCP_SYSCALL_USER:
 427            /* system call in user-mode emulation */
 428            /* WARNING:
 429             * PPC ABI uses overflow flag in cr0 to signal an error
 430             * in syscalls.
 431             */
 432            env->crf[0] &= ~0x1;
 433            env->nip += 4;
 434            ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
 435                             env->gpr[5], env->gpr[6], env->gpr[7],
 436                             env->gpr[8], 0, 0);
 437            if (ret == -TARGET_ERESTARTSYS) {
 438                env->nip -= 4;
 439                break;
 440            }
 441            if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) {
 442                /* Returning from a successful sigreturn syscall.
 443                   Avoid corrupting register state.  */
 444                break;
 445            }
 446            if (ret > (target_ulong)(-515)) {
 447                env->crf[0] |= 0x1;
 448                ret = -ret;
 449            }
 450            env->gpr[3] = ret;
 451            break;
 452        case EXCP_DEBUG:
 453            info.si_signo = TARGET_SIGTRAP;
 454            info.si_errno = 0;
 455            info.si_code = TARGET_TRAP_BRKPT;
 456            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 457            break;
 458        case EXCP_INTERRUPT:
 459            /* just indicate that signals should be handled asap */
 460            break;
 461        case EXCP_ATOMIC:
 462            cpu_exec_step_atomic(cs);
 463            arch_interrupt = false;
 464            break;
 465        default:
 466            cpu_abort(cs, "Unknown exception 0x%x. Aborting\n", trapnr);
 467            break;
 468        }
 469        process_pending_signals(env);
 470
 471        /* Most of the traps imply a transition through kernel mode,
 472         * which implies an REI instruction has been executed.  Which
 473         * means that RX and LOCK_ADDR should be cleared.  But there
 474         * are a few exceptions for traps internal to QEMU.
 475         */
 476        if (arch_interrupt) {
 477            env->reserve_addr = -1;
 478        }
 479    }
 480}
 481
 482void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
 483{
 484    int i;
 485
 486#if defined(TARGET_PPC64)
 487    int flag = (env->insns_flags2 & PPC2_BOOKE206) ? MSR_CM : MSR_SF;
 488#if defined(TARGET_ABI32)
 489    env->msr &= ~((target_ulong)1 << flag);
 490#else
 491    env->msr |= (target_ulong)1 << flag;
 492#endif
 493#endif
 494    env->nip = regs->nip;
 495    for(i = 0; i < 32; i++) {
 496        env->gpr[i] = regs->gpr[i];
 497    }
 498}
 499