aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2014-04-24 16:58:02 -0400
committerDavid S. Miller <davem@davemloft.net>2014-05-04 01:31:52 -0400
commit51e5ef1bb7ab0e5fa7de4e802da5ab22fe35f0bf (patch)
treef8ef5fdc807082bf9d9f75577e764cec96ed13a4
parent5b1e94fa439a3227beefad58c28c17f68287a8e9 (diff)
sparc64: Fix huge PMD invalidation.
On sparc64 "present" and "valid" are seperate PTE bits, this allows us to naturally distinguish between the user explicitly asking for PROT_NONE with mprotect() and other situations. However we weren't handling this properly in the huge PMD paths. First of all, the page table walker in the TSB miss path only checks for _PAGE_PMD_HUGE. So the generic pmdp_invalidate() would clear _PAGE_PRESENT but the TLB miss paths would still load it into the TLB as a valid huge PMD. Fix this by clearing the valid bit in pmdp_invalidate(), and also checking the valid bit in USER_PGTABLE_CHECK_PMD_HUGE using "brgez" since _PAGE_VALID is bit 63 in both the sun4u and sun4v pte layouts. Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--arch/sparc/include/asm/pgtable_64.h18
-rw-r--r--arch/sparc/include/asm/tsb.h3
-rw-r--r--arch/sparc/mm/tlb.c11
3 files changed, 17 insertions, 15 deletions
diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h
index 0f9e94537eee..e3db4b8e689b 100644
--- a/arch/sparc/include/asm/pgtable_64.h
+++ b/arch/sparc/include/asm/pgtable_64.h
@@ -719,20 +719,6 @@ static inline pmd_t pmd_mkwrite(pmd_t pmd)
719 return __pmd(pte_val(pte)); 719 return __pmd(pte_val(pte));
720} 720}
721 721
722static inline pmd_t pmd_mknotpresent(pmd_t pmd)
723{
724 unsigned long mask;
725
726 if (tlb_type == hypervisor)
727 mask = _PAGE_PRESENT_4V;
728 else
729 mask = _PAGE_PRESENT_4U;
730
731 pmd_val(pmd) &= ~mask;
732
733 return pmd;
734}
735
736static inline pmd_t pmd_mksplitting(pmd_t pmd) 722static inline pmd_t pmd_mksplitting(pmd_t pmd)
737{ 723{
738 pte_t pte = __pte(pmd_val(pmd)); 724 pte_t pte = __pte(pmd_val(pmd));
@@ -893,6 +879,10 @@ extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t *);
893extern void update_mmu_cache_pmd(struct vm_area_struct *vma, unsigned long addr, 879extern void update_mmu_cache_pmd(struct vm_area_struct *vma, unsigned long addr,
894 pmd_t *pmd); 880 pmd_t *pmd);
895 881
882#define __HAVE_ARCH_PMDP_INVALIDATE
883extern void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
884 pmd_t *pmdp);
885
896#define __HAVE_ARCH_PGTABLE_DEPOSIT 886#define __HAVE_ARCH_PGTABLE_DEPOSIT
897extern void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp, 887extern void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,
898 pgtable_t pgtable); 888 pgtable_t pgtable);
diff --git a/arch/sparc/include/asm/tsb.h b/arch/sparc/include/asm/tsb.h
index 2230f80d9fe3..90916f955cac 100644
--- a/arch/sparc/include/asm/tsb.h
+++ b/arch/sparc/include/asm/tsb.h
@@ -171,7 +171,8 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
171 andcc REG1, REG2, %g0; \ 171 andcc REG1, REG2, %g0; \
172 be,pt %xcc, 700f; \ 172 be,pt %xcc, 700f; \
173 sethi %hi(4 * 1024 * 1024), REG2; \ 173 sethi %hi(4 * 1024 * 1024), REG2; \
174 andn REG1, REG2, REG1; \ 174 brgez,pn REG1, FAIL_LABEL; \
175 andn REG1, REG2, REG1; \
175 and VADDR, REG2, REG2; \ 176 and VADDR, REG2, REG2; \
176 brlz,pt REG1, PTE_LABEL; \ 177 brlz,pt REG1, PTE_LABEL; \
177 or REG1, REG2, REG1; \ 178 or REG1, REG2, REG1; \
diff --git a/arch/sparc/mm/tlb.c b/arch/sparc/mm/tlb.c
index c07667fcd66e..b89aba217e3b 100644
--- a/arch/sparc/mm/tlb.c
+++ b/arch/sparc/mm/tlb.c
@@ -193,6 +193,17 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr,
193 } 193 }
194} 194}
195 195
196void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
197 pmd_t *pmdp)
198{
199 pmd_t entry = *pmdp;
200
201 pmd_val(entry) &= ~_PAGE_VALID;
202
203 set_pmd_at(vma->vm_mm, address, pmdp, entry);
204 flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
205}
206
196void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp, 207void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,
197 pgtable_t pgtable) 208 pgtable_t pgtable)
198{ 209{