Make string arrays used to convert numbers to strings when DEBUG_EEPRO100 is enabled...
[qemu] / hw / alpha_palcode.c
1 /*
2  *  Alpha emulation - PALcode emulation for qemu.
3  *
4  *  Copyright (c) 2007 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, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <stdint.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23
24 #include "qemu.h"
25 #include "cpu.h"
26 #include "exec-all.h"
27
28 #if !defined (CONFIG_USER_ONLY)
29 /* Shared handlers */
30 static void pal_reset (CPUState *env);
31 /* Console handlers */
32 static void pal_console_call (CPUState *env, uint32_t palcode);
33 /* OpenVMS handlers */
34 static void pal_openvms_call (CPUState *env, uint32_t palcode);
35 /* UNIX / Linux handlers */
36 static void pal_unix_call (CPUState *env, uint32_t palcode);
37
38 pal_handler_t pal_handlers[] = {
39     /* Console handler */
40     {
41         .reset = &pal_reset,
42         .call_pal = &pal_console_call,
43     },
44     /* OpenVMS handler */
45     {
46         .reset = &pal_reset,
47         .call_pal = &pal_openvms_call,
48     },
49     /* UNIX / Linux handler */
50     {
51         .reset = &pal_reset,
52         .call_pal = &pal_unix_call,
53     },
54 };
55
56 #if 0
57 /* One must explicitly check that the TB is valid and the FOE bit is reset */
58 static void update_itb (void)
59 {
60     /* This writes into a temp register, not the actual one */
61     mtpr(TB_TAG);
62     mtpr(TB_CTL);
63     /* This commits the TB update */
64     mtpr(ITB_PTE);
65 }
66
67 static void update_dtb (void);
68 {
69     mtpr(TB_CTL);
70     /* This write into a temp register, not the actual one */
71     mtpr(TB_TAG);
72     /* This commits the TB update */
73     mtpr(DTB_PTE);
74 }
75 #endif
76
77 static void pal_reset (CPUState *env)
78 {
79 }
80
81 static void do_swappal (CPUState *env, uint64_t palid)
82 {
83     pal_handler_t *pal_handler;
84     int status;
85
86     status = 0;
87     switch (palid) {
88     case 0 ... 2:
89         pal_handler = &pal_handlers[palid];
90         env->pal_handler = pal_handler;
91         env->ipr[IPR_PAL_BASE] = -1ULL;
92         (*pal_handler->reset)(env);
93         break;
94     case 3 ... 255:
95         /* Unknown identifier */
96         env->ir[0] = 1;
97         return;
98     default:
99         /* We were given the entry point address */
100         env->pal_handler = NULL;
101         env->ipr[IPR_PAL_BASE] = palid;
102         env->pc = env->ipr[IPR_PAL_BASE];
103         cpu_loop_exit();
104     }
105 }
106
107 static void pal_console_call (CPUState *env, uint32_t palcode)
108 {
109     uint64_t palid;
110
111     if (palcode < 0x00000080) {
112         /* Privileged palcodes */
113         if (!(env->ps >> 3)) {
114             /* TODO: generate privilege exception */
115         }
116     }
117     switch (palcode) {
118     case 0x00000000:
119         /* HALT */
120         /* REQUIRED */
121         break;
122     case 0x00000001:
123         /* CFLUSH */
124         break;
125     case 0x00000002:
126         /* DRAINA */
127         /* REQUIRED */
128         /* Implemented as no-op */
129         break;
130     case 0x00000009:
131         /* CSERVE */
132         /* REQUIRED */
133         break;
134     case 0x0000000A:
135         /* SWPPAL */
136         /* REQUIRED */
137         palid = env->ir[16];
138         do_swappal(env, palid);
139         break;
140     case 0x00000080:
141         /* BPT */
142         /* REQUIRED */
143         break;
144     case 0x00000081:
145         /* BUGCHK */
146         /* REQUIRED */
147         break;
148     case 0x00000086:
149         /* IMB */
150         /* REQUIRED */
151         /* Implemented as no-op */
152         break;
153     case 0x0000009E:
154         /* RDUNIQUE */
155         /* REQUIRED */
156         break;
157     case 0x0000009F:
158         /* WRUNIQUE */
159         /* REQUIRED */
160         break;
161     case 0x000000AA:
162         /* GENTRAP */
163         /* REQUIRED */
164         break;
165     default:
166         break;
167     }
168 }
169
170 static void pal_openvms_call (CPUState *env, uint32_t palcode)
171 {
172     uint64_t palid, val, oldval;
173
174     if (palcode < 0x00000080) {
175         /* Privileged palcodes */
176         if (!(env->ps >> 3)) {
177             /* TODO: generate privilege exception */
178         }
179     }
180     switch (palcode) {
181     case 0x00000000:
182         /* HALT */
183         /* REQUIRED */
184         break;
185     case 0x00000001:
186         /* CFLUSH */
187         break;
188     case 0x00000002:
189         /* DRAINA */
190         /* REQUIRED */
191         /* Implemented as no-op */
192         break;
193     case 0x00000003:
194         /* LDQP */
195         break;
196     case 0x00000004:
197         /* STQP */
198         break;
199     case 0x00000005:
200         /* SWPCTX */
201         break;
202     case 0x00000006:
203         /* MFPR_ASN */
204         if (cpu_alpha_mfpr(env, IPR_ASN, &val) == 0)
205             env->ir[0] = val;
206         break;
207     case 0x00000007:
208         /* MTPR_ASTEN */
209         val = env->ir[16];
210         if (cpu_alpha_mtpr(env, IPR_ASTEN, val, &oldval) == 1)
211             env->ir[0] = val;
212         break;
213     case 0x00000008:
214         /* MTPR_ASTSR */
215         val = env->ir[16];
216         if (cpu_alpha_mtpr(env, IPR_ASTSR, val, &oldval) == 1)
217             env->ir[0] = val;
218         break;
219     case 0x00000009:
220         /* CSERVE */
221         /* REQUIRED */
222         break;
223     case 0x0000000A:
224         /* SWPPAL */
225         /* REQUIRED */
226         palid = env->ir[16];
227         do_swappal(env, palid);
228         break;
229     case 0x0000000B:
230         /* MFPR_FEN */
231         if (cpu_alpha_mfpr(env, IPR_FEN, &val) == 0)
232             env->ir[0] = val;
233         break;
234     case 0x0000000C:
235         /* MTPR_FEN */
236         val = env->ir[16];
237         if (cpu_alpha_mtpr(env, IPR_FEN, val, &oldval) == 1)
238             env->ir[0] = val;
239         break;
240     case 0x0000000D:
241         /* MTPR_IPIR */
242         val = env->ir[16];
243         if (cpu_alpha_mtpr(env, IPR_IPIR, val, &oldval) == 1)
244             env->ir[0] = val;
245         break;
246     case 0x0000000E:
247         /* MFPR_IPL */
248         if (cpu_alpha_mfpr(env, IPR_IPL, &val) == 0)
249             env->ir[0] = val;
250         break;
251     case 0x0000000F:
252         /* MTPR_IPL */
253         val = env->ir[16];
254         if (cpu_alpha_mtpr(env, IPR_IPL, val, &oldval) == 1)
255             env->ir[0] = val;
256         break;
257     case 0x00000010:
258         /* MFPR_MCES */
259         if (cpu_alpha_mfpr(env, IPR_MCES, &val) == 0)
260             env->ir[0] = val;
261         break;
262     case 0x00000011:
263         /* MTPR_MCES */
264         val = env->ir[16];
265         if (cpu_alpha_mtpr(env, IPR_MCES, val, &oldval) == 1)
266             env->ir[0] = val;
267         break;
268     case 0x00000012:
269         /* MFPR_PCBB */
270         if (cpu_alpha_mfpr(env, IPR_PCBB, &val) == 0)
271             env->ir[0] = val;
272         break;
273     case 0x00000013:
274         /* MFPR_PRBR */
275         if (cpu_alpha_mfpr(env, IPR_PRBR, &val) == 0)
276             env->ir[0] = val;
277         break;
278     case 0x00000014:
279         /* MTPR_PRBR */
280         val = env->ir[16];
281         if (cpu_alpha_mtpr(env, IPR_PRBR, val, &oldval) == 1)
282             env->ir[0] = val;
283         break;
284     case 0x00000015:
285         /* MFPR_PTBR */
286         if (cpu_alpha_mfpr(env, IPR_PTBR, &val) == 0)
287             env->ir[0] = val;
288         break;
289     case 0x00000016:
290         /* MFPR_SCBB */
291         if (cpu_alpha_mfpr(env, IPR_SCBB, &val) == 0)
292             env->ir[0] = val;
293         break;
294     case 0x00000017:
295         /* MTPR_SCBB */
296         val = env->ir[16];
297         if (cpu_alpha_mtpr(env, IPR_SCBB, val, &oldval) == 1)
298             env->ir[0] = val;
299         break;
300     case 0x00000018:
301         /* MTPR_SIRR */
302         val = env->ir[16];
303         if (cpu_alpha_mtpr(env, IPR_SIRR, val, &oldval) == 1)
304             env->ir[0] = val;
305         break;
306     case 0x00000019:
307         /* MFPR_SISR */
308         if (cpu_alpha_mfpr(env, IPR_SISR, &val) == 0)
309             env->ir[0] = val;
310         break;
311     case 0x0000001A:
312         /* MFPR_TBCHK */
313         if (cpu_alpha_mfpr(env, IPR_TBCHK, &val) == 0)
314             env->ir[0] = val;
315         break;
316     case 0x0000001B:
317         /* MTPR_TBIA */
318         val = env->ir[16];
319         if (cpu_alpha_mtpr(env, IPR_TBIA, val, &oldval) == 1)
320             env->ir[0] = val;
321         break;
322     case 0x0000001C:
323         /* MTPR_TBIAP */
324         val = env->ir[16];
325         if (cpu_alpha_mtpr(env, IPR_TBIAP, val, &oldval) == 1)
326             env->ir[0] = val;
327         break;
328     case 0x0000001D:
329         /* MTPR_TBIS */
330         val = env->ir[16];
331         if (cpu_alpha_mtpr(env, IPR_TBIS, val, &oldval) == 1)
332             env->ir[0] = val;
333         break;
334     case 0x0000001E:
335         /* MFPR_ESP */
336         if (cpu_alpha_mfpr(env, IPR_ESP, &val) == 0)
337             env->ir[0] = val;
338         break;
339     case 0x0000001F:
340         /* MTPR_ESP */
341         val = env->ir[16];
342         if (cpu_alpha_mtpr(env, IPR_ESP, val, &oldval) == 1)
343             env->ir[0] = val;
344         break;
345     case 0x00000020:
346         /* MFPR_SSP */
347         if (cpu_alpha_mfpr(env, IPR_SSP, &val) == 0)
348             env->ir[0] = val;
349         break;
350     case 0x00000021:
351         /* MTPR_SSP */
352         val = env->ir[16];
353         if (cpu_alpha_mtpr(env, IPR_SSP, val, &oldval) == 1)
354             env->ir[0] = val;
355         break;
356     case 0x00000022:
357         /* MFPR_USP */
358         if (cpu_alpha_mfpr(env, IPR_USP, &val) == 0)
359             env->ir[0] = val;
360         break;
361     case 0x00000023:
362         /* MTPR_USP */
363         val = env->ir[16];
364         if (cpu_alpha_mtpr(env, IPR_USP, val, &oldval) == 1)
365             env->ir[0] = val;
366         break;
367     case 0x00000024:
368         /* MTPR_TBISD */
369         val = env->ir[16];
370         if (cpu_alpha_mtpr(env, IPR_TBISD, val, &oldval) == 1)
371             env->ir[0] = val;
372         break;
373     case 0x00000025:
374         /* MTPR_TBISI */
375         val = env->ir[16];
376         if (cpu_alpha_mtpr(env, IPR_TBISI, val, &oldval) == 1)
377             env->ir[0] = val;
378         break;
379     case 0x00000026:
380         /* MFPR_ASTEN */
381         if (cpu_alpha_mfpr(env, IPR_ASTEN, &val) == 0)
382             env->ir[0] = val;
383         break;
384     case 0x00000027:
385         /* MFPR_ASTSR */
386         if (cpu_alpha_mfpr(env, IPR_ASTSR, &val) == 0)
387             env->ir[0] = val;
388         break;
389     case 0x00000029:
390         /* MFPR_VPTB */
391         if (cpu_alpha_mfpr(env, IPR_VPTB, &val) == 0)
392             env->ir[0] = val;
393         break;
394     case 0x0000002A:
395         /* MTPR_VPTB */
396         val = env->ir[16];
397         if (cpu_alpha_mtpr(env, IPR_VPTB, val, &oldval) == 1)
398             env->ir[0] = val;
399         break;
400     case 0x0000002B:
401         /* MTPR_PERFMON */
402         val = env->ir[16];
403         if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
404             env->ir[0] = val;
405         break;
406     case 0x0000002E:
407         /* MTPR_DATFX */
408         val = env->ir[16];
409         if (cpu_alpha_mtpr(env, IPR_DATFX, val, &oldval) == 1)
410             env->ir[0] = val;
411         break;
412     case 0x0000003E:
413         /* WTINT */
414         break;
415     case 0x0000003F:
416         /* MFPR_WHAMI */
417         if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
418             env->ir[0] = val;
419         break;
420     case 0x00000080:
421         /* BPT */
422         /* REQUIRED */
423         break;
424     case 0x00000081:
425         /* BUGCHK */
426         /* REQUIRED */
427         break;
428     case 0x00000082:
429         /* CHME */
430         break;
431     case 0x00000083:
432         /* CHMK */
433         break;
434     case 0x00000084:
435         /* CHMS */
436         break;
437     case 0x00000085:
438         /* CHMU */
439         break;
440     case 0x00000086:
441         /* IMB */
442         /* REQUIRED */
443         /* Implemented as no-op */
444         break;
445     case 0x00000087:
446         /* INSQHIL */
447         break;
448     case 0x00000088:
449         /* INSQTIL */
450         break;
451     case 0x00000089:
452         /* INSQHIQ */
453         break;
454     case 0x0000008A:
455         /* INSQTIQ */
456         break;
457     case 0x0000008B:
458         /* INSQUEL */
459         break;
460     case 0x0000008C:
461         /* INSQUEQ */
462         break;
463     case 0x0000008D:
464         /* INSQUEL/D */
465         break;
466     case 0x0000008E:
467         /* INSQUEQ/D */
468         break;
469     case 0x0000008F:
470         /* PROBER */
471         break;
472     case 0x00000090:
473         /* PROBEW */
474         break;
475     case 0x00000091:
476         /* RD_PS */
477         break;
478     case 0x00000092:
479         /* REI */
480         break;
481     case 0x00000093:
482         /* REMQHIL */
483         break;
484     case 0x00000094:
485         /* REMQTIL */
486         break;
487     case 0x00000095:
488         /* REMQHIQ */
489         break;
490     case 0x00000096:
491         /* REMQTIQ */
492         break;
493     case 0x00000097:
494         /* REMQUEL */
495         break;
496     case 0x00000098:
497         /* REMQUEQ */
498         break;
499     case 0x00000099:
500         /* REMQUEL/D */
501         break;
502     case 0x0000009A:
503         /* REMQUEQ/D */
504         break;
505     case 0x0000009B:
506         /* SWASTEN */
507         break;
508     case 0x0000009C:
509         /* WR_PS_SW */
510         break;
511     case 0x0000009D:
512         /* RSCC */
513         break;
514     case 0x0000009E:
515         /* READ_UNQ */
516         /* REQUIRED */
517         break;
518     case 0x0000009F:
519         /* WRITE_UNQ */
520         /* REQUIRED */
521         break;
522     case 0x000000A0:
523         /* AMOVRR */
524         break;
525     case 0x000000A1:
526         /* AMOVRM */
527         break;
528     case 0x000000A2:
529         /* INSQHILR */
530         break;
531     case 0x000000A3:
532         /* INSQTILR */
533         break;
534     case 0x000000A4:
535         /* INSQHIQR */
536         break;
537     case 0x000000A5:
538         /* INSQTIQR */
539         break;
540     case 0x000000A6:
541         /* REMQHILR */
542         break;
543     case 0x000000A7:
544         /* REMQTILR */
545         break;
546     case 0x000000A8:
547         /* REMQHIQR */
548         break;
549     case 0x000000A9:
550         /* REMQTIQR */
551         break;
552     case 0x000000AA:
553         /* GENTRAP */
554         /* REQUIRED */
555         break;
556     case 0x000000AE:
557         /* CLRFEN */
558         break;
559     default:
560         break;
561     }
562 }
563
564 static void pal_unix_call (CPUState *env, uint32_t palcode)
565 {
566     uint64_t palid, val, oldval;
567
568     if (palcode < 0x00000080) {
569         /* Privileged palcodes */
570         if (!(env->ps >> 3)) {
571             /* TODO: generate privilege exception */
572         }
573     }
574     switch (palcode) {
575     case 0x00000000:
576         /* HALT */
577         /* REQUIRED */
578         break;
579     case 0x00000001:
580         /* CFLUSH */
581         break;
582     case 0x00000002:
583         /* DRAINA */
584         /* REQUIRED */
585         /* Implemented as no-op */
586         break;
587     case 0x00000009:
588         /* CSERVE */
589         /* REQUIRED */
590         break;
591     case 0x0000000A:
592         /* SWPPAL */
593         /* REQUIRED */
594         palid = env->ir[16];
595         do_swappal(env, palid);
596         break;
597     case 0x0000000D:
598         /* WRIPIR */
599         val = env->ir[16];
600         if (cpu_alpha_mtpr(env, IPR_IPIR, val, &oldval) == 1)
601             env->ir[0] = val;
602         break;
603     case 0x00000010:
604         /* RDMCES */
605         if (cpu_alpha_mfpr(env, IPR_MCES, &val) == 0)
606             env->ir[0] = val;
607         break;
608     case 0x00000011:
609         /* WRMCES */
610         val = env->ir[16];
611         if (cpu_alpha_mtpr(env, IPR_MCES, val, &oldval) == 1)
612             env->ir[0] = val;
613         break;
614     case 0x0000002B:
615         /* WRFEN */
616         val = env->ir[16];
617         if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
618             env->ir[0] = val;
619         break;
620     case 0x0000002D:
621         /* WRVPTPTR */
622         break;
623     case 0x00000030:
624         /* SWPCTX */
625         break;
626     case 0x00000031:
627         /* WRVAL */
628         break;
629     case 0x00000032:
630         /* RDVAL */
631         break;
632     case 0x00000033:
633         /* TBI */
634         val = env->ir[16];
635         if (cpu_alpha_mtpr(env, IPR_TBIS, val, &oldval) == 1)
636             env->ir[0] = val;
637         break;
638     case 0x00000034:
639         /* WRENT */
640         break;
641     case 0x00000035:
642         /* SWPIPL */
643         break;
644     case 0x00000036:
645         /* RDPS */
646         break;
647     case 0x00000037:
648         /* WRKGP */
649         break;
650     case 0x00000038:
651         /* WRUSP */
652         val = env->ir[16];
653         if (cpu_alpha_mtpr(env, IPR_USP, val, &oldval) == 1)
654             env->ir[0] = val;
655         break;
656     case 0x00000039:
657         /* WRPERFMON */
658         val = env->ir[16];
659         if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
660             env->ir[0] = val;
661         break;
662     case 0x0000003A:
663         /* RDUSP */
664         if (cpu_alpha_mfpr(env, IPR_USP, &val) == 0)
665             env->ir[0] = val;
666         break;
667     case 0x0000003C:
668         /* WHAMI */
669         if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
670             env->ir[0] = val;
671         break;
672     case 0x0000003D:
673         /* RETSYS */
674         break;
675     case 0x0000003E:
676         /* WTINT */
677         break;
678     case 0x0000003F:
679         /* RTI */
680         if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
681             env->ir[0] = val;
682         break;
683     case 0x00000080:
684         /* BPT */
685         /* REQUIRED */
686         break;
687     case 0x00000081:
688         /* BUGCHK */
689         /* REQUIRED */
690         break;
691     case 0x00000083:
692         /* CALLSYS */
693         break;
694     case 0x00000086:
695         /* IMB */
696         /* REQUIRED */
697         /* Implemented as no-op */
698         break;
699     case 0x00000092:
700         /* URTI */
701         break;
702     case 0x0000009E:
703         /* RDUNIQUE */
704         /* REQUIRED */
705         break;
706     case 0x0000009F:
707         /* WRUNIQUE */
708         /* REQUIRED */
709         break;
710     case 0x000000AA:
711         /* GENTRAP */
712         /* REQUIRED */
713         break;
714     case 0x000000AE:
715         /* CLRFEN */
716         break;
717     default:
718         break;
719     }
720 }
721
722 void call_pal (CPUState *env)
723 {
724     pal_handler_t *pal_handler = env->pal_handler;
725
726     switch (env->exception_index) {
727     case EXCP_RESET:
728         (*pal_handler->reset)(env);
729         break;
730     case EXCP_MCHK:
731         (*pal_handler->machine_check)(env);
732         break;
733     case EXCP_ARITH:
734         (*pal_handler->arithmetic)(env);
735         break;
736     case EXCP_INTERRUPT:
737         (*pal_handler->interrupt)(env);
738         break;
739     case EXCP_DFAULT:
740         (*pal_handler->dfault)(env);
741         break;
742     case EXCP_DTB_MISS_PAL:
743         (*pal_handler->dtb_miss_pal)(env);
744         break;
745     case EXCP_DTB_MISS_NATIVE:
746         (*pal_handler->dtb_miss_native)(env);
747         break;
748     case EXCP_UNALIGN:
749         (*pal_handler->unalign)(env);
750         break;
751     case EXCP_ITB_MISS:
752         (*pal_handler->itb_miss)(env);
753         break;
754     case EXCP_ITB_ACV:
755         (*pal_handler->itb_acv)(env);
756         break;
757     case EXCP_OPCDEC:
758         (*pal_handler->opcdec)(env);
759         break;
760     case EXCP_FEN:
761         (*pal_handler->fen)(env);
762         break;
763     default:
764         if (env->exception_index >= EXCP_CALL_PAL &&
765             env->exception_index < EXCP_CALL_PALP) {
766             /* Unprivileged PAL call */
767             (*pal_handler->call_pal)
768                 (env, (env->exception_index - EXCP_CALL_PAL) >> 6);
769         } else if (env->exception_index >= EXCP_CALL_PALP &&
770                    env->exception_index < EXCP_CALL_PALE) {
771             /* Privileged PAL call */
772             (*pal_handler->call_pal)
773                 (env, ((env->exception_index - EXCP_CALL_PALP) >> 6) + 0x80);
774         } else {
775             /* Should never happen */
776         }
777         break;
778     }
779     env->ipr[IPR_EXC_ADDR] &= ~1;
780 }
781
782 void pal_init (CPUState *env)
783 {
784     do_swappal(env, 0);
785 }
786
787 #if 0
788 static uint64_t get_ptebase (CPUState *env, uint64_t vaddr)
789 {
790     uint64_t virbnd, ptbr;
791
792     if ((env->features & FEATURE_VIRBND)) {
793         cpu_alpha_mfpr(env, IPR_VIRBND, &virbnd);
794         if (vaddr >= virbnd)
795             cpu_alpha_mfpr(env, IPR_SYSPTBR, &ptbr);
796         else
797             cpu_alpha_mfpr(env, IPR_PTBR, &ptbr);
798     } else {
799         cpu_alpha_mfpr(env, IPR_PTBR, &ptbr);
800     }
801
802     return ptbr;
803 }
804
805 static int get_page_bits (CPUState *env)
806 {
807     /* XXX */
808     return 13;
809 }
810
811 static int get_pte (uint64_t *pfnp, int *zbitsp, int *protp,
812                     uint64_t ptebase, int page_bits, uint64_t level,
813                     int mmu_idx, int rw)
814 {
815     uint64_t pteaddr, pte, pfn;
816     uint8_t gh;
817     int ure, uwe, kre, kwe, foE, foR, foW, v, ret, ar, is_user;
818
819     /* XXX: TOFIX */
820     is_user = mmu_idx == MMU_USER_IDX;
821     pteaddr = (ptebase << page_bits) + (8 * level);
822     pte = ldq_raw(pteaddr);
823     /* Decode all interresting PTE fields */
824     pfn = pte >> 32;
825     uwe = (pte >> 13) & 1;
826     kwe = (pte >> 12) & 1;
827     ure = (pte >> 9) & 1;
828     kre = (pte >> 8) & 1;
829     gh = (pte >> 5) & 3;
830     foE = (pte >> 3) & 1;
831     foW = (pte >> 2) & 1;
832     foR = (pte >> 1) & 1;
833     v = pte & 1;
834     ret = 0;
835     if (!v)
836         ret = 0x1;
837     /* Check access rights */
838     ar = 0;
839     if (is_user) {
840         if (ure)
841             ar |= PAGE_READ;
842         if (uwe)
843             ar |= PAGE_WRITE;
844         if (rw == 1 && !uwe)
845             ret |= 0x2;
846         if (rw != 1 && !ure)
847             ret |= 0x2;
848     } else {
849         if (kre)
850             ar |= PAGE_READ;
851         if (kwe)
852             ar |= PAGE_WRITE;
853         if (rw == 1 && !kwe)
854             ret |= 0x2;
855         if (rw != 1 && !kre)
856             ret |= 0x2;
857     }
858     if (rw == 0 && foR)
859         ret |= 0x4;
860     if (rw == 2 && foE)
861         ret |= 0x8;
862     if (rw == 1 && foW)
863         ret |= 0xC;
864     *pfnp = pfn;
865     if (zbitsp != NULL)
866         *zbitsp = page_bits + (3 * gh);
867     if (protp != NULL)
868         *protp = ar;
869
870     return ret;
871 }
872
873 static int paddr_from_pte (uint64_t *paddr, int *zbitsp, int *prot,
874                            uint64_t ptebase, int page_bits,
875                            uint64_t vaddr, int mmu_idx, int rw)
876 {
877     uint64_t pfn, page_mask, lvl_mask, level1, level2, level3;
878     int lvl_bits, ret;
879
880     page_mask = (1ULL << page_bits) - 1ULL;
881     lvl_bits = page_bits - 3;
882     lvl_mask = (1ULL << lvl_bits) - 1ULL;
883     level3 = (vaddr >> page_bits) & lvl_mask;
884     level2 = (vaddr >> (page_bits + lvl_bits)) & lvl_mask;
885     level1 = (vaddr >> (page_bits + (2 * lvl_bits))) & lvl_mask;
886     /* Level 1 PTE */
887     ret = get_pte(&pfn, NULL, NULL, ptebase, page_bits, level1, 0, 0);
888     switch (ret) {
889     case 3:
890         /* Access violation */
891         return 2;
892     case 2:
893         /* translation not valid */
894         return 1;
895     default:
896         /* OK */
897         break;
898     }
899     /* Level 2 PTE */
900     ret = get_pte(&pfn, NULL, NULL, pfn, page_bits, level2, 0, 0);
901     switch (ret) {
902     case 3:
903         /* Access violation */
904         return 2;
905     case 2:
906         /* translation not valid */
907         return 1;
908     default:
909         /* OK */
910         break;
911     }
912     /* Level 3 PTE */
913     ret = get_pte(&pfn, zbitsp, prot, pfn, page_bits, level3, mmu_idx, rw);
914     if (ret & 0x1) {
915         /* Translation not valid */
916         ret = 1;
917     } else if (ret & 2) {
918         /* Access violation */
919         ret = 2;
920     } else {
921         switch (ret & 0xC) {
922         case 0:
923             /* OK */
924             ret = 0;
925             break;
926         case 0x4:
927             /* Fault on read */
928             ret = 3;
929             break;
930         case 0x8:
931             /* Fault on execute */
932             ret = 4;
933             break;
934         case 0xC:
935             /* Fault on write */
936             ret = 5;
937             break;
938         }
939     }
940     *paddr = (pfn << page_bits) | (vaddr & page_mask);
941
942     return 0;
943 }
944
945 static int virtual_to_physical (CPUState *env, uint64_t *physp,
946                                 int *zbitsp, int *protp,
947                                 uint64_t virtual, int mmu_idx, int rw)
948 {
949     uint64_t sva, ptebase;
950     int seg, page_bits, ret;
951
952     sva = ((int64_t)(virtual << (64 - VA_BITS))) >> (64 - VA_BITS);
953     if (sva != virtual)
954         seg = -1;
955     else
956         seg = sva >> (VA_BITS - 2);
957     virtual &= ~(0xFFFFFC0000000000ULL << (VA_BITS - 43));
958     ptebase = get_ptebase(env, virtual);
959     page_bits = get_page_bits(env);
960     ret = 0;
961     switch (seg) {
962     case 0:
963         /* seg1: 3 levels of PTE */
964         ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
965                              virtual, mmu_idx, rw);
966         break;
967     case 1:
968         /* seg1: 2 levels of PTE */
969         ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
970                              virtual, mmu_idx, rw);
971         break;
972     case 2:
973         /* kernel segment */
974         if (mmu_idx != 0) {
975             ret = 2;
976         } else {
977             *physp = virtual;
978         }
979         break;
980     case 3:
981         /* seg1: TB mapped */
982         ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
983                              virtual, mmu_idx, rw);
984         break;
985     default:
986         ret = 1;
987         break;
988     }
989
990     return ret;
991 }
992
993 /* XXX: code provision */
994 int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
995                               int mmu_idx, int is_softmmu)
996 {
997     uint64_t physical, page_size, end;
998     int prot, zbits, ret;
999
1000 #if defined(CONFIG_USER_ONLY)
1001         ret = 2;
1002 #else
1003         ret = virtual_to_physical(env, &physical, &zbits, &prot,
1004                                   address, mmu_idx, rw);
1005 #endif
1006     switch (ret) {
1007     case 0:
1008         /* No fault */
1009         page_size = 1ULL << zbits;
1010         address &= ~(page_size - 1);
1011         for (end = physical + page_size; physical < end; physical += 0x1000) {
1012             ret = tlb_set_page(env, address, physical, prot,
1013                                mmu_idx, is_softmmu);
1014             address += 0x1000;
1015         }
1016         break;
1017 #if 0
1018     case 1:
1019         env->exception_index = EXCP_DFAULT;
1020         env->ipr[IPR_EXC_ADDR] = address;
1021         ret = 1;
1022         break;
1023     case 2:
1024         env->exception_index = EXCP_ACCESS_VIOLATION;
1025         env->ipr[IPR_EXC_ADDR] = address;
1026         ret = 1;
1027         break;
1028     case 3:
1029         env->exception_index = EXCP_FAULT_ON_READ;
1030         env->ipr[IPR_EXC_ADDR] = address;
1031         ret = 1;
1032         break;
1033     case 4:
1034         env->exception_index = EXCP_FAULT_ON_EXECUTE;
1035         env->ipr[IPR_EXC_ADDR] = address;
1036         ret = 1;
1037     case 5:
1038         env->exception_index = EXCP_FAULT_ON_WRITE;
1039         env->ipr[IPR_EXC_ADDR] = address;
1040         ret = 1;
1041 #endif
1042     default:
1043         /* Should never happen */
1044         env->exception_index = EXCP_MCHK;
1045         env->ipr[IPR_EXC_ADDR] = address;
1046         ret = 1;
1047         break;
1048     }
1049
1050     return ret;
1051 }
1052 #endif
1053
1054 #else /* !defined (CONFIG_USER_ONLY) */
1055 void pal_init (CPUState *env)
1056 {
1057 }
1058
1059 void call_pal (CPUState *env, int palcode)
1060 {
1061     target_long ret;
1062
1063     qemu_log("%s: palcode %02x\n", __func__, palcode);
1064     switch (palcode) {
1065     case 0x83:
1066         /* CALLSYS */
1067         qemu_log("CALLSYS n " TARGET_FMT_ld "\n", env->ir[0]);
1068         ret = do_syscall(env, env->ir[IR_V0], env->ir[IR_A0], env->ir[IR_A1],
1069                          env->ir[IR_A2], env->ir[IR_A3], env->ir[IR_A4],
1070                          env->ir[IR_A5]);
1071         if (ret >= 0) {
1072             env->ir[IR_A3] = 0;
1073             env->ir[IR_V0] = ret;
1074         } else {
1075             env->ir[IR_A3] = 1;
1076             env->ir[IR_V0] = -ret;
1077         }
1078         break;
1079     case 0x9E:
1080         /* RDUNIQUE */
1081         env->ir[IR_V0] = env->unique;
1082         qemu_log("RDUNIQUE: " TARGET_FMT_lx "\n", env->unique);
1083         break;
1084     case 0x9F:
1085         /* WRUNIQUE */
1086         env->unique = env->ir[IR_A0];
1087         qemu_log("WRUNIQUE: " TARGET_FMT_lx "\n", env->unique);
1088         break;
1089     default:
1090         qemu_log("%s: unhandled palcode %02x\n",
1091                     __func__, palcode);
1092         exit(1);
1093     }
1094 }
1095 #endif