Commit eacc324914c2dc7aecec3b4ea920252b685b5c8e

Authored by j_mayer
1 parent a01d8cad

Implement PowerPC 64 SLB invalidation helpers.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3391 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 63 additions and 19 deletions
target-ppc/helper.c
@@ -601,6 +601,16 @@ static always_inline int find_pte (CPUState *env, mmu_ctx_t *ctx, @@ -601,6 +601,16 @@ static always_inline int find_pte (CPUState *env, mmu_ctx_t *ctx,
601 } 601 }
602 602
603 #if defined(TARGET_PPC64) 603 #if defined(TARGET_PPC64)
  604 +static inline int slb_is_valid (uint64_t slb64)
  605 +{
  606 + return slb64 & 0x0000000008000000ULL ? 1 : 0;
  607 +}
  608 +
  609 +static inline void slb_invalidate (uint64_t *slb64)
  610 +{
  611 + *slb64 &= ~0x0000000008000000ULL;
  612 +}
  613 +
604 static int slb_lookup (CPUPPCState *env, target_ulong eaddr, 614 static int slb_lookup (CPUPPCState *env, target_ulong eaddr,
605 target_ulong *vsid, target_ulong *page_mask, int *attr) 615 target_ulong *vsid, target_ulong *page_mask, int *attr)
606 { 616 {
@@ -609,7 +619,6 @@ static int slb_lookup (CPUPPCState *env, target_ulong eaddr, @@ -609,7 +619,6 @@ static int slb_lookup (CPUPPCState *env, target_ulong eaddr,
609 uint64_t tmp64; 619 uint64_t tmp64;
610 uint32_t tmp; 620 uint32_t tmp;
611 int n, ret; 621 int n, ret;
612 - int slb_nr;  
613 622
614 ret = -5; 623 ret = -5;
615 sr_base = env->spr[SPR_ASR]; 624 sr_base = env->spr[SPR_ASR];
@@ -620,8 +629,7 @@ static int slb_lookup (CPUPPCState *env, target_ulong eaddr, @@ -620,8 +629,7 @@ static int slb_lookup (CPUPPCState *env, target_ulong eaddr,
620 } 629 }
621 #endif 630 #endif
622 mask = 0x0000000000000000ULL; /* Avoid gcc warning */ 631 mask = 0x0000000000000000ULL; /* Avoid gcc warning */
623 - slb_nr = env->slb_nr;  
624 - for (n = 0; n < slb_nr; n++) { 632 + for (n = 0; n < env->slb_nr; n++) {
625 tmp64 = ldq_phys(sr_base); 633 tmp64 = ldq_phys(sr_base);
626 tmp = ldl_phys(sr_base + 8); 634 tmp = ldl_phys(sr_base + 8);
627 #if defined(DEBUG_SLB) 635 #if defined(DEBUG_SLB)
@@ -630,7 +638,7 @@ static int slb_lookup (CPUPPCState *env, target_ulong eaddr, @@ -630,7 +638,7 @@ static int slb_lookup (CPUPPCState *env, target_ulong eaddr,
630 PRIx32 "\n", __func__, n, sr_base, tmp64, tmp); 638 PRIx32 "\n", __func__, n, sr_base, tmp64, tmp);
631 } 639 }
632 #endif 640 #endif
633 - if (tmp64 & 0x0000000008000000ULL) { 641 + if (slb_is_valid(tmp64)) {
634 /* SLB entry is valid */ 642 /* SLB entry is valid */
635 switch (tmp64 & 0x0000000006000000ULL) { 643 switch (tmp64 & 0x0000000006000000ULL) {
636 case 0x0000000000000000ULL: 644 case 0x0000000000000000ULL:
@@ -651,7 +659,7 @@ static int slb_lookup (CPUPPCState *env, target_ulong eaddr, @@ -651,7 +659,7 @@ static int slb_lookup (CPUPPCState *env, target_ulong eaddr,
651 *vsid = ((tmp64 << 24) | (tmp >> 8)) & 0x0003FFFFFFFFFFFFULL; 659 *vsid = ((tmp64 << 24) | (tmp >> 8)) & 0x0003FFFFFFFFFFFFULL;
652 *page_mask = ~mask; 660 *page_mask = ~mask;
653 *attr = tmp & 0xFF; 661 *attr = tmp & 0xFF;
654 - ret = 0; 662 + ret = n;
655 break; 663 break;
656 } 664 }
657 } 665 }
@@ -661,6 +669,56 @@ static int slb_lookup (CPUPPCState *env, target_ulong eaddr, @@ -661,6 +669,56 @@ static int slb_lookup (CPUPPCState *env, target_ulong eaddr,
661 return ret; 669 return ret;
662 } 670 }
663 671
  672 +void ppc_slb_invalidate_all (CPUPPCState *env)
  673 +{
  674 + target_phys_addr_t sr_base;
  675 + uint64_t tmp64;
  676 + int n, do_invalidate;
  677 +
  678 + do_invalidate = 0;
  679 + sr_base = env->spr[SPR_ASR];
  680 + for (n = 0; n < env->slb_nr; n++) {
  681 + tmp64 = ldq_phys(sr_base);
  682 + if (slb_is_valid(tmp64)) {
  683 + slb_invalidate(&tmp64);
  684 + stq_phys(sr_base, tmp64);
  685 + /* XXX: given the fact that segment size is 256 MB or 1TB,
  686 + * and we still don't have a tlb_flush_mask(env, n, mask)
  687 + * in Qemu, we just invalidate all TLBs
  688 + */
  689 + do_invalidate = 1;
  690 + }
  691 + sr_base += 12;
  692 + }
  693 + if (do_invalidate)
  694 + tlb_flush(env, 1);
  695 +}
  696 +
  697 +void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0)
  698 +{
  699 + target_phys_addr_t sr_base;
  700 + target_ulong vsid, page_mask;
  701 + uint64_t tmp64;
  702 + int attr;
  703 + int n;
  704 +
  705 + n = slb_lookup(env, T0, &vsid, &page_mask, &attr);
  706 + if (n >= 0) {
  707 + sr_base = env->spr[SPR_ASR];
  708 + sr_base += 12 * n;
  709 + tmp64 = ldq_phys(sr_base);
  710 + if (slb_is_valid(tmp64)) {
  711 + slb_invalidate(&tmp64);
  712 + stq_phys(sr_base, tmp64);
  713 + /* XXX: given the fact that segment size is 256 MB or 1TB,
  714 + * and we still don't have a tlb_flush_mask(env, n, mask)
  715 + * in Qemu, we just invalidate all TLBs
  716 + */
  717 + tlb_flush(env, 1);
  718 + }
  719 + }
  720 +}
  721 +
664 target_ulong ppc_load_slb (CPUPPCState *env, int slb_nr) 722 target_ulong ppc_load_slb (CPUPPCState *env, int slb_nr)
665 { 723 {
666 target_phys_addr_t sr_base; 724 target_phys_addr_t sr_base;
@@ -1828,20 +1886,6 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr) @@ -1828,20 +1886,6 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
1828 #endif 1886 #endif
1829 } 1887 }
1830 1888
1831 -#if defined(TARGET_PPC64)  
1832 -void ppc_slb_invalidate_all (CPUPPCState *env)  
1833 -{  
1834 - /* XXX: TODO */  
1835 - tlb_flush(env, 1);  
1836 -}  
1837 -  
1838 -void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0)  
1839 -{  
1840 - /* XXX: TODO */  
1841 - tlb_flush(env, 1);  
1842 -}  
1843 -#endif  
1844 -  
1845 /*****************************************************************************/ 1889 /*****************************************************************************/
1846 /* Special registers manipulation */ 1890 /* Special registers manipulation */
1847 #if defined(TARGET_PPC64) 1891 #if defined(TARGET_PPC64)