Statistics
| Branch: | Revision:

root / target-ppc / helper.c @ a8d3431a

History | View | Annotate | Download (27.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 "exec.h"
21
#if defined (USE_OPEN_FIRMWARE)
22
#include <time.h>
23
#include "of.h"
24
#endif
25

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

    
30
/*****************************************************************************/
31
/* PPC MMU emulation */
32

    
33
/* Perform BAT hit & translation */
34
static int get_bat (CPUState *env, uint32_t *real, int *prot,
35
                    uint32_t virtual, int rw, int type)
36
{
37
    uint32_t *BATlt, *BATut, *BATu, *BATl;
38
    uint32_t base, BEPIl, BEPIu, bl;
39
    int i;
40
    int ret = -1;
41

    
42
#if defined (DEBUG_BATS)
43
    if (loglevel > 0) {
44
        fprintf(logfile, "%s: %cBAT v 0x%08x\n", __func__,
45
               type == ACCESS_CODE ? 'I' : 'D', virtual);
46
    }
47
#endif
48
    switch (type) {
49
    case ACCESS_CODE:
50
        BATlt = env->IBAT[1];
51
        BATut = env->IBAT[0];
52
        break;
53
    default:
54
        BATlt = env->DBAT[1];
55
        BATut = env->DBAT[0];
56
        break;
57
    }
58
#if defined (DEBUG_BATS)
59
    if (loglevel > 0) {
60
        fprintf(logfile, "%s...: %cBAT v 0x%08x\n", __func__,
61
               type == ACCESS_CODE ? 'I' : 'D', virtual);
62
    }
63
#endif
64
    base = virtual & 0xFFFC0000;
65
    for (i = 0; i < 4; i++) {
66
        BATu = &BATut[i];
67
        BATl = &BATlt[i];
68
        BEPIu = *BATu & 0xF0000000;
69
        BEPIl = *BATu & 0x0FFE0000;
70
        bl = (*BATu & 0x00001FFC) << 15;
71
#if defined (DEBUG_BATS)
72
        if (loglevel > 0) {
73
            fprintf(logfile, "%s: %cBAT%d v 0x%08x BATu 0x%08x BATl 0x%08x\n",
74
                    __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
75
                    *BATu, *BATl);
76
        }
77
#endif
78
        if ((virtual & 0xF0000000) == BEPIu &&
79
            ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
80
            /* BAT matches */
81
            if ((msr_pr == 0 && (*BATu & 0x00000002)) ||
82
                (msr_pr == 1 && (*BATu & 0x00000001))) {
83
                /* Get physical address */
84
                *real = (*BATl & 0xF0000000) |
85
                    ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
86
                    (virtual & 0x0001F000);
87
                if (*BATl & 0x00000001)
88
                    *prot = PAGE_READ;
89
                if (*BATl & 0x00000002)
90
                    *prot = PAGE_WRITE | PAGE_READ;
91
#if defined (DEBUG_BATS)
92
                if (loglevel > 0) {
93
                    fprintf(logfile, "BAT %d match: r 0x%08x prot=%c%c\n",
94
                            i, *real, *prot & PAGE_READ ? 'R' : '-',
95
                            *prot & PAGE_WRITE ? 'W' : '-');
96
                }
97
#endif
98
                ret = 0;
99
                break;
100
            }
101
        }
102
    }
103
    if (ret < 0) {
104
#if defined (DEBUG_BATS)
105
        printf("no BAT match for 0x%08x:\n", virtual);
106
        for (i = 0; i < 4; i++) {
107
            BATu = &BATut[i];
108
            BATl = &BATlt[i];
109
            BEPIu = *BATu & 0xF0000000;
110
            BEPIl = *BATu & 0x0FFE0000;
111
            bl = (*BATu & 0x00001FFC) << 15;
112
            printf("%s: %cBAT%d v 0x%08x BATu 0x%08x BATl 0x%08x \n\t"
113
                   "0x%08x 0x%08x 0x%08x\n",
114
                   __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
115
                   *BATu, *BATl, BEPIu, BEPIl, bl);
116
        }
117
#endif
118
    }
119
    /* No hit */
120
    return ret;
121
}
122

    
123
/* PTE table lookup */
124
static int find_pte (uint32_t *RPN, int *prot, uint32_t base, uint32_t va,
125
                     int h, int key, int rw)
126
{
127
    uint32_t pte0, pte1, keep = 0, access = 0;
128
    int i, good = -1, store = 0;
129
    int ret = -1; /* No entry found */
130

    
131
    for (i = 0; i < 8; i++) {
132
        pte0 = ldl_phys(base + (i * 8));
133
        pte1 =  ldl_phys(base + (i * 8) + 4);
134
#if defined (DEBUG_MMU)
135
        if (loglevel > 0) {
136
            fprintf(logfile, "Load pte from 0x%08x => 0x%08x 0x%08x "
137
                    "%d %d %d 0x%08x\n", base + (i * 8), pte0, pte1,
138
                    pte0 >> 31, h, (pte0 >> 6) & 1, va);
139
        }
140
#endif
141
        /* Check validity and table match */
142
        if (pte0 & 0x80000000 && (h == ((pte0 >> 6) & 1))) {
143
            /* Check vsid & api */
144
            if ((pte0 & 0x7FFFFFBF) == va) {
145
                if (good == -1) {
146
                    good = i;
147
                    keep = pte1;
148
                } else {
149
                    /* All matches should have equal RPN, WIMG & PP */
150
                    if ((keep & 0xFFFFF07B) != (pte1 & 0xFFFFF07B)) {
151
                        if (loglevel > 0)
152
                            fprintf(logfile, "Bad RPN/WIMG/PP\n");
153
                        return -1;
154
                    }
155
                }
156
                /* Check access rights */
157
                if (key == 0) {
158
                    access = PAGE_READ;
159
                    if ((pte1 & 0x00000003) != 0x3)
160
                        access |= PAGE_WRITE;
161
                } else {
162
                    switch (pte1 & 0x00000003) {
163
                    case 0x0:
164
                        access = 0;
165
                        break;
166
                    case 0x1:
167
                    case 0x3:
168
                        access = PAGE_READ;
169
                        break;
170
                    case 0x2:
171
                        access = PAGE_READ | PAGE_WRITE;
172
                        break;
173
                    }
174
                }
175
                if (ret < 0) {
176
                    if ((rw == 0 && (access & PAGE_READ)) ||
177
                        (rw == 1 && (access & PAGE_WRITE))) {
178
#if defined (DEBUG_MMU)
179
                        if (loglevel > 0)
180
                            fprintf(logfile, "PTE access granted !\n");
181
#endif
182
                    good = i;
183
                    keep = pte1;
184
                    ret = 0;
185
                    } else {
186
                        /* Access right violation */
187
                        ret = -2;
188
#if defined (DEBUG_MMU)
189
                        if (loglevel > 0)
190
                            fprintf(logfile, "PTE access rejected\n");
191
#endif
192
                }
193
                    *prot = access;
194
                }
195
            }
196
        }
197
    }
198
    if (good != -1) {
199
        *RPN = keep & 0xFFFFF000;
200
#if defined (DEBUG_MMU)
201
        if (loglevel > 0) {
202
            fprintf(logfile, "found PTE at addr 0x%08x prot=0x%01x ret=%d\n",
203
               *RPN, *prot, ret);
204
        }
205
#endif
206
        /* Update page flags */
207
        if (!(keep & 0x00000100)) {
208
            /* Access flag */
209
            keep |= 0x00000100;
210
            store = 1;
211
        }
212
            if (!(keep & 0x00000080)) {
213
            if (rw && ret == 0) {
214
                /* Change flag */
215
                keep |= 0x00000080;
216
                store = 1;
217
            } else {
218
                /* Force page fault for first write access */
219
                *prot &= ~PAGE_WRITE;
220
            }
221
        }
222
        if (store) {
223
            stl_phys_notdirty(base + (good * 8) + 4, keep);
224
        }
225
    }
226

    
227
    return ret;
228
}
229

    
230
static inline uint32_t get_pgaddr (uint32_t sdr1, uint32_t hash, uint32_t mask)
231
{
232
    return (sdr1 & 0xFFFF0000) | (hash & mask);
233
}
234

    
235
/* Perform segment based translation */
236
static int get_segment (CPUState *env, uint32_t *real, int *prot,
237
                        uint32_t virtual, int rw, int type)
238
{
239
    uint32_t pg_addr, sdr, ptem, vsid, pgidx;
240
    uint32_t hash, mask;
241
    uint32_t sr;
242
    int key;
243
    int ret = -1, ret2;
244

    
245
    sr = env->sr[virtual >> 28];
246
#if defined (DEBUG_MMU)
247
    if (loglevel > 0) {
248
        fprintf(logfile, "Check segment v=0x%08x %d 0x%08x nip=0x%08x "
249
                "lr=0x%08x ir=%d dr=%d pr=%d %d t=%d\n",
250
                virtual, virtual >> 28, sr, env->nip,
251
                env->lr, msr_ir, msr_dr, msr_pr, rw, type);
252
    }
253
#endif
254
    key = (((sr & 0x20000000) && msr_pr == 1) ||
255
        ((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0;
256
    if ((sr & 0x80000000) == 0) {
257
#if defined (DEBUG_MMU)
258
        if (loglevel > 0)
259
            fprintf(logfile, "pte segment: key=%d n=0x%08x\n",
260
                    key, sr & 0x10000000);
261
#endif
262
        /* Check if instruction fetch is allowed, if needed */
263
        if (type != ACCESS_CODE || (sr & 0x10000000) == 0) {
264
            /* Page address translation */
265
            vsid = sr & 0x00FFFFFF;
266
            pgidx = (virtual >> 12) & 0xFFFF;
267
            sdr = env->sdr1;
268
            hash = ((vsid ^ pgidx) & 0x0007FFFF) << 6;
269
            mask = ((sdr & 0x000001FF) << 16) | 0xFFC0;
270
            pg_addr = get_pgaddr(sdr, hash, mask);
271
            ptem = (vsid << 7) | (pgidx >> 10);
272
#if defined (DEBUG_MMU)
273
            if (loglevel > 0) {
274
                fprintf(logfile, "0 sdr1=0x%08x vsid=0x%06x api=0x%04x "
275
                        "hash=0x%07x pg_addr=0x%08x\n", sdr, vsid, pgidx, hash,
276
                        pg_addr);
277
            }
278
#endif
279
            /* Primary table lookup */
280
            ret = find_pte(real, prot, pg_addr, ptem, 0, key, rw);
281
            if (ret < 0) {
282
                /* Secondary table lookup */
283
                hash = (~hash) & 0x01FFFFC0;
284
                pg_addr = get_pgaddr(sdr, hash, mask);
285
#if defined (DEBUG_MMU)
286
                if (virtual != 0xEFFFFFFF && loglevel > 0) {
287
                    fprintf(logfile, "1 sdr1=0x%08x vsid=0x%06x api=0x%04x "
288
                            "hash=0x%05x pg_addr=0x%08x\n", sdr, vsid, pgidx,
289
                            hash, pg_addr);
290
                }
291
#endif
292
                ret2 = find_pte(real, prot, pg_addr, ptem, 1, key, rw);
293
                if (ret2 != -1)
294
                    ret = ret2;
295
            }
296
        } else {
297
#if defined (DEBUG_MMU)
298
            if (loglevel > 0)
299
                fprintf(logfile, "No access allowed\n");
300
#endif
301
            ret = -3;
302
        }
303
    } else {
304
#if defined (DEBUG_MMU)
305
        if (loglevel > 0)
306
            fprintf(logfile, "direct store...\n");
307
#endif
308
        /* Direct-store segment : absolutely *BUGGY* for now */
309
        switch (type) {
310
        case ACCESS_INT:
311
            /* Integer load/store : only access allowed */
312
            break;
313
        case ACCESS_CODE:
314
            /* No code fetch is allowed in direct-store areas */
315
            return -4;
316
        case ACCESS_FLOAT:
317
            /* Floating point load/store */
318
            return -4;
319
        case ACCESS_RES:
320
            /* lwarx, ldarx or srwcx. */
321
            return -4;
322
        case ACCESS_CACHE:
323
            /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
324
            /* Should make the instruction do no-op.
325
             * As it already do no-op, it's quite easy :-)
326
             */
327
            *real = virtual;
328
            return 0;
329
        case ACCESS_EXT:
330
            /* eciwx or ecowx */
331
            return -4;
332
        default:
333
            if (logfile) {
334
                fprintf(logfile, "ERROR: instruction should not need "
335
                        "address translation\n");
336
            }
337
            printf("ERROR: instruction should not need "
338
                   "address translation\n");
339
            return -4;
340
        }
341
        if ((rw == 1 || key != 1) && (rw == 0 || key != 0)) {
342
            *real = virtual;
343
            ret = 2;
344
        } else {
345
            ret = -2;
346
        }
347
    }
348

    
349
    return ret;
350
}
351

    
352
int get_physical_address (CPUState *env, uint32_t *physical, int *prot,
353
                          uint32_t address, int rw, int access_type)
354
{
355
    int ret;
356
#if 0
357
    if (loglevel > 0) {
358
        fprintf(logfile, "%s\n", __func__);
359
    }
360
#endif    
361
    if ((access_type == ACCESS_CODE && msr_ir == 0) ||
362
        (access_type != ACCESS_CODE && msr_dr == 0)) {
363
        /* No address translation */
364
        *physical = address & ~0xFFF;
365
        *prot = PAGE_READ | PAGE_WRITE;
366
        ret = 0;
367
    } else {
368
        /* Try to find a BAT */
369
        ret = get_bat(env, physical, prot, address, rw, access_type);
370
        if (ret < 0) {
371
            /* We didn't match any BAT entry */
372
            ret = get_segment(env, physical, prot, address, rw, access_type);
373
        }
374
    }
375
#if 0
376
    if (loglevel > 0) {
377
        fprintf(logfile, "%s address %08x => %08x\n",
378
                __func__, address, *physical);
379
    }
380
#endif    
381
    return ret;
382
}
383

    
384
#if defined(CONFIG_USER_ONLY) 
385
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
386
{
387
    return addr;
388
}
389
#else
390
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
391
{
392
    uint32_t phys_addr;
393
    int prot;
394

    
395
    if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0)
396
        return -1;
397
    return phys_addr;
398
}
399
#endif
400

    
401
#if !defined(CONFIG_USER_ONLY) 
402

    
403
#define MMUSUFFIX _mmu
404
#define GETPC() (__builtin_return_address(0))
405

    
406
#define SHIFT 0
407
#include "softmmu_template.h"
408

    
409
#define SHIFT 1
410
#include "softmmu_template.h"
411

    
412
#define SHIFT 2
413
#include "softmmu_template.h"
414

    
415
#define SHIFT 3
416
#include "softmmu_template.h"
417

    
418
/* try to fill the TLB and return an exception if error. If retaddr is
419
   NULL, it means that the function was called in C code (i.e. not
420
   from generated code or from helper.c) */
421
/* XXX: fix it to restore all registers */
422
void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr)
423
{
424
    TranslationBlock *tb;
425
    CPUState *saved_env;
426
    unsigned long pc;
427
    int ret;
428

    
429
    /* XXX: hack to restore env in all cases, even if not called from
430
       generated code */
431
    saved_env = env;
432
    env = cpu_single_env;
433
#if 0
434
    {
435
        unsigned long tlb_addrr, tlb_addrw;
436
        int index;
437
        index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
438
        tlb_addrr = env->tlb_read[is_user][index].address;
439
        tlb_addrw = env->tlb_write[is_user][index].address;
440
        if (loglevel) {
441
            fprintf(logfile,
442
                    "%s 1 %p %p idx=%d addr=0x%08lx tbl_addr=0x%08lx 0x%08lx "
443
               "(0x%08lx 0x%08lx)\n", __func__, env,
444
               &env->tlb_read[is_user][index], index, addr,
445
               tlb_addrr, tlb_addrw, addr & TARGET_PAGE_MASK,
446
               tlb_addrr & (TARGET_PAGE_MASK | TLB_INVALID_MASK));
447
        }
448
    }
449
#endif
450
    ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, is_user, 1);
451
    if (ret) {
452
        if (retaddr) {
453
            /* now we have a real cpu fault */
454
            pc = (unsigned long)retaddr;
455
            tb = tb_find_pc(pc);
456
            if (tb) {
457
                /* the PC is inside the translated code. It means that we have
458
                   a virtual CPU fault */
459
                cpu_restore_state(tb, env, pc, NULL);
460
            }
461
        }
462
        do_raise_exception_err(env->exception_index, env->error_code);
463
    }
464
#if 0
465
    {
466
        unsigned long tlb_addrr, tlb_addrw;
467
        int index;
468
        index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
469
        tlb_addrr = env->tlb_read[is_user][index].address;
470
        tlb_addrw = env->tlb_write[is_user][index].address;
471
        printf("%s 2 %p %p idx=%d addr=0x%08lx tbl_addr=0x%08lx 0x%08lx "
472
               "(0x%08lx 0x%08lx)\n", __func__, env,
473
               &env->tlb_read[is_user][index], index, addr,
474
               tlb_addrr, tlb_addrw, addr & TARGET_PAGE_MASK,
475
               tlb_addrr & (TARGET_PAGE_MASK | TLB_INVALID_MASK));
476
    }
477
#endif
478
    env = saved_env;
479
}
480

    
481
void cpu_ppc_init_mmu(CPUState *env)
482
{
483
    /* Nothing to do: all translation are disabled */
484
}
485
#endif
486

    
487
/* Perform address translation */
488
int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
489
                              int is_user, int is_softmmu)
490
{
491
    uint32_t physical;
492
    int prot;
493
    int exception = 0, error_code = 0;
494
    int access_type;
495
    int ret = 0;
496

    
497
    if (rw == 2) {
498
        /* code access */
499
        rw = 0;
500
        access_type = ACCESS_CODE;
501
    } else {
502
        /* data access */
503
        /* XXX: put correct access by using cpu_restore_state()
504
           correctly */
505
        access_type = ACCESS_INT;
506
        //        access_type = env->access_type;
507
    }
508
    if (env->user_mode_only) {
509
        /* user mode only emulation */
510
        ret = -2;
511
        goto do_fault;
512
    }
513
    ret = get_physical_address(env, &physical, &prot,
514
                               address, rw, access_type);
515
    if (ret == 0) {
516
        ret = tlb_set_page(env, address & ~0xFFF, physical, prot,
517
                           is_user, is_softmmu);
518
    } else if (ret < 0) {
519
    do_fault:
520
#if defined (DEBUG_MMU)
521
        if (loglevel > 0)
522
            cpu_dump_state(env, logfile, fprintf, 0);
523
#endif
524
        if (access_type == ACCESS_CODE) {
525
            exception = EXCP_ISI;
526
            switch (ret) {
527
            case -1:
528
                /* No matches in page tables */
529
                error_code = EXCP_ISI_TRANSLATE;
530
                break;
531
            case -2:
532
                /* Access rights violation */
533
                error_code = EXCP_ISI_PROT;
534
                break;
535
            case -3:
536
                /* No execute protection violation */
537
                error_code = EXCP_ISI_NOEXEC;
538
                break;
539
            case -4:
540
                /* Direct store exception */
541
                /* No code fetch is allowed in direct-store areas */
542
                error_code = EXCP_ISI_DIRECT;
543
                break;
544
            }
545
        } else {
546
            exception = EXCP_DSI;
547
            switch (ret) {
548
            case -1:
549
                /* No matches in page tables */
550
                error_code = EXCP_DSI_TRANSLATE;
551
                break;
552
            case -2:
553
                /* Access rights violation */
554
                error_code = EXCP_DSI_PROT;
555
                break;
556
            case -4:
557
                /* Direct store exception */
558
                switch (access_type) {
559
                case ACCESS_FLOAT:
560
                    /* Floating point load/store */
561
                    exception = EXCP_ALIGN;
562
                    error_code = EXCP_ALIGN_FP;
563
                    break;
564
                case ACCESS_RES:
565
                    /* lwarx, ldarx or srwcx. */
566
                    exception = EXCP_DSI;
567
                    error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT;
568
                    break;
569
                case ACCESS_EXT:
570
                    /* eciwx or ecowx */
571
                    exception = EXCP_DSI;
572
                    error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT |
573
                        EXCP_DSI_ECXW;
574
                    break;
575
                default:
576
                    printf("DSI: invalid exception (%d)\n", ret);
577
                    exception = EXCP_PROGRAM;
578
                    error_code = EXCP_INVAL | EXCP_INVAL_INVAL;
579
                    break;
580
                }
581
            }
582
            if (rw)
583
                error_code |= EXCP_DSI_STORE;
584
            /* Store fault address */
585
            env->spr[DAR] = address;
586
        }
587
#if 0
588
        printf("%s: set exception to %d %02x\n",
589
               __func__, exception, error_code);
590
#endif
591
        env->exception_index = exception;
592
        env->error_code = error_code;
593
        ret = 1;
594
    }
595
    return ret;
596
}
597

    
598
uint32_t _load_xer (CPUState *env)
599
{
600
    return (xer_so << XER_SO) |
601
        (xer_ov << XER_OV) |
602
        (xer_ca << XER_CA) |
603
        (xer_bc << XER_BC);
604
}
605

    
606
void _store_xer (CPUState *env, uint32_t value)
607
{
608
    xer_so = (value >> XER_SO) & 0x01;
609
    xer_ov = (value >> XER_OV) & 0x01;
610
    xer_ca = (value >> XER_CA) & 0x01;
611
    xer_bc = (value >> XER_BC) & 0x1f;
612
}
613

    
614
uint32_t _load_msr (CPUState *env)
615
{
616
    return (msr_pow << MSR_POW) |
617
        (msr_ile << MSR_ILE) |
618
        (msr_ee << MSR_EE) |
619
        (msr_pr << MSR_PR) |
620
        (msr_fp << MSR_FP) |
621
        (msr_me << MSR_ME) |
622
        (msr_fe0 << MSR_FE0) |
623
        (msr_se << MSR_SE) |
624
        (msr_be << MSR_BE) |
625
        (msr_fe1 << MSR_FE1) |
626
        (msr_ip << MSR_IP) |
627
        (msr_ir << MSR_IR) |
628
        (msr_dr << MSR_DR) |
629
        (msr_ri << MSR_RI) |
630
        (msr_le << MSR_LE);
631
}
632

    
633
void _store_msr (CPUState *env, uint32_t value)
634
{
635
#if 0 // TRY
636
    if (((value >> MSR_IR) & 0x01) != msr_ir ||
637
        ((value >> MSR_DR) & 0x01) != msr_dr)
638
    {
639
        /* Flush all tlb when changing translation mode or privilege level */
640
        tlb_flush(env, 1);
641
    }
642
#endif
643
    msr_pow = (value >> MSR_POW) & 0x03;
644
    msr_ile = (value >> MSR_ILE) & 0x01;
645
    msr_ee = (value >> MSR_EE) & 0x01;
646
    msr_pr = (value >> MSR_PR) & 0x01;
647
    msr_fp = (value >> MSR_FP) & 0x01;
648
    msr_me = (value >> MSR_ME) & 0x01;
649
    msr_fe0 = (value >> MSR_FE0) & 0x01;
650
    msr_se = (value >> MSR_SE) & 0x01;
651
    msr_be = (value >> MSR_BE) & 0x01;
652
    msr_fe1 = (value >> MSR_FE1) & 0x01;
653
    msr_ip = (value >> MSR_IP) & 0x01;
654
    msr_ir = (value >> MSR_IR) & 0x01;
655
    msr_dr = (value >> MSR_DR) & 0x01;
656
    msr_ri = (value >> MSR_RI) & 0x01;
657
    msr_le = (value >> MSR_LE) & 0x01;
658
}
659

    
660
void do_interrupt (CPUState *env)
661
{
662
#if defined (CONFIG_USER_ONLY)
663
    env->exception_index |= 0x100;
664
#else
665
    uint32_t msr;
666
    int excp = env->exception_index;
667

    
668
    msr = _load_msr(env);
669
#if defined (DEBUG_EXCEPTIONS)
670
    if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) 
671
    {
672
        if (loglevel > 0) {
673
            fprintf(logfile, "Raise exception at 0x%08x => 0x%08x (%02x)\n",
674
                    env->nip, excp << 8, env->error_code);
675
        }
676
        if (loglevel > 0)
677
            cpu_dump_state(env, logfile, fprintf, 0);
678
    }
679
#endif
680
    if (loglevel & CPU_LOG_INT) {
681
        fprintf(logfile, "Raise exception at 0x%08x => 0x%08x (%02x)\n",
682
                env->nip, excp << 8, env->error_code);
683
    }
684
    /* Generate informations in save/restore registers */
685
    switch (excp) {
686
    case EXCP_OFCALL:
687
#if defined (USE_OPEN_FIRMWARE)
688
        env->gpr[3] = OF_client_entry((void *)env->gpr[3]);
689
#endif
690
        return;
691
    case EXCP_RTASCALL:
692
#if defined (USE_OPEN_FIRMWARE)
693
        printf("RTAS call !\n");
694
        env->gpr[3] = RTAS_entry((void *)env->gpr[3]);
695
        printf("RTAS call done\n");
696
#endif
697
        return;
698
    case EXCP_NONE:
699
        /* Do nothing */
700
#if defined (DEBUG_EXCEPTIONS)
701
        printf("%s: escape EXCP_NONE\n", __func__);
702
#endif
703
        return;
704
    case EXCP_RESET:
705
        if (msr_ip)
706
            excp += 0xFFC00;
707
        goto store_next;
708
    case EXCP_MACHINE_CHECK:
709
        if (msr_me == 0) {
710
            cpu_abort(env, "Machine check exception while not allowed\n");
711
        }
712
        msr_me = 0;
713
        break;
714
    case EXCP_DSI:
715
        /* Store exception cause */
716
        /* data location address has been stored
717
         * when the fault has been detected
718
     */
719
        msr &= ~0xFFFF0000;
720
        env->spr[DSISR] = 0;
721
        if (env->error_code &  EXCP_DSI_TRANSLATE)
722
            env->spr[DSISR] |= 0x40000000;
723
        else if (env->error_code & EXCP_DSI_PROT)
724
            env->spr[DSISR] |= 0x08000000;
725
        else if (env->error_code & EXCP_DSI_NOTSUP) {
726
            env->spr[DSISR] |= 0x80000000;
727
            if (env->error_code & EXCP_DSI_DIRECT)
728
                env->spr[DSISR] |= 0x04000000;
729
        }
730
        if (env->error_code & EXCP_DSI_STORE)
731
            env->spr[DSISR] |= 0x02000000;
732
        if ((env->error_code & 0xF) == EXCP_DSI_DABR)
733
            env->spr[DSISR] |= 0x00400000;
734
        if (env->error_code & EXCP_DSI_ECXW)
735
            env->spr[DSISR] |= 0x00100000;
736
#if defined (DEBUG_EXCEPTIONS)
737
        if (loglevel) {
738
            fprintf(logfile, "DSI exception: DSISR=0x%08x, DAR=0x%08x\n",
739
                    env->spr[DSISR], env->spr[DAR]);
740
        } else {
741
            printf("DSI exception: DSISR=0x%08x, DAR=0x%08x nip=0x%08x\n",
742
                   env->spr[DSISR], env->spr[DAR], env->nip);
743
        }
744
#endif
745
        goto store_next;
746
    case EXCP_ISI:
747
        /* Store exception cause */
748
        msr &= ~0xFFFF0000;
749
        if (env->error_code == EXCP_ISI_TRANSLATE)
750
            msr |= 0x40000000;
751
        else if (env->error_code == EXCP_ISI_NOEXEC ||
752
                 env->error_code == EXCP_ISI_GUARD ||
753
                 env->error_code == EXCP_ISI_DIRECT)
754
            msr |= 0x10000000;
755
        else
756
            msr |= 0x08000000;
757
#if defined (DEBUG_EXCEPTIONS)
758
        if (loglevel) {
759
            fprintf(logfile, "ISI exception: msr=0x%08x, nip=0x%08x\n",
760
                    msr, env->nip);
761
        } else {
762
            printf("ISI exception: msr=0x%08x, nip=0x%08x tbl:0x%08x\n",
763
                   msr, env->nip, env->spr[V_TBL]);
764
        }
765
#endif
766
        goto store_next;
767
    case EXCP_EXTERNAL:
768
        if (msr_ee == 0) {
769
#if defined (DEBUG_EXCEPTIONS)
770
            if (loglevel > 0) {
771
                fprintf(logfile, "Skipping hardware interrupt\n");
772
    }
773
#endif
774
            /* Requeue it */
775
            do_raise_exception(EXCP_EXTERNAL);
776
            return;
777
            }
778
        goto store_next;
779
    case EXCP_ALIGN:
780
        /* Store exception cause */
781
        /* Get rS/rD and rA from faulting opcode */
782
        env->spr[DSISR] |=
783
            (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16;
784
        /* data location address has been stored
785
         * when the fault has been detected
786
         */
787
        goto store_current;
788
    case EXCP_PROGRAM:
789
        msr &= ~0xFFFF0000;
790
        switch (env->error_code & ~0xF) {
791
        case EXCP_FP:
792
            if (msr_fe0 == 0 && msr_fe1 == 0) {
793
#if defined (DEBUG_EXCEPTIONS)
794
                printf("Ignore floating point exception\n");
795
#endif
796
                return;
797
        }
798
            msr |= 0x00100000;
799
            /* Set FX */
800
            env->fpscr[7] |= 0x8;
801
            /* Finally, update FEX */
802
            if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) &
803
                ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3)))
804
                env->fpscr[7] |= 0x4;
805
        break;
806
        case EXCP_INVAL:
807
            //            printf("Invalid instruction at 0x%08x\n", env->nip);
808
            msr |= 0x00080000;
809
        break;
810
        case EXCP_PRIV:
811
            msr |= 0x00040000;
812
        break;
813
        case EXCP_TRAP:
814
            msr |= 0x00020000;
815
            break;
816
        default:
817
            /* Should never occur */
818
        break;
819
    }
820
        msr |= 0x00010000;
821
        goto store_current;
822
    case EXCP_NO_FP:
823
        goto store_current;
824
    case EXCP_DECR:
825
        if (msr_ee == 0) {
826
            /* Requeue it */
827
            do_raise_exception(EXCP_DECR);
828
            return;
829
        }
830
        goto store_next;
831
    case EXCP_SYSCALL:
832
        if (loglevel & CPU_LOG_INT) {
833
            fprintf(logfile, "syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n",
834
                    env->gpr[0], env->gpr[3], env->gpr[4],
835
                    env->gpr[5], env->gpr[6]);
836
            if (env->gpr[0] == 4 && env->gpr[3] == 1) {
837
                int len, addr, i;
838
                uint8_t c;
839

    
840
                fprintf(logfile, "write: ");
841
                addr = env->gpr[4];
842
                len = env->gpr[5];
843
                if (len > 64)
844
                    len = 64;
845
                for(i = 0; i < len; i++) {
846
                    c = 0;
847
                    cpu_memory_rw_debug(env, addr + i, &c, 1, 0);
848
                    if (c < 32 || c > 126)
849
                        c = '.';
850
                    fprintf(logfile, "%c", c);
851
                }
852
                fprintf(logfile, "\n");
853
            }
854
        }
855
        goto store_next;
856
    case EXCP_TRACE:
857
        goto store_next;
858
    case EXCP_FP_ASSIST:
859
        goto store_next;
860
    case EXCP_MTMSR:
861
        /* Nothing to do */
862
        return;
863
    case EXCP_BRANCH:
864
        /* Nothing to do */
865
        return;
866
    case EXCP_RFI:
867
        /* Restore user-mode state */
868
        tb_flush(env);
869
#if defined (DEBUG_EXCEPTIONS)
870
        if (msr_pr == 1)
871
            printf("Return from exception => 0x%08x\n", (uint32_t)env->nip);
872
#endif
873
        return;
874
    store_current:
875
        /* SRR0 is set to current instruction */
876
        env->spr[SRR0] = (uint32_t)env->nip - 4;
877
        break;
878
    store_next:
879
        /* SRR0 is set to next instruction */
880
        env->spr[SRR0] = (uint32_t)env->nip;
881
        break;
882
    }
883
    env->spr[SRR1] = msr;
884
    /* reload MSR with correct bits */
885
    msr_pow = 0;
886
    msr_ee = 0;
887
    msr_pr = 0;
888
    msr_fp = 0;
889
    msr_fe0 = 0;
890
    msr_se = 0;
891
    msr_be = 0;
892
    msr_fe1 = 0;
893
    msr_ir = 0;
894
    msr_dr = 0;
895
    msr_ri = 0;
896
    msr_le = msr_ile;
897
    /* Jump to handler */
898
    env->nip = excp << 8;
899
    env->exception_index = EXCP_NONE;
900
    /* Invalidate all TLB as we may have changed translation mode */
901
    tlb_flush(env, 1);
902
    /* ensure that no TB jump will be modified as
903
       the program flow was changed */
904
#ifdef __sparc__
905
    tmp_T0 = 0;
906
#else
907
    T0 = 0;
908
#endif
909
#endif
910
    env->exception_index = -1;
911
}