summaryrefslogtreecommitdiffstats
path: root/arch/arm64
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
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')
-rw-r--r--arch/arm64/Kconfig3
-rw-r--r--arch/arm64/mm/mmu.c26
-rw-r--r--arch/arm64/mm/pageattr.c46
3 files changed, 63 insertions, 12 deletions
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 53e48a617fef..5a1f2e47d153 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -537,6 +537,9 @@ config HOTPLUG_CPU
537source kernel/Kconfig.preempt 537source kernel/Kconfig.preempt
538source kernel/Kconfig.hz 538source kernel/Kconfig.hz
539 539
540config ARCH_SUPPORTS_DEBUG_PAGEALLOC
541 def_bool y
542
540config ARCH_HAS_HOLES_MEMORYMODEL 543config ARCH_HAS_HOLES_MEMORYMODEL
541 def_bool y if SPARSEMEM 544 def_bool y if SPARSEMEM
542 545
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index ef0d66cf5535..a6f28e5b9585 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -149,6 +149,26 @@ static void split_pud(pud_t *old_pud, pmd_t *pmd)
149 } while (pmd++, i++, i < PTRS_PER_PMD); 149 } while (pmd++, i++, i < PTRS_PER_PMD);
150} 150}
151 151
152#ifdef CONFIG_DEBUG_PAGEALLOC
153static bool block_mappings_allowed(phys_addr_t (*pgtable_alloc)(void))
154{
155
156 /*
157 * If debug_page_alloc is enabled we must map the linear map
158 * using pages. However, other mappings created by
159 * create_mapping_noalloc must use sections in some cases. Allow
160 * sections to be used in those cases, where no pgtable_alloc
161 * function is provided.
162 */
163 return !pgtable_alloc || !debug_pagealloc_enabled();
164}
165#else
166static bool block_mappings_allowed(phys_addr_t (*pgtable_alloc)(void))
167{
168 return true;
169}
170#endif
171
152static void alloc_init_pmd(pud_t *pud, unsigned long addr, unsigned long end, 172static void alloc_init_pmd(pud_t *pud, unsigned long addr, unsigned long end,
153 phys_addr_t phys, pgprot_t prot, 173 phys_addr_t phys, pgprot_t prot,
154 phys_addr_t (*pgtable_alloc)(void)) 174 phys_addr_t (*pgtable_alloc)(void))
@@ -181,7 +201,8 @@ static void alloc_init_pmd(pud_t *pud, unsigned long addr, unsigned long end,
181 do { 201 do {
182 next = pmd_addr_end(addr, end); 202 next = pmd_addr_end(addr, end);
183 /* try section mapping first */ 203 /* try section mapping first */
184 if (((addr | next | phys) & ~SECTION_MASK) == 0) { 204 if (((addr | next | phys) & ~SECTION_MASK) == 0 &&
205 block_mappings_allowed(pgtable_alloc)) {
185 pmd_t old_pmd =*pmd; 206 pmd_t old_pmd =*pmd;
186 set_pmd(pmd, __pmd(phys | 207 set_pmd(pmd, __pmd(phys |
187 pgprot_val(mk_sect_prot(prot)))); 208 pgprot_val(mk_sect_prot(prot))));
@@ -241,7 +262,8 @@ static void alloc_init_pud(pgd_t *pgd, unsigned long addr, unsigned long end,
241 /* 262 /*
242 * For 4K granule only, attempt to put down a 1GB block 263 * For 4K granule only, attempt to put down a 1GB block
243 */ 264 */
244 if (use_1G_block(addr, next, phys)) { 265 if (use_1G_block(addr, next, phys) &&
266 block_mappings_allowed(pgtable_alloc)) {
245 pud_t old_pud = *pud; 267 pud_t old_pud = *pud;
246 set_pud(pud, __pud(phys | 268 set_pud(pud, __pud(phys |
247 pgprot_val(mk_sect_prot(prot)))); 269 pgprot_val(mk_sect_prot(prot))));
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