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/facility.h>
10 #include <asm/pgtable.h>
14 static inline unsigned long sske_frame(unsigned long addr
, unsigned char skey
)
16 asm volatile(".insn rrf,0xb22b0000,%[skey],%[addr],9,0"
17 : [addr
] "+a" (addr
) : [skey
] "d" (skey
));
21 void __storage_key_init_range(unsigned long start
, unsigned long end
)
23 unsigned long boundary
, size
;
26 if (MACHINE_HAS_EDAT1
) {
27 /* set storage keys for a 1MB frame */
29 boundary
= (start
+ size
) & ~(size
- 1);
30 if (boundary
<= end
) {
32 start
= sske_frame(start
, PAGE_DEFAULT_KEY
);
33 } while (start
< boundary
);
37 page_set_storage_key(start
, PAGE_DEFAULT_KEY
, 0);
43 static pte_t
*walk_page_table(unsigned long addr
)
50 pgdp
= pgd_offset_k(addr
);
53 pudp
= pud_offset(pgdp
, addr
);
54 if (pud_none(*pudp
) || pud_large(*pudp
))
56 pmdp
= pmd_offset(pudp
, addr
);
57 if (pmd_none(*pmdp
) || pmd_large(*pmdp
))
59 ptep
= pte_offset_kernel(pmdp
, addr
);
65 static void change_page_attr(unsigned long addr
, int numpages
,
71 for (i
= 0; i
< numpages
; i
++) {
72 ptep
= walk_page_table(addr
);
73 if (WARN_ON_ONCE(!ptep
))
77 __ptep_ipte(addr
, ptep
);
83 int set_memory_ro(unsigned long addr
, int numpages
)
85 change_page_attr(addr
, numpages
, pte_wrprotect
);
89 int set_memory_rw(unsigned long addr
, int numpages
)
91 change_page_attr(addr
, numpages
, pte_mkwrite
);
96 int set_memory_nx(unsigned long addr
, int numpages
)
101 int set_memory_x(unsigned long addr
, int numpages
)
106 #ifdef CONFIG_DEBUG_PAGEALLOC
108 static void ipte_range(pte_t
*pte
, unsigned long address
, int nr
)
112 if (test_facility(13)) {
113 __ptep_ipte_range(address
, nr
- 1, pte
);
116 for (i
= 0; i
< nr
; i
++) {
117 __ptep_ipte(address
, pte
);
118 address
+= PAGE_SIZE
;
123 void __kernel_map_pages(struct page
*page
, int numpages
, int enable
)
125 unsigned long address
;
132 for (i
= 0; i
< numpages
;) {
133 address
= page_to_phys(page
+ i
);
134 pgd
= pgd_offset_k(address
);
135 pud
= pud_offset(pgd
, address
);
136 pmd
= pmd_offset(pud
, address
);
137 pte
= pte_offset_kernel(pmd
, address
);
138 nr
= (unsigned long)pte
>> ilog2(sizeof(long));
139 nr
= PTRS_PER_PTE
- (nr
& (PTRS_PER_PTE
- 1));
140 nr
= min(numpages
- i
, nr
);
142 for (j
= 0; j
< nr
; j
++) {
143 pte_val(*pte
) = __pa(address
);
144 address
+= PAGE_SIZE
;
148 ipte_range(pte
, address
, nr
);
154 #ifdef CONFIG_HIBERNATION
155 bool kernel_page_present(struct page
*page
)
160 addr
= page_to_phys(page
);
165 : "=d" (cc
), "+a" (addr
) : : "cc");
168 #endif /* CONFIG_HIBERNATION */
170 #endif /* CONFIG_DEBUG_PAGEALLOC */