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