.. | .. |
---|
| 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 | } |
---|