Commit eacc324914c2dc7aecec3b4ea920252b685b5c8e
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 | 601 | } |
| 602 | 602 | |
| 603 | 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 | 614 | static int slb_lookup (CPUPPCState *env, target_ulong eaddr, |
| 605 | 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 | 619 | uint64_t tmp64; |
| 610 | 620 | uint32_t tmp; |
| 611 | 621 | int n, ret; |
| 612 | - int slb_nr; | |
| 613 | 622 | |
| 614 | 623 | ret = -5; |
| 615 | 624 | sr_base = env->spr[SPR_ASR]; |
| ... | ... | @@ -620,8 +629,7 @@ static int slb_lookup (CPUPPCState *env, target_ulong eaddr, |
| 620 | 629 | } |
| 621 | 630 | #endif |
| 622 | 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 | 633 | tmp64 = ldq_phys(sr_base); |
| 626 | 634 | tmp = ldl_phys(sr_base + 8); |
| 627 | 635 | #if defined(DEBUG_SLB) |
| ... | ... | @@ -630,7 +638,7 @@ static int slb_lookup (CPUPPCState *env, target_ulong eaddr, |
| 630 | 638 | PRIx32 "\n", __func__, n, sr_base, tmp64, tmp); |
| 631 | 639 | } |
| 632 | 640 | #endif |
| 633 | - if (tmp64 & 0x0000000008000000ULL) { | |
| 641 | + if (slb_is_valid(tmp64)) { | |
| 634 | 642 | /* SLB entry is valid */ |
| 635 | 643 | switch (tmp64 & 0x0000000006000000ULL) { |
| 636 | 644 | case 0x0000000000000000ULL: |
| ... | ... | @@ -651,7 +659,7 @@ static int slb_lookup (CPUPPCState *env, target_ulong eaddr, |
| 651 | 659 | *vsid = ((tmp64 << 24) | (tmp >> 8)) & 0x0003FFFFFFFFFFFFULL; |
| 652 | 660 | *page_mask = ~mask; |
| 653 | 661 | *attr = tmp & 0xFF; |
| 654 | - ret = 0; | |
| 662 | + ret = n; | |
| 655 | 663 | break; |
| 656 | 664 | } |
| 657 | 665 | } |
| ... | ... | @@ -661,6 +669,56 @@ static int slb_lookup (CPUPPCState *env, target_ulong eaddr, |
| 661 | 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 | 722 | target_ulong ppc_load_slb (CPUPPCState *env, int slb_nr) |
| 665 | 723 | { |
| 666 | 724 | target_phys_addr_t sr_base; |
| ... | ... | @@ -1828,20 +1886,6 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr) |
| 1828 | 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 | 1890 | /* Special registers manipulation */ |
| 1847 | 1891 | #if defined(TARGET_PPC64) | ... | ... |