Statistics
| Branch: | Revision:

root / target-ppc / excp_helper.c @ 13ef70f6

History | View | Annotate | Download (33.1 kB)

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

    
36
void (*cpu_ppc_hypercall)(CPUPPCState *);
37

    
38
/*****************************************************************************/
39
/* Exception processing */
40
#if defined(CONFIG_USER_ONLY)
41
void do_interrupt(CPUPPCState *env)
42
{
43
    env->exception_index = POWERPC_EXCP_NONE;
44
    env->error_code = 0;
45
}
46

    
47
void 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) */
53
static 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
 */
66
static 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

    
644
void do_interrupt(CPUPPCState *env)
645
{
646
    powerpc_excp(env, env->excp_model, env->exception_index);
647
}
648

    
649
void 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)
767
static 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

    
777
void 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

    
788
void 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)
794
void 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

    
803
static 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

    
833
void 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)
840
void helper_rfid(CPUPPCState *env)
841
{
842
    do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
843
           ~((target_ulong)0x783F0000), 0);
844
}
845

    
846
void 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 */
855
void 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

    
861
void helper_rfci(CPUPPCState *env)
862
{
863
    do_rfi(env, env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
864
           ~((target_ulong)0x3FFF0000), 0);
865
}
866

    
867
void helper_rfdi(CPUPPCState *env)
868
{
869
    do_rfi(env, env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
870
           ~((target_ulong)0x3FFF0000), 0);
871
}
872

    
873
void 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

    
880
void 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)
894
void 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

    
912
void helper_rfsvc(CPUPPCState *env)
913
{
914
    do_rfi(env, env->lr, env->ctr, 0x0000FFFF, 0);
915
}
916

    
917
/* Embedded.Processor Control */
918
static 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

    
941
void 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

    
952
void 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