Fix typo in comment, by Andreas Faerber.
[qemu/dscho.git] / hw / alpha_palcode.c
blob0fe9d969fbe0a6cd783af13e8c90b202f07a8e21
1 /*
2 * Alpha emulation - PALcode emulation for qemu.
3 *
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, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <stdint.h>
22 #include <stdlib.h>
23 #include <stdio.h>
25 #include "qemu.h"
26 #include "cpu.h"
27 #include "exec-all.h"
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);
39 pal_handler_t pal_handlers[] = {
40 /* Console handler */
42 .reset = &pal_reset,
43 .call_pal = &pal_console_call,
45 /* OpenVMS handler */
47 .reset = &pal_reset,
48 .call_pal = &pal_openvms_call,
50 /* UNIX / Linux handler */
52 .reset = &pal_reset,
53 .call_pal = &pal_unix_call,
57 #if 0
58 /* One must explicitely check that the TB is valid and the FOE bit is reset */
59 static void update_itb ()
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);
68 static void update_dtb ();
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);
76 #endif
78 static void pal_reset (CPUState *env)
82 static void do_swappal (CPUState *env, uint64_t palid)
84 pal_handler_t *pal_handler;
85 int status;
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();
108 static void pal_console_call (CPUState *env, uint32_t palcode)
110 uint64_t palid;
112 if (palcode < 0x00000080) {
113 /* Privileged palcodes */
114 if (!(env->ps >> 3)) {
115 /* TODO: generate privilege exception */
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;
171 static void pal_openvms_call (CPUState *env, uint32_t palcode)
173 uint64_t palid, val, oldval;
175 if (palcode < 0x00000080) {
176 /* Privileged palcodes */
177 if (!(env->ps >> 3)) {
178 /* TODO: generate privilege exception */
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;
565 static void pal_unix_call (CPUState *env, uint32_t palcode)
567 uint64_t palid, val, oldval;
569 if (palcode < 0x00000080) {
570 /* Privileged palcodes */
571 if (!(env->ps >> 3)) {
572 /* TODO: generate privilege exception */
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;
723 void call_pal (CPUState *env)
725 pal_handler_t *pal_handler = env->pal_handler;
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 */
778 break;
780 env->ipr[IPR_EXC_ADDR] &= ~1;
783 void pal_init (CPUState *env)
785 do_swappal(env, 0);
788 #if 0
789 static uint64_t get_ptebase (CPUState *env, uint64_t vaddr)
791 uint64_t virbnd, ptbr;
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);
803 return ptbr;
806 static int get_page_bits (CPUState *env)
808 /* XXX */
809 return 13;
812 static int get_pte (uint64_t *pfnp, int *zbitsp, int *protp,
813 uint64_t ptebase, int page_bits, uint64_t level,
814 int is_user, int rw)
816 uint64_t pteaddr, pte, pfn;
817 uint8_t gh;
818 int ure, uwe, kre, kwe, foE, foR, foW, v, ret, ar;
820 pteaddr = (ptebase << page_bits) + (8 * level);
821 pte = ldq_raw(pteaddr);
822 /* Decode all interresting PTE fields */
823 pfn = pte >> 32;
824 uwe = (pte >> 13) & 1;
825 kwe = (pte >> 12) & 1;
826 ure = (pte >> 9) & 1;
827 kre = (pte >> 8) & 1;
828 gh = (pte >> 5) & 3;
829 foE = (pte >> 3) & 1;
830 foW = (pte >> 2) & 1;
831 foR = (pte >> 1) & 1;
832 v = pte & 1;
833 ret = 0;
834 if (!v)
835 ret = 0x1;
836 /* Check access rights */
837 ar = 0;
838 if (is_user) {
839 if (ure)
840 ar |= PAGE_READ;
841 if (uwe)
842 ar |= PAGE_WRITE;
843 if (rw == 1 && !uwe)
844 ret |= 0x2;
845 if (rw != 1 && !ure)
846 ret |= 0x2;
847 } else {
848 if (kre)
849 ar |= PAGE_READ;
850 if (kwe)
851 ar |= PAGE_WRITE;
852 if (rw == 1 && !kwe)
853 ret |= 0x2;
854 if (rw != 1 && !kre)
855 ret |= 0x2;
857 if (rw == 0 && foR)
858 ret |= 0x4;
859 if (rw == 2 && foE)
860 ret |= 0x8;
861 if (rw == 1 && foW)
862 ret |= 0xC;
863 *pfnp = pfn;
864 if (zbitsp != NULL)
865 *zbitsp = page_bits + (3 * gh);
866 if (protp != NULL)
867 *protp = ar;
869 return ret;
872 static int paddr_from_pte (uint64_t *paddr, int *zbitsp, int *prot,
873 uint64_t ptebase, int page_bits,
874 uint64_t vaddr, int is_user, int rw)
876 uint64_t pfn, page_mask, lvl_mask, level1, level2, level3;
877 int lvl_bits, ret;
879 page_mask = (1ULL << page_bits) - 1ULL;
880 lvl_bits = page_bits - 3;
881 lvl_mask = (1ULL << lvl_bits) - 1ULL;
882 level3 = (vaddr >> page_bits) & lvl_mask;
883 level2 = (vaddr >> (page_bits + lvl_bits)) & lvl_mask;
884 level1 = (vaddr >> (page_bits + (2 * lvl_bits))) & lvl_mask;
885 /* Level 1 PTE */
886 ret = get_pte(&pfn, NULL, NULL, ptebase, page_bits, level1, 0, 0);
887 switch (ret) {
888 case 3:
889 /* Access violation */
890 return 2;
891 case 2:
892 /* translation not valid */
893 return 1;
894 default:
895 /* OK */
896 break;
898 /* Level 2 PTE */
899 ret = get_pte(&pfn, NULL, NULL, pfn, page_bits, level2, 0, 0);
900 switch (ret) {
901 case 3:
902 /* Access violation */
903 return 2;
904 case 2:
905 /* translation not valid */
906 return 1;
907 default:
908 /* OK */
909 break;
911 /* Level 3 PTE */
912 ret = get_pte(&pfn, zbitsp, prot, pfn, page_bits, level3, is_user, rw);
913 if (ret & 0x1) {
914 /* Translation not valid */
915 ret = 1;
916 } else if (ret & 2) {
917 /* Access violation */
918 ret = 2;
919 } else {
920 switch (ret & 0xC) {
921 case 0:
922 /* OK */
923 ret = 0;
924 break;
925 case 0x4:
926 /* Fault on read */
927 ret = 3;
928 break;
929 case 0x8:
930 /* Fault on execute */
931 ret = 4;
932 break;
933 case 0xC:
934 /* Fault on write */
935 ret = 5;
936 break;
939 *paddr = (pfn << page_bits) | (vaddr & page_mask);
941 return 0;
944 static int virtual_to_physical (CPUState *env, uint64_t *physp,
945 int *zbitsp, int *protp,
946 uint64_t virtual, int is_user, int rw)
948 uint64_t sva, ptebase;
949 int seg, page_bits, ret;
951 sva = ((int64_t)(virtual << (64 - VA_BITS))) >> (64 - VA_BITS);
952 if (sva != virtual)
953 seg = -1;
954 else
955 seg = sva >> (VA_BITS - 2);
956 virtual &= ~(0xFFFFFC0000000000ULL << (VA_BITS - 43));
957 ptebase = get_ptebase(env, virtual);
958 page_bits = get_page_bits(env);
959 ret = 0;
960 switch (seg) {
961 case 0:
962 /* seg1: 3 levels of PTE */
963 ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
964 virtual, is_user, rw);
965 break;
966 case 1:
967 /* seg1: 2 levels of PTE */
968 ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
969 virtual, is_user, rw);
970 break;
971 case 2:
972 /* kernel segment */
973 if (is_user) {
974 ret = 2;
975 } else {
976 *physp = virtual;
978 break;
979 case 3:
980 /* seg1: TB mapped */
981 ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
982 virtual, is_user, rw);
983 break;
984 default:
985 ret = 1;
986 break;
989 return ret;
992 /* XXX: code provision */
993 int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
994 int is_user, int is_softmmu)
996 uint64_t physical, page_size, end;
997 int prot, zbits, ret;
999 if (env->user_mode_only) {
1000 ret = 2;
1001 } else {
1002 ret = virtual_to_physical(env, &physical, &zbits, &prot,
1003 address, is_user, rw);
1005 switch (ret) {
1006 case 0:
1007 /* No fault */
1008 page_size = 1ULL << zbits;
1009 address &= ~(page_size - 1);
1010 for (end = physical + page_size; physical < end; physical += 0x1000) {
1011 ret = tlb_set_page(env, address, physical, prot,
1012 is_user, is_softmmu);
1013 address += 0x1000;
1015 break;
1016 #if 0
1017 case 1:
1018 env->exception_index = EXCP_DFAULT;
1019 env->ipr[IPR_EXC_ADDR] = address;
1020 ret = 1;
1021 break;
1022 case 2:
1023 env->exception_index = EXCP_ACCESS_VIOLATION;
1024 env->ipr[IPR_EXC_ADDR] = address;
1025 ret = 1;
1026 break;
1027 case 3:
1028 env->exception_index = EXCP_FAULT_ON_READ;
1029 env->ipr[IPR_EXC_ADDR] = address;
1030 ret = 1;
1031 break;
1032 case 4:
1033 env->exception_index = EXCP_FAULT_ON_EXECUTE;
1034 env->ipr[IPR_EXC_ADDR] = address;
1035 ret = 1;
1036 case 5:
1037 env->exception_index = EXCP_FAULT_ON_WRITE;
1038 env->ipr[IPR_EXC_ADDR] = address;
1039 ret = 1;
1040 #endif
1041 default:
1042 /* Should never happen */
1043 env->exception_index = EXCP_MCHK;
1044 env->ipr[IPR_EXC_ADDR] = address;
1045 ret = 1;
1046 break;
1049 return ret;
1051 #endif
1053 #else /* !defined (CONFIG_USER_ONLY) */
1054 void pal_init (CPUState *env)
1058 void call_pal (CPUState *env, int palcode)
1060 target_ulong ret;
1062 printf("%s: palcode %02x\n", __func__, palcode);
1063 if (logfile != NULL)
1064 fprintf(logfile, "%s: palcode %02x\n", __func__, palcode);
1065 switch (palcode) {
1066 case 0x83:
1067 /* CALLSYS */
1068 printf("CALLSYS n " TARGET_FMT_ld "\n", env->ir[0]);
1069 if (logfile != NULL)
1070 fprintf(logfile, "CALLSYS n " TARGET_FMT_ld "\n", env->ir[0]);
1071 ret = do_syscall(env, env->ir[IR_V0], env->ir[IR_A0], env->ir[IR_A1],
1072 env->ir[IR_A2], env->ir[IR_A3], env->ir[IR_A4],
1073 env->ir[IR_A5]);
1074 env->ir[IR_A3] = ret;
1075 if (ret > (target_ulong)(-515)) {
1076 env->ir[IR_V0] = 1;
1077 } else {
1078 env->ir[IR_V0] = 0;
1080 break;
1081 case 0x9E:
1082 /* RDUNIQUE */
1083 env->ir[IR_V0] = env->unique;
1084 printf("RDUNIQUE: " TARGET_FMT_lx "\n", env->unique);
1085 break;
1086 case 0x9F:
1087 /* WRUNIQUE */
1088 env->unique = env->ir[IR_A0];
1089 printf("WRUNIQUE: " TARGET_FMT_lx "\n", env->unique);
1090 break;
1091 default:
1092 printf("%s: unhandled palcode %02x\n", __func__, palcode);
1093 if (logfile != NULL)
1094 fprintf(logfile, "%s: unhandled palcode %02x\n",
1095 __func__, palcode);
1096 exit(1);
1099 #endif