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