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