Skip to content

Commit f6bec26

Browse files
rpptmcgrof
authored andcommitted
mm/execmem, arch: convert simple overrides of module_alloc to execmem
Several architectures override module_alloc() only to define address range for code allocations different than VMALLOC address space. Provide a generic implementation in execmem that uses the parameters for address space ranges, required alignment and page protections provided by architectures. The architectures must fill execmem_info structure and implement execmem_arch_setup() that returns a pointer to that structure. This way the execmem initialization won't be called from every architecture, but rather from a central place, namely a core_initcall() in execmem. The execmem provides execmem_alloc() API that wraps __vmalloc_node_range() with the parameters defined by the architectures. If an architecture does not implement execmem_arch_setup(), execmem_alloc() will fall back to module_alloc(). Signed-off-by: Mike Rapoport (IBM) <[email protected]> Acked-by: Song Liu <[email protected]> Reviewed-by: Masami Hiramatsu (Google) <[email protected]> Signed-off-by: Luis Chamberlain <[email protected]>
1 parent 12af2b8 commit f6bec26

File tree

9 files changed

+210
-34
lines changed

9 files changed

+210
-34
lines changed

arch/loongarch/kernel/module.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <linux/ftrace.h>
1919
#include <linux/string.h>
2020
#include <linux/kernel.h>
21+
#include <linux/execmem.h>
2122
#include <asm/alternative.h>
2223
#include <asm/inst.h>
2324
#include <asm/unwind.h>
@@ -490,10 +491,22 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
490491
return 0;
491492
}
492493

493-
void *module_alloc(unsigned long size)
494+
static struct execmem_info execmem_info __ro_after_init;
495+
496+
struct execmem_info __init *execmem_arch_setup(void)
494497
{
495-
return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
496-
GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE, __builtin_return_address(0));
498+
execmem_info = (struct execmem_info){
499+
.ranges = {
500+
[EXECMEM_DEFAULT] = {
501+
.start = MODULES_VADDR,
502+
.end = MODULES_END,
503+
.pgprot = PAGE_KERNEL,
504+
.alignment = 1,
505+
},
506+
},
507+
};
508+
509+
return &execmem_info;
497510
}
498511

499512
static void module_init_ftrace_plt(const Elf_Ehdr *hdr,

arch/mips/kernel/module.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <linux/kernel.h>
2121
#include <linux/spinlock.h>
2222
#include <linux/jump_label.h>
23+
#include <linux/execmem.h>
2324
#include <asm/jump_label.h>
2425

2526
struct mips_hi16 {
@@ -32,11 +33,22 @@ static LIST_HEAD(dbe_list);
3233
static DEFINE_SPINLOCK(dbe_lock);
3334

3435
#ifdef MODULES_VADDR
35-
void *module_alloc(unsigned long size)
36+
static struct execmem_info execmem_info __ro_after_init;
37+
38+
struct execmem_info __init *execmem_arch_setup(void)
3639
{
37-
return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
38-
GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE,
39-
__builtin_return_address(0));
40+
execmem_info = (struct execmem_info){
41+
.ranges = {
42+
[EXECMEM_DEFAULT] = {
43+
.start = MODULES_VADDR,
44+
.end = MODULES_END,
45+
.pgprot = PAGE_KERNEL,
46+
.alignment = 1,
47+
},
48+
},
49+
};
50+
51+
return &execmem_info;
4052
}
4153
#endif
4254

arch/nios2/kernel/module.c

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,26 @@
1818
#include <linux/fs.h>
1919
#include <linux/string.h>
2020
#include <linux/kernel.h>
21+
#include <linux/execmem.h>
2122

2223
#include <asm/cacheflush.h>
2324

24-
void *module_alloc(unsigned long size)
25+
static struct execmem_info execmem_info __ro_after_init;
26+
27+
struct execmem_info __init *execmem_arch_setup(void)
2528
{
26-
return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
27-
GFP_KERNEL, PAGE_KERNEL_EXEC,
28-
VM_FLUSH_RESET_PERMS, NUMA_NO_NODE,
29-
__builtin_return_address(0));
29+
execmem_info = (struct execmem_info){
30+
.ranges = {
31+
[EXECMEM_DEFAULT] = {
32+
.start = MODULES_VADDR,
33+
.end = MODULES_END,
34+
.pgprot = PAGE_KERNEL_EXEC,
35+
.alignment = 1,
36+
},
37+
},
38+
};
39+
40+
return &execmem_info;
3041
}
3142

3243
int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,

arch/parisc/kernel/module.c

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
#include <linux/bug.h>
5050
#include <linux/mm.h>
5151
#include <linux/slab.h>
52+
#include <linux/execmem.h>
5253

5354
#include <asm/unwind.h>
5455
#include <asm/sections.h>
@@ -173,15 +174,22 @@ static inline int reassemble_22(int as22)
173174
((as22 & 0x0003ff) << 3));
174175
}
175176

176-
void *module_alloc(unsigned long size)
177+
static struct execmem_info execmem_info __ro_after_init;
178+
179+
struct execmem_info __init *execmem_arch_setup(void)
177180
{
178-
/* using RWX means less protection for modules, but it's
179-
* easier than trying to map the text, data, init_text and
180-
* init_data correctly */
181-
return __vmalloc_node_range(size, 1, VMALLOC_START, VMALLOC_END,
182-
GFP_KERNEL,
183-
PAGE_KERNEL_RWX, 0, NUMA_NO_NODE,
184-
__builtin_return_address(0));
181+
execmem_info = (struct execmem_info){
182+
.ranges = {
183+
[EXECMEM_DEFAULT] = {
184+
.start = VMALLOC_START,
185+
.end = VMALLOC_END,
186+
.pgprot = PAGE_KERNEL_RWX,
187+
.alignment = 1,
188+
},
189+
},
190+
};
191+
192+
return &execmem_info;
185193
}
186194

187195
#ifndef CONFIG_64BIT

arch/riscv/kernel/module.c

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/vmalloc.h>
1515
#include <linux/sizes.h>
1616
#include <linux/pgtable.h>
17+
#include <linux/execmem.h>
1718
#include <asm/alternative.h>
1819
#include <asm/sections.h>
1920

@@ -906,13 +907,22 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
906907
}
907908

908909
#if defined(CONFIG_MMU) && defined(CONFIG_64BIT)
909-
void *module_alloc(unsigned long size)
910-
{
911-
return __vmalloc_node_range(size, 1, MODULES_VADDR,
912-
MODULES_END, GFP_KERNEL,
913-
PAGE_KERNEL, VM_FLUSH_RESET_PERMS,
914-
NUMA_NO_NODE,
915-
__builtin_return_address(0));
910+
static struct execmem_info execmem_info __ro_after_init;
911+
912+
struct execmem_info __init *execmem_arch_setup(void)
913+
{
914+
execmem_info = (struct execmem_info){
915+
.ranges = {
916+
[EXECMEM_DEFAULT] = {
917+
.start = MODULES_VADDR,
918+
.end = MODULES_END,
919+
.pgprot = PAGE_KERNEL,
920+
.alignment = 1,
921+
},
922+
},
923+
};
924+
925+
return &execmem_info;
916926
}
917927
#endif
918928

arch/sparc/kernel/module.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,30 @@
1414
#include <linux/string.h>
1515
#include <linux/ctype.h>
1616
#include <linux/mm.h>
17+
#include <linux/execmem.h>
1718

1819
#include <asm/processor.h>
1920
#include <asm/spitfire.h>
2021
#include <asm/cacheflush.h>
2122

2223
#include "entry.h"
2324

24-
void *module_alloc(unsigned long size)
25+
static struct execmem_info execmem_info __ro_after_init;
26+
27+
struct execmem_info __init *execmem_arch_setup(void)
2528
{
26-
return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
27-
GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE,
28-
__builtin_return_address(0));
29+
execmem_info = (struct execmem_info){
30+
.ranges = {
31+
[EXECMEM_DEFAULT] = {
32+
.start = MODULES_VADDR,
33+
.end = MODULES_END,
34+
.pgprot = PAGE_KERNEL,
35+
.alignment = 1,
36+
},
37+
},
38+
};
39+
40+
return &execmem_info;
2941
}
3042

3143
/* Make generic code ignore STT_REGISTER dummy undefined symbols. */

include/linux/execmem.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,47 @@ enum execmem_type {
3333
EXECMEM_TYPE_MAX,
3434
};
3535

36+
/**
37+
* struct execmem_range - definition of an address space suitable for code and
38+
* related data allocations
39+
* @start: address space start
40+
* @end: address space end (inclusive)
41+
* @pgprot: permissions for memory in this address space
42+
* @alignment: alignment required for text allocations
43+
*/
44+
struct execmem_range {
45+
unsigned long start;
46+
unsigned long end;
47+
pgprot_t pgprot;
48+
unsigned int alignment;
49+
};
50+
51+
/**
52+
* struct execmem_info - architecture parameters for code allocations
53+
* @ranges: array of parameter sets defining architecture specific
54+
* parameters for executable memory allocations. The ranges that are not
55+
* explicitly initialized by an architecture use parameters defined for
56+
* @EXECMEM_DEFAULT.
57+
*/
58+
struct execmem_info {
59+
struct execmem_range ranges[EXECMEM_TYPE_MAX];
60+
};
61+
62+
/**
63+
* execmem_arch_setup - define parameters for allocations of executable memory
64+
*
65+
* A hook for architectures to define parameters for allocations of
66+
* executable memory. These parameters should be filled into the
67+
* @execmem_info structure.
68+
*
69+
* For architectures that do not implement this method a default set of
70+
* parameters will be used
71+
*
72+
* Return: a structure defining architecture parameters and restrictions
73+
* for allocations of executable memory
74+
*/
75+
struct execmem_info *execmem_arch_setup(void);
76+
3677
/**
3778
* execmem_alloc - allocate executable memory
3879
* @type: type of the allocation
@@ -54,4 +95,10 @@ void *execmem_alloc(enum execmem_type type, size_t size);
5495
*/
5596
void execmem_free(void *ptr);
5697

98+
#ifdef CONFIG_EXECMEM
99+
void execmem_init(void);
100+
#else
101+
static inline void execmem_init(void) {}
102+
#endif
103+
57104
#endif /* _LINUX_EXECMEM_ALLOC_H */

mm/execmem.c

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,30 @@
1111
#include <linux/execmem.h>
1212
#include <linux/moduleloader.h>
1313

14-
static void *__execmem_alloc(size_t size)
14+
static struct execmem_info *execmem_info __ro_after_init;
15+
16+
static void *__execmem_alloc(struct execmem_range *range, size_t size)
1517
{
16-
return module_alloc(size);
18+
unsigned long start = range->start;
19+
unsigned long end = range->end;
20+
unsigned int align = range->alignment;
21+
pgprot_t pgprot = range->pgprot;
22+
23+
return __vmalloc_node_range(size, align, start, end,
24+
GFP_KERNEL, pgprot, VM_FLUSH_RESET_PERMS,
25+
NUMA_NO_NODE, __builtin_return_address(0));
1726
}
1827

1928
void *execmem_alloc(enum execmem_type type, size_t size)
2029
{
21-
return __execmem_alloc(size);
30+
struct execmem_range *range;
31+
32+
if (!execmem_info)
33+
return module_alloc(size);
34+
35+
range = &execmem_info->ranges[type];
36+
37+
return __execmem_alloc(range, size);
2238
}
2339

2440
void execmem_free(void *ptr)
@@ -30,3 +46,48 @@ void execmem_free(void *ptr)
3046
WARN_ON(in_interrupt());
3147
vfree(ptr);
3248
}
49+
50+
static bool execmem_validate(struct execmem_info *info)
51+
{
52+
struct execmem_range *r = &info->ranges[EXECMEM_DEFAULT];
53+
54+
if (!r->alignment || !r->start || !r->end || !pgprot_val(r->pgprot)) {
55+
pr_crit("Invalid parameters for execmem allocator, module loading will fail");
56+
return false;
57+
}
58+
59+
return true;
60+
}
61+
62+
static void execmem_init_missing(struct execmem_info *info)
63+
{
64+
struct execmem_range *default_range = &info->ranges[EXECMEM_DEFAULT];
65+
66+
for (int i = EXECMEM_DEFAULT + 1; i < EXECMEM_TYPE_MAX; i++) {
67+
struct execmem_range *r = &info->ranges[i];
68+
69+
if (!r->start) {
70+
r->pgprot = default_range->pgprot;
71+
r->alignment = default_range->alignment;
72+
r->start = default_range->start;
73+
r->end = default_range->end;
74+
}
75+
}
76+
}
77+
78+
struct execmem_info * __weak execmem_arch_setup(void)
79+
{
80+
return NULL;
81+
}
82+
83+
void __init execmem_init(void)
84+
{
85+
struct execmem_info *info = execmem_arch_setup();
86+
87+
if (!info || !execmem_validate(info))
88+
return;
89+
90+
execmem_init_missing(info);
91+
92+
execmem_info = info;
93+
}

mm/mm_init.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <linux/swap.h>
2828
#include <linux/cma.h>
2929
#include <linux/crash_dump.h>
30+
#include <linux/execmem.h>
3031
#include "internal.h"
3132
#include "slab.h"
3233
#include "shuffle.h"
@@ -2793,4 +2794,5 @@ void __init mm_core_init(void)
27932794
pti_init();
27942795
kmsan_init_runtime();
27952796
mm_cache_init();
2797+
execmem_init();
27962798
}

0 commit comments

Comments
 (0)