Statistics
| Branch: | Revision:

root / target-ppc / helper.c @ 97eb5b14

History | View | Annotate | Download (29.4 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
void cpu_loop_exit(void)
36
{
37
    longjmp(env->jmp_env, 1);
38
}
39

    
40
void do_process_exceptions (void)
41
{
42
    cpu_loop_exit();
43
}
44

    
45
int check_exception_state (CPUState *env)
46
{
47
    int i;
48

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

    
72
    return 0;
73
}
74

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

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

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

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

    
273
    return ret;
274
}
275

    
276
static inline uint32_t get_pgaddr (uint32_t sdr1, uint32_t hash, uint32_t mask)
277
{
278
    return (sdr1 & 0xFFFF0000) | (hash & mask);
279
}
280

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

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

    
385
    return ret;
386
}
387

    
388
int get_physical_address (CPUState *env, uint32_t *physical, int *prot,
389
                          uint32_t address, int rw, int access_type)
390
{
391
    int ret;
392

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

    
413
#if defined(CONFIG_USER_ONLY) 
414
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
415
{
416
    return addr;
417
}
418
#else
419
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
420
{
421
    uint32_t phys_addr;
422
    int prot;
423

    
424
    if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0)
425
        return -1;
426
    return phys_addr;
427
}
428
#endif
429

    
430
#if !defined(CONFIG_USER_ONLY) 
431

    
432
#define MMUSUFFIX _mmu
433
#define GETPC() (__builtin_return_address(0))
434

    
435
#define SHIFT 0
436
#include "softmmu_template.h"
437

    
438
#define SHIFT 1
439
#include "softmmu_template.h"
440

    
441
#define SHIFT 2
442
#include "softmmu_template.h"
443

    
444
#define SHIFT 3
445
#include "softmmu_template.h"
446

    
447
/* try to fill the TLB and return an exception if error. If retaddr is
448
   NULL, it means that the function was called in C code (i.e. not
449
   from generated code or from helper.c) */
450
/* XXX: fix it to restore all registers */
451
void tlb_fill(unsigned long addr, int is_write, int flags, void *retaddr)
452
{
453
    TranslationBlock *tb;
454
    int ret, is_user;
455
    unsigned long pc;
456
    CPUState *saved_env;
457

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

    
509
void cpu_ppc_init_mmu(CPUPPCState *env)
510
{
511
    /* Nothing to do: all translation are disabled */
512
}
513
#endif
514

    
515
/* Perform address translation */
516
int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
517
                              int flags, int is_softmmu)
518
{
519
    uint32_t physical;
520
    int prot;
521
    int exception = 0, error_code = 0;
522
    int is_user, access_type;
523
    int ret = 0;
524

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

    
664
    return ret;
665
}
666

    
667
uint32_t _load_xer (void)
668
{
669
    return (xer_so << XER_SO) |
670
        (xer_ov << XER_OV) |
671
        (xer_ca << XER_CA) |
672
        (xer_bc << XER_BC);
673
}
674

    
675
void _store_xer (uint32_t value)
676
{
677
    xer_so = (value >> XER_SO) & 0x01;
678
    xer_ov = (value >> XER_OV) & 0x01;
679
    xer_ca = (value >> XER_CA) & 0x01;
680
    xer_bc = (value >> XER_BC) & 0x1f;
681
}
682

    
683
uint32_t _load_msr (void)
684
{
685
    return (msr_pow << MSR_POW) |
686
        (msr_ile << MSR_ILE) |
687
        (msr_ee << MSR_EE) |
688
        (msr_pr << MSR_PR) |
689
        (msr_fp << MSR_FP) |
690
        (msr_me << MSR_ME) |
691
        (msr_fe0 << MSR_FE0) |
692
        (msr_se << MSR_SE) |
693
        (msr_be << MSR_BE) |
694
        (msr_fe1 << MSR_FE1) |
695
        (msr_ip << MSR_IP) |
696
        (msr_ir << MSR_IR) |
697
        (msr_dr << MSR_DR) |
698
        (msr_ri << MSR_RI) |
699
        (msr_le << MSR_LE);
700
}
701

    
702
void _store_msr (uint32_t value)
703
{
704
    msr_pow = (value >> MSR_POW) & 0x03;
705
    msr_ile = (value >> MSR_ILE) & 0x01;
706
    msr_ee = (value >> MSR_EE) & 0x01;
707
    msr_pr = (value >> MSR_PR) & 0x01;
708
    msr_fp = (value >> MSR_FP) & 0x01;
709
    msr_me = (value >> MSR_ME) & 0x01;
710
    msr_fe0 = (value >> MSR_FE0) & 0x01;
711
    msr_se = (value >> MSR_SE) & 0x01;
712
    msr_be = (value >> MSR_BE) & 0x01;
713
    msr_fe1 = (value >> MSR_FE1) & 0x01;
714
    msr_ip = (value >> MSR_IP) & 0x01;
715
    msr_ir = (value >> MSR_IR) & 0x01;
716
    msr_dr = (value >> MSR_DR) & 0x01;
717
    msr_ri = (value >> MSR_RI) & 0x01;
718
    msr_le = (value >> MSR_LE) & 0x01;
719
}
720

    
721
void do_interrupt (CPUState *env)
722
{
723
#if defined (CONFIG_USER_ONLY)
724
    env->exception_index |= 0x100;
725
#else
726
    uint32_t msr;
727
    int excp = env->exception_index;
728

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