Commit c55e9aefa7c151176e2e88c0f79044580930a970
1 parent
0a032cbe
PowerPC 4xx software driven TLB fixes + debug traces.
Add code provision for more MMU models support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2683 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
163 additions
and
39 deletions
target-ppc/cpu.h
... | ... | @@ -581,12 +581,12 @@ struct ppc6xx_tlb_t { |
581 | 581 | |
582 | 582 | typedef struct ppcemb_tlb_t ppcemb_tlb_t; |
583 | 583 | struct ppcemb_tlb_t { |
584 | - target_ulong RPN; | |
584 | + target_phys_addr_t RPN; | |
585 | 585 | target_ulong EPN; |
586 | 586 | target_ulong PID; |
587 | - int size; | |
588 | - int prot; | |
589 | - int attr; /* Storage attributes */ | |
587 | + target_ulong size; | |
588 | + uint32_t prot; | |
589 | + uint32_t attr; /* Storage attributes */ | |
590 | 590 | }; |
591 | 591 | |
592 | 592 | union ppc_tlb_t { |
... | ... | @@ -765,10 +765,6 @@ struct CPUPPCState { |
765 | 765 | int id_tlbs; /* If 1, MMU has separated TLBs for instructions & data */ |
766 | 766 | int nb_pids; /* Number of available PID registers */ |
767 | 767 | ppc_tlb_t *tlb; /* TLB is optional. Allocate them only if needed */ |
768 | - /* Callbacks for specific checks on some implementations */ | |
769 | - int (*tlb_check_more)(CPUPPCState *env, ppc_tlb_t *tlb, int *prot, | |
770 | - target_ulong vaddr, int rw, int acc_type, | |
771 | - int is_user); | |
772 | 768 | /* 403 dedicated access protection registers */ |
773 | 769 | target_ulong pb[4]; |
774 | 770 | ... | ... |
target-ppc/helper.c
... | ... | @@ -657,7 +657,8 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, |
657 | 657 | target_ulong mask; |
658 | 658 | int i, ret, zsel, zpr; |
659 | 659 | |
660 | - ret = -6; | |
660 | + ret = -1; | |
661 | + raddr = -1; | |
661 | 662 | for (i = 0; i < env->nb_tlb; i++) { |
662 | 663 | tlb = &env->tlb[i].tlbe; |
663 | 664 | /* Check valid flag */ |
... | ... | @@ -691,8 +692,8 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, |
691 | 692 | switch (zpr) { |
692 | 693 | case 0x0: |
693 | 694 | if (msr_pr) { |
694 | - ret = -3; | |
695 | 695 | ctx->prot = 0; |
696 | + ret = -3; | |
696 | 697 | break; |
697 | 698 | } |
698 | 699 | /* No break here */ |
... | ... | @@ -702,25 +703,26 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, |
702 | 703 | if (!(tlb->prot & PAGE_EXEC)) { |
703 | 704 | ret = -3; |
704 | 705 | } else { |
705 | - if (tlb->prot & PAGE_WRITE) | |
706 | + if (tlb->prot & PAGE_WRITE) { | |
706 | 707 | ctx->prot = PAGE_READ | PAGE_WRITE; |
707 | - else | |
708 | + } else { | |
708 | 709 | ctx->prot = PAGE_READ; |
710 | + } | |
709 | 711 | ret = 0; |
710 | 712 | } |
711 | 713 | break; |
712 | 714 | case 0x3: |
713 | 715 | /* All accesses granted */ |
714 | - ret = 0; | |
715 | 716 | ctx->prot = PAGE_READ | PAGE_WRITE; |
717 | + ret = 0; | |
716 | 718 | break; |
717 | 719 | } |
718 | 720 | } else { |
719 | 721 | switch (zpr) { |
720 | 722 | case 0x0: |
721 | 723 | if (msr_pr) { |
722 | - ret = -2; | |
723 | 724 | ctx->prot = 0; |
725 | + ret = -2; | |
724 | 726 | break; |
725 | 727 | } |
726 | 728 | /* No break here */ |
... | ... | @@ -728,20 +730,21 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, |
728 | 730 | case 0x2: |
729 | 731 | /* Check from TLB entry */ |
730 | 732 | /* Check write protection bit */ |
731 | - if (rw && !(tlb->prot & PAGE_WRITE)) { | |
732 | - ret = -2; | |
733 | + if (tlb->prot & PAGE_WRITE) { | |
734 | + ctx->prot = PAGE_READ | PAGE_WRITE; | |
735 | + ret = 0; | |
733 | 736 | } else { |
734 | - ret = 2; | |
735 | - if (tlb->prot & PAGE_WRITE) | |
736 | - ctx->prot = PAGE_READ | PAGE_WRITE; | |
737 | + ctx->prot = PAGE_READ; | |
738 | + if (rw) | |
739 | + ret = -2; | |
737 | 740 | else |
738 | - ctx->prot = PAGE_READ; | |
741 | + ret = 0; | |
739 | 742 | } |
740 | 743 | break; |
741 | 744 | case 0x3: |
742 | 745 | /* All accesses granted */ |
743 | - ret = 2; | |
744 | 746 | ctx->prot = PAGE_READ | PAGE_WRITE; |
747 | + ret = 0; | |
745 | 748 | break; |
746 | 749 | } |
747 | 750 | } |
... | ... | @@ -749,11 +752,17 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx, |
749 | 752 | ctx->raddr = raddr; |
750 | 753 | if (loglevel) { |
751 | 754 | fprintf(logfile, "%s: access granted " ADDRX " => " REGX |
752 | - " %d\n", __func__, address, ctx->raddr, ctx->prot); | |
755 | + " %d %d\n", __func__, address, ctx->raddr, ctx->prot, | |
756 | + ret); | |
753 | 757 | } |
754 | - return i; | |
758 | + return 0; | |
755 | 759 | } |
756 | 760 | } |
761 | + if (loglevel) { | |
762 | + fprintf(logfile, "%s: access refused " ADDRX " => " REGX | |
763 | + " %d %d\n", __func__, address, raddr, ctx->prot, | |
764 | + ret); | |
765 | + } | |
757 | 766 | |
758 | 767 | return ret; |
759 | 768 | } |
... | ... | @@ -808,32 +817,49 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, |
808 | 817 | /* No address translation */ |
809 | 818 | ret = check_physical(env, ctx, eaddr, rw); |
810 | 819 | } else { |
820 | + ret = -1; | |
811 | 821 | switch (PPC_MMU(env)) { |
812 | 822 | case PPC_FLAGS_MMU_32B: |
813 | 823 | case PPC_FLAGS_MMU_SOFT_6xx: |
814 | 824 | /* Try to find a BAT */ |
815 | - ret = -1; | |
816 | 825 | if (check_BATs) |
817 | 826 | ret = get_bat(env, ctx, eaddr, rw, access_type); |
827 | + /* No break here */ | |
828 | +#if defined(TARGET_PPC64) | |
829 | + case PPC_FLAGS_MMU_64B: | |
830 | + case PPC_FLAGS_MMU_64BRIDGE: | |
831 | +#endif | |
818 | 832 | if (ret < 0) { |
819 | - /* We didn't match any BAT entry */ | |
833 | + /* We didn't match any BAT entry or don't have BATs */ | |
820 | 834 | ret = get_segment(env, ctx, eaddr, rw, access_type); |
821 | 835 | } |
822 | 836 | break; |
823 | 837 | case PPC_FLAGS_MMU_SOFT_4xx: |
838 | + case PPC_FLAGS_MMU_403: | |
824 | 839 | ret = mmu4xx_get_physical_address(env, ctx, eaddr, |
825 | 840 | rw, access_type); |
826 | 841 | break; |
827 | - default: | |
842 | + case PPC_FLAGS_MMU_601: | |
843 | + /* XXX: TODO */ | |
844 | + cpu_abort(env, "601 MMU model not implemented\n"); | |
845 | + return -1; | |
846 | + case PPC_FLAGS_MMU_BOOKE: | |
828 | 847 | /* XXX: TODO */ |
829 | - cpu_abort(env, "MMU model not implemented\n"); | |
848 | + cpu_abort(env, "BookeE MMU model not implemented\n"); | |
849 | + return -1; | |
850 | + case PPC_FLAGS_MMU_BOOKE_FSL: | |
851 | + /* XXX: TODO */ | |
852 | + cpu_abort(env, "BookE FSL MMU model not implemented\n"); | |
853 | + return -1; | |
854 | + default: | |
855 | + cpu_abort(env, "Unknown or invalid MMU model\n"); | |
830 | 856 | return -1; |
831 | 857 | } |
832 | 858 | } |
833 | 859 | #if 0 |
834 | 860 | if (loglevel > 0) { |
835 | - fprintf(logfile, "%s address " ADDRX " => " ADDRX "\n", | |
836 | - __func__, eaddr, ctx->raddr); | |
861 | + fprintf(logfile, "%s address " ADDRX " => %d " ADDRX "\n", | |
862 | + __func__, eaddr, ret, ctx->raddr); | |
837 | 863 | } |
838 | 864 | #endif |
839 | 865 | |
... | ... | @@ -885,19 +911,48 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, |
885 | 911 | switch (ret) { |
886 | 912 | case -1: |
887 | 913 | /* No matches in page tables or TLB */ |
888 | - if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) { | |
914 | + switch (PPC_MMU(env)) { | |
915 | + case PPC_FLAGS_MMU_SOFT_6xx: | |
889 | 916 | exception = EXCP_I_TLBMISS; |
890 | 917 | env->spr[SPR_IMISS] = address; |
891 | 918 | env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem; |
892 | 919 | error_code = 1 << 18; |
893 | 920 | goto tlb_miss; |
894 | - } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) { | |
921 | + case PPC_FLAGS_MMU_SOFT_4xx: | |
922 | + case PPC_FLAGS_MMU_403: | |
895 | 923 | exception = EXCP_40x_ITLBMISS; |
896 | 924 | error_code = 0; |
897 | 925 | env->spr[SPR_40x_DEAR] = address; |
898 | 926 | env->spr[SPR_40x_ESR] = 0x00000000; |
899 | - } else { | |
927 | + break; | |
928 | + case PPC_FLAGS_MMU_32B: | |
900 | 929 | error_code = 0x40000000; |
930 | + break; | |
931 | +#if defined(TARGET_PPC64) | |
932 | + case PPC_FLAGS_MMU_64B: | |
933 | + /* XXX: TODO */ | |
934 | + cpu_abort(env, "MMU model not implemented\n"); | |
935 | + return -1; | |
936 | + case PPC_FLAGS_MMU_64BRIDGE: | |
937 | + /* XXX: TODO */ | |
938 | + cpu_abort(env, "MMU model not implemented\n"); | |
939 | + return -1; | |
940 | +#endif | |
941 | + case PPC_FLAGS_MMU_601: | |
942 | + /* XXX: TODO */ | |
943 | + cpu_abort(env, "MMU model not implemented\n"); | |
944 | + return -1; | |
945 | + case PPC_FLAGS_MMU_BOOKE: | |
946 | + /* XXX: TODO */ | |
947 | + cpu_abort(env, "MMU model not implemented\n"); | |
948 | + return -1; | |
949 | + case PPC_FLAGS_MMU_BOOKE_FSL: | |
950 | + /* XXX: TODO */ | |
951 | + cpu_abort(env, "MMU model not implemented\n"); | |
952 | + return -1; | |
953 | + default: | |
954 | + cpu_abort(env, "Unknown or invalid MMU model\n"); | |
955 | + return -1; | |
901 | 956 | } |
902 | 957 | break; |
903 | 958 | case -2: |
... | ... | @@ -924,7 +979,8 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, |
924 | 979 | switch (ret) { |
925 | 980 | case -1: |
926 | 981 | /* No matches in page tables or TLB */ |
927 | - if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) { | |
982 | + switch (PPC_MMU(env)) { | |
983 | + case PPC_FLAGS_MMU_SOFT_6xx: | |
928 | 984 | if (rw == 1) { |
929 | 985 | exception = EXCP_DS_TLBMISS; |
930 | 986 | error_code = 1 << 16; |
... | ... | @@ -940,7 +996,8 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, |
940 | 996 | env->spr[SPR_HASH2] = ctx.pg_addr[1]; |
941 | 997 | /* Do not alter DAR nor DSISR */ |
942 | 998 | goto out; |
943 | - } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) { | |
999 | + case PPC_FLAGS_MMU_SOFT_4xx: | |
1000 | + case PPC_FLAGS_MMU_403: | |
944 | 1001 | exception = EXCP_40x_DTLBMISS; |
945 | 1002 | error_code = 0; |
946 | 1003 | env->spr[SPR_40x_DEAR] = address; |
... | ... | @@ -948,8 +1005,35 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, |
948 | 1005 | env->spr[SPR_40x_ESR] = 0x00800000; |
949 | 1006 | else |
950 | 1007 | env->spr[SPR_40x_ESR] = 0x00000000; |
951 | - } else { | |
1008 | + break; | |
1009 | + case PPC_FLAGS_MMU_32B: | |
952 | 1010 | error_code = 0x40000000; |
1011 | + break; | |
1012 | +#if defined(TARGET_PPC64) | |
1013 | + case PPC_FLAGS_MMU_64B: | |
1014 | + /* XXX: TODO */ | |
1015 | + cpu_abort(env, "MMU model not implemented\n"); | |
1016 | + return -1; | |
1017 | + case PPC_FLAGS_MMU_64BRIDGE: | |
1018 | + /* XXX: TODO */ | |
1019 | + cpu_abort(env, "MMU model not implemented\n"); | |
1020 | + return -1; | |
1021 | +#endif | |
1022 | + case PPC_FLAGS_MMU_601: | |
1023 | + /* XXX: TODO */ | |
1024 | + cpu_abort(env, "MMU model not implemented\n"); | |
1025 | + return -1; | |
1026 | + case PPC_FLAGS_MMU_BOOKE: | |
1027 | + /* XXX: TODO */ | |
1028 | + cpu_abort(env, "MMU model not implemented\n"); | |
1029 | + return -1; | |
1030 | + case PPC_FLAGS_MMU_BOOKE_FSL: | |
1031 | + /* XXX: TODO */ | |
1032 | + cpu_abort(env, "MMU model not implemented\n"); | |
1033 | + return -1; | |
1034 | + default: | |
1035 | + cpu_abort(env, "Unknown or invalid MMU model\n"); | |
1036 | + return -1; | |
953 | 1037 | } |
954 | 1038 | break; |
955 | 1039 | case -2: | ... | ... |
target-ppc/op_helper.c
... | ... | @@ -2537,39 +2537,72 @@ void do_4xx_tlbsx_ (void) |
2537 | 2537 | env->crf[0] = tmp; |
2538 | 2538 | } |
2539 | 2539 | |
2540 | -void do_4xx_tlbwe_lo (void) | |
2540 | +void do_4xx_tlbwe_hi (void) | |
2541 | 2541 | { |
2542 | 2542 | ppcemb_tlb_t *tlb; |
2543 | 2543 | target_ulong page, end; |
2544 | 2544 | |
2545 | +#if defined (DEBUG_SOFTWARE_TLB) | |
2546 | + if (loglevel) { | |
2547 | + fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1); | |
2548 | + } | |
2549 | +#endif | |
2545 | 2550 | T0 &= 0x3F; |
2546 | 2551 | tlb = &env->tlb[T0].tlbe; |
2547 | 2552 | /* Invalidate previous TLB (if it's valid) */ |
2548 | 2553 | if (tlb->prot & PAGE_VALID) { |
2549 | 2554 | end = tlb->EPN + tlb->size; |
2555 | +#if defined (DEBUG_SOFTWARE_TLB) | |
2556 | + if (loglevel) { | |
2557 | + fprintf(logfile, "%s: invalidate old TLB %d start " ADDRX | |
2558 | + " end " ADDRX "\n", __func__, (int)T0, tlb->EPN, end); | |
2559 | + } | |
2560 | +#endif | |
2550 | 2561 | for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) |
2551 | 2562 | tlb_flush_page(env, page); |
2552 | 2563 | } |
2553 | 2564 | tlb->size = booke_tlb_to_page_size((T1 >> 7) & 0x7); |
2554 | 2565 | tlb->EPN = (T1 & 0xFFFFFC00) & ~(tlb->size - 1); |
2555 | - if (T1 & 0x400) | |
2566 | + if (T1 & 0x40) | |
2556 | 2567 | tlb->prot |= PAGE_VALID; |
2557 | 2568 | else |
2558 | 2569 | tlb->prot &= ~PAGE_VALID; |
2559 | - tlb->PID = env->spr[SPR_BOOKE_PID]; /* PID */ | |
2570 | + tlb->PID = env->spr[SPR_40x_PID]; /* PID */ | |
2560 | 2571 | tlb->attr = T1 & 0xFF; |
2572 | +#if defined (DEBUG_SOFTWARE_TLB) | |
2573 | + if (loglevel) { | |
2574 | + fprintf(logfile, "%s: set up TLB %d RPN " ADDRX " EPN " ADDRX | |
2575 | + " size " ADDRX " prot %c%c%c%c PID %d\n", __func__, | |
2576 | + (int)T0, tlb->RPN, tlb->EPN, tlb->size, | |
2577 | + tlb->prot & PAGE_READ ? 'r' : '-', | |
2578 | + tlb->prot & PAGE_WRITE ? 'w' : '-', | |
2579 | + tlb->prot & PAGE_EXEC ? 'x' : '-', | |
2580 | + tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID); | |
2581 | + } | |
2582 | +#endif | |
2561 | 2583 | /* Invalidate new TLB (if valid) */ |
2562 | 2584 | if (tlb->prot & PAGE_VALID) { |
2563 | 2585 | end = tlb->EPN + tlb->size; |
2586 | +#if defined (DEBUG_SOFTWARE_TLB) | |
2587 | + if (loglevel) { | |
2588 | + fprintf(logfile, "%s: invalidate TLB %d start " ADDRX | |
2589 | + " end " ADDRX "\n", __func__, (int)T0, tlb->EPN, end); | |
2590 | + } | |
2591 | +#endif | |
2564 | 2592 | for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) |
2565 | 2593 | tlb_flush_page(env, page); |
2566 | 2594 | } |
2567 | 2595 | } |
2568 | 2596 | |
2569 | -void do_4xx_tlbwe_hi (void) | |
2597 | +void do_4xx_tlbwe_lo (void) | |
2570 | 2598 | { |
2571 | 2599 | ppcemb_tlb_t *tlb; |
2572 | 2600 | |
2601 | +#if defined (DEBUG_SOFTWARE_TLB) | |
2602 | + if (loglevel) { | |
2603 | + fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1); | |
2604 | + } | |
2605 | +#endif | |
2573 | 2606 | T0 &= 0x3F; |
2574 | 2607 | tlb = &env->tlb[T0].tlbe; |
2575 | 2608 | tlb->RPN = T1 & 0xFFFFFC00; |
... | ... | @@ -2578,5 +2611,16 @@ void do_4xx_tlbwe_hi (void) |
2578 | 2611 | tlb->prot |= PAGE_EXEC; |
2579 | 2612 | if (T1 & 0x100) |
2580 | 2613 | tlb->prot |= PAGE_WRITE; |
2614 | +#if defined (DEBUG_SOFTWARE_TLB) | |
2615 | + if (loglevel) { | |
2616 | + fprintf(logfile, "%s: set up TLB %d RPN " ADDRX " EPN " ADDRX | |
2617 | + " size " ADDRX " prot %c%c%c%c PID %d\n", __func__, | |
2618 | + (int)T0, tlb->RPN, tlb->EPN, tlb->size, | |
2619 | + tlb->prot & PAGE_READ ? 'r' : '-', | |
2620 | + tlb->prot & PAGE_WRITE ? 'w' : '-', | |
2621 | + tlb->prot & PAGE_EXEC ? 'x' : '-', | |
2622 | + tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID); | |
2623 | + } | |
2624 | +#endif | |
2581 | 2625 | } |
2582 | 2626 | #endif /* !CONFIG_USER_ONLY */ | ... | ... |