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 */ | ... | ... |