Statistics
| Branch: | Revision:

root / target-ppc / helper.c @ 9a64fbe4

History | View | Annotate | Download (29.1 kB)

1
/*
2
 *  PPC emulation helpers for qemu.
3
 * 
4
 *  Copyright (c) 2003 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, write to the Free Software
18
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
 */
20
#include <sys/mman.h>
21

    
22
#include "exec.h"
23
#if defined (USE_OPEN_FIRMWARE)
24
#include "of.h"
25
#endif
26

    
27
//#define DEBUG_MMU
28
//#define DEBUG_BATS
29
//#define DEBUG_EXCEPTIONS
30

    
31
extern FILE *logfile, *stderr;
32
void exit (int);
33
void abort (void);
34

    
35
int phys_ram_size;
36
int phys_ram_fd;
37
uint8_t *phys_ram_base;
38

    
39
void cpu_loop_exit(void)
40
{
41
    longjmp(env->jmp_env, 1);
42
}
43

    
44
void do_process_exceptions (void)
45
{
46
    cpu_loop_exit();
47
}
48

    
49
int check_exception_state (CPUState *env)
50
{
51
    int i;
52

    
53
    /* Process PPC exceptions */
54
    for (i = 1; i  < EXCP_PPC_MAX; i++) {
55
        if (env->exceptions & (1 << i)) {
56
            switch (i) {
57
            case EXCP_EXTERNAL:
58
            case EXCP_DECR:
59
                if (msr_ee == 0)
60
                    return 0;
61
                break;
62
            case EXCP_PROGRAM:
63
                if (env->errors[EXCP_PROGRAM] == EXCP_FP &&
64
                    msr_fe0 == 0 && msr_fe1 == 0)
65
                    return 0;
66
                break;
67
            default:
68
                break;
69
            }
70
            env->exception_index = i;
71
            env->error_code = env->errors[i];
72
            return 1;
73
        }
74
    }
75

    
76
    return 0;
77
}
78

    
79
/*****************************************************************************/
80
/* PPC MMU emulation */
81
/* Perform BAT hit & translation */
82
static int get_bat (CPUState *env, uint32_t *real, int *prot,
83
                    uint32_t virtual, int rw, int type)
84
{
85
    uint32_t *BATlt, *BATut, *BATu, *BATl;
86
    uint32_t base, BEPIl, BEPIu, bl;
87
    int i;
88
    int ret = -1;
89

    
90
#if defined (DEBUG_BATS)
91
    if (loglevel > 0) {
92
        fprintf(logfile, "%s: %cBAT v 0x%08x\n", __func__,
93
               type == ACCESS_CODE ? 'I' : 'D', virtual);
94
    }
95
    printf("%s: %cBAT v 0x%08x\n", __func__,
96
           type == ACCESS_CODE ? 'I' : 'D', virtual);
97
#endif
98
    switch (type) {
99
    case ACCESS_CODE:
100
        BATlt = env->IBAT[1];
101
        BATut = env->IBAT[0];
102
        break;
103
    default:
104
        BATlt = env->DBAT[1];
105
        BATut = env->DBAT[0];
106
        break;
107
    }
108
#if defined (DEBUG_BATS)
109
    if (loglevel > 0) {
110
        fprintf(logfile, "%s...: %cBAT v 0x%08x\n", __func__,
111
               type == ACCESS_CODE ? 'I' : 'D', virtual);
112
    }
113
    printf("%s...: %cBAT v 0x%08x\n", __func__,
114
           type == ACCESS_CODE ? 'I' : 'D', virtual);
115
#endif
116
    base = virtual & 0xFFFC0000;
117
    for (i = 0; i < 4; i++) {
118
        BATu = &BATut[i];
119
        BATl = &BATlt[i];
120
        BEPIu = *BATu & 0xF0000000;
121
        BEPIl = *BATu & 0x0FFE0000;
122
        bl = (*BATu & 0x00001FFC) << 15;
123
#if defined (DEBUG_BATS)
124
        if (loglevel > 0) {
125
            fprintf(logfile, "%s: %cBAT%d v 0x%08x BATu 0x%08x BATl 0x%08x\n",
126
                    __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
127
                    *BATu, *BATl);
128
        } else {
129
            printf("%s: %cBAT%d v 0x%08x BATu 0x%08x BATl 0x%08x\n",
130
                   __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
131
                   *BATu, *BATl);
132
        }
133
#endif
134
        if ((virtual & 0xF0000000) == BEPIu &&
135
            ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
136
            /* BAT matches */
137
            if ((msr_pr == 0 && (*BATu & 0x00000002)) ||
138
                (msr_pr == 1 && (*BATu & 0x00000001))) {
139
                /* Get physical address */
140
                *real = (*BATl & 0xF0000000) |
141
                    ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
142
                    (virtual & 0x0001FFFF);
143
                if (*BATl & 0x00000001)
144
                    *prot = PROT_READ;
145
                if (*BATl & 0x00000002)
146
                    *prot = PROT_WRITE | PROT_READ;
147
#if defined (DEBUG_BATS)
148
                if (loglevel > 0) {
149
                    fprintf(logfile, "BAT %d match: r 0x%08x prot=%c%c\n",
150
                            i, *real, *prot & PROT_READ ? 'R' : '-',
151
                            *prot & PROT_WRITE ? 'W' : '-');
152
                } else {
153
                    printf("BAT %d match: 0x%08x => 0x%08x prot=%c%c\n",
154
                           i, virtual, *real, *prot & PROT_READ ? 'R' : '-',
155
                           *prot & PROT_WRITE ? 'W' : '-');
156
                }
157
#endif
158
                ret = 0;
159
                break;
160
            }
161
        }
162
    }
163
    if (ret < 0) {
164
#if defined (DEBUG_BATS)
165
        printf("no BAT match for 0x%08x:\n", virtual);
166
        for (i = 0; i < 4; i++) {
167
            BATu = &BATut[i];
168
            BATl = &BATlt[i];
169
            BEPIu = *BATu & 0xF0000000;
170
            BEPIl = *BATu & 0x0FFE0000;
171
            bl = (*BATu & 0x00001FFC) << 15;
172
            printf("%s: %cBAT%d v 0x%08x BATu 0x%08x BATl 0x%08x \n\t"
173
                   "0x%08x 0x%08x 0x%08x\n",
174
                   __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
175
                   *BATu, *BATl, BEPIu, BEPIl, bl);
176
        }
177
#endif
178
        env->spr[DAR] = virtual;
179
    }
180
    /* No hit */
181
    return ret;
182
}
183

    
184
/* PTE table lookup */
185
static int find_pte (uint32_t *RPN, int *prot, uint32_t base, uint32_t va,
186
                     int h, int key, int rw)
187
{
188
    uint32_t pte0, pte1, keep = 0;
189
    int i, good = -1, store = 0;
190
    int ret = -1; /* No entry found */
191

    
192
    for (i = 0; i < 8; i++) {
193
        pte0 = ldl_raw((void *)((uint32_t)phys_ram_base + base + (i * 8)));
194
        pte1 =  ldl_raw((void *)((uint32_t)phys_ram_base + base + (i * 8) + 4));
195
#if defined (DEBUG_MMU)
196
        printf("Load pte from 0x%08x => 0x%08x 0x%08x\n", base + (i * 8),
197
               pte0, pte1);
198
#endif
199
        /* Check validity and table match */
200
        if (pte0 & 0x80000000 && (h == ((pte0 >> 6) & 1))) {
201
#if defined (DEBUG_MMU)
202
            printf("PTE is valid and table matches... compare 0x%08x:%08x\n",
203
                   pte0 & 0x7FFFFFBF, va);
204
#endif
205
            /* Check vsid & api */
206
            if ((pte0 & 0x7FFFFFBF) == va) {
207
#if defined (DEBUG_MMU)
208
                printf("PTE match !\n");
209
#endif
210
                if (good == -1) {
211
                    good = i;
212
                    keep = pte1;
213
                } else {
214
                    /* All matches should have equal RPN, WIMG & PP */
215
                    if ((keep & 0xFFFFF07B) != (pte1 & 0xFFFFF07B)) {
216
                        printf("Bad RPN/WIMG/PP\n");
217
                        return -1;
218
                    }
219
                }
220
                /* Check access rights */
221
                if (key == 0) {
222
                    *prot = PROT_READ;
223
                    if ((pte1 & 0x00000003) != 0x3)
224
                        *prot |= PROT_WRITE;
225
                } else {
226
                    switch (pte1 & 0x00000003) {
227
                    case 0x0:
228
                        *prot = 0;
229
                        break;
230
                    case 0x1:
231
                    case 0x3:
232
                        *prot = PROT_READ;
233
                        break;
234
                    case 0x2:
235
                        *prot = PROT_READ | PROT_WRITE;
236
                        break;
237
                    }
238
                }
239
                if ((rw == 0 && *prot != 0) ||
240
                    (rw == 1 && (*prot & PROT_WRITE))) {
241
#if defined (DEBUG_MMU)
242
                    printf("PTE access granted !\n");
243
#endif
244
                    good = i;
245
                    keep = pte1;
246
                    ret = 0;
247
                } else if (ret == -1) {
248
                    ret = -2; /* Access right violation */
249
#if defined (DEBUG_MMU)
250
                    printf("PTE access rejected\n");
251
#endif
252
                }
253
            }
254
        }
255
    }
256
    if (good != -1) {
257
        *RPN = keep & 0xFFFFF000;
258
#if defined (DEBUG_MMU)
259
        printf("found PTE at addr 0x%08x prot=0x%01x ret=%d\n",
260
               *RPN, *prot, ret);
261
#endif
262
        /* Update page flags */
263
        if (!(keep & 0x00000100)) {
264
            keep |= 0x00000100;
265
            store = 1;
266
        }
267
        if (rw) {
268
            if (!(keep & 0x00000080)) {
269
                keep |= 0x00000080;
270
                store = 1;
271
            }
272
        }
273
        if (store)
274
            stl_raw((void *)(base + (good * 2) + 1), keep);
275
    }
276

    
277
    return ret;
278
}
279

    
280
static inline uint32_t get_pgaddr (uint32_t sdr1, uint32_t hash, uint32_t mask)
281
{
282
    return (sdr1 & 0xFFFF0000) | (hash & mask);
283
}
284

    
285
/* Perform segment based translation */
286
static int get_segment (CPUState *env, uint32_t *real, int *prot,
287
                        uint32_t virtual, int rw, int type)
288
{
289
    uint32_t pg_addr, sdr, ptem, vsid, pgidx;
290
    uint32_t hash, mask;
291
    uint32_t sr;
292
    int key;
293
    int ret = -1, ret2;
294

    
295
    sr = env->sr[virtual >> 28];
296
#if defined (DEBUG_MMU)
297
    printf("Check segment v=0x%08x %d 0x%08x nip=0x%08x lr=0x%08x ir=%d dr=%d "
298
           "pr=%d t=%d\n", virtual, virtual >> 28, sr, env->nip,
299
           env->lr, msr_ir, msr_dr, msr_pr, type);
300
#endif
301
    key = ((sr & 0x20000000) && msr_pr == 1) ||
302
        ((sr & 0x40000000) && msr_pr == 0) ? 1 : 0;
303
    if ((sr & 0x80000000) == 0) {
304
#if defined (DEBUG_MMU)
305
        printf("pte segment: key=%d n=0x%08x\n", key, sr & 0x10000000);
306
#endif
307
        /* Check if instruction fetch is allowed, if needed */
308
        if (type != ACCESS_CODE || (sr & 0x10000000) == 0) {
309
            /* Page address translation */
310
            vsid = sr & 0x00FFFFFF;
311
            pgidx = (virtual >> 12) & 0xFFFF;
312
            sdr = env->spr[SDR1];
313
            hash = ((vsid ^ pgidx) & 0x07FFFF) << 6;
314
            mask = ((sdr & 0x000001FF) << 16) | 0xFFC0;
315
            pg_addr = get_pgaddr(sdr, hash, mask);
316
            ptem = (vsid << 7) | (pgidx >> 10);
317
#if defined (DEBUG_MMU)
318
            printf("0 sdr1=0x%08x vsid=0x%06x api=0x%04x hash=0x%07x "
319
                   "pg_addr=0x%08x\n", sdr, vsid, pgidx, hash, pg_addr);
320
#endif
321
            /* Primary table lookup */
322
            ret = find_pte(real, prot, pg_addr, ptem, 0, key, rw);
323
            if (ret < 0) {
324
                /* Secondary table lookup */
325
                hash = (~hash) & 0x01FFFFC0;
326
                pg_addr = get_pgaddr(sdr, hash, mask);
327
#if defined (DEBUG_MMU)
328
                printf("1 sdr1=0x%08x vsid=0x%06x api=0x%04x hash=0x%05x "
329
                       "pg_addr=0x%08x\n", sdr, vsid, pgidx, hash, pg_addr);
330
#endif
331
                ret2 = find_pte(real, prot, pg_addr, ptem, 1, key, rw);
332
                if (ret2 != -1)
333
                    ret = ret2;
334
            }
335
            if (ret != -1)
336
                *real |= (virtual & 0x00000FFF);
337
            if (ret == -2 && type == ACCESS_CODE && (sr & 0x10000000))
338
                ret = -3;
339
        } else {
340
#if defined (DEBUG_MMU)
341
            printf("No access allowed\n");
342
#endif
343
        }
344
    } else {
345
#if defined (DEBUG_MMU)
346
        printf("direct store...\n");
347
#endif
348
        /* Direct-store segment : absolutely *BUGGY* for now */
349
        switch (type) {
350
        case ACCESS_INT:
351
            /* Integer load/store : only access allowed */
352
            break;
353
        case ACCESS_CODE:
354
            /* No code fetch is allowed in direct-store areas */
355
            return -4;
356
        case ACCESS_FLOAT:
357
            /* Floating point load/store */
358
            return -4;
359
        case ACCESS_RES:
360
            /* lwarx, ldarx or srwcx. */
361
            return -4;
362
        case ACCESS_CACHE:
363
            /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
364
            /* Should make the instruction do no-op.
365
             * As it already do no-op, it's quite easy :-)
366
             */
367
            *real = virtual;
368
            return 0;
369
        case ACCESS_EXT:
370
            /* eciwx or ecowx */
371
            return -4;
372
        default:
373
            if (logfile) {
374
                fprintf(logfile, "ERROR: instruction should not need "
375
                        "address translation\n");
376
            }
377
            printf("ERROR: instruction should not need "
378
                   "address translation\n");
379
            return -4;
380
        }
381
        if ((rw == 1 || key != 1) && (rw == 0 || key != 0)) {
382
            *real = virtual;
383
            ret = 2;
384
        } else {
385
            ret = -2;
386
        }
387
    }
388

    
389
    return ret;
390
}
391

    
392
int get_physical_address (CPUState *env, uint32_t *physical, int *prot,
393
                          uint32_t address, int rw, int access_type)
394
{
395
    int ret;
396

    
397
    if (loglevel > 0) {
398
        fprintf(logfile, "%s\n", __func__);
399
    }
400
    if ((access_type == ACCESS_CODE && msr_ir == 0) || msr_dr == 0) {
401
        /* No address translation */
402
        *physical = address;
403
        *prot = PROT_READ | PROT_WRITE;
404
        ret = 0;
405
    } else {
406
        /* Try to find a BAT */
407
        ret = get_bat(env, physical, prot, address, rw, access_type);
408
        if (ret < 0) {
409
            /* We didn't match any BAT entry */
410
            ret = get_segment(env, physical, prot, address, rw, access_type);
411
        }
412
    }
413
    
414
    return ret;
415
}
416

    
417

    
418
#if !defined(CONFIG_USER_ONLY) 
419

    
420
#define MMUSUFFIX _mmu
421
#define GETPC() (__builtin_return_address(0))
422

    
423
#define SHIFT 0
424
#include "softmmu_template.h"
425

    
426
#define SHIFT 1
427
#include "softmmu_template.h"
428

    
429
#define SHIFT 2
430
#include "softmmu_template.h"
431

    
432
#define SHIFT 3
433
#include "softmmu_template.h"
434

    
435
/* try to fill the TLB and return an exception if error. If retaddr is
436
   NULL, it means that the function was called in C code (i.e. not
437
   from generated code or from helper.c) */
438
/* XXX: fix it to restore all registers */
439
void tlb_fill(unsigned long addr, int is_write, int flags, void *retaddr)
440
{
441
    TranslationBlock *tb;
442
    int ret, is_user;
443
    unsigned long pc;
444
    CPUState *saved_env;
445

    
446
    /* XXX: hack to restore env in all cases, even if not called from
447
       generated code */
448
    saved_env = env;
449
    env = cpu_single_env;
450
    is_user = flags & 0x01;
451
    {
452
        unsigned long tlb_addrr, tlb_addrw;
453
        int index;
454
        index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
455
        tlb_addrr = env->tlb_read[is_user][index].address;
456
        tlb_addrw = env->tlb_write[is_user][index].address;
457
#if 0
458
        printf("%s 1 %p %p idx=%d addr=0x%08lx tbl_addr=0x%08lx 0x%08lx "
459
               "(0x%08lx 0x%08lx)\n", __func__, env,
460
               &env->tlb_read[is_user][index], index, addr,
461
               tlb_addrr, tlb_addrw, addr & TARGET_PAGE_MASK,
462
               tlb_addrr & (TARGET_PAGE_MASK | TLB_INVALID_MASK));
463
#endif
464
    }
465
    ret = cpu_handle_mmu_fault(env, addr, is_write, flags, 1);
466
    if (ret) {
467
        if (retaddr) {
468
            /* now we have a real cpu fault */
469
            pc = (unsigned long)retaddr;
470
            tb = tb_find_pc(pc);
471
            if (tb) {
472
                /* the PC is inside the translated code. It means that we have
473
                   a virtual CPU fault */
474
                cpu_restore_state(tb, env, pc);
475
            }
476
        }
477
        do_queue_exception_err(env->exception_index, env->error_code);
478
        do_process_exceptions();
479
    }
480
    {
481
        unsigned long tlb_addrr, tlb_addrw;
482
        int index;
483
        index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
484
        tlb_addrr = env->tlb_read[is_user][index].address;
485
        tlb_addrw = env->tlb_write[is_user][index].address;
486
#if 0
487
        printf("%s 2 %p %p idx=%d addr=0x%08lx tbl_addr=0x%08lx 0x%08lx "
488
               "(0x%08lx 0x%08lx)\n", __func__, env,
489
               &env->tlb_read[is_user][index], index, addr,
490
               tlb_addrr, tlb_addrw, addr & TARGET_PAGE_MASK,
491
               tlb_addrr & (TARGET_PAGE_MASK | TLB_INVALID_MASK));
492
#endif
493
    }
494
    env = saved_env;
495
}
496

    
497
void cpu_ppc_init_mmu(CPUPPCState *env)
498
{
499
    /* Nothing to do: all translation are disabled */
500
}
501
#endif
502

    
503
/* Perform address translation */
504
int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
505
                              int flags, int is_softmmu)
506
{
507
    uint32_t physical;
508
    int prot;
509
    int exception = 0, error_code = 0;
510
    int is_user, access_type;
511
    int ret = 0;
512

    
513
//    printf("%s 0\n", __func__);
514
    is_user = flags & 0x01;
515
    access_type = flags & ~0x01;
516
    if (env->user_mode_only) {
517
        /* user mode only emulation */
518
        ret = -1;
519
        goto do_fault;
520
    }
521
    ret = get_physical_address(env, &physical, &prot,
522
                               address, rw, access_type);
523
    if (ret == 0) {
524
        ret = tlb_set_page(env, address, physical, prot, is_user, is_softmmu);
525
    } else if (ret < 0) {
526
    do_fault:
527
#if defined (DEBUG_MMU)
528
        printf("%s 5\n", __func__);
529
        printf("nip=0x%08x LR=0x%08x CTR=0x%08x MSR=0x%08x TBL=0x%08x\n",
530
               env->nip, env->lr, env->ctr, /*msr*/0, env->tb[0]);
531
        {
532
            int  i;
533
            for (i = 0; i < 32; i++) {
534
                if ((i & 7) == 0)
535
                    printf("GPR%02d:", i);
536
                printf(" %08x", env->gpr[i]);
537
                if ((i & 7) == 7)
538
                    printf("\n");
539
            }
540
            printf("CR: 0x");
541
            for (i = 0; i < 8; i++)
542
                printf("%01x", env->crf[i]);
543
            printf("  [");
544
            for (i = 0; i < 8; i++) {
545
                char a = '-';
546
                if (env->crf[i] & 0x08)
547
                    a = 'L';
548
                else if (env->crf[i] & 0x04)
549
                    a = 'G';
550
                else if (env->crf[i] & 0x02)
551
                    a = 'E';
552
                printf(" %c%c", a, env->crf[i] & 0x01 ? 'O' : ' ');
553
            }
554
            printf(" ] ");
555
        }
556
        printf("TB: 0x%08x %08x\n", env->tb[1], env->tb[0]);
557
        printf("SRR0 0x%08x SRR1 0x%08x\n", env->spr[SRR0], env->spr[SRR1]);
558
#endif
559
        if (access_type == ACCESS_CODE) {
560
            exception = EXCP_ISI;
561
            switch (ret) {
562
            case -1:
563
                /* No matches in page tables */
564
                error_code = EXCP_ISI_TRANSLATE;
565
                break;
566
            case -2:
567
                /* Access rights violation */
568
                error_code = EXCP_ISI_PROT;
569
                break;
570
            case -3:
571
                error_code = EXCP_ISI_NOEXEC;
572
                break;
573
            case -4:
574
                /* Direct store exception */
575
                /* No code fetch is allowed in direct-store areas */
576
                exception = EXCP_ISI;
577
                error_code = EXCP_ISI_NOEXEC;
578
                break;
579
            }
580
        } else {
581
            exception = EXCP_DSI;
582
            switch (ret) {
583
            case -1:
584
                /* No matches in page tables */
585
                error_code = EXCP_DSI_TRANSLATE;
586
                break;
587
            case -2:
588
                /* Access rights violation */
589
                error_code = EXCP_DSI_PROT;
590
                break;
591
            case -4:
592
                /* Direct store exception */
593
                switch (access_type) {
594
                case ACCESS_FLOAT:
595
                    /* Floating point load/store */
596
                    exception = EXCP_ALIGN;
597
                    error_code = EXCP_ALIGN_FP;
598
                    break;
599
                case ACCESS_RES:
600
                    /* lwarx, ldarx or srwcx. */
601
                    exception = EXCP_DSI;
602
                    error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT;
603
                    if (rw)
604
                        error_code |= EXCP_DSI_STORE;
605
                    break;
606
                case ACCESS_EXT:
607
                    /* eciwx or ecowx */
608
                    exception = EXCP_DSI;
609
                    error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT | EXCP_ECXW;
610
                    break;
611
                default:
612
                    exception = EXCP_PROGRAM;
613
                    error_code = EXCP_INVAL | EXCP_INVAL_INVAL;
614
                    break;
615
                }
616
            }
617
            if (rw)
618
                error_code |= EXCP_DSI_STORE;
619
            /* Should find a better solution:
620
             * this will be invalid for some exception if more than one
621
             * exception occurs for one instruction
622
             */
623
            env->spr[DSISR] = 0;
624
            if (error_code & EXCP_DSI_DIRECT) {
625
                env->spr[DSISR] |= 0x80000000;
626
                if (access_type == ACCESS_EXT ||
627
                    access_type == ACCESS_RES)
628
                    env->spr[DSISR] |= 0x04000000;
629
            }
630
            if ((error_code & 0xF) == EXCP_DSI_TRANSLATE)
631
                env->spr[DSISR] |= 0x40000000;
632
            if (error_code & EXCP_DSI_PROT)
633
                env->spr[DSISR] |= 0x08000000;
634
            if (error_code & EXCP_DSI_STORE)
635
                env->spr[DSISR] |= 0x02000000;
636
            if ((error_code & 0xF) == EXCP_DSI_DABR)
637
                env->spr[DSISR] |= 0x00400000;
638
            if (access_type == ACCESS_EXT)
639
                env->spr[DSISR] |= 0x00100000;
640
        }
641
#if 0
642
        printf("%s: set exception to %d %02x\n",
643
               __func__, exception, error_code);
644
#endif
645
        env->exception_index = exception;
646
        env->error_code = error_code;
647
        /* Store fault address */
648
        env->spr[DAR] = address;
649
        ret = 1;
650
    }
651

    
652
    return ret;
653
}
654

    
655
uint32_t _load_xer (void)
656
{
657
    return (xer_so << XER_SO) |
658
        (xer_ov << XER_OV) |
659
        (xer_ca << XER_CA) |
660
        (xer_bc << XER_BC);
661
}
662

    
663
void _store_xer (uint32_t value)
664
{
665
    xer_so = (value >> XER_SO) & 0x01;
666
    xer_ov = (value >> XER_OV) & 0x01;
667
    xer_ca = (value >> XER_CA) & 0x01;
668
    xer_bc = (value >> XER_BC) & 0x1f;
669
}
670

    
671
uint32_t _load_msr (void)
672
{
673
    return (msr_pow << MSR_POW) |
674
        (msr_ile << MSR_ILE) |
675
        (msr_ee << MSR_EE) |
676
        (msr_pr << MSR_PR) |
677
        (msr_fp << MSR_FP) |
678
        (msr_me << MSR_ME) |
679
        (msr_fe0 << MSR_FE0) |
680
        (msr_se << MSR_SE) |
681
        (msr_be << MSR_BE) |
682
        (msr_fe1 << MSR_FE1) |
683
        (msr_ip << MSR_IP) |
684
        (msr_ir << MSR_IR) |
685
        (msr_dr << MSR_DR) |
686
        (msr_ri << MSR_RI) |
687
        (msr_le << MSR_LE);
688
}
689

    
690
void _store_msr (uint32_t value)
691
{
692
    msr_pow = (value >> MSR_POW) & 0x03;
693
    msr_ile = (value >> MSR_ILE) & 0x01;
694
    msr_ee = (value >> MSR_EE) & 0x01;
695
    msr_pr = (value >> MSR_PR) & 0x01;
696
    msr_fp = (value >> MSR_FP) & 0x01;
697
    msr_me = (value >> MSR_ME) & 0x01;
698
    msr_fe0 = (value >> MSR_FE0) & 0x01;
699
    msr_se = (value >> MSR_SE) & 0x01;
700
    msr_be = (value >> MSR_BE) & 0x01;
701
    msr_fe1 = (value >> MSR_FE1) & 0x01;
702
    msr_ip = (value >> MSR_IP) & 0x01;
703
    msr_ir = (value >> MSR_IR) & 0x01;
704
    msr_dr = (value >> MSR_DR) & 0x01;
705
    msr_ri = (value >> MSR_RI) & 0x01;
706
    msr_le = (value >> MSR_LE) & 0x01;
707
}
708

    
709
void do_interrupt (CPUState *env)
710
{
711
#if defined (CONFIG_USER_ONLY)
712
    env->exception_index |= 0x100;
713
#else
714
    uint32_t msr;
715
    int excp = env->exception_index;
716

    
717
    /* Dequeue PPC exceptions */
718
    if (excp < EXCP_PPC_MAX)
719
        env->exceptions &= ~(1 << excp);
720
    msr = _load_msr();
721
#if defined (DEBUG_EXCEPTIONS)
722
    if (excp != EXCP_DECR && excp == EXCP_PROGRAM && excp < EXCP_PPC_MAX) 
723
    {
724
        if (loglevel > 0) {
725
            fprintf(logfile, "Raise exception at 0x%08x => 0x%08x (%02x)\n",
726
                    env->nip, excp << 8, env->error_code);
727
        } else {
728
            printf("Raise exception at 0x%08x => 0x%08x (%02x)\n",
729
                   env->nip, excp << 8, env->error_code);
730
        }
731
        printf("nip=0x%08x LR=0x%08x CTR=0x%08x MSR=0x%08x DECR=0x%08x\n",
732
               env->nip, env->lr, env->ctr, msr, env->decr);
733
        {
734
    int i;
735
            for (i = 0; i < 32; i++) {
736
                if ((i & 7) == 0)
737
                    printf("GPR%02d:", i);
738
                printf(" %08x", env->gpr[i]);
739
                if ((i & 7) == 7)
740
                    printf("\n");
741
    }
742
            printf("CR: 0x");
743
    for (i = 0; i < 8; i++)
744
                printf("%01x", env->crf[i]);
745
            printf("  [");
746
            for (i = 0; i < 8; i++) {
747
                char a = '-';
748
                if (env->crf[i] & 0x08)
749
                    a = 'L';
750
                else if (env->crf[i] & 0x04)
751
                    a = 'G';
752
                else if (env->crf[i] & 0x02)
753
                    a = 'E';
754
                printf(" %c%c", a, env->crf[i] & 0x01 ? 'O' : ' ');
755
    }
756
            printf(" ] ");
757
    }
758
        printf("TB: 0x%08x %08x\n", env->tb[1], env->tb[0]);
759
        printf("XER 0x%08x SRR0 0x%08x SRR1 0x%08x\n",
760
               _load_xer(), env->spr[SRR0], env->spr[SRR1]);
761
    }
762
#endif
763
    /* Generate informations in save/restore registers */
764
    switch (excp) {
765
    case EXCP_OFCALL:
766
#if defined (USE_OPEN_FIRMWARE)
767
        env->gpr[3] = OF_client_entry((void *)env->gpr[3]);
768
#endif
769
        return;
770
    case EXCP_RTASCALL:
771
#if defined (USE_OPEN_FIRMWARE)
772
        printf("RTAS call !\n");
773
        env->gpr[3] = RTAS_entry((void *)env->gpr[3]);
774
        printf("RTAS call done\n");
775
#endif
776
        return;
777
    case EXCP_NONE:
778
        /* Do nothing */
779
#if defined (DEBUG_EXCEPTIONS)
780
        printf("%s: escape EXCP_NONE\n", __func__);
781
#endif
782
        return;
783
    case EXCP_RESET:
784
        if (msr_ip)
785
            excp += 0xFFC00;
786
        goto store_next;
787
    case EXCP_MACHINE_CHECK:
788
        if (msr_me == 0) {
789
            printf("Machine check exception while not allowed !\n");
790
            if (loglevel) {
791
                fprintf(logfile,
792
                        "Machine check exception while not allowed !\n");
793
        }
794
            abort();
795
    }
796
        msr_me = 0;
797
        break;
798
    case EXCP_DSI:
799
        /* Store exception cause */
800
        /* data location address has been stored
801
         * when the fault has been detected
802
     */
803
        goto store_current;
804
    case EXCP_ISI:
805
        /* Store exception cause */
806
        if (env->error_code == EXCP_ISI_TRANSLATE)
807
            msr |= 0x40000000;
808
        else if (env->error_code == EXCP_ISI_NOEXEC ||
809
            env->error_code == EXCP_ISI_GUARD)
810
            msr |= 0x10000000;
811
        else
812
            msr |= 0x08000000;
813
        goto store_next;
814
    case EXCP_EXTERNAL:
815
        if (msr_ee == 0) {
816
#if defined (DEBUG_EXCEPTIONS)
817
            if (loglevel > 0) {
818
                fprintf(logfile, "Skipping hardware interrupt\n");
819
            } else {
820
                printf("Skipping hardware interrupt\n");
821
    }
822
#endif
823
            return;
824
            }
825
        goto store_next;
826
    case EXCP_ALIGN:
827
        /* Store exception cause */
828
        /* Get rS/rD and rA from faulting opcode */
829
        env->spr[DSISR] |=
830
            (ldl_code((void *)(env->nip - 4)) & 0x03FF0000) >> 16;
831
        /* data location address has been stored
832
         * when the fault has been detected
833
         */
834
        goto store_current;
835
    case EXCP_PROGRAM:
836
        msr &= ~0xFFFF0000;
837
        switch (env->error_code & ~0xF) {
838
        case EXCP_FP:
839
            if (msr_fe0 == 0 && msr_fe1 == 0) {
840
#if defined (DEBUG_EXCEPTIONS)
841
                printf("Ignore floating point exception\n");
842
#endif
843
                return;
844
        }
845
            msr |= 0x00100000;
846
            /* Set FX */
847
            env->fpscr[7] |= 0x8;
848
            /* Finally, update FEX */
849
            if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) &
850
                ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3)))
851
                env->fpscr[7] |= 0x4;
852
        break;
853
        case EXCP_INVAL:
854
            msr |= 0x00080000;
855
        break;
856
        case EXCP_PRIV:
857
            msr |= 0x00040000;
858
        break;
859
        case EXCP_TRAP:
860
            msr |= 0x00020000;
861
            break;
862
        default:
863
            /* Should never occur */
864
        break;
865
    }
866
        msr |= 0x00010000;
867
        goto store_current;
868
    case EXCP_NO_FP:
869
        goto store_current;
870
    case EXCP_DECR:
871
        if (msr_ee == 0) {
872
            /* Requeue it */
873
            do_queue_exception(EXCP_DECR);
874
            return;
875
        }
876
        goto store_next;
877
    case EXCP_SYSCALL:
878
#if defined (DEBUG_EXCEPTIONS)
879
        printf("syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n",
880
               env->gpr[0], env->gpr[3], env->gpr[4], env->gpr[5], env->gpr[6]);
881
#endif
882
        goto store_next;
883
    case EXCP_TRACE:
884
        goto store_next;
885
    case EXCP_FP_ASSIST:
886
        goto store_next;
887
    case EXCP_MTMSR:
888
        /* Nothing to do */
889
#if defined (DEBUG_EXCEPTIONS)
890
        printf("%s: escape EXCP_MTMSR\n", __func__);
891
#endif
892
        return;
893
    case EXCP_BRANCH:
894
        /* Nothing to do */
895
#if defined (DEBUG_EXCEPTIONS)
896
        printf("%s: escape EXCP_BRANCH\n", __func__);
897
#endif
898
        return;
899
    case EXCP_RFI:
900
        /* Restore user-mode state */
901
#if defined (DEBUG_EXCEPTIONS)
902
        printf("%s: escape EXCP_RFI\n", __func__);
903
#endif
904
        return;
905
    store_current:
906
        /* SRR0 is set to current instruction */
907
        env->spr[SRR0] = (uint32_t)env->nip - 4;
908
        break;
909
    store_next:
910
        /* SRR0 is set to next instruction */
911
        env->spr[SRR0] = (uint32_t)env->nip;
912
        break;
913
    }
914
    env->spr[SRR1] = msr;
915
    /* reload MSR with correct bits */
916
    msr_pow = 0;
917
    msr_ee = 0;
918
    msr_pr = 0;
919
    msr_fp = 0;
920
    msr_fe0 = 0;
921
    msr_se = 0;
922
    msr_be = 0;
923
    msr_fe1 = 0;
924
    msr_ir = 0;
925
    msr_dr = 0;
926
    msr_ri = 0;
927
    msr_le = msr_ile;
928
    /* Jump to handler */
929
    env->nip = excp << 8;
930
    env->exception_index = EXCP_NONE;
931
    /* Invalidate all TLB as we may have changed translation mode */
932
    do_tlbia();
933
    /* ensure that no TB jump will be modified as
934
       the program flow was changed */
935
#ifdef __sparc__
936
    tmp_T0 = 0;
937
#else
938
    T0 = 0;
939
#endif
940
#endif
941
}