qemu/target-ppc/excp_helper.c
<<
>>
Prefs
   1/*
   2 *  PowerPC exception emulation helpers for QEMU.
   3 *
   4 *  Copyright (c) 2003-2007 Jocelyn Mayer
   5 *
   6 * This library is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU Lesser General Public
   8 * License as published by the Free Software Foundation; either
   9 * version 2 of the License, or (at your option) any later version.
  10 *
  11 * This library 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 GNU
  14 * Lesser General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU Lesser General Public
  17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  18 */
  19#include "cpu.h"
  20#include "helper.h"
  21
  22#include "helper_regs.h"
  23
  24//#define DEBUG_OP
  25//#define DEBUG_EXCEPTIONS
  26
  27#ifdef DEBUG_EXCEPTIONS
  28#  define LOG_EXCP(...) qemu_log(__VA_ARGS__)
  29#else
  30#  define LOG_EXCP(...) do { } while (0)
  31#endif
  32
  33/*****************************************************************************/
  34/* PowerPC Hypercall emulation */
  35
  36void (*cpu_ppc_hypercall)(CPUPPCState *);
  37
  38/*****************************************************************************/
  39/* Exception processing */
  40#if defined(CONFIG_USER_ONLY)
  41void do_interrupt(CPUPPCState *env)
  42{
  43    env->exception_index = POWERPC_EXCP_NONE;
  44    env->error_code = 0;
  45}
  46
  47void ppc_hw_interrupt(CPUPPCState *env)
  48{
  49    env->exception_index = POWERPC_EXCP_NONE;
  50    env->error_code = 0;
  51}
  52#else /* defined(CONFIG_USER_ONLY) */
  53static inline void dump_syscall(CPUPPCState *env)
  54{
  55    qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 " r3=%016" PRIx64
  56                  " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
  57                  " nip=" TARGET_FMT_lx "\n",
  58                  ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3),
  59                  ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5),
  60                  ppc_dump_gpr(env, 6), env->nip);
  61}
  62
  63/* Note that this function should be greatly optimized
  64 * when called with a constant excp, from ppc_hw_interrupt
  65 */
  66static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp)
  67{
  68    target_ulong msr, new_msr, vector;
  69    int srr0, srr1, asrr0, asrr1;
  70    int lpes0, lpes1, lev;
  71
  72    if (0) {
  73        /* XXX: find a suitable condition to enable the hypervisor mode */
  74        lpes0 = (env->spr[SPR_LPCR] >> 1) & 1;
  75        lpes1 = (env->spr[SPR_LPCR] >> 2) & 1;
  76    } else {
  77        /* Those values ensure we won't enter the hypervisor mode */
  78        lpes0 = 0;
  79        lpes1 = 1;
  80    }
  81
  82    qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
  83                  " => %08x (%02x)\n", env->nip, excp, env->error_code);
  84
  85    /* new srr1 value excluding must-be-zero bits */
  86    msr = env->msr & ~0x783f0000ULL;
  87
  88    /* new interrupt handler msr */
  89    new_msr = env->msr & ((target_ulong)1 << MSR_ME);
  90
  91    /* target registers */
  92    srr0 = SPR_SRR0;
  93    srr1 = SPR_SRR1;
  94    asrr0 = -1;
  95    asrr1 = -1;
  96
  97    switch (excp) {
  98    case POWERPC_EXCP_NONE:
  99        /* Should never happen */
 100        return;
 101    case POWERPC_EXCP_CRITICAL:    /* Critical input                         */
 102        switch (excp_model) {
 103        case POWERPC_EXCP_40x:
 104            srr0 = SPR_40x_SRR2;
 105            srr1 = SPR_40x_SRR3;
 106            break;
 107        case POWERPC_EXCP_BOOKE:
 108            srr0 = SPR_BOOKE_CSRR0;
 109            srr1 = SPR_BOOKE_CSRR1;
 110            break;
 111        case POWERPC_EXCP_G2:
 112            break;
 113        default:
 114            goto excp_invalid;
 115        }
 116        goto store_next;
 117    case POWERPC_EXCP_MCHECK:    /* Machine check exception                  */
 118        if (msr_me == 0) {
 119            /* Machine check exception is not enabled.
 120             * Enter checkstop state.
 121             */
 122            if (qemu_log_enabled()) {
 123                qemu_log("Machine check while not allowed. "
 124                        "Entering checkstop state\n");
 125            } else {
 126                fprintf(stderr, "Machine check while not allowed. "
 127                        "Entering checkstop state\n");
 128            }
 129            env->halted = 1;
 130            env->interrupt_request |= CPU_INTERRUPT_EXITTB;
 131        }
 132        if (0) {
 133            /* XXX: find a suitable condition to enable the hypervisor mode */
 134            new_msr |= (target_ulong)MSR_HVB;
 135        }
 136
 137        /* machine check exceptions don't have ME set */
 138        new_msr &= ~((target_ulong)1 << MSR_ME);
 139
 140        /* XXX: should also have something loaded in DAR / DSISR */
 141        switch (excp_model) {
 142        case POWERPC_EXCP_40x:
 143            srr0 = SPR_40x_SRR2;
 144            srr1 = SPR_40x_SRR3;
 145            break;
 146        case POWERPC_EXCP_BOOKE:
 147            srr0 = SPR_BOOKE_MCSRR0;
 148            srr1 = SPR_BOOKE_MCSRR1;
 149            asrr0 = SPR_BOOKE_CSRR0;
 150            asrr1 = SPR_BOOKE_CSRR1;
 151            break;
 152        default:
 153            break;
 154        }
 155        goto store_next;
 156    case POWERPC_EXCP_DSI:       /* Data storage exception                   */
 157        LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
 158                 "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
 159        if (lpes1 == 0) {
 160            new_msr |= (target_ulong)MSR_HVB;
 161        }
 162        goto store_next;
 163    case POWERPC_EXCP_ISI:       /* Instruction storage exception            */
 164        LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
 165                 "\n", msr, env->nip);
 166        if (lpes1 == 0) {
 167            new_msr |= (target_ulong)MSR_HVB;
 168        }
 169        msr |= env->error_code;
 170        goto store_next;
 171    case POWERPC_EXCP_EXTERNAL:  /* External input                           */
 172        if (lpes0 == 1) {
 173            new_msr |= (target_ulong)MSR_HVB;
 174        }
 175        goto store_next;
 176    case POWERPC_EXCP_ALIGN:     /* Alignment exception                      */
 177        if (lpes1 == 0) {
 178            new_msr |= (target_ulong)MSR_HVB;
 179        }
 180        /* XXX: this is false */
 181        /* Get rS/rD and rA from faulting opcode */
 182        env->spr[SPR_DSISR] |= (cpu_ldl_code(env, (env->nip - 4))
 183                                & 0x03FF0000) >> 16;
 184        goto store_current;
 185    case POWERPC_EXCP_PROGRAM:   /* Program exception                        */
 186        switch (env->error_code & ~0xF) {
 187        case POWERPC_EXCP_FP:
 188            if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
 189                LOG_EXCP("Ignore floating point exception\n");
 190                env->exception_index = POWERPC_EXCP_NONE;
 191                env->error_code = 0;
 192                return;
 193            }
 194            if (lpes1 == 0) {
 195                new_msr |= (target_ulong)MSR_HVB;
 196            }
 197            msr |= 0x00100000;
 198            if (msr_fe0 == msr_fe1) {
 199                goto store_next;
 200            }
 201            msr |= 0x00010000;
 202            break;
 203        case POWERPC_EXCP_INVAL:
 204            LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
 205            if (lpes1 == 0) {
 206                new_msr |= (target_ulong)MSR_HVB;
 207            }
 208            msr |= 0x00080000;
 209            env->spr[SPR_BOOKE_ESR] = ESR_PIL;
 210            break;
 211        case POWERPC_EXCP_PRIV:
 212            if (lpes1 == 0) {
 213                new_msr |= (target_ulong)MSR_HVB;
 214            }
 215            msr |= 0x00040000;
 216            env->spr[SPR_BOOKE_ESR] = ESR_PPR;
 217            break;
 218        case POWERPC_EXCP_TRAP:
 219            if (lpes1 == 0) {
 220                new_msr |= (target_ulong)MSR_HVB;
 221            }
 222            msr |= 0x00020000;
 223            env->spr[SPR_BOOKE_ESR] = ESR_PTR;
 224            break;
 225        default:
 226            /* Should never occur */
 227            cpu_abort(env, "Invalid program exception %d. Aborting\n",
 228                      env->error_code);
 229            break;
 230        }
 231        goto store_current;
 232    case POWERPC_EXCP_FPU:       /* Floating-point unavailable exception     */
 233        if (lpes1 == 0) {
 234            new_msr |= (target_ulong)MSR_HVB;
 235        }
 236        goto store_current;
 237    case POWERPC_EXCP_SYSCALL:   /* System call exception                    */
 238        dump_syscall(env);
 239        lev = env->error_code;
 240        if ((lev == 1) && cpu_ppc_hypercall) {
 241            cpu_ppc_hypercall(env);
 242            return;
 243        }
 244        if (lev == 1 || (lpes0 == 0 && lpes1 == 0)) {
 245            new_msr |= (target_ulong)MSR_HVB;
 246        }
 247        goto store_next;
 248    case POWERPC_EXCP_APU:       /* Auxiliary processor unavailable          */
 249        goto store_current;
 250    case POWERPC_EXCP_DECR:      /* Decrementer exception                    */
 251        if (lpes1 == 0) {
 252            new_msr |= (target_ulong)MSR_HVB;
 253        }
 254        goto store_next;
 255    case POWERPC_EXCP_FIT:       /* Fixed-interval timer interrupt           */
 256        /* FIT on 4xx */
 257        LOG_EXCP("FIT exception\n");
 258        goto store_next;
 259    case POWERPC_EXCP_WDT:       /* Watchdog timer interrupt                 */
 260        LOG_EXCP("WDT exception\n");
 261        switch (excp_model) {
 262        case POWERPC_EXCP_BOOKE:
 263            srr0 = SPR_BOOKE_CSRR0;
 264            srr1 = SPR_BOOKE_CSRR1;
 265            break;
 266        default:
 267            break;
 268        }
 269        goto store_next;
 270    case POWERPC_EXCP_DTLB:      /* Data TLB error                           */
 271        goto store_next;
 272    case POWERPC_EXCP_ITLB:      /* Instruction TLB error                    */
 273        goto store_next;
 274    case POWERPC_EXCP_DEBUG:     /* Debug interrupt                          */
 275        switch (excp_model) {
 276        case POWERPC_EXCP_BOOKE:
 277            srr0 = SPR_BOOKE_DSRR0;
 278            srr1 = SPR_BOOKE_DSRR1;
 279            asrr0 = SPR_BOOKE_CSRR0;
 280            asrr1 = SPR_BOOKE_CSRR1;
 281            break;
 282        default:
 283            break;
 284        }
 285        /* XXX: TODO */
 286        cpu_abort(env, "Debug exception is not implemented yet !\n");
 287        goto store_next;
 288    case POWERPC_EXCP_SPEU:      /* SPE/embedded floating-point unavailable  */
 289        env->spr[SPR_BOOKE_ESR] = ESR_SPV;
 290        goto store_current;
 291    case POWERPC_EXCP_EFPDI:     /* Embedded floating-point data interrupt   */
 292        /* XXX: TODO */
 293        cpu_abort(env, "Embedded floating point data exception "
 294                  "is not implemented yet !\n");
 295        env->spr[SPR_BOOKE_ESR] = ESR_SPV;
 296        goto store_next;
 297    case POWERPC_EXCP_EFPRI:     /* Embedded floating-point round interrupt  */
 298        /* XXX: TODO */
 299        cpu_abort(env, "Embedded floating point round exception "
 300                  "is not implemented yet !\n");
 301        env->spr[SPR_BOOKE_ESR] = ESR_SPV;
 302        goto store_next;
 303    case POWERPC_EXCP_EPERFM:    /* Embedded performance monitor interrupt   */
 304        /* XXX: TODO */
 305        cpu_abort(env,
 306                  "Performance counter exception is not implemented yet !\n");
 307        goto store_next;
 308    case POWERPC_EXCP_DOORI:     /* Embedded doorbell interrupt              */
 309        goto store_next;
 310    case POWERPC_EXCP_DOORCI:    /* Embedded doorbell critical interrupt     */
 311        srr0 = SPR_BOOKE_CSRR0;
 312        srr1 = SPR_BOOKE_CSRR1;
 313        goto store_next;
 314    case POWERPC_EXCP_RESET:     /* System reset exception                   */
 315        if (msr_pow) {
 316            /* indicate that we resumed from power save mode */
 317            msr |= 0x10000;
 318        } else {
 319            new_msr &= ~((target_ulong)1 << MSR_ME);
 320        }
 321
 322        if (0) {
 323            /* XXX: find a suitable condition to enable the hypervisor mode */
 324            new_msr |= (target_ulong)MSR_HVB;
 325        }
 326        goto store_next;
 327    case POWERPC_EXCP_DSEG:      /* Data segment exception                   */
 328        if (lpes1 == 0) {
 329            new_msr |= (target_ulong)MSR_HVB;
 330        }
 331        goto store_next;
 332    case POWERPC_EXCP_ISEG:      /* Instruction segment exception            */
 333        if (lpes1 == 0) {
 334            new_msr |= (target_ulong)MSR_HVB;
 335        }
 336        goto store_next;
 337    case POWERPC_EXCP_HDECR:     /* Hypervisor decrementer exception         */
 338        srr0 = SPR_HSRR0;
 339        srr1 = SPR_HSRR1;
 340        new_msr |= (target_ulong)MSR_HVB;
 341        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
 342        goto store_next;
 343    case POWERPC_EXCP_TRACE:     /* Trace exception                          */
 344        if (lpes1 == 0) {
 345            new_msr |= (target_ulong)MSR_HVB;
 346        }
 347        goto store_next;
 348    case POWERPC_EXCP_HDSI:      /* Hypervisor data storage exception        */
 349        srr0 = SPR_HSRR0;
 350        srr1 = SPR_HSRR1;
 351        new_msr |= (target_ulong)MSR_HVB;
 352        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
 353        goto store_next;
 354    case POWERPC_EXCP_HISI:      /* Hypervisor instruction storage exception */
 355        srr0 = SPR_HSRR0;
 356        srr1 = SPR_HSRR1;
 357        new_msr |= (target_ulong)MSR_HVB;
 358        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
 359        goto store_next;
 360    case POWERPC_EXCP_HDSEG:     /* Hypervisor data segment exception        */
 361        srr0 = SPR_HSRR0;
 362        srr1 = SPR_HSRR1;
 363        new_msr |= (target_ulong)MSR_HVB;
 364        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
 365        goto store_next;
 366    case POWERPC_EXCP_HISEG:     /* Hypervisor instruction segment exception */
 367        srr0 = SPR_HSRR0;
 368        srr1 = SPR_HSRR1;
 369        new_msr |= (target_ulong)MSR_HVB;
 370        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
 371        goto store_next;
 372    case POWERPC_EXCP_VPU:       /* Vector unavailable exception             */
 373        if (lpes1 == 0) {
 374            new_msr |= (target_ulong)MSR_HVB;
 375        }
 376        goto store_current;
 377    case POWERPC_EXCP_PIT:       /* Programmable interval timer interrupt    */
 378        LOG_EXCP("PIT exception\n");
 379        goto store_next;
 380    case POWERPC_EXCP_IO:        /* IO error exception                       */
 381        /* XXX: TODO */
 382        cpu_abort(env, "601 IO error exception is not implemented yet !\n");
 383        goto store_next;
 384    case POWERPC_EXCP_RUNM:      /* Run mode exception                       */
 385        /* XXX: TODO */
 386        cpu_abort(env, "601 run mode exception is not implemented yet !\n");
 387        goto store_next;
 388    case POWERPC_EXCP_EMUL:      /* Emulation trap exception                 */
 389        /* XXX: TODO */
 390        cpu_abort(env, "602 emulation trap exception "
 391                  "is not implemented yet !\n");
 392        goto store_next;
 393    case POWERPC_EXCP_IFTLB:     /* Instruction fetch TLB error              */
 394        if (lpes1 == 0) { /* XXX: check this */
 395            new_msr |= (target_ulong)MSR_HVB;
 396        }
 397        switch (excp_model) {
 398        case POWERPC_EXCP_602:
 399        case POWERPC_EXCP_603:
 400        case POWERPC_EXCP_603E:
 401        case POWERPC_EXCP_G2:
 402            goto tlb_miss_tgpr;
 403        case POWERPC_EXCP_7x5:
 404            goto tlb_miss;
 405        case POWERPC_EXCP_74xx:
 406            goto tlb_miss_74xx;
 407        default:
 408            cpu_abort(env, "Invalid instruction TLB miss exception\n");
 409            break;
 410        }
 411        break;
 412    case POWERPC_EXCP_DLTLB:     /* Data load TLB miss                       */
 413        if (lpes1 == 0) { /* XXX: check this */
 414            new_msr |= (target_ulong)MSR_HVB;
 415        }
 416        switch (excp_model) {
 417        case POWERPC_EXCP_602:
 418        case POWERPC_EXCP_603:
 419        case POWERPC_EXCP_603E:
 420        case POWERPC_EXCP_G2:
 421            goto tlb_miss_tgpr;
 422        case POWERPC_EXCP_7x5:
 423            goto tlb_miss;
 424        case POWERPC_EXCP_74xx:
 425            goto tlb_miss_74xx;
 426        default:
 427            cpu_abort(env, "Invalid data load TLB miss exception\n");
 428            break;
 429        }
 430        break;
 431    case POWERPC_EXCP_DSTLB:     /* Data store TLB miss                      */
 432        if (lpes1 == 0) { /* XXX: check this */
 433            new_msr |= (target_ulong)MSR_HVB;
 434        }
 435        switch (excp_model) {
 436        case POWERPC_EXCP_602:
 437        case POWERPC_EXCP_603:
 438        case POWERPC_EXCP_603E:
 439        case POWERPC_EXCP_G2:
 440        tlb_miss_tgpr:
 441            /* Swap temporary saved registers with GPRs */
 442            if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
 443                new_msr |= (target_ulong)1 << MSR_TGPR;
 444                hreg_swap_gpr_tgpr(env);
 445            }
 446            goto tlb_miss;
 447        case POWERPC_EXCP_7x5:
 448        tlb_miss:
 449#if defined(DEBUG_SOFTWARE_TLB)
 450            if (qemu_log_enabled()) {
 451                const char *es;
 452                target_ulong *miss, *cmp;
 453                int en;
 454
 455                if (excp == POWERPC_EXCP_IFTLB) {
 456                    es = "I";
 457                    en = 'I';
 458                    miss = &env->spr[SPR_IMISS];
 459                    cmp = &env->spr[SPR_ICMP];
 460                } else {
 461                    if (excp == POWERPC_EXCP_DLTLB) {
 462                        es = "DL";
 463                    } else {
 464                        es = "DS";
 465                    }
 466                    en = 'D';
 467                    miss = &env->spr[SPR_DMISS];
 468                    cmp = &env->spr[SPR_DCMP];
 469                }
 470                qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
 471                         TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
 472                         TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
 473                         env->spr[SPR_HASH1], env->spr[SPR_HASH2],
 474                         env->error_code);
 475            }
 476#endif
 477            msr |= env->crf[0] << 28;
 478            msr |= env->error_code; /* key, D/I, S/L bits */
 479            /* Set way using a LRU mechanism */
 480            msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
 481            break;
 482        case POWERPC_EXCP_74xx:
 483        tlb_miss_74xx:
 484#if defined(DEBUG_SOFTWARE_TLB)
 485            if (qemu_log_enabled()) {
 486                const char *es;
 487                target_ulong *miss, *cmp;
 488                int en;
 489
 490                if (excp == POWERPC_EXCP_IFTLB) {
 491                    es = "I";
 492                    en = 'I';
 493                    miss = &env->spr[SPR_TLBMISS];
 494                    cmp = &env->spr[SPR_PTEHI];
 495                } else {
 496                    if (excp == POWERPC_EXCP_DLTLB) {
 497                        es = "DL";
 498                    } else {
 499                        es = "DS";
 500                    }
 501                    en = 'D';
 502                    miss = &env->spr[SPR_TLBMISS];
 503                    cmp = &env->spr[SPR_PTEHI];
 504                }
 505                qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
 506                         TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
 507                         env->error_code);
 508            }
 509#endif
 510            msr |= env->error_code; /* key bit */
 511            break;
 512        default:
 513            cpu_abort(env, "Invalid data store TLB miss exception\n");
 514            break;
 515        }
 516        goto store_next;
 517    case POWERPC_EXCP_FPA:       /* Floating-point assist exception          */
 518        /* XXX: TODO */
 519        cpu_abort(env, "Floating point assist exception "
 520                  "is not implemented yet !\n");
 521        goto store_next;
 522    case POWERPC_EXCP_DABR:      /* Data address breakpoint                  */
 523        /* XXX: TODO */
 524        cpu_abort(env, "DABR exception is not implemented yet !\n");
 525        goto store_next;
 526    case POWERPC_EXCP_IABR:      /* Instruction address breakpoint           */
 527        /* XXX: TODO */
 528        cpu_abort(env, "IABR exception is not implemented yet !\n");
 529        goto store_next;
 530    case POWERPC_EXCP_SMI:       /* System management interrupt              */
 531        /* XXX: TODO */
 532        cpu_abort(env, "SMI exception is not implemented yet !\n");
 533        goto store_next;
 534    case POWERPC_EXCP_THERM:     /* Thermal interrupt                        */
 535        /* XXX: TODO */
 536        cpu_abort(env, "Thermal management exception "
 537                  "is not implemented yet !\n");
 538        goto store_next;
 539    case POWERPC_EXCP_PERFM:     /* Embedded performance monitor interrupt   */
 540        if (lpes1 == 0) {
 541            new_msr |= (target_ulong)MSR_HVB;
 542        }
 543        /* XXX: TODO */
 544        cpu_abort(env,
 545                  "Performance counter exception is not implemented yet !\n");
 546        goto store_next;
 547    case POWERPC_EXCP_VPUA:      /* Vector assist exception                  */
 548        /* XXX: TODO */
 549        cpu_abort(env, "VPU assist exception is not implemented yet !\n");
 550        goto store_next;
 551    case POWERPC_EXCP_SOFTP:     /* Soft patch exception                     */
 552        /* XXX: TODO */
 553        cpu_abort(env,
 554                  "970 soft-patch exception is not implemented yet !\n");
 555        goto store_next;
 556    case POWERPC_EXCP_MAINT:     /* Maintenance exception                    */
 557        /* XXX: TODO */
 558        cpu_abort(env,
 559                  "970 maintenance exception is not implemented yet !\n");
 560        goto store_next;
 561    case POWERPC_EXCP_MEXTBR:    /* Maskable external breakpoint             */
 562        /* XXX: TODO */
 563        cpu_abort(env, "Maskable external exception "
 564                  "is not implemented yet !\n");
 565        goto store_next;
 566    case POWERPC_EXCP_NMEXTBR:   /* Non maskable external breakpoint         */
 567        /* XXX: TODO */
 568        cpu_abort(env, "Non maskable external exception "
 569                  "is not implemented yet !\n");
 570        goto store_next;
 571    default:
 572    excp_invalid:
 573        cpu_abort(env, "Invalid PowerPC exception %d. Aborting\n", excp);
 574        break;
 575    store_current:
 576        /* save current instruction location */
 577        env->spr[srr0] = env->nip - 4;
 578        break;
 579    store_next:
 580        /* save next instruction location */
 581        env->spr[srr0] = env->nip;
 582        break;
 583    }
 584    /* Save MSR */
 585    env->spr[srr1] = msr;
 586    /* If any alternate SRR register are defined, duplicate saved values */
 587    if (asrr0 != -1) {
 588        env->spr[asrr0] = env->spr[srr0];
 589    }
 590    if (asrr1 != -1) {
 591        env->spr[asrr1] = env->spr[srr1];
 592    }
 593    /* If we disactivated any translation, flush TLBs */
 594    if (msr & ((1 << MSR_IR) | (1 << MSR_DR))) {
 595        tlb_flush(env, 1);
 596    }
 597
 598    if (msr_ile) {
 599        new_msr |= (target_ulong)1 << MSR_LE;
 600    }
 601
 602    /* Jump to handler */
 603    vector = env->excp_vectors[excp];
 604    if (vector == (target_ulong)-1ULL) {
 605        cpu_abort(env, "Raised an exception without defined vector %d\n",
 606                  excp);
 607    }
 608    vector |= env->excp_prefix;
 609#if defined(TARGET_PPC64)
 610    if (excp_model == POWERPC_EXCP_BOOKE) {
 611        if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
 612            /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
 613            new_msr |= (target_ulong)1 << MSR_CM;
 614        } else {
 615            vector = (uint32_t)vector;
 616        }
 617    } else {
 618        if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) {
 619            vector = (uint32_t)vector;
 620        } else {
 621            new_msr |= (target_ulong)1 << MSR_SF;
 622        }
 623    }
 624#endif
 625    /* XXX: we don't use hreg_store_msr here as already have treated
 626     *      any special case that could occur. Just store MSR and update hflags
 627     */
 628    env->msr = new_msr & env->msr_mask;
 629    hreg_compute_hflags(env);
 630    env->nip = vector;
 631    /* Reset exception state */
 632    env->exception_index = POWERPC_EXCP_NONE;
 633    env->error_code = 0;
 634
 635    if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
 636        (env->mmu_model == POWERPC_MMU_BOOKE206)) {
 637        /* XXX: The BookE changes address space when switching modes,
 638                we should probably implement that as different MMU indexes,
 639                but for the moment we do it the slow way and flush all.  */
 640        tlb_flush(env, 1);
 641    }
 642}
 643
 644void do_interrupt(CPUPPCState *env)
 645{
 646    powerpc_excp(env, env->excp_model, env->exception_index);
 647}
 648
 649void ppc_hw_interrupt(CPUPPCState *env)
 650{
 651    int hdice;
 652
 653#if 0
 654    qemu_log_mask(CPU_LOG_INT, "%s: %p pending %08x req %08x me %d ee %d\n",
 655                __func__, env, env->pending_interrupts,
 656                env->interrupt_request, (int)msr_me, (int)msr_ee);
 657#endif
 658    /* External reset */
 659    if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
 660        env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
 661        powerpc_excp(env, env->excp_model, POWERPC_EXCP_RESET);
 662        return;
 663    }
 664    /* Machine check exception */
 665    if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
 666        env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
 667        powerpc_excp(env, env->excp_model, POWERPC_EXCP_MCHECK);
 668        return;
 669    }
 670#if 0 /* TODO */
 671    /* External debug exception */
 672    if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
 673        env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
 674        powerpc_excp(env, env->excp_model, POWERPC_EXCP_DEBUG);
 675        return;
 676    }
 677#endif
 678    if (0) {
 679        /* XXX: find a suitable condition to enable the hypervisor mode */
 680        hdice = env->spr[SPR_LPCR] & 1;
 681    } else {
 682        hdice = 0;
 683    }
 684    if ((msr_ee != 0 || msr_hv == 0 || msr_pr != 0) && hdice != 0) {
 685        /* Hypervisor decrementer exception */
 686        if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
 687            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
 688            powerpc_excp(env, env->excp_model, POWERPC_EXCP_HDECR);
 689            return;
 690        }
 691    }
 692    if (msr_ce != 0) {
 693        /* External critical interrupt */
 694        if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
 695            /* Taking a critical external interrupt does not clear the external
 696             * critical interrupt status
 697             */
 698#if 0
 699            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CEXT);
 700#endif
 701            powerpc_excp(env, env->excp_model, POWERPC_EXCP_CRITICAL);
 702            return;
 703        }
 704    }
 705    if (msr_ee != 0) {
 706        /* Watchdog timer on embedded PowerPC */
 707        if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
 708            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
 709            powerpc_excp(env, env->excp_model, POWERPC_EXCP_WDT);
 710            return;
 711        }
 712        if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
 713            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
 714            powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORCI);
 715            return;
 716        }
 717        /* Fixed interval timer on embedded PowerPC */
 718        if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
 719            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
 720            powerpc_excp(env, env->excp_model, POWERPC_EXCP_FIT);
 721            return;
 722        }
 723        /* Programmable interval timer on embedded PowerPC */
 724        if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
 725            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
 726            powerpc_excp(env, env->excp_model, POWERPC_EXCP_PIT);
 727            return;
 728        }
 729        /* Decrementer exception */
 730        if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
 731            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
 732            powerpc_excp(env, env->excp_model, POWERPC_EXCP_DECR);
 733            return;
 734        }
 735        /* External interrupt */
 736        if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
 737            /* Taking an external interrupt does not clear the external
 738             * interrupt status
 739             */
 740#if 0
 741            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT);
 742#endif
 743            powerpc_excp(env, env->excp_model, POWERPC_EXCP_EXTERNAL);
 744            return;
 745        }
 746        if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
 747            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
 748            powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORI);
 749            return;
 750        }
 751        if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
 752            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
 753            powerpc_excp(env, env->excp_model, POWERPC_EXCP_PERFM);
 754            return;
 755        }
 756        /* Thermal interrupt */
 757        if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
 758            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
 759            powerpc_excp(env, env->excp_model, POWERPC_EXCP_THERM);
 760            return;
 761        }
 762    }
 763}
 764#endif /* !CONFIG_USER_ONLY */
 765
 766#if defined(DEBUG_OP)
 767static void cpu_dump_rfi(target_ulong RA, target_ulong msr)
 768{
 769    qemu_log("Return from exception at " TARGET_FMT_lx " with flags "
 770             TARGET_FMT_lx "\n", RA, msr);
 771}
 772#endif
 773
 774/*****************************************************************************/
 775/* Exceptions processing helpers */
 776
 777void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
 778                                uint32_t error_code)
 779{
 780#if 0
 781    printf("Raise exception %3x code : %d\n", exception, error_code);
 782#endif
 783    env->exception_index = exception;
 784    env->error_code = error_code;
 785    cpu_loop_exit(env);
 786}
 787
 788void helper_raise_exception(CPUPPCState *env, uint32_t exception)
 789{
 790    helper_raise_exception_err(env, exception, 0);
 791}
 792
 793#if !defined(CONFIG_USER_ONLY)
 794void helper_store_msr(CPUPPCState *env, target_ulong val)
 795{
 796    val = hreg_store_msr(env, val, 0);
 797    if (val != 0) {
 798        env->interrupt_request |= CPU_INTERRUPT_EXITTB;
 799        helper_raise_exception(env, val);
 800    }
 801}
 802
 803static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr,
 804                          target_ulong msrm, int keep_msrh)
 805{
 806#if defined(TARGET_PPC64)
 807    if (msr_is_64bit(env, msr)) {
 808        nip = (uint64_t)nip;
 809        msr &= (uint64_t)msrm;
 810    } else {
 811        nip = (uint32_t)nip;
 812        msr = (uint32_t)(msr & msrm);
 813        if (keep_msrh) {
 814            msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
 815        }
 816    }
 817#else
 818    nip = (uint32_t)nip;
 819    msr &= (uint32_t)msrm;
 820#endif
 821    /* XXX: beware: this is false if VLE is supported */
 822    env->nip = nip & ~((target_ulong)0x00000003);
 823    hreg_store_msr(env, msr, 1);
 824#if defined(DEBUG_OP)
 825    cpu_dump_rfi(env->nip, env->msr);
 826#endif
 827    /* No need to raise an exception here,
 828     * as rfi is always the last insn of a TB
 829     */
 830    env->interrupt_request |= CPU_INTERRUPT_EXITTB;
 831}
 832
 833void helper_rfi(CPUPPCState *env)
 834{
 835    do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
 836           ~((target_ulong)0x783F0000), 1);
 837}
 838
 839#if defined(TARGET_PPC64)
 840void helper_rfid(CPUPPCState *env)
 841{
 842    do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
 843           ~((target_ulong)0x783F0000), 0);
 844}
 845
 846void helper_hrfid(CPUPPCState *env)
 847{
 848    do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
 849           ~((target_ulong)0x783F0000), 0);
 850}
 851#endif
 852
 853/*****************************************************************************/
 854/* Embedded PowerPC specific helpers */
 855void helper_40x_rfci(CPUPPCState *env)
 856{
 857    do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
 858           ~((target_ulong)0xFFFF0000), 0);
 859}
 860
 861void helper_rfci(CPUPPCState *env)
 862{
 863    do_rfi(env, env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
 864           ~((target_ulong)0x3FFF0000), 0);
 865}
 866
 867void helper_rfdi(CPUPPCState *env)
 868{
 869    do_rfi(env, env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
 870           ~((target_ulong)0x3FFF0000), 0);
 871}
 872
 873void helper_rfmci(CPUPPCState *env)
 874{
 875    do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
 876           ~((target_ulong)0x3FFF0000), 0);
 877}
 878#endif
 879
 880void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
 881               uint32_t flags)
 882{
 883    if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
 884                  ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
 885                  ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
 886                  ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
 887                  ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
 888        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
 889                                   POWERPC_EXCP_TRAP);
 890    }
 891}
 892
 893#if defined(TARGET_PPC64)
 894void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
 895               uint32_t flags)
 896{
 897    if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
 898                  ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
 899                  ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
 900                  ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
 901                  ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
 902        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
 903                                   POWERPC_EXCP_TRAP);
 904    }
 905}
 906#endif
 907
 908#if !defined(CONFIG_USER_ONLY)
 909/*****************************************************************************/
 910/* PowerPC 601 specific instructions (POWER bridge) */
 911
 912void helper_rfsvc(CPUPPCState *env)
 913{
 914    do_rfi(env, env->lr, env->ctr, 0x0000FFFF, 0);
 915}
 916
 917/* Embedded.Processor Control */
 918static int dbell2irq(target_ulong rb)
 919{
 920    int msg = rb & DBELL_TYPE_MASK;
 921    int irq = -1;
 922
 923    switch (msg) {
 924    case DBELL_TYPE_DBELL:
 925        irq = PPC_INTERRUPT_DOORBELL;
 926        break;
 927    case DBELL_TYPE_DBELL_CRIT:
 928        irq = PPC_INTERRUPT_CDOORBELL;
 929        break;
 930    case DBELL_TYPE_G_DBELL:
 931    case DBELL_TYPE_G_DBELL_CRIT:
 932    case DBELL_TYPE_G_DBELL_MC:
 933        /* XXX implement */
 934    default:
 935        break;
 936    }
 937
 938    return irq;
 939}
 940
 941void helper_msgclr(CPUPPCState *env, target_ulong rb)
 942{
 943    int irq = dbell2irq(rb);
 944
 945    if (irq < 0) {
 946        return;
 947    }
 948
 949    env->pending_interrupts &= ~(1 << irq);
 950}
 951
 952void helper_msgsnd(target_ulong rb)
 953{
 954    int irq = dbell2irq(rb);
 955    int pir = rb & DBELL_PIRTAG_MASK;
 956    CPUPPCState *cenv;
 957
 958    if (irq < 0) {
 959        return;
 960    }
 961
 962    for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) {
 963        if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
 964            cenv->pending_interrupts |= 1 << irq;
 965            cpu_interrupt(cenv, CPU_INTERRUPT_HARD);
 966        }
 967    }
 968}
 969#endif
 970