2 * Copyright (c) 2014, The Linux Foundation. All rights reserved.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/sched.h>
17 #include <linux/vmalloc.h>
19 #include <asm/pgtable.h>
20 #include <asm/set_memory.h>
21 #include <asm/tlbflush.h>
23 struct page_change_data
{
28 static int change_page_range(pte_t
*ptep
, pgtable_t token
, unsigned long addr
,
31 struct page_change_data
*cdata
= data
;
32 pte_t pte
= READ_ONCE(*ptep
);
34 pte
= clear_pte_bit(pte
, cdata
->clear_mask
);
35 pte
= set_pte_bit(pte
, cdata
->set_mask
);
42 * This function assumes that the range is mapped with PAGE_SIZE pages.
44 static int __change_memory_common(unsigned long start
, unsigned long size
,
45 pgprot_t set_mask
, pgprot_t clear_mask
)
47 struct page_change_data data
;
50 data
.set_mask
= set_mask
;
51 data
.clear_mask
= clear_mask
;
53 ret
= apply_to_page_range(&init_mm
, start
, size
, change_page_range
,
56 flush_tlb_kernel_range(start
, start
+ size
);
60 static int change_memory_common(unsigned long addr
, int numpages
,
61 pgprot_t set_mask
, pgprot_t clear_mask
)
63 unsigned long start
= addr
;
64 unsigned long size
= PAGE_SIZE
*numpages
;
65 unsigned long end
= start
+ size
;
66 struct vm_struct
*area
;
68 if (!PAGE_ALIGNED(addr
)) {
75 * Kernel VA mappings are always live, and splitting live section
76 * mappings into page mappings may cause TLB conflicts. This means
77 * we have to ensure that changing the permission bits of the range
78 * we are operating on does not result in such splitting.
80 * Let's restrict ourselves to mappings created by vmalloc (or vmap).
81 * Those are guaranteed to consist entirely of page mappings, and
82 * splitting is never needed.
84 * So check whether the [addr, addr + size) interval is entirely
85 * covered by precisely one VM area that has the VM_ALLOC flag set.
87 area
= find_vm_area((void *)addr
);
89 end
> (unsigned long)area
->addr
+ area
->size
||
90 !(area
->flags
& VM_ALLOC
))
96 return __change_memory_common(start
, size
, set_mask
, clear_mask
);
99 int set_memory_ro(unsigned long addr
, int numpages
)
101 return change_memory_common(addr
, numpages
,
102 __pgprot(PTE_RDONLY
),
103 __pgprot(PTE_WRITE
));
106 int set_memory_rw(unsigned long addr
, int numpages
)
108 return change_memory_common(addr
, numpages
,
110 __pgprot(PTE_RDONLY
));
113 int set_memory_nx(unsigned long addr
, int numpages
)
115 return change_memory_common(addr
, numpages
,
119 EXPORT_SYMBOL_GPL(set_memory_nx
);
121 int set_memory_x(unsigned long addr
, int numpages
)
123 return change_memory_common(addr
, numpages
,
127 EXPORT_SYMBOL_GPL(set_memory_x
);
129 int set_memory_valid(unsigned long addr
, int numpages
, int enable
)
132 return __change_memory_common(addr
, PAGE_SIZE
* numpages
,
136 return __change_memory_common(addr
, PAGE_SIZE
* numpages
,
138 __pgprot(PTE_VALID
));
141 #ifdef CONFIG_DEBUG_PAGEALLOC
142 void __kernel_map_pages(struct page
*page
, int numpages
, int enable
)
144 set_memory_valid((unsigned long)page_address(page
), numpages
, enable
);
146 #ifdef CONFIG_HIBERNATION
148 * When built with CONFIG_DEBUG_PAGEALLOC and CONFIG_HIBERNATION, this function
149 * is used to determine if a linear map page has been marked as not-valid by
150 * CONFIG_DEBUG_PAGEALLOC. Walk the page table and check the PTE_VALID bit.
151 * This is based on kern_addr_valid(), which almost does what we need.
153 * Because this is only called on the kernel linear map, p?d_sect() implies
154 * p?d_present(). When debug_pagealloc is enabled, sections mappings are
157 bool kernel_page_present(struct page
*page
)
163 unsigned long addr
= (unsigned long)page_address(page
);
165 pgdp
= pgd_offset_k(addr
);
166 if (pgd_none(READ_ONCE(*pgdp
)))
169 pudp
= pud_offset(pgdp
, addr
);
170 pud
= READ_ONCE(*pudp
);
176 pmdp
= pmd_offset(pudp
, addr
);
177 pmd
= READ_ONCE(*pmdp
);
183 ptep
= pte_offset_kernel(pmdp
, addr
);
184 return pte_valid(READ_ONCE(*ptep
));
186 #endif /* CONFIG_HIBERNATION */
187 #endif /* CONFIG_DEBUG_PAGEALLOC */