Revision 74d37793 target-ppc/op_helper.c
b/target-ppc/op_helper.c | ||
---|---|---|
2552 | 2552 |
env = saved_env; |
2553 | 2553 |
} |
2554 | 2554 |
|
2555 |
/* Segment registers load and store */ |
|
2556 |
target_ulong helper_load_sr (target_ulong sr_num) |
|
2557 |
{ |
|
2558 |
return env->sr[sr_num]; |
|
2559 |
} |
|
2560 |
|
|
2561 |
void helper_store_sr (target_ulong sr_num, target_ulong val) |
|
2562 |
{ |
|
2563 |
do_store_sr(env, sr_num, val); |
|
2564 |
} |
|
2565 |
|
|
2566 |
/* SLB management */ |
|
2567 |
#if defined(TARGET_PPC64) |
|
2568 |
target_ulong helper_load_slb (target_ulong slb_nr) |
|
2569 |
{ |
|
2570 |
return ppc_load_slb(env, slb_nr); |
|
2571 |
} |
|
2572 |
|
|
2573 |
void helper_store_slb (target_ulong slb_nr, target_ulong rs) |
|
2574 |
{ |
|
2575 |
ppc_store_slb(env, slb_nr, rs); |
|
2576 |
} |
|
2577 |
|
|
2578 |
void helper_slbia (void) |
|
2579 |
{ |
|
2580 |
ppc_slb_invalidate_all(env); |
|
2581 |
} |
|
2582 |
|
|
2583 |
void helper_slbie (target_ulong addr) |
|
2584 |
{ |
|
2585 |
ppc_slb_invalidate_one(env, addr); |
|
2586 |
} |
|
2587 |
|
|
2588 |
#endif /* defined(TARGET_PPC64) */ |
|
2589 |
|
|
2590 |
/* TLB management */ |
|
2591 |
void helper_tlbia (void) |
|
2592 |
{ |
|
2593 |
ppc_tlb_invalidate_all(env); |
|
2594 |
} |
|
2595 |
|
|
2596 |
void helper_tlbie (target_ulong addr) |
|
2597 |
{ |
|
2598 |
ppc_tlb_invalidate_one(env, addr); |
|
2599 |
} |
|
2600 |
|
|
2555 | 2601 |
/* Software driven TLBs management */ |
2556 | 2602 |
/* PowerPC 602/603 software TLB load instructions helpers */ |
2557 |
static void helper_load_6xx_tlb (target_ulong new_EPN, int is_code)
|
|
2603 |
static void do_6xx_tlb (target_ulong new_EPN, int is_code)
|
|
2558 | 2604 |
{ |
2559 | 2605 |
target_ulong RPN, CMP, EPN; |
2560 | 2606 |
int way; |
... | ... | |
2580 | 2626 |
way, is_code, CMP, RPN); |
2581 | 2627 |
} |
2582 | 2628 |
|
2583 |
void helper_load_6xx_tlbd (target_ulong EPN)
|
|
2629 |
void helper_6xx_tlbd (target_ulong EPN) |
|
2584 | 2630 |
{ |
2585 |
helper_load_6xx_tlb(EPN, 0);
|
|
2631 |
do_6xx_tlb(EPN, 0);
|
|
2586 | 2632 |
} |
2587 | 2633 |
|
2588 |
void helper_load_6xx_tlbi (target_ulong EPN)
|
|
2634 |
void helper_6xx_tlbi (target_ulong EPN) |
|
2589 | 2635 |
{ |
2590 |
helper_load_6xx_tlb(EPN, 1);
|
|
2636 |
do_6xx_tlb(EPN, 1);
|
|
2591 | 2637 |
} |
2592 | 2638 |
|
2593 | 2639 |
/* PowerPC 74xx software TLB load instructions helpers */ |
2594 |
static void helper_load_74xx_tlb (target_ulong new_EPN, int is_code)
|
|
2640 |
static void do_74xx_tlb (target_ulong new_EPN, int is_code)
|
|
2595 | 2641 |
{ |
2596 | 2642 |
target_ulong RPN, CMP, EPN; |
2597 | 2643 |
int way; |
... | ... | |
2612 | 2658 |
way, is_code, CMP, RPN); |
2613 | 2659 |
} |
2614 | 2660 |
|
2615 |
void helper_load_74xx_tlbd (target_ulong EPN)
|
|
2661 |
void helper_74xx_tlbd (target_ulong EPN) |
|
2616 | 2662 |
{ |
2617 |
helper_load_74xx_tlb(EPN, 0);
|
|
2663 |
do_74xx_tlb(EPN, 0);
|
|
2618 | 2664 |
} |
2619 | 2665 |
|
2620 |
void helper_load_74xx_tlbi (target_ulong EPN)
|
|
2666 |
void helper_74xx_tlbi (target_ulong EPN) |
|
2621 | 2667 |
{ |
2622 |
helper_load_74xx_tlb(EPN, 1);
|
|
2668 |
do_74xx_tlb(EPN, 1);
|
|
2623 | 2669 |
} |
2624 | 2670 |
|
2625 | 2671 |
static always_inline target_ulong booke_tlb_to_page_size (int size) |
... | ... | |
2691 | 2737 |
} |
2692 | 2738 |
|
2693 | 2739 |
/* Helpers for 4xx TLB management */ |
2694 |
void do_4xx_tlbre_lo (void)
|
|
2740 |
target_ulong helper_4xx_tlbre_lo (target_ulong entry)
|
|
2695 | 2741 |
{ |
2696 | 2742 |
ppcemb_tlb_t *tlb; |
2743 |
target_ulong ret; |
|
2697 | 2744 |
int size; |
2698 | 2745 |
|
2699 |
T0 &= 0x3F;
|
|
2700 |
tlb = &env->tlb[T0].tlbe;
|
|
2701 |
T0 = tlb->EPN;
|
|
2746 |
entry &= 0x3F;
|
|
2747 |
tlb = &env->tlb[entry].tlbe;
|
|
2748 |
ret = tlb->EPN;
|
|
2702 | 2749 |
if (tlb->prot & PAGE_VALID) |
2703 |
T0 |= 0x400;
|
|
2750 |
ret |= 0x400;
|
|
2704 | 2751 |
size = booke_page_size_to_tlb(tlb->size); |
2705 | 2752 |
if (size < 0 || size > 0x7) |
2706 | 2753 |
size = 1; |
2707 |
T0 |= size << 7;
|
|
2754 |
ret |= size << 7;
|
|
2708 | 2755 |
env->spr[SPR_40x_PID] = tlb->PID; |
2756 |
return ret; |
|
2709 | 2757 |
} |
2710 | 2758 |
|
2711 |
void do_4xx_tlbre_hi (void)
|
|
2759 |
target_ulong helper_4xx_tlbre_hi (target_ulong entry)
|
|
2712 | 2760 |
{ |
2713 | 2761 |
ppcemb_tlb_t *tlb; |
2762 |
target_ulong ret; |
|
2714 | 2763 |
|
2715 |
T0 &= 0x3F;
|
|
2716 |
tlb = &env->tlb[T0].tlbe;
|
|
2717 |
T0 = tlb->RPN;
|
|
2764 |
entry &= 0x3F;
|
|
2765 |
tlb = &env->tlb[entry].tlbe;
|
|
2766 |
ret = tlb->RPN;
|
|
2718 | 2767 |
if (tlb->prot & PAGE_EXEC) |
2719 |
T0 |= 0x200;
|
|
2768 |
ret |= 0x200;
|
|
2720 | 2769 |
if (tlb->prot & PAGE_WRITE) |
2721 |
T0 |= 0x100; |
|
2770 |
ret |= 0x100; |
|
2771 |
return ret; |
|
2722 | 2772 |
} |
2723 | 2773 |
|
2724 |
void do_4xx_tlbwe_hi (void)
|
|
2774 |
void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
|
|
2725 | 2775 |
{ |
2726 | 2776 |
ppcemb_tlb_t *tlb; |
2727 | 2777 |
target_ulong page, end; |
2728 | 2778 |
|
2729 | 2779 |
#if defined (DEBUG_SOFTWARE_TLB) |
2730 | 2780 |
if (loglevel != 0) { |
2731 |
fprintf(logfile, "%s T0 " TDX " T1 " TDX "\n", __func__, T0, T1);
|
|
2781 |
fprintf(logfile, "%s entry " TDX " val " TDX "\n", __func__, entry, val);
|
|
2732 | 2782 |
} |
2733 | 2783 |
#endif |
2734 |
T0 &= 0x3F;
|
|
2735 |
tlb = &env->tlb[T0].tlbe;
|
|
2784 |
entry &= 0x3F;
|
|
2785 |
tlb = &env->tlb[entry].tlbe;
|
|
2736 | 2786 |
/* Invalidate previous TLB (if it's valid) */ |
2737 | 2787 |
if (tlb->prot & PAGE_VALID) { |
2738 | 2788 |
end = tlb->EPN + tlb->size; |
2739 | 2789 |
#if defined (DEBUG_SOFTWARE_TLB) |
2740 | 2790 |
if (loglevel != 0) { |
2741 | 2791 |
fprintf(logfile, "%s: invalidate old TLB %d start " ADDRX |
2742 |
" end " ADDRX "\n", __func__, (int)T0, tlb->EPN, end);
|
|
2792 |
" end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
|
|
2743 | 2793 |
} |
2744 | 2794 |
#endif |
2745 | 2795 |
for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) |
2746 | 2796 |
tlb_flush_page(env, page); |
2747 | 2797 |
} |
2748 |
tlb->size = booke_tlb_to_page_size((T1 >> 7) & 0x7);
|
|
2798 |
tlb->size = booke_tlb_to_page_size((val >> 7) & 0x7);
|
|
2749 | 2799 |
/* We cannot handle TLB size < TARGET_PAGE_SIZE. |
2750 | 2800 |
* If this ever occurs, one should use the ppcemb target instead |
2751 | 2801 |
* of the ppc or ppc64 one |
2752 | 2802 |
*/ |
2753 |
if ((T1 & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
|
|
2803 |
if ((val & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
|
|
2754 | 2804 |
cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u " |
2755 | 2805 |
"are not supported (%d)\n", |
2756 |
tlb->size, TARGET_PAGE_SIZE, (int)((T1 >> 7) & 0x7));
|
|
2806 |
tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
|
|
2757 | 2807 |
} |
2758 |
tlb->EPN = T1 & ~(tlb->size - 1);
|
|
2759 |
if (T1 & 0x40)
|
|
2808 |
tlb->EPN = val & ~(tlb->size - 1);
|
|
2809 |
if (val & 0x40)
|
|
2760 | 2810 |
tlb->prot |= PAGE_VALID; |
2761 | 2811 |
else |
2762 | 2812 |
tlb->prot &= ~PAGE_VALID; |
2763 |
if (T1 & 0x20) {
|
|
2813 |
if (val & 0x20) {
|
|
2764 | 2814 |
/* XXX: TO BE FIXED */ |
2765 | 2815 |
cpu_abort(env, "Little-endian TLB entries are not supported by now\n"); |
2766 | 2816 |
} |
2767 | 2817 |
tlb->PID = env->spr[SPR_40x_PID]; /* PID */ |
2768 |
tlb->attr = T1 & 0xFF;
|
|
2818 |
tlb->attr = val & 0xFF;
|
|
2769 | 2819 |
#if defined (DEBUG_SOFTWARE_TLB) |
2770 | 2820 |
if (loglevel != 0) { |
2771 | 2821 |
fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX |
... | ... | |
2791 | 2841 |
} |
2792 | 2842 |
} |
2793 | 2843 |
|
2794 |
void do_4xx_tlbwe_lo (void)
|
|
2844 |
void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
|
|
2795 | 2845 |
{ |
2796 | 2846 |
ppcemb_tlb_t *tlb; |
2797 | 2847 |
|
2798 | 2848 |
#if defined (DEBUG_SOFTWARE_TLB) |
2799 | 2849 |
if (loglevel != 0) { |
2800 |
fprintf(logfile, "%s T0 " TDX " T1 " TDX "\n", __func__, T0, T1);
|
|
2850 |
fprintf(logfile, "%s entry " TDX " val " TDX "\n", __func__, entry, val);
|
|
2801 | 2851 |
} |
2802 | 2852 |
#endif |
2803 |
T0 &= 0x3F;
|
|
2804 |
tlb = &env->tlb[T0].tlbe;
|
|
2805 |
tlb->RPN = T1 & 0xFFFFFC00;
|
|
2853 |
entry &= 0x3F;
|
|
2854 |
tlb = &env->tlb[entry].tlbe;
|
|
2855 |
tlb->RPN = val & 0xFFFFFC00;
|
|
2806 | 2856 |
tlb->prot = PAGE_READ; |
2807 |
if (T1 & 0x200)
|
|
2857 |
if (val & 0x200)
|
|
2808 | 2858 |
tlb->prot |= PAGE_EXEC; |
2809 |
if (T1 & 0x100)
|
|
2859 |
if (val & 0x100)
|
|
2810 | 2860 |
tlb->prot |= PAGE_WRITE; |
2811 | 2861 |
#if defined (DEBUG_SOFTWARE_TLB) |
2812 | 2862 |
if (loglevel != 0) { |
2813 | 2863 |
fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX |
2814 | 2864 |
" size " ADDRX " prot %c%c%c%c PID %d\n", __func__, |
2815 |
(int)T0, tlb->RPN, tlb->EPN, tlb->size,
|
|
2865 |
(int)entry, tlb->RPN, tlb->EPN, tlb->size,
|
|
2816 | 2866 |
tlb->prot & PAGE_READ ? 'r' : '-', |
2817 | 2867 |
tlb->prot & PAGE_WRITE ? 'w' : '-', |
2818 | 2868 |
tlb->prot & PAGE_EXEC ? 'x' : '-', |
... | ... | |
2821 | 2871 |
#endif |
2822 | 2872 |
} |
2823 | 2873 |
|
2874 |
target_ulong helper_4xx_tlbsx (target_ulong address) |
|
2875 |
{ |
|
2876 |
return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]); |
|
2877 |
} |
|
2878 |
|
|
2824 | 2879 |
/* PowerPC 440 TLB management */ |
2825 |
void do_440_tlbwe (int word)
|
|
2880 |
void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
|
|
2826 | 2881 |
{ |
2827 | 2882 |
ppcemb_tlb_t *tlb; |
2828 | 2883 |
target_ulong EPN, RPN, size; |
... | ... | |
2830 | 2885 |
|
2831 | 2886 |
#if defined (DEBUG_SOFTWARE_TLB) |
2832 | 2887 |
if (loglevel != 0) { |
2833 |
fprintf(logfile, "%s word %d T0 " TDX " T1 " TDX "\n",
|
|
2834 |
__func__, word, T0, T1);
|
|
2888 |
fprintf(logfile, "%s word %d entry " TDX " value " TDX "\n",
|
|
2889 |
__func__, word, entry, value);
|
|
2835 | 2890 |
} |
2836 | 2891 |
#endif |
2837 | 2892 |
do_flush_tlbs = 0; |
2838 |
T0 &= 0x3F;
|
|
2839 |
tlb = &env->tlb[T0].tlbe;
|
|
2893 |
entry &= 0x3F;
|
|
2894 |
tlb = &env->tlb[entry].tlbe;
|
|
2840 | 2895 |
switch (word) { |
2841 | 2896 |
default: |
2842 | 2897 |
/* Just here to please gcc */ |
2843 | 2898 |
case 0: |
2844 |
EPN = T1 & 0xFFFFFC00;
|
|
2899 |
EPN = value & 0xFFFFFC00;
|
|
2845 | 2900 |
if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) |
2846 | 2901 |
do_flush_tlbs = 1; |
2847 | 2902 |
tlb->EPN = EPN; |
2848 |
size = booke_tlb_to_page_size((T1 >> 4) & 0xF);
|
|
2903 |
size = booke_tlb_to_page_size((value >> 4) & 0xF);
|
|
2849 | 2904 |
if ((tlb->prot & PAGE_VALID) && tlb->size < size) |
2850 | 2905 |
do_flush_tlbs = 1; |
2851 | 2906 |
tlb->size = size; |
2852 | 2907 |
tlb->attr &= ~0x1; |
2853 |
tlb->attr |= (T1 >> 8) & 1;
|
|
2854 |
if (T1 & 0x200) {
|
|
2908 |
tlb->attr |= (value >> 8) & 1;
|
|
2909 |
if (value & 0x200) {
|
|
2855 | 2910 |
tlb->prot |= PAGE_VALID; |
2856 | 2911 |
} else { |
2857 | 2912 |
if (tlb->prot & PAGE_VALID) { |
... | ... | |
2864 | 2919 |
tlb_flush(env, 1); |
2865 | 2920 |
break; |
2866 | 2921 |
case 1: |
2867 |
RPN = T1 & 0xFFFFFC0F;
|
|
2922 |
RPN = value & 0xFFFFFC0F;
|
|
2868 | 2923 |
if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) |
2869 | 2924 |
tlb_flush(env, 1); |
2870 | 2925 |
tlb->RPN = RPN; |
2871 | 2926 |
break; |
2872 | 2927 |
case 2: |
2873 |
tlb->attr = (tlb->attr & 0x1) | (T1 & 0x0000FF00);
|
|
2928 |
tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
|
|
2874 | 2929 |
tlb->prot = tlb->prot & PAGE_VALID; |
2875 |
if (T1 & 0x1)
|
|
2930 |
if (value & 0x1)
|
|
2876 | 2931 |
tlb->prot |= PAGE_READ << 4; |
2877 |
if (T1 & 0x2)
|
|
2932 |
if (value & 0x2)
|
|
2878 | 2933 |
tlb->prot |= PAGE_WRITE << 4; |
2879 |
if (T1 & 0x4)
|
|
2934 |
if (value & 0x4)
|
|
2880 | 2935 |
tlb->prot |= PAGE_EXEC << 4; |
2881 |
if (T1 & 0x8)
|
|
2936 |
if (value & 0x8)
|
|
2882 | 2937 |
tlb->prot |= PAGE_READ; |
2883 |
if (T1 & 0x10)
|
|
2938 |
if (value & 0x10)
|
|
2884 | 2939 |
tlb->prot |= PAGE_WRITE; |
2885 |
if (T1 & 0x20)
|
|
2940 |
if (value & 0x20)
|
|
2886 | 2941 |
tlb->prot |= PAGE_EXEC; |
2887 | 2942 |
break; |
2888 | 2943 |
} |
2889 | 2944 |
} |
2890 | 2945 |
|
2891 |
void do_440_tlbre (int word)
|
|
2946 |
target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
|
|
2892 | 2947 |
{ |
2893 | 2948 |
ppcemb_tlb_t *tlb; |
2949 |
target_ulong ret; |
|
2894 | 2950 |
int size; |
2895 | 2951 |
|
2896 |
T0 &= 0x3F;
|
|
2897 |
tlb = &env->tlb[T0].tlbe;
|
|
2952 |
entry &= 0x3F;
|
|
2953 |
tlb = &env->tlb[entry].tlbe;
|
|
2898 | 2954 |
switch (word) { |
2899 | 2955 |
default: |
2900 | 2956 |
/* Just here to please gcc */ |
2901 | 2957 |
case 0: |
2902 |
T0 = tlb->EPN;
|
|
2958 |
ret = tlb->EPN;
|
|
2903 | 2959 |
size = booke_page_size_to_tlb(tlb->size); |
2904 | 2960 |
if (size < 0 || size > 0xF) |
2905 | 2961 |
size = 1; |
2906 |
T0 |= size << 4;
|
|
2962 |
ret |= size << 4;
|
|
2907 | 2963 |
if (tlb->attr & 0x1) |
2908 |
T0 |= 0x100;
|
|
2964 |
ret |= 0x100;
|
|
2909 | 2965 |
if (tlb->prot & PAGE_VALID) |
2910 |
T0 |= 0x200;
|
|
2966 |
ret |= 0x200;
|
|
2911 | 2967 |
env->spr[SPR_440_MMUCR] &= ~0x000000FF; |
2912 | 2968 |
env->spr[SPR_440_MMUCR] |= tlb->PID; |
2913 | 2969 |
break; |
2914 | 2970 |
case 1: |
2915 |
T0 = tlb->RPN;
|
|
2971 |
ret = tlb->RPN;
|
|
2916 | 2972 |
break; |
2917 | 2973 |
case 2: |
2918 |
T0 = tlb->attr & ~0x1;
|
|
2974 |
ret = tlb->attr & ~0x1;
|
|
2919 | 2975 |
if (tlb->prot & (PAGE_READ << 4)) |
2920 |
T0 |= 0x1;
|
|
2976 |
ret |= 0x1;
|
|
2921 | 2977 |
if (tlb->prot & (PAGE_WRITE << 4)) |
2922 |
T0 |= 0x2;
|
|
2978 |
ret |= 0x2;
|
|
2923 | 2979 |
if (tlb->prot & (PAGE_EXEC << 4)) |
2924 |
T0 |= 0x4;
|
|
2980 |
ret |= 0x4;
|
|
2925 | 2981 |
if (tlb->prot & PAGE_READ) |
2926 |
T0 |= 0x8;
|
|
2982 |
ret |= 0x8;
|
|
2927 | 2983 |
if (tlb->prot & PAGE_WRITE) |
2928 |
T0 |= 0x10;
|
|
2984 |
ret |= 0x10;
|
|
2929 | 2985 |
if (tlb->prot & PAGE_EXEC) |
2930 |
T0 |= 0x20;
|
|
2986 |
ret |= 0x20;
|
|
2931 | 2987 |
break; |
2932 | 2988 |
} |
2989 |
return ret; |
|
2933 | 2990 |
} |
2991 |
|
|
2992 |
target_ulong helper_440_tlbsx (target_ulong address) |
|
2993 |
{ |
|
2994 |
return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF); |
|
2995 |
} |
|
2996 |
|
|
2934 | 2997 |
#endif /* !CONFIG_USER_ONLY */ |
Also available in: Unified diff