Statistics
| Branch: | Revision:

root / target-ppc / helper.c @ 18fba28c

History | View | Annotate | Download (27.3 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
    /* XXX: should enter PM state if msr_pow has been set */
659
}
660

    
661
#if defined (CONFIG_USER_ONLY)
662
void do_interrupt (CPUState *env)
663
{
664
    env->exception_index = -1;
665
}
666
#else
667
void do_interrupt (CPUState *env)
668
{
669
    uint32_t msr;
670
    int excp;
671

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

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