Revision c55e9aef
b/target-ppc/cpu.h | ||
---|---|---|
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 | 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 |
|
b/target-ppc/helper.c | ||
---|---|---|
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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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: |
b/target-ppc/op_helper.c | ||
---|---|---|
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 | 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 */ |
Also available in: Unified diff