Commit | Line | Data |
---|---|---|
2874c5fd | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
9b081e10 CL |
2 | /* |
3 | * PowerPC version | |
4 | * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) | |
5 | * | |
6 | * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au) | |
7 | * and Cort Dougan (PReP) (cort@cs.nmt.edu) | |
8 | * Copyright (C) 1996 Paul Mackerras | |
9 | * | |
10 | * Derived from "arch/i386/mm/init.c" | |
11 | * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds | |
12 | * | |
13 | * Dave Engebretsen <engebret@us.ibm.com> | |
14 | * Rework for PPC64 port. | |
9b081e10 CL |
15 | */ |
16 | ||
17 | #undef DEBUG | |
18 | ||
19 | #include <linux/string.h> | |
ca5999fd | 20 | #include <linux/pgtable.h> |
65fddcfc | 21 | #include <asm/pgalloc.h> |
69795cab | 22 | #include <asm/kup.h> |
67548622 | 23 | #include <asm/smp.h> |
69795cab | 24 | |
4ed47dbe JY |
25 | phys_addr_t memstart_addr __ro_after_init = (phys_addr_t)~0ull; |
26 | EXPORT_SYMBOL_GPL(memstart_addr); | |
27 | phys_addr_t kernstart_addr __ro_after_init; | |
28 | EXPORT_SYMBOL_GPL(kernstart_addr); | |
39f4b7bf JY |
29 | unsigned long kernstart_virt_addr __ro_after_init = KERNELBASE; |
30 | EXPORT_SYMBOL_GPL(kernstart_virt_addr); | |
4ed47dbe | 31 | |
61130e20 AK |
32 | bool disable_kuep = !IS_ENABLED(CONFIG_PPC_KUEP); |
33 | bool disable_kuap = !IS_ENABLED(CONFIG_PPC_KUAP); | |
353d7a84 HB |
34 | #ifdef CONFIG_KFENCE |
35 | bool __ro_after_init kfence_disabled; | |
b5fbf7e2 | 36 | bool __ro_after_init kfence_early_init = !!CONFIG_KFENCE_SAMPLE_INTERVAL; |
353d7a84 | 37 | #endif |
0fb1c25a CL |
38 | |
39 | static int __init parse_nosmep(char *p) | |
40 | { | |
67548622 CL |
41 | if (!IS_ENABLED(CONFIG_PPC_BOOK3S_64)) |
42 | return 0; | |
43 | ||
0fb1c25a CL |
44 | disable_kuep = true; |
45 | pr_warn("Disabling Kernel Userspace Execution Prevention\n"); | |
46 | return 0; | |
47 | } | |
48 | early_param("nosmep", parse_nosmep); | |
49 | ||
de78a9c4 CL |
50 | static int __init parse_nosmap(char *p) |
51 | { | |
52 | disable_kuap = true; | |
53 | pr_warn("Disabling Kernel Userspace Access Protection\n"); | |
54 | return 0; | |
55 | } | |
56 | early_param("nosmap", parse_nosmap); | |
57 | ||
67548622 CL |
58 | void __weak setup_kuep(bool disabled) |
59 | { | |
60 | if (!IS_ENABLED(CONFIG_PPC_KUEP) || disabled) | |
61 | return; | |
62 | ||
63 | if (smp_processor_id() != boot_cpuid) | |
64 | return; | |
65 | ||
66 | pr_info("Activating Kernel Userspace Execution Prevention\n"); | |
67 | } | |
68 | ||
6c1fa60d CL |
69 | void setup_kup(void) |
70 | { | |
71 | setup_kuap(disable_kuap); | |
72 | setup_kuep(disable_kuep); | |
73 | } | |
74 | ||
1e03c7e2 CL |
75 | #define CTOR(shift) static void ctor_##shift(void *addr) \ |
76 | { \ | |
e7a9af8c | 77 | memset(addr, 0, sizeof(pgd_t) << (shift)); \ |
9b081e10 CL |
78 | } |
79 | ||
1e03c7e2 CL |
80 | CTOR(0); CTOR(1); CTOR(2); CTOR(3); CTOR(4); CTOR(5); CTOR(6); CTOR(7); |
81 | CTOR(8); CTOR(9); CTOR(10); CTOR(11); CTOR(12); CTOR(13); CTOR(14); CTOR(15); | |
9b081e10 | 82 | |
1e03c7e2 | 83 | static inline void (*ctor(int shift))(void *) |
9b081e10 | 84 | { |
1e03c7e2 CL |
85 | BUILD_BUG_ON(MAX_PGTABLE_INDEX_SIZE != 15); |
86 | ||
87 | switch (shift) { | |
88 | case 0: return ctor_0; | |
89 | case 1: return ctor_1; | |
90 | case 2: return ctor_2; | |
91 | case 3: return ctor_3; | |
92 | case 4: return ctor_4; | |
93 | case 5: return ctor_5; | |
94 | case 6: return ctor_6; | |
95 | case 7: return ctor_7; | |
96 | case 8: return ctor_8; | |
97 | case 9: return ctor_9; | |
98 | case 10: return ctor_10; | |
99 | case 11: return ctor_11; | |
100 | case 12: return ctor_12; | |
101 | case 13: return ctor_13; | |
102 | case 14: return ctor_14; | |
103 | case 15: return ctor_15; | |
104 | } | |
105 | return NULL; | |
9b081e10 CL |
106 | } |
107 | ||
129dd323 | 108 | struct kmem_cache *pgtable_cache[MAX_PGTABLE_INDEX_SIZE + 1]; |
ba9b399a | 109 | EXPORT_SYMBOL_GPL(pgtable_cache); /* used by kvm_hv module */ |
9b081e10 CL |
110 | |
111 | /* | |
112 | * Create a kmem_cache() for pagetables. This is not used for PTE | |
113 | * pages - they're linked to struct page, come from the normal free | |
114 | * pages pool and have a different entry size (see real_pte_t) to | |
115 | * everything else. Caches created by this function are used for all | |
116 | * the higher level pagetables, and for hugepage pagetables. | |
117 | */ | |
1e03c7e2 | 118 | void pgtable_cache_add(unsigned int shift) |
9b081e10 CL |
119 | { |
120 | char *name; | |
e7a9af8c | 121 | unsigned long table_size = sizeof(pgd_t) << shift; |
9b081e10 CL |
122 | unsigned long align = table_size; |
123 | ||
124 | /* When batching pgtable pointers for RCU freeing, we store | |
125 | * the index size in the low bits. Table alignment must be | |
126 | * big enough to fit it. | |
0c22e4b2 CL |
127 | */ |
128 | unsigned long minalign = MAX_PGTABLE_INDEX_SIZE + 1; | |
f46c8a75 | 129 | struct kmem_cache *new = NULL; |
9b081e10 CL |
130 | |
131 | /* It would be nice if this was a BUILD_BUG_ON(), but at the | |
132 | * moment, gcc doesn't seem to recognize is_power_of_2 as a | |
133 | * constant expression, so so much for that. */ | |
134 | BUG_ON(!is_power_of_2(minalign)); | |
129dd323 | 135 | BUG_ON(shift > MAX_PGTABLE_INDEX_SIZE); |
9b081e10 CL |
136 | |
137 | if (PGT_CACHE(shift)) | |
138 | return; /* Already have a cache of this size */ | |
139 | ||
140 | align = max_t(unsigned long, align, minalign); | |
141 | name = kasprintf(GFP_KERNEL, "pgtable-2^%d", shift); | |
f46c8a75 KC |
142 | if (name) |
143 | new = kmem_cache_create(name, table_size, align, 0, ctor(shift)); | |
bf5ca68d NP |
144 | if (!new) |
145 | panic("Could not allocate pgtable cache for order %d", shift); | |
146 | ||
9b081e10 | 147 | kfree(name); |
129dd323 | 148 | pgtable_cache[shift] = new; |
bf5ca68d | 149 | |
9b081e10 CL |
150 | pr_debug("Allocated pgtable cache for order %d\n", shift); |
151 | } | |
ba9b399a | 152 | EXPORT_SYMBOL_GPL(pgtable_cache_add); /* used by kvm_hv module */ |
9b081e10 CL |
153 | |
154 | void pgtable_cache_init(void) | |
155 | { | |
1e03c7e2 | 156 | pgtable_cache_add(PGD_INDEX_SIZE); |
9b081e10 | 157 | |
32bff4b9 | 158 | if (PMD_CACHE_INDEX) |
1e03c7e2 | 159 | pgtable_cache_add(PMD_CACHE_INDEX); |
9b081e10 CL |
160 | /* |
161 | * In all current configs, when the PUD index exists it's the | |
162 | * same size as either the pgd or pmd index except with THP enabled | |
163 | * on book3s 64 | |
164 | */ | |
32bff4b9 | 165 | if (PUD_CACHE_INDEX) |
1e03c7e2 | 166 | pgtable_cache_add(PUD_CACHE_INDEX); |
9b081e10 | 167 | } |