aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm64/mm/pageattr.c
diff options
context:
space:
mode:
authorLaura Abbott <labbott@fedoraproject.org>2016-02-05 19:24:47 -0500
committerCatalin Marinas <catalin.marinas@arm.com>2016-02-16 10:40:30 -0500
commit83863f25e4b8214e994ef8b5647aad614d74b45d (patch)
treedef928e193b847e4035a6d895efafc9f9b881896 /arch/arm64/mm/pageattr.c
parent132233a759580f5ce9b1bfaac9073e47d03c460d (diff)
arm64: Add support for ARCH_SUPPORTS_DEBUG_PAGEALLOC
ARCH_SUPPORTS_DEBUG_PAGEALLOC provides a hook to map and unmap pages for debugging purposes. This requires memory be mapped with PAGE_SIZE mappings since breaking down larger mappings at runtime will lead to TLB conflicts. Check if debug_pagealloc is enabled at runtime and if so, map everyting with PAGE_SIZE pages. Implement the functions to actually map/unmap the pages at runtime. Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Reviewed-by: Mark Rutland <mark.rutland@arm.com> Tested-by: Mark Rutland <mark.rutland@arm.com> Signed-off-by: Laura Abbott <labbott@fedoraproject.org> [catalin.marinas@arm.com: static annotation block_mappings_allowed() and #ifdef] Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Diffstat (limited to 'arch/arm64/mm/pageattr.c')
-rw-r--r--arch/arm64/mm/pageattr.c46
1 files changed, 36 insertions, 10 deletions
diff --git a/arch/arm64/mm/pageattr.c b/arch/arm64/mm/pageattr.c
index 0795c3a36d8f..ca6d268e3313 100644
--- a/arch/arm64/mm/pageattr.c
+++ b/arch/arm64/mm/pageattr.c
@@ -37,14 +37,31 @@ static int change_page_range(pte_t *ptep, pgtable_t token, unsigned long addr,
37 return 0; 37 return 0;
38} 38}
39 39
40/*
41 * This function assumes that the range is mapped with PAGE_SIZE pages.
42 */
43static int __change_memory_common(unsigned long start, unsigned long size,
44 pgprot_t set_mask, pgprot_t clear_mask)
45{
46 struct page_change_data data;
47 int ret;
48
49 data.set_mask = set_mask;
50 data.clear_mask = clear_mask;
51
52 ret = apply_to_page_range(&init_mm, start, size, change_page_range,
53 &data);
54
55 flush_tlb_kernel_range(start, start + size);
56 return ret;
57}
58
40static int change_memory_common(unsigned long addr, int numpages, 59static int change_memory_common(unsigned long addr, int numpages,
41 pgprot_t set_mask, pgprot_t clear_mask) 60 pgprot_t set_mask, pgprot_t clear_mask)
42{ 61{
43 unsigned long start = addr; 62 unsigned long start = addr;
44 unsigned long size = PAGE_SIZE*numpages; 63 unsigned long size = PAGE_SIZE*numpages;
45 unsigned long end = start + size; 64 unsigned long end = start + size;
46 int ret;
47 struct page_change_data data;
48 struct vm_struct *area; 65 struct vm_struct *area;
49 66
50 if (!PAGE_ALIGNED(addr)) { 67 if (!PAGE_ALIGNED(addr)) {
@@ -75,14 +92,7 @@ static int change_memory_common(unsigned long addr, int numpages,
75 if (!numpages) 92 if (!numpages)
76 return 0; 93 return 0;
77 94
78 data.set_mask = set_mask; 95 return __change_memory_common(start, size, set_mask, clear_mask);
79 data.clear_mask = clear_mask;
80
81 ret = apply_to_page_range(&init_mm, start, size, change_page_range,
82 &data);
83
84 flush_tlb_kernel_range(start, end);
85 return ret;
86} 96}
87 97
88int set_memory_ro(unsigned long addr, int numpages) 98int set_memory_ro(unsigned long addr, int numpages)
@@ -114,3 +124,19 @@ int set_memory_x(unsigned long addr, int numpages)
114 __pgprot(PTE_PXN)); 124 __pgprot(PTE_PXN));
115} 125}
116EXPORT_SYMBOL_GPL(set_memory_x); 126EXPORT_SYMBOL_GPL(set_memory_x);
127
128#ifdef CONFIG_DEBUG_PAGEALLOC
129void __kernel_map_pages(struct page *page, int numpages, int enable)
130{
131 unsigned long addr = (unsigned long) page_address(page);
132
133 if (enable)
134 __change_memory_common(addr, PAGE_SIZE * numpages,
135 __pgprot(PTE_VALID),
136 __pgprot(0));
137 else
138 __change_memory_common(addr, PAGE_SIZE * numpages,
139 __pgprot(0),
140 __pgprot(PTE_VALID));
141}
142#endif