1 /* 2 * Copyright IBM Corp. 2011 3 * Author(s): Jan Glauber <jang@linux.vnet.ibm.com> 4 */ 5 #include <linux/module.h> 6 #include <linux/mm.h> 7 #include <linux/hugetlb.h> 8 #include <asm/cacheflush.h> 9 #include <asm/pgtable.h> 10 11 static pte_t *walk_page_table(unsigned long addr) 12 { 13 pgd_t *pgdp; 14 pud_t *pudp; 15 pmd_t *pmdp; 16 pte_t *ptep; 17 18 pgdp = pgd_offset_k(addr); 19 if (pgd_none(*pgdp)) 20 return NULL; 21 pudp = pud_offset(pgdp, addr); 22 if (pud_none(*pudp)) 23 return NULL; 24 pmdp = pmd_offset(pudp, addr); 25 if (pmd_none(*pmdp) || pmd_large(*pmdp)) 26 return NULL; 27 ptep = pte_offset_kernel(pmdp, addr); 28 if (pte_none(*ptep)) 29 return NULL; 30 return ptep; 31 } 32 33 static void change_page_attr(unsigned long addr, int numpages, 34 pte_t (*set) (pte_t)) 35 { 36 pte_t *ptep, pte; 37 int i; 38 39 for (i = 0; i < numpages; i++) { 40 ptep = walk_page_table(addr); 41 if (WARN_ON_ONCE(!ptep)) 42 break; 43 pte = *ptep; 44 pte = set(pte); 45 __ptep_ipte(addr, ptep); 46 *ptep = pte; 47 addr += PAGE_SIZE; 48 } 49 } 50 51 int set_memory_ro(unsigned long addr, int numpages) 52 { 53 change_page_attr(addr, numpages, pte_wrprotect); 54 return 0; 55 } 56 57 int set_memory_rw(unsigned long addr, int numpages) 58 { 59 change_page_attr(addr, numpages, pte_mkwrite); 60 return 0; 61 } 62 63 /* not possible */ 64 int set_memory_nx(unsigned long addr, int numpages) 65 { 66 return 0; 67 } 68 69 int set_memory_x(unsigned long addr, int numpages) 70 { 71 return 0; 72 } 73