| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * address space "slices" (meta-segments) support |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 6 | 7 | * Based on hugetlb implementation |
|---|
| 7 | 8 | * |
|---|
| 8 | 9 | * Copyright (C) 2003 David Gibson, IBM Corporation. |
|---|
| 9 | | - * |
|---|
| 10 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 11 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 12 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 13 | | - * (at your option) any later version. |
|---|
| 14 | | - * |
|---|
| 15 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 16 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 17 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 18 | | - * GNU General Public License for more details. |
|---|
| 19 | | - * |
|---|
| 20 | | - * You should have received a copy of the GNU General Public License |
|---|
| 21 | | - * along with this program; if not, write to the Free Software |
|---|
| 22 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 23 | 10 | */ |
|---|
| 24 | 11 | |
|---|
| 25 | 12 | #undef DEBUG |
|---|
| .. | .. |
|---|
| 31 | 18 | #include <linux/spinlock.h> |
|---|
| 32 | 19 | #include <linux/export.h> |
|---|
| 33 | 20 | #include <linux/hugetlb.h> |
|---|
| 21 | +#include <linux/sched/mm.h> |
|---|
| 34 | 22 | #include <linux/security.h> |
|---|
| 35 | 23 | #include <asm/mman.h> |
|---|
| 36 | 24 | #include <asm/mmu.h> |
|---|
| .. | .. |
|---|
| 62 | 50 | |
|---|
| 63 | 51 | #endif |
|---|
| 64 | 52 | |
|---|
| 65 | | -static inline bool slice_addr_is_low(unsigned long addr) |
|---|
| 53 | +static inline notrace bool slice_addr_is_low(unsigned long addr) |
|---|
| 66 | 54 | { |
|---|
| 67 | 55 | u64 tmp = (u64)addr; |
|---|
| 68 | 56 | |
|---|
| .. | .. |
|---|
| 100 | 88 | { |
|---|
| 101 | 89 | struct vm_area_struct *vma; |
|---|
| 102 | 90 | |
|---|
| 103 | | - if ((mm->context.slb_addr_limit - len) < addr) |
|---|
| 91 | + if ((mm_ctx_slb_addr_limit(&mm->context) - len) < addr) |
|---|
| 104 | 92 | return 0; |
|---|
| 105 | 93 | vma = find_vma(mm, addr); |
|---|
| 106 | 94 | return (!vma || (addr + len) <= vm_start_gap(vma)); |
|---|
| .. | .. |
|---|
| 117 | 105 | unsigned long start = slice << SLICE_HIGH_SHIFT; |
|---|
| 118 | 106 | unsigned long end = start + (1ul << SLICE_HIGH_SHIFT); |
|---|
| 119 | 107 | |
|---|
| 120 | | -#ifdef CONFIG_PPC64 |
|---|
| 121 | 108 | /* Hack, so that each addresses is controlled by exactly one |
|---|
| 122 | 109 | * of the high or low area bitmaps, the first high area starts |
|---|
| 123 | 110 | * at 4GB, not 0 */ |
|---|
| 124 | 111 | if (start == 0) |
|---|
| 125 | | - start = SLICE_LOW_TOP; |
|---|
| 126 | | -#endif |
|---|
| 112 | + start = (unsigned long)SLICE_LOW_TOP; |
|---|
| 127 | 113 | |
|---|
| 128 | 114 | return !slice_area_is_free(mm, start, end - start); |
|---|
| 129 | 115 | } |
|---|
| .. | .. |
|---|
| 148 | 134 | if (!slice_high_has_vma(mm, i)) |
|---|
| 149 | 135 | __set_bit(i, ret->high_slices); |
|---|
| 150 | 136 | } |
|---|
| 151 | | - |
|---|
| 152 | | -#ifdef CONFIG_PPC_BOOK3S_64 |
|---|
| 153 | | -static struct slice_mask *slice_mask_for_size(struct mm_struct *mm, int psize) |
|---|
| 154 | | -{ |
|---|
| 155 | | -#ifdef CONFIG_PPC_64K_PAGES |
|---|
| 156 | | - if (psize == MMU_PAGE_64K) |
|---|
| 157 | | - return &mm->context.mask_64k; |
|---|
| 158 | | -#endif |
|---|
| 159 | | - if (psize == MMU_PAGE_4K) |
|---|
| 160 | | - return &mm->context.mask_4k; |
|---|
| 161 | | -#ifdef CONFIG_HUGETLB_PAGE |
|---|
| 162 | | - if (psize == MMU_PAGE_16M) |
|---|
| 163 | | - return &mm->context.mask_16m; |
|---|
| 164 | | - if (psize == MMU_PAGE_16G) |
|---|
| 165 | | - return &mm->context.mask_16g; |
|---|
| 166 | | -#endif |
|---|
| 167 | | - BUG(); |
|---|
| 168 | | -} |
|---|
| 169 | | -#elif defined(CONFIG_PPC_8xx) |
|---|
| 170 | | -static struct slice_mask *slice_mask_for_size(struct mm_struct *mm, int psize) |
|---|
| 171 | | -{ |
|---|
| 172 | | - if (psize == mmu_virtual_psize) |
|---|
| 173 | | - return &mm->context.mask_base_psize; |
|---|
| 174 | | -#ifdef CONFIG_HUGETLB_PAGE |
|---|
| 175 | | - if (psize == MMU_PAGE_512K) |
|---|
| 176 | | - return &mm->context.mask_512k; |
|---|
| 177 | | - if (psize == MMU_PAGE_8M) |
|---|
| 178 | | - return &mm->context.mask_8m; |
|---|
| 179 | | -#endif |
|---|
| 180 | | - BUG(); |
|---|
| 181 | | -} |
|---|
| 182 | | -#else |
|---|
| 183 | | -#error "Must define the slice masks for page sizes supported by the platform" |
|---|
| 184 | | -#endif |
|---|
| 185 | 137 | |
|---|
| 186 | 138 | static bool slice_check_range_fits(struct mm_struct *mm, |
|---|
| 187 | 139 | const struct slice_mask *available, |
|---|
| .. | .. |
|---|
| 227 | 179 | copy_mm_to_paca(current->active_mm); |
|---|
| 228 | 180 | |
|---|
| 229 | 181 | local_irq_save(flags); |
|---|
| 230 | | - slb_flush_and_rebolt(); |
|---|
| 182 | + slb_flush_and_restore_bolted(); |
|---|
| 231 | 183 | local_irq_restore(flags); |
|---|
| 232 | 184 | #endif |
|---|
| 233 | 185 | } |
|---|
| .. | .. |
|---|
| 245 | 197 | slice_dbg("slice_convert(mm=%p, psize=%d)\n", mm, psize); |
|---|
| 246 | 198 | slice_print_mask(" mask", mask); |
|---|
| 247 | 199 | |
|---|
| 248 | | - psize_mask = slice_mask_for_size(mm, psize); |
|---|
| 200 | + psize_mask = slice_mask_for_size(&mm->context, psize); |
|---|
| 249 | 201 | |
|---|
| 250 | 202 | /* We need to use a spinlock here to protect against |
|---|
| 251 | 203 | * concurrent 64k -> 4k demotion ... |
|---|
| 252 | 204 | */ |
|---|
| 253 | 205 | spin_lock_irqsave(&slice_convert_lock, flags); |
|---|
| 254 | 206 | |
|---|
| 255 | | - lpsizes = mm->context.low_slices_psize; |
|---|
| 207 | + lpsizes = mm_ctx_low_slices(&mm->context); |
|---|
| 256 | 208 | for (i = 0; i < SLICE_NUM_LOW; i++) { |
|---|
| 257 | 209 | if (!(mask->low_slices & (1u << i))) |
|---|
| 258 | 210 | continue; |
|---|
| .. | .. |
|---|
| 262 | 214 | |
|---|
| 263 | 215 | /* Update the slice_mask */ |
|---|
| 264 | 216 | old_psize = (lpsizes[index] >> (mask_index * 4)) & 0xf; |
|---|
| 265 | | - old_mask = slice_mask_for_size(mm, old_psize); |
|---|
| 217 | + old_mask = slice_mask_for_size(&mm->context, old_psize); |
|---|
| 266 | 218 | old_mask->low_slices &= ~(1u << i); |
|---|
| 267 | 219 | psize_mask->low_slices |= 1u << i; |
|---|
| 268 | 220 | |
|---|
| .. | .. |
|---|
| 271 | 223 | (((unsigned long)psize) << (mask_index * 4)); |
|---|
| 272 | 224 | } |
|---|
| 273 | 225 | |
|---|
| 274 | | - hpsizes = mm->context.high_slices_psize; |
|---|
| 275 | | - for (i = 0; i < GET_HIGH_SLICE_INDEX(mm->context.slb_addr_limit); i++) { |
|---|
| 226 | + hpsizes = mm_ctx_high_slices(&mm->context); |
|---|
| 227 | + for (i = 0; i < GET_HIGH_SLICE_INDEX(mm_ctx_slb_addr_limit(&mm->context)); i++) { |
|---|
| 276 | 228 | if (!test_bit(i, mask->high_slices)) |
|---|
| 277 | 229 | continue; |
|---|
| 278 | 230 | |
|---|
| .. | .. |
|---|
| 281 | 233 | |
|---|
| 282 | 234 | /* Update the slice_mask */ |
|---|
| 283 | 235 | old_psize = (hpsizes[index] >> (mask_index * 4)) & 0xf; |
|---|
| 284 | | - old_mask = slice_mask_for_size(mm, old_psize); |
|---|
| 236 | + old_mask = slice_mask_for_size(&mm->context, old_psize); |
|---|
| 285 | 237 | __clear_bit(i, old_mask->high_slices); |
|---|
| 286 | 238 | __set_bit(i, psize_mask->high_slices); |
|---|
| 287 | 239 | |
|---|
| .. | .. |
|---|
| 291 | 243 | } |
|---|
| 292 | 244 | |
|---|
| 293 | 245 | slice_dbg(" lsps=%lx, hsps=%lx\n", |
|---|
| 294 | | - (unsigned long)mm->context.low_slices_psize, |
|---|
| 295 | | - (unsigned long)mm->context.high_slices_psize); |
|---|
| 246 | + (unsigned long)mm_ctx_low_slices(&mm->context), |
|---|
| 247 | + (unsigned long)mm_ctx_high_slices(&mm->context)); |
|---|
| 296 | 248 | |
|---|
| 297 | 249 | spin_unlock_irqrestore(&slice_convert_lock, flags); |
|---|
| 298 | 250 | |
|---|
| .. | .. |
|---|
| 392 | 344 | * DEFAULT_MAP_WINDOW we should apply this. |
|---|
| 393 | 345 | */ |
|---|
| 394 | 346 | if (high_limit > DEFAULT_MAP_WINDOW) |
|---|
| 395 | | - addr += mm->context.slb_addr_limit - DEFAULT_MAP_WINDOW; |
|---|
| 347 | + addr += mm_ctx_slb_addr_limit(&mm->context) - DEFAULT_MAP_WINDOW; |
|---|
| 396 | 348 | |
|---|
| 397 | 349 | while (addr > min_addr) { |
|---|
| 398 | 350 | info.high_limit = addr; |
|---|
| .. | .. |
|---|
| 504 | 456 | return -ENOMEM; |
|---|
| 505 | 457 | } |
|---|
| 506 | 458 | |
|---|
| 507 | | - if (high_limit > mm->context.slb_addr_limit) { |
|---|
| 459 | + if (high_limit > mm_ctx_slb_addr_limit(&mm->context)) { |
|---|
| 508 | 460 | /* |
|---|
| 509 | 461 | * Increasing the slb_addr_limit does not require |
|---|
| 510 | 462 | * slice mask cache to be recalculated because it should |
|---|
| 511 | 463 | * be already initialised beyond the old address limit. |
|---|
| 512 | 464 | */ |
|---|
| 513 | | - mm->context.slb_addr_limit = high_limit; |
|---|
| 465 | + mm_ctx_set_slb_addr_limit(&mm->context, high_limit); |
|---|
| 514 | 466 | |
|---|
| 515 | 467 | on_each_cpu(slice_flush_segments, mm, 1); |
|---|
| 516 | 468 | } |
|---|
| 517 | 469 | |
|---|
| 518 | 470 | /* Sanity checks */ |
|---|
| 519 | 471 | BUG_ON(mm->task_size == 0); |
|---|
| 520 | | - BUG_ON(mm->context.slb_addr_limit == 0); |
|---|
| 472 | + BUG_ON(mm_ctx_slb_addr_limit(&mm->context) == 0); |
|---|
| 521 | 473 | VM_BUG_ON(radix_enabled()); |
|---|
| 522 | 474 | |
|---|
| 523 | 475 | slice_dbg("slice_get_unmapped_area(mm=%p, psize=%d...\n", mm, psize); |
|---|
| .. | .. |
|---|
| 526 | 478 | |
|---|
| 527 | 479 | /* If hint, make sure it matches our alignment restrictions */ |
|---|
| 528 | 480 | if (!fixed && addr) { |
|---|
| 529 | | - addr = _ALIGN_UP(addr, page_size); |
|---|
| 481 | + addr = ALIGN(addr, page_size); |
|---|
| 530 | 482 | slice_dbg(" aligned addr=%lx\n", addr); |
|---|
| 531 | 483 | /* Ignore hint if it's too large or overlaps a VMA */ |
|---|
| 532 | 484 | if (addr > high_limit - len || addr < mmap_min_addr || |
|---|
| .. | .. |
|---|
| 537 | 489 | /* First make up a "good" mask of slices that have the right size |
|---|
| 538 | 490 | * already |
|---|
| 539 | 491 | */ |
|---|
| 540 | | - maskp = slice_mask_for_size(mm, psize); |
|---|
| 492 | + maskp = slice_mask_for_size(&mm->context, psize); |
|---|
| 541 | 493 | |
|---|
| 542 | 494 | /* |
|---|
| 543 | 495 | * Here "good" means slices that are already the right page size, |
|---|
| .. | .. |
|---|
| 564 | 516 | * a pointer to good mask for the next code to use. |
|---|
| 565 | 517 | */ |
|---|
| 566 | 518 | if (IS_ENABLED(CONFIG_PPC_64K_PAGES) && psize == MMU_PAGE_64K) { |
|---|
| 567 | | - compat_maskp = slice_mask_for_size(mm, MMU_PAGE_4K); |
|---|
| 519 | + compat_maskp = slice_mask_for_size(&mm->context, MMU_PAGE_4K); |
|---|
| 568 | 520 | if (fixed) |
|---|
| 569 | 521 | slice_or_mask(&good_mask, maskp, compat_maskp); |
|---|
| 570 | 522 | else |
|---|
| .. | .. |
|---|
| 641 | 593 | newaddr = slice_find_area(mm, len, &potential_mask, |
|---|
| 642 | 594 | psize, topdown, high_limit); |
|---|
| 643 | 595 | |
|---|
| 644 | | -#ifdef CONFIG_PPC_64K_PAGES |
|---|
| 645 | | - if (newaddr == -ENOMEM && psize == MMU_PAGE_64K) { |
|---|
| 596 | + if (IS_ENABLED(CONFIG_PPC_64K_PAGES) && newaddr == -ENOMEM && |
|---|
| 597 | + psize == MMU_PAGE_64K) { |
|---|
| 646 | 598 | /* retry the search with 4k-page slices included */ |
|---|
| 647 | 599 | slice_or_mask(&potential_mask, &potential_mask, compat_maskp); |
|---|
| 648 | 600 | newaddr = slice_find_area(mm, len, &potential_mask, |
|---|
| 649 | 601 | psize, topdown, high_limit); |
|---|
| 650 | 602 | } |
|---|
| 651 | | -#endif |
|---|
| 652 | 603 | |
|---|
| 653 | 604 | if (newaddr == -ENOMEM) |
|---|
| 654 | 605 | return -ENOMEM; |
|---|
| .. | .. |
|---|
| 695 | 646 | unsigned long flags) |
|---|
| 696 | 647 | { |
|---|
| 697 | 648 | return slice_get_unmapped_area(addr, len, flags, |
|---|
| 698 | | - current->mm->context.user_psize, 0); |
|---|
| 649 | + mm_ctx_user_psize(¤t->mm->context), 0); |
|---|
| 699 | 650 | } |
|---|
| 700 | 651 | |
|---|
| 701 | 652 | unsigned long arch_get_unmapped_area_topdown(struct file *filp, |
|---|
| .. | .. |
|---|
| 705 | 656 | const unsigned long flags) |
|---|
| 706 | 657 | { |
|---|
| 707 | 658 | return slice_get_unmapped_area(addr0, len, flags, |
|---|
| 708 | | - current->mm->context.user_psize, 1); |
|---|
| 659 | + mm_ctx_user_psize(¤t->mm->context), 1); |
|---|
| 709 | 660 | } |
|---|
| 710 | 661 | |
|---|
| 711 | | -unsigned int get_slice_psize(struct mm_struct *mm, unsigned long addr) |
|---|
| 662 | +unsigned int notrace get_slice_psize(struct mm_struct *mm, unsigned long addr) |
|---|
| 712 | 663 | { |
|---|
| 713 | 664 | unsigned char *psizes; |
|---|
| 714 | 665 | int index, mask_index; |
|---|
| .. | .. |
|---|
| 716 | 667 | VM_BUG_ON(radix_enabled()); |
|---|
| 717 | 668 | |
|---|
| 718 | 669 | if (slice_addr_is_low(addr)) { |
|---|
| 719 | | - psizes = mm->context.low_slices_psize; |
|---|
| 670 | + psizes = mm_ctx_low_slices(&mm->context); |
|---|
| 720 | 671 | index = GET_LOW_SLICE_INDEX(addr); |
|---|
| 721 | 672 | } else { |
|---|
| 722 | | - psizes = mm->context.high_slices_psize; |
|---|
| 673 | + psizes = mm_ctx_high_slices(&mm->context); |
|---|
| 723 | 674 | index = GET_HIGH_SLICE_INDEX(addr); |
|---|
| 724 | 675 | } |
|---|
| 725 | 676 | mask_index = index & 0x1; |
|---|
| .. | .. |
|---|
| 740 | 691 | * case of fork it is just inherited from the mm being |
|---|
| 741 | 692 | * duplicated. |
|---|
| 742 | 693 | */ |
|---|
| 743 | | -#ifdef CONFIG_PPC64 |
|---|
| 744 | | - mm->context.slb_addr_limit = DEFAULT_MAP_WINDOW_USER64; |
|---|
| 745 | | -#else |
|---|
| 746 | | - mm->context.slb_addr_limit = DEFAULT_MAP_WINDOW; |
|---|
| 747 | | -#endif |
|---|
| 748 | | - |
|---|
| 749 | | - mm->context.user_psize = psize; |
|---|
| 694 | + mm_ctx_set_slb_addr_limit(&mm->context, SLB_ADDR_LIMIT_DEFAULT); |
|---|
| 695 | + mm_ctx_set_user_psize(&mm->context, psize); |
|---|
| 750 | 696 | |
|---|
| 751 | 697 | /* |
|---|
| 752 | 698 | * Set all slice psizes to the default. |
|---|
| 753 | 699 | */ |
|---|
| 754 | | - lpsizes = mm->context.low_slices_psize; |
|---|
| 700 | + lpsizes = mm_ctx_low_slices(&mm->context); |
|---|
| 755 | 701 | memset(lpsizes, (psize << 4) | psize, SLICE_NUM_LOW >> 1); |
|---|
| 756 | 702 | |
|---|
| 757 | | - hpsizes = mm->context.high_slices_psize; |
|---|
| 703 | + hpsizes = mm_ctx_high_slices(&mm->context); |
|---|
| 758 | 704 | memset(hpsizes, (psize << 4) | psize, SLICE_NUM_HIGH >> 1); |
|---|
| 759 | 705 | |
|---|
| 760 | 706 | /* |
|---|
| 761 | 707 | * Slice mask cache starts zeroed, fill the default size cache. |
|---|
| 762 | 708 | */ |
|---|
| 763 | | - mask = slice_mask_for_size(mm, psize); |
|---|
| 709 | + mask = slice_mask_for_size(&mm->context, psize); |
|---|
| 764 | 710 | mask->low_slices = ~0UL; |
|---|
| 765 | 711 | if (SLICE_NUM_HIGH) |
|---|
| 766 | 712 | bitmap_fill(mask->high_slices, SLICE_NUM_HIGH); |
|---|
| 767 | 713 | } |
|---|
| 714 | + |
|---|
| 715 | +#ifdef CONFIG_PPC_BOOK3S_64 |
|---|
| 716 | +void slice_setup_new_exec(void) |
|---|
| 717 | +{ |
|---|
| 718 | + struct mm_struct *mm = current->mm; |
|---|
| 719 | + |
|---|
| 720 | + slice_dbg("slice_setup_new_exec(mm=%p)\n", mm); |
|---|
| 721 | + |
|---|
| 722 | + if (!is_32bit_task()) |
|---|
| 723 | + return; |
|---|
| 724 | + |
|---|
| 725 | + mm_ctx_set_slb_addr_limit(&mm->context, DEFAULT_MAP_WINDOW); |
|---|
| 726 | +} |
|---|
| 727 | +#endif |
|---|
| 768 | 728 | |
|---|
| 769 | 729 | void slice_set_range_psize(struct mm_struct *mm, unsigned long start, |
|---|
| 770 | 730 | unsigned long len, unsigned int psize) |
|---|
| .. | .. |
|---|
| 801 | 761 | unsigned long len) |
|---|
| 802 | 762 | { |
|---|
| 803 | 763 | const struct slice_mask *maskp; |
|---|
| 804 | | - unsigned int psize = mm->context.user_psize; |
|---|
| 764 | + unsigned int psize = mm_ctx_user_psize(&mm->context); |
|---|
| 805 | 765 | |
|---|
| 806 | 766 | VM_BUG_ON(radix_enabled()); |
|---|
| 807 | 767 | |
|---|
| 808 | | - maskp = slice_mask_for_size(mm, psize); |
|---|
| 809 | | -#ifdef CONFIG_PPC_64K_PAGES |
|---|
| 768 | + maskp = slice_mask_for_size(&mm->context, psize); |
|---|
| 769 | + |
|---|
| 810 | 770 | /* We need to account for 4k slices too */ |
|---|
| 811 | | - if (psize == MMU_PAGE_64K) { |
|---|
| 771 | + if (IS_ENABLED(CONFIG_PPC_64K_PAGES) && psize == MMU_PAGE_64K) { |
|---|
| 812 | 772 | const struct slice_mask *compat_maskp; |
|---|
| 813 | 773 | struct slice_mask available; |
|---|
| 814 | 774 | |
|---|
| 815 | | - compat_maskp = slice_mask_for_size(mm, MMU_PAGE_4K); |
|---|
| 775 | + compat_maskp = slice_mask_for_size(&mm->context, MMU_PAGE_4K); |
|---|
| 816 | 776 | slice_or_mask(&available, maskp, compat_maskp); |
|---|
| 817 | 777 | return !slice_check_range_fits(mm, &available, addr, len); |
|---|
| 818 | 778 | } |
|---|
| 819 | | -#endif |
|---|
| 820 | 779 | |
|---|
| 821 | 780 | return !slice_check_range_fits(mm, maskp, addr, len); |
|---|
| 822 | 781 | } |
|---|