11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2f0c426bcSKumar Gala /* Kernel module help for powerpc.
3f0c426bcSKumar Gala Copyright (C) 2001, 2003 Rusty Russell IBM Corporation.
4f0c426bcSKumar Gala Copyright (C) 2008 Freescale Semiconductor, Inc.
5f0c426bcSKumar Gala
6f0c426bcSKumar Gala */
7f0c426bcSKumar Gala #include <linux/elf.h>
8f0c426bcSKumar Gala #include <linux/moduleloader.h>
9f0c426bcSKumar Gala #include <linux/err.h>
108abddd96SNicholas Piggin #include <linux/mm.h>
11f0c426bcSKumar Gala #include <linux/bug.h>
12f0c426bcSKumar Gala #include <asm/module.h>
137c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
14f0c426bcSKumar Gala #include <asm/firmware.h>
15f0c426bcSKumar Gala #include <linux/sort.h>
16b88c4767SRobert Jennings #include <asm/setup.h>
172ec13df1SChristophe Leroy #include <asm/sections.h>
18f0c426bcSKumar Gala
find_section(const Elf_Ehdr * hdr,const Elf_Shdr * sechdrs,const char * name)197c98bd72SDaniel Axtens static const Elf_Shdr *find_section(const Elf_Ehdr *hdr,
20f0c426bcSKumar Gala const Elf_Shdr *sechdrs,
21f0c426bcSKumar Gala const char *name)
22f0c426bcSKumar Gala {
23f0c426bcSKumar Gala char *secstrings;
24f0c426bcSKumar Gala unsigned int i;
25f0c426bcSKumar Gala
26f0c426bcSKumar Gala secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
27f0c426bcSKumar Gala for (i = 1; i < hdr->e_shnum; i++)
28f0c426bcSKumar Gala if (strcmp(secstrings+sechdrs[i].sh_name, name) == 0)
29f0c426bcSKumar Gala return &sechdrs[i];
30f0c426bcSKumar Gala return NULL;
31f0c426bcSKumar Gala }
32f0c426bcSKumar Gala
module_finalize(const Elf_Ehdr * hdr,const Elf_Shdr * sechdrs,struct module * me)33f0c426bcSKumar Gala int module_finalize(const Elf_Ehdr *hdr,
34f0c426bcSKumar Gala const Elf_Shdr *sechdrs, struct module *me)
35f0c426bcSKumar Gala {
36f0c426bcSKumar Gala const Elf_Shdr *sect;
37f0c426bcSKumar Gala int rc;
38f0c426bcSKumar Gala
39136cd345SMichael Ellerman rc = module_finalize_ftrace(me, sechdrs);
40136cd345SMichael Ellerman if (rc)
41136cd345SMichael Ellerman return rc;
42136cd345SMichael Ellerman
43136cd345SMichael Ellerman /* Apply feature fixups */
44f0c426bcSKumar Gala sect = find_section(hdr, sechdrs, "__ftr_fixup");
45f0c426bcSKumar Gala if (sect != NULL)
46f0c426bcSKumar Gala do_feature_fixups(cur_cpu_spec->cpu_features,
47f0c426bcSKumar Gala (void *)sect->sh_addr,
48f0c426bcSKumar Gala (void *)sect->sh_addr + sect->sh_size);
49f0c426bcSKumar Gala
50f0c426bcSKumar Gala sect = find_section(hdr, sechdrs, "__mmu_ftr_fixup");
51f0c426bcSKumar Gala if (sect != NULL)
527c03d653SBenjamin Herrenschmidt do_feature_fixups(cur_cpu_spec->mmu_features,
537c03d653SBenjamin Herrenschmidt (void *)sect->sh_addr,
547c03d653SBenjamin Herrenschmidt (void *)sect->sh_addr + sect->sh_size);
557c03d653SBenjamin Herrenschmidt
567c03d653SBenjamin Herrenschmidt #ifdef CONFIG_PPC64
577c03d653SBenjamin Herrenschmidt sect = find_section(hdr, sechdrs, "__fw_ftr_fixup");
58f0c426bcSKumar Gala if (sect != NULL)
59f0c426bcSKumar Gala do_feature_fixups(powerpc_firmware_features,
60f0c426bcSKumar Gala (void *)sect->sh_addr,
61f0c426bcSKumar Gala (void *)sect->sh_addr + sect->sh_size);
62f0c426bcSKumar Gala #endif /* CONFIG_PPC64 */
63f0c426bcSKumar Gala
64179ab1cbSMichael Ellerman #ifdef CONFIG_PPC64_ELF_ABI_V1
65815069caSMichal Suchanek sect = find_section(hdr, sechdrs, ".opd");
66*7d40aff8SChristophe Leroy if (sect != NULL) {
6759fe7eafSNaveen N. Rao me->arch.start_opd = sect->sh_addr;
6859fe7eafSNaveen N. Rao me->arch.end_opd = sect->sh_addr + sect->sh_size;
6959fe7eafSNaveen N. Rao }
7059fe7eafSNaveen N. Rao #endif /* CONFIG_PPC64_ELF_ABI_V1 */
7159fe7eafSNaveen N. Rao
72*7d40aff8SChristophe Leroy #ifdef CONFIG_PPC_BARRIER_NOSPEC
7359fe7eafSNaveen N. Rao sect = find_section(hdr, sechdrs, "__spec_barrier_fixup");
74179ab1cbSMichael Ellerman if (sect != NULL)
75815069caSMichal Suchanek do_barrier_nospec_fixups_range(barrier_nospec_enabled,
76815069caSMichal Suchanek (void *)sect->sh_addr,
77815069caSMichal Suchanek (void *)sect->sh_addr + sect->sh_size);
78815069caSMichal Suchanek #endif /* CONFIG_PPC_BARRIER_NOSPEC */
79815069caSMichal Suchanek
80179ab1cbSMichael Ellerman sect = find_section(hdr, sechdrs, "__lwsync_fixup");
81f0c426bcSKumar Gala if (sect != NULL)
822d1b2027SKumar Gala do_lwsync_fixups(cur_cpu_spec->cpu_features,
832d1b2027SKumar Gala (void *)sect->sh_addr,
842d1b2027SKumar Gala (void *)sect->sh_addr + sect->sh_size);
852d1b2027SKumar Gala
862d1b2027SKumar Gala return 0;
872d1b2027SKumar Gala }
88f0c426bcSKumar Gala