1caab277bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2257cb251SWill Deacon /* 3257cb251SWill Deacon * AArch64 loadable module support. 4257cb251SWill Deacon * 5257cb251SWill Deacon * Copyright (C) 2012 ARM Limited 6257cb251SWill Deacon * 7257cb251SWill Deacon * Author: Will Deacon <will.deacon@arm.com> 8257cb251SWill Deacon */ 9257cb251SWill Deacon 10257cb251SWill Deacon #include <linux/bitops.h> 11257cb251SWill Deacon #include <linux/elf.h> 12f1a54ae9SMark Rutland #include <linux/ftrace.h> 13257cb251SWill Deacon #include <linux/gfp.h> 1439d114ddSAndrey Ryabinin #include <linux/kasan.h> 15257cb251SWill Deacon #include <linux/kernel.h> 16257cb251SWill Deacon #include <linux/mm.h> 17257cb251SWill Deacon #include <linux/moduleloader.h> 183b619e22SArd Biesheuvel #include <linux/scs.h> 19257cb251SWill Deacon #include <linux/vmalloc.h> 202c2b282dSPaul Walmsley #include <asm/alternative.h> 21c84fced8SJiang Liu #include <asm/insn.h> 223b619e22SArd Biesheuvel #include <asm/scs.h> 23932ded4bSAndre Przywara #include <asm/sections.h> 24c84fced8SJiang Liu 25257cb251SWill Deacon void *module_alloc(unsigned long size) 26257cb251SWill Deacon { 276f496a55SArd Biesheuvel u64 module_alloc_end = module_alloc_base + MODULES_VSIZE; 280c2cf6d9SFlorian Fainelli gfp_t gfp_mask = GFP_KERNEL; 2939d114ddSAndrey Ryabinin void *p; 3039d114ddSAndrey Ryabinin 310c2cf6d9SFlorian Fainelli /* Silence the initial allocation */ 320c2cf6d9SFlorian Fainelli if (IS_ENABLED(CONFIG_ARM64_MODULE_PLTS)) 330c2cf6d9SFlorian Fainelli gfp_mask |= __GFP_NOWARN; 340c2cf6d9SFlorian Fainelli 35f80fb3a3SArd Biesheuvel p = __vmalloc_node_range(size, MODULE_ALIGN, module_alloc_base, 36*8339f7d8SMark Rutland module_alloc_end, gfp_mask, PAGE_KERNEL, 0, 37cb9e3c29SAndrey Ryabinin NUMA_NO_NODE, __builtin_return_address(0)); 3839d114ddSAndrey Ryabinin 39*8339f7d8SMark Rutland if (!p && IS_ENABLED(CONFIG_ARM64_MODULE_PLTS)) { 40f2b9ba87SArd Biesheuvel p = __vmalloc_node_range(size, MODULE_ALIGN, module_alloc_base, 41b2eed9b5SArd Biesheuvel module_alloc_base + SZ_2G, GFP_KERNEL, 427dfac3c5SArd Biesheuvel PAGE_KERNEL, 0, NUMA_NO_NODE, 43f2b9ba87SArd Biesheuvel __builtin_return_address(0)); 44*8339f7d8SMark Rutland } 45fd045f6cSArd Biesheuvel 4663840de2SAndrey Konovalov if (p && (kasan_alloc_module_shadow(p, size, gfp_mask) < 0)) { 4739d114ddSAndrey Ryabinin vfree(p); 4839d114ddSAndrey Ryabinin return NULL; 4939d114ddSAndrey Ryabinin } 5039d114ddSAndrey Ryabinin 5136c4a73bSAndrey Konovalov /* Memory is intended to be executable, reset the pointer tag. */ 5236c4a73bSAndrey Konovalov return kasan_reset_tag(p); 53257cb251SWill Deacon } 54257cb251SWill Deacon 55257cb251SWill Deacon enum aarch64_reloc_op { 56257cb251SWill Deacon RELOC_OP_NONE, 57257cb251SWill Deacon RELOC_OP_ABS, 58257cb251SWill Deacon RELOC_OP_PREL, 59257cb251SWill Deacon RELOC_OP_PAGE, 60257cb251SWill Deacon }; 61257cb251SWill Deacon 6202129ae5SLuc Van Oostenryck static u64 do_reloc(enum aarch64_reloc_op reloc_op, __le32 *place, u64 val) 63257cb251SWill Deacon { 64257cb251SWill Deacon switch (reloc_op) { 65257cb251SWill Deacon case RELOC_OP_ABS: 66257cb251SWill Deacon return val; 67257cb251SWill Deacon case RELOC_OP_PREL: 68257cb251SWill Deacon return val - (u64)place; 69257cb251SWill Deacon case RELOC_OP_PAGE: 70257cb251SWill Deacon return (val & ~0xfff) - ((u64)place & ~0xfff); 71257cb251SWill Deacon case RELOC_OP_NONE: 72257cb251SWill Deacon return 0; 73257cb251SWill Deacon } 74257cb251SWill Deacon 75257cb251SWill Deacon pr_err("do_reloc: unknown relocation operation %d\n", reloc_op); 76257cb251SWill Deacon return 0; 77257cb251SWill Deacon } 78257cb251SWill Deacon 79257cb251SWill Deacon static int reloc_data(enum aarch64_reloc_op op, void *place, u64 val, int len) 80257cb251SWill Deacon { 81257cb251SWill Deacon s64 sval = do_reloc(op, place, val); 82257cb251SWill Deacon 831cf24a2cSArd Biesheuvel /* 841cf24a2cSArd Biesheuvel * The ELF psABI for AArch64 documents the 16-bit and 32-bit place 853fd00bebSArd Biesheuvel * relative and absolute relocations as having a range of [-2^15, 2^16) 863fd00bebSArd Biesheuvel * or [-2^31, 2^32), respectively. However, in order to be able to 873fd00bebSArd Biesheuvel * detect overflows reliably, we have to choose whether we interpret 883fd00bebSArd Biesheuvel * such quantities as signed or as unsigned, and stick with it. 891cf24a2cSArd Biesheuvel * The way we organize our address space requires a signed 901cf24a2cSArd Biesheuvel * interpretation of 32-bit relative references, so let's use that 911cf24a2cSArd Biesheuvel * for all R_AARCH64_PRELxx relocations. This means our upper 921cf24a2cSArd Biesheuvel * bound for overflow detection should be Sxx_MAX rather than Uxx_MAX. 931cf24a2cSArd Biesheuvel */ 941cf24a2cSArd Biesheuvel 95257cb251SWill Deacon switch (len) { 96257cb251SWill Deacon case 16: 97257cb251SWill Deacon *(s16 *)place = sval; 983fd00bebSArd Biesheuvel switch (op) { 993fd00bebSArd Biesheuvel case RELOC_OP_ABS: 1003fd00bebSArd Biesheuvel if (sval < 0 || sval > U16_MAX) 1013fd00bebSArd Biesheuvel return -ERANGE; 1023fd00bebSArd Biesheuvel break; 1033fd00bebSArd Biesheuvel case RELOC_OP_PREL: 1041cf24a2cSArd Biesheuvel if (sval < S16_MIN || sval > S16_MAX) 105f9308969SArd Biesheuvel return -ERANGE; 106257cb251SWill Deacon break; 1073fd00bebSArd Biesheuvel default: 1083fd00bebSArd Biesheuvel pr_err("Invalid 16-bit data relocation (%d)\n", op); 1093fd00bebSArd Biesheuvel return 0; 1103fd00bebSArd Biesheuvel } 1113fd00bebSArd Biesheuvel break; 112257cb251SWill Deacon case 32: 113257cb251SWill Deacon *(s32 *)place = sval; 1143fd00bebSArd Biesheuvel switch (op) { 1153fd00bebSArd Biesheuvel case RELOC_OP_ABS: 1163fd00bebSArd Biesheuvel if (sval < 0 || sval > U32_MAX) 1173fd00bebSArd Biesheuvel return -ERANGE; 1183fd00bebSArd Biesheuvel break; 1193fd00bebSArd Biesheuvel case RELOC_OP_PREL: 1201cf24a2cSArd Biesheuvel if (sval < S32_MIN || sval > S32_MAX) 121f9308969SArd Biesheuvel return -ERANGE; 122257cb251SWill Deacon break; 1233fd00bebSArd Biesheuvel default: 1243fd00bebSArd Biesheuvel pr_err("Invalid 32-bit data relocation (%d)\n", op); 1253fd00bebSArd Biesheuvel return 0; 1263fd00bebSArd Biesheuvel } 1273fd00bebSArd Biesheuvel break; 128257cb251SWill Deacon case 64: 129257cb251SWill Deacon *(s64 *)place = sval; 130257cb251SWill Deacon break; 131257cb251SWill Deacon default: 132257cb251SWill Deacon pr_err("Invalid length (%d) for data relocation\n", len); 133257cb251SWill Deacon return 0; 134257cb251SWill Deacon } 135257cb251SWill Deacon return 0; 136257cb251SWill Deacon } 137257cb251SWill Deacon 138b24a5575SArd Biesheuvel enum aarch64_insn_movw_imm_type { 139b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVNZ, 140b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ, 141b24a5575SArd Biesheuvel }; 142b24a5575SArd Biesheuvel 14302129ae5SLuc Van Oostenryck static int reloc_insn_movw(enum aarch64_reloc_op op, __le32 *place, u64 val, 144b24a5575SArd Biesheuvel int lsb, enum aarch64_insn_movw_imm_type imm_type) 145257cb251SWill Deacon { 146b24a5575SArd Biesheuvel u64 imm; 147c84fced8SJiang Liu s64 sval; 14802129ae5SLuc Van Oostenryck u32 insn = le32_to_cpu(*place); 149257cb251SWill Deacon 150c84fced8SJiang Liu sval = do_reloc(op, place, val); 151b24a5575SArd Biesheuvel imm = sval >> lsb; 152122e2fa0SWill Deacon 153c84fced8SJiang Liu if (imm_type == AARCH64_INSN_IMM_MOVNZ) { 154257cb251SWill Deacon /* 155257cb251SWill Deacon * For signed MOVW relocations, we have to manipulate the 156257cb251SWill Deacon * instruction encoding depending on whether or not the 157257cb251SWill Deacon * immediate is less than zero. 158257cb251SWill Deacon */ 159257cb251SWill Deacon insn &= ~(3 << 29); 160b24a5575SArd Biesheuvel if (sval >= 0) { 161257cb251SWill Deacon /* >=0: Set the instruction to MOVZ (opcode 10b). */ 162257cb251SWill Deacon insn |= 2 << 29; 163257cb251SWill Deacon } else { 164257cb251SWill Deacon /* 165257cb251SWill Deacon * <0: Set the instruction to MOVN (opcode 00b). 166257cb251SWill Deacon * Since we've masked the opcode already, we 167257cb251SWill Deacon * don't need to do anything other than 168257cb251SWill Deacon * inverting the new immediate field. 169257cb251SWill Deacon */ 170257cb251SWill Deacon imm = ~imm; 171257cb251SWill Deacon } 172257cb251SWill Deacon } 173257cb251SWill Deacon 174257cb251SWill Deacon /* Update the instruction with the new encoding. */ 175b24a5575SArd Biesheuvel insn = aarch64_insn_encode_immediate(AARCH64_INSN_IMM_16, insn, imm); 17602129ae5SLuc Van Oostenryck *place = cpu_to_le32(insn); 177257cb251SWill Deacon 178b24a5575SArd Biesheuvel if (imm > U16_MAX) 179257cb251SWill Deacon return -ERANGE; 180257cb251SWill Deacon 181257cb251SWill Deacon return 0; 182257cb251SWill Deacon } 183257cb251SWill Deacon 18402129ae5SLuc Van Oostenryck static int reloc_insn_imm(enum aarch64_reloc_op op, __le32 *place, u64 val, 185c84fced8SJiang Liu int lsb, int len, enum aarch64_insn_imm_type imm_type) 186257cb251SWill Deacon { 187257cb251SWill Deacon u64 imm, imm_mask; 188257cb251SWill Deacon s64 sval; 18902129ae5SLuc Van Oostenryck u32 insn = le32_to_cpu(*place); 190257cb251SWill Deacon 191257cb251SWill Deacon /* Calculate the relocation value. */ 192257cb251SWill Deacon sval = do_reloc(op, place, val); 193257cb251SWill Deacon sval >>= lsb; 194257cb251SWill Deacon 195257cb251SWill Deacon /* Extract the value bits and shift them to bit 0. */ 196257cb251SWill Deacon imm_mask = (BIT(lsb + len) - 1) >> lsb; 197257cb251SWill Deacon imm = sval & imm_mask; 198257cb251SWill Deacon 199257cb251SWill Deacon /* Update the instruction's immediate field. */ 200c84fced8SJiang Liu insn = aarch64_insn_encode_immediate(imm_type, insn, imm); 20102129ae5SLuc Van Oostenryck *place = cpu_to_le32(insn); 202257cb251SWill Deacon 203257cb251SWill Deacon /* 204257cb251SWill Deacon * Extract the upper value bits (including the sign bit) and 205257cb251SWill Deacon * shift them to bit 0. 206257cb251SWill Deacon */ 207257cb251SWill Deacon sval = (s64)(sval & ~(imm_mask >> 1)) >> (len - 1); 208257cb251SWill Deacon 209257cb251SWill Deacon /* 210257cb251SWill Deacon * Overflow has occurred if the upper bits are not all equal to 211257cb251SWill Deacon * the sign bit of the value. 212257cb251SWill Deacon */ 213257cb251SWill Deacon if ((u64)(sval + 1) >= 2) 214257cb251SWill Deacon return -ERANGE; 215257cb251SWill Deacon 216257cb251SWill Deacon return 0; 217257cb251SWill Deacon } 218257cb251SWill Deacon 219c8ebf64eSJessica Yu static int reloc_insn_adrp(struct module *mod, Elf64_Shdr *sechdrs, 220c8ebf64eSJessica Yu __le32 *place, u64 val) 221a257e025SArd Biesheuvel { 222a257e025SArd Biesheuvel u32 insn; 223a257e025SArd Biesheuvel 224bdb85cd1SArd Biesheuvel if (!is_forbidden_offset_for_adrp(place)) 225a257e025SArd Biesheuvel return reloc_insn_imm(RELOC_OP_PAGE, place, val, 12, 21, 226a257e025SArd Biesheuvel AARCH64_INSN_IMM_ADR); 227a257e025SArd Biesheuvel 228a257e025SArd Biesheuvel /* patch ADRP to ADR if it is in range */ 229a257e025SArd Biesheuvel if (!reloc_insn_imm(RELOC_OP_PREL, place, val & ~0xfff, 0, 21, 230a257e025SArd Biesheuvel AARCH64_INSN_IMM_ADR)) { 231a257e025SArd Biesheuvel insn = le32_to_cpu(*place); 232a257e025SArd Biesheuvel insn &= ~BIT(31); 233a257e025SArd Biesheuvel } else { 234a257e025SArd Biesheuvel /* out of range for ADR -> emit a veneer */ 235c8ebf64eSJessica Yu val = module_emit_veneer_for_adrp(mod, sechdrs, place, val & ~0xfff); 236a257e025SArd Biesheuvel if (!val) 237a257e025SArd Biesheuvel return -ENOEXEC; 238a257e025SArd Biesheuvel insn = aarch64_insn_gen_branch_imm((u64)place, val, 239a257e025SArd Biesheuvel AARCH64_INSN_BRANCH_NOLINK); 240a257e025SArd Biesheuvel } 241a257e025SArd Biesheuvel 242a257e025SArd Biesheuvel *place = cpu_to_le32(insn); 243a257e025SArd Biesheuvel return 0; 244a257e025SArd Biesheuvel } 245a257e025SArd Biesheuvel 246257cb251SWill Deacon int apply_relocate_add(Elf64_Shdr *sechdrs, 247257cb251SWill Deacon const char *strtab, 248257cb251SWill Deacon unsigned int symindex, 249257cb251SWill Deacon unsigned int relsec, 250257cb251SWill Deacon struct module *me) 251257cb251SWill Deacon { 252257cb251SWill Deacon unsigned int i; 253257cb251SWill Deacon int ovf; 254257cb251SWill Deacon bool overflow_check; 255257cb251SWill Deacon Elf64_Sym *sym; 256257cb251SWill Deacon void *loc; 257257cb251SWill Deacon u64 val; 258257cb251SWill Deacon Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr; 259257cb251SWill Deacon 260257cb251SWill Deacon for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { 261257cb251SWill Deacon /* loc corresponds to P in the AArch64 ELF document. */ 262257cb251SWill Deacon loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr 263257cb251SWill Deacon + rel[i].r_offset; 264257cb251SWill Deacon 265257cb251SWill Deacon /* sym is the ELF symbol we're referring to. */ 266257cb251SWill Deacon sym = (Elf64_Sym *)sechdrs[symindex].sh_addr 267257cb251SWill Deacon + ELF64_R_SYM(rel[i].r_info); 268257cb251SWill Deacon 269257cb251SWill Deacon /* val corresponds to (S + A) in the AArch64 ELF document. */ 270257cb251SWill Deacon val = sym->st_value + rel[i].r_addend; 271257cb251SWill Deacon 272257cb251SWill Deacon /* Check for overflow by default. */ 273257cb251SWill Deacon overflow_check = true; 274257cb251SWill Deacon 275257cb251SWill Deacon /* Perform the static relocation. */ 276257cb251SWill Deacon switch (ELF64_R_TYPE(rel[i].r_info)) { 277257cb251SWill Deacon /* Null relocations. */ 278257cb251SWill Deacon case R_ARM_NONE: 279257cb251SWill Deacon case R_AARCH64_NONE: 280257cb251SWill Deacon ovf = 0; 281257cb251SWill Deacon break; 282257cb251SWill Deacon 283257cb251SWill Deacon /* Data relocations. */ 284257cb251SWill Deacon case R_AARCH64_ABS64: 285257cb251SWill Deacon overflow_check = false; 286257cb251SWill Deacon ovf = reloc_data(RELOC_OP_ABS, loc, val, 64); 287257cb251SWill Deacon break; 288257cb251SWill Deacon case R_AARCH64_ABS32: 289257cb251SWill Deacon ovf = reloc_data(RELOC_OP_ABS, loc, val, 32); 290257cb251SWill Deacon break; 291257cb251SWill Deacon case R_AARCH64_ABS16: 292257cb251SWill Deacon ovf = reloc_data(RELOC_OP_ABS, loc, val, 16); 293257cb251SWill Deacon break; 294257cb251SWill Deacon case R_AARCH64_PREL64: 295257cb251SWill Deacon overflow_check = false; 296257cb251SWill Deacon ovf = reloc_data(RELOC_OP_PREL, loc, val, 64); 297257cb251SWill Deacon break; 298257cb251SWill Deacon case R_AARCH64_PREL32: 299257cb251SWill Deacon ovf = reloc_data(RELOC_OP_PREL, loc, val, 32); 300257cb251SWill Deacon break; 301257cb251SWill Deacon case R_AARCH64_PREL16: 302257cb251SWill Deacon ovf = reloc_data(RELOC_OP_PREL, loc, val, 16); 303257cb251SWill Deacon break; 304257cb251SWill Deacon 305257cb251SWill Deacon /* MOVW instruction relocations. */ 306257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G0_NC: 307257cb251SWill Deacon overflow_check = false; 308df561f66SGustavo A. R. Silva fallthrough; 309257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G0: 310257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0, 311b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 312257cb251SWill Deacon break; 313257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G1_NC: 314257cb251SWill Deacon overflow_check = false; 315df561f66SGustavo A. R. Silva fallthrough; 316257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G1: 317257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16, 318b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 319257cb251SWill Deacon break; 320257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G2_NC: 321257cb251SWill Deacon overflow_check = false; 322df561f66SGustavo A. R. Silva fallthrough; 323257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G2: 324257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32, 325b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 326257cb251SWill Deacon break; 327257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G3: 328257cb251SWill Deacon /* We're using the top bits so we can't overflow. */ 329257cb251SWill Deacon overflow_check = false; 330257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 48, 331b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 332257cb251SWill Deacon break; 333257cb251SWill Deacon case R_AARCH64_MOVW_SABS_G0: 334257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0, 335c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 336257cb251SWill Deacon break; 337257cb251SWill Deacon case R_AARCH64_MOVW_SABS_G1: 338257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16, 339c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 340257cb251SWill Deacon break; 341257cb251SWill Deacon case R_AARCH64_MOVW_SABS_G2: 342257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32, 343c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 344257cb251SWill Deacon break; 345257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G0_NC: 346257cb251SWill Deacon overflow_check = false; 347257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0, 348b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 349257cb251SWill Deacon break; 350257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G0: 351257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0, 352c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 353257cb251SWill Deacon break; 354257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G1_NC: 355257cb251SWill Deacon overflow_check = false; 356257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16, 357b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 358257cb251SWill Deacon break; 359257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G1: 360257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16, 361c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 362257cb251SWill Deacon break; 363257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G2_NC: 364257cb251SWill Deacon overflow_check = false; 365257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32, 366b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 367257cb251SWill Deacon break; 368257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G2: 369257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32, 370c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 371257cb251SWill Deacon break; 372257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G3: 373257cb251SWill Deacon /* We're using the top bits so we can't overflow. */ 374257cb251SWill Deacon overflow_check = false; 375257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 48, 376c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 377257cb251SWill Deacon break; 378257cb251SWill Deacon 379257cb251SWill Deacon /* Immediate instruction relocations. */ 380257cb251SWill Deacon case R_AARCH64_LD_PREL_LO19: 381257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 19, 382c84fced8SJiang Liu AARCH64_INSN_IMM_19); 383257cb251SWill Deacon break; 384257cb251SWill Deacon case R_AARCH64_ADR_PREL_LO21: 385257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 0, 21, 386c84fced8SJiang Liu AARCH64_INSN_IMM_ADR); 387257cb251SWill Deacon break; 388257cb251SWill Deacon case R_AARCH64_ADR_PREL_PG_HI21_NC: 389257cb251SWill Deacon overflow_check = false; 390df561f66SGustavo A. R. Silva fallthrough; 391257cb251SWill Deacon case R_AARCH64_ADR_PREL_PG_HI21: 392c8ebf64eSJessica Yu ovf = reloc_insn_adrp(me, sechdrs, loc, val); 393a257e025SArd Biesheuvel if (ovf && ovf != -ERANGE) 394a257e025SArd Biesheuvel return ovf; 395257cb251SWill Deacon break; 396257cb251SWill Deacon case R_AARCH64_ADD_ABS_LO12_NC: 397257cb251SWill Deacon case R_AARCH64_LDST8_ABS_LO12_NC: 398257cb251SWill Deacon overflow_check = false; 399257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 0, 12, 400c84fced8SJiang Liu AARCH64_INSN_IMM_12); 401257cb251SWill Deacon break; 402257cb251SWill Deacon case R_AARCH64_LDST16_ABS_LO12_NC: 403257cb251SWill Deacon overflow_check = false; 404257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 1, 11, 405c84fced8SJiang Liu AARCH64_INSN_IMM_12); 406257cb251SWill Deacon break; 407257cb251SWill Deacon case R_AARCH64_LDST32_ABS_LO12_NC: 408257cb251SWill Deacon overflow_check = false; 409257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 2, 10, 410c84fced8SJiang Liu AARCH64_INSN_IMM_12); 411257cb251SWill Deacon break; 412257cb251SWill Deacon case R_AARCH64_LDST64_ABS_LO12_NC: 413257cb251SWill Deacon overflow_check = false; 414257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 3, 9, 415c84fced8SJiang Liu AARCH64_INSN_IMM_12); 416257cb251SWill Deacon break; 417257cb251SWill Deacon case R_AARCH64_LDST128_ABS_LO12_NC: 418257cb251SWill Deacon overflow_check = false; 419257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 4, 8, 420c84fced8SJiang Liu AARCH64_INSN_IMM_12); 421257cb251SWill Deacon break; 422257cb251SWill Deacon case R_AARCH64_TSTBR14: 423257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 14, 424c84fced8SJiang Liu AARCH64_INSN_IMM_14); 425257cb251SWill Deacon break; 426257cb251SWill Deacon case R_AARCH64_CONDBR19: 427257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 19, 428c84fced8SJiang Liu AARCH64_INSN_IMM_19); 429257cb251SWill Deacon break; 430257cb251SWill Deacon case R_AARCH64_JUMP26: 431257cb251SWill Deacon case R_AARCH64_CALL26: 432257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 26, 433c84fced8SJiang Liu AARCH64_INSN_IMM_26); 434fd045f6cSArd Biesheuvel 435fd045f6cSArd Biesheuvel if (IS_ENABLED(CONFIG_ARM64_MODULE_PLTS) && 436fd045f6cSArd Biesheuvel ovf == -ERANGE) { 437c8ebf64eSJessica Yu val = module_emit_plt_entry(me, sechdrs, loc, &rel[i], sym); 4385e8307b9SArd Biesheuvel if (!val) 4395e8307b9SArd Biesheuvel return -ENOEXEC; 440fd045f6cSArd Biesheuvel ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 441fd045f6cSArd Biesheuvel 26, AARCH64_INSN_IMM_26); 442fd045f6cSArd Biesheuvel } 443257cb251SWill Deacon break; 444257cb251SWill Deacon 445257cb251SWill Deacon default: 446257cb251SWill Deacon pr_err("module %s: unsupported RELA relocation: %llu\n", 447257cb251SWill Deacon me->name, ELF64_R_TYPE(rel[i].r_info)); 448257cb251SWill Deacon return -ENOEXEC; 449257cb251SWill Deacon } 450257cb251SWill Deacon 451257cb251SWill Deacon if (overflow_check && ovf == -ERANGE) 452257cb251SWill Deacon goto overflow; 453257cb251SWill Deacon 454257cb251SWill Deacon } 455257cb251SWill Deacon 456257cb251SWill Deacon return 0; 457257cb251SWill Deacon 458257cb251SWill Deacon overflow: 459257cb251SWill Deacon pr_err("module %s: overflow in relocation type %d val %Lx\n", 460257cb251SWill Deacon me->name, (int)ELF64_R_TYPE(rel[i].r_info), val); 461257cb251SWill Deacon return -ENOEXEC; 462257cb251SWill Deacon } 463932ded4bSAndre Przywara 4643b23e499STorsten Duwe static inline void __init_plt(struct plt_entry *plt, unsigned long addr) 4653b23e499STorsten Duwe { 4663b23e499STorsten Duwe *plt = get_plt_entry(addr, plt); 4673b23e499STorsten Duwe } 4683b23e499STorsten Duwe 469f1a54ae9SMark Rutland static int module_init_ftrace_plt(const Elf_Ehdr *hdr, 470f1a54ae9SMark Rutland const Elf_Shdr *sechdrs, 471f1a54ae9SMark Rutland struct module *mod) 472f1a54ae9SMark Rutland { 473f1a54ae9SMark Rutland #if defined(CONFIG_ARM64_MODULE_PLTS) && defined(CONFIG_DYNAMIC_FTRACE) 474f1a54ae9SMark Rutland const Elf_Shdr *s; 4753b23e499STorsten Duwe struct plt_entry *plts; 476f1a54ae9SMark Rutland 477f1a54ae9SMark Rutland s = find_section(hdr, sechdrs, ".text.ftrace_trampoline"); 478f1a54ae9SMark Rutland if (!s) 479f1a54ae9SMark Rutland return -ENOEXEC; 480f1a54ae9SMark Rutland 4813b23e499STorsten Duwe plts = (void *)s->sh_addr; 4823b23e499STorsten Duwe 4833b23e499STorsten Duwe __init_plt(&plts[FTRACE_PLT_IDX], FTRACE_ADDR); 4843b23e499STorsten Duwe 4853b23e499STorsten Duwe mod->arch.ftrace_trampolines = plts; 486f1a54ae9SMark Rutland #endif 487f1a54ae9SMark Rutland return 0; 488f1a54ae9SMark Rutland } 489f1a54ae9SMark Rutland 490bd8b21d3SMark Rutland int module_finalize(const Elf_Ehdr *hdr, 491bd8b21d3SMark Rutland const Elf_Shdr *sechdrs, 492bd8b21d3SMark Rutland struct module *me) 493bd8b21d3SMark Rutland { 494bd8b21d3SMark Rutland const Elf_Shdr *s; 495bd8b21d3SMark Rutland s = find_section(hdr, sechdrs, ".altinstructions"); 496bd8b21d3SMark Rutland if (s) 497bd8b21d3SMark Rutland apply_alternatives_module((void *)s->sh_addr, s->sh_size); 498bd8b21d3SMark Rutland 4993b619e22SArd Biesheuvel if (scs_is_dynamic()) { 5003b619e22SArd Biesheuvel s = find_section(hdr, sechdrs, ".init.eh_frame"); 5013b619e22SArd Biesheuvel if (s) 5023b619e22SArd Biesheuvel scs_patch((void *)s->sh_addr, s->sh_size); 5033b619e22SArd Biesheuvel } 5043b619e22SArd Biesheuvel 505f1a54ae9SMark Rutland return module_init_ftrace_plt(hdr, sechdrs, me); 506932ded4bSAndre Przywara } 507