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