10186f47e703fb7aa14b54459d642ef5374b3a685Kumar Gala/*
20186f47e703fb7aa14b54459d642ef5374b3a685Kumar Gala * This file contains common routines for dealing with free of page tables
38d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt * Along with common page table handling code
40186f47e703fb7aa14b54459d642ef5374b3a685Kumar Gala *
50186f47e703fb7aa14b54459d642ef5374b3a685Kumar Gala *  Derived from arch/powerpc/mm/tlb_64.c:
60186f47e703fb7aa14b54459d642ef5374b3a685Kumar Gala *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
70186f47e703fb7aa14b54459d642ef5374b3a685Kumar Gala *
80186f47e703fb7aa14b54459d642ef5374b3a685Kumar Gala *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
90186f47e703fb7aa14b54459d642ef5374b3a685Kumar Gala *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
100186f47e703fb7aa14b54459d642ef5374b3a685Kumar Gala *    Copyright (C) 1996 Paul Mackerras
110186f47e703fb7aa14b54459d642ef5374b3a685Kumar Gala *
120186f47e703fb7aa14b54459d642ef5374b3a685Kumar Gala *  Derived from "arch/i386/mm/init.c"
130186f47e703fb7aa14b54459d642ef5374b3a685Kumar Gala *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
140186f47e703fb7aa14b54459d642ef5374b3a685Kumar Gala *
150186f47e703fb7aa14b54459d642ef5374b3a685Kumar Gala *  Dave Engebretsen <engebret@us.ibm.com>
160186f47e703fb7aa14b54459d642ef5374b3a685Kumar Gala *      Rework for PPC64 port.
170186f47e703fb7aa14b54459d642ef5374b3a685Kumar Gala *
180186f47e703fb7aa14b54459d642ef5374b3a685Kumar Gala *  This program is free software; you can redistribute it and/or
190186f47e703fb7aa14b54459d642ef5374b3a685Kumar Gala *  modify it under the terms of the GNU General Public License
200186f47e703fb7aa14b54459d642ef5374b3a685Kumar Gala *  as published by the Free Software Foundation; either version
210186f47e703fb7aa14b54459d642ef5374b3a685Kumar Gala *  2 of the License, or (at your option) any later version.
220186f47e703fb7aa14b54459d642ef5374b3a685Kumar Gala */
230186f47e703fb7aa14b54459d642ef5374b3a685Kumar Gala
240186f47e703fb7aa14b54459d642ef5374b3a685Kumar Gala#include <linux/kernel.h>
255a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h>
260186f47e703fb7aa14b54459d642ef5374b3a685Kumar Gala#include <linux/mm.h>
270186f47e703fb7aa14b54459d642ef5374b3a685Kumar Gala#include <linux/percpu.h>
280186f47e703fb7aa14b54459d642ef5374b3a685Kumar Gala#include <linux/hardirq.h>
2941151e77a4d96ea138cede6d84c955aa4769ce74Becky Bruce#include <linux/hugetlb.h>
300186f47e703fb7aa14b54459d642ef5374b3a685Kumar Gala#include <asm/pgalloc.h>
310186f47e703fb7aa14b54459d642ef5374b3a685Kumar Gala#include <asm/tlbflush.h>
320186f47e703fb7aa14b54459d642ef5374b3a685Kumar Gala#include <asm/tlb.h>
330186f47e703fb7aa14b54459d642ef5374b3a685Kumar Gala
348d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidtstatic inline int is_exec_fault(void)
358d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt{
368d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt	return current->thread.regs && TRAP(current->thread.regs) == 0x400;
378d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt}
388d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt
398d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt/* We only try to do i/d cache coherency on stuff that looks like
408d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt * reasonably "normal" PTEs. We currently require a PTE to be present
41ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt * and we avoid _PAGE_SPECIAL and _PAGE_NO_CACHE. We also only do that
42ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt * on userspace PTEs
438d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt */
448d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidtstatic inline int pte_looks_normal(pte_t pte)
458d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt{
468d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt	return (pte_val(pte) &
47ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	    (_PAGE_PRESENT | _PAGE_SPECIAL | _PAGE_NO_CACHE | _PAGE_USER)) ==
48ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	    (_PAGE_PRESENT | _PAGE_USER);
498d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt}
508d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt
51e51df2c170efaeadce4d416e1825b0830de0a795Anton Blanchardstatic struct page *maybe_pte_to_page(pte_t pte)
52ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt{
53ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	unsigned long pfn = pte_pfn(pte);
54ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	struct page *page;
55ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt
56ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	if (unlikely(!pfn_valid(pfn)))
57ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt		return NULL;
58ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	page = pfn_to_page(pfn);
59ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	if (PageReserved(page))
60ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt		return NULL;
61ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	return page;
62ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt}
63ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt
64ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt#if defined(CONFIG_PPC_STD_MMU) || _PAGE_EXEC == 0
65ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt
668d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt/* Server-style MMU handles coherency when hashing if HW exec permission
67ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt * is supposed per page (currently 64-bit only). If not, then, we always
68ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt * flush the cache for valid PTEs in set_pte. Embedded CPU without HW exec
69ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt * support falls into the same category.
708d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt */
71ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt
7279df1b374ba681f1322a0efd9a88bb85f1462796LEROY Christophestatic pte_t set_pte_filter(pte_t pte)
738d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt{
74ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	pte = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS);
75ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	if (pte_looks_normal(pte) && !(cpu_has_feature(CPU_FTR_COHERENT_ICACHE) ||
76ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt				       cpu_has_feature(CPU_FTR_NOEXECUTE))) {
77ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt		struct page *pg = maybe_pte_to_page(pte);
78ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt		if (!pg)
79ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt			return pte;
80ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt		if (!test_bit(PG_arch_1, &pg->flags)) {
81ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt			flush_dcache_icache_page(pg);
82ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt			set_bit(PG_arch_1, &pg->flags);
83ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt		}
84ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	}
85ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	return pte;
868d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt}
87ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt
88ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidtstatic pte_t set_access_flags_filter(pte_t pte, struct vm_area_struct *vma,
89ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt				     int dirty)
908d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt{
91ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	return pte;
928d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt}
93ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt
94ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt#else /* defined(CONFIG_PPC_STD_MMU) || _PAGE_EXEC == 0 */
95ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt
96ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt/* Embedded type MMU with HW exec support. This is a bit more complicated
97ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt * as we don't have two bits to spare for _PAGE_EXEC and _PAGE_HWEXEC so
98ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt * instead we "filter out" the exec permission for non clean pages.
998d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt */
10079df1b374ba681f1322a0efd9a88bb85f1462796LEROY Christophestatic pte_t set_pte_filter(pte_t pte)
1018d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt{
102ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	struct page *pg;
103ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt
104ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	/* No exec permission in the first place, move on */
105ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	if (!(pte_val(pte) & _PAGE_EXEC) || !pte_looks_normal(pte))
106ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt		return pte;
107ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt
108ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	/* If you set _PAGE_EXEC on weird pages you're on your own */
109ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	pg = maybe_pte_to_page(pte);
110ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	if (unlikely(!pg))
111ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt		return pte;
112ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt
113ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	/* If the page clean, we move on */
114ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	if (test_bit(PG_arch_1, &pg->flags))
115ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt		return pte;
116ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt
117ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	/* If it's an exec fault, we flush the cache and make it clean */
118ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	if (is_exec_fault()) {
119ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt		flush_dcache_icache_page(pg);
120ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt		set_bit(PG_arch_1, &pg->flags);
121ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt		return pte;
122ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	}
123ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt
124ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	/* Else, we filter out _PAGE_EXEC */
125ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	return __pte(pte_val(pte) & ~_PAGE_EXEC);
1268d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt}
127ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt
128ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidtstatic pte_t set_access_flags_filter(pte_t pte, struct vm_area_struct *vma,
129ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt				     int dirty)
130ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt{
131ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	struct page *pg;
132ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt
133ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	/* So here, we only care about exec faults, as we use them
134ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	 * to recover lost _PAGE_EXEC and perform I$/D$ coherency
135ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	 * if necessary. Also if _PAGE_EXEC is already set, same deal,
136ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	 * we just bail out
137ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	 */
138ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	if (dirty || (pte_val(pte) & _PAGE_EXEC) || !is_exec_fault())
139ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt		return pte;
140ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt
141ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt#ifdef CONFIG_DEBUG_VM
142ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	/* So this is an exec fault, _PAGE_EXEC is not set. If it was
143ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	 * an error we would have bailed out earlier in do_page_fault()
144ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	 * but let's make sure of it
145ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	 */
146ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	if (WARN_ON(!(vma->vm_flags & VM_EXEC)))
147ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt		return pte;
148ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt#endif /* CONFIG_DEBUG_VM */
149ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt
150ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	/* If you set _PAGE_EXEC on weird pages you're on your own */
151ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	pg = maybe_pte_to_page(pte);
152ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	if (unlikely(!pg))
153ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt		goto bail;
154ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt
155ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	/* If the page is already clean, we move on */
156ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	if (test_bit(PG_arch_1, &pg->flags))
157ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt		goto bail;
158ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt
159ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	/* Clean the page and set PG_arch_1 */
160ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	flush_dcache_icache_page(pg);
161ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	set_bit(PG_arch_1, &pg->flags);
162ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt
163ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt bail:
164ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	return __pte(pte_val(pte) | _PAGE_EXEC);
165ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt}
166ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt
167ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt#endif /* !(defined(CONFIG_PPC_STD_MMU) || _PAGE_EXEC == 0) */
1688d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt
1698d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt/*
1708d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt * set_pte stores a linux PTE into the linux page table.
1718d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt */
172ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidtvoid set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep,
173ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt		pte_t pte)
1748d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt{
1758d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt#ifdef CONFIG_DEBUG_VM
1768937ba48dcf62b5cdf7abb93652914af16756f50Aneesh Kumar K.V	WARN_ON(pte_val(*ptep) & _PAGE_PRESENT);
1778d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt#endif
1788d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt	/* Note: mm->context.id might not yet have been assigned as
1798d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt	 * this context might not have been activated yet when this
1808d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt	 * is called.
1818d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt	 */
18279df1b374ba681f1322a0efd9a88bb85f1462796LEROY Christophe	pte = set_pte_filter(pte);
1838d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt
1848d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt	/* Perform the setting of the PTE */
1858d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt	__set_pte_at(mm, addr, ptep, pte, 0);
1868d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt}
1878d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt
1888d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt/*
1898d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt * This is called when relaxing access to a PTE. It's also called in the page
1908d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt * fault path when we don't hit any of the major fault cases, ie, a minor
1918d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt * update of _PAGE_ACCESSED, _PAGE_DIRTY, etc... The generic code will have
1928d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt * handled those two for us, we additionally deal with missing execute
1938d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt * permission here on some processors
1948d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt */
1958d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidtint ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address,
1968d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt			  pte_t *ptep, pte_t entry, int dirty)
1978d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt{
1988d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt	int changed;
199ea3cc330ac0cd521ff07c7cd432a1848c19a7e92Benjamin Herrenschmidt	entry = set_access_flags_filter(entry, vma, dirty);
2008d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt	changed = !pte_same(*(ptep), entry);
2018d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt	if (changed) {
20241151e77a4d96ea138cede6d84c955aa4769ce74Becky Bruce		if (!is_vm_hugetlb_page(vma))
203af3e4aca47d2e05a545a5e10ba5c7193e0b665e0Mel Gorman			assert_pte_locked(vma->vm_mm, address);
2048d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt		__ptep_set_access_flags(ptep, entry);
2058d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt		flush_tlb_page_nohash(vma, address);
2068d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt	}
2078d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt	return changed;
2088d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt}
2098d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt
2108d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt#ifdef CONFIG_DEBUG_VM
2118d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidtvoid assert_pte_locked(struct mm_struct *mm, unsigned long addr)
2128d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt{
2138d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt	pgd_t *pgd;
2148d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt	pud_t *pud;
2158d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt	pmd_t *pmd;
2168d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt
2178d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt	if (mm == &init_mm)
2188d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt		return;
2198d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt	pgd = mm->pgd + pgd_index(addr);
2208d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt	BUG_ON(pgd_none(*pgd));
2218d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt	pud = pud_offset(pgd, addr);
2228d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt	BUG_ON(pud_none(*pud));
2238d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt	pmd = pmd_offset(pud, addr);
224a00e7bea0dde6a44b9bbe84f30b731d9ec73858bAneesh Kumar K.V	/*
225a00e7bea0dde6a44b9bbe84f30b731d9ec73858bAneesh Kumar K.V	 * khugepaged to collapse normal pages to hugepage, first set
226a00e7bea0dde6a44b9bbe84f30b731d9ec73858bAneesh Kumar K.V	 * pmd to none to force page fault/gup to take mmap_sem. After
227a00e7bea0dde6a44b9bbe84f30b731d9ec73858bAneesh Kumar K.V	 * pmd is set to none, we do a pte_clear which does this assertion
228a00e7bea0dde6a44b9bbe84f30b731d9ec73858bAneesh Kumar K.V	 * so if we find pmd none, return.
229a00e7bea0dde6a44b9bbe84f30b731d9ec73858bAneesh Kumar K.V	 */
230a00e7bea0dde6a44b9bbe84f30b731d9ec73858bAneesh Kumar K.V	if (pmd_none(*pmd))
231a00e7bea0dde6a44b9bbe84f30b731d9ec73858bAneesh Kumar K.V		return;
2328d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt	BUG_ON(!pmd_present(*pmd));
233797a747a82e23530ee45d2927bf84f3571c1acb2Kumar Gala	assert_spin_locked(pte_lockptr(mm, pmd));
2348d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt}
2358d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt#endif /* CONFIG_DEBUG_VM */
2368d30c14cab30d405a05f2aaceda1e9ad57800f36Benjamin Herrenschmidt
237