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