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