Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.14 146 lines 3.0 kB view raw
1/* 2 * Copyright IBM Corp. 2011 3 * Author(s): Jan Glauber <jang@linux.vnet.ibm.com> 4 */ 5#include <linux/hugetlb.h> 6#include <linux/module.h> 7#include <linux/mm.h> 8#include <asm/cacheflush.h> 9#include <asm/pgtable.h> 10#include <asm/page.h> 11 12#if PAGE_DEFAULT_KEY 13static inline unsigned long sske_frame(unsigned long addr, unsigned char skey) 14{ 15 asm volatile(".insn rrf,0xb22b0000,%[skey],%[addr],9,0" 16 : [addr] "+a" (addr) : [skey] "d" (skey)); 17 return addr; 18} 19 20void __storage_key_init_range(unsigned long start, unsigned long end) 21{ 22 unsigned long boundary, size; 23 24 while (start < end) { 25 if (MACHINE_HAS_EDAT1) { 26 /* set storage keys for a 1MB frame */ 27 size = 1UL << 20; 28 boundary = (start + size) & ~(size - 1); 29 if (boundary <= end) { 30 do { 31 start = sske_frame(start, PAGE_DEFAULT_KEY); 32 } while (start < boundary); 33 continue; 34 } 35 } 36 page_set_storage_key(start, PAGE_DEFAULT_KEY, 0); 37 start += PAGE_SIZE; 38 } 39} 40#endif 41 42static pte_t *walk_page_table(unsigned long addr) 43{ 44 pgd_t *pgdp; 45 pud_t *pudp; 46 pmd_t *pmdp; 47 pte_t *ptep; 48 49 pgdp = pgd_offset_k(addr); 50 if (pgd_none(*pgdp)) 51 return NULL; 52 pudp = pud_offset(pgdp, addr); 53 if (pud_none(*pudp) || pud_large(*pudp)) 54 return NULL; 55 pmdp = pmd_offset(pudp, addr); 56 if (pmd_none(*pmdp) || pmd_large(*pmdp)) 57 return NULL; 58 ptep = pte_offset_kernel(pmdp, addr); 59 if (pte_none(*ptep)) 60 return NULL; 61 return ptep; 62} 63 64static void change_page_attr(unsigned long addr, int numpages, 65 pte_t (*set) (pte_t)) 66{ 67 pte_t *ptep, pte; 68 int i; 69 70 for (i = 0; i < numpages; i++) { 71 ptep = walk_page_table(addr); 72 if (WARN_ON_ONCE(!ptep)) 73 break; 74 pte = *ptep; 75 pte = set(pte); 76 __ptep_ipte(addr, ptep); 77 *ptep = pte; 78 addr += PAGE_SIZE; 79 } 80} 81 82int set_memory_ro(unsigned long addr, int numpages) 83{ 84 change_page_attr(addr, numpages, pte_wrprotect); 85 return 0; 86} 87 88int set_memory_rw(unsigned long addr, int numpages) 89{ 90 change_page_attr(addr, numpages, pte_mkwrite); 91 return 0; 92} 93 94/* not possible */ 95int set_memory_nx(unsigned long addr, int numpages) 96{ 97 return 0; 98} 99 100int set_memory_x(unsigned long addr, int numpages) 101{ 102 return 0; 103} 104 105#ifdef CONFIG_DEBUG_PAGEALLOC 106void kernel_map_pages(struct page *page, int numpages, int enable) 107{ 108 unsigned long address; 109 pgd_t *pgd; 110 pud_t *pud; 111 pmd_t *pmd; 112 pte_t *pte; 113 int i; 114 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); 121 if (!enable) { 122 __ptep_ipte(address, pte); 123 pte_val(*pte) = _PAGE_INVALID; 124 continue; 125 } 126 pte_val(*pte) = __pa(address); 127 } 128} 129 130#ifdef CONFIG_HIBERNATION 131bool kernel_page_present(struct page *page) 132{ 133 unsigned long addr; 134 int cc; 135 136 addr = page_to_phys(page); 137 asm volatile( 138 " lra %1,0(%1)\n" 139 " ipm %0\n" 140 " srl %0,28" 141 : "=d" (cc), "+a" (addr) : : "cc"); 142 return cc == 0; 143} 144#endif /* CONFIG_HIBERNATION */ 145 146#endif /* CONFIG_DEBUG_PAGEALLOC */