Revision 8eee0af9

b/target-ppc/cpu.h
344 344
    ppcemb_tlb_t tlbe;
345 345
};
346 346

  
347
typedef struct ppc_slb_t ppc_slb_t;
348
struct ppc_slb_t {
349
    uint64_t tmp64;
350
    uint32_t tmp;
351
};
352

  
347 353
/*****************************************************************************/
348 354
/* Machine state register bits definition                                    */
349 355
#define MSR_SF   63 /* Sixty-four-bit mode                            hflags */
......
584 590
    /* Address space register */
585 591
    target_ulong asr;
586 592
    /* PowerPC 64 SLB area */
593
    ppc_slb_t slb[64];
587 594
    int slb_nr;
588 595
#endif
589 596
    /* segment registers */
b/target-ppc/helper.c
693 693
}
694 694

  
695 695
#if defined(TARGET_PPC64)
696
static always_inline int slb_is_valid (uint64_t slb64)
696
static ppc_slb_t *slb_get_entry(CPUPPCState *env, int nr)
697 697
{
698
    return slb64 & 0x0000000008000000ULL ? 1 : 0;
698
    ppc_slb_t *retval = &env->slb[nr];
699

  
700
#if 0 // XXX implement bridge mode?
701
    if (env->spr[SPR_ASR] & 1) {
702
        target_phys_addr_t sr_base;
703

  
704
        sr_base = env->spr[SPR_ASR] & 0xfffffffffffff000;
705
        sr_base += (12 * nr);
706

  
707
        retval->tmp64 = ldq_phys(sr_base);
708
        retval->tmp = ldl_phys(sr_base + 8);
709
    }
710
#endif
711

  
712
    return retval;
713
}
714

  
715
static void slb_set_entry(CPUPPCState *env, int nr, ppc_slb_t *slb)
716
{
717
    ppc_slb_t *entry = &env->slb[nr];
718

  
719
    if (slb == entry)
720
        return;
721

  
722
    entry->tmp64 = slb->tmp64;
723
    entry->tmp = slb->tmp;
724
}
725

  
726
static always_inline int slb_is_valid (ppc_slb_t *slb)
727
{
728
    return (int)(slb->tmp64 & 0x0000000008000000ULL);
699 729
}
700 730

  
701
static always_inline void slb_invalidate (uint64_t *slb64)
731
static always_inline void slb_invalidate (ppc_slb_t *slb)
702 732
{
703
    *slb64 &= ~0x0000000008000000ULL;
733
    slb->tmp64 &= ~0x0000000008000000ULL;
704 734
}
705 735

  
706 736
static always_inline int slb_lookup (CPUPPCState *env, target_ulong eaddr,
......
708 738
                                     target_ulong *page_mask, int *attr,
709 739
                                     int *target_page_bits)
710 740
{
711
    target_phys_addr_t sr_base;
712 741
    target_ulong mask;
713
    uint64_t tmp64;
714
    uint32_t tmp;
715 742
    int n, ret;
716 743

  
717 744
    ret = -5;
718
    sr_base = env->spr[SPR_ASR];
719
    LOG_SLB("%s: eaddr " ADDRX " base " PADDRX "\n",
720
                __func__, eaddr, sr_base);
745
    LOG_SLB("%s: eaddr " ADDRX "\n", __func__, eaddr);
721 746
    mask = 0x0000000000000000ULL; /* Avoid gcc warning */
722 747
    for (n = 0; n < env->slb_nr; n++) {
723
        tmp64 = ldq_phys(sr_base);
724
        tmp = ldl_phys(sr_base + 8);
725
        LOG_SLB("%s: seg %d " PADDRX " %016" PRIx64 " %08"
726
                    PRIx32 "\n", __func__, n, sr_base, tmp64, tmp);
727
        if (slb_is_valid(tmp64)) {
748
        ppc_slb_t *slb = slb_get_entry(env, n);
749

  
750
        LOG_SLB("%s: seg %d %016" PRIx64 " %08"
751
                    PRIx32 "\n", __func__, n, slb->tmp64, slb->tmp);
752
        if (slb_is_valid(slb)) {
728 753
            /* SLB entry is valid */
729
            if (tmp & 0x8) {
754
            if (slb->tmp & 0x8) {
730 755
                /* 1 TB Segment */
731 756
                mask = 0xFFFF000000000000ULL;
732 757
                if (target_page_bits)
......
737 762
                if (target_page_bits)
738 763
                    *target_page_bits = TARGET_PAGE_BITS;
739 764
            }
740
            if ((eaddr & mask) == (tmp64 & mask)) {
765
            if ((eaddr & mask) == (slb->tmp64 & mask)) {
741 766
                /* SLB match */
742
                *vsid = ((tmp64 << 24) | (tmp >> 8)) & 0x0003FFFFFFFFFFFFULL;
767
                *vsid = ((slb->tmp64 << 24) | (slb->tmp >> 8)) & 0x0003FFFFFFFFFFFFULL;
743 768
                *page_mask = ~mask;
744
                *attr = tmp & 0xFF;
769
                *attr = slb->tmp & 0xFF;
745 770
                ret = n;
746 771
                break;
747 772
            }
748 773
        }
749
        sr_base += 12;
750 774
    }
751 775

  
752 776
    return ret;
......
754 778

  
755 779
void ppc_slb_invalidate_all (CPUPPCState *env)
756 780
{
757
    target_phys_addr_t sr_base;
758
    uint64_t tmp64;
759 781
    int n, do_invalidate;
760 782

  
761 783
    do_invalidate = 0;
762
    sr_base = env->spr[SPR_ASR];
763 784
    /* XXX: Warning: slbia never invalidates the first segment */
764 785
    for (n = 1; n < env->slb_nr; n++) {
765
        tmp64 = ldq_phys(sr_base);
766
        if (slb_is_valid(tmp64)) {
767
            slb_invalidate(&tmp64);
768
            stq_phys(sr_base, tmp64);
786
        ppc_slb_t *slb = slb_get_entry(env, n);
787

  
788
        if (slb_is_valid(slb)) {
789
            slb_invalidate(slb);
790
            slb_set_entry(env, n, slb);
769 791
            /* XXX: given the fact that segment size is 256 MB or 1TB,
770 792
             *      and we still don't have a tlb_flush_mask(env, n, mask)
771 793
             *      in Qemu, we just invalidate all TLBs
772 794
             */
773 795
            do_invalidate = 1;
774 796
        }
775
        sr_base += 12;
776 797
    }
777 798
    if (do_invalidate)
778 799
        tlb_flush(env, 1);
......
780 801

  
781 802
void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0)
782 803
{
783
    target_phys_addr_t sr_base;
784 804
    target_ulong vsid, page_mask;
785
    uint64_t tmp64;
786 805
    int attr;
787 806
    int n;
788 807

  
789 808
    n = slb_lookup(env, T0, &vsid, &page_mask, &attr, NULL);
790 809
    if (n >= 0) {
791
        sr_base = env->spr[SPR_ASR];
792
        sr_base += 12 * n;
793
        tmp64 = ldq_phys(sr_base);
794
        if (slb_is_valid(tmp64)) {
795
            slb_invalidate(&tmp64);
796
            stq_phys(sr_base, tmp64);
810
        ppc_slb_t *slb = slb_get_entry(env, n);
811

  
812
        if (slb_is_valid(slb)) {
813
            slb_invalidate(slb);
814
            slb_set_entry(env, n, slb);
797 815
            /* XXX: given the fact that segment size is 256 MB or 1TB,
798 816
             *      and we still don't have a tlb_flush_mask(env, n, mask)
799 817
             *      in Qemu, we just invalidate all TLBs
......
805 823

  
806 824
target_ulong ppc_load_slb (CPUPPCState *env, int slb_nr)
807 825
{
808
    target_phys_addr_t sr_base;
809 826
    target_ulong rt;
810
    uint64_t tmp64;
811
    uint32_t tmp;
812

  
813
    sr_base = env->spr[SPR_ASR];
814
    sr_base += 12 * slb_nr;
815
    tmp64 = ldq_phys(sr_base);
816
    tmp = ldl_phys(sr_base + 8);
817
    if (tmp64 & 0x0000000008000000ULL) {
827
    ppc_slb_t *slb = slb_get_entry(env, slb_nr);
828

  
829
    if (slb_is_valid(slb)) {
818 830
        /* SLB entry is valid */
819 831
        /* Copy SLB bits 62:88 to Rt 37:63 (VSID 23:49) */
820
        rt = tmp >> 8;             /* 65:88 => 40:63 */
821
        rt |= (tmp64 & 0x7) << 24; /* 62:64 => 37:39 */
832
        rt = slb->tmp >> 8;             /* 65:88 => 40:63 */
833
        rt |= (slb->tmp64 & 0x7) << 24; /* 62:64 => 37:39 */
822 834
        /* Copy SLB bits 89:92 to Rt 33:36 (KsKpNL) */
823
        rt |= ((tmp >> 4) & 0xF) << 27;
835
        rt |= ((slb->tmp >> 4) & 0xF) << 27;
824 836
    } else {
825 837
        rt = 0;
826 838
    }
827
    LOG_SLB("%s: " PADDRX " %016" PRIx64 " %08" PRIx32 " => %d "
828
                ADDRX "\n", __func__, sr_base, tmp64, tmp, slb_nr, rt);
839
    LOG_SLB("%s: %016" PRIx64 " %08" PRIx32 " => %d "
840
                ADDRX "\n", __func__, slb->tmp64, slb->tmp, slb_nr, rt);
829 841

  
830 842
    return rt;
831 843
}
832 844

  
833 845
void ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs)
834 846
{
835
    target_phys_addr_t sr_base;
836
    uint64_t tmp64;
837
    uint32_t tmp;
847
    ppc_slb_t *slb;
838 848

  
839 849
    uint64_t vsid;
840 850
    uint64_t esid;
......
847 857
    valid = (rb & (1 << 27));
848 858
    slb_nr = rb & 0xfff;
849 859

  
850
    tmp64 = (esid << 28) | valid | (vsid >> 24);
851
    tmp = (vsid << 8) | (flags << 3);
852

  
853
    /* Write SLB entry to memory */
854
    sr_base = env->spr[SPR_ASR];
855
    sr_base += 12 * slb_nr;
860
    slb = slb_get_entry(env, slb_nr);
861
    slb->tmp64 = (esid << 28) | valid | (vsid >> 24);
862
    slb->tmp = (vsid << 8) | (flags << 3);
856 863

  
857
    LOG_SLB("%s: %d " ADDRX " - " ADDRX " => " PADDRX " %016" PRIx64
864
    LOG_SLB("%s: %d " ADDRX " - " ADDRX " => %016" PRIx64
858 865
                " %08" PRIx32 "\n", __func__,
859
                slb_nr, rb, rs, sr_base, tmp64, tmp);
866
                slb_nr, rb, rs, tmp64, tmp);
860 867

  
861
    stq_phys(sr_base, tmp64);
862
    stl_phys(sr_base + 8, tmp);
868
    slb_set_entry(env, slb_nr, slb);
863 869
}
864 870
#endif /* defined(TARGET_PPC64) */
865 871

  
b/target-ppc/translate_init.c
6056 6056
                 &spr_read_generic, &spr_write_generic,
6057 6057
                 0x00000000);
6058 6058
#if !defined(CONFIG_USER_ONLY)
6059
    env->slb_nr = 32;
6059
    env->slb_nr = 64;
6060 6060
#endif
6061 6061
    init_excp_970(env);
6062 6062
    env->dcache_line_size = 128;

Also available in: Unified diff