xref: /linux/arch/powerpc/mm/init-common.c (revision ca5999fde0a1761665a38e4c9a72dbcd7d190a81)
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>
209b081e10SChristophe Leroy #include <asm/pgalloc.h>
21*ca5999fdSMike Rapoport #include <linux/pgtable.h>
2269795cabSChristophe Leroy #include <asm/kup.h>
2369795cabSChristophe Leroy 
244ed47dbeSJason Yan phys_addr_t memstart_addr __ro_after_init = (phys_addr_t)~0ull;
254ed47dbeSJason Yan EXPORT_SYMBOL_GPL(memstart_addr);
264ed47dbeSJason Yan phys_addr_t kernstart_addr __ro_after_init;
274ed47dbeSJason Yan EXPORT_SYMBOL_GPL(kernstart_addr);
2839f4b7bfSJason Yan unsigned long kernstart_virt_addr __ro_after_init = KERNELBASE;
2939f4b7bfSJason Yan EXPORT_SYMBOL_GPL(kernstart_virt_addr);
304ed47dbeSJason Yan 
310fb1c25aSChristophe Leroy static bool disable_kuep = !IS_ENABLED(CONFIG_PPC_KUEP);
32de78a9c4SChristophe Leroy static bool disable_kuap = !IS_ENABLED(CONFIG_PPC_KUAP);
330fb1c25aSChristophe Leroy 
340fb1c25aSChristophe Leroy static int __init parse_nosmep(char *p)
350fb1c25aSChristophe Leroy {
360fb1c25aSChristophe Leroy 	disable_kuep = true;
370fb1c25aSChristophe Leroy 	pr_warn("Disabling Kernel Userspace Execution Prevention\n");
380fb1c25aSChristophe Leroy 	return 0;
390fb1c25aSChristophe Leroy }
400fb1c25aSChristophe Leroy early_param("nosmep", parse_nosmep);
410fb1c25aSChristophe Leroy 
42de78a9c4SChristophe Leroy static int __init parse_nosmap(char *p)
43de78a9c4SChristophe Leroy {
44de78a9c4SChristophe Leroy 	disable_kuap = true;
45de78a9c4SChristophe Leroy 	pr_warn("Disabling Kernel Userspace Access Protection\n");
46de78a9c4SChristophe Leroy 	return 0;
47de78a9c4SChristophe Leroy }
48de78a9c4SChristophe Leroy early_param("nosmap", parse_nosmap);
49de78a9c4SChristophe Leroy 
5067d53f30SChristophe Leroy void __ref setup_kup(void)
5169795cabSChristophe Leroy {
520fb1c25aSChristophe Leroy 	setup_kuep(disable_kuep);
53de78a9c4SChristophe Leroy 	setup_kuap(disable_kuap);
5469795cabSChristophe Leroy }
559b081e10SChristophe Leroy 
561e03c7e2SChristophe Leroy #define CTOR(shift) static void ctor_##shift(void *addr) \
571e03c7e2SChristophe Leroy {							\
581e03c7e2SChristophe Leroy 	memset(addr, 0, sizeof(void *) << (shift));	\
599b081e10SChristophe Leroy }
609b081e10SChristophe Leroy 
611e03c7e2SChristophe Leroy CTOR(0); CTOR(1); CTOR(2); CTOR(3); CTOR(4); CTOR(5); CTOR(6); CTOR(7);
621e03c7e2SChristophe Leroy CTOR(8); CTOR(9); CTOR(10); CTOR(11); CTOR(12); CTOR(13); CTOR(14); CTOR(15);
639b081e10SChristophe Leroy 
641e03c7e2SChristophe Leroy static inline void (*ctor(int shift))(void *)
659b081e10SChristophe Leroy {
661e03c7e2SChristophe Leroy 	BUILD_BUG_ON(MAX_PGTABLE_INDEX_SIZE != 15);
671e03c7e2SChristophe Leroy 
681e03c7e2SChristophe Leroy 	switch (shift) {
691e03c7e2SChristophe Leroy 	case 0: return ctor_0;
701e03c7e2SChristophe Leroy 	case 1: return ctor_1;
711e03c7e2SChristophe Leroy 	case 2: return ctor_2;
721e03c7e2SChristophe Leroy 	case 3: return ctor_3;
731e03c7e2SChristophe Leroy 	case 4: return ctor_4;
741e03c7e2SChristophe Leroy 	case 5: return ctor_5;
751e03c7e2SChristophe Leroy 	case 6: return ctor_6;
761e03c7e2SChristophe Leroy 	case 7: return ctor_7;
771e03c7e2SChristophe Leroy 	case 8: return ctor_8;
781e03c7e2SChristophe Leroy 	case 9: return ctor_9;
791e03c7e2SChristophe Leroy 	case 10: return ctor_10;
801e03c7e2SChristophe Leroy 	case 11: return ctor_11;
811e03c7e2SChristophe Leroy 	case 12: return ctor_12;
821e03c7e2SChristophe Leroy 	case 13: return ctor_13;
831e03c7e2SChristophe Leroy 	case 14: return ctor_14;
841e03c7e2SChristophe Leroy 	case 15: return ctor_15;
851e03c7e2SChristophe Leroy 	}
861e03c7e2SChristophe Leroy 	return NULL;
879b081e10SChristophe Leroy }
889b081e10SChristophe Leroy 
89129dd323SChristophe Leroy struct kmem_cache *pgtable_cache[MAX_PGTABLE_INDEX_SIZE + 1];
90ba9b399aSPaul Mackerras EXPORT_SYMBOL_GPL(pgtable_cache);	/* used by kvm_hv module */
919b081e10SChristophe Leroy 
929b081e10SChristophe Leroy /*
939b081e10SChristophe Leroy  * Create a kmem_cache() for pagetables.  This is not used for PTE
949b081e10SChristophe Leroy  * pages - they're linked to struct page, come from the normal free
959b081e10SChristophe Leroy  * pages pool and have a different entry size (see real_pte_t) to
969b081e10SChristophe Leroy  * everything else.  Caches created by this function are used for all
979b081e10SChristophe Leroy  * the higher level pagetables, and for hugepage pagetables.
989b081e10SChristophe Leroy  */
991e03c7e2SChristophe Leroy void pgtable_cache_add(unsigned int shift)
1009b081e10SChristophe Leroy {
1019b081e10SChristophe Leroy 	char *name;
1029b081e10SChristophe Leroy 	unsigned long table_size = sizeof(void *) << shift;
1039b081e10SChristophe Leroy 	unsigned long align = table_size;
1049b081e10SChristophe Leroy 
1059b081e10SChristophe Leroy 	/* When batching pgtable pointers for RCU freeing, we store
1069b081e10SChristophe Leroy 	 * the index size in the low bits.  Table alignment must be
1079b081e10SChristophe Leroy 	 * big enough to fit it.
1089b081e10SChristophe Leroy 	 *
1099b081e10SChristophe Leroy 	 * Likewise, hugeapge pagetable pointers contain a (different)
1109b081e10SChristophe Leroy 	 * shift value in the low bits.  All tables must be aligned so
1119b081e10SChristophe Leroy 	 * as to leave enough 0 bits in the address to contain it. */
1129b081e10SChristophe Leroy 	unsigned long minalign = max(MAX_PGTABLE_INDEX_SIZE + 1,
1139b081e10SChristophe Leroy 				     HUGEPD_SHIFT_MASK + 1);
1149b081e10SChristophe Leroy 	struct kmem_cache *new;
1159b081e10SChristophe Leroy 
1169b081e10SChristophe Leroy 	/* It would be nice if this was a BUILD_BUG_ON(), but at the
1179b081e10SChristophe Leroy 	 * moment, gcc doesn't seem to recognize is_power_of_2 as a
1189b081e10SChristophe Leroy 	 * constant expression, so so much for that. */
1199b081e10SChristophe Leroy 	BUG_ON(!is_power_of_2(minalign));
120129dd323SChristophe Leroy 	BUG_ON(shift > MAX_PGTABLE_INDEX_SIZE);
1219b081e10SChristophe Leroy 
1229b081e10SChristophe Leroy 	if (PGT_CACHE(shift))
1239b081e10SChristophe Leroy 		return; /* Already have a cache of this size */
1249b081e10SChristophe Leroy 
1259b081e10SChristophe Leroy 	align = max_t(unsigned long, align, minalign);
1269b081e10SChristophe Leroy 	name = kasprintf(GFP_KERNEL, "pgtable-2^%d", shift);
1271e03c7e2SChristophe Leroy 	new = kmem_cache_create(name, table_size, align, 0, ctor(shift));
128bf5ca68dSNicholas Piggin 	if (!new)
129bf5ca68dSNicholas Piggin 		panic("Could not allocate pgtable cache for order %d", shift);
130bf5ca68dSNicholas Piggin 
1319b081e10SChristophe Leroy 	kfree(name);
132129dd323SChristophe Leroy 	pgtable_cache[shift] = new;
133bf5ca68dSNicholas Piggin 
1349b081e10SChristophe Leroy 	pr_debug("Allocated pgtable cache for order %d\n", shift);
1359b081e10SChristophe Leroy }
136ba9b399aSPaul Mackerras EXPORT_SYMBOL_GPL(pgtable_cache_add);	/* used by kvm_hv module */
1379b081e10SChristophe Leroy 
1389b081e10SChristophe Leroy void pgtable_cache_init(void)
1399b081e10SChristophe Leroy {
1401e03c7e2SChristophe Leroy 	pgtable_cache_add(PGD_INDEX_SIZE);
1419b081e10SChristophe Leroy 
14232bff4b9SChristophe Leroy 	if (PMD_CACHE_INDEX)
1431e03c7e2SChristophe Leroy 		pgtable_cache_add(PMD_CACHE_INDEX);
1449b081e10SChristophe Leroy 	/*
1459b081e10SChristophe Leroy 	 * In all current configs, when the PUD index exists it's the
1469b081e10SChristophe Leroy 	 * same size as either the pgd or pmd index except with THP enabled
1479b081e10SChristophe Leroy 	 * on book3s 64
1489b081e10SChristophe Leroy 	 */
14932bff4b9SChristophe Leroy 	if (PUD_CACHE_INDEX)
1501e03c7e2SChristophe Leroy 		pgtable_cache_add(PUD_CACHE_INDEX);
1519b081e10SChristophe Leroy }
152