1 /* 2 * Copyright (c) 2014, The Linux Foundation. All rights reserved. 3 * 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. 7 * 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. 12 */ 13 #include <linux/kernel.h> 14 #include <linux/mm.h> 15 #include <linux/module.h> 16 #include <linux/sched.h> 17 #include <linux/vmalloc.h> 18 19 #include <asm/pgtable.h> 20 #include <asm/set_memory.h> 21 #include <asm/tlbflush.h> 22 23 struct page_change_data { 24 pgprot_t set_mask; 25 pgprot_t clear_mask; 26 }; 27 28 static int change_page_range(pte_t *ptep, pgtable_t token, unsigned long addr, 29 void *data) 30 { 31 struct page_change_data *cdata = data; 32 pte_t pte = *ptep; 33 34 pte = clear_pte_bit(pte, cdata->clear_mask); 35 pte = set_pte_bit(pte, cdata->set_mask); 36 37 set_pte(ptep, pte); 38 return 0; 39 } 40 41 /* 42 * This function assumes that the range is mapped with PAGE_SIZE pages. 43 */ 44 static int __change_memory_common(unsigned long start, unsigned long size, 45 pgprot_t set_mask, pgprot_t clear_mask) 46 { 47 struct page_change_data data; 48 int ret; 49 50 data.set_mask = set_mask; 51 data.clear_mask = clear_mask; 52 53 ret = apply_to_page_range(&init_mm, start, size, change_page_range, 54 &data); 55 56 flush_tlb_kernel_range(start, start + size); 57 return ret; 58 } 59 60 static int change_memory_common(unsigned long addr, int numpages, 61 pgprot_t set_mask, pgprot_t clear_mask) 62 { 63 unsigned long start = addr; 64 unsigned long size = PAGE_SIZE*numpages; 65 unsigned long end = start + size; 66 struct vm_struct *area; 67 68 if (!PAGE_ALIGNED(addr)) { 69 start &= PAGE_MASK; 70 end = start + size; 71 WARN_ON_ONCE(1); 72 } 73 74 /* 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. 79 * 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. 83 * 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. 86 */ 87 area = find_vm_area((void *)addr); 88 if (!area || 89 end > (unsigned long)area->addr + area->size || 90 !(area->flags & VM_ALLOC)) 91 return -EINVAL; 92 93 if (!numpages) 94 return 0; 95 96 return __change_memory_common(start, size, set_mask, clear_mask); 97 } 98 99 int set_memory_ro(unsigned long addr, int numpages) 100 { 101 return change_memory_common(addr, numpages, 102 __pgprot(PTE_RDONLY), 103 __pgprot(PTE_WRITE)); 104 } 105 106 int set_memory_rw(unsigned long addr, int numpages) 107 { 108 return change_memory_common(addr, numpages, 109 __pgprot(PTE_WRITE), 110 __pgprot(PTE_RDONLY)); 111 } 112 113 int set_memory_nx(unsigned long addr, int numpages) 114 { 115 return change_memory_common(addr, numpages, 116 __pgprot(PTE_PXN), 117 __pgprot(0)); 118 } 119 EXPORT_SYMBOL_GPL(set_memory_nx); 120 121 int set_memory_x(unsigned long addr, int numpages) 122 { 123 return change_memory_common(addr, numpages, 124 __pgprot(0), 125 __pgprot(PTE_PXN)); 126 } 127 EXPORT_SYMBOL_GPL(set_memory_x); 128 129 int set_memory_valid(unsigned long addr, int numpages, int enable) 130 { 131 if (enable) 132 return __change_memory_common(addr, PAGE_SIZE * numpages, 133 __pgprot(PTE_VALID), 134 __pgprot(0)); 135 else 136 return __change_memory_common(addr, PAGE_SIZE * numpages, 137 __pgprot(0), 138 __pgprot(PTE_VALID)); 139 } 140 141 #ifdef CONFIG_DEBUG_PAGEALLOC 142 void __kernel_map_pages(struct page *page, int numpages, int enable) 143 { 144 set_memory_valid((unsigned long)page_address(page), numpages, enable); 145 } 146 #ifdef CONFIG_HIBERNATION 147 /* 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. 152 * 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 155 * disabled. 156 */ 157 bool kernel_page_present(struct page *page) 158 { 159 pgd_t *pgd; 160 pud_t *pud; 161 pmd_t *pmd; 162 pte_t *pte; 163 unsigned long addr = (unsigned long)page_address(page); 164 165 pgd = pgd_offset_k(addr); 166 if (pgd_none(*pgd)) 167 return false; 168 169 pud = pud_offset(pgd, addr); 170 if (pud_none(*pud)) 171 return false; 172 if (pud_sect(*pud)) 173 return true; 174 175 pmd = pmd_offset(pud, addr); 176 if (pmd_none(*pmd)) 177 return false; 178 if (pmd_sect(*pmd)) 179 return true; 180 181 pte = pte_offset_kernel(pmd, addr); 182 return pte_valid(*pte); 183 } 184 #endif /* CONFIG_HIBERNATION */ 185 #endif /* CONFIG_DEBUG_PAGEALLOC */ 186