1*caab277bSThomas 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> 12257cb251SWill Deacon #include <linux/gfp.h> 1339d114ddSAndrey Ryabinin #include <linux/kasan.h> 14257cb251SWill Deacon #include <linux/kernel.h> 15257cb251SWill Deacon #include <linux/mm.h> 16257cb251SWill Deacon #include <linux/moduleloader.h> 17257cb251SWill Deacon #include <linux/vmalloc.h> 182c2b282dSPaul Walmsley #include <asm/alternative.h> 19c84fced8SJiang Liu #include <asm/insn.h> 20932ded4bSAndre Przywara #include <asm/sections.h> 21c84fced8SJiang Liu 22257cb251SWill Deacon void *module_alloc(unsigned long size) 23257cb251SWill Deacon { 240c2cf6d9SFlorian Fainelli gfp_t gfp_mask = GFP_KERNEL; 2539d114ddSAndrey Ryabinin void *p; 2639d114ddSAndrey Ryabinin 270c2cf6d9SFlorian Fainelli /* Silence the initial allocation */ 280c2cf6d9SFlorian Fainelli if (IS_ENABLED(CONFIG_ARM64_MODULE_PLTS)) 290c2cf6d9SFlorian Fainelli gfp_mask |= __GFP_NOWARN; 300c2cf6d9SFlorian Fainelli 31f80fb3a3SArd Biesheuvel p = __vmalloc_node_range(size, MODULE_ALIGN, module_alloc_base, 32f80fb3a3SArd Biesheuvel module_alloc_base + MODULES_VSIZE, 330c2cf6d9SFlorian Fainelli gfp_mask, PAGE_KERNEL_EXEC, 0, 34cb9e3c29SAndrey Ryabinin NUMA_NO_NODE, __builtin_return_address(0)); 3539d114ddSAndrey Ryabinin 36fd045f6cSArd Biesheuvel if (!p && IS_ENABLED(CONFIG_ARM64_MODULE_PLTS) && 37fd045f6cSArd Biesheuvel !IS_ENABLED(CONFIG_KASAN)) 38fd045f6cSArd Biesheuvel /* 39fd045f6cSArd Biesheuvel * KASAN can only deal with module allocations being served 40fd045f6cSArd Biesheuvel * from the reserved module region, since the remainder of 41fd045f6cSArd Biesheuvel * the vmalloc region is already backed by zero shadow pages, 42fd045f6cSArd Biesheuvel * and punching holes into it is non-trivial. Since the module 43fd045f6cSArd Biesheuvel * region is not randomized when KASAN is enabled, it is even 44fd045f6cSArd Biesheuvel * less likely that the module region gets exhausted, so we 45fd045f6cSArd Biesheuvel * can simply omit this fallback in that case. 46fd045f6cSArd Biesheuvel */ 47f2b9ba87SArd Biesheuvel p = __vmalloc_node_range(size, MODULE_ALIGN, module_alloc_base, 48b2eed9b5SArd Biesheuvel module_alloc_base + SZ_2G, GFP_KERNEL, 49f2b9ba87SArd Biesheuvel PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE, 50f2b9ba87SArd Biesheuvel __builtin_return_address(0)); 51fd045f6cSArd Biesheuvel 5239d114ddSAndrey Ryabinin if (p && (kasan_module_alloc(p, size) < 0)) { 5339d114ddSAndrey Ryabinin vfree(p); 5439d114ddSAndrey Ryabinin return NULL; 5539d114ddSAndrey Ryabinin } 5639d114ddSAndrey Ryabinin 5739d114ddSAndrey Ryabinin return p; 58257cb251SWill Deacon } 59257cb251SWill Deacon 60257cb251SWill Deacon enum aarch64_reloc_op { 61257cb251SWill Deacon RELOC_OP_NONE, 62257cb251SWill Deacon RELOC_OP_ABS, 63257cb251SWill Deacon RELOC_OP_PREL, 64257cb251SWill Deacon RELOC_OP_PAGE, 65257cb251SWill Deacon }; 66257cb251SWill Deacon 6702129ae5SLuc Van Oostenryck static u64 do_reloc(enum aarch64_reloc_op reloc_op, __le32 *place, u64 val) 68257cb251SWill Deacon { 69257cb251SWill Deacon switch (reloc_op) { 70257cb251SWill Deacon case RELOC_OP_ABS: 71257cb251SWill Deacon return val; 72257cb251SWill Deacon case RELOC_OP_PREL: 73257cb251SWill Deacon return val - (u64)place; 74257cb251SWill Deacon case RELOC_OP_PAGE: 75257cb251SWill Deacon return (val & ~0xfff) - ((u64)place & ~0xfff); 76257cb251SWill Deacon case RELOC_OP_NONE: 77257cb251SWill Deacon return 0; 78257cb251SWill Deacon } 79257cb251SWill Deacon 80257cb251SWill Deacon pr_err("do_reloc: unknown relocation operation %d\n", reloc_op); 81257cb251SWill Deacon return 0; 82257cb251SWill Deacon } 83257cb251SWill Deacon 84257cb251SWill Deacon static int reloc_data(enum aarch64_reloc_op op, void *place, u64 val, int len) 85257cb251SWill Deacon { 86257cb251SWill Deacon s64 sval = do_reloc(op, place, val); 87257cb251SWill Deacon 881cf24a2cSArd Biesheuvel /* 891cf24a2cSArd Biesheuvel * The ELF psABI for AArch64 documents the 16-bit and 32-bit place 903fd00bebSArd Biesheuvel * relative and absolute relocations as having a range of [-2^15, 2^16) 913fd00bebSArd Biesheuvel * or [-2^31, 2^32), respectively. However, in order to be able to 923fd00bebSArd Biesheuvel * detect overflows reliably, we have to choose whether we interpret 933fd00bebSArd Biesheuvel * such quantities as signed or as unsigned, and stick with it. 941cf24a2cSArd Biesheuvel * The way we organize our address space requires a signed 951cf24a2cSArd Biesheuvel * interpretation of 32-bit relative references, so let's use that 961cf24a2cSArd Biesheuvel * for all R_AARCH64_PRELxx relocations. This means our upper 971cf24a2cSArd Biesheuvel * bound for overflow detection should be Sxx_MAX rather than Uxx_MAX. 981cf24a2cSArd Biesheuvel */ 991cf24a2cSArd Biesheuvel 100257cb251SWill Deacon switch (len) { 101257cb251SWill Deacon case 16: 102257cb251SWill Deacon *(s16 *)place = sval; 1033fd00bebSArd Biesheuvel switch (op) { 1043fd00bebSArd Biesheuvel case RELOC_OP_ABS: 1053fd00bebSArd Biesheuvel if (sval < 0 || sval > U16_MAX) 1063fd00bebSArd Biesheuvel return -ERANGE; 1073fd00bebSArd Biesheuvel break; 1083fd00bebSArd Biesheuvel case RELOC_OP_PREL: 1091cf24a2cSArd Biesheuvel if (sval < S16_MIN || sval > S16_MAX) 110f9308969SArd Biesheuvel return -ERANGE; 111257cb251SWill Deacon break; 1123fd00bebSArd Biesheuvel default: 1133fd00bebSArd Biesheuvel pr_err("Invalid 16-bit data relocation (%d)\n", op); 1143fd00bebSArd Biesheuvel return 0; 1153fd00bebSArd Biesheuvel } 1163fd00bebSArd Biesheuvel break; 117257cb251SWill Deacon case 32: 118257cb251SWill Deacon *(s32 *)place = sval; 1193fd00bebSArd Biesheuvel switch (op) { 1203fd00bebSArd Biesheuvel case RELOC_OP_ABS: 1213fd00bebSArd Biesheuvel if (sval < 0 || sval > U32_MAX) 1223fd00bebSArd Biesheuvel return -ERANGE; 1233fd00bebSArd Biesheuvel break; 1243fd00bebSArd Biesheuvel case RELOC_OP_PREL: 1251cf24a2cSArd Biesheuvel if (sval < S32_MIN || sval > S32_MAX) 126f9308969SArd Biesheuvel return -ERANGE; 127257cb251SWill Deacon break; 1283fd00bebSArd Biesheuvel default: 1293fd00bebSArd Biesheuvel pr_err("Invalid 32-bit data relocation (%d)\n", op); 1303fd00bebSArd Biesheuvel return 0; 1313fd00bebSArd Biesheuvel } 1323fd00bebSArd Biesheuvel break; 133257cb251SWill Deacon case 64: 134257cb251SWill Deacon *(s64 *)place = sval; 135257cb251SWill Deacon break; 136257cb251SWill Deacon default: 137257cb251SWill Deacon pr_err("Invalid length (%d) for data relocation\n", len); 138257cb251SWill Deacon return 0; 139257cb251SWill Deacon } 140257cb251SWill Deacon return 0; 141257cb251SWill Deacon } 142257cb251SWill Deacon 143b24a5575SArd Biesheuvel enum aarch64_insn_movw_imm_type { 144b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVNZ, 145b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ, 146b24a5575SArd Biesheuvel }; 147b24a5575SArd Biesheuvel 14802129ae5SLuc Van Oostenryck static int reloc_insn_movw(enum aarch64_reloc_op op, __le32 *place, u64 val, 149b24a5575SArd Biesheuvel int lsb, enum aarch64_insn_movw_imm_type imm_type) 150257cb251SWill Deacon { 151b24a5575SArd Biesheuvel u64 imm; 152c84fced8SJiang Liu s64 sval; 15302129ae5SLuc Van Oostenryck u32 insn = le32_to_cpu(*place); 154257cb251SWill Deacon 155c84fced8SJiang Liu sval = do_reloc(op, place, val); 156b24a5575SArd Biesheuvel imm = sval >> lsb; 157122e2fa0SWill Deacon 158c84fced8SJiang Liu if (imm_type == AARCH64_INSN_IMM_MOVNZ) { 159257cb251SWill Deacon /* 160257cb251SWill Deacon * For signed MOVW relocations, we have to manipulate the 161257cb251SWill Deacon * instruction encoding depending on whether or not the 162257cb251SWill Deacon * immediate is less than zero. 163257cb251SWill Deacon */ 164257cb251SWill Deacon insn &= ~(3 << 29); 165b24a5575SArd Biesheuvel if (sval >= 0) { 166257cb251SWill Deacon /* >=0: Set the instruction to MOVZ (opcode 10b). */ 167257cb251SWill Deacon insn |= 2 << 29; 168257cb251SWill Deacon } else { 169257cb251SWill Deacon /* 170257cb251SWill Deacon * <0: Set the instruction to MOVN (opcode 00b). 171257cb251SWill Deacon * Since we've masked the opcode already, we 172257cb251SWill Deacon * don't need to do anything other than 173257cb251SWill Deacon * inverting the new immediate field. 174257cb251SWill Deacon */ 175257cb251SWill Deacon imm = ~imm; 176257cb251SWill Deacon } 177257cb251SWill Deacon } 178257cb251SWill Deacon 179257cb251SWill Deacon /* Update the instruction with the new encoding. */ 180b24a5575SArd Biesheuvel insn = aarch64_insn_encode_immediate(AARCH64_INSN_IMM_16, insn, imm); 18102129ae5SLuc Van Oostenryck *place = cpu_to_le32(insn); 182257cb251SWill Deacon 183b24a5575SArd Biesheuvel if (imm > U16_MAX) 184257cb251SWill Deacon return -ERANGE; 185257cb251SWill Deacon 186257cb251SWill Deacon return 0; 187257cb251SWill Deacon } 188257cb251SWill Deacon 18902129ae5SLuc Van Oostenryck static int reloc_insn_imm(enum aarch64_reloc_op op, __le32 *place, u64 val, 190c84fced8SJiang Liu int lsb, int len, enum aarch64_insn_imm_type imm_type) 191257cb251SWill Deacon { 192257cb251SWill Deacon u64 imm, imm_mask; 193257cb251SWill Deacon s64 sval; 19402129ae5SLuc Van Oostenryck u32 insn = le32_to_cpu(*place); 195257cb251SWill Deacon 196257cb251SWill Deacon /* Calculate the relocation value. */ 197257cb251SWill Deacon sval = do_reloc(op, place, val); 198257cb251SWill Deacon sval >>= lsb; 199257cb251SWill Deacon 200257cb251SWill Deacon /* Extract the value bits and shift them to bit 0. */ 201257cb251SWill Deacon imm_mask = (BIT(lsb + len) - 1) >> lsb; 202257cb251SWill Deacon imm = sval & imm_mask; 203257cb251SWill Deacon 204257cb251SWill Deacon /* Update the instruction's immediate field. */ 205c84fced8SJiang Liu insn = aarch64_insn_encode_immediate(imm_type, insn, imm); 20602129ae5SLuc Van Oostenryck *place = cpu_to_le32(insn); 207257cb251SWill Deacon 208257cb251SWill Deacon /* 209257cb251SWill Deacon * Extract the upper value bits (including the sign bit) and 210257cb251SWill Deacon * shift them to bit 0. 211257cb251SWill Deacon */ 212257cb251SWill Deacon sval = (s64)(sval & ~(imm_mask >> 1)) >> (len - 1); 213257cb251SWill Deacon 214257cb251SWill Deacon /* 215257cb251SWill Deacon * Overflow has occurred if the upper bits are not all equal to 216257cb251SWill Deacon * the sign bit of the value. 217257cb251SWill Deacon */ 218257cb251SWill Deacon if ((u64)(sval + 1) >= 2) 219257cb251SWill Deacon return -ERANGE; 220257cb251SWill Deacon 221257cb251SWill Deacon return 0; 222257cb251SWill Deacon } 223257cb251SWill Deacon 224c8ebf64eSJessica Yu static int reloc_insn_adrp(struct module *mod, Elf64_Shdr *sechdrs, 225c8ebf64eSJessica Yu __le32 *place, u64 val) 226a257e025SArd Biesheuvel { 227a257e025SArd Biesheuvel u32 insn; 228a257e025SArd Biesheuvel 229bdb85cd1SArd Biesheuvel if (!is_forbidden_offset_for_adrp(place)) 230a257e025SArd Biesheuvel return reloc_insn_imm(RELOC_OP_PAGE, place, val, 12, 21, 231a257e025SArd Biesheuvel AARCH64_INSN_IMM_ADR); 232a257e025SArd Biesheuvel 233a257e025SArd Biesheuvel /* patch ADRP to ADR if it is in range */ 234a257e025SArd Biesheuvel if (!reloc_insn_imm(RELOC_OP_PREL, place, val & ~0xfff, 0, 21, 235a257e025SArd Biesheuvel AARCH64_INSN_IMM_ADR)) { 236a257e025SArd Biesheuvel insn = le32_to_cpu(*place); 237a257e025SArd Biesheuvel insn &= ~BIT(31); 238a257e025SArd Biesheuvel } else { 239a257e025SArd Biesheuvel /* out of range for ADR -> emit a veneer */ 240c8ebf64eSJessica Yu val = module_emit_veneer_for_adrp(mod, sechdrs, place, val & ~0xfff); 241a257e025SArd Biesheuvel if (!val) 242a257e025SArd Biesheuvel return -ENOEXEC; 243a257e025SArd Biesheuvel insn = aarch64_insn_gen_branch_imm((u64)place, val, 244a257e025SArd Biesheuvel AARCH64_INSN_BRANCH_NOLINK); 245a257e025SArd Biesheuvel } 246a257e025SArd Biesheuvel 247a257e025SArd Biesheuvel *place = cpu_to_le32(insn); 248a257e025SArd Biesheuvel return 0; 249a257e025SArd Biesheuvel } 250a257e025SArd Biesheuvel 251257cb251SWill Deacon int apply_relocate_add(Elf64_Shdr *sechdrs, 252257cb251SWill Deacon const char *strtab, 253257cb251SWill Deacon unsigned int symindex, 254257cb251SWill Deacon unsigned int relsec, 255257cb251SWill Deacon struct module *me) 256257cb251SWill Deacon { 257257cb251SWill Deacon unsigned int i; 258257cb251SWill Deacon int ovf; 259257cb251SWill Deacon bool overflow_check; 260257cb251SWill Deacon Elf64_Sym *sym; 261257cb251SWill Deacon void *loc; 262257cb251SWill Deacon u64 val; 263257cb251SWill Deacon Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr; 264257cb251SWill Deacon 265257cb251SWill Deacon for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { 266257cb251SWill Deacon /* loc corresponds to P in the AArch64 ELF document. */ 267257cb251SWill Deacon loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr 268257cb251SWill Deacon + rel[i].r_offset; 269257cb251SWill Deacon 270257cb251SWill Deacon /* sym is the ELF symbol we're referring to. */ 271257cb251SWill Deacon sym = (Elf64_Sym *)sechdrs[symindex].sh_addr 272257cb251SWill Deacon + ELF64_R_SYM(rel[i].r_info); 273257cb251SWill Deacon 274257cb251SWill Deacon /* val corresponds to (S + A) in the AArch64 ELF document. */ 275257cb251SWill Deacon val = sym->st_value + rel[i].r_addend; 276257cb251SWill Deacon 277257cb251SWill Deacon /* Check for overflow by default. */ 278257cb251SWill Deacon overflow_check = true; 279257cb251SWill Deacon 280257cb251SWill Deacon /* Perform the static relocation. */ 281257cb251SWill Deacon switch (ELF64_R_TYPE(rel[i].r_info)) { 282257cb251SWill Deacon /* Null relocations. */ 283257cb251SWill Deacon case R_ARM_NONE: 284257cb251SWill Deacon case R_AARCH64_NONE: 285257cb251SWill Deacon ovf = 0; 286257cb251SWill Deacon break; 287257cb251SWill Deacon 288257cb251SWill Deacon /* Data relocations. */ 289257cb251SWill Deacon case R_AARCH64_ABS64: 290257cb251SWill Deacon overflow_check = false; 291257cb251SWill Deacon ovf = reloc_data(RELOC_OP_ABS, loc, val, 64); 292257cb251SWill Deacon break; 293257cb251SWill Deacon case R_AARCH64_ABS32: 294257cb251SWill Deacon ovf = reloc_data(RELOC_OP_ABS, loc, val, 32); 295257cb251SWill Deacon break; 296257cb251SWill Deacon case R_AARCH64_ABS16: 297257cb251SWill Deacon ovf = reloc_data(RELOC_OP_ABS, loc, val, 16); 298257cb251SWill Deacon break; 299257cb251SWill Deacon case R_AARCH64_PREL64: 300257cb251SWill Deacon overflow_check = false; 301257cb251SWill Deacon ovf = reloc_data(RELOC_OP_PREL, loc, val, 64); 302257cb251SWill Deacon break; 303257cb251SWill Deacon case R_AARCH64_PREL32: 304257cb251SWill Deacon ovf = reloc_data(RELOC_OP_PREL, loc, val, 32); 305257cb251SWill Deacon break; 306257cb251SWill Deacon case R_AARCH64_PREL16: 307257cb251SWill Deacon ovf = reloc_data(RELOC_OP_PREL, loc, val, 16); 308257cb251SWill Deacon break; 309257cb251SWill Deacon 310257cb251SWill Deacon /* MOVW instruction relocations. */ 311257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G0_NC: 312257cb251SWill Deacon overflow_check = false; 313257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G0: 314257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0, 315b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 316257cb251SWill Deacon break; 317257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G1_NC: 318257cb251SWill Deacon overflow_check = false; 319257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G1: 320257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16, 321b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 322257cb251SWill Deacon break; 323257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G2_NC: 324257cb251SWill Deacon overflow_check = false; 325257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G2: 326257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32, 327b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 328257cb251SWill Deacon break; 329257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G3: 330257cb251SWill Deacon /* We're using the top bits so we can't overflow. */ 331257cb251SWill Deacon overflow_check = false; 332257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 48, 333b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 334257cb251SWill Deacon break; 335257cb251SWill Deacon case R_AARCH64_MOVW_SABS_G0: 336257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0, 337c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 338257cb251SWill Deacon break; 339257cb251SWill Deacon case R_AARCH64_MOVW_SABS_G1: 340257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16, 341c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 342257cb251SWill Deacon break; 343257cb251SWill Deacon case R_AARCH64_MOVW_SABS_G2: 344257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32, 345c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 346257cb251SWill Deacon break; 347257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G0_NC: 348257cb251SWill Deacon overflow_check = false; 349257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0, 350b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 351257cb251SWill Deacon break; 352257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G0: 353257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0, 354c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 355257cb251SWill Deacon break; 356257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G1_NC: 357257cb251SWill Deacon overflow_check = false; 358257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16, 359b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 360257cb251SWill Deacon break; 361257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G1: 362257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16, 363c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 364257cb251SWill Deacon break; 365257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G2_NC: 366257cb251SWill Deacon overflow_check = false; 367257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32, 368b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 369257cb251SWill Deacon break; 370257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G2: 371257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32, 372c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 373257cb251SWill Deacon break; 374257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G3: 375257cb251SWill Deacon /* We're using the top bits so we can't overflow. */ 376257cb251SWill Deacon overflow_check = false; 377257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 48, 378c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 379257cb251SWill Deacon break; 380257cb251SWill Deacon 381257cb251SWill Deacon /* Immediate instruction relocations. */ 382257cb251SWill Deacon case R_AARCH64_LD_PREL_LO19: 383257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 19, 384c84fced8SJiang Liu AARCH64_INSN_IMM_19); 385257cb251SWill Deacon break; 386257cb251SWill Deacon case R_AARCH64_ADR_PREL_LO21: 387257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 0, 21, 388c84fced8SJiang Liu AARCH64_INSN_IMM_ADR); 389257cb251SWill Deacon break; 390257cb251SWill Deacon case R_AARCH64_ADR_PREL_PG_HI21_NC: 391257cb251SWill Deacon overflow_check = false; 392257cb251SWill Deacon case R_AARCH64_ADR_PREL_PG_HI21: 393c8ebf64eSJessica Yu ovf = reloc_insn_adrp(me, sechdrs, loc, val); 394a257e025SArd Biesheuvel if (ovf && ovf != -ERANGE) 395a257e025SArd Biesheuvel return ovf; 396257cb251SWill Deacon break; 397257cb251SWill Deacon case R_AARCH64_ADD_ABS_LO12_NC: 398257cb251SWill Deacon case R_AARCH64_LDST8_ABS_LO12_NC: 399257cb251SWill Deacon overflow_check = false; 400257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 0, 12, 401c84fced8SJiang Liu AARCH64_INSN_IMM_12); 402257cb251SWill Deacon break; 403257cb251SWill Deacon case R_AARCH64_LDST16_ABS_LO12_NC: 404257cb251SWill Deacon overflow_check = false; 405257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 1, 11, 406c84fced8SJiang Liu AARCH64_INSN_IMM_12); 407257cb251SWill Deacon break; 408257cb251SWill Deacon case R_AARCH64_LDST32_ABS_LO12_NC: 409257cb251SWill Deacon overflow_check = false; 410257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 2, 10, 411c84fced8SJiang Liu AARCH64_INSN_IMM_12); 412257cb251SWill Deacon break; 413257cb251SWill Deacon case R_AARCH64_LDST64_ABS_LO12_NC: 414257cb251SWill Deacon overflow_check = false; 415257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 3, 9, 416c84fced8SJiang Liu AARCH64_INSN_IMM_12); 417257cb251SWill Deacon break; 418257cb251SWill Deacon case R_AARCH64_LDST128_ABS_LO12_NC: 419257cb251SWill Deacon overflow_check = false; 420257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 4, 8, 421c84fced8SJiang Liu AARCH64_INSN_IMM_12); 422257cb251SWill Deacon break; 423257cb251SWill Deacon case R_AARCH64_TSTBR14: 424257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 14, 425c84fced8SJiang Liu AARCH64_INSN_IMM_14); 426257cb251SWill Deacon break; 427257cb251SWill Deacon case R_AARCH64_CONDBR19: 428257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 19, 429c84fced8SJiang Liu AARCH64_INSN_IMM_19); 430257cb251SWill Deacon break; 431257cb251SWill Deacon case R_AARCH64_JUMP26: 432257cb251SWill Deacon case R_AARCH64_CALL26: 433257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 26, 434c84fced8SJiang Liu AARCH64_INSN_IMM_26); 435fd045f6cSArd Biesheuvel 436fd045f6cSArd Biesheuvel if (IS_ENABLED(CONFIG_ARM64_MODULE_PLTS) && 437fd045f6cSArd Biesheuvel ovf == -ERANGE) { 438c8ebf64eSJessica Yu val = module_emit_plt_entry(me, sechdrs, loc, &rel[i], sym); 4395e8307b9SArd Biesheuvel if (!val) 4405e8307b9SArd Biesheuvel return -ENOEXEC; 441fd045f6cSArd Biesheuvel ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 442fd045f6cSArd Biesheuvel 26, AARCH64_INSN_IMM_26); 443fd045f6cSArd Biesheuvel } 444257cb251SWill Deacon break; 445257cb251SWill Deacon 446257cb251SWill Deacon default: 447257cb251SWill Deacon pr_err("module %s: unsupported RELA relocation: %llu\n", 448257cb251SWill Deacon me->name, ELF64_R_TYPE(rel[i].r_info)); 449257cb251SWill Deacon return -ENOEXEC; 450257cb251SWill Deacon } 451257cb251SWill Deacon 452257cb251SWill Deacon if (overflow_check && ovf == -ERANGE) 453257cb251SWill Deacon goto overflow; 454257cb251SWill Deacon 455257cb251SWill Deacon } 456257cb251SWill Deacon 457257cb251SWill Deacon return 0; 458257cb251SWill Deacon 459257cb251SWill Deacon overflow: 460257cb251SWill Deacon pr_err("module %s: overflow in relocation type %d val %Lx\n", 461257cb251SWill Deacon me->name, (int)ELF64_R_TYPE(rel[i].r_info), val); 462257cb251SWill Deacon return -ENOEXEC; 463257cb251SWill Deacon } 464932ded4bSAndre Przywara 465932ded4bSAndre Przywara int module_finalize(const Elf_Ehdr *hdr, 466932ded4bSAndre Przywara const Elf_Shdr *sechdrs, 467932ded4bSAndre Przywara struct module *me) 468932ded4bSAndre Przywara { 469932ded4bSAndre Przywara const Elf_Shdr *s, *se; 470932ded4bSAndre Przywara const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; 471932ded4bSAndre Przywara 472932ded4bSAndre Przywara for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++) { 47342938868SWill Deacon if (strcmp(".altinstructions", secstrs + s->sh_name) == 0) 47442938868SWill Deacon apply_alternatives_module((void *)s->sh_addr, s->sh_size); 475e71a4e1bSArd Biesheuvel #ifdef CONFIG_ARM64_MODULE_PLTS 476e71a4e1bSArd Biesheuvel if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE) && 477e71a4e1bSArd Biesheuvel !strcmp(".text.ftrace_trampoline", secstrs + s->sh_name)) 478e71a4e1bSArd Biesheuvel me->arch.ftrace_trampoline = (void *)s->sh_addr; 479e71a4e1bSArd Biesheuvel #endif 480932ded4bSAndre Przywara } 481932ded4bSAndre Przywara 482932ded4bSAndre Przywara return 0; 483932ded4bSAndre Przywara } 484