1257cb251SWill Deacon /* 2257cb251SWill Deacon * AArch64 loadable module support. 3257cb251SWill Deacon * 4257cb251SWill Deacon * Copyright (C) 2012 ARM Limited 5257cb251SWill Deacon * 6257cb251SWill Deacon * This program is free software; you can redistribute it and/or modify 7257cb251SWill Deacon * it under the terms of the GNU General Public License version 2 as 8257cb251SWill Deacon * published by the Free Software Foundation. 9257cb251SWill Deacon * 10257cb251SWill Deacon * This program is distributed in the hope that it will be useful, 11257cb251SWill Deacon * but WITHOUT ANY WARRANTY; without even the implied warranty of 12257cb251SWill Deacon * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13257cb251SWill Deacon * GNU General Public License for more details. 14257cb251SWill Deacon * 15257cb251SWill Deacon * You should have received a copy of the GNU General Public License 16257cb251SWill Deacon * along with this program. If not, see <http://www.gnu.org/licenses/>. 17257cb251SWill Deacon * 18257cb251SWill Deacon * Author: Will Deacon <will.deacon@arm.com> 19257cb251SWill Deacon */ 20257cb251SWill Deacon 21257cb251SWill Deacon #include <linux/bitops.h> 22257cb251SWill Deacon #include <linux/elf.h> 23257cb251SWill Deacon #include <linux/gfp.h> 2439d114ddSAndrey Ryabinin #include <linux/kasan.h> 25257cb251SWill Deacon #include <linux/kernel.h> 26257cb251SWill Deacon #include <linux/mm.h> 27257cb251SWill Deacon #include <linux/moduleloader.h> 28257cb251SWill Deacon #include <linux/vmalloc.h> 292c2b282dSPaul Walmsley #include <asm/alternative.h> 30c84fced8SJiang Liu #include <asm/insn.h> 31932ded4bSAndre Przywara #include <asm/sections.h> 32c84fced8SJiang Liu 33257cb251SWill Deacon void *module_alloc(unsigned long size) 34257cb251SWill Deacon { 350c2cf6d9SFlorian Fainelli gfp_t gfp_mask = GFP_KERNEL; 3639d114ddSAndrey Ryabinin void *p; 3739d114ddSAndrey Ryabinin 380c2cf6d9SFlorian Fainelli /* Silence the initial allocation */ 390c2cf6d9SFlorian Fainelli if (IS_ENABLED(CONFIG_ARM64_MODULE_PLTS)) 400c2cf6d9SFlorian Fainelli gfp_mask |= __GFP_NOWARN; 410c2cf6d9SFlorian Fainelli 42f80fb3a3SArd Biesheuvel p = __vmalloc_node_range(size, MODULE_ALIGN, module_alloc_base, 43f80fb3a3SArd Biesheuvel module_alloc_base + MODULES_VSIZE, 440c2cf6d9SFlorian Fainelli gfp_mask, PAGE_KERNEL_EXEC, 0, 45cb9e3c29SAndrey Ryabinin NUMA_NO_NODE, __builtin_return_address(0)); 4639d114ddSAndrey Ryabinin 47fd045f6cSArd Biesheuvel if (!p && IS_ENABLED(CONFIG_ARM64_MODULE_PLTS) && 48fd045f6cSArd Biesheuvel !IS_ENABLED(CONFIG_KASAN)) 49fd045f6cSArd Biesheuvel /* 50fd045f6cSArd Biesheuvel * KASAN can only deal with module allocations being served 51fd045f6cSArd Biesheuvel * from the reserved module region, since the remainder of 52fd045f6cSArd Biesheuvel * the vmalloc region is already backed by zero shadow pages, 53fd045f6cSArd Biesheuvel * and punching holes into it is non-trivial. Since the module 54fd045f6cSArd Biesheuvel * region is not randomized when KASAN is enabled, it is even 55fd045f6cSArd Biesheuvel * less likely that the module region gets exhausted, so we 56fd045f6cSArd Biesheuvel * can simply omit this fallback in that case. 57fd045f6cSArd Biesheuvel */ 58f2b9ba87SArd Biesheuvel p = __vmalloc_node_range(size, MODULE_ALIGN, module_alloc_base, 59f2b9ba87SArd Biesheuvel module_alloc_base + SZ_4G, GFP_KERNEL, 60f2b9ba87SArd Biesheuvel PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE, 61f2b9ba87SArd Biesheuvel __builtin_return_address(0)); 62fd045f6cSArd Biesheuvel 6339d114ddSAndrey Ryabinin if (p && (kasan_module_alloc(p, size) < 0)) { 6439d114ddSAndrey Ryabinin vfree(p); 6539d114ddSAndrey Ryabinin return NULL; 6639d114ddSAndrey Ryabinin } 6739d114ddSAndrey Ryabinin 6839d114ddSAndrey Ryabinin return p; 69257cb251SWill Deacon } 70257cb251SWill Deacon 71257cb251SWill Deacon enum aarch64_reloc_op { 72257cb251SWill Deacon RELOC_OP_NONE, 73257cb251SWill Deacon RELOC_OP_ABS, 74257cb251SWill Deacon RELOC_OP_PREL, 75257cb251SWill Deacon RELOC_OP_PAGE, 76257cb251SWill Deacon }; 77257cb251SWill Deacon 7802129ae5SLuc Van Oostenryck static u64 do_reloc(enum aarch64_reloc_op reloc_op, __le32 *place, u64 val) 79257cb251SWill Deacon { 80257cb251SWill Deacon switch (reloc_op) { 81257cb251SWill Deacon case RELOC_OP_ABS: 82257cb251SWill Deacon return val; 83257cb251SWill Deacon case RELOC_OP_PREL: 84257cb251SWill Deacon return val - (u64)place; 85257cb251SWill Deacon case RELOC_OP_PAGE: 86257cb251SWill Deacon return (val & ~0xfff) - ((u64)place & ~0xfff); 87257cb251SWill Deacon case RELOC_OP_NONE: 88257cb251SWill Deacon return 0; 89257cb251SWill Deacon } 90257cb251SWill Deacon 91257cb251SWill Deacon pr_err("do_reloc: unknown relocation operation %d\n", reloc_op); 92257cb251SWill Deacon return 0; 93257cb251SWill Deacon } 94257cb251SWill Deacon 95257cb251SWill Deacon static int reloc_data(enum aarch64_reloc_op op, void *place, u64 val, int len) 96257cb251SWill Deacon { 97257cb251SWill Deacon s64 sval = do_reloc(op, place, val); 98257cb251SWill Deacon 99257cb251SWill Deacon switch (len) { 100257cb251SWill Deacon case 16: 101257cb251SWill Deacon *(s16 *)place = sval; 102f9308969SArd Biesheuvel if (sval < S16_MIN || sval > U16_MAX) 103f9308969SArd Biesheuvel return -ERANGE; 104257cb251SWill Deacon break; 105257cb251SWill Deacon case 32: 106257cb251SWill Deacon *(s32 *)place = sval; 107f9308969SArd Biesheuvel if (sval < S32_MIN || sval > U32_MAX) 108f9308969SArd Biesheuvel return -ERANGE; 109257cb251SWill Deacon break; 110257cb251SWill Deacon case 64: 111257cb251SWill Deacon *(s64 *)place = sval; 112257cb251SWill Deacon break; 113257cb251SWill Deacon default: 114257cb251SWill Deacon pr_err("Invalid length (%d) for data relocation\n", len); 115257cb251SWill Deacon return 0; 116257cb251SWill Deacon } 117257cb251SWill Deacon return 0; 118257cb251SWill Deacon } 119257cb251SWill Deacon 120b24a5575SArd Biesheuvel enum aarch64_insn_movw_imm_type { 121b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVNZ, 122b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ, 123b24a5575SArd Biesheuvel }; 124b24a5575SArd Biesheuvel 12502129ae5SLuc Van Oostenryck static int reloc_insn_movw(enum aarch64_reloc_op op, __le32 *place, u64 val, 126b24a5575SArd Biesheuvel int lsb, enum aarch64_insn_movw_imm_type imm_type) 127257cb251SWill Deacon { 128b24a5575SArd Biesheuvel u64 imm; 129c84fced8SJiang Liu s64 sval; 13002129ae5SLuc Van Oostenryck u32 insn = le32_to_cpu(*place); 131257cb251SWill Deacon 132c84fced8SJiang Liu sval = do_reloc(op, place, val); 133b24a5575SArd Biesheuvel imm = sval >> lsb; 134122e2fa0SWill Deacon 135c84fced8SJiang Liu if (imm_type == AARCH64_INSN_IMM_MOVNZ) { 136257cb251SWill Deacon /* 137257cb251SWill Deacon * For signed MOVW relocations, we have to manipulate the 138257cb251SWill Deacon * instruction encoding depending on whether or not the 139257cb251SWill Deacon * immediate is less than zero. 140257cb251SWill Deacon */ 141257cb251SWill Deacon insn &= ~(3 << 29); 142b24a5575SArd Biesheuvel if (sval >= 0) { 143257cb251SWill Deacon /* >=0: Set the instruction to MOVZ (opcode 10b). */ 144257cb251SWill Deacon insn |= 2 << 29; 145257cb251SWill Deacon } else { 146257cb251SWill Deacon /* 147257cb251SWill Deacon * <0: Set the instruction to MOVN (opcode 00b). 148257cb251SWill Deacon * Since we've masked the opcode already, we 149257cb251SWill Deacon * don't need to do anything other than 150257cb251SWill Deacon * inverting the new immediate field. 151257cb251SWill Deacon */ 152257cb251SWill Deacon imm = ~imm; 153257cb251SWill Deacon } 154257cb251SWill Deacon } 155257cb251SWill Deacon 156257cb251SWill Deacon /* Update the instruction with the new encoding. */ 157b24a5575SArd Biesheuvel insn = aarch64_insn_encode_immediate(AARCH64_INSN_IMM_16, insn, imm); 15802129ae5SLuc Van Oostenryck *place = cpu_to_le32(insn); 159257cb251SWill Deacon 160b24a5575SArd Biesheuvel if (imm > U16_MAX) 161257cb251SWill Deacon return -ERANGE; 162257cb251SWill Deacon 163257cb251SWill Deacon return 0; 164257cb251SWill Deacon } 165257cb251SWill Deacon 16602129ae5SLuc Van Oostenryck static int reloc_insn_imm(enum aarch64_reloc_op op, __le32 *place, u64 val, 167c84fced8SJiang Liu int lsb, int len, enum aarch64_insn_imm_type imm_type) 168257cb251SWill Deacon { 169257cb251SWill Deacon u64 imm, imm_mask; 170257cb251SWill Deacon s64 sval; 17102129ae5SLuc Van Oostenryck u32 insn = le32_to_cpu(*place); 172257cb251SWill Deacon 173257cb251SWill Deacon /* Calculate the relocation value. */ 174257cb251SWill Deacon sval = do_reloc(op, place, val); 175257cb251SWill Deacon sval >>= lsb; 176257cb251SWill Deacon 177257cb251SWill Deacon /* Extract the value bits and shift them to bit 0. */ 178257cb251SWill Deacon imm_mask = (BIT(lsb + len) - 1) >> lsb; 179257cb251SWill Deacon imm = sval & imm_mask; 180257cb251SWill Deacon 181257cb251SWill Deacon /* Update the instruction's immediate field. */ 182c84fced8SJiang Liu insn = aarch64_insn_encode_immediate(imm_type, insn, imm); 18302129ae5SLuc Van Oostenryck *place = cpu_to_le32(insn); 184257cb251SWill Deacon 185257cb251SWill Deacon /* 186257cb251SWill Deacon * Extract the upper value bits (including the sign bit) and 187257cb251SWill Deacon * shift them to bit 0. 188257cb251SWill Deacon */ 189257cb251SWill Deacon sval = (s64)(sval & ~(imm_mask >> 1)) >> (len - 1); 190257cb251SWill Deacon 191257cb251SWill Deacon /* 192257cb251SWill Deacon * Overflow has occurred if the upper bits are not all equal to 193257cb251SWill Deacon * the sign bit of the value. 194257cb251SWill Deacon */ 195257cb251SWill Deacon if ((u64)(sval + 1) >= 2) 196257cb251SWill Deacon return -ERANGE; 197257cb251SWill Deacon 198257cb251SWill Deacon return 0; 199257cb251SWill Deacon } 200257cb251SWill Deacon 201*c8ebf64eSJessica Yu static int reloc_insn_adrp(struct module *mod, Elf64_Shdr *sechdrs, 202*c8ebf64eSJessica Yu __le32 *place, u64 val) 203a257e025SArd Biesheuvel { 204a257e025SArd Biesheuvel u32 insn; 205a257e025SArd Biesheuvel 206a257e025SArd Biesheuvel if (!IS_ENABLED(CONFIG_ARM64_ERRATUM_843419) || 207ca79accaSArd Biesheuvel !cpus_have_const_cap(ARM64_WORKAROUND_843419) || 208a257e025SArd Biesheuvel ((u64)place & 0xfff) < 0xff8) 209a257e025SArd Biesheuvel return reloc_insn_imm(RELOC_OP_PAGE, place, val, 12, 21, 210a257e025SArd Biesheuvel AARCH64_INSN_IMM_ADR); 211a257e025SArd Biesheuvel 212a257e025SArd Biesheuvel /* patch ADRP to ADR if it is in range */ 213a257e025SArd Biesheuvel if (!reloc_insn_imm(RELOC_OP_PREL, place, val & ~0xfff, 0, 21, 214a257e025SArd Biesheuvel AARCH64_INSN_IMM_ADR)) { 215a257e025SArd Biesheuvel insn = le32_to_cpu(*place); 216a257e025SArd Biesheuvel insn &= ~BIT(31); 217a257e025SArd Biesheuvel } else { 218a257e025SArd Biesheuvel /* out of range for ADR -> emit a veneer */ 219*c8ebf64eSJessica Yu val = module_emit_veneer_for_adrp(mod, sechdrs, place, val & ~0xfff); 220a257e025SArd Biesheuvel if (!val) 221a257e025SArd Biesheuvel return -ENOEXEC; 222a257e025SArd Biesheuvel insn = aarch64_insn_gen_branch_imm((u64)place, val, 223a257e025SArd Biesheuvel AARCH64_INSN_BRANCH_NOLINK); 224a257e025SArd Biesheuvel } 225a257e025SArd Biesheuvel 226a257e025SArd Biesheuvel *place = cpu_to_le32(insn); 227a257e025SArd Biesheuvel return 0; 228a257e025SArd Biesheuvel } 229a257e025SArd Biesheuvel 230257cb251SWill Deacon int apply_relocate_add(Elf64_Shdr *sechdrs, 231257cb251SWill Deacon const char *strtab, 232257cb251SWill Deacon unsigned int symindex, 233257cb251SWill Deacon unsigned int relsec, 234257cb251SWill Deacon struct module *me) 235257cb251SWill Deacon { 236257cb251SWill Deacon unsigned int i; 237257cb251SWill Deacon int ovf; 238257cb251SWill Deacon bool overflow_check; 239257cb251SWill Deacon Elf64_Sym *sym; 240257cb251SWill Deacon void *loc; 241257cb251SWill Deacon u64 val; 242257cb251SWill Deacon Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr; 243257cb251SWill Deacon 244257cb251SWill Deacon for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { 245257cb251SWill Deacon /* loc corresponds to P in the AArch64 ELF document. */ 246257cb251SWill Deacon loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr 247257cb251SWill Deacon + rel[i].r_offset; 248257cb251SWill Deacon 249257cb251SWill Deacon /* sym is the ELF symbol we're referring to. */ 250257cb251SWill Deacon sym = (Elf64_Sym *)sechdrs[symindex].sh_addr 251257cb251SWill Deacon + ELF64_R_SYM(rel[i].r_info); 252257cb251SWill Deacon 253257cb251SWill Deacon /* val corresponds to (S + A) in the AArch64 ELF document. */ 254257cb251SWill Deacon val = sym->st_value + rel[i].r_addend; 255257cb251SWill Deacon 256257cb251SWill Deacon /* Check for overflow by default. */ 257257cb251SWill Deacon overflow_check = true; 258257cb251SWill Deacon 259257cb251SWill Deacon /* Perform the static relocation. */ 260257cb251SWill Deacon switch (ELF64_R_TYPE(rel[i].r_info)) { 261257cb251SWill Deacon /* Null relocations. */ 262257cb251SWill Deacon case R_ARM_NONE: 263257cb251SWill Deacon case R_AARCH64_NONE: 264257cb251SWill Deacon ovf = 0; 265257cb251SWill Deacon break; 266257cb251SWill Deacon 267257cb251SWill Deacon /* Data relocations. */ 268257cb251SWill Deacon case R_AARCH64_ABS64: 269257cb251SWill Deacon overflow_check = false; 270257cb251SWill Deacon ovf = reloc_data(RELOC_OP_ABS, loc, val, 64); 271257cb251SWill Deacon break; 272257cb251SWill Deacon case R_AARCH64_ABS32: 273257cb251SWill Deacon ovf = reloc_data(RELOC_OP_ABS, loc, val, 32); 274257cb251SWill Deacon break; 275257cb251SWill Deacon case R_AARCH64_ABS16: 276257cb251SWill Deacon ovf = reloc_data(RELOC_OP_ABS, loc, val, 16); 277257cb251SWill Deacon break; 278257cb251SWill Deacon case R_AARCH64_PREL64: 279257cb251SWill Deacon overflow_check = false; 280257cb251SWill Deacon ovf = reloc_data(RELOC_OP_PREL, loc, val, 64); 281257cb251SWill Deacon break; 282257cb251SWill Deacon case R_AARCH64_PREL32: 283257cb251SWill Deacon ovf = reloc_data(RELOC_OP_PREL, loc, val, 32); 284257cb251SWill Deacon break; 285257cb251SWill Deacon case R_AARCH64_PREL16: 286257cb251SWill Deacon ovf = reloc_data(RELOC_OP_PREL, loc, val, 16); 287257cb251SWill Deacon break; 288257cb251SWill Deacon 289257cb251SWill Deacon /* MOVW instruction relocations. */ 290257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G0_NC: 291257cb251SWill Deacon overflow_check = false; 292257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G0: 293257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0, 294b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 295257cb251SWill Deacon break; 296257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G1_NC: 297257cb251SWill Deacon overflow_check = false; 298257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G1: 299257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16, 300b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 301257cb251SWill Deacon break; 302257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G2_NC: 303257cb251SWill Deacon overflow_check = false; 304257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G2: 305257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32, 306b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 307257cb251SWill Deacon break; 308257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G3: 309257cb251SWill Deacon /* We're using the top bits so we can't overflow. */ 310257cb251SWill Deacon overflow_check = false; 311257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 48, 312b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 313257cb251SWill Deacon break; 314257cb251SWill Deacon case R_AARCH64_MOVW_SABS_G0: 315257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0, 316c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 317257cb251SWill Deacon break; 318257cb251SWill Deacon case R_AARCH64_MOVW_SABS_G1: 319257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16, 320c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 321257cb251SWill Deacon break; 322257cb251SWill Deacon case R_AARCH64_MOVW_SABS_G2: 323257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32, 324c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 325257cb251SWill Deacon break; 326257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G0_NC: 327257cb251SWill Deacon overflow_check = false; 328257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0, 329b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 330257cb251SWill Deacon break; 331257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G0: 332257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0, 333c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 334257cb251SWill Deacon break; 335257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G1_NC: 336257cb251SWill Deacon overflow_check = false; 337257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16, 338b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 339257cb251SWill Deacon break; 340257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G1: 341257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16, 342c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 343257cb251SWill Deacon break; 344257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G2_NC: 345257cb251SWill Deacon overflow_check = false; 346257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32, 347b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 348257cb251SWill Deacon break; 349257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G2: 350257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32, 351c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 352257cb251SWill Deacon break; 353257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G3: 354257cb251SWill Deacon /* We're using the top bits so we can't overflow. */ 355257cb251SWill Deacon overflow_check = false; 356257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 48, 357c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 358257cb251SWill Deacon break; 359257cb251SWill Deacon 360257cb251SWill Deacon /* Immediate instruction relocations. */ 361257cb251SWill Deacon case R_AARCH64_LD_PREL_LO19: 362257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 19, 363c84fced8SJiang Liu AARCH64_INSN_IMM_19); 364257cb251SWill Deacon break; 365257cb251SWill Deacon case R_AARCH64_ADR_PREL_LO21: 366257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 0, 21, 367c84fced8SJiang Liu AARCH64_INSN_IMM_ADR); 368257cb251SWill Deacon break; 369257cb251SWill Deacon case R_AARCH64_ADR_PREL_PG_HI21_NC: 370257cb251SWill Deacon overflow_check = false; 371257cb251SWill Deacon case R_AARCH64_ADR_PREL_PG_HI21: 372*c8ebf64eSJessica Yu ovf = reloc_insn_adrp(me, sechdrs, loc, val); 373a257e025SArd Biesheuvel if (ovf && ovf != -ERANGE) 374a257e025SArd Biesheuvel return ovf; 375257cb251SWill Deacon break; 376257cb251SWill Deacon case R_AARCH64_ADD_ABS_LO12_NC: 377257cb251SWill Deacon case R_AARCH64_LDST8_ABS_LO12_NC: 378257cb251SWill Deacon overflow_check = false; 379257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 0, 12, 380c84fced8SJiang Liu AARCH64_INSN_IMM_12); 381257cb251SWill Deacon break; 382257cb251SWill Deacon case R_AARCH64_LDST16_ABS_LO12_NC: 383257cb251SWill Deacon overflow_check = false; 384257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 1, 11, 385c84fced8SJiang Liu AARCH64_INSN_IMM_12); 386257cb251SWill Deacon break; 387257cb251SWill Deacon case R_AARCH64_LDST32_ABS_LO12_NC: 388257cb251SWill Deacon overflow_check = false; 389257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 2, 10, 390c84fced8SJiang Liu AARCH64_INSN_IMM_12); 391257cb251SWill Deacon break; 392257cb251SWill Deacon case R_AARCH64_LDST64_ABS_LO12_NC: 393257cb251SWill Deacon overflow_check = false; 394257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 3, 9, 395c84fced8SJiang Liu AARCH64_INSN_IMM_12); 396257cb251SWill Deacon break; 397257cb251SWill Deacon case R_AARCH64_LDST128_ABS_LO12_NC: 398257cb251SWill Deacon overflow_check = false; 399257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 4, 8, 400c84fced8SJiang Liu AARCH64_INSN_IMM_12); 401257cb251SWill Deacon break; 402257cb251SWill Deacon case R_AARCH64_TSTBR14: 403257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 14, 404c84fced8SJiang Liu AARCH64_INSN_IMM_14); 405257cb251SWill Deacon break; 406257cb251SWill Deacon case R_AARCH64_CONDBR19: 407257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 19, 408c84fced8SJiang Liu AARCH64_INSN_IMM_19); 409257cb251SWill Deacon break; 410257cb251SWill Deacon case R_AARCH64_JUMP26: 411257cb251SWill Deacon case R_AARCH64_CALL26: 412257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 26, 413c84fced8SJiang Liu AARCH64_INSN_IMM_26); 414fd045f6cSArd Biesheuvel 415fd045f6cSArd Biesheuvel if (IS_ENABLED(CONFIG_ARM64_MODULE_PLTS) && 416fd045f6cSArd Biesheuvel ovf == -ERANGE) { 417*c8ebf64eSJessica Yu val = module_emit_plt_entry(me, sechdrs, loc, &rel[i], sym); 4185e8307b9SArd Biesheuvel if (!val) 4195e8307b9SArd Biesheuvel return -ENOEXEC; 420fd045f6cSArd Biesheuvel ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 421fd045f6cSArd Biesheuvel 26, AARCH64_INSN_IMM_26); 422fd045f6cSArd Biesheuvel } 423257cb251SWill Deacon break; 424257cb251SWill Deacon 425257cb251SWill Deacon default: 426257cb251SWill Deacon pr_err("module %s: unsupported RELA relocation: %llu\n", 427257cb251SWill Deacon me->name, ELF64_R_TYPE(rel[i].r_info)); 428257cb251SWill Deacon return -ENOEXEC; 429257cb251SWill Deacon } 430257cb251SWill Deacon 431257cb251SWill Deacon if (overflow_check && ovf == -ERANGE) 432257cb251SWill Deacon goto overflow; 433257cb251SWill Deacon 434257cb251SWill Deacon } 435257cb251SWill Deacon 436257cb251SWill Deacon return 0; 437257cb251SWill Deacon 438257cb251SWill Deacon overflow: 439257cb251SWill Deacon pr_err("module %s: overflow in relocation type %d val %Lx\n", 440257cb251SWill Deacon me->name, (int)ELF64_R_TYPE(rel[i].r_info), val); 441257cb251SWill Deacon return -ENOEXEC; 442257cb251SWill Deacon } 443932ded4bSAndre Przywara 444932ded4bSAndre Przywara int module_finalize(const Elf_Ehdr *hdr, 445932ded4bSAndre Przywara const Elf_Shdr *sechdrs, 446932ded4bSAndre Przywara struct module *me) 447932ded4bSAndre Przywara { 448932ded4bSAndre Przywara const Elf_Shdr *s, *se; 449932ded4bSAndre Przywara const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; 450932ded4bSAndre Przywara 451932ded4bSAndre Przywara for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++) { 45242938868SWill Deacon if (strcmp(".altinstructions", secstrs + s->sh_name) == 0) 45342938868SWill Deacon apply_alternatives_module((void *)s->sh_addr, s->sh_size); 454e71a4e1bSArd Biesheuvel #ifdef CONFIG_ARM64_MODULE_PLTS 455e71a4e1bSArd Biesheuvel if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE) && 456e71a4e1bSArd Biesheuvel !strcmp(".text.ftrace_trampoline", secstrs + s->sh_name)) 457e71a4e1bSArd Biesheuvel me->arch.ftrace_trampoline = (void *)s->sh_addr; 458e71a4e1bSArd Biesheuvel #endif 459932ded4bSAndre Przywara } 460932ded4bSAndre Przywara 461932ded4bSAndre Przywara return 0; 462932ded4bSAndre Przywara } 463