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