Merge branch 'master' of ssh://repo.or.cz/srv/git/qemu
[qemu/hppa.git] / hw / alpha_palcode.c
blobbfffb5d29cdab0a48c1795e147c8f039e5f34420
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, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 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 explicitly check that the TB is valid and the FOE bit is reset */
59 static void update_itb (void)
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 (void);
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 mmu_idx, int rw)
816 uint64_t pteaddr, pte, pfn;
817 uint8_t gh;
818 int ure, uwe, kre, kwe, foE, foR, foW, v, ret, ar, is_user;
820 /* XXX: TOFIX */
821 is_user = mmu_idx == MMU_USER_IDX;
822 pteaddr = (ptebase << page_bits) + (8 * level);
823 pte = ldq_raw(pteaddr);
824 /* Decode all interresting PTE fields */
825 pfn = pte >> 32;
826 uwe = (pte >> 13) & 1;
827 kwe = (pte >> 12) & 1;
828 ure = (pte >> 9) & 1;
829 kre = (pte >> 8) & 1;
830 gh = (pte >> 5) & 3;
831 foE = (pte >> 3) & 1;
832 foW = (pte >> 2) & 1;
833 foR = (pte >> 1) & 1;
834 v = pte & 1;
835 ret = 0;
836 if (!v)
837 ret = 0x1;
838 /* Check access rights */
839 ar = 0;
840 if (is_user) {
841 if (ure)
842 ar |= PAGE_READ;
843 if (uwe)
844 ar |= PAGE_WRITE;
845 if (rw == 1 && !uwe)
846 ret |= 0x2;
847 if (rw != 1 && !ure)
848 ret |= 0x2;
849 } else {
850 if (kre)
851 ar |= PAGE_READ;
852 if (kwe)
853 ar |= PAGE_WRITE;
854 if (rw == 1 && !kwe)
855 ret |= 0x2;
856 if (rw != 1 && !kre)
857 ret |= 0x2;
859 if (rw == 0 && foR)
860 ret |= 0x4;
861 if (rw == 2 && foE)
862 ret |= 0x8;
863 if (rw == 1 && foW)
864 ret |= 0xC;
865 *pfnp = pfn;
866 if (zbitsp != NULL)
867 *zbitsp = page_bits + (3 * gh);
868 if (protp != NULL)
869 *protp = ar;
871 return ret;
874 static int paddr_from_pte (uint64_t *paddr, int *zbitsp, int *prot,
875 uint64_t ptebase, int page_bits,
876 uint64_t vaddr, int mmu_idx, int rw)
878 uint64_t pfn, page_mask, lvl_mask, level1, level2, level3;
879 int lvl_bits, ret;
881 page_mask = (1ULL << page_bits) - 1ULL;
882 lvl_bits = page_bits - 3;
883 lvl_mask = (1ULL << lvl_bits) - 1ULL;
884 level3 = (vaddr >> page_bits) & lvl_mask;
885 level2 = (vaddr >> (page_bits + lvl_bits)) & lvl_mask;
886 level1 = (vaddr >> (page_bits + (2 * lvl_bits))) & lvl_mask;
887 /* Level 1 PTE */
888 ret = get_pte(&pfn, NULL, NULL, ptebase, page_bits, level1, 0, 0);
889 switch (ret) {
890 case 3:
891 /* Access violation */
892 return 2;
893 case 2:
894 /* translation not valid */
895 return 1;
896 default:
897 /* OK */
898 break;
900 /* Level 2 PTE */
901 ret = get_pte(&pfn, NULL, NULL, pfn, page_bits, level2, 0, 0);
902 switch (ret) {
903 case 3:
904 /* Access violation */
905 return 2;
906 case 2:
907 /* translation not valid */
908 return 1;
909 default:
910 /* OK */
911 break;
913 /* Level 3 PTE */
914 ret = get_pte(&pfn, zbitsp, prot, pfn, page_bits, level3, mmu_idx, rw);
915 if (ret & 0x1) {
916 /* Translation not valid */
917 ret = 1;
918 } else if (ret & 2) {
919 /* Access violation */
920 ret = 2;
921 } else {
922 switch (ret & 0xC) {
923 case 0:
924 /* OK */
925 ret = 0;
926 break;
927 case 0x4:
928 /* Fault on read */
929 ret = 3;
930 break;
931 case 0x8:
932 /* Fault on execute */
933 ret = 4;
934 break;
935 case 0xC:
936 /* Fault on write */
937 ret = 5;
938 break;
941 *paddr = (pfn << page_bits) | (vaddr & page_mask);
943 return 0;
946 static int virtual_to_physical (CPUState *env, uint64_t *physp,
947 int *zbitsp, int *protp,
948 uint64_t virtual, int mmu_idx, int rw)
950 uint64_t sva, ptebase;
951 int seg, page_bits, ret;
953 sva = ((int64_t)(virtual << (64 - VA_BITS))) >> (64 - VA_BITS);
954 if (sva != virtual)
955 seg = -1;
956 else
957 seg = sva >> (VA_BITS - 2);
958 virtual &= ~(0xFFFFFC0000000000ULL << (VA_BITS - 43));
959 ptebase = get_ptebase(env, virtual);
960 page_bits = get_page_bits(env);
961 ret = 0;
962 switch (seg) {
963 case 0:
964 /* seg1: 3 levels of PTE */
965 ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
966 virtual, mmu_idx, rw);
967 break;
968 case 1:
969 /* seg1: 2 levels of PTE */
970 ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
971 virtual, mmu_idx, rw);
972 break;
973 case 2:
974 /* kernel segment */
975 if (mmu_idx != 0) {
976 ret = 2;
977 } else {
978 *physp = virtual;
980 break;
981 case 3:
982 /* seg1: TB mapped */
983 ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
984 virtual, mmu_idx, rw);
985 break;
986 default:
987 ret = 1;
988 break;
991 return ret;
994 /* XXX: code provision */
995 int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
996 int mmu_idx, int is_softmmu)
998 uint64_t physical, page_size, end;
999 int prot, zbits, ret;
1001 #if defined(CONFIG_USER_ONLY)
1002 ret = 2;
1003 #else
1004 ret = virtual_to_physical(env, &physical, &zbits, &prot,
1005 address, mmu_idx, rw);
1006 #endif
1007 switch (ret) {
1008 case 0:
1009 /* No fault */
1010 page_size = 1ULL << zbits;
1011 address &= ~(page_size - 1);
1012 for (end = physical + page_size; physical < end; physical += 0x1000) {
1013 ret = tlb_set_page(env, address, physical, prot,
1014 mmu_idx, is_softmmu);
1015 address += 0x1000;
1017 break;
1018 #if 0
1019 case 1:
1020 env->exception_index = EXCP_DFAULT;
1021 env->ipr[IPR_EXC_ADDR] = address;
1022 ret = 1;
1023 break;
1024 case 2:
1025 env->exception_index = EXCP_ACCESS_VIOLATION;
1026 env->ipr[IPR_EXC_ADDR] = address;
1027 ret = 1;
1028 break;
1029 case 3:
1030 env->exception_index = EXCP_FAULT_ON_READ;
1031 env->ipr[IPR_EXC_ADDR] = address;
1032 ret = 1;
1033 break;
1034 case 4:
1035 env->exception_index = EXCP_FAULT_ON_EXECUTE;
1036 env->ipr[IPR_EXC_ADDR] = address;
1037 ret = 1;
1038 case 5:
1039 env->exception_index = EXCP_FAULT_ON_WRITE;
1040 env->ipr[IPR_EXC_ADDR] = address;
1041 ret = 1;
1042 #endif
1043 default:
1044 /* Should never happen */
1045 env->exception_index = EXCP_MCHK;
1046 env->ipr[IPR_EXC_ADDR] = address;
1047 ret = 1;
1048 break;
1051 return ret;
1053 #endif
1055 #else /* !defined (CONFIG_USER_ONLY) */
1056 void pal_init (CPUState *env)
1060 void call_pal (CPUState *env, int palcode)
1062 target_long ret;
1064 qemu_log("%s: palcode %02x\n", __func__, palcode);
1065 switch (palcode) {
1066 case 0x83:
1067 /* CALLSYS */
1068 qemu_log("CALLSYS n " TARGET_FMT_ld "\n", env->ir[0]);
1069 ret = do_syscall(env, env->ir[IR_V0], env->ir[IR_A0], env->ir[IR_A1],
1070 env->ir[IR_A2], env->ir[IR_A3], env->ir[IR_A4],
1071 env->ir[IR_A5]);
1072 if (ret >= 0) {
1073 env->ir[IR_A3] = 0;
1074 env->ir[IR_V0] = ret;
1075 } else {
1076 env->ir[IR_A3] = 1;
1077 env->ir[IR_V0] = -ret;
1079 break;
1080 case 0x9E:
1081 /* RDUNIQUE */
1082 env->ir[IR_V0] = env->unique;
1083 qemu_log("RDUNIQUE: " TARGET_FMT_lx "\n", env->unique);
1084 break;
1085 case 0x9F:
1086 /* WRUNIQUE */
1087 env->unique = env->ir[IR_A0];
1088 qemu_log("WRUNIQUE: " TARGET_FMT_lx "\n", env->unique);
1089 break;
1090 default:
1091 qemu_log("%s: unhandled palcode %02x\n",
1092 __func__, palcode);
1093 exit(1);
1096 #endif