12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
29b081e10SChristophe Leroy /*
39b081e10SChristophe Leroy * PowerPC version
49b081e10SChristophe Leroy * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
59b081e10SChristophe Leroy *
69b081e10SChristophe Leroy * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
79b081e10SChristophe Leroy * and Cort Dougan (PReP) (cort@cs.nmt.edu)
89b081e10SChristophe Leroy * Copyright (C) 1996 Paul Mackerras
99b081e10SChristophe Leroy *
109b081e10SChristophe Leroy * Derived from "arch/i386/mm/init.c"
119b081e10SChristophe Leroy * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
129b081e10SChristophe Leroy *
139b081e10SChristophe Leroy * Dave Engebretsen <engebret@us.ibm.com>
149b081e10SChristophe Leroy * Rework for PPC64 port.
159b081e10SChristophe Leroy */
169b081e10SChristophe Leroy
179b081e10SChristophe Leroy #undef DEBUG
189b081e10SChristophe Leroy
199b081e10SChristophe Leroy #include <linux/string.h>
20ca5999fdSMike Rapoport #include <linux/pgtable.h>
2165fddcfcSMike Rapoport #include <asm/pgalloc.h>
2269795cabSChristophe Leroy #include <asm/kup.h>
2367548622SChristophe Leroy #include <asm/smp.h>
2469795cabSChristophe Leroy
254ed47dbeSJason Yan phys_addr_t memstart_addr __ro_after_init = (phys_addr_t)~0ull;
264ed47dbeSJason Yan EXPORT_SYMBOL_GPL(memstart_addr);
274ed47dbeSJason Yan phys_addr_t kernstart_addr __ro_after_init;
284ed47dbeSJason Yan EXPORT_SYMBOL_GPL(kernstart_addr);
2939f4b7bfSJason Yan unsigned long kernstart_virt_addr __ro_after_init = KERNELBASE;
3039f4b7bfSJason Yan EXPORT_SYMBOL_GPL(kernstart_virt_addr);
314ed47dbeSJason Yan
3261130e20SAneesh Kumar K.V bool disable_kuep = !IS_ENABLED(CONFIG_PPC_KUEP);
3361130e20SAneesh Kumar K.V bool disable_kuap = !IS_ENABLED(CONFIG_PPC_KUAP);
34353d7a84SHari Bathini #ifdef CONFIG_KFENCE
35353d7a84SHari Bathini bool __ro_after_init kfence_disabled;
36353d7a84SHari Bathini #endif
370fb1c25aSChristophe Leroy
parse_nosmep(char * p)380fb1c25aSChristophe Leroy static int __init parse_nosmep(char *p)
390fb1c25aSChristophe Leroy {
4067548622SChristophe Leroy if (!IS_ENABLED(CONFIG_PPC_BOOK3S_64))
4167548622SChristophe Leroy return 0;
4267548622SChristophe Leroy
430fb1c25aSChristophe Leroy disable_kuep = true;
440fb1c25aSChristophe Leroy pr_warn("Disabling Kernel Userspace Execution Prevention\n");
450fb1c25aSChristophe Leroy return 0;
460fb1c25aSChristophe Leroy }
470fb1c25aSChristophe Leroy early_param("nosmep", parse_nosmep);
480fb1c25aSChristophe Leroy
parse_nosmap(char * p)49de78a9c4SChristophe Leroy static int __init parse_nosmap(char *p)
50de78a9c4SChristophe Leroy {
51de78a9c4SChristophe Leroy disable_kuap = true;
52de78a9c4SChristophe Leroy pr_warn("Disabling Kernel Userspace Access Protection\n");
53de78a9c4SChristophe Leroy return 0;
54de78a9c4SChristophe Leroy }
55de78a9c4SChristophe Leroy early_param("nosmap", parse_nosmap);
56de78a9c4SChristophe Leroy
setup_kuep(bool disabled)5767548622SChristophe Leroy void __weak setup_kuep(bool disabled)
5867548622SChristophe Leroy {
5967548622SChristophe Leroy if (!IS_ENABLED(CONFIG_PPC_KUEP) || disabled)
6067548622SChristophe Leroy return;
6167548622SChristophe Leroy
6267548622SChristophe Leroy if (smp_processor_id() != boot_cpuid)
6367548622SChristophe Leroy return;
6467548622SChristophe Leroy
6567548622SChristophe Leroy pr_info("Activating Kernel Userspace Execution Prevention\n");
6667548622SChristophe Leroy }
6767548622SChristophe Leroy
setup_kup(void)686c1fa60dSChristophe Leroy void setup_kup(void)
696c1fa60dSChristophe Leroy {
706c1fa60dSChristophe Leroy setup_kuap(disable_kuap);
716c1fa60dSChristophe Leroy setup_kuep(disable_kuep);
726c1fa60dSChristophe Leroy }
736c1fa60dSChristophe Leroy
741e03c7e2SChristophe Leroy #define CTOR(shift) static void ctor_##shift(void *addr) \
751e03c7e2SChristophe Leroy { \
76*e7a9af8cSChristophe Leroy memset(addr, 0, sizeof(pgd_t) << (shift)); \
779b081e10SChristophe Leroy }
789b081e10SChristophe Leroy
791e03c7e2SChristophe Leroy CTOR(0); CTOR(1); CTOR(2); CTOR(3); CTOR(4); CTOR(5); CTOR(6); CTOR(7);
801e03c7e2SChristophe Leroy CTOR(8); CTOR(9); CTOR(10); CTOR(11); CTOR(12); CTOR(13); CTOR(14); CTOR(15);
819b081e10SChristophe Leroy
ctor(int shift)821e03c7e2SChristophe Leroy static inline void (*ctor(int shift))(void *)
839b081e10SChristophe Leroy {
841e03c7e2SChristophe Leroy BUILD_BUG_ON(MAX_PGTABLE_INDEX_SIZE != 15);
851e03c7e2SChristophe Leroy
861e03c7e2SChristophe Leroy switch (shift) {
871e03c7e2SChristophe Leroy case 0: return ctor_0;
881e03c7e2SChristophe Leroy case 1: return ctor_1;
891e03c7e2SChristophe Leroy case 2: return ctor_2;
901e03c7e2SChristophe Leroy case 3: return ctor_3;
911e03c7e2SChristophe Leroy case 4: return ctor_4;
921e03c7e2SChristophe Leroy case 5: return ctor_5;
931e03c7e2SChristophe Leroy case 6: return ctor_6;
941e03c7e2SChristophe Leroy case 7: return ctor_7;
951e03c7e2SChristophe Leroy case 8: return ctor_8;
961e03c7e2SChristophe Leroy case 9: return ctor_9;
971e03c7e2SChristophe Leroy case 10: return ctor_10;
981e03c7e2SChristophe Leroy case 11: return ctor_11;
991e03c7e2SChristophe Leroy case 12: return ctor_12;
1001e03c7e2SChristophe Leroy case 13: return ctor_13;
1011e03c7e2SChristophe Leroy case 14: return ctor_14;
1021e03c7e2SChristophe Leroy case 15: return ctor_15;
1031e03c7e2SChristophe Leroy }
1041e03c7e2SChristophe Leroy return NULL;
1059b081e10SChristophe Leroy }
1069b081e10SChristophe Leroy
107129dd323SChristophe Leroy struct kmem_cache *pgtable_cache[MAX_PGTABLE_INDEX_SIZE + 1];
108ba9b399aSPaul Mackerras EXPORT_SYMBOL_GPL(pgtable_cache); /* used by kvm_hv module */
1099b081e10SChristophe Leroy
1109b081e10SChristophe Leroy /*
1119b081e10SChristophe Leroy * Create a kmem_cache() for pagetables. This is not used for PTE
1129b081e10SChristophe Leroy * pages - they're linked to struct page, come from the normal free
1139b081e10SChristophe Leroy * pages pool and have a different entry size (see real_pte_t) to
1149b081e10SChristophe Leroy * everything else. Caches created by this function are used for all
1159b081e10SChristophe Leroy * the higher level pagetables, and for hugepage pagetables.
1169b081e10SChristophe Leroy */
pgtable_cache_add(unsigned int shift)1171e03c7e2SChristophe Leroy void pgtable_cache_add(unsigned int shift)
1189b081e10SChristophe Leroy {
1199b081e10SChristophe Leroy char *name;
120*e7a9af8cSChristophe Leroy unsigned long table_size = sizeof(pgd_t) << shift;
1219b081e10SChristophe Leroy unsigned long align = table_size;
1229b081e10SChristophe Leroy
1239b081e10SChristophe Leroy /* When batching pgtable pointers for RCU freeing, we store
1249b081e10SChristophe Leroy * the index size in the low bits. Table alignment must be
1259b081e10SChristophe Leroy * big enough to fit it.
1260c22e4b2SChristophe Leroy */
1270c22e4b2SChristophe Leroy unsigned long minalign = MAX_PGTABLE_INDEX_SIZE + 1;
128f46c8a75SKunwu Chan struct kmem_cache *new = NULL;
1299b081e10SChristophe Leroy
1309b081e10SChristophe Leroy /* It would be nice if this was a BUILD_BUG_ON(), but at the
1319b081e10SChristophe Leroy * moment, gcc doesn't seem to recognize is_power_of_2 as a
1329b081e10SChristophe Leroy * constant expression, so so much for that. */
1339b081e10SChristophe Leroy BUG_ON(!is_power_of_2(minalign));
134129dd323SChristophe Leroy BUG_ON(shift > MAX_PGTABLE_INDEX_SIZE);
1359b081e10SChristophe Leroy
1369b081e10SChristophe Leroy if (PGT_CACHE(shift))
1379b081e10SChristophe Leroy return; /* Already have a cache of this size */
1389b081e10SChristophe Leroy
1399b081e10SChristophe Leroy align = max_t(unsigned long, align, minalign);
1409b081e10SChristophe Leroy name = kasprintf(GFP_KERNEL, "pgtable-2^%d", shift);
141f46c8a75SKunwu Chan if (name)
1421e03c7e2SChristophe Leroy new = kmem_cache_create(name, table_size, align, 0, ctor(shift));
143bf5ca68dSNicholas Piggin if (!new)
144bf5ca68dSNicholas Piggin panic("Could not allocate pgtable cache for order %d", shift);
145bf5ca68dSNicholas Piggin
1469b081e10SChristophe Leroy kfree(name);
147129dd323SChristophe Leroy pgtable_cache[shift] = new;
148bf5ca68dSNicholas Piggin
1499b081e10SChristophe Leroy pr_debug("Allocated pgtable cache for order %d\n", shift);
1509b081e10SChristophe Leroy }
151ba9b399aSPaul Mackerras EXPORT_SYMBOL_GPL(pgtable_cache_add); /* used by kvm_hv module */
1529b081e10SChristophe Leroy
pgtable_cache_init(void)1539b081e10SChristophe Leroy void pgtable_cache_init(void)
1549b081e10SChristophe Leroy {
1551e03c7e2SChristophe Leroy pgtable_cache_add(PGD_INDEX_SIZE);
1569b081e10SChristophe Leroy
15732bff4b9SChristophe Leroy if (PMD_CACHE_INDEX)
1581e03c7e2SChristophe Leroy pgtable_cache_add(PMD_CACHE_INDEX);
1599b081e10SChristophe Leroy /*
1609b081e10SChristophe Leroy * In all current configs, when the PUD index exists it's the
1619b081e10SChristophe Leroy * same size as either the pgd or pmd index except with THP enabled
1629b081e10SChristophe Leroy * on book3s 64
1639b081e10SChristophe Leroy */
16432bff4b9SChristophe Leroy if (PUD_CACHE_INDEX)
1651e03c7e2SChristophe Leroy pgtable_cache_add(PUD_CACHE_INDEX);
1669b081e10SChristophe Leroy }
167