xref: /linux/arch/powerpc/kernel/module.c (revision 4d7b321a9ce0782a953874ec69acc2b12b9cb2cd)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*  Kernel module help for powerpc.
3     Copyright (C) 2001, 2003 Rusty Russell IBM Corporation.
4     Copyright (C) 2008 Freescale Semiconductor, Inc.
5 
6 */
7 #include <linux/elf.h>
8 #include <linux/moduleloader.h>
9 #include <linux/err.h>
10 #include <linux/vmalloc.h>
11 #include <linux/mm.h>
12 #include <linux/bug.h>
13 #include <linux/execmem.h>
14 #include <asm/module.h>
15 #include <linux/uaccess.h>
16 #include <asm/firmware.h>
17 #include <linux/sort.h>
18 #include <asm/setup.h>
19 #include <asm/sections.h>
20 
21 static LIST_HEAD(module_bug_list);
22 
23 static const Elf_Shdr *find_section(const Elf_Ehdr *hdr,
24 				    const Elf_Shdr *sechdrs,
25 				    const char *name)
26 {
27 	char *secstrings;
28 	unsigned int i;
29 
30 	secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
31 	for (i = 1; i < hdr->e_shnum; i++)
32 		if (strcmp(secstrings+sechdrs[i].sh_name, name) == 0)
33 			return &sechdrs[i];
34 	return NULL;
35 }
36 
37 int module_finalize(const Elf_Ehdr *hdr,
38 		const Elf_Shdr *sechdrs, struct module *me)
39 {
40 	const Elf_Shdr *sect;
41 	int rc;
42 
43 	rc = module_finalize_ftrace(me, sechdrs);
44 	if (rc)
45 		return rc;
46 
47 	/* Apply feature fixups */
48 	sect = find_section(hdr, sechdrs, "__ftr_fixup");
49 	if (sect != NULL)
50 		do_feature_fixups(cur_cpu_spec->cpu_features,
51 				  (void *)sect->sh_addr,
52 				  (void *)sect->sh_addr + sect->sh_size);
53 
54 	sect = find_section(hdr, sechdrs, "__mmu_ftr_fixup");
55 	if (sect != NULL)
56 		do_feature_fixups(cur_cpu_spec->mmu_features,
57 				  (void *)sect->sh_addr,
58 				  (void *)sect->sh_addr + sect->sh_size);
59 
60 #ifdef CONFIG_PPC64
61 	sect = find_section(hdr, sechdrs, "__fw_ftr_fixup");
62 	if (sect != NULL)
63 		do_feature_fixups(powerpc_firmware_features,
64 				  (void *)sect->sh_addr,
65 				  (void *)sect->sh_addr + sect->sh_size);
66 #endif /* CONFIG_PPC64 */
67 
68 #ifdef CONFIG_PPC64_ELF_ABI_V1
69 	sect = find_section(hdr, sechdrs, ".opd");
70 	if (sect != NULL) {
71 		me->arch.start_opd = sect->sh_addr;
72 		me->arch.end_opd = sect->sh_addr + sect->sh_size;
73 	}
74 #endif /* CONFIG_PPC64_ELF_ABI_V1 */
75 
76 #ifdef CONFIG_PPC_BARRIER_NOSPEC
77 	sect = find_section(hdr, sechdrs, "__spec_barrier_fixup");
78 	if (sect != NULL)
79 		do_barrier_nospec_fixups_range(barrier_nospec_enabled,
80 				  (void *)sect->sh_addr,
81 				  (void *)sect->sh_addr + sect->sh_size);
82 #endif /* CONFIG_PPC_BARRIER_NOSPEC */
83 
84 	sect = find_section(hdr, sechdrs, "__lwsync_fixup");
85 	if (sect != NULL)
86 		do_lwsync_fixups(cur_cpu_spec->cpu_features,
87 				 (void *)sect->sh_addr,
88 				 (void *)sect->sh_addr + sect->sh_size);
89 
90 	return 0;
91 }
92 
93 static struct execmem_info execmem_info __ro_after_init;
94 
95 struct execmem_info __init *execmem_arch_setup(void)
96 {
97 	pgprot_t prot = strict_module_rwx_enabled() ? PAGE_KERNEL : PAGE_KERNEL_EXEC;
98 	unsigned long fallback_start = 0, fallback_end = 0;
99 	unsigned long start, end;
100 
101 	/*
102 	 * BOOK3S_32 and 8xx define MODULES_VADDR for text allocations and
103 	 * allow allocating data in the entire vmalloc space
104 	 */
105 #ifdef MODULES_VADDR
106 	unsigned long limit = (unsigned long)_etext - SZ_32M;
107 
108 	BUILD_BUG_ON(TASK_SIZE > MODULES_VADDR);
109 
110 	/* First try within 32M limit from _etext to avoid branch trampolines */
111 	if (MODULES_VADDR < PAGE_OFFSET && MODULES_END > limit) {
112 		start = limit;
113 		fallback_start = MODULES_VADDR;
114 		fallback_end = MODULES_END;
115 	} else {
116 		start = MODULES_VADDR;
117 	}
118 
119 	end = MODULES_END;
120 #else
121 	start = VMALLOC_START;
122 	end = VMALLOC_END;
123 #endif
124 
125 	execmem_info = (struct execmem_info){
126 		.ranges = {
127 			[EXECMEM_DEFAULT] = {
128 				.start	= start,
129 				.end	= end,
130 				.pgprot	= prot,
131 				.alignment = 1,
132 				.fallback_start	= fallback_start,
133 				.fallback_end	= fallback_end,
134 			},
135 			[EXECMEM_MODULE_DATA] = {
136 				.start	= VMALLOC_START,
137 				.end	= VMALLOC_END,
138 				.pgprot	= PAGE_KERNEL,
139 				.alignment = 1,
140 			},
141 		},
142 	};
143 
144 	return &execmem_info;
145 }
146