Revision 81762d6d target-ppc/helper.c
b/target-ppc/helper.c | ||
---|---|---|
672 | 672 |
} |
673 | 673 |
|
674 | 674 |
#if defined(TARGET_PPC64) |
675 |
static ppc_slb_t *slb_get_entry(CPUPPCState *env, int nr) |
|
676 |
{ |
|
677 |
ppc_slb_t *retval = &env->slb[nr]; |
|
678 |
|
|
679 |
#if 0 // XXX implement bridge mode? |
|
680 |
if (env->spr[SPR_ASR] & 1) { |
|
681 |
target_phys_addr_t sr_base; |
|
682 |
|
|
683 |
sr_base = env->spr[SPR_ASR] & 0xfffffffffffff000; |
|
684 |
sr_base += (12 * nr); |
|
685 |
|
|
686 |
retval->tmp64 = ldq_phys(sr_base); |
|
687 |
retval->tmp = ldl_phys(sr_base + 8); |
|
688 |
} |
|
689 |
#endif |
|
690 |
|
|
691 |
return retval; |
|
692 |
} |
|
693 |
|
|
694 |
static void slb_set_entry(CPUPPCState *env, int nr, ppc_slb_t *slb) |
|
695 |
{ |
|
696 |
ppc_slb_t *entry = &env->slb[nr]; |
|
697 |
|
|
698 |
if (slb == entry) |
|
699 |
return; |
|
700 |
|
|
701 |
entry->tmp64 = slb->tmp64; |
|
702 |
entry->tmp = slb->tmp; |
|
703 |
} |
|
704 |
|
|
705 |
static inline int slb_is_valid(ppc_slb_t *slb) |
|
706 |
{ |
|
707 |
return (int)(slb->tmp64 & 0x0000000008000000ULL); |
|
708 |
} |
|
709 |
|
|
710 |
static inline void slb_invalidate(ppc_slb_t *slb) |
|
711 |
{ |
|
712 |
slb->tmp64 &= ~0x0000000008000000ULL; |
|
713 |
} |
|
714 |
|
|
715 | 675 |
static inline int slb_lookup(CPUPPCState *env, target_ulong eaddr, |
716 | 676 |
target_ulong *vsid, target_ulong *page_mask, |
717 | 677 |
int *attr, int *target_page_bits) |
718 | 678 |
{ |
719 |
target_ulong mask;
|
|
720 |
int n, ret;
|
|
679 |
uint64_t esid;
|
|
680 |
int n; |
|
721 | 681 |
|
722 |
ret = -5; |
|
723 | 682 |
LOG_SLB("%s: eaddr " TARGET_FMT_lx "\n", __func__, eaddr); |
724 |
mask = 0x0000000000000000ULL; /* Avoid gcc warning */ |
|
683 |
|
|
684 |
esid = (eaddr & SEGMENT_MASK_256M) | SLB_ESID_V; |
|
685 |
|
|
725 | 686 |
for (n = 0; n < env->slb_nr; n++) { |
726 |
ppc_slb_t *slb = slb_get_entry(env, n); |
|
727 |
|
|
728 |
LOG_SLB("%s: seg %d %016" PRIx64 " %08" |
|
729 |
PRIx32 "\n", __func__, n, slb->tmp64, slb->tmp); |
|
730 |
if (slb_is_valid(slb)) { |
|
731 |
/* SLB entry is valid */ |
|
732 |
mask = 0xFFFFFFFFF0000000ULL; |
|
733 |
if (slb->tmp & 0x8) { |
|
734 |
/* 16 MB PTEs */ |
|
735 |
if (target_page_bits) |
|
736 |
*target_page_bits = 24; |
|
737 |
} else { |
|
738 |
/* 4 KB PTEs */ |
|
739 |
if (target_page_bits) |
|
740 |
*target_page_bits = TARGET_PAGE_BITS; |
|
741 |
} |
|
742 |
if ((eaddr & mask) == (slb->tmp64 & mask)) { |
|
743 |
/* SLB match */ |
|
744 |
*vsid = ((slb->tmp64 << 24) | (slb->tmp >> 8)) & 0x0003FFFFFFFFFFFFULL; |
|
745 |
*page_mask = ~mask; |
|
746 |
*attr = slb->tmp & 0xFF; |
|
747 |
ret = n; |
|
748 |
break; |
|
687 |
ppc_slb_t *slb = &env->slb[n]; |
|
688 |
|
|
689 |
LOG_SLB("%s: slot %d %016" PRIx64 " %016" |
|
690 |
PRIx64 "\n", __func__, n, slb->esid, slb->vsid); |
|
691 |
if (slb->esid == esid) { |
|
692 |
*vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT; |
|
693 |
*page_mask = ~SEGMENT_MASK_256M; |
|
694 |
*attr = slb->vsid & SLB_VSID_ATTR; |
|
695 |
if (target_page_bits) { |
|
696 |
*target_page_bits = (slb->vsid & SLB_VSID_L) |
|
697 |
? TARGET_PAGE_BITS_16M |
|
698 |
: TARGET_PAGE_BITS; |
|
749 | 699 |
} |
700 |
return n; |
|
750 | 701 |
} |
751 | 702 |
} |
752 | 703 |
|
753 |
return ret;
|
|
704 |
return -5;
|
|
754 | 705 |
} |
755 | 706 |
|
756 | 707 |
void ppc_slb_invalidate_all (CPUPPCState *env) |
... | ... | |
760 | 711 |
do_invalidate = 0; |
761 | 712 |
/* XXX: Warning: slbia never invalidates the first segment */ |
762 | 713 |
for (n = 1; n < env->slb_nr; n++) { |
763 |
ppc_slb_t *slb = slb_get_entry(env, n);
|
|
714 |
ppc_slb_t *slb = &env->slb[n];
|
|
764 | 715 |
|
765 |
if (slb_is_valid(slb)) { |
|
766 |
slb_invalidate(slb); |
|
767 |
slb_set_entry(env, n, slb); |
|
716 |
if (slb->esid & SLB_ESID_V) { |
|
717 |
slb->esid &= ~SLB_ESID_V; |
|
768 | 718 |
/* XXX: given the fact that segment size is 256 MB or 1TB, |
769 | 719 |
* and we still don't have a tlb_flush_mask(env, n, mask) |
770 | 720 |
* in Qemu, we just invalidate all TLBs |
... | ... | |
781 | 731 |
target_ulong vsid, page_mask; |
782 | 732 |
int attr; |
783 | 733 |
int n; |
734 |
ppc_slb_t *slb; |
|
784 | 735 |
|
785 | 736 |
n = slb_lookup(env, T0, &vsid, &page_mask, &attr, NULL); |
786 |
if (n >= 0) { |
|
787 |
ppc_slb_t *slb = slb_get_entry(env, n); |
|
788 |
|
|
789 |
if (slb_is_valid(slb)) { |
|
790 |
slb_invalidate(slb); |
|
791 |
slb_set_entry(env, n, slb); |
|
792 |
/* XXX: given the fact that segment size is 256 MB or 1TB, |
|
793 |
* and we still don't have a tlb_flush_mask(env, n, mask) |
|
794 |
* in Qemu, we just invalidate all TLBs |
|
795 |
*/ |
|
796 |
tlb_flush(env, 1); |
|
797 |
} |
|
737 |
if (n < 0) { |
|
738 |
return; |
|
798 | 739 |
} |
799 |
} |
|
800 | 740 |
|
801 |
target_ulong ppc_load_slb (CPUPPCState *env, int slb_nr) |
|
802 |
{ |
|
803 |
target_ulong rt; |
|
804 |
ppc_slb_t *slb = slb_get_entry(env, slb_nr); |
|
741 |
slb = &env->slb[n]; |
|
805 | 742 |
|
806 |
if (slb_is_valid(slb)) { |
|
807 |
/* SLB entry is valid */ |
|
808 |
/* Copy SLB bits 62:88 to Rt 37:63 (VSID 23:49) */ |
|
809 |
rt = slb->tmp >> 8; /* 65:88 => 40:63 */ |
|
810 |
rt |= (slb->tmp64 & 0x7) << 24; /* 62:64 => 37:39 */ |
|
811 |
/* Copy SLB bits 89:92 to Rt 33:36 (KsKpNL) */ |
|
812 |
rt |= ((slb->tmp >> 4) & 0xF) << 27; |
|
813 |
} else { |
|
814 |
rt = 0; |
|
815 |
} |
|
816 |
LOG_SLB("%s: %016" PRIx64 " %08" PRIx32 " => %d " |
|
817 |
TARGET_FMT_lx "\n", __func__, slb->tmp64, slb->tmp, slb_nr, rt); |
|
743 |
if (slb->esid & SLB_ESID_V) { |
|
744 |
slb->esid &= ~SLB_ESID_V; |
|
818 | 745 |
|
819 |
return rt; |
|
746 |
/* XXX: given the fact that segment size is 256 MB or 1TB, |
|
747 |
* and we still don't have a tlb_flush_mask(env, n, mask) |
|
748 |
* in Qemu, we just invalidate all TLBs |
|
749 |
*/ |
|
750 |
tlb_flush(env, 1); |
|
751 |
} |
|
820 | 752 |
} |
821 | 753 |
|
822 |
void ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs)
|
|
754 |
int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs)
|
|
823 | 755 |
{ |
824 |
ppc_slb_t *slb; |
|
825 |
|
|
826 |
uint64_t vsid; |
|
827 |
uint64_t esid; |
|
828 |
int flags, valid, slb_nr; |
|
829 |
|
|
830 |
vsid = rs >> 12; |
|
831 |
flags = ((rs >> 8) & 0xf); |
|
756 |
int slot = rb & 0xfff; |
|
757 |
uint64_t esid = rb & ~0xfff; |
|
758 |
ppc_slb_t *slb = &env->slb[slot]; |
|
832 | 759 |
|
833 |
esid = rb >> 28;
|
|
834 |
valid = (rb & (1 << 27));
|
|
835 |
slb_nr = rb & 0xfff;
|
|
760 |
if (slot >= env->slb_nr) {
|
|
761 |
return -1;
|
|
762 |
}
|
|
836 | 763 |
|
837 |
slb = slb_get_entry(env, slb_nr); |
|
838 |
slb->tmp64 = (esid << 28) | valid | (vsid >> 24); |
|
839 |
slb->tmp = (vsid << 8) | (flags << 3); |
|
764 |
slb->esid = esid; |
|
765 |
slb->vsid = rs; |
|
840 | 766 |
|
841 | 767 |
LOG_SLB("%s: %d " TARGET_FMT_lx " - " TARGET_FMT_lx " => %016" PRIx64 |
842 |
" %08" PRIx32 "\n", __func__, slb_nr, rb, rs, slb->tmp64,
|
|
843 |
slb->tmp);
|
|
768 |
" %016" PRIx64 "\n", __func__, slot, rb, rs,
|
|
769 |
slb->esid, slb->vsid);
|
|
844 | 770 |
|
845 |
slb_set_entry(env, slb_nr, slb);
|
|
771 |
return 0;
|
|
846 | 772 |
} |
847 | 773 |
#endif /* defined(TARGET_PPC64) */ |
848 | 774 |
|
... | ... | |
860 | 786 |
{ |
861 | 787 |
target_phys_addr_t sdr, hash, mask, sdr_mask, htab_mask; |
862 | 788 |
target_ulong sr, vsid, vsid_mask, pgidx, page_mask; |
863 |
#if defined(TARGET_PPC64) |
|
864 |
int attr; |
|
865 |
#endif |
|
866 | 789 |
int ds, vsid_sh, sdr_sh, pr, target_page_bits; |
867 | 790 |
int ret, ret2; |
868 | 791 |
|
869 | 792 |
pr = msr_pr; |
870 | 793 |
#if defined(TARGET_PPC64) |
871 | 794 |
if (env->mmu_model & POWERPC_MMU_64) { |
795 |
int attr; |
|
796 |
|
|
872 | 797 |
LOG_MMU("Check SLBs\n"); |
873 | 798 |
ret = slb_lookup(env, eaddr, &vsid, &page_mask, &attr, |
874 | 799 |
&target_page_bits); |
875 | 800 |
if (ret < 0) |
876 | 801 |
return ret; |
877 |
ctx->key = ((attr & 0x40) && (pr != 0)) || |
|
878 |
((attr & 0x80) && (pr == 0)) ? 1 : 0; |
|
802 |
ctx->key = !!(pr ? (attr & SLB_VSID_KP) : (attr & SLB_VSID_KS)); |
|
879 | 803 |
ds = 0; |
880 |
ctx->nx = attr & 0x10 ? 1 : 0;
|
|
804 |
ctx->nx = !!(attr & SLB_VSID_N);
|
|
881 | 805 |
ctx->eaddr = eaddr; |
882 | 806 |
vsid_mask = 0x00003FFFFFFFFF80ULL; |
883 | 807 |
vsid_sh = 7; |
Also available in: Unified diff