linux-user: fix ARM core dumps on opposite-endian hosts
[qemu.git] / hw / alpha_palcode.c
blob843bd1491eac94e0bf48873db2f28f3a880bcaef
1 /*
2 * Alpha emulation - PALcode emulation for qemu.
4 * Copyright (c) 2007 Jocelyn Mayer
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.
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.
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/>.
20 #include <stdint.h>
21 #include <stdlib.h>
22 #include <stdio.h>
24 #include "qemu.h"
25 #include "cpu.h"
26 #include "exec-all.h"
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);
38 pal_handler_t pal_handlers[] = {
39 /* Console handler */
41 .reset = &pal_reset,
42 .call_pal = &pal_console_call,
44 /* OpenVMS handler */
46 .reset = &pal_reset,
47 .call_pal = &pal_openvms_call,
49 /* UNIX / Linux handler */
51 .reset = &pal_reset,
52 .call_pal = &pal_unix_call,
56 #if 0
57 /* One must explicitly check that the TB is valid and the FOE bit is reset */
58 static void update_itb (void)
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);
67 static void update_dtb (void);
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);
75 #endif
77 static void pal_reset (CPUState *env)
81 static void do_swappal (CPUState *env, uint64_t palid)
83 pal_handler_t *pal_handler;
84 int status;
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();
107 static void pal_console_call (CPUState *env, uint32_t palcode)
109 uint64_t palid;
111 if (palcode < 0x00000080) {
112 /* Privileged palcodes */
113 if (!(env->ps >> 3)) {
114 /* TODO: generate privilege exception */
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;
170 static void pal_openvms_call (CPUState *env, uint32_t palcode)
172 uint64_t palid, val, oldval;
174 if (palcode < 0x00000080) {
175 /* Privileged palcodes */
176 if (!(env->ps >> 3)) {
177 /* TODO: generate privilege exception */
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;
564 static void pal_unix_call (CPUState *env, uint32_t palcode)
566 uint64_t palid, val, oldval;
568 if (palcode < 0x00000080) {
569 /* Privileged palcodes */
570 if (!(env->ps >> 3)) {
571 /* TODO: generate privilege exception */
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;
722 void call_pal (CPUState *env)
724 pal_handler_t *pal_handler = env->pal_handler;
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 */
777 break;
779 env->ipr[IPR_EXC_ADDR] &= ~1;
782 void pal_init (CPUState *env)
784 do_swappal(env, 0);
787 #if 0
788 static uint64_t get_ptebase (CPUState *env, uint64_t vaddr)
790 uint64_t virbnd, ptbr;
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);
802 return ptbr;
805 static int get_page_bits (CPUState *env)
807 /* XXX */
808 return 13;
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)
815 uint64_t pteaddr, pte, pfn;
816 uint8_t gh;
817 int ure, uwe, kre, kwe, foE, foR, foW, v, ret, ar, is_user;
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;
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;
870 return ret;
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)
877 uint64_t pfn, page_mask, lvl_mask, level1, level2, level3;
878 int lvl_bits, ret;
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;
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;
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;
940 *paddr = (pfn << page_bits) | (vaddr & page_mask);
942 return 0;
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)
949 uint64_t sva, ptebase;
950 int seg, page_bits, ret;
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;
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;
990 return ret;
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)
997 uint64_t physical, page_size, end;
998 int prot, zbits, ret;
1000 #if defined(CONFIG_USER_ONLY)
1001 ret = 2;
1002 #else
1003 ret = virtual_to_physical(env, &physical, &zbits, &prot,
1004 address, mmu_idx, rw);
1005 #endif
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;
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;
1050 return ret;
1052 #endif
1054 #else /* !defined (CONFIG_USER_ONLY) */
1055 void pal_init (CPUState *env)
1059 void call_pal (CPUState *env, int palcode)
1061 target_long ret;
1063 switch (palcode) {
1064 case 0x80:
1065 /* BPT */
1066 qemu_log("BPT\n");
1067 /* FIXME: Sends SIGTRAP, si_code=TRAP_BRKPT. */
1068 exit(1);
1069 case 0x81:
1070 /* BUGCHK */
1071 qemu_log("BUGCHK\n");
1072 /* FIXME: Sends SIGTRAP, si_code=SI_FAULT. */
1073 exit(1);
1074 case 0x83:
1075 /* CALLSYS */
1076 qemu_log("CALLSYS n " TARGET_FMT_ld "\n", env->ir[0]);
1077 ret = do_syscall(env, env->ir[IR_V0], env->ir[IR_A0], env->ir[IR_A1],
1078 env->ir[IR_A2], env->ir[IR_A3], env->ir[IR_A4],
1079 env->ir[IR_A5]);
1080 if (ret >= 0) {
1081 env->ir[IR_A3] = 0;
1082 env->ir[IR_V0] = ret;
1083 } else {
1084 env->ir[IR_A3] = 1;
1085 env->ir[IR_V0] = -ret;
1087 break;
1088 case 0x86:
1089 /* IMB */
1090 qemu_log("IMB\n");
1091 /* ??? We can probably elide the code using page_unprotect that is
1092 checking for self-modifying code. Instead we could simply call
1093 tb_flush here. Until we work out the changes required to turn
1094 off the extra write protection, this can be a no-op. */
1095 break;
1096 case 0x9E:
1097 /* RDUNIQUE */
1098 qemu_log("RDUNIQUE: " TARGET_FMT_lx "\n", env->unique);
1099 /* Handled in the translator for usermode. */
1100 abort();
1101 case 0x9F:
1102 /* WRUNIQUE */
1103 qemu_log("WRUNIQUE: " TARGET_FMT_lx "\n", env->ir[IR_A0]);
1104 /* Handled in the translator for usermode. */
1105 abort();
1106 case 0xAA:
1107 /* GENTRAP */
1108 qemu_log("GENTRAP: " TARGET_FMT_lx "\n", env->ir[IR_A0]);
1109 /* FIXME: This is supposed to send a signal:
1110 SIGFPE:
1111 GEN_INTOVF, GEN_INTDIV, GEN_FLTOVF, GEN_FLTDIV,
1112 GEN_FLTUND, GEN_FLTINV, GEN_FLTINE, GEN_ROPRAND
1113 SIGTRAP:
1114 others
1115 with various settings of si_code. */
1116 exit(1);
1117 default:
1118 qemu_log("%s: unhandled palcode %02x\n", __func__, palcode);
1119 exit(1);
1122 #endif