Revision 5b5aba4f target-ppc/helper.c
b/target-ppc/helper.c | ||
---|---|---|
582 | 582 |
|
583 | 583 |
/* PTE table lookup */ |
584 | 584 |
static always_inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, |
585 |
int rw, int type) |
|
585 |
int rw, int type, |
|
586 |
int target_page_bits) |
|
586 | 587 |
{ |
587 | 588 |
target_ulong base, pte0, pte1; |
588 | 589 |
int i, good = -1; |
... | ... | |
594 | 595 |
#if defined(TARGET_PPC64) |
595 | 596 |
if (is_64b) { |
596 | 597 |
pte0 = ldq_phys(base + (i * 16)); |
597 |
pte1 = ldq_phys(base + (i * 16) + 8); |
|
598 |
pte1 = ldq_phys(base + (i * 16) + 8); |
|
599 |
|
|
600 |
/* We have a TLB that saves 4K pages, so let's |
|
601 |
* split a huge page to 4k chunks */ |
|
602 |
if (target_page_bits != TARGET_PAGE_BITS) |
|
603 |
pte1 |= (ctx->eaddr & (( 1 << target_page_bits ) - 1)) |
|
604 |
& TARGET_PAGE_MASK; |
|
605 |
|
|
598 | 606 |
r = pte64_check(ctx, pte0, pte1, h, rw, type); |
599 | 607 |
LOG_MMU("Load pte from " ADDRX " => " ADDRX " " ADDRX |
600 | 608 |
" %d %d %d " ADDRX "\n", |
... | ... | |
658 | 666 |
return ret; |
659 | 667 |
} |
660 | 668 |
|
661 |
static always_inline int find_pte32 (mmu_ctx_t *ctx, int h, int rw, int type) |
|
669 |
static always_inline int find_pte32 (mmu_ctx_t *ctx, int h, int rw, |
|
670 |
int type, int target_page_bits) |
|
662 | 671 |
{ |
663 |
return _find_pte(ctx, 0, h, rw, type); |
|
672 |
return _find_pte(ctx, 0, h, rw, type, target_page_bits);
|
|
664 | 673 |
} |
665 | 674 |
|
666 | 675 |
#if defined(TARGET_PPC64) |
667 |
static always_inline int find_pte64 (mmu_ctx_t *ctx, int h, int rw, int type) |
|
676 |
static always_inline int find_pte64 (mmu_ctx_t *ctx, int h, int rw, |
|
677 |
int type, int target_page_bits) |
|
668 | 678 |
{ |
669 |
return _find_pte(ctx, 1, h, rw, type); |
|
679 |
return _find_pte(ctx, 1, h, rw, type, target_page_bits);
|
|
670 | 680 |
} |
671 | 681 |
#endif |
672 | 682 |
|
673 | 683 |
static always_inline int find_pte (CPUState *env, mmu_ctx_t *ctx, |
674 |
int h, int rw, int type) |
|
684 |
int h, int rw, int type, |
|
685 |
int target_page_bits) |
|
675 | 686 |
{ |
676 | 687 |
#if defined(TARGET_PPC64) |
677 | 688 |
if (env->mmu_model & POWERPC_MMU_64) |
678 |
return find_pte64(ctx, h, rw, type); |
|
689 |
return find_pte64(ctx, h, rw, type, target_page_bits);
|
|
679 | 690 |
#endif |
680 | 691 |
|
681 |
return find_pte32(ctx, h, rw, type); |
|
692 |
return find_pte32(ctx, h, rw, type, target_page_bits);
|
|
682 | 693 |
} |
683 | 694 |
|
684 | 695 |
#if defined(TARGET_PPC64) |
... | ... | |
694 | 705 |
|
695 | 706 |
static always_inline int slb_lookup (CPUPPCState *env, target_ulong eaddr, |
696 | 707 |
target_ulong *vsid, |
697 |
target_ulong *page_mask, int *attr) |
|
708 |
target_ulong *page_mask, int *attr, |
|
709 |
int *target_page_bits) |
|
698 | 710 |
{ |
699 | 711 |
target_phys_addr_t sr_base; |
700 | 712 |
target_ulong mask; |
... | ... | |
714 | 726 |
PRIx32 "\n", __func__, n, sr_base, tmp64, tmp); |
715 | 727 |
if (slb_is_valid(tmp64)) { |
716 | 728 |
/* SLB entry is valid */ |
717 |
switch (tmp64 & 0x0000000006000000ULL) { |
|
718 |
case 0x0000000000000000ULL: |
|
719 |
/* 256 MB segment */ |
|
720 |
mask = 0xFFFFFFFFF0000000ULL; |
|
721 |
break; |
|
722 |
case 0x0000000002000000ULL: |
|
723 |
/* 1 TB segment */ |
|
729 |
if (tmp & 0x8) { |
|
730 |
/* 1 TB Segment */ |
|
724 | 731 |
mask = 0xFFFF000000000000ULL; |
725 |
break; |
|
726 |
case 0x0000000004000000ULL: |
|
727 |
case 0x0000000006000000ULL: |
|
728 |
/* Reserved => segment is invalid */ |
|
729 |
continue; |
|
732 |
if (target_page_bits) |
|
733 |
*target_page_bits = 24; // XXX 16M pages? |
|
734 |
} else { |
|
735 |
/* 256MB Segment */ |
|
736 |
mask = 0xFFFFFFFFF0000000ULL; |
|
737 |
if (target_page_bits) |
|
738 |
*target_page_bits = TARGET_PAGE_BITS; |
|
730 | 739 |
} |
731 | 740 |
if ((eaddr & mask) == (tmp64 & mask)) { |
732 | 741 |
/* SLB match */ |
... | ... | |
777 | 786 |
int attr; |
778 | 787 |
int n; |
779 | 788 |
|
780 |
n = slb_lookup(env, T0, &vsid, &page_mask, &attr); |
|
789 |
n = slb_lookup(env, T0, &vsid, &page_mask, &attr, NULL);
|
|
781 | 790 |
if (n >= 0) { |
782 | 791 |
sr_base = env->spr[SPR_ASR]; |
783 | 792 |
sr_base += 12 * n; |
... | ... | |
871 | 880 |
#if defined(TARGET_PPC64) |
872 | 881 |
int attr; |
873 | 882 |
#endif |
874 |
int ds, vsid_sh, sdr_sh, pr; |
|
883 |
int ds, vsid_sh, sdr_sh, pr, target_page_bits;
|
|
875 | 884 |
int ret, ret2; |
876 | 885 |
|
877 | 886 |
pr = msr_pr; |
878 | 887 |
#if defined(TARGET_PPC64) |
879 | 888 |
if (env->mmu_model & POWERPC_MMU_64) { |
880 | 889 |
LOG_MMU("Check SLBs\n"); |
881 |
ret = slb_lookup(env, eaddr, &vsid, &page_mask, &attr); |
|
890 |
ret = slb_lookup(env, eaddr, &vsid, &page_mask, &attr, |
|
891 |
&target_page_bits); |
|
882 | 892 |
if (ret < 0) |
883 | 893 |
return ret; |
884 | 894 |
ctx->key = ((attr & 0x40) && (pr != 0)) || |
885 | 895 |
((attr & 0x80) && (pr == 0)) ? 1 : 0; |
886 | 896 |
ds = 0; |
887 |
ctx->nx = attr & 0x20 ? 1 : 0; |
|
897 |
ctx->nx = attr & 0x10 ? 1 : 0; |
|
898 |
ctx->eaddr = eaddr; |
|
888 | 899 |
vsid_mask = 0x00003FFFFFFFFF80ULL; |
889 | 900 |
vsid_sh = 7; |
890 | 901 |
sdr_sh = 18; |
... | ... | |
903 | 914 |
vsid_sh = 6; |
904 | 915 |
sdr_sh = 16; |
905 | 916 |
sdr_mask = 0xFFC0; |
917 |
target_page_bits = TARGET_PAGE_BITS; |
|
906 | 918 |
LOG_MMU("Check segment v=" ADDRX " %d " ADDRX |
907 | 919 |
" nip=" ADDRX " lr=" ADDRX " ir=%d dr=%d pr=%d %d t=%d\n", |
908 | 920 |
eaddr, (int)(eaddr >> 28), sr, env->nip, |
... | ... | |
918 | 930 |
/* Page address translation */ |
919 | 931 |
/* Primary table address */ |
920 | 932 |
sdr = env->sdr1; |
921 |
pgidx = (eaddr & page_mask) >> TARGET_PAGE_BITS;
|
|
933 |
pgidx = (eaddr & page_mask) >> target_page_bits;
|
|
922 | 934 |
#if defined(TARGET_PPC64) |
923 | 935 |
if (env->mmu_model & POWERPC_MMU_64) { |
924 | 936 |
htab_mask = 0x0FFFFFFF >> (28 - (sdr & 0x1F)); |
... | ... | |
944 | 956 |
#if defined(TARGET_PPC64) |
945 | 957 |
if (env->mmu_model & POWERPC_MMU_64) { |
946 | 958 |
/* Only 5 bits of the page index are used in the AVPN */ |
947 |
ctx->ptem = (vsid << 12) | ((pgidx >> 4) & 0x0F80); |
|
959 |
if (target_page_bits > 23) { |
|
960 |
ctx->ptem = (vsid << 12) | |
|
961 |
((pgidx << (target_page_bits - 16)) & 0xF80); |
|
962 |
} else { |
|
963 |
ctx->ptem = (vsid << 12) | ((pgidx >> 4) & 0x0F80); |
|
964 |
} |
|
948 | 965 |
} else |
949 | 966 |
#endif |
950 | 967 |
{ |
... | ... | |
962 | 979 |
" pg_addr=" PADDRX "\n", |
963 | 980 |
sdr, vsid, pgidx, hash, ctx->pg_addr[0]); |
964 | 981 |
/* Primary table lookup */ |
965 |
ret = find_pte(env, ctx, 0, rw, type); |
|
982 |
ret = find_pte(env, ctx, 0, rw, type, target_page_bits);
|
|
966 | 983 |
if (ret < 0) { |
967 | 984 |
/* Secondary table lookup */ |
968 | 985 |
if (eaddr != 0xEFFFFFFF) |
... | ... | |
970 | 987 |
"api=" ADDRX " hash=" PADDRX |
971 | 988 |
" pg_addr=" PADDRX "\n", |
972 | 989 |
sdr, vsid, pgidx, hash, ctx->pg_addr[1]); |
973 |
ret2 = find_pte(env, ctx, 1, rw, type); |
|
990 |
ret2 = find_pte(env, ctx, 1, rw, type, |
|
991 |
target_page_bits); |
|
974 | 992 |
if (ret2 != -1) |
975 | 993 |
ret = ret2; |
976 | 994 |
} |
Also available in: Unified diff