Commit 8eee0af947cafdce5668abb6b7545f3887624ba8

Authored by blueswir1
1 parent e47ce3f2

Keep SLB in-CPU

Real 970 CPUs have the SLB not memory backed, but inside the CPU.
This breaks bridge mode for 970 for now, but at least keeps us from
overwriting physical addresses 0x0 - 0x300, rendering our interrupt
handlers useless.

I put in a stub for bridge mode operation that could be enabled
easily, but for now it's safer to leave that off I guess (970fx doesn't
have bridge mode AFAIK).

Signed-off-by: Alexander Graf <alex@csgraf.de>


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6757 c046a42c-6fe2-441c-8c8c-71466251a162
target-ppc/cpu.h
@@ -344,6 +344,12 @@ union ppc_tlb_t { @@ -344,6 +344,12 @@ union ppc_tlb_t {
344 ppcemb_tlb_t tlbe; 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 /* Machine state register bits definition */ 354 /* Machine state register bits definition */
349 #define MSR_SF 63 /* Sixty-four-bit mode hflags */ 355 #define MSR_SF 63 /* Sixty-four-bit mode hflags */
@@ -584,6 +590,7 @@ struct CPUPPCState { @@ -584,6 +590,7 @@ struct CPUPPCState {
584 /* Address space register */ 590 /* Address space register */
585 target_ulong asr; 591 target_ulong asr;
586 /* PowerPC 64 SLB area */ 592 /* PowerPC 64 SLB area */
  593 + ppc_slb_t slb[64];
587 int slb_nr; 594 int slb_nr;
588 #endif 595 #endif
589 /* segment registers */ 596 /* segment registers */
target-ppc/helper.c
@@ -693,14 +693,44 @@ static always_inline int find_pte (CPUState *env, mmu_ctx_t *ctx, @@ -693,14 +693,44 @@ static always_inline int find_pte (CPUState *env, mmu_ctx_t *ctx,
693 } 693 }
694 694
695 #if defined(TARGET_PPC64) 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 static always_inline int slb_lookup (CPUPPCState *env, target_ulong eaddr, 736 static always_inline int slb_lookup (CPUPPCState *env, target_ulong eaddr,
@@ -708,25 +738,20 @@ static always_inline int slb_lookup (CPUPPCState *env, target_ulong eaddr, @@ -708,25 +738,20 @@ static always_inline int slb_lookup (CPUPPCState *env, target_ulong eaddr,
708 target_ulong *page_mask, int *attr, 738 target_ulong *page_mask, int *attr,
709 int *target_page_bits) 739 int *target_page_bits)
710 { 740 {
711 - target_phys_addr_t sr_base;  
712 target_ulong mask; 741 target_ulong mask;
713 - uint64_t tmp64;  
714 - uint32_t tmp;  
715 int n, ret; 742 int n, ret;
716 743
717 ret = -5; 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 mask = 0x0000000000000000ULL; /* Avoid gcc warning */ 746 mask = 0x0000000000000000ULL; /* Avoid gcc warning */
722 for (n = 0; n < env->slb_nr; n++) { 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 /* SLB entry is valid */ 753 /* SLB entry is valid */
729 - if (tmp & 0x8) { 754 + if (slb->tmp & 0x8) {
730 /* 1 TB Segment */ 755 /* 1 TB Segment */
731 mask = 0xFFFF000000000000ULL; 756 mask = 0xFFFF000000000000ULL;
732 if (target_page_bits) 757 if (target_page_bits)
@@ -737,16 +762,15 @@ static always_inline int slb_lookup (CPUPPCState *env, target_ulong eaddr, @@ -737,16 +762,15 @@ static always_inline int slb_lookup (CPUPPCState *env, target_ulong eaddr,
737 if (target_page_bits) 762 if (target_page_bits)
738 *target_page_bits = TARGET_PAGE_BITS; 763 *target_page_bits = TARGET_PAGE_BITS;
739 } 764 }
740 - if ((eaddr & mask) == (tmp64 & mask)) { 765 + if ((eaddr & mask) == (slb->tmp64 & mask)) {
741 /* SLB match */ 766 /* SLB match */
742 - *vsid = ((tmp64 << 24) | (tmp >> 8)) & 0x0003FFFFFFFFFFFFULL; 767 + *vsid = ((slb->tmp64 << 24) | (slb->tmp >> 8)) & 0x0003FFFFFFFFFFFFULL;
743 *page_mask = ~mask; 768 *page_mask = ~mask;
744 - *attr = tmp & 0xFF; 769 + *attr = slb->tmp & 0xFF;
745 ret = n; 770 ret = n;
746 break; 771 break;
747 } 772 }
748 } 773 }
749 - sr_base += 12;  
750 } 774 }
751 775
752 return ret; 776 return ret;
@@ -754,25 +778,22 @@ static always_inline int slb_lookup (CPUPPCState *env, target_ulong eaddr, @@ -754,25 +778,22 @@ static always_inline int slb_lookup (CPUPPCState *env, target_ulong eaddr,
754 778
755 void ppc_slb_invalidate_all (CPUPPCState *env) 779 void ppc_slb_invalidate_all (CPUPPCState *env)
756 { 780 {
757 - target_phys_addr_t sr_base;  
758 - uint64_t tmp64;  
759 int n, do_invalidate; 781 int n, do_invalidate;
760 782
761 do_invalidate = 0; 783 do_invalidate = 0;
762 - sr_base = env->spr[SPR_ASR];  
763 /* XXX: Warning: slbia never invalidates the first segment */ 784 /* XXX: Warning: slbia never invalidates the first segment */
764 for (n = 1; n < env->slb_nr; n++) { 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 /* XXX: given the fact that segment size is 256 MB or 1TB, 791 /* XXX: given the fact that segment size is 256 MB or 1TB,
770 * and we still don't have a tlb_flush_mask(env, n, mask) 792 * and we still don't have a tlb_flush_mask(env, n, mask)
771 * in Qemu, we just invalidate all TLBs 793 * in Qemu, we just invalidate all TLBs
772 */ 794 */
773 do_invalidate = 1; 795 do_invalidate = 1;
774 } 796 }
775 - sr_base += 12;  
776 } 797 }
777 if (do_invalidate) 798 if (do_invalidate)
778 tlb_flush(env, 1); 799 tlb_flush(env, 1);
@@ -780,20 +801,17 @@ void ppc_slb_invalidate_all (CPUPPCState *env) @@ -780,20 +801,17 @@ void ppc_slb_invalidate_all (CPUPPCState *env)
780 801
781 void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0) 802 void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0)
782 { 803 {
783 - target_phys_addr_t sr_base;  
784 target_ulong vsid, page_mask; 804 target_ulong vsid, page_mask;
785 - uint64_t tmp64;  
786 int attr; 805 int attr;
787 int n; 806 int n;
788 807
789 n = slb_lookup(env, T0, &vsid, &page_mask, &attr, NULL); 808 n = slb_lookup(env, T0, &vsid, &page_mask, &attr, NULL);
790 if (n >= 0) { 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 /* XXX: given the fact that segment size is 256 MB or 1TB, 815 /* XXX: given the fact that segment size is 256 MB or 1TB,
798 * and we still don't have a tlb_flush_mask(env, n, mask) 816 * and we still don't have a tlb_flush_mask(env, n, mask)
799 * in Qemu, we just invalidate all TLBs 817 * in Qemu, we just invalidate all TLBs
@@ -805,36 +823,28 @@ void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0) @@ -805,36 +823,28 @@ void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0)
805 823
806 target_ulong ppc_load_slb (CPUPPCState *env, int slb_nr) 824 target_ulong ppc_load_slb (CPUPPCState *env, int slb_nr)
807 { 825 {
808 - target_phys_addr_t sr_base;  
809 target_ulong rt; 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 /* SLB entry is valid */ 830 /* SLB entry is valid */
819 /* Copy SLB bits 62:88 to Rt 37:63 (VSID 23:49) */ 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 /* Copy SLB bits 89:92 to Rt 33:36 (KsKpNL) */ 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 } else { 836 } else {
825 rt = 0; 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 return rt; 842 return rt;
831 } 843 }
832 844
833 void ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs) 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 uint64_t vsid; 849 uint64_t vsid;
840 uint64_t esid; 850 uint64_t esid;
@@ -847,19 +857,15 @@ void ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs) @@ -847,19 +857,15 @@ void ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs)
847 valid = (rb & (1 << 27)); 857 valid = (rb & (1 << 27));
848 slb_nr = rb & 0xfff; 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 " %08" PRIx32 "\n", __func__, 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 #endif /* defined(TARGET_PPC64) */ 870 #endif /* defined(TARGET_PPC64) */
865 871
target-ppc/translate_init.c
@@ -6056,7 +6056,7 @@ static void init_proc_970FX (CPUPPCState *env) @@ -6056,7 +6056,7 @@ static void init_proc_970FX (CPUPPCState *env)
6056 &spr_read_generic, &spr_write_generic, 6056 &spr_read_generic, &spr_write_generic,
6057 0x00000000); 6057 0x00000000);
6058 #if !defined(CONFIG_USER_ONLY) 6058 #if !defined(CONFIG_USER_ONLY)
6059 - env->slb_nr = 32; 6059 + env->slb_nr = 64;
6060 #endif 6060 #endif
6061 init_excp_970(env); 6061 init_excp_970(env);
6062 env->dcache_line_size = 128; 6062 env->dcache_line_size = 128;