more stdvga cleanups.
[qemu.git] / hw / alpha_palcode.c
blob033b54201c27a26bdce1a1046ce78d6d081f8ac5
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 "cpu.h"
25 #include "exec-all.h"
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);
36 pal_handler_t pal_handlers[] = {
37 /* Console handler */
39 .reset = &pal_reset,
40 .call_pal = &pal_console_call,
42 /* OpenVMS handler */
44 .reset = &pal_reset,
45 .call_pal = &pal_openvms_call,
47 /* UNIX / Linux handler */
49 .reset = &pal_reset,
50 .call_pal = &pal_unix_call,
54 #if 0
55 /* One must explicitly check that the TB is valid and the FOE bit is reset */
56 static void update_itb (void)
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);
65 static void update_dtb (void);
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);
73 #endif
75 static void pal_reset (CPUState *env)
79 static void do_swappal (CPUState *env, uint64_t palid)
81 pal_handler_t *pal_handler;
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();
103 static void pal_console_call (CPUState *env, uint32_t palcode)
105 uint64_t palid;
107 if (palcode < 0x00000080) {
108 /* Privileged palcodes */
109 if (!(env->ps >> 3)) {
110 /* TODO: generate privilege exception */
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;
166 static void pal_openvms_call (CPUState *env, uint32_t palcode)
168 uint64_t palid, val, oldval;
170 if (palcode < 0x00000080) {
171 /* Privileged palcodes */
172 if (!(env->ps >> 3)) {
173 /* TODO: generate privilege exception */
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;
560 static void pal_unix_call (CPUState *env, uint32_t palcode)
562 uint64_t palid, val, oldval;
564 if (palcode < 0x00000080) {
565 /* Privileged palcodes */
566 if (!(env->ps >> 3)) {
567 /* TODO: generate privilege exception */
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;
718 void call_pal (CPUState *env)
720 pal_handler_t *pal_handler = env->pal_handler;
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 */
773 break;
775 env->ipr[IPR_EXC_ADDR] &= ~1;
778 void pal_init (CPUState *env)
780 do_swappal(env, 0);
783 #if 0
784 static uint64_t get_ptebase (CPUState *env, uint64_t vaddr)
786 uint64_t virbnd, ptbr;
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);
798 return ptbr;
801 static int get_page_bits (CPUState *env)
803 /* XXX */
804 return 13;
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)
811 uint64_t pteaddr, pte, pfn;
812 uint8_t gh;
813 int ure, uwe, kre, kwe, foE, foR, foW, v, ret, ar, is_user;
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;
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;
866 return ret;
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)
873 uint64_t pfn, page_mask, lvl_mask, level1, level2, level3;
874 int lvl_bits, ret;
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;
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;
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;
936 *paddr = (pfn << page_bits) | (vaddr & page_mask);
938 return 0;
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)
945 uint64_t sva, ptebase;
946 int seg, page_bits, ret;
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;
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;
986 return ret;
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)
993 uint64_t physical, page_size, end;
994 int prot, zbits, ret;
996 ret = virtual_to_physical(env, &physical, &zbits, &prot,
997 address, mmu_idx, rw);
999 switch (ret) {
1000 case 0:
1001 /* No fault */
1002 page_size = 1ULL << zbits;
1003 address &= ~(page_size - 1);
1004 /* FIXME: page_size should probably be passed to tlb_set_page,
1005 and this loop removed. */
1006 for (end = physical + page_size; physical < end; physical += 0x1000) {
1007 tlb_set_page(env, address, physical, prot, mmu_idx,
1008 TARGET_PAGE_SIZE);
1009 address += 0x1000;
1011 ret = 0;
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;
1046 return ret;
1048 #endif