xref: /linux/arch/powerpc/mm/init-common.c (revision 810996a36309a56a39b406d9ad2903115714228f)
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