linux/arch/powerpc/kernel/module.c
<<
>>
Prefs
   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 <asm/module.h>
  14#include <linux/uaccess.h>
  15#include <asm/firmware.h>
  16#include <linux/sort.h>
  17#include <asm/setup.h>
  18#include <asm/sections.h>
  19
  20static LIST_HEAD(module_bug_list);
  21
  22static const Elf_Shdr *find_section(const Elf_Ehdr *hdr,
  23                                    const Elf_Shdr *sechdrs,
  24                                    const char *name)
  25{
  26        char *secstrings;
  27        unsigned int i;
  28
  29        secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
  30        for (i = 1; i < hdr->e_shnum; i++)
  31                if (strcmp(secstrings+sechdrs[i].sh_name, name) == 0)
  32                        return &sechdrs[i];
  33        return NULL;
  34}
  35
  36int module_finalize(const Elf_Ehdr *hdr,
  37                const Elf_Shdr *sechdrs, struct module *me)
  38{
  39        const Elf_Shdr *sect;
  40        int rc;
  41
  42        rc = module_finalize_ftrace(me, sechdrs);
  43        if (rc)
  44                return rc;
  45
  46        /* Apply feature fixups */
  47        sect = find_section(hdr, sechdrs, "__ftr_fixup");
  48        if (sect != NULL)
  49                do_feature_fixups(cur_cpu_spec->cpu_features,
  50                                  (void *)sect->sh_addr,
  51                                  (void *)sect->sh_addr + sect->sh_size);
  52
  53        sect = find_section(hdr, sechdrs, "__mmu_ftr_fixup");
  54        if (sect != NULL)
  55                do_feature_fixups(cur_cpu_spec->mmu_features,
  56                                  (void *)sect->sh_addr,
  57                                  (void *)sect->sh_addr + sect->sh_size);
  58
  59#ifdef CONFIG_PPC64
  60        sect = find_section(hdr, sechdrs, "__fw_ftr_fixup");
  61        if (sect != NULL)
  62                do_feature_fixups(powerpc_firmware_features,
  63                                  (void *)sect->sh_addr,
  64                                  (void *)sect->sh_addr + sect->sh_size);
  65#endif /* CONFIG_PPC64 */
  66
  67#ifdef PPC64_ELF_ABI_v1
  68        sect = find_section(hdr, sechdrs, ".opd");
  69        if (sect != NULL) {
  70                me->arch.start_opd = sect->sh_addr;
  71                me->arch.end_opd = sect->sh_addr + sect->sh_size;
  72        }
  73#endif /* PPC64_ELF_ABI_v1 */
  74
  75#ifdef CONFIG_PPC_BARRIER_NOSPEC
  76        sect = find_section(hdr, sechdrs, "__spec_barrier_fixup");
  77        if (sect != NULL)
  78                do_barrier_nospec_fixups_range(barrier_nospec_enabled,
  79                                  (void *)sect->sh_addr,
  80                                  (void *)sect->sh_addr + sect->sh_size);
  81#endif /* CONFIG_PPC_BARRIER_NOSPEC */
  82
  83        sect = find_section(hdr, sechdrs, "__lwsync_fixup");
  84        if (sect != NULL)
  85                do_lwsync_fixups(cur_cpu_spec->cpu_features,
  86                                 (void *)sect->sh_addr,
  87                                 (void *)sect->sh_addr + sect->sh_size);
  88
  89        return 0;
  90}
  91
  92static __always_inline void *
  93__module_alloc(unsigned long size, unsigned long start, unsigned long end)
  94{
  95        pgprot_t prot = strict_module_rwx_enabled() ? PAGE_KERNEL : PAGE_KERNEL_EXEC;
  96
  97        /*
  98         * Don't do huge page allocations for modules yet until more testing
  99         * is done. STRICT_MODULE_RWX may require extra work to support this
 100         * too.
 101         */
 102        return __vmalloc_node_range(size, 1, start, end, GFP_KERNEL, prot,
 103                                    VM_FLUSH_RESET_PERMS | VM_NO_HUGE_VMAP,
 104                                    NUMA_NO_NODE, __builtin_return_address(0));
 105}
 106
 107void *module_alloc(unsigned long size)
 108{
 109#ifdef MODULES_VADDR
 110        unsigned long limit = (unsigned long)_etext - SZ_32M;
 111        void *ptr = NULL;
 112
 113        BUILD_BUG_ON(TASK_SIZE > MODULES_VADDR);
 114
 115        /* First try within 32M limit from _etext to avoid branch trampolines */
 116        if (MODULES_VADDR < PAGE_OFFSET && MODULES_END > limit)
 117                ptr = __module_alloc(size, limit, MODULES_END);
 118
 119        if (!ptr)
 120                ptr = __module_alloc(size, MODULES_VADDR, MODULES_END);
 121
 122        return ptr;
 123#else
 124        return __module_alloc(size, VMALLOC_START, VMALLOC_END);
 125#endif
 126}
 127