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