162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * PowerPC version 462306a36Sopenharmony_ci * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) 762306a36Sopenharmony_ci * and Cort Dougan (PReP) (cort@cs.nmt.edu) 862306a36Sopenharmony_ci * Copyright (C) 1996 Paul Mackerras 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Derived from "arch/i386/mm/init.c" 1162306a36Sopenharmony_ci * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Dave Engebretsen <engebret@us.ibm.com> 1462306a36Sopenharmony_ci * Rework for PPC64 port. 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#undef DEBUG 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <linux/string.h> 2062306a36Sopenharmony_ci#include <linux/pgtable.h> 2162306a36Sopenharmony_ci#include <asm/pgalloc.h> 2262306a36Sopenharmony_ci#include <asm/kup.h> 2362306a36Sopenharmony_ci#include <asm/smp.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ciphys_addr_t memstart_addr __ro_after_init = (phys_addr_t)~0ull; 2662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(memstart_addr); 2762306a36Sopenharmony_ciphys_addr_t kernstart_addr __ro_after_init; 2862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kernstart_addr); 2962306a36Sopenharmony_ciunsigned long kernstart_virt_addr __ro_after_init = KERNELBASE; 3062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kernstart_virt_addr); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cibool disable_kuep = !IS_ENABLED(CONFIG_PPC_KUEP); 3362306a36Sopenharmony_cibool disable_kuap = !IS_ENABLED(CONFIG_PPC_KUAP); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic int __init parse_nosmep(char *p) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_PPC_BOOK3S_64)) 3862306a36Sopenharmony_ci return 0; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci disable_kuep = true; 4162306a36Sopenharmony_ci pr_warn("Disabling Kernel Userspace Execution Prevention\n"); 4262306a36Sopenharmony_ci return 0; 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ciearly_param("nosmep", parse_nosmep); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic int __init parse_nosmap(char *p) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci disable_kuap = true; 4962306a36Sopenharmony_ci pr_warn("Disabling Kernel Userspace Access Protection\n"); 5062306a36Sopenharmony_ci return 0; 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ciearly_param("nosmap", parse_nosmap); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_civoid __weak setup_kuep(bool disabled) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_PPC_KUEP) || disabled) 5762306a36Sopenharmony_ci return; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci if (smp_processor_id() != boot_cpuid) 6062306a36Sopenharmony_ci return; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci pr_info("Activating Kernel Userspace Execution Prevention\n"); 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_civoid setup_kup(void) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci setup_kuap(disable_kuap); 6862306a36Sopenharmony_ci setup_kuep(disable_kuep); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#define CTOR(shift) static void ctor_##shift(void *addr) \ 7262306a36Sopenharmony_ci{ \ 7362306a36Sopenharmony_ci memset(addr, 0, sizeof(void *) << (shift)); \ 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ciCTOR(0); CTOR(1); CTOR(2); CTOR(3); CTOR(4); CTOR(5); CTOR(6); CTOR(7); 7762306a36Sopenharmony_ciCTOR(8); CTOR(9); CTOR(10); CTOR(11); CTOR(12); CTOR(13); CTOR(14); CTOR(15); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic inline void (*ctor(int shift))(void *) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci BUILD_BUG_ON(MAX_PGTABLE_INDEX_SIZE != 15); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci switch (shift) { 8462306a36Sopenharmony_ci case 0: return ctor_0; 8562306a36Sopenharmony_ci case 1: return ctor_1; 8662306a36Sopenharmony_ci case 2: return ctor_2; 8762306a36Sopenharmony_ci case 3: return ctor_3; 8862306a36Sopenharmony_ci case 4: return ctor_4; 8962306a36Sopenharmony_ci case 5: return ctor_5; 9062306a36Sopenharmony_ci case 6: return ctor_6; 9162306a36Sopenharmony_ci case 7: return ctor_7; 9262306a36Sopenharmony_ci case 8: return ctor_8; 9362306a36Sopenharmony_ci case 9: return ctor_9; 9462306a36Sopenharmony_ci case 10: return ctor_10; 9562306a36Sopenharmony_ci case 11: return ctor_11; 9662306a36Sopenharmony_ci case 12: return ctor_12; 9762306a36Sopenharmony_ci case 13: return ctor_13; 9862306a36Sopenharmony_ci case 14: return ctor_14; 9962306a36Sopenharmony_ci case 15: return ctor_15; 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci return NULL; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistruct kmem_cache *pgtable_cache[MAX_PGTABLE_INDEX_SIZE + 1]; 10562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pgtable_cache); /* used by kvm_hv module */ 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci/* 10862306a36Sopenharmony_ci * Create a kmem_cache() for pagetables. This is not used for PTE 10962306a36Sopenharmony_ci * pages - they're linked to struct page, come from the normal free 11062306a36Sopenharmony_ci * pages pool and have a different entry size (see real_pte_t) to 11162306a36Sopenharmony_ci * everything else. Caches created by this function are used for all 11262306a36Sopenharmony_ci * the higher level pagetables, and for hugepage pagetables. 11362306a36Sopenharmony_ci */ 11462306a36Sopenharmony_civoid pgtable_cache_add(unsigned int shift) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci char *name; 11762306a36Sopenharmony_ci unsigned long table_size = sizeof(void *) << shift; 11862306a36Sopenharmony_ci unsigned long align = table_size; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci /* When batching pgtable pointers for RCU freeing, we store 12162306a36Sopenharmony_ci * the index size in the low bits. Table alignment must be 12262306a36Sopenharmony_ci * big enough to fit it. 12362306a36Sopenharmony_ci * 12462306a36Sopenharmony_ci * Likewise, hugeapge pagetable pointers contain a (different) 12562306a36Sopenharmony_ci * shift value in the low bits. All tables must be aligned so 12662306a36Sopenharmony_ci * as to leave enough 0 bits in the address to contain it. */ 12762306a36Sopenharmony_ci unsigned long minalign = max(MAX_PGTABLE_INDEX_SIZE + 1, 12862306a36Sopenharmony_ci HUGEPD_SHIFT_MASK + 1); 12962306a36Sopenharmony_ci struct kmem_cache *new = NULL; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci /* It would be nice if this was a BUILD_BUG_ON(), but at the 13262306a36Sopenharmony_ci * moment, gcc doesn't seem to recognize is_power_of_2 as a 13362306a36Sopenharmony_ci * constant expression, so so much for that. */ 13462306a36Sopenharmony_ci BUG_ON(!is_power_of_2(minalign)); 13562306a36Sopenharmony_ci BUG_ON(shift > MAX_PGTABLE_INDEX_SIZE); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci if (PGT_CACHE(shift)) 13862306a36Sopenharmony_ci return; /* Already have a cache of this size */ 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci align = max_t(unsigned long, align, minalign); 14162306a36Sopenharmony_ci name = kasprintf(GFP_KERNEL, "pgtable-2^%d", shift); 14262306a36Sopenharmony_ci if (name) 14362306a36Sopenharmony_ci new = kmem_cache_create(name, table_size, align, 0, ctor(shift)); 14462306a36Sopenharmony_ci if (!new) 14562306a36Sopenharmony_ci panic("Could not allocate pgtable cache for order %d", shift); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci kfree(name); 14862306a36Sopenharmony_ci pgtable_cache[shift] = new; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci pr_debug("Allocated pgtable cache for order %d\n", shift); 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pgtable_cache_add); /* used by kvm_hv module */ 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_civoid pgtable_cache_init(void) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci pgtable_cache_add(PGD_INDEX_SIZE); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci if (PMD_CACHE_INDEX) 15962306a36Sopenharmony_ci pgtable_cache_add(PMD_CACHE_INDEX); 16062306a36Sopenharmony_ci /* 16162306a36Sopenharmony_ci * In all current configs, when the PUD index exists it's the 16262306a36Sopenharmony_ci * same size as either the pgd or pmd index except with THP enabled 16362306a36Sopenharmony_ci * on book3s 64 16462306a36Sopenharmony_ci */ 16562306a36Sopenharmony_ci if (PUD_CACHE_INDEX) 16662306a36Sopenharmony_ci pgtable_cache_add(PUD_CACHE_INDEX); 16762306a36Sopenharmony_ci} 168