2 * Copyright IBM Corp. 2011
3 * Author(s): Jan Glauber <jang@linux.vnet.ibm.com>
5 #include <linux/hugetlb.h>
6 #include <linux/module.h>
8 #include <asm/cacheflush.h>
9 #include <asm/pgtable.h>
12 static inline unsigned long sske_frame(unsigned long addr
, unsigned char skey
)
14 asm volatile(".insn rrf,0xb22b0000,%[skey],%[addr],9,0"
15 : [addr
] "+a" (addr
) : [skey
] "d" (skey
));
19 void storage_key_init_range(unsigned long start
, unsigned long end
)
21 unsigned long boundary
, size
;
24 if (MACHINE_HAS_EDAT1
) {
25 /* set storage keys for a 1MB frame */
27 boundary
= (start
+ size
) & ~(size
- 1);
28 if (boundary
<= end
) {
30 start
= sske_frame(start
, PAGE_DEFAULT_KEY
);
31 } while (start
< boundary
);
35 page_set_storage_key(start
, PAGE_DEFAULT_KEY
, 0);
40 static pte_t
*walk_page_table(unsigned long addr
)
47 pgdp
= pgd_offset_k(addr
);
50 pudp
= pud_offset(pgdp
, addr
);
51 if (pud_none(*pudp
) || pud_large(*pudp
))
53 pmdp
= pmd_offset(pudp
, addr
);
54 if (pmd_none(*pmdp
) || pmd_large(*pmdp
))
56 ptep
= pte_offset_kernel(pmdp
, addr
);
62 static void change_page_attr(unsigned long addr
, int numpages
,
68 for (i
= 0; i
< numpages
; i
++) {
69 ptep
= walk_page_table(addr
);
70 if (WARN_ON_ONCE(!ptep
))
74 __ptep_ipte(addr
, ptep
);
80 int set_memory_ro(unsigned long addr
, int numpages
)
82 change_page_attr(addr
, numpages
, pte_wrprotect
);
86 int set_memory_rw(unsigned long addr
, int numpages
)
88 change_page_attr(addr
, numpages
, pte_mkwrite
);
93 int set_memory_nx(unsigned long addr
, int numpages
)
98 int set_memory_x(unsigned long addr
, int numpages
)
103 #ifdef CONFIG_DEBUG_PAGEALLOC
104 void kernel_map_pages(struct page
*page
, int numpages
, int enable
)
106 unsigned long address
;
113 for (i
= 0; i
< numpages
; i
++) {
114 address
= page_to_phys(page
+ i
);
115 pgd
= pgd_offset_k(address
);
116 pud
= pud_offset(pgd
, address
);
117 pmd
= pmd_offset(pud
, address
);
118 pte
= pte_offset_kernel(pmd
, address
);
120 __ptep_ipte(address
, pte
);
121 pte_val(*pte
) = _PAGE_TYPE_EMPTY
;
124 pte_val(*pte
) = __pa(address
);
128 #ifdef CONFIG_HIBERNATION
129 bool kernel_page_present(struct page
*page
)
134 addr
= page_to_phys(page
);
139 : "=d" (cc
), "+a" (addr
) : : "cc");
142 #endif /* CONFIG_HIBERNATION */
144 #endif /* CONFIG_DEBUG_PAGEALLOC */