Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/powerpc/mm/init-common.c
26439 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* PowerPC version
4
* Copyright (C) 1995-1996 Gary Thomas ([email protected])
5
*
6
* Modifications by Paul Mackerras (PowerMac) ([email protected])
7
* and Cort Dougan (PReP) ([email protected])
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 <[email protected]>
14
* Rework for PPC64 port.
15
*/
16
17
#undef DEBUG
18
19
#include <linux/string.h>
20
#include <linux/pgtable.h>
21
#include <asm/pgalloc.h>
22
#include <asm/kup.h>
23
#include <asm/smp.h>
24
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);
29
unsigned long kernstart_virt_addr __ro_after_init = KERNELBASE;
30
EXPORT_SYMBOL_GPL(kernstart_virt_addr);
31
32
bool disable_kuep = !IS_ENABLED(CONFIG_PPC_KUEP);
33
bool disable_kuap = !IS_ENABLED(CONFIG_PPC_KUAP);
34
#ifdef CONFIG_KFENCE
35
bool __ro_after_init kfence_disabled;
36
bool __ro_after_init kfence_early_init = !!CONFIG_KFENCE_SAMPLE_INTERVAL;
37
#endif
38
39
static int __init parse_nosmep(char *p)
40
{
41
if (!IS_ENABLED(CONFIG_PPC_BOOK3S_64))
42
return 0;
43
44
disable_kuep = true;
45
pr_warn("Disabling Kernel Userspace Execution Prevention\n");
46
return 0;
47
}
48
early_param("nosmep", parse_nosmep);
49
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
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
69
void setup_kup(void)
70
{
71
setup_kuap(disable_kuap);
72
setup_kuep(disable_kuep);
73
}
74
75
#define CTOR(shift) static void ctor_##shift(void *addr) \
76
{ \
77
memset(addr, 0, sizeof(pgd_t) << (shift)); \
78
}
79
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);
82
83
static inline void (*ctor(int shift))(void *)
84
{
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;
106
}
107
108
struct kmem_cache *pgtable_cache[MAX_PGTABLE_INDEX_SIZE + 1];
109
EXPORT_SYMBOL_GPL(pgtable_cache); /* used by kvm_hv module */
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
*/
118
void pgtable_cache_add(unsigned int shift)
119
{
120
char *name;
121
unsigned long table_size = sizeof(pgd_t) << shift;
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.
127
*/
128
unsigned long minalign = MAX_PGTABLE_INDEX_SIZE + 1;
129
struct kmem_cache *new = NULL;
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));
135
BUG_ON(shift > MAX_PGTABLE_INDEX_SIZE);
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);
142
if (name)
143
new = kmem_cache_create(name, table_size, align, 0, ctor(shift));
144
if (!new)
145
panic("Could not allocate pgtable cache for order %d", shift);
146
147
kfree(name);
148
pgtable_cache[shift] = new;
149
150
pr_debug("Allocated pgtable cache for order %d\n", shift);
151
}
152
EXPORT_SYMBOL_GPL(pgtable_cache_add); /* used by kvm_hv module */
153
154
void pgtable_cache_init(void)
155
{
156
pgtable_cache_add(PGD_INDEX_SIZE);
157
158
if (PMD_CACHE_INDEX)
159
pgtable_cache_add(PMD_CACHE_INDEX);
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
*/
165
if (PUD_CACHE_INDEX)
166
pgtable_cache_add(PUD_CACHE_INDEX);
167
}
168
169