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> 18*e46b7103SMark Rutland #include <linux/random.h> 193b619e22SArd Biesheuvel #include <linux/scs.h> 20257cb251SWill Deacon #include <linux/vmalloc.h> 21*e46b7103SMark Rutland 222c2b282dSPaul Walmsley #include <asm/alternative.h> 23c84fced8SJiang Liu #include <asm/insn.h> 243b619e22SArd Biesheuvel #include <asm/scs.h> 25932ded4bSAndre Przywara #include <asm/sections.h> 26c84fced8SJiang Liu 27*e46b7103SMark Rutland static u64 __ro_after_init module_alloc_base = (u64)_etext - MODULES_VSIZE; 28*e46b7103SMark Rutland 29*e46b7103SMark Rutland #ifdef CONFIG_RANDOMIZE_BASE 30*e46b7103SMark Rutland static int __init kaslr_module_init(void) 31*e46b7103SMark Rutland { 32*e46b7103SMark Rutland u64 module_range; 33*e46b7103SMark Rutland u32 seed; 34*e46b7103SMark Rutland 35*e46b7103SMark Rutland if (!kaslr_enabled()) 36*e46b7103SMark Rutland return 0; 37*e46b7103SMark Rutland 38*e46b7103SMark Rutland seed = get_random_u32(); 39*e46b7103SMark Rutland 40*e46b7103SMark Rutland if (IS_ENABLED(CONFIG_RANDOMIZE_MODULE_REGION_FULL)) { 41*e46b7103SMark Rutland /* 42*e46b7103SMark Rutland * Randomize the module region over a 2 GB window covering the 43*e46b7103SMark Rutland * kernel. This reduces the risk of modules leaking information 44*e46b7103SMark Rutland * about the address of the kernel itself, but results in 45*e46b7103SMark Rutland * branches between modules and the core kernel that are 46*e46b7103SMark Rutland * resolved via PLTs. (Branches between modules will be 47*e46b7103SMark Rutland * resolved normally.) 48*e46b7103SMark Rutland */ 49*e46b7103SMark Rutland module_range = SZ_2G - (u64)(_end - _stext); 50*e46b7103SMark Rutland module_alloc_base = max((u64)_end - SZ_2G, (u64)MODULES_VADDR); 51*e46b7103SMark Rutland } else { 52*e46b7103SMark Rutland /* 53*e46b7103SMark Rutland * Randomize the module region by setting module_alloc_base to 54*e46b7103SMark Rutland * a PAGE_SIZE multiple in the range [_etext - MODULES_VSIZE, 55*e46b7103SMark Rutland * _stext) . This guarantees that the resulting region still 56*e46b7103SMark Rutland * covers [_stext, _etext], and that all relative branches can 57*e46b7103SMark Rutland * be resolved without veneers unless this region is exhausted 58*e46b7103SMark Rutland * and we fall back to a larger 2GB window in module_alloc() 59*e46b7103SMark Rutland * when ARM64_MODULE_PLTS is enabled. 60*e46b7103SMark Rutland */ 61*e46b7103SMark Rutland module_range = MODULES_VSIZE - (u64)(_etext - _stext); 62*e46b7103SMark Rutland } 63*e46b7103SMark Rutland 64*e46b7103SMark Rutland /* use the lower 21 bits to randomize the base of the module region */ 65*e46b7103SMark Rutland module_alloc_base += (module_range * (seed & ((1 << 21) - 1))) >> 21; 66*e46b7103SMark Rutland module_alloc_base &= PAGE_MASK; 67*e46b7103SMark Rutland 68*e46b7103SMark Rutland return 0; 69*e46b7103SMark Rutland } 70*e46b7103SMark Rutland subsys_initcall(kaslr_module_init) 71*e46b7103SMark Rutland #endif 72*e46b7103SMark Rutland 73257cb251SWill Deacon void *module_alloc(unsigned long size) 74257cb251SWill Deacon { 756f496a55SArd Biesheuvel u64 module_alloc_end = module_alloc_base + MODULES_VSIZE; 760c2cf6d9SFlorian Fainelli gfp_t gfp_mask = GFP_KERNEL; 7739d114ddSAndrey Ryabinin void *p; 7839d114ddSAndrey Ryabinin 790c2cf6d9SFlorian Fainelli /* Silence the initial allocation */ 800c2cf6d9SFlorian Fainelli if (IS_ENABLED(CONFIG_ARM64_MODULE_PLTS)) 810c2cf6d9SFlorian Fainelli gfp_mask |= __GFP_NOWARN; 820c2cf6d9SFlorian Fainelli 83f80fb3a3SArd Biesheuvel p = __vmalloc_node_range(size, MODULE_ALIGN, module_alloc_base, 848339f7d8SMark Rutland module_alloc_end, gfp_mask, PAGE_KERNEL, 0, 85cb9e3c29SAndrey Ryabinin NUMA_NO_NODE, __builtin_return_address(0)); 8639d114ddSAndrey Ryabinin 878339f7d8SMark Rutland if (!p && IS_ENABLED(CONFIG_ARM64_MODULE_PLTS)) { 88f2b9ba87SArd Biesheuvel p = __vmalloc_node_range(size, MODULE_ALIGN, module_alloc_base, 89b2eed9b5SArd Biesheuvel module_alloc_base + SZ_2G, GFP_KERNEL, 907dfac3c5SArd Biesheuvel PAGE_KERNEL, 0, NUMA_NO_NODE, 91f2b9ba87SArd Biesheuvel __builtin_return_address(0)); 928339f7d8SMark Rutland } 93fd045f6cSArd Biesheuvel 9463840de2SAndrey Konovalov if (p && (kasan_alloc_module_shadow(p, size, gfp_mask) < 0)) { 9539d114ddSAndrey Ryabinin vfree(p); 9639d114ddSAndrey Ryabinin return NULL; 9739d114ddSAndrey Ryabinin } 9839d114ddSAndrey Ryabinin 9936c4a73bSAndrey Konovalov /* Memory is intended to be executable, reset the pointer tag. */ 10036c4a73bSAndrey Konovalov return kasan_reset_tag(p); 101257cb251SWill Deacon } 102257cb251SWill Deacon 103257cb251SWill Deacon enum aarch64_reloc_op { 104257cb251SWill Deacon RELOC_OP_NONE, 105257cb251SWill Deacon RELOC_OP_ABS, 106257cb251SWill Deacon RELOC_OP_PREL, 107257cb251SWill Deacon RELOC_OP_PAGE, 108257cb251SWill Deacon }; 109257cb251SWill Deacon 11002129ae5SLuc Van Oostenryck static u64 do_reloc(enum aarch64_reloc_op reloc_op, __le32 *place, u64 val) 111257cb251SWill Deacon { 112257cb251SWill Deacon switch (reloc_op) { 113257cb251SWill Deacon case RELOC_OP_ABS: 114257cb251SWill Deacon return val; 115257cb251SWill Deacon case RELOC_OP_PREL: 116257cb251SWill Deacon return val - (u64)place; 117257cb251SWill Deacon case RELOC_OP_PAGE: 118257cb251SWill Deacon return (val & ~0xfff) - ((u64)place & ~0xfff); 119257cb251SWill Deacon case RELOC_OP_NONE: 120257cb251SWill Deacon return 0; 121257cb251SWill Deacon } 122257cb251SWill Deacon 123257cb251SWill Deacon pr_err("do_reloc: unknown relocation operation %d\n", reloc_op); 124257cb251SWill Deacon return 0; 125257cb251SWill Deacon } 126257cb251SWill Deacon 127257cb251SWill Deacon static int reloc_data(enum aarch64_reloc_op op, void *place, u64 val, int len) 128257cb251SWill Deacon { 129257cb251SWill Deacon s64 sval = do_reloc(op, place, val); 130257cb251SWill Deacon 1311cf24a2cSArd Biesheuvel /* 1321cf24a2cSArd Biesheuvel * The ELF psABI for AArch64 documents the 16-bit and 32-bit place 1333fd00bebSArd Biesheuvel * relative and absolute relocations as having a range of [-2^15, 2^16) 1343fd00bebSArd Biesheuvel * or [-2^31, 2^32), respectively. However, in order to be able to 1353fd00bebSArd Biesheuvel * detect overflows reliably, we have to choose whether we interpret 1363fd00bebSArd Biesheuvel * such quantities as signed or as unsigned, and stick with it. 1371cf24a2cSArd Biesheuvel * The way we organize our address space requires a signed 1381cf24a2cSArd Biesheuvel * interpretation of 32-bit relative references, so let's use that 1391cf24a2cSArd Biesheuvel * for all R_AARCH64_PRELxx relocations. This means our upper 1401cf24a2cSArd Biesheuvel * bound for overflow detection should be Sxx_MAX rather than Uxx_MAX. 1411cf24a2cSArd Biesheuvel */ 1421cf24a2cSArd Biesheuvel 143257cb251SWill Deacon switch (len) { 144257cb251SWill Deacon case 16: 145257cb251SWill Deacon *(s16 *)place = sval; 1463fd00bebSArd Biesheuvel switch (op) { 1473fd00bebSArd Biesheuvel case RELOC_OP_ABS: 1483fd00bebSArd Biesheuvel if (sval < 0 || sval > U16_MAX) 1493fd00bebSArd Biesheuvel return -ERANGE; 1503fd00bebSArd Biesheuvel break; 1513fd00bebSArd Biesheuvel case RELOC_OP_PREL: 1521cf24a2cSArd Biesheuvel if (sval < S16_MIN || sval > S16_MAX) 153f9308969SArd Biesheuvel return -ERANGE; 154257cb251SWill Deacon break; 1553fd00bebSArd Biesheuvel default: 1563fd00bebSArd Biesheuvel pr_err("Invalid 16-bit data relocation (%d)\n", op); 1573fd00bebSArd Biesheuvel return 0; 1583fd00bebSArd Biesheuvel } 1593fd00bebSArd Biesheuvel break; 160257cb251SWill Deacon case 32: 161257cb251SWill Deacon *(s32 *)place = sval; 1623fd00bebSArd Biesheuvel switch (op) { 1633fd00bebSArd Biesheuvel case RELOC_OP_ABS: 1643fd00bebSArd Biesheuvel if (sval < 0 || sval > U32_MAX) 1653fd00bebSArd Biesheuvel return -ERANGE; 1663fd00bebSArd Biesheuvel break; 1673fd00bebSArd Biesheuvel case RELOC_OP_PREL: 1681cf24a2cSArd Biesheuvel if (sval < S32_MIN || sval > S32_MAX) 169f9308969SArd Biesheuvel return -ERANGE; 170257cb251SWill Deacon break; 1713fd00bebSArd Biesheuvel default: 1723fd00bebSArd Biesheuvel pr_err("Invalid 32-bit data relocation (%d)\n", op); 1733fd00bebSArd Biesheuvel return 0; 1743fd00bebSArd Biesheuvel } 1753fd00bebSArd Biesheuvel break; 176257cb251SWill Deacon case 64: 177257cb251SWill Deacon *(s64 *)place = sval; 178257cb251SWill Deacon break; 179257cb251SWill Deacon default: 180257cb251SWill Deacon pr_err("Invalid length (%d) for data relocation\n", len); 181257cb251SWill Deacon return 0; 182257cb251SWill Deacon } 183257cb251SWill Deacon return 0; 184257cb251SWill Deacon } 185257cb251SWill Deacon 186b24a5575SArd Biesheuvel enum aarch64_insn_movw_imm_type { 187b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVNZ, 188b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ, 189b24a5575SArd Biesheuvel }; 190b24a5575SArd Biesheuvel 19102129ae5SLuc Van Oostenryck static int reloc_insn_movw(enum aarch64_reloc_op op, __le32 *place, u64 val, 192b24a5575SArd Biesheuvel int lsb, enum aarch64_insn_movw_imm_type imm_type) 193257cb251SWill Deacon { 194b24a5575SArd Biesheuvel u64 imm; 195c84fced8SJiang Liu s64 sval; 19602129ae5SLuc Van Oostenryck u32 insn = le32_to_cpu(*place); 197257cb251SWill Deacon 198c84fced8SJiang Liu sval = do_reloc(op, place, val); 199b24a5575SArd Biesheuvel imm = sval >> lsb; 200122e2fa0SWill Deacon 201c84fced8SJiang Liu if (imm_type == AARCH64_INSN_IMM_MOVNZ) { 202257cb251SWill Deacon /* 203257cb251SWill Deacon * For signed MOVW relocations, we have to manipulate the 204257cb251SWill Deacon * instruction encoding depending on whether or not the 205257cb251SWill Deacon * immediate is less than zero. 206257cb251SWill Deacon */ 207257cb251SWill Deacon insn &= ~(3 << 29); 208b24a5575SArd Biesheuvel if (sval >= 0) { 209257cb251SWill Deacon /* >=0: Set the instruction to MOVZ (opcode 10b). */ 210257cb251SWill Deacon insn |= 2 << 29; 211257cb251SWill Deacon } else { 212257cb251SWill Deacon /* 213257cb251SWill Deacon * <0: Set the instruction to MOVN (opcode 00b). 214257cb251SWill Deacon * Since we've masked the opcode already, we 215257cb251SWill Deacon * don't need to do anything other than 216257cb251SWill Deacon * inverting the new immediate field. 217257cb251SWill Deacon */ 218257cb251SWill Deacon imm = ~imm; 219257cb251SWill Deacon } 220257cb251SWill Deacon } 221257cb251SWill Deacon 222257cb251SWill Deacon /* Update the instruction with the new encoding. */ 223b24a5575SArd Biesheuvel insn = aarch64_insn_encode_immediate(AARCH64_INSN_IMM_16, insn, imm); 22402129ae5SLuc Van Oostenryck *place = cpu_to_le32(insn); 225257cb251SWill Deacon 226b24a5575SArd Biesheuvel if (imm > U16_MAX) 227257cb251SWill Deacon return -ERANGE; 228257cb251SWill Deacon 229257cb251SWill Deacon return 0; 230257cb251SWill Deacon } 231257cb251SWill Deacon 23202129ae5SLuc Van Oostenryck static int reloc_insn_imm(enum aarch64_reloc_op op, __le32 *place, u64 val, 233c84fced8SJiang Liu int lsb, int len, enum aarch64_insn_imm_type imm_type) 234257cb251SWill Deacon { 235257cb251SWill Deacon u64 imm, imm_mask; 236257cb251SWill Deacon s64 sval; 23702129ae5SLuc Van Oostenryck u32 insn = le32_to_cpu(*place); 238257cb251SWill Deacon 239257cb251SWill Deacon /* Calculate the relocation value. */ 240257cb251SWill Deacon sval = do_reloc(op, place, val); 241257cb251SWill Deacon sval >>= lsb; 242257cb251SWill Deacon 243257cb251SWill Deacon /* Extract the value bits and shift them to bit 0. */ 244257cb251SWill Deacon imm_mask = (BIT(lsb + len) - 1) >> lsb; 245257cb251SWill Deacon imm = sval & imm_mask; 246257cb251SWill Deacon 247257cb251SWill Deacon /* Update the instruction's immediate field. */ 248c84fced8SJiang Liu insn = aarch64_insn_encode_immediate(imm_type, insn, imm); 24902129ae5SLuc Van Oostenryck *place = cpu_to_le32(insn); 250257cb251SWill Deacon 251257cb251SWill Deacon /* 252257cb251SWill Deacon * Extract the upper value bits (including the sign bit) and 253257cb251SWill Deacon * shift them to bit 0. 254257cb251SWill Deacon */ 255257cb251SWill Deacon sval = (s64)(sval & ~(imm_mask >> 1)) >> (len - 1); 256257cb251SWill Deacon 257257cb251SWill Deacon /* 258257cb251SWill Deacon * Overflow has occurred if the upper bits are not all equal to 259257cb251SWill Deacon * the sign bit of the value. 260257cb251SWill Deacon */ 261257cb251SWill Deacon if ((u64)(sval + 1) >= 2) 262257cb251SWill Deacon return -ERANGE; 263257cb251SWill Deacon 264257cb251SWill Deacon return 0; 265257cb251SWill Deacon } 266257cb251SWill Deacon 267c8ebf64eSJessica Yu static int reloc_insn_adrp(struct module *mod, Elf64_Shdr *sechdrs, 268c8ebf64eSJessica Yu __le32 *place, u64 val) 269a257e025SArd Biesheuvel { 270a257e025SArd Biesheuvel u32 insn; 271a257e025SArd Biesheuvel 272bdb85cd1SArd Biesheuvel if (!is_forbidden_offset_for_adrp(place)) 273a257e025SArd Biesheuvel return reloc_insn_imm(RELOC_OP_PAGE, place, val, 12, 21, 274a257e025SArd Biesheuvel AARCH64_INSN_IMM_ADR); 275a257e025SArd Biesheuvel 276a257e025SArd Biesheuvel /* patch ADRP to ADR if it is in range */ 277a257e025SArd Biesheuvel if (!reloc_insn_imm(RELOC_OP_PREL, place, val & ~0xfff, 0, 21, 278a257e025SArd Biesheuvel AARCH64_INSN_IMM_ADR)) { 279a257e025SArd Biesheuvel insn = le32_to_cpu(*place); 280a257e025SArd Biesheuvel insn &= ~BIT(31); 281a257e025SArd Biesheuvel } else { 282a257e025SArd Biesheuvel /* out of range for ADR -> emit a veneer */ 283c8ebf64eSJessica Yu val = module_emit_veneer_for_adrp(mod, sechdrs, place, val & ~0xfff); 284a257e025SArd Biesheuvel if (!val) 285a257e025SArd Biesheuvel return -ENOEXEC; 286a257e025SArd Biesheuvel insn = aarch64_insn_gen_branch_imm((u64)place, val, 287a257e025SArd Biesheuvel AARCH64_INSN_BRANCH_NOLINK); 288a257e025SArd Biesheuvel } 289a257e025SArd Biesheuvel 290a257e025SArd Biesheuvel *place = cpu_to_le32(insn); 291a257e025SArd Biesheuvel return 0; 292a257e025SArd Biesheuvel } 293a257e025SArd Biesheuvel 294257cb251SWill Deacon int apply_relocate_add(Elf64_Shdr *sechdrs, 295257cb251SWill Deacon const char *strtab, 296257cb251SWill Deacon unsigned int symindex, 297257cb251SWill Deacon unsigned int relsec, 298257cb251SWill Deacon struct module *me) 299257cb251SWill Deacon { 300257cb251SWill Deacon unsigned int i; 301257cb251SWill Deacon int ovf; 302257cb251SWill Deacon bool overflow_check; 303257cb251SWill Deacon Elf64_Sym *sym; 304257cb251SWill Deacon void *loc; 305257cb251SWill Deacon u64 val; 306257cb251SWill Deacon Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr; 307257cb251SWill Deacon 308257cb251SWill Deacon for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { 309257cb251SWill Deacon /* loc corresponds to P in the AArch64 ELF document. */ 310257cb251SWill Deacon loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr 311257cb251SWill Deacon + rel[i].r_offset; 312257cb251SWill Deacon 313257cb251SWill Deacon /* sym is the ELF symbol we're referring to. */ 314257cb251SWill Deacon sym = (Elf64_Sym *)sechdrs[symindex].sh_addr 315257cb251SWill Deacon + ELF64_R_SYM(rel[i].r_info); 316257cb251SWill Deacon 317257cb251SWill Deacon /* val corresponds to (S + A) in the AArch64 ELF document. */ 318257cb251SWill Deacon val = sym->st_value + rel[i].r_addend; 319257cb251SWill Deacon 320257cb251SWill Deacon /* Check for overflow by default. */ 321257cb251SWill Deacon overflow_check = true; 322257cb251SWill Deacon 323257cb251SWill Deacon /* Perform the static relocation. */ 324257cb251SWill Deacon switch (ELF64_R_TYPE(rel[i].r_info)) { 325257cb251SWill Deacon /* Null relocations. */ 326257cb251SWill Deacon case R_ARM_NONE: 327257cb251SWill Deacon case R_AARCH64_NONE: 328257cb251SWill Deacon ovf = 0; 329257cb251SWill Deacon break; 330257cb251SWill Deacon 331257cb251SWill Deacon /* Data relocations. */ 332257cb251SWill Deacon case R_AARCH64_ABS64: 333257cb251SWill Deacon overflow_check = false; 334257cb251SWill Deacon ovf = reloc_data(RELOC_OP_ABS, loc, val, 64); 335257cb251SWill Deacon break; 336257cb251SWill Deacon case R_AARCH64_ABS32: 337257cb251SWill Deacon ovf = reloc_data(RELOC_OP_ABS, loc, val, 32); 338257cb251SWill Deacon break; 339257cb251SWill Deacon case R_AARCH64_ABS16: 340257cb251SWill Deacon ovf = reloc_data(RELOC_OP_ABS, loc, val, 16); 341257cb251SWill Deacon break; 342257cb251SWill Deacon case R_AARCH64_PREL64: 343257cb251SWill Deacon overflow_check = false; 344257cb251SWill Deacon ovf = reloc_data(RELOC_OP_PREL, loc, val, 64); 345257cb251SWill Deacon break; 346257cb251SWill Deacon case R_AARCH64_PREL32: 347257cb251SWill Deacon ovf = reloc_data(RELOC_OP_PREL, loc, val, 32); 348257cb251SWill Deacon break; 349257cb251SWill Deacon case R_AARCH64_PREL16: 350257cb251SWill Deacon ovf = reloc_data(RELOC_OP_PREL, loc, val, 16); 351257cb251SWill Deacon break; 352257cb251SWill Deacon 353257cb251SWill Deacon /* MOVW instruction relocations. */ 354257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G0_NC: 355257cb251SWill Deacon overflow_check = false; 356df561f66SGustavo A. R. Silva fallthrough; 357257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G0: 358257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0, 359b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 360257cb251SWill Deacon break; 361257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G1_NC: 362257cb251SWill Deacon overflow_check = false; 363df561f66SGustavo A. R. Silva fallthrough; 364257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G1: 365257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16, 366b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 367257cb251SWill Deacon break; 368257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G2_NC: 369257cb251SWill Deacon overflow_check = false; 370df561f66SGustavo A. R. Silva fallthrough; 371257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G2: 372257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32, 373b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 374257cb251SWill Deacon break; 375257cb251SWill Deacon case R_AARCH64_MOVW_UABS_G3: 376257cb251SWill Deacon /* We're using the top bits so we can't overflow. */ 377257cb251SWill Deacon overflow_check = false; 378257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 48, 379b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 380257cb251SWill Deacon break; 381257cb251SWill Deacon case R_AARCH64_MOVW_SABS_G0: 382257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0, 383c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 384257cb251SWill Deacon break; 385257cb251SWill Deacon case R_AARCH64_MOVW_SABS_G1: 386257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16, 387c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 388257cb251SWill Deacon break; 389257cb251SWill Deacon case R_AARCH64_MOVW_SABS_G2: 390257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32, 391c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 392257cb251SWill Deacon break; 393257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G0_NC: 394257cb251SWill Deacon overflow_check = false; 395257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0, 396b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 397257cb251SWill Deacon break; 398257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G0: 399257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0, 400c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 401257cb251SWill Deacon break; 402257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G1_NC: 403257cb251SWill Deacon overflow_check = false; 404257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16, 405b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 406257cb251SWill Deacon break; 407257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G1: 408257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16, 409c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 410257cb251SWill Deacon break; 411257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G2_NC: 412257cb251SWill Deacon overflow_check = false; 413257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32, 414b24a5575SArd Biesheuvel AARCH64_INSN_IMM_MOVKZ); 415257cb251SWill Deacon break; 416257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G2: 417257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32, 418c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 419257cb251SWill Deacon break; 420257cb251SWill Deacon case R_AARCH64_MOVW_PREL_G3: 421257cb251SWill Deacon /* We're using the top bits so we can't overflow. */ 422257cb251SWill Deacon overflow_check = false; 423257cb251SWill Deacon ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 48, 424c84fced8SJiang Liu AARCH64_INSN_IMM_MOVNZ); 425257cb251SWill Deacon break; 426257cb251SWill Deacon 427257cb251SWill Deacon /* Immediate instruction relocations. */ 428257cb251SWill Deacon case R_AARCH64_LD_PREL_LO19: 429257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 19, 430c84fced8SJiang Liu AARCH64_INSN_IMM_19); 431257cb251SWill Deacon break; 432257cb251SWill Deacon case R_AARCH64_ADR_PREL_LO21: 433257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 0, 21, 434c84fced8SJiang Liu AARCH64_INSN_IMM_ADR); 435257cb251SWill Deacon break; 436257cb251SWill Deacon case R_AARCH64_ADR_PREL_PG_HI21_NC: 437257cb251SWill Deacon overflow_check = false; 438df561f66SGustavo A. R. Silva fallthrough; 439257cb251SWill Deacon case R_AARCH64_ADR_PREL_PG_HI21: 440c8ebf64eSJessica Yu ovf = reloc_insn_adrp(me, sechdrs, loc, val); 441a257e025SArd Biesheuvel if (ovf && ovf != -ERANGE) 442a257e025SArd Biesheuvel return ovf; 443257cb251SWill Deacon break; 444257cb251SWill Deacon case R_AARCH64_ADD_ABS_LO12_NC: 445257cb251SWill Deacon case R_AARCH64_LDST8_ABS_LO12_NC: 446257cb251SWill Deacon overflow_check = false; 447257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 0, 12, 448c84fced8SJiang Liu AARCH64_INSN_IMM_12); 449257cb251SWill Deacon break; 450257cb251SWill Deacon case R_AARCH64_LDST16_ABS_LO12_NC: 451257cb251SWill Deacon overflow_check = false; 452257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 1, 11, 453c84fced8SJiang Liu AARCH64_INSN_IMM_12); 454257cb251SWill Deacon break; 455257cb251SWill Deacon case R_AARCH64_LDST32_ABS_LO12_NC: 456257cb251SWill Deacon overflow_check = false; 457257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 2, 10, 458c84fced8SJiang Liu AARCH64_INSN_IMM_12); 459257cb251SWill Deacon break; 460257cb251SWill Deacon case R_AARCH64_LDST64_ABS_LO12_NC: 461257cb251SWill Deacon overflow_check = false; 462257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 3, 9, 463c84fced8SJiang Liu AARCH64_INSN_IMM_12); 464257cb251SWill Deacon break; 465257cb251SWill Deacon case R_AARCH64_LDST128_ABS_LO12_NC: 466257cb251SWill Deacon overflow_check = false; 467257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 4, 8, 468c84fced8SJiang Liu AARCH64_INSN_IMM_12); 469257cb251SWill Deacon break; 470257cb251SWill Deacon case R_AARCH64_TSTBR14: 471257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 14, 472c84fced8SJiang Liu AARCH64_INSN_IMM_14); 473257cb251SWill Deacon break; 474257cb251SWill Deacon case R_AARCH64_CONDBR19: 475257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 19, 476c84fced8SJiang Liu AARCH64_INSN_IMM_19); 477257cb251SWill Deacon break; 478257cb251SWill Deacon case R_AARCH64_JUMP26: 479257cb251SWill Deacon case R_AARCH64_CALL26: 480257cb251SWill Deacon ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 26, 481c84fced8SJiang Liu AARCH64_INSN_IMM_26); 482fd045f6cSArd Biesheuvel 483fd045f6cSArd Biesheuvel if (IS_ENABLED(CONFIG_ARM64_MODULE_PLTS) && 484fd045f6cSArd Biesheuvel ovf == -ERANGE) { 485c8ebf64eSJessica Yu val = module_emit_plt_entry(me, sechdrs, loc, &rel[i], sym); 4865e8307b9SArd Biesheuvel if (!val) 4875e8307b9SArd Biesheuvel return -ENOEXEC; 488fd045f6cSArd Biesheuvel ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 489fd045f6cSArd Biesheuvel 26, AARCH64_INSN_IMM_26); 490fd045f6cSArd Biesheuvel } 491257cb251SWill Deacon break; 492257cb251SWill Deacon 493257cb251SWill Deacon default: 494257cb251SWill Deacon pr_err("module %s: unsupported RELA relocation: %llu\n", 495257cb251SWill Deacon me->name, ELF64_R_TYPE(rel[i].r_info)); 496257cb251SWill Deacon return -ENOEXEC; 497257cb251SWill Deacon } 498257cb251SWill Deacon 499257cb251SWill Deacon if (overflow_check && ovf == -ERANGE) 500257cb251SWill Deacon goto overflow; 501257cb251SWill Deacon 502257cb251SWill Deacon } 503257cb251SWill Deacon 504257cb251SWill Deacon return 0; 505257cb251SWill Deacon 506257cb251SWill Deacon overflow: 507257cb251SWill Deacon pr_err("module %s: overflow in relocation type %d val %Lx\n", 508257cb251SWill Deacon me->name, (int)ELF64_R_TYPE(rel[i].r_info), val); 509257cb251SWill Deacon return -ENOEXEC; 510257cb251SWill Deacon } 511932ded4bSAndre Przywara 5123b23e499STorsten Duwe static inline void __init_plt(struct plt_entry *plt, unsigned long addr) 5133b23e499STorsten Duwe { 5143b23e499STorsten Duwe *plt = get_plt_entry(addr, plt); 5153b23e499STorsten Duwe } 5163b23e499STorsten Duwe 517f1a54ae9SMark Rutland static int module_init_ftrace_plt(const Elf_Ehdr *hdr, 518f1a54ae9SMark Rutland const Elf_Shdr *sechdrs, 519f1a54ae9SMark Rutland struct module *mod) 520f1a54ae9SMark Rutland { 521f1a54ae9SMark Rutland #if defined(CONFIG_ARM64_MODULE_PLTS) && defined(CONFIG_DYNAMIC_FTRACE) 522f1a54ae9SMark Rutland const Elf_Shdr *s; 5233b23e499STorsten Duwe struct plt_entry *plts; 524f1a54ae9SMark Rutland 525f1a54ae9SMark Rutland s = find_section(hdr, sechdrs, ".text.ftrace_trampoline"); 526f1a54ae9SMark Rutland if (!s) 527f1a54ae9SMark Rutland return -ENOEXEC; 528f1a54ae9SMark Rutland 5293b23e499STorsten Duwe plts = (void *)s->sh_addr; 5303b23e499STorsten Duwe 5313b23e499STorsten Duwe __init_plt(&plts[FTRACE_PLT_IDX], FTRACE_ADDR); 5323b23e499STorsten Duwe 5333b23e499STorsten Duwe mod->arch.ftrace_trampolines = plts; 534f1a54ae9SMark Rutland #endif 535f1a54ae9SMark Rutland return 0; 536f1a54ae9SMark Rutland } 537f1a54ae9SMark Rutland 538bd8b21d3SMark Rutland int module_finalize(const Elf_Ehdr *hdr, 539bd8b21d3SMark Rutland const Elf_Shdr *sechdrs, 540bd8b21d3SMark Rutland struct module *me) 541bd8b21d3SMark Rutland { 542bd8b21d3SMark Rutland const Elf_Shdr *s; 543bd8b21d3SMark Rutland s = find_section(hdr, sechdrs, ".altinstructions"); 544bd8b21d3SMark Rutland if (s) 545bd8b21d3SMark Rutland apply_alternatives_module((void *)s->sh_addr, s->sh_size); 546bd8b21d3SMark Rutland 5473b619e22SArd Biesheuvel if (scs_is_dynamic()) { 5483b619e22SArd Biesheuvel s = find_section(hdr, sechdrs, ".init.eh_frame"); 5493b619e22SArd Biesheuvel if (s) 5503b619e22SArd Biesheuvel scs_patch((void *)s->sh_addr, s->sh_size); 5513b619e22SArd Biesheuvel } 5523b619e22SArd Biesheuvel 553f1a54ae9SMark Rutland return module_init_ftrace_plt(hdr, sechdrs, me); 554932ded4bSAndre Przywara } 555