|
|
1.1 root 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 explicitely check that the TB is valid and the FOE bit is reset */
59: static void update_itb ()
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 ();
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 (env->user_mode_only) {
1002: ret = 2;
1003: } else {
1004: ret = virtual_to_physical(env, &physical, &zbits, &prot,
1005: address, mmu_idx, rw);
1006: }
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_ulong ret;
1063:
1064: printf("%s: palcode %02x\n", __func__, palcode);
1065: if (logfile != NULL)
1066: fprintf(logfile, "%s: palcode %02x\n", __func__, palcode);
1067: switch (palcode) {
1068: case 0x83:
1069: /* CALLSYS */
1070: printf("CALLSYS n " TARGET_FMT_ld "\n", env->ir[0]);
1071: if (logfile != NULL)
1072: fprintf(logfile, "CALLSYS n " TARGET_FMT_ld "\n", env->ir[0]);
1073: ret = do_syscall(env, env->ir[IR_V0], env->ir[IR_A0], env->ir[IR_A1],
1074: env->ir[IR_A2], env->ir[IR_A3], env->ir[IR_A4],
1075: env->ir[IR_A5]);
1076: env->ir[IR_A3] = ret;
1077: if (ret > (target_ulong)(-515)) {
1078: env->ir[IR_V0] = 1;
1079: } else {
1080: env->ir[IR_V0] = 0;
1081: }
1082: break;
1083: case 0x9E:
1084: /* RDUNIQUE */
1085: env->ir[IR_V0] = env->unique;
1086: printf("RDUNIQUE: " TARGET_FMT_lx "\n", env->unique);
1087: break;
1088: case 0x9F:
1089: /* WRUNIQUE */
1090: env->unique = env->ir[IR_A0];
1091: printf("WRUNIQUE: " TARGET_FMT_lx "\n", env->unique);
1092: break;
1093: default:
1094: printf("%s: unhandled palcode %02x\n", __func__, palcode);
1095: if (logfile != NULL)
1096: fprintf(logfile, "%s: unhandled palcode %02x\n",
1097: __func__, palcode);
1098: exit(1);
1099: }
1100: }
1101: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.