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