Revision fda6a0ec target-ppc/helper.c
b/target-ppc/helper.c | ||
---|---|---|
567 | 567 |
return ret; |
568 | 568 |
} |
569 | 569 |
|
570 |
static inline target_phys_addr_t get_pteg_offset(CPUState *env, |
|
571 |
target_phys_addr_t hash, |
|
572 |
int pte_size) |
|
573 |
{ |
|
574 |
return (hash * pte_size * 8) & env->htab_mask; |
|
575 |
} |
|
576 |
|
|
570 | 577 |
/* PTE table lookup */ |
571 |
static inline int _find_pte(mmu_ctx_t *ctx, int is_64b, int h, int rw,
|
|
572 |
int type, int target_page_bits) |
|
578 |
static inline int _find_pte(CPUState *env, mmu_ctx_t *ctx, int is_64b, int h,
|
|
579 |
int rw, int type, int target_page_bits)
|
|
573 | 580 |
{ |
574 |
target_ulong base, pte0, pte1; |
|
581 |
target_phys_addr_t pteg_off; |
|
582 |
target_ulong pte0, pte1; |
|
575 | 583 |
int i, good = -1; |
576 | 584 |
int ret, r; |
577 | 585 |
|
578 | 586 |
ret = -1; /* No entry found */ |
579 |
base = ctx->pg_addr[h]; |
|
587 |
pteg_off = get_pteg_offset(env, ctx->hash[h], |
|
588 |
is_64b ? HASH_PTE_SIZE_64 : HASH_PTE_SIZE_32); |
|
580 | 589 |
for (i = 0; i < 8; i++) { |
581 | 590 |
#if defined(TARGET_PPC64) |
582 | 591 |
if (is_64b) { |
583 |
pte0 = ldq_phys(base + (i * 16));
|
|
584 |
pte1 = ldq_phys(base + (i * 16) + 8);
|
|
592 |
pte0 = ldq_phys(env->htab_base + pteg_off + (i * 16));
|
|
593 |
pte1 = ldq_phys(env->htab_base + pteg_off + (i * 16) + 8);
|
|
585 | 594 |
|
586 | 595 |
/* We have a TLB that saves 4K pages, so let's |
587 | 596 |
* split a huge page to 4k chunks */ |
... | ... | |
592 | 601 |
r = pte64_check(ctx, pte0, pte1, h, rw, type); |
593 | 602 |
LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " " |
594 | 603 |
TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n", |
595 |
base + (i * 16), pte0, pte1, (int)(pte0 & 1), h, |
|
604 |
pteg_base + (i * 16), pte0, pte1, (int)(pte0 & 1), h,
|
|
596 | 605 |
(int)((pte0 >> 1) & 1), ctx->ptem); |
597 | 606 |
} else |
598 | 607 |
#endif |
599 | 608 |
{ |
600 |
pte0 = ldl_phys(base + (i * 8));
|
|
601 |
pte1 = ldl_phys(base + (i * 8) + 4);
|
|
609 |
pte0 = ldl_phys(env->htab_base + pteg_off + (i * 8));
|
|
610 |
pte1 = ldl_phys(env->htab_base + pteg_off + (i * 8) + 4);
|
|
602 | 611 |
r = pte32_check(ctx, pte0, pte1, h, rw, type); |
603 | 612 |
LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " " |
604 | 613 |
TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n", |
605 |
base + (i * 8), pte0, pte1, (int)(pte0 >> 31), h, |
|
614 |
pteg_base + (i * 8), pte0, pte1, (int)(pte0 >> 31), h,
|
|
606 | 615 |
(int)((pte0 >> 6) & 1), ctx->ptem); |
607 | 616 |
} |
608 | 617 |
switch (r) { |
... | ... | |
638 | 647 |
if (pte_update_flags(ctx, &pte1, ret, rw) == 1) { |
639 | 648 |
#if defined(TARGET_PPC64) |
640 | 649 |
if (is_64b) { |
641 |
stq_phys_notdirty(base + (good * 16) + 8, pte1); |
|
650 |
stq_phys_notdirty(env->htab_base + pteg_off + (good * 16) + 8, |
|
651 |
pte1); |
|
642 | 652 |
} else |
643 | 653 |
#endif |
644 | 654 |
{ |
645 |
stl_phys_notdirty(base + (good * 8) + 4, pte1); |
|
655 |
stl_phys_notdirty(env->htab_base + pteg_off + (good * 8) + 4, |
|
656 |
pte1); |
|
646 | 657 |
} |
647 | 658 |
} |
648 | 659 |
} |
... | ... | |
650 | 661 |
return ret; |
651 | 662 |
} |
652 | 663 |
|
653 |
static inline int find_pte32(mmu_ctx_t *ctx, int h, int rw, int type,
|
|
654 |
int target_page_bits) |
|
664 |
static inline int find_pte32(CPUState *env, mmu_ctx_t *ctx, int h, int rw,
|
|
665 |
int type, int target_page_bits)
|
|
655 | 666 |
{ |
656 |
return _find_pte(ctx, 0, h, rw, type, target_page_bits); |
|
667 |
return _find_pte(env, ctx, 0, h, rw, type, target_page_bits);
|
|
657 | 668 |
} |
658 | 669 |
|
659 | 670 |
#if defined(TARGET_PPC64) |
660 |
static inline int find_pte64(mmu_ctx_t *ctx, int h, int rw, int type,
|
|
661 |
int target_page_bits) |
|
671 |
static inline int find_pte64(CPUState *env, mmu_ctx_t *ctx, int h, int rw,
|
|
672 |
int type, int target_page_bits)
|
|
662 | 673 |
{ |
663 |
return _find_pte(ctx, 1, h, rw, type, target_page_bits); |
|
674 |
return _find_pte(env, ctx, 1, h, rw, type, target_page_bits);
|
|
664 | 675 |
} |
665 | 676 |
#endif |
666 | 677 |
|
... | ... | |
669 | 680 |
{ |
670 | 681 |
#if defined(TARGET_PPC64) |
671 | 682 |
if (env->mmu_model & POWERPC_MMU_64) |
672 |
return find_pte64(ctx, h, rw, type, target_page_bits); |
|
683 |
return find_pte64(env, ctx, h, rw, type, target_page_bits);
|
|
673 | 684 |
#endif |
674 | 685 |
|
675 |
return find_pte32(ctx, h, rw, type, target_page_bits); |
|
686 |
return find_pte32(env, ctx, h, rw, type, target_page_bits);
|
|
676 | 687 |
} |
677 | 688 |
|
678 | 689 |
#if defined(TARGET_PPC64) |
... | ... | |
788 | 799 |
#endif /* defined(TARGET_PPC64) */ |
789 | 800 |
|
790 | 801 |
/* Perform segment based translation */ |
791 |
static inline target_phys_addr_t get_pgaddr(target_phys_addr_t htab_base, |
|
792 |
target_phys_addr_t htab_mask, |
|
793 |
target_phys_addr_t hash) |
|
794 |
{ |
|
795 |
return htab_base | (hash & htab_mask); |
|
796 |
} |
|
797 |
|
|
798 | 802 |
static inline int get_segment(CPUState *env, mmu_ctx_t *ctx, |
799 | 803 |
target_ulong eaddr, int rw, int type) |
800 | 804 |
{ |
801 | 805 |
target_phys_addr_t hash; |
802 |
target_ulong sr, vsid, vsid_mask, pgidx, page_mask;
|
|
803 |
int ds, vsid_sh, pr, target_page_bits;
|
|
806 |
target_ulong sr, vsid, pgidx, page_mask; |
|
807 |
int ds, pr, target_page_bits; |
|
804 | 808 |
int ret, ret2; |
805 | 809 |
|
806 | 810 |
pr = msr_pr; |
... | ... | |
823 | 827 |
ds = 0; |
824 | 828 |
ctx->nx = !!(slb->vsid & SLB_VSID_N); |
825 | 829 |
ctx->eaddr = eaddr; |
826 |
vsid_mask = 0x00003FFFFFFFFF80ULL; |
|
827 |
vsid_sh = 7; |
|
828 | 830 |
} else |
829 | 831 |
#endif /* defined(TARGET_PPC64) */ |
830 | 832 |
{ |
... | ... | |
835 | 837 |
ds = sr & 0x80000000 ? 1 : 0; |
836 | 838 |
ctx->nx = sr & 0x10000000 ? 1 : 0; |
837 | 839 |
vsid = sr & 0x00FFFFFF; |
838 |
vsid_mask = 0x01FFFFC0; |
|
839 |
vsid_sh = 6; |
|
840 | 840 |
target_page_bits = TARGET_PAGE_BITS; |
841 | 841 |
LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip=" |
842 | 842 |
TARGET_FMT_lx " lr=" TARGET_FMT_lx |
... | ... | |
851 | 851 |
/* Check if instruction fetch is allowed, if needed */ |
852 | 852 |
if (type != ACCESS_CODE || ctx->nx == 0) { |
853 | 853 |
/* Page address translation */ |
854 |
/* Primary table address */ |
|
855 | 854 |
pgidx = (eaddr & page_mask) >> target_page_bits; |
856 | 855 |
#if defined(TARGET_PPC64) |
857 | 856 |
if (env->mmu_model & POWERPC_MMU_64) { |
858 | 857 |
/* XXX: this is false for 1 TB segments */ |
859 |
hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask;
|
|
858 |
hash = vsid ^ pgidx;
|
|
860 | 859 |
} else |
861 | 860 |
#endif |
862 | 861 |
{ |
863 |
hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask;
|
|
862 |
hash = vsid ^ pgidx;
|
|
864 | 863 |
} |
865 | 864 |
LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx |
866 | 865 |
" hash " TARGET_FMT_plx "\n", |
867 | 866 |
env->htab_base, env->htab_mask, hash); |
868 |
ctx->pg_addr[0] = get_pgaddr(env->htab_base, env->htab_mask, hash); |
|
869 |
/* Secondary table address */ |
|
870 |
hash = (~hash) & vsid_mask; |
|
871 |
LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx |
|
872 |
" hash " TARGET_FMT_plx "\n", |
|
873 |
env->htab_base, env->htab_mask, hash); |
|
874 |
ctx->pg_addr[1] = get_pgaddr(env->htab_base, env->htab_mask, hash); |
|
867 |
ctx->hash[0] = hash; |
|
868 |
ctx->hash[1] = ~hash; |
|
869 |
|
|
875 | 870 |
#if defined(TARGET_PPC64) |
876 | 871 |
if (env->mmu_model & POWERPC_MMU_64) { |
877 | 872 |
/* Only 5 bits of the page index are used in the AVPN */ |
... | ... | |
895 | 890 |
} else { |
896 | 891 |
LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx |
897 | 892 |
" vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx |
898 |
" hash=" TARGET_FMT_plx " pg_addr=" TARGET_FMT_plx "\n",
|
|
899 |
env->htab_base, env->htab_mask, vsid, pgidx, hash,
|
|
900 |
ctx->pg_addr[0]);
|
|
893 |
" hash=" TARGET_FMT_plx "\n", |
|
894 |
env->htab_base, env->htab_mask, vsid, pgidx, |
|
895 |
ctx->hash[0]);
|
|
901 | 896 |
/* Primary table lookup */ |
902 | 897 |
ret = find_pte(env, ctx, 0, rw, type, target_page_bits); |
903 | 898 |
if (ret < 0) { |
... | ... | |
908 | 903 |
" hash=" TARGET_FMT_plx " pg_addr=" |
909 | 904 |
TARGET_FMT_plx "\n", env->htab_base, |
910 | 905 |
env->htab_mask, vsid, pgidx, hash, |
911 |
ctx->pg_addr[1]);
|
|
906 |
ctx->hash[1]);
|
|
912 | 907 |
ret2 = find_pte(env, ctx, 1, rw, type, |
913 | 908 |
target_page_bits); |
914 | 909 |
if (ret2 != -1) |
... | ... | |
1460 | 1455 |
env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem; |
1461 | 1456 |
tlb_miss: |
1462 | 1457 |
env->error_code |= ctx.key << 19; |
1463 |
env->spr[SPR_HASH1] = ctx.pg_addr[0]; |
|
1464 |
env->spr[SPR_HASH2] = ctx.pg_addr[1]; |
|
1458 |
env->spr[SPR_HASH1] = env->htab_base + |
|
1459 |
get_pteg_offset(env, ctx.hash[0], HASH_PTE_SIZE_32); |
|
1460 |
env->spr[SPR_HASH2] = env->htab_base + |
|
1461 |
get_pteg_offset(env, ctx.hash[1], HASH_PTE_SIZE_32); |
|
1465 | 1462 |
break; |
1466 | 1463 |
case POWERPC_MMU_SOFT_74xx: |
1467 | 1464 |
if (rw == 1) { |
Also available in: Unified diff