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>
13 static inline unsigned long sske_frame(unsigned long addr
, unsigned char skey
)
15 asm volatile(".insn rrf,0xb22b0000,%[skey],%[addr],9,0"
16 : [addr
] "+a" (addr
) : [skey
] "d" (skey
));
20 void __storage_key_init_range(unsigned long start
, unsigned long end
)
22 unsigned long boundary
, size
;
25 if (MACHINE_HAS_EDAT1
) {
26 /* set storage keys for a 1MB frame */
28 boundary
= (start
+ size
) & ~(size
- 1);
29 if (boundary
<= end
) {
31 start
= sske_frame(start
, PAGE_DEFAULT_KEY
);
32 } while (start
< boundary
);
36 page_set_storage_key(start
, PAGE_DEFAULT_KEY
, 0);
42 static pte_t
*walk_page_table(unsigned long addr
)
49 pgdp
= pgd_offset_k(addr
);
52 pudp
= pud_offset(pgdp
, addr
);
53 if (pud_none(*pudp
) || pud_large(*pudp
))
55 pmdp
= pmd_offset(pudp
, addr
);
56 if (pmd_none(*pmdp
) || pmd_large(*pmdp
))
58 ptep
= pte_offset_kernel(pmdp
, addr
);
64 static void change_page_attr(unsigned long addr
, int numpages
,
70 for (i
= 0; i
< numpages
; i
++) {
71 ptep
= walk_page_table(addr
);
72 if (WARN_ON_ONCE(!ptep
))
76 __ptep_ipte(addr
, ptep
);
82 int set_memory_ro(unsigned long addr
, int numpages
)
84 change_page_attr(addr
, numpages
, pte_wrprotect
);
88 int set_memory_rw(unsigned long addr
, int numpages
)
90 change_page_attr(addr
, numpages
, pte_mkwrite
);
95 int set_memory_nx(unsigned long addr
, int numpages
)
100 int set_memory_x(unsigned long addr
, int numpages
)
105 #ifdef CONFIG_DEBUG_PAGEALLOC
106 void kernel_map_pages(struct page
*page
, int numpages
, int enable
)
108 unsigned long address
;
115 for (i
= 0; i
< numpages
; i
++) {
116 address
= page_to_phys(page
+ i
);
117 pgd
= pgd_offset_k(address
);
118 pud
= pud_offset(pgd
, address
);
119 pmd
= pmd_offset(pud
, address
);
120 pte
= pte_offset_kernel(pmd
, address
);
122 __ptep_ipte(address
, pte
);
123 pte_val(*pte
) = _PAGE_INVALID
;
126 pte_val(*pte
) = __pa(address
);
130 #ifdef CONFIG_HIBERNATION
131 bool kernel_page_present(struct page
*page
)
136 addr
= page_to_phys(page
);
141 : "=d" (cc
), "+a" (addr
) : : "cc");
144 #endif /* CONFIG_HIBERNATION */
146 #endif /* CONFIG_DEBUG_PAGEALLOC */