1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * s390x MMU 4 * 5 * Copyright (c) 2017 Red Hat Inc 6 * 7 * Authors: 8 * David Hildenbrand <david@redhat.com> 9 */ 10 11 #include <libcflat.h> 12 #include <asm/pgtable.h> 13 #include <asm/arch_def.h> 14 #include <asm/barrier.h> 15 #include <vmalloc.h> 16 #include "mmu.h" 17 18 /* 19 * The naming convention used here is the same as used in the Linux kernel; 20 * this is the correspondence between the s390x architectural names and the 21 * Linux ones: 22 * 23 * pgd - region 1 table entry 24 * p4d - region 2 table entry 25 * pud - region 3 table entry 26 * pmd - segment table entry 27 * pte - page table entry 28 */ 29 30 static pgd_t *table_root; 31 32 void configure_dat(int enable) 33 { 34 uint64_t mask; 35 36 if (enable) 37 mask = extract_psw_mask() | PSW_MASK_DAT; 38 else 39 mask = extract_psw_mask() & ~PSW_MASK_DAT; 40 41 load_psw_mask(mask); 42 } 43 44 static void mmu_enable(pgd_t *pgtable) 45 { 46 const uint64_t asce = __pa(pgtable) | ASCE_DT_REGION1 | 47 REGION_TABLE_LENGTH; 48 49 /* set primary asce */ 50 lctlg(1, asce); 51 assert(stctg(1) == asce); 52 53 /* enable dat (primary == 0 set as default) */ 54 configure_dat(1); 55 56 /* we can now also use DAT unconditionally in our PGM handler */ 57 lowcore.pgm_new_psw.mask |= PSW_MASK_DAT; 58 } 59 60 /* 61 * Get the pud (region 3) DAT table entry for the given address and root, 62 * allocating it if necessary 63 */ 64 static inline pud_t *get_pud(pgd_t *pgtable, uintptr_t vaddr) 65 { 66 pgd_t *pgd = pgd_offset(pgtable, vaddr); 67 p4d_t *p4d = p4d_alloc(pgd, vaddr); 68 pud_t *pud = pud_alloc(p4d, vaddr); 69 70 return pud; 71 } 72 73 /* 74 * Get the pmd (segment) DAT table entry for the given address and pud, 75 * allocating it if necessary. 76 * The pud must not be huge. 77 */ 78 static inline pmd_t *get_pmd(pud_t *pud, uintptr_t vaddr) 79 { 80 pmd_t *pmd; 81 82 assert(!pud_huge(*pud)); 83 pmd = pmd_alloc(pud, vaddr); 84 return pmd; 85 } 86 87 /* 88 * Get the pte (page) DAT table entry for the given address and pmd, 89 * allocating it if necessary. 90 * The pmd must not be large. 91 */ 92 static inline pte_t *get_pte(pmd_t *pmd, uintptr_t vaddr) 93 { 94 pte_t *pte; 95 96 assert(!pmd_large(*pmd)); 97 pte = pte_alloc(pmd, vaddr); 98 return pte; 99 } 100 101 /* 102 * Splits a large pmd (segment) DAT table entry into equivalent 4kB small 103 * pages. 104 * @pmd The pmd to split, it must be large. 105 * @va the virtual address corresponding to this pmd. 106 */ 107 static void split_pmd(pmd_t *pmd, uintptr_t va) 108 { 109 phys_addr_t pa = pmd_val(*pmd) & SEGMENT_ENTRY_SFAA; 110 unsigned long i, prot; 111 pte_t *pte; 112 113 assert(pmd_large(*pmd)); 114 pte = alloc_pages(PAGE_TABLE_ORDER); 115 prot = pmd_val(*pmd) & (SEGMENT_ENTRY_IEP | SEGMENT_ENTRY_P); 116 for (i = 0; i < PAGE_TABLE_ENTRIES; i++) 117 pte_val(pte[i]) = pa | PAGE_SIZE * i | prot; 118 idte_pmdp(va, &pmd_val(*pmd)); 119 pmd_val(*pmd) = __pa(pte) | SEGMENT_ENTRY_TT_SEGMENT; 120 121 } 122 123 /* 124 * Splits a huge pud (region 3) DAT table entry into equivalent 1MB large 125 * pages. 126 * @pud The pud to split, it must be huge. 127 * @va the virtual address corresponding to this pud. 128 */ 129 static void split_pud(pud_t *pud, uintptr_t va) 130 { 131 phys_addr_t pa = pud_val(*pud) & REGION3_ENTRY_RFAA; 132 unsigned long i, prot; 133 pmd_t *pmd; 134 135 assert(pud_huge(*pud)); 136 pmd = alloc_pages(SEGMENT_TABLE_ORDER); 137 prot = pud_val(*pud) & (REGION3_ENTRY_IEP | REGION_ENTRY_P); 138 for (i = 0; i < SEGMENT_TABLE_ENTRIES; i++) 139 pmd_val(pmd[i]) = pa | SZ_1M * i | prot | SEGMENT_ENTRY_FC | SEGMENT_ENTRY_TT_SEGMENT; 140 idte_pudp(va, &pud_val(*pud)); 141 pud_val(*pud) = __pa(pmd) | REGION_ENTRY_TT_REGION3 | REGION_TABLE_LENGTH; 142 } 143 144 void *get_dat_entry(pgd_t *pgtable, void *vaddr, enum pgt_level level) 145 { 146 uintptr_t va = (uintptr_t)vaddr; 147 pgd_t *pgd; 148 p4d_t *p4d; 149 pud_t *pud; 150 pmd_t *pmd; 151 152 assert(level && (level <= 5)); 153 pgd = pgd_offset(pgtable, va); 154 if (level == pgtable_level_pgd) 155 return pgd; 156 p4d = p4d_alloc(pgd, va); 157 if (level == pgtable_level_p4d) 158 return p4d; 159 pud = pud_alloc(p4d, va); 160 161 if (level == pgtable_level_pud) 162 return pud; 163 if (!pud_none(*pud) && pud_huge(*pud)) 164 split_pud(pud, va); 165 pmd = get_pmd(pud, va); 166 if (level == pgtable_level_pmd) 167 return pmd; 168 if (!pmd_none(*pmd) && pmd_large(*pmd)) 169 split_pmd(pmd, va); 170 return get_pte(pmd, va); 171 } 172 173 void *split_page(pgd_t *pgtable, void *vaddr, enum pgt_level level) 174 { 175 assert((level >= 3) && (level <= 5)); 176 return get_dat_entry(pgtable ? pgtable : table_root, vaddr, level); 177 } 178 179 phys_addr_t virt_to_pte_phys(pgd_t *pgtable, void *vaddr) 180 { 181 uintptr_t va = (uintptr_t)vaddr; 182 pud_t *pud; 183 pmd_t *pmd; 184 pte_t *pte; 185 186 pud = get_pud(pgtable, va); 187 if (pud_huge(*pud)) 188 return (pud_val(*pud) & REGION3_ENTRY_RFAA) | (va & ~REGION3_ENTRY_RFAA); 189 pmd = get_pmd(pud, va); 190 if (pmd_large(*pmd)) 191 return (pmd_val(*pmd) & SEGMENT_ENTRY_SFAA) | (va & ~SEGMENT_ENTRY_SFAA); 192 pte = get_pte(pmd, va); 193 return (pte_val(*pte) & PAGE_MASK) | (va & ~PAGE_MASK); 194 } 195 196 /* 197 * Get the DAT table entry of the given level for the given address, 198 * splitting if necessary. If the entry was not invalid, invalidate it, and 199 * return the pointer to the entry and, if requested, its old value. 200 * @pgtable root of the page tables 201 * @vaddr virtual address 202 * @level 3 (for 2GB pud), 4 (for 1MB pmd) or 5 (for 4kB pages) 203 * @old if not NULL, will be written with the old value of the DAT table 204 * entry before invalidation 205 */ 206 static void *dat_get_and_invalidate(pgd_t *pgtable, void *vaddr, enum pgt_level level, unsigned long *old) 207 { 208 unsigned long va = (unsigned long)vaddr; 209 void *ptr; 210 211 ptr = get_dat_entry(pgtable, vaddr, level); 212 if (old) 213 *old = *(unsigned long *)ptr; 214 if ((level == pgtable_level_pgd) && !pgd_none(*(pgd_t *)ptr)) 215 idte_pgdp(va, ptr); 216 else if ((level == pgtable_level_p4d) && !p4d_none(*(p4d_t *)ptr)) 217 idte_p4dp(va, ptr); 218 else if ((level == pgtable_level_pud) && !pud_none(*(pud_t *)ptr)) 219 idte_pudp(va, ptr); 220 else if ((level == pgtable_level_pmd) && !pmd_none(*(pmd_t *)ptr)) 221 idte_pmdp(va, ptr); 222 else if (!pte_none(*(pte_t *)ptr)) 223 ipte(va, ptr); 224 return ptr; 225 } 226 227 static void cleanup_pmd(pmd_t *pmd) 228 { 229 /* was invalid or large, nothing to do */ 230 if (pmd_none(*pmd) || pmd_large(*pmd)) 231 return; 232 /* was not large, free the corresponding page table */ 233 free_pages((void *)(pmd_val(*pmd) & PAGE_MASK)); 234 } 235 236 static void cleanup_pud(pud_t *pud) 237 { 238 unsigned long i; 239 pmd_t *pmd; 240 241 /* was invalid or large, nothing to do */ 242 if (pud_none(*pud) || pud_huge(*pud)) 243 return; 244 /* recursively clean up all pmds if needed */ 245 pmd = (pmd_t *)(pud_val(*pud) & PAGE_MASK); 246 for (i = 0; i < SEGMENT_TABLE_ENTRIES; i++) 247 cleanup_pmd(pmd + i); 248 /* free the corresponding segment table */ 249 free_pages(pmd); 250 } 251 252 /* 253 * Set the DAT entry for the given level of the given virtual address. If a 254 * mapping already existed, it is overwritten. If an existing mapping with 255 * smaller pages existed, all the lower tables are freed. 256 * Returns the pointer to the DAT table entry. 257 * @pgtable root of the page tables 258 * @val the new value for the DAT table entry 259 * @vaddr the virtual address 260 * @level 3 for pud (region 3), 4 for pmd (segment) and 5 for pte (pages) 261 */ 262 static void *set_dat_entry(pgd_t *pgtable, unsigned long val, void *vaddr, enum pgt_level level) 263 { 264 unsigned long old, *res; 265 266 res = dat_get_and_invalidate(pgtable, vaddr, level, &old); 267 if (level == pgtable_level_pmd) 268 cleanup_pmd((pmd_t *)&old); 269 if (level == pgtable_level_pud) 270 cleanup_pud((pud_t *)&old); 271 *res = val; 272 return res; 273 } 274 275 pteval_t *install_page(pgd_t *pgtable, phys_addr_t phys, void *vaddr) 276 { 277 assert(IS_ALIGNED(phys, PAGE_SIZE)); 278 assert(IS_ALIGNED((uintptr_t)vaddr, PAGE_SIZE)); 279 return set_dat_entry(pgtable, phys, vaddr, pgtable_level_pte); 280 } 281 282 pmdval_t *install_large_page(pgd_t *pgtable, phys_addr_t phys, void *vaddr) 283 { 284 assert(IS_ALIGNED(phys, SZ_1M)); 285 assert(IS_ALIGNED((uintptr_t)vaddr, SZ_1M)); 286 return set_dat_entry(pgtable, phys | SEGMENT_ENTRY_FC, vaddr, pgtable_level_pmd); 287 } 288 289 pudval_t *install_huge_page(pgd_t *pgtable, phys_addr_t phys, void *vaddr) 290 { 291 assert(IS_ALIGNED(phys, SZ_2G)); 292 assert(IS_ALIGNED((uintptr_t)vaddr, SZ_2G)); 293 return set_dat_entry(pgtable, phys | REGION3_ENTRY_FC | REGION_ENTRY_TT_REGION3, vaddr, pgtable_level_pud); 294 } 295 296 void protect_dat_entry(void *vaddr, unsigned long prot, enum pgt_level level) 297 { 298 unsigned long old, *ptr; 299 300 ptr = dat_get_and_invalidate(table_root, vaddr, level, &old); 301 *ptr = old | prot; 302 } 303 304 void unprotect_dat_entry(void *vaddr, unsigned long prot, enum pgt_level level) 305 { 306 unsigned long old, *ptr; 307 308 ptr = dat_get_and_invalidate(table_root, vaddr, level, &old); 309 *ptr = old & ~prot; 310 } 311 312 void protect_range(void *start, unsigned long len, unsigned long prot) 313 { 314 uintptr_t curr = (uintptr_t)start & PAGE_MASK; 315 316 len &= PAGE_MASK; 317 for (; len; len -= PAGE_SIZE, curr += PAGE_SIZE) 318 protect_dat_entry((void *)curr, prot, 5); 319 } 320 321 void unprotect_range(void *start, unsigned long len, unsigned long prot) 322 { 323 uintptr_t curr = (uintptr_t)start & PAGE_MASK; 324 325 len &= PAGE_MASK; 326 for (; len; len -= PAGE_SIZE, curr += PAGE_SIZE) 327 unprotect_dat_entry((void *)curr, prot, 5); 328 } 329 330 static void setup_identity(pgd_t *pgtable, phys_addr_t start_addr, 331 phys_addr_t end_addr) 332 { 333 phys_addr_t cur; 334 335 start_addr &= PAGE_MASK; 336 for (cur = start_addr; true; cur += PAGE_SIZE) { 337 if (start_addr < end_addr && cur >= end_addr) 338 break; 339 if (start_addr > end_addr && cur <= end_addr) 340 break; 341 install_page(pgtable, cur, __va(cur)); 342 } 343 } 344 345 void *setup_mmu(phys_addr_t phys_end, void *unused) 346 { 347 pgd_t *page_root; 348 349 /* allocate a region-1 table */ 350 page_root = pgd_alloc_one(); 351 352 /* map all physical memory 1:1 */ 353 setup_identity(page_root, 0, phys_end); 354 355 /* generate 128MB of invalid adresses at the end (for testing PGM) */ 356 init_alloc_vpage((void *) -(1UL << 27)); 357 setup_identity(page_root, -(1UL << 27), 0); 358 359 /* finally enable DAT with the new table */ 360 mmu_enable(page_root); 361 table_root = page_root; 362 return page_root; 363 } 364