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