added cpu_get_phys_page_debug()
[qemu] / target-ppc / helper.c
1 /*
2  *  PPC emulation helpers for qemu.
3  * 
4  *  Copyright (c) 2003 Jocelyn Mayer
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include <sys/mman.h>
21
22 #include "exec.h"
23 #if defined (USE_OPEN_FIRMWARE)
24 #include "of.h"
25 #endif
26
27 //#define DEBUG_MMU
28 //#define DEBUG_BATS
29 //#define DEBUG_EXCEPTIONS
30
31 extern FILE *logfile, *stderr;
32 void exit (int);
33 void abort (void);
34
35 int phys_ram_size;
36 int phys_ram_fd;
37 uint8_t *phys_ram_base;
38
39 void cpu_loop_exit(void)
40 {
41     longjmp(env->jmp_env, 1);
42 }
43
44 void do_process_exceptions (void)
45 {
46     cpu_loop_exit();
47 }
48
49 int check_exception_state (CPUState *env)
50 {
51     int i;
52
53     /* Process PPC exceptions */
54     for (i = 1; i  < EXCP_PPC_MAX; i++) {
55         if (env->exceptions & (1 << i)) {
56             switch (i) {
57             case EXCP_EXTERNAL:
58             case EXCP_DECR:
59                 if (msr_ee == 0)
60                     return 0;
61                 break;
62             case EXCP_PROGRAM:
63                 if (env->errors[EXCP_PROGRAM] == EXCP_FP &&
64                     msr_fe0 == 0 && msr_fe1 == 0)
65                     return 0;
66                 break;
67             default:
68                 break;
69             }
70             env->exception_index = i;
71             env->error_code = env->errors[i];
72             return 1;
73         }
74     }
75
76     return 0;
77 }
78
79 /*****************************************************************************/
80 /* PPC MMU emulation */
81 /* Perform BAT hit & translation */
82 static int get_bat (CPUState *env, uint32_t *real, int *prot,
83                     uint32_t virtual, int rw, int type)
84 {
85     uint32_t *BATlt, *BATut, *BATu, *BATl;
86     uint32_t base, BEPIl, BEPIu, bl;
87     int i;
88     int ret = -1;
89
90 #if defined (DEBUG_BATS)
91     if (loglevel > 0) {
92         fprintf(logfile, "%s: %cBAT v 0x%08x\n", __func__,
93                type == ACCESS_CODE ? 'I' : 'D', virtual);
94     }
95     printf("%s: %cBAT v 0x%08x\n", __func__,
96            type == ACCESS_CODE ? 'I' : 'D', virtual);
97 #endif
98     switch (type) {
99     case ACCESS_CODE:
100         BATlt = env->IBAT[1];
101         BATut = env->IBAT[0];
102         break;
103     default:
104         BATlt = env->DBAT[1];
105         BATut = env->DBAT[0];
106         break;
107     }
108 #if defined (DEBUG_BATS)
109     if (loglevel > 0) {
110         fprintf(logfile, "%s...: %cBAT v 0x%08x\n", __func__,
111                type == ACCESS_CODE ? 'I' : 'D', virtual);
112     }
113     printf("%s...: %cBAT v 0x%08x\n", __func__,
114            type == ACCESS_CODE ? 'I' : 'D', virtual);
115 #endif
116     base = virtual & 0xFFFC0000;
117     for (i = 0; i < 4; i++) {
118         BATu = &BATut[i];
119         BATl = &BATlt[i];
120         BEPIu = *BATu & 0xF0000000;
121         BEPIl = *BATu & 0x0FFE0000;
122         bl = (*BATu & 0x00001FFC) << 15;
123 #if defined (DEBUG_BATS)
124         if (loglevel > 0) {
125             fprintf(logfile, "%s: %cBAT%d v 0x%08x BATu 0x%08x BATl 0x%08x\n",
126                     __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
127                     *BATu, *BATl);
128         } else {
129             printf("%s: %cBAT%d v 0x%08x BATu 0x%08x BATl 0x%08x\n",
130                    __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
131                    *BATu, *BATl);
132         }
133 #endif
134         if ((virtual & 0xF0000000) == BEPIu &&
135             ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
136             /* BAT matches */
137             if ((msr_pr == 0 && (*BATu & 0x00000002)) ||
138                 (msr_pr == 1 && (*BATu & 0x00000001))) {
139                 /* Get physical address */
140                 *real = (*BATl & 0xF0000000) |
141                     ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
142                     (virtual & 0x0001FFFF);
143                 if (*BATl & 0x00000001)
144                     *prot = PROT_READ;
145                 if (*BATl & 0x00000002)
146                     *prot = PROT_WRITE | PROT_READ;
147 #if defined (DEBUG_BATS)
148                 if (loglevel > 0) {
149                     fprintf(logfile, "BAT %d match: r 0x%08x prot=%c%c\n",
150                             i, *real, *prot & PROT_READ ? 'R' : '-',
151                             *prot & PROT_WRITE ? 'W' : '-');
152                 } else {
153                     printf("BAT %d match: 0x%08x => 0x%08x prot=%c%c\n",
154                            i, virtual, *real, *prot & PROT_READ ? 'R' : '-',
155                            *prot & PROT_WRITE ? 'W' : '-');
156                 }
157 #endif
158                 ret = 0;
159                 break;
160             }
161         }
162     }
163     if (ret < 0) {
164 #if defined (DEBUG_BATS)
165         printf("no BAT match for 0x%08x:\n", virtual);
166         for (i = 0; i < 4; i++) {
167             BATu = &BATut[i];
168             BATl = &BATlt[i];
169             BEPIu = *BATu & 0xF0000000;
170             BEPIl = *BATu & 0x0FFE0000;
171             bl = (*BATu & 0x00001FFC) << 15;
172             printf("%s: %cBAT%d v 0x%08x BATu 0x%08x BATl 0x%08x \n\t"
173                    "0x%08x 0x%08x 0x%08x\n",
174                    __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
175                    *BATu, *BATl, BEPIu, BEPIl, bl);
176         }
177 #endif
178         env->spr[DAR] = virtual;
179     }
180     /* No hit */
181     return ret;
182 }
183
184 /* PTE table lookup */
185 static int find_pte (uint32_t *RPN, int *prot, uint32_t base, uint32_t va,
186                      int h, int key, int rw)
187 {
188     uint32_t pte0, pte1, keep = 0;
189     int i, good = -1, store = 0;
190     int ret = -1; /* No entry found */
191
192     for (i = 0; i < 8; i++) {
193         pte0 = ldl_raw((void *)((uint32_t)phys_ram_base + base + (i * 8)));
194         pte1 =  ldl_raw((void *)((uint32_t)phys_ram_base + base + (i * 8) + 4));
195 #if defined (DEBUG_MMU)
196         printf("Load pte from 0x%08x => 0x%08x 0x%08x\n", base + (i * 8),
197                pte0, pte1);
198 #endif
199         /* Check validity and table match */
200         if (pte0 & 0x80000000 && (h == ((pte0 >> 6) & 1))) {
201 #if defined (DEBUG_MMU)
202             printf("PTE is valid and table matches... compare 0x%08x:%08x\n",
203                    pte0 & 0x7FFFFFBF, va);
204 #endif
205             /* Check vsid & api */
206             if ((pte0 & 0x7FFFFFBF) == va) {
207 #if defined (DEBUG_MMU)
208                 printf("PTE match !\n");
209 #endif
210                 if (good == -1) {
211                     good = i;
212                     keep = pte1;
213                 } else {
214                     /* All matches should have equal RPN, WIMG & PP */
215                     if ((keep & 0xFFFFF07B) != (pte1 & 0xFFFFF07B)) {
216                         printf("Bad RPN/WIMG/PP\n");
217                         return -1;
218                     }
219                 }
220                 /* Check access rights */
221                 if (key == 0) {
222                     *prot = PROT_READ;
223                     if ((pte1 & 0x00000003) != 0x3)
224                         *prot |= PROT_WRITE;
225                 } else {
226                     switch (pte1 & 0x00000003) {
227                     case 0x0:
228                         *prot = 0;
229                         break;
230                     case 0x1:
231                     case 0x3:
232                         *prot = PROT_READ;
233                         break;
234                     case 0x2:
235                         *prot = PROT_READ | PROT_WRITE;
236                         break;
237                     }
238                 }
239                 if ((rw == 0 && *prot != 0) ||
240                     (rw == 1 && (*prot & PROT_WRITE))) {
241 #if defined (DEBUG_MMU)
242                     printf("PTE access granted !\n");
243 #endif
244                     good = i;
245                     keep = pte1;
246                     ret = 0;
247                 } else if (ret == -1) {
248                     ret = -2; /* Access right violation */
249 #if defined (DEBUG_MMU)
250                     printf("PTE access rejected\n");
251 #endif
252                 }
253             }
254         }
255     }
256     if (good != -1) {
257         *RPN = keep & 0xFFFFF000;
258 #if defined (DEBUG_MMU)
259         printf("found PTE at addr 0x%08x prot=0x%01x ret=%d\n",
260                *RPN, *prot, ret);
261 #endif
262         /* Update page flags */
263         if (!(keep & 0x00000100)) {
264             keep |= 0x00000100;
265             store = 1;
266         }
267         if (rw) {
268             if (!(keep & 0x00000080)) {
269                 keep |= 0x00000080;
270                 store = 1;
271             }
272         }
273         if (store)
274             stl_raw((void *)(base + (good * 2) + 1), keep);
275     }
276
277     return ret;
278 }
279
280 static inline uint32_t get_pgaddr (uint32_t sdr1, uint32_t hash, uint32_t mask)
281 {
282     return (sdr1 & 0xFFFF0000) | (hash & mask);
283 }
284
285 /* Perform segment based translation */
286 static int get_segment (CPUState *env, uint32_t *real, int *prot,
287                         uint32_t virtual, int rw, int type)
288 {
289     uint32_t pg_addr, sdr, ptem, vsid, pgidx;
290     uint32_t hash, mask;
291     uint32_t sr;
292     int key;
293     int ret = -1, ret2;
294
295     sr = env->sr[virtual >> 28];
296 #if defined (DEBUG_MMU)
297     printf("Check segment v=0x%08x %d 0x%08x nip=0x%08x lr=0x%08x ir=%d dr=%d "
298            "pr=%d t=%d\n", virtual, virtual >> 28, sr, env->nip,
299            env->lr, msr_ir, msr_dr, msr_pr, type);
300 #endif
301     key = ((sr & 0x20000000) && msr_pr == 1) ||
302         ((sr & 0x40000000) && msr_pr == 0) ? 1 : 0;
303     if ((sr & 0x80000000) == 0) {
304 #if defined (DEBUG_MMU)
305         printf("pte segment: key=%d n=0x%08x\n", key, sr & 0x10000000);
306 #endif
307         /* Check if instruction fetch is allowed, if needed */
308         if (type != ACCESS_CODE || (sr & 0x10000000) == 0) {
309             /* Page address translation */
310             vsid = sr & 0x00FFFFFF;
311             pgidx = (virtual >> 12) & 0xFFFF;
312             sdr = env->spr[SDR1];
313             hash = ((vsid ^ pgidx) & 0x07FFFF) << 6;
314             mask = ((sdr & 0x000001FF) << 16) | 0xFFC0;
315             pg_addr = get_pgaddr(sdr, hash, mask);
316             ptem = (vsid << 7) | (pgidx >> 10);
317 #if defined (DEBUG_MMU)
318             printf("0 sdr1=0x%08x vsid=0x%06x api=0x%04x hash=0x%07x "
319                    "pg_addr=0x%08x\n", sdr, vsid, pgidx, hash, pg_addr);
320 #endif
321             /* Primary table lookup */
322             ret = find_pte(real, prot, pg_addr, ptem, 0, key, rw);
323             if (ret < 0) {
324                 /* Secondary table lookup */
325                 hash = (~hash) & 0x01FFFFC0;
326                 pg_addr = get_pgaddr(sdr, hash, mask);
327 #if defined (DEBUG_MMU)
328                 printf("1 sdr1=0x%08x vsid=0x%06x api=0x%04x hash=0x%05x "
329                        "pg_addr=0x%08x\n", sdr, vsid, pgidx, hash, pg_addr);
330 #endif
331                 ret2 = find_pte(real, prot, pg_addr, ptem, 1, key, rw);
332                 if (ret2 != -1)
333                     ret = ret2;
334             }
335             if (ret != -1)
336                 *real |= (virtual & 0x00000FFF);
337             if (ret == -2 && type == ACCESS_CODE && (sr & 0x10000000))
338                 ret = -3;
339         } else {
340 #if defined (DEBUG_MMU)
341             printf("No access allowed\n");
342 #endif
343         }
344     } else {
345 #if defined (DEBUG_MMU)
346         printf("direct store...\n");
347 #endif
348         /* Direct-store segment : absolutely *BUGGY* for now */
349         switch (type) {
350         case ACCESS_INT:
351             /* Integer load/store : only access allowed */
352             break;
353         case ACCESS_CODE:
354             /* No code fetch is allowed in direct-store areas */
355             return -4;
356         case ACCESS_FLOAT:
357             /* Floating point load/store */
358             return -4;
359         case ACCESS_RES:
360             /* lwarx, ldarx or srwcx. */
361             return -4;
362         case ACCESS_CACHE:
363             /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
364             /* Should make the instruction do no-op.
365              * As it already do no-op, it's quite easy :-)
366              */
367             *real = virtual;
368             return 0;
369         case ACCESS_EXT:
370             /* eciwx or ecowx */
371             return -4;
372         default:
373             if (logfile) {
374                 fprintf(logfile, "ERROR: instruction should not need "
375                         "address translation\n");
376             }
377             printf("ERROR: instruction should not need "
378                    "address translation\n");
379             return -4;
380         }
381         if ((rw == 1 || key != 1) && (rw == 0 || key != 0)) {
382             *real = virtual;
383             ret = 2;
384         } else {
385             ret = -2;
386         }
387     }
388
389     return ret;
390 }
391
392 int get_physical_address (CPUState *env, uint32_t *physical, int *prot,
393                           uint32_t address, int rw, int access_type)
394 {
395     int ret;
396
397     if (loglevel > 0) {
398         fprintf(logfile, "%s\n", __func__);
399     }
400     if ((access_type == ACCESS_CODE && msr_ir == 0) || msr_dr == 0) {
401         /* No address translation */
402         *physical = address;
403         *prot = PROT_READ | PROT_WRITE;
404         ret = 0;
405     } else {
406         /* Try to find a BAT */
407         ret = get_bat(env, physical, prot, address, rw, access_type);
408         if (ret < 0) {
409             /* We didn't match any BAT entry */
410             ret = get_segment(env, physical, prot, address, rw, access_type);
411         }
412     }
413     
414     return ret;
415 }
416
417 #if defined(CONFIG_USER_ONLY) 
418 target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
419 {
420     return addr;
421 }
422 #else
423 target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
424 {
425     uint32_t phys_addr;
426     int prot;
427
428     if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0)
429         return -1;
430     return phys_addr;
431 }
432 #endif
433
434 #if !defined(CONFIG_USER_ONLY) 
435
436 #define MMUSUFFIX _mmu
437 #define GETPC() (__builtin_return_address(0))
438
439 #define SHIFT 0
440 #include "softmmu_template.h"
441
442 #define SHIFT 1
443 #include "softmmu_template.h"
444
445 #define SHIFT 2
446 #include "softmmu_template.h"
447
448 #define SHIFT 3
449 #include "softmmu_template.h"
450
451 /* try to fill the TLB and return an exception if error. If retaddr is
452    NULL, it means that the function was called in C code (i.e. not
453    from generated code or from helper.c) */
454 /* XXX: fix it to restore all registers */
455 void tlb_fill(unsigned long addr, int is_write, int flags, void *retaddr)
456 {
457     TranslationBlock *tb;
458     int ret, is_user;
459     unsigned long pc;
460     CPUState *saved_env;
461
462     /* XXX: hack to restore env in all cases, even if not called from
463        generated code */
464     saved_env = env;
465     env = cpu_single_env;
466     is_user = flags & 0x01;
467     {
468         unsigned long tlb_addrr, tlb_addrw;
469         int index;
470         index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
471         tlb_addrr = env->tlb_read[is_user][index].address;
472         tlb_addrw = env->tlb_write[is_user][index].address;
473 #if 0
474         printf("%s 1 %p %p idx=%d addr=0x%08lx tbl_addr=0x%08lx 0x%08lx "
475                "(0x%08lx 0x%08lx)\n", __func__, env,
476                &env->tlb_read[is_user][index], index, addr,
477                tlb_addrr, tlb_addrw, addr & TARGET_PAGE_MASK,
478                tlb_addrr & (TARGET_PAGE_MASK | TLB_INVALID_MASK));
479 #endif
480     }
481     ret = cpu_handle_mmu_fault(env, addr, is_write, flags, 1);
482     if (ret) {
483         if (retaddr) {
484             /* now we have a real cpu fault */
485             pc = (unsigned long)retaddr;
486             tb = tb_find_pc(pc);
487             if (tb) {
488                 /* the PC is inside the translated code. It means that we have
489                    a virtual CPU fault */
490                 cpu_restore_state(tb, env, pc);
491             }
492         }
493         do_queue_exception_err(env->exception_index, env->error_code);
494         do_process_exceptions();
495     }
496     {
497         unsigned long tlb_addrr, tlb_addrw;
498         int index;
499         index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
500         tlb_addrr = env->tlb_read[is_user][index].address;
501         tlb_addrw = env->tlb_write[is_user][index].address;
502 #if 0
503         printf("%s 2 %p %p idx=%d addr=0x%08lx tbl_addr=0x%08lx 0x%08lx "
504                "(0x%08lx 0x%08lx)\n", __func__, env,
505                &env->tlb_read[is_user][index], index, addr,
506                tlb_addrr, tlb_addrw, addr & TARGET_PAGE_MASK,
507                tlb_addrr & (TARGET_PAGE_MASK | TLB_INVALID_MASK));
508 #endif
509     }
510     env = saved_env;
511 }
512
513 void cpu_ppc_init_mmu(CPUPPCState *env)
514 {
515     /* Nothing to do: all translation are disabled */
516 }
517 #endif
518
519 /* Perform address translation */
520 int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
521                               int flags, int is_softmmu)
522 {
523     uint32_t physical;
524     int prot;
525     int exception = 0, error_code = 0;
526     int is_user, access_type;
527     int ret = 0;
528
529 //    printf("%s 0\n", __func__);
530     is_user = flags & 0x01;
531     access_type = env->access_type;
532     if (env->user_mode_only) {
533         /* user mode only emulation */
534         ret = -1;
535         goto do_fault;
536     }
537     ret = get_physical_address(env, &physical, &prot,
538                                address, rw, access_type);
539     if (ret == 0) {
540         ret = tlb_set_page(env, address, physical, prot, is_user, is_softmmu);
541     } else if (ret < 0) {
542     do_fault:
543 #if defined (DEBUG_MMU)
544         printf("%s 5\n", __func__);
545         printf("nip=0x%08x LR=0x%08x CTR=0x%08x MSR=0x%08x TBL=0x%08x\n",
546                env->nip, env->lr, env->ctr, /*msr*/0, env->tb[0]);
547         {
548             int  i;
549             for (i = 0; i < 32; i++) {
550                 if ((i & 7) == 0)
551                     printf("GPR%02d:", i);
552                 printf(" %08x", env->gpr[i]);
553                 if ((i & 7) == 7)
554                     printf("\n");
555             }
556             printf("CR: 0x");
557             for (i = 0; i < 8; i++)
558                 printf("%01x", env->crf[i]);
559             printf("  [");
560             for (i = 0; i < 8; i++) {
561                 char a = '-';
562                 if (env->crf[i] & 0x08)
563                     a = 'L';
564                 else if (env->crf[i] & 0x04)
565                     a = 'G';
566                 else if (env->crf[i] & 0x02)
567                     a = 'E';
568                 printf(" %c%c", a, env->crf[i] & 0x01 ? 'O' : ' ');
569             }
570             printf(" ] ");
571         }
572         printf("TB: 0x%08x %08x\n", env->tb[1], env->tb[0]);
573         printf("SRR0 0x%08x SRR1 0x%08x\n", env->spr[SRR0], env->spr[SRR1]);
574 #endif
575         if (access_type == ACCESS_CODE) {
576             exception = EXCP_ISI;
577             switch (ret) {
578             case -1:
579                 /* No matches in page tables */
580                 error_code = EXCP_ISI_TRANSLATE;
581                 break;
582             case -2:
583                 /* Access rights violation */
584                 error_code = EXCP_ISI_PROT;
585                 break;
586             case -3:
587                 error_code = EXCP_ISI_NOEXEC;
588                 break;
589             case -4:
590                 /* Direct store exception */
591                 /* No code fetch is allowed in direct-store areas */
592                 exception = EXCP_ISI;
593                 error_code = EXCP_ISI_NOEXEC;
594                 break;
595             }
596         } else {
597             exception = EXCP_DSI;
598             switch (ret) {
599             case -1:
600                 /* No matches in page tables */
601                 error_code = EXCP_DSI_TRANSLATE;
602                 break;
603             case -2:
604                 /* Access rights violation */
605                 error_code = EXCP_DSI_PROT;
606                 break;
607             case -4:
608                 /* Direct store exception */
609                 switch (access_type) {
610                 case ACCESS_FLOAT:
611                     /* Floating point load/store */
612                     exception = EXCP_ALIGN;
613                     error_code = EXCP_ALIGN_FP;
614                     break;
615                 case ACCESS_RES:
616                     /* lwarx, ldarx or srwcx. */
617                     exception = EXCP_DSI;
618                     error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT;
619                     if (rw)
620                         error_code |= EXCP_DSI_STORE;
621                     break;
622                 case ACCESS_EXT:
623                     /* eciwx or ecowx */
624                     exception = EXCP_DSI;
625                     error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT | EXCP_ECXW;
626                     break;
627                 default:
628                     exception = EXCP_PROGRAM;
629                     error_code = EXCP_INVAL | EXCP_INVAL_INVAL;
630                     break;
631                 }
632             }
633             if (rw)
634                 error_code |= EXCP_DSI_STORE;
635             /* Should find a better solution:
636              * this will be invalid for some exception if more than one
637              * exception occurs for one instruction
638              */
639             env->spr[DSISR] = 0;
640             if (error_code & EXCP_DSI_DIRECT) {
641                 env->spr[DSISR] |= 0x80000000;
642                 if (access_type == ACCESS_EXT ||
643                     access_type == ACCESS_RES)
644                     env->spr[DSISR] |= 0x04000000;
645             }
646             if ((error_code & 0xF) == EXCP_DSI_TRANSLATE)
647                 env->spr[DSISR] |= 0x40000000;
648             if (error_code & EXCP_DSI_PROT)
649                 env->spr[DSISR] |= 0x08000000;
650             if (error_code & EXCP_DSI_STORE)
651                 env->spr[DSISR] |= 0x02000000;
652             if ((error_code & 0xF) == EXCP_DSI_DABR)
653                 env->spr[DSISR] |= 0x00400000;
654             if (access_type == ACCESS_EXT)
655                 env->spr[DSISR] |= 0x00100000;
656         }
657 #if 0
658         printf("%s: set exception to %d %02x\n",
659                __func__, exception, error_code);
660 #endif
661         env->exception_index = exception;
662         env->error_code = error_code;
663         /* Store fault address */
664         env->spr[DAR] = address;
665         ret = 1;
666     }
667
668     return ret;
669 }
670
671 uint32_t _load_xer (void)
672 {
673     return (xer_so << XER_SO) |
674         (xer_ov << XER_OV) |
675         (xer_ca << XER_CA) |
676         (xer_bc << XER_BC);
677 }
678
679 void _store_xer (uint32_t value)
680 {
681     xer_so = (value >> XER_SO) & 0x01;
682     xer_ov = (value >> XER_OV) & 0x01;
683     xer_ca = (value >> XER_CA) & 0x01;
684     xer_bc = (value >> XER_BC) & 0x1f;
685 }
686
687 uint32_t _load_msr (void)
688 {
689     return (msr_pow << MSR_POW) |
690         (msr_ile << MSR_ILE) |
691         (msr_ee << MSR_EE) |
692         (msr_pr << MSR_PR) |
693         (msr_fp << MSR_FP) |
694         (msr_me << MSR_ME) |
695         (msr_fe0 << MSR_FE0) |
696         (msr_se << MSR_SE) |
697         (msr_be << MSR_BE) |
698         (msr_fe1 << MSR_FE1) |
699         (msr_ip << MSR_IP) |
700         (msr_ir << MSR_IR) |
701         (msr_dr << MSR_DR) |
702         (msr_ri << MSR_RI) |
703         (msr_le << MSR_LE);
704 }
705
706 void _store_msr (uint32_t value)
707 {
708     msr_pow = (value >> MSR_POW) & 0x03;
709     msr_ile = (value >> MSR_ILE) & 0x01;
710     msr_ee = (value >> MSR_EE) & 0x01;
711     msr_pr = (value >> MSR_PR) & 0x01;
712     msr_fp = (value >> MSR_FP) & 0x01;
713     msr_me = (value >> MSR_ME) & 0x01;
714     msr_fe0 = (value >> MSR_FE0) & 0x01;
715     msr_se = (value >> MSR_SE) & 0x01;
716     msr_be = (value >> MSR_BE) & 0x01;
717     msr_fe1 = (value >> MSR_FE1) & 0x01;
718     msr_ip = (value >> MSR_IP) & 0x01;
719     msr_ir = (value >> MSR_IR) & 0x01;
720     msr_dr = (value >> MSR_DR) & 0x01;
721     msr_ri = (value >> MSR_RI) & 0x01;
722     msr_le = (value >> MSR_LE) & 0x01;
723 }
724
725 void do_interrupt (CPUState *env)
726 {
727 #if defined (CONFIG_USER_ONLY)
728     env->exception_index |= 0x100;
729 #else
730     uint32_t msr;
731     int excp = env->exception_index;
732
733     /* Dequeue PPC exceptions */
734     if (excp < EXCP_PPC_MAX)
735         env->exceptions &= ~(1 << excp);
736     msr = _load_msr();
737 #if defined (DEBUG_EXCEPTIONS)
738     if (excp != EXCP_DECR && excp == EXCP_PROGRAM && excp < EXCP_PPC_MAX) 
739     {
740         if (loglevel > 0) {
741             fprintf(logfile, "Raise exception at 0x%08x => 0x%08x (%02x)\n",
742                     env->nip, excp << 8, env->error_code);
743         } else {
744             printf("Raise exception at 0x%08x => 0x%08x (%02x)\n",
745                    env->nip, excp << 8, env->error_code);
746         }
747         printf("nip=0x%08x LR=0x%08x CTR=0x%08x MSR=0x%08x DECR=0x%08x\n",
748                env->nip, env->lr, env->ctr, msr, env->decr);
749         {
750     int i;
751             for (i = 0; i < 32; i++) {
752                 if ((i & 7) == 0)
753                     printf("GPR%02d:", i);
754                 printf(" %08x", env->gpr[i]);
755                 if ((i & 7) == 7)
756                     printf("\n");
757     }
758             printf("CR: 0x");
759     for (i = 0; i < 8; i++)
760                 printf("%01x", env->crf[i]);
761             printf("  [");
762             for (i = 0; i < 8; i++) {
763                 char a = '-';
764                 if (env->crf[i] & 0x08)
765                     a = 'L';
766                 else if (env->crf[i] & 0x04)
767                     a = 'G';
768                 else if (env->crf[i] & 0x02)
769                     a = 'E';
770                 printf(" %c%c", a, env->crf[i] & 0x01 ? 'O' : ' ');
771     }
772             printf(" ] ");
773     }
774         printf("TB: 0x%08x %08x\n", env->tb[1], env->tb[0]);
775         printf("XER 0x%08x SRR0 0x%08x SRR1 0x%08x\n",
776                _load_xer(), env->spr[SRR0], env->spr[SRR1]);
777     }
778 #endif
779     /* Generate informations in save/restore registers */
780     switch (excp) {
781     case EXCP_OFCALL:
782 #if defined (USE_OPEN_FIRMWARE)
783         env->gpr[3] = OF_client_entry((void *)env->gpr[3]);
784 #endif
785         return;
786     case EXCP_RTASCALL:
787 #if defined (USE_OPEN_FIRMWARE)
788         printf("RTAS call !\n");
789         env->gpr[3] = RTAS_entry((void *)env->gpr[3]);
790         printf("RTAS call done\n");
791 #endif
792         return;
793     case EXCP_NONE:
794         /* Do nothing */
795 #if defined (DEBUG_EXCEPTIONS)
796         printf("%s: escape EXCP_NONE\n", __func__);
797 #endif
798         return;
799     case EXCP_RESET:
800         if (msr_ip)
801             excp += 0xFFC00;
802         goto store_next;
803     case EXCP_MACHINE_CHECK:
804         if (msr_me == 0) {
805             printf("Machine check exception while not allowed !\n");
806             if (loglevel) {
807                 fprintf(logfile,
808                         "Machine check exception while not allowed !\n");
809         }
810             abort();
811     }
812         msr_me = 0;
813         break;
814     case EXCP_DSI:
815         /* Store exception cause */
816         /* data location address has been stored
817          * when the fault has been detected
818      */
819         goto store_current;
820     case EXCP_ISI:
821         /* Store exception cause */
822         if (env->error_code == EXCP_ISI_TRANSLATE)
823             msr |= 0x40000000;
824         else if (env->error_code == EXCP_ISI_NOEXEC ||
825             env->error_code == EXCP_ISI_GUARD)
826             msr |= 0x10000000;
827         else
828             msr |= 0x08000000;
829         goto store_next;
830     case EXCP_EXTERNAL:
831         if (msr_ee == 0) {
832 #if defined (DEBUG_EXCEPTIONS)
833             if (loglevel > 0) {
834                 fprintf(logfile, "Skipping hardware interrupt\n");
835             } else {
836                 printf("Skipping hardware interrupt\n");
837     }
838 #endif
839             return;
840             }
841         goto store_next;
842     case EXCP_ALIGN:
843         /* Store exception cause */
844         /* Get rS/rD and rA from faulting opcode */
845         env->spr[DSISR] |=
846             (ldl_code((void *)(env->nip - 4)) & 0x03FF0000) >> 16;
847         /* data location address has been stored
848          * when the fault has been detected
849          */
850         goto store_current;
851     case EXCP_PROGRAM:
852         msr &= ~0xFFFF0000;
853         switch (env->error_code & ~0xF) {
854         case EXCP_FP:
855             if (msr_fe0 == 0 && msr_fe1 == 0) {
856 #if defined (DEBUG_EXCEPTIONS)
857                 printf("Ignore floating point exception\n");
858 #endif
859                 return;
860         }
861             msr |= 0x00100000;
862             /* Set FX */
863             env->fpscr[7] |= 0x8;
864             /* Finally, update FEX */
865             if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) &
866                 ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3)))
867                 env->fpscr[7] |= 0x4;
868         break;
869         case EXCP_INVAL:
870             msr |= 0x00080000;
871         break;
872         case EXCP_PRIV:
873             msr |= 0x00040000;
874         break;
875         case EXCP_TRAP:
876             msr |= 0x00020000;
877             break;
878         default:
879             /* Should never occur */
880         break;
881     }
882         msr |= 0x00010000;
883         goto store_current;
884     case EXCP_NO_FP:
885         goto store_current;
886     case EXCP_DECR:
887         if (msr_ee == 0) {
888             /* Requeue it */
889             do_queue_exception(EXCP_DECR);
890             return;
891         }
892         goto store_next;
893     case EXCP_SYSCALL:
894 #if defined (DEBUG_EXCEPTIONS)
895         printf("syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n",
896                env->gpr[0], env->gpr[3], env->gpr[4], env->gpr[5], env->gpr[6]);
897 #endif
898         goto store_next;
899     case EXCP_TRACE:
900         goto store_next;
901     case EXCP_FP_ASSIST:
902         goto store_next;
903     case EXCP_MTMSR:
904         /* Nothing to do */
905 #if defined (DEBUG_EXCEPTIONS)
906         printf("%s: escape EXCP_MTMSR\n", __func__);
907 #endif
908         return;
909     case EXCP_BRANCH:
910         /* Nothing to do */
911 #if defined (DEBUG_EXCEPTIONS)
912         printf("%s: escape EXCP_BRANCH\n", __func__);
913 #endif
914         return;
915     case EXCP_RFI:
916         /* Restore user-mode state */
917 #if defined (DEBUG_EXCEPTIONS)
918         printf("%s: escape EXCP_RFI\n", __func__);
919 #endif
920         return;
921     store_current:
922         /* SRR0 is set to current instruction */
923         env->spr[SRR0] = (uint32_t)env->nip - 4;
924         break;
925     store_next:
926         /* SRR0 is set to next instruction */
927         env->spr[SRR0] = (uint32_t)env->nip;
928         break;
929     }
930     env->spr[SRR1] = msr;
931     /* reload MSR with correct bits */
932     msr_pow = 0;
933     msr_ee = 0;
934     msr_pr = 0;
935     msr_fp = 0;
936     msr_fe0 = 0;
937     msr_se = 0;
938     msr_be = 0;
939     msr_fe1 = 0;
940     msr_ir = 0;
941     msr_dr = 0;
942     msr_ri = 0;
943     msr_le = msr_ile;
944     /* Jump to handler */
945     env->nip = excp << 8;
946     env->exception_index = EXCP_NONE;
947     /* Invalidate all TLB as we may have changed translation mode */
948     do_tlbia();
949     /* ensure that no TB jump will be modified as
950        the program flow was changed */
951 #ifdef __sparc__
952     tmp_T0 = 0;
953 #else
954     T0 = 0;
955 #endif
956 #endif
957 }