1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2e2c0cdfbSPalmer Dabbelt /* 3e2c0cdfbSPalmer Dabbelt * 4e2c0cdfbSPalmer Dabbelt * Copyright (C) 2017 Zihao Yu 5e2c0cdfbSPalmer Dabbelt */ 6e2c0cdfbSPalmer Dabbelt 7e2c0cdfbSPalmer Dabbelt #include <linux/elf.h> 8e2c0cdfbSPalmer Dabbelt #include <linux/err.h> 9e2c0cdfbSPalmer Dabbelt #include <linux/errno.h> 10*8fd6c514SCharlie Jenkins #include <linux/hashtable.h> 11*8fd6c514SCharlie Jenkins #include <linux/kernel.h> 12*8fd6c514SCharlie Jenkins #include <linux/log2.h> 13e2c0cdfbSPalmer Dabbelt #include <linux/moduleloader.h> 140cff8bffSVincent Chen #include <linux/vmalloc.h> 150cff8bffSVincent Chen #include <linux/sizes.h> 16ca5999fdSMike Rapoport #include <linux/pgtable.h> 17a8e91016SHeiko Stuebner #include <asm/alternative.h> 180cff8bffSVincent Chen #include <asm/sections.h> 19e2c0cdfbSPalmer Dabbelt 20*8fd6c514SCharlie Jenkins struct used_bucket { 21*8fd6c514SCharlie Jenkins struct list_head head; 22*8fd6c514SCharlie Jenkins struct hlist_head *bucket; 23*8fd6c514SCharlie Jenkins }; 24*8fd6c514SCharlie Jenkins 25*8fd6c514SCharlie Jenkins struct relocation_head { 26*8fd6c514SCharlie Jenkins struct hlist_node node; 27*8fd6c514SCharlie Jenkins struct list_head *rel_entry; 28*8fd6c514SCharlie Jenkins void *location; 29*8fd6c514SCharlie Jenkins }; 30*8fd6c514SCharlie Jenkins 31*8fd6c514SCharlie Jenkins struct relocation_entry { 32*8fd6c514SCharlie Jenkins struct list_head head; 33*8fd6c514SCharlie Jenkins Elf_Addr value; 34*8fd6c514SCharlie Jenkins unsigned int type; 35*8fd6c514SCharlie Jenkins }; 36*8fd6c514SCharlie Jenkins 37*8fd6c514SCharlie Jenkins struct relocation_handlers { 38*8fd6c514SCharlie Jenkins int (*reloc_handler)(struct module *me, void *location, Elf_Addr v); 39*8fd6c514SCharlie Jenkins int (*accumulate_handler)(struct module *me, void *location, 40*8fd6c514SCharlie Jenkins long buffer); 41*8fd6c514SCharlie Jenkins }; 42*8fd6c514SCharlie Jenkins 43*8fd6c514SCharlie Jenkins unsigned int initialize_relocation_hashtable(unsigned int num_relocations); 44*8fd6c514SCharlie Jenkins void process_accumulated_relocations(struct module *me); 45*8fd6c514SCharlie Jenkins int add_relocation_to_accumulate(struct module *me, int type, void *location, 46*8fd6c514SCharlie Jenkins unsigned int hashtable_bits, Elf_Addr v); 47*8fd6c514SCharlie Jenkins 48*8fd6c514SCharlie Jenkins struct hlist_head *relocation_hashtable; 49*8fd6c514SCharlie Jenkins 50*8fd6c514SCharlie Jenkins struct list_head used_buckets_list; 51*8fd6c514SCharlie Jenkins 520966d385SEmil Renner Berthing /* 530966d385SEmil Renner Berthing * The auipc+jalr instruction pair can reach any PC-relative offset 540966d385SEmil Renner Berthing * in the range [-2^31 - 2^11, 2^31 - 2^11) 550966d385SEmil Renner Berthing */ 560966d385SEmil Renner Berthing static bool riscv_insn_valid_32bit_offset(ptrdiff_t val) 570966d385SEmil Renner Berthing { 580966d385SEmil Renner Berthing #ifdef CONFIG_32BIT 590966d385SEmil Renner Berthing return true; 600966d385SEmil Renner Berthing #else 610966d385SEmil Renner Berthing return (-(1L << 31) - (1L << 11)) <= val && val < ((1L << 31) - (1L << 11)); 620966d385SEmil Renner Berthing #endif 630966d385SEmil Renner Berthing } 640966d385SEmil Renner Berthing 658cbe0accSEmil Renner Berthing static int riscv_insn_rmw(void *location, u32 keep, u32 set) 668cbe0accSEmil Renner Berthing { 678cbe0accSEmil Renner Berthing u16 *parcel = location; 688cbe0accSEmil Renner Berthing u32 insn = (u32)le16_to_cpu(parcel[0]) | (u32)le16_to_cpu(parcel[1]) << 16; 698cbe0accSEmil Renner Berthing 708cbe0accSEmil Renner Berthing insn &= keep; 718cbe0accSEmil Renner Berthing insn |= set; 728cbe0accSEmil Renner Berthing 738cbe0accSEmil Renner Berthing parcel[0] = cpu_to_le16(insn); 748cbe0accSEmil Renner Berthing parcel[1] = cpu_to_le16(insn >> 16); 758cbe0accSEmil Renner Berthing return 0; 768cbe0accSEmil Renner Berthing } 778cbe0accSEmil Renner Berthing 788cbe0accSEmil Renner Berthing static int riscv_insn_rvc_rmw(void *location, u16 keep, u16 set) 798cbe0accSEmil Renner Berthing { 808cbe0accSEmil Renner Berthing u16 *parcel = location; 818cbe0accSEmil Renner Berthing u16 insn = le16_to_cpu(*parcel); 828cbe0accSEmil Renner Berthing 838cbe0accSEmil Renner Berthing insn &= keep; 848cbe0accSEmil Renner Berthing insn |= set; 858cbe0accSEmil Renner Berthing 868cbe0accSEmil Renner Berthing *parcel = cpu_to_le16(insn); 878cbe0accSEmil Renner Berthing return 0; 888cbe0accSEmil Renner Berthing } 898cbe0accSEmil Renner Berthing 908cbe0accSEmil Renner Berthing static int apply_r_riscv_32_rela(struct module *me, void *location, Elf_Addr v) 9177aa85deSAndreas Schwab { 9277aa85deSAndreas Schwab if (v != (u32)v) { 9377aa85deSAndreas Schwab pr_err("%s: value %016llx out of range for 32-bit field\n", 94ef3a6140SOlof Johansson me->name, (long long)v); 9577aa85deSAndreas Schwab return -EINVAL; 9677aa85deSAndreas Schwab } 978cbe0accSEmil Renner Berthing *(u32 *)location = v; 9877aa85deSAndreas Schwab return 0; 9977aa85deSAndreas Schwab } 10077aa85deSAndreas Schwab 1018cbe0accSEmil Renner Berthing static int apply_r_riscv_64_rela(struct module *me, void *location, Elf_Addr v) 102e2c0cdfbSPalmer Dabbelt { 103e2c0cdfbSPalmer Dabbelt *(u64 *)location = v; 104e2c0cdfbSPalmer Dabbelt return 0; 105e2c0cdfbSPalmer Dabbelt } 106e2c0cdfbSPalmer Dabbelt 1078cbe0accSEmil Renner Berthing static int apply_r_riscv_branch_rela(struct module *me, void *location, 108e2c0cdfbSPalmer Dabbelt Elf_Addr v) 109e2c0cdfbSPalmer Dabbelt { 1108cbe0accSEmil Renner Berthing ptrdiff_t offset = (void *)v - location; 111e2c0cdfbSPalmer Dabbelt u32 imm12 = (offset & 0x1000) << (31 - 12); 112e2c0cdfbSPalmer Dabbelt u32 imm11 = (offset & 0x800) >> (11 - 7); 113e2c0cdfbSPalmer Dabbelt u32 imm10_5 = (offset & 0x7e0) << (30 - 10); 114e2c0cdfbSPalmer Dabbelt u32 imm4_1 = (offset & 0x1e) << (11 - 4); 115e2c0cdfbSPalmer Dabbelt 1168cbe0accSEmil Renner Berthing return riscv_insn_rmw(location, 0x1fff07f, imm12 | imm11 | imm10_5 | imm4_1); 117e2c0cdfbSPalmer Dabbelt } 118e2c0cdfbSPalmer Dabbelt 1198cbe0accSEmil Renner Berthing static int apply_r_riscv_jal_rela(struct module *me, void *location, 120e2c0cdfbSPalmer Dabbelt Elf_Addr v) 121e2c0cdfbSPalmer Dabbelt { 1228cbe0accSEmil Renner Berthing ptrdiff_t offset = (void *)v - location; 123e2c0cdfbSPalmer Dabbelt u32 imm20 = (offset & 0x100000) << (31 - 20); 124e2c0cdfbSPalmer Dabbelt u32 imm19_12 = (offset & 0xff000); 125e2c0cdfbSPalmer Dabbelt u32 imm11 = (offset & 0x800) << (20 - 11); 126e2c0cdfbSPalmer Dabbelt u32 imm10_1 = (offset & 0x7fe) << (30 - 10); 127e2c0cdfbSPalmer Dabbelt 1288cbe0accSEmil Renner Berthing return riscv_insn_rmw(location, 0xfff, imm20 | imm19_12 | imm11 | imm10_1); 129e2c0cdfbSPalmer Dabbelt } 130e2c0cdfbSPalmer Dabbelt 1318cbe0accSEmil Renner Berthing static int apply_r_riscv_rvc_branch_rela(struct module *me, void *location, 13256ea45aeSZong Li Elf_Addr v) 13356ea45aeSZong Li { 1348cbe0accSEmil Renner Berthing ptrdiff_t offset = (void *)v - location; 13556ea45aeSZong Li u16 imm8 = (offset & 0x100) << (12 - 8); 13656ea45aeSZong Li u16 imm7_6 = (offset & 0xc0) >> (6 - 5); 13756ea45aeSZong Li u16 imm5 = (offset & 0x20) >> (5 - 2); 13856ea45aeSZong Li u16 imm4_3 = (offset & 0x18) << (12 - 5); 13956ea45aeSZong Li u16 imm2_1 = (offset & 0x6) << (12 - 10); 14056ea45aeSZong Li 1418cbe0accSEmil Renner Berthing return riscv_insn_rvc_rmw(location, 0xe383, 1428cbe0accSEmil Renner Berthing imm8 | imm7_6 | imm5 | imm4_3 | imm2_1); 14356ea45aeSZong Li } 14456ea45aeSZong Li 1458cbe0accSEmil Renner Berthing static int apply_r_riscv_rvc_jump_rela(struct module *me, void *location, 14656ea45aeSZong Li Elf_Addr v) 14756ea45aeSZong Li { 1488cbe0accSEmil Renner Berthing ptrdiff_t offset = (void *)v - location; 14956ea45aeSZong Li u16 imm11 = (offset & 0x800) << (12 - 11); 15056ea45aeSZong Li u16 imm10 = (offset & 0x400) >> (10 - 8); 15156ea45aeSZong Li u16 imm9_8 = (offset & 0x300) << (12 - 11); 15256ea45aeSZong Li u16 imm7 = (offset & 0x80) >> (7 - 6); 15356ea45aeSZong Li u16 imm6 = (offset & 0x40) << (12 - 11); 15456ea45aeSZong Li u16 imm5 = (offset & 0x20) >> (5 - 2); 15556ea45aeSZong Li u16 imm4 = (offset & 0x10) << (12 - 5); 15656ea45aeSZong Li u16 imm3_1 = (offset & 0xe) << (12 - 10); 15756ea45aeSZong Li 1588cbe0accSEmil Renner Berthing return riscv_insn_rvc_rmw(location, 0xe003, 1598cbe0accSEmil Renner Berthing imm11 | imm10 | imm9_8 | imm7 | imm6 | imm5 | imm4 | imm3_1); 16056ea45aeSZong Li } 16156ea45aeSZong Li 1628cbe0accSEmil Renner Berthing static int apply_r_riscv_pcrel_hi20_rela(struct module *me, void *location, 163e2c0cdfbSPalmer Dabbelt Elf_Addr v) 164e2c0cdfbSPalmer Dabbelt { 1658cbe0accSEmil Renner Berthing ptrdiff_t offset = (void *)v - location; 166e2c0cdfbSPalmer Dabbelt 1670966d385SEmil Renner Berthing if (!riscv_insn_valid_32bit_offset(offset)) { 168e2c0cdfbSPalmer Dabbelt pr_err( 169e2c0cdfbSPalmer Dabbelt "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n", 170ef3a6140SOlof Johansson me->name, (long long)v, location); 171e2c0cdfbSPalmer Dabbelt return -EINVAL; 172e2c0cdfbSPalmer Dabbelt } 173e2c0cdfbSPalmer Dabbelt 1748cbe0accSEmil Renner Berthing return riscv_insn_rmw(location, 0xfff, (offset + 0x800) & 0xfffff000); 175e2c0cdfbSPalmer Dabbelt } 176e2c0cdfbSPalmer Dabbelt 1778cbe0accSEmil Renner Berthing static int apply_r_riscv_pcrel_lo12_i_rela(struct module *me, void *location, 178e2c0cdfbSPalmer Dabbelt Elf_Addr v) 179e2c0cdfbSPalmer Dabbelt { 180e2c0cdfbSPalmer Dabbelt /* 181e2c0cdfbSPalmer Dabbelt * v is the lo12 value to fill. It is calculated before calling this 182e2c0cdfbSPalmer Dabbelt * handler. 183e2c0cdfbSPalmer Dabbelt */ 1848cbe0accSEmil Renner Berthing return riscv_insn_rmw(location, 0xfffff, (v & 0xfff) << 20); 185e2c0cdfbSPalmer Dabbelt } 186e2c0cdfbSPalmer Dabbelt 1878cbe0accSEmil Renner Berthing static int apply_r_riscv_pcrel_lo12_s_rela(struct module *me, void *location, 188e2c0cdfbSPalmer Dabbelt Elf_Addr v) 189e2c0cdfbSPalmer Dabbelt { 190e2c0cdfbSPalmer Dabbelt /* 191e2c0cdfbSPalmer Dabbelt * v is the lo12 value to fill. It is calculated before calling this 192e2c0cdfbSPalmer Dabbelt * handler. 193e2c0cdfbSPalmer Dabbelt */ 194e2c0cdfbSPalmer Dabbelt u32 imm11_5 = (v & 0xfe0) << (31 - 11); 195e2c0cdfbSPalmer Dabbelt u32 imm4_0 = (v & 0x1f) << (11 - 4); 196e2c0cdfbSPalmer Dabbelt 1978cbe0accSEmil Renner Berthing return riscv_insn_rmw(location, 0x1fff07f, imm11_5 | imm4_0); 198e2c0cdfbSPalmer Dabbelt } 199e2c0cdfbSPalmer Dabbelt 2008cbe0accSEmil Renner Berthing static int apply_r_riscv_hi20_rela(struct module *me, void *location, 201e7456e69SZong Li Elf_Addr v) 202e7456e69SZong Li { 203da4ed378SJoe Perches if (IS_ENABLED(CONFIG_CMODEL_MEDLOW)) { 204e7456e69SZong Li pr_err( 205e7456e69SZong Li "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n", 206ef3a6140SOlof Johansson me->name, (long long)v, location); 207e7456e69SZong Li return -EINVAL; 208e7456e69SZong Li } 209e7456e69SZong Li 2108cbe0accSEmil Renner Berthing return riscv_insn_rmw(location, 0xfff, ((s32)v + 0x800) & 0xfffff000); 211e7456e69SZong Li } 212e7456e69SZong Li 2138cbe0accSEmil Renner Berthing static int apply_r_riscv_lo12_i_rela(struct module *me, void *location, 214e7456e69SZong Li Elf_Addr v) 215e7456e69SZong Li { 216e7456e69SZong Li /* Skip medlow checking because of filtering by HI20 already */ 217e7456e69SZong Li s32 hi20 = ((s32)v + 0x800) & 0xfffff000; 218e7456e69SZong Li s32 lo12 = ((s32)v - hi20); 2198cbe0accSEmil Renner Berthing 2208cbe0accSEmil Renner Berthing return riscv_insn_rmw(location, 0xfffff, (lo12 & 0xfff) << 20); 221e7456e69SZong Li } 222e7456e69SZong Li 2238cbe0accSEmil Renner Berthing static int apply_r_riscv_lo12_s_rela(struct module *me, void *location, 224e7456e69SZong Li Elf_Addr v) 225e7456e69SZong Li { 226e7456e69SZong Li /* Skip medlow checking because of filtering by HI20 already */ 227e7456e69SZong Li s32 hi20 = ((s32)v + 0x800) & 0xfffff000; 228e7456e69SZong Li s32 lo12 = ((s32)v - hi20); 229e7456e69SZong Li u32 imm11_5 = (lo12 & 0xfe0) << (31 - 11); 230e7456e69SZong Li u32 imm4_0 = (lo12 & 0x1f) << (11 - 4); 2318cbe0accSEmil Renner Berthing 2328cbe0accSEmil Renner Berthing return riscv_insn_rmw(location, 0x1fff07f, imm11_5 | imm4_0); 233e7456e69SZong Li } 234e7456e69SZong Li 2358cbe0accSEmil Renner Berthing static int apply_r_riscv_got_hi20_rela(struct module *me, void *location, 236da975dd4SZong Li Elf_Addr v) 237da975dd4SZong Li { 2388cbe0accSEmil Renner Berthing ptrdiff_t offset = (void *)v - location; 239da975dd4SZong Li 240da975dd4SZong Li /* Always emit the got entry */ 241da975dd4SZong Li if (IS_ENABLED(CONFIG_MODULE_SECTIONS)) { 2428cbe0accSEmil Renner Berthing offset = (void *)module_emit_got_entry(me, v) - location; 243da975dd4SZong Li } else { 244da975dd4SZong Li pr_err( 245da975dd4SZong Li "%s: can not generate the GOT entry for symbol = %016llx from PC = %p\n", 246ef3a6140SOlof Johansson me->name, (long long)v, location); 247da975dd4SZong Li return -EINVAL; 248da975dd4SZong Li } 249da975dd4SZong Li 2508cbe0accSEmil Renner Berthing return riscv_insn_rmw(location, 0xfff, (offset + 0x800) & 0xfffff000); 251da975dd4SZong Li } 252da975dd4SZong Li 2538cbe0accSEmil Renner Berthing static int apply_r_riscv_call_plt_rela(struct module *me, void *location, 254e2c0cdfbSPalmer Dabbelt Elf_Addr v) 255e2c0cdfbSPalmer Dabbelt { 2568cbe0accSEmil Renner Berthing ptrdiff_t offset = (void *)v - location; 257e2c0cdfbSPalmer Dabbelt u32 hi20, lo12; 258e2c0cdfbSPalmer Dabbelt 2590966d385SEmil Renner Berthing if (!riscv_insn_valid_32bit_offset(offset)) { 260da975dd4SZong Li /* Only emit the plt entry if offset over 32-bit range */ 261da975dd4SZong Li if (IS_ENABLED(CONFIG_MODULE_SECTIONS)) { 2628cbe0accSEmil Renner Berthing offset = (void *)module_emit_plt_entry(me, v) - location; 263da975dd4SZong Li } else { 264e2c0cdfbSPalmer Dabbelt pr_err( 265e2c0cdfbSPalmer Dabbelt "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n", 266ef3a6140SOlof Johansson me->name, (long long)v, location); 267e2c0cdfbSPalmer Dabbelt return -EINVAL; 268e2c0cdfbSPalmer Dabbelt } 269da975dd4SZong Li } 270e2c0cdfbSPalmer Dabbelt 271e2c0cdfbSPalmer Dabbelt hi20 = (offset + 0x800) & 0xfffff000; 272e2c0cdfbSPalmer Dabbelt lo12 = (offset - hi20) & 0xfff; 2738cbe0accSEmil Renner Berthing riscv_insn_rmw(location, 0xfff, hi20); 2748cbe0accSEmil Renner Berthing return riscv_insn_rmw(location + 4, 0xfffff, lo12 << 20); 275e2c0cdfbSPalmer Dabbelt } 276e2c0cdfbSPalmer Dabbelt 2778cbe0accSEmil Renner Berthing static int apply_r_riscv_call_rela(struct module *me, void *location, 278e1910c72SZong Li Elf_Addr v) 279e1910c72SZong Li { 2808cbe0accSEmil Renner Berthing ptrdiff_t offset = (void *)v - location; 281e1910c72SZong Li u32 hi20, lo12; 282e1910c72SZong Li 2830966d385SEmil Renner Berthing if (!riscv_insn_valid_32bit_offset(offset)) { 284e1910c72SZong Li pr_err( 285e1910c72SZong Li "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n", 286ef3a6140SOlof Johansson me->name, (long long)v, location); 287e1910c72SZong Li return -EINVAL; 288e1910c72SZong Li } 289e1910c72SZong Li 290e1910c72SZong Li hi20 = (offset + 0x800) & 0xfffff000; 291e1910c72SZong Li lo12 = (offset - hi20) & 0xfff; 2928cbe0accSEmil Renner Berthing riscv_insn_rmw(location, 0xfff, hi20); 2938cbe0accSEmil Renner Berthing return riscv_insn_rmw(location + 4, 0xfffff, lo12 << 20); 294e1910c72SZong Li } 295e1910c72SZong Li 2968cbe0accSEmil Renner Berthing static int apply_r_riscv_relax_rela(struct module *me, void *location, 297e2c0cdfbSPalmer Dabbelt Elf_Addr v) 298e2c0cdfbSPalmer Dabbelt { 299e2c0cdfbSPalmer Dabbelt return 0; 300e2c0cdfbSPalmer Dabbelt } 301e2c0cdfbSPalmer Dabbelt 3028cbe0accSEmil Renner Berthing static int apply_r_riscv_align_rela(struct module *me, void *location, 30329e405cdSZong Li Elf_Addr v) 30429e405cdSZong Li { 30529e405cdSZong Li pr_err( 30629e405cdSZong Li "%s: The unexpected relocation type 'R_RISCV_ALIGN' from PC = %p\n", 30729e405cdSZong Li me->name, location); 30829e405cdSZong Li return -EINVAL; 30929e405cdSZong Li } 31029e405cdSZong Li 311*8fd6c514SCharlie Jenkins static int apply_r_riscv_add8_rela(struct module *me, void *location, Elf_Addr v) 312*8fd6c514SCharlie Jenkins { 313*8fd6c514SCharlie Jenkins *(u8 *)location += (u8)v; 314*8fd6c514SCharlie Jenkins return 0; 315*8fd6c514SCharlie Jenkins } 316*8fd6c514SCharlie Jenkins 3178cbe0accSEmil Renner Berthing static int apply_r_riscv_add16_rela(struct module *me, void *location, 3181bc400ffSAndrew Jones Elf_Addr v) 3191bc400ffSAndrew Jones { 3201bc400ffSAndrew Jones *(u16 *)location += (u16)v; 3211bc400ffSAndrew Jones return 0; 3221bc400ffSAndrew Jones } 3231bc400ffSAndrew Jones 3248cbe0accSEmil Renner Berthing static int apply_r_riscv_add32_rela(struct module *me, void *location, 3258e691b16SZong Li Elf_Addr v) 3268e691b16SZong Li { 327781c8fe2SAndreas Schwab *(u32 *)location += (u32)v; 3288e691b16SZong Li return 0; 3298e691b16SZong Li } 3308e691b16SZong Li 3318cbe0accSEmil Renner Berthing static int apply_r_riscv_add64_rela(struct module *me, void *location, 33211a54f42SEmil Renner Berthing Elf_Addr v) 33311a54f42SEmil Renner Berthing { 33411a54f42SEmil Renner Berthing *(u64 *)location += (u64)v; 33511a54f42SEmil Renner Berthing return 0; 33611a54f42SEmil Renner Berthing } 33711a54f42SEmil Renner Berthing 338*8fd6c514SCharlie Jenkins static int apply_r_riscv_sub8_rela(struct module *me, void *location, Elf_Addr v) 339*8fd6c514SCharlie Jenkins { 340*8fd6c514SCharlie Jenkins *(u8 *)location -= (u8)v; 341*8fd6c514SCharlie Jenkins return 0; 342*8fd6c514SCharlie Jenkins } 343*8fd6c514SCharlie Jenkins 3448cbe0accSEmil Renner Berthing static int apply_r_riscv_sub16_rela(struct module *me, void *location, 3451bc400ffSAndrew Jones Elf_Addr v) 3461bc400ffSAndrew Jones { 3471bc400ffSAndrew Jones *(u16 *)location -= (u16)v; 3481bc400ffSAndrew Jones return 0; 3491bc400ffSAndrew Jones } 3501bc400ffSAndrew Jones 3518cbe0accSEmil Renner Berthing static int apply_r_riscv_sub32_rela(struct module *me, void *location, 3524aad074cSZong Li Elf_Addr v) 3534aad074cSZong Li { 354781c8fe2SAndreas Schwab *(u32 *)location -= (u32)v; 3554aad074cSZong Li return 0; 3564aad074cSZong Li } 3574aad074cSZong Li 3588cbe0accSEmil Renner Berthing static int apply_r_riscv_sub64_rela(struct module *me, void *location, 35911a54f42SEmil Renner Berthing Elf_Addr v) 36011a54f42SEmil Renner Berthing { 36111a54f42SEmil Renner Berthing *(u64 *)location -= (u64)v; 36211a54f42SEmil Renner Berthing return 0; 36311a54f42SEmil Renner Berthing } 36411a54f42SEmil Renner Berthing 365*8fd6c514SCharlie Jenkins static int dynamic_linking_not_supported(struct module *me, void *location, 366*8fd6c514SCharlie Jenkins Elf_Addr v) 367*8fd6c514SCharlie Jenkins { 368*8fd6c514SCharlie Jenkins pr_err("%s: Dynamic linking not supported in kernel modules PC = %p\n", 369*8fd6c514SCharlie Jenkins me->name, location); 370*8fd6c514SCharlie Jenkins return -EINVAL; 371*8fd6c514SCharlie Jenkins } 372*8fd6c514SCharlie Jenkins 373*8fd6c514SCharlie Jenkins static int tls_not_supported(struct module *me, void *location, Elf_Addr v) 374*8fd6c514SCharlie Jenkins { 375*8fd6c514SCharlie Jenkins pr_err("%s: Thread local storage not supported in kernel modules PC = %p\n", 376*8fd6c514SCharlie Jenkins me->name, location); 377*8fd6c514SCharlie Jenkins return -EINVAL; 378*8fd6c514SCharlie Jenkins } 379*8fd6c514SCharlie Jenkins 380*8fd6c514SCharlie Jenkins static int apply_r_riscv_sub6_rela(struct module *me, void *location, Elf_Addr v) 381*8fd6c514SCharlie Jenkins { 382*8fd6c514SCharlie Jenkins u8 *byte = location; 383*8fd6c514SCharlie Jenkins u8 value = v; 384*8fd6c514SCharlie Jenkins 385*8fd6c514SCharlie Jenkins *byte = (*byte - (value & 0x3f)) & 0x3f; 386*8fd6c514SCharlie Jenkins return 0; 387*8fd6c514SCharlie Jenkins } 388*8fd6c514SCharlie Jenkins 389*8fd6c514SCharlie Jenkins static int apply_r_riscv_set6_rela(struct module *me, void *location, Elf_Addr v) 390*8fd6c514SCharlie Jenkins { 391*8fd6c514SCharlie Jenkins u8 *byte = location; 392*8fd6c514SCharlie Jenkins u8 value = v; 393*8fd6c514SCharlie Jenkins 394*8fd6c514SCharlie Jenkins *byte = (*byte & 0xc0) | (value & 0x3f); 395*8fd6c514SCharlie Jenkins return 0; 396*8fd6c514SCharlie Jenkins } 397*8fd6c514SCharlie Jenkins 398*8fd6c514SCharlie Jenkins static int apply_r_riscv_set8_rela(struct module *me, void *location, Elf_Addr v) 399*8fd6c514SCharlie Jenkins { 400*8fd6c514SCharlie Jenkins *(u8 *)location = (u8)v; 401*8fd6c514SCharlie Jenkins return 0; 402*8fd6c514SCharlie Jenkins } 403*8fd6c514SCharlie Jenkins 404*8fd6c514SCharlie Jenkins static int apply_r_riscv_set16_rela(struct module *me, void *location, 405*8fd6c514SCharlie Jenkins Elf_Addr v) 406*8fd6c514SCharlie Jenkins { 407*8fd6c514SCharlie Jenkins *(u16 *)location = (u16)v; 408*8fd6c514SCharlie Jenkins return 0; 409*8fd6c514SCharlie Jenkins } 410*8fd6c514SCharlie Jenkins 411*8fd6c514SCharlie Jenkins static int apply_r_riscv_set32_rela(struct module *me, void *location, 412*8fd6c514SCharlie Jenkins Elf_Addr v) 413*8fd6c514SCharlie Jenkins { 414*8fd6c514SCharlie Jenkins *(u32 *)location = (u32)v; 415*8fd6c514SCharlie Jenkins return 0; 416*8fd6c514SCharlie Jenkins } 417*8fd6c514SCharlie Jenkins 418*8fd6c514SCharlie Jenkins static int apply_r_riscv_32_pcrel_rela(struct module *me, void *location, 419*8fd6c514SCharlie Jenkins Elf_Addr v) 420*8fd6c514SCharlie Jenkins { 421*8fd6c514SCharlie Jenkins *(u32 *)location = v - (uintptr_t)location; 422*8fd6c514SCharlie Jenkins return 0; 423*8fd6c514SCharlie Jenkins } 424*8fd6c514SCharlie Jenkins 425*8fd6c514SCharlie Jenkins static int apply_r_riscv_plt32_rela(struct module *me, void *location, 426*8fd6c514SCharlie Jenkins Elf_Addr v) 427*8fd6c514SCharlie Jenkins { 428*8fd6c514SCharlie Jenkins ptrdiff_t offset = (void *)v - location; 429*8fd6c514SCharlie Jenkins 430*8fd6c514SCharlie Jenkins if (!riscv_insn_valid_32bit_offset(offset)) { 431*8fd6c514SCharlie Jenkins /* Only emit the plt entry if offset over 32-bit range */ 432*8fd6c514SCharlie Jenkins if (IS_ENABLED(CONFIG_MODULE_SECTIONS)) { 433*8fd6c514SCharlie Jenkins offset = (void *)module_emit_plt_entry(me, v) - location; 434*8fd6c514SCharlie Jenkins } else { 435*8fd6c514SCharlie Jenkins pr_err("%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n", 436*8fd6c514SCharlie Jenkins me->name, (long long)v, location); 437*8fd6c514SCharlie Jenkins return -EINVAL; 438*8fd6c514SCharlie Jenkins } 439*8fd6c514SCharlie Jenkins } 440*8fd6c514SCharlie Jenkins 441*8fd6c514SCharlie Jenkins *(u32 *)location = (u32)offset; 442*8fd6c514SCharlie Jenkins return 0; 443*8fd6c514SCharlie Jenkins } 444*8fd6c514SCharlie Jenkins 445*8fd6c514SCharlie Jenkins static int apply_r_riscv_set_uleb128(struct module *me, void *location, Elf_Addr v) 446*8fd6c514SCharlie Jenkins { 447*8fd6c514SCharlie Jenkins *(long *)location = v; 448*8fd6c514SCharlie Jenkins return 0; 449*8fd6c514SCharlie Jenkins } 450*8fd6c514SCharlie Jenkins 451*8fd6c514SCharlie Jenkins static int apply_r_riscv_sub_uleb128(struct module *me, void *location, Elf_Addr v) 452*8fd6c514SCharlie Jenkins { 453*8fd6c514SCharlie Jenkins *(long *)location -= v; 454*8fd6c514SCharlie Jenkins return 0; 455*8fd6c514SCharlie Jenkins } 456*8fd6c514SCharlie Jenkins 457*8fd6c514SCharlie Jenkins static int apply_6_bit_accumulation(struct module *me, void *location, long buffer) 458*8fd6c514SCharlie Jenkins { 459*8fd6c514SCharlie Jenkins u8 *byte = location; 460*8fd6c514SCharlie Jenkins u8 value = buffer; 461*8fd6c514SCharlie Jenkins 462*8fd6c514SCharlie Jenkins if (buffer > 0x3f) { 463*8fd6c514SCharlie Jenkins pr_err("%s: value %ld out of range for 6-bit relocation.\n", 464*8fd6c514SCharlie Jenkins me->name, buffer); 465*8fd6c514SCharlie Jenkins return -EINVAL; 466*8fd6c514SCharlie Jenkins } 467*8fd6c514SCharlie Jenkins 468*8fd6c514SCharlie Jenkins *byte = (*byte & 0xc0) | (value & 0x3f); 469*8fd6c514SCharlie Jenkins return 0; 470*8fd6c514SCharlie Jenkins } 471*8fd6c514SCharlie Jenkins 472*8fd6c514SCharlie Jenkins static int apply_8_bit_accumulation(struct module *me, void *location, long buffer) 473*8fd6c514SCharlie Jenkins { 474*8fd6c514SCharlie Jenkins if (buffer > U8_MAX) { 475*8fd6c514SCharlie Jenkins pr_err("%s: value %ld out of range for 8-bit relocation.\n", 476*8fd6c514SCharlie Jenkins me->name, buffer); 477*8fd6c514SCharlie Jenkins return -EINVAL; 478*8fd6c514SCharlie Jenkins } 479*8fd6c514SCharlie Jenkins *(u8 *)location = (u8)buffer; 480*8fd6c514SCharlie Jenkins return 0; 481*8fd6c514SCharlie Jenkins } 482*8fd6c514SCharlie Jenkins 483*8fd6c514SCharlie Jenkins static int apply_16_bit_accumulation(struct module *me, void *location, long buffer) 484*8fd6c514SCharlie Jenkins { 485*8fd6c514SCharlie Jenkins if (buffer > U16_MAX) { 486*8fd6c514SCharlie Jenkins pr_err("%s: value %ld out of range for 16-bit relocation.\n", 487*8fd6c514SCharlie Jenkins me->name, buffer); 488*8fd6c514SCharlie Jenkins return -EINVAL; 489*8fd6c514SCharlie Jenkins } 490*8fd6c514SCharlie Jenkins *(u16 *)location = (u16)buffer; 491*8fd6c514SCharlie Jenkins return 0; 492*8fd6c514SCharlie Jenkins } 493*8fd6c514SCharlie Jenkins 494*8fd6c514SCharlie Jenkins static int apply_32_bit_accumulation(struct module *me, void *location, long buffer) 495*8fd6c514SCharlie Jenkins { 496*8fd6c514SCharlie Jenkins if (buffer > U32_MAX) { 497*8fd6c514SCharlie Jenkins pr_err("%s: value %ld out of range for 32-bit relocation.\n", 498*8fd6c514SCharlie Jenkins me->name, buffer); 499*8fd6c514SCharlie Jenkins return -EINVAL; 500*8fd6c514SCharlie Jenkins } 501*8fd6c514SCharlie Jenkins *(u32 *)location = (u32)buffer; 502*8fd6c514SCharlie Jenkins return 0; 503*8fd6c514SCharlie Jenkins } 504*8fd6c514SCharlie Jenkins 505*8fd6c514SCharlie Jenkins static int apply_64_bit_accumulation(struct module *me, void *location, long buffer) 506*8fd6c514SCharlie Jenkins { 507*8fd6c514SCharlie Jenkins *(u64 *)location = (u64)buffer; 508*8fd6c514SCharlie Jenkins return 0; 509*8fd6c514SCharlie Jenkins } 510*8fd6c514SCharlie Jenkins 511*8fd6c514SCharlie Jenkins static int apply_uleb128_accumulation(struct module *me, void *location, long buffer) 512*8fd6c514SCharlie Jenkins { 513*8fd6c514SCharlie Jenkins /* 514*8fd6c514SCharlie Jenkins * ULEB128 is a variable length encoding. Encode the buffer into 515*8fd6c514SCharlie Jenkins * the ULEB128 data format. 516*8fd6c514SCharlie Jenkins */ 517*8fd6c514SCharlie Jenkins u8 *p = location; 518*8fd6c514SCharlie Jenkins 519*8fd6c514SCharlie Jenkins while (buffer != 0) { 520*8fd6c514SCharlie Jenkins u8 value = buffer & 0x7f; 521*8fd6c514SCharlie Jenkins 522*8fd6c514SCharlie Jenkins buffer >>= 7; 523*8fd6c514SCharlie Jenkins value |= (!!buffer) << 7; 524*8fd6c514SCharlie Jenkins 525*8fd6c514SCharlie Jenkins *p++ = value; 526*8fd6c514SCharlie Jenkins } 527*8fd6c514SCharlie Jenkins return 0; 528*8fd6c514SCharlie Jenkins } 529*8fd6c514SCharlie Jenkins 530*8fd6c514SCharlie Jenkins /* 531*8fd6c514SCharlie Jenkins * Relocations defined in the riscv-elf-psabi-doc. 532*8fd6c514SCharlie Jenkins * This handles static linking only. 533*8fd6c514SCharlie Jenkins */ 534*8fd6c514SCharlie Jenkins static const struct relocation_handlers reloc_handlers[] = { 535*8fd6c514SCharlie Jenkins [R_RISCV_32] = { apply_r_riscv_32_rela }, 536*8fd6c514SCharlie Jenkins [R_RISCV_64] = { apply_r_riscv_64_rela }, 537*8fd6c514SCharlie Jenkins [R_RISCV_RELATIVE] = { dynamic_linking_not_supported }, 538*8fd6c514SCharlie Jenkins [R_RISCV_COPY] = { dynamic_linking_not_supported }, 539*8fd6c514SCharlie Jenkins [R_RISCV_JUMP_SLOT] = { dynamic_linking_not_supported }, 540*8fd6c514SCharlie Jenkins [R_RISCV_TLS_DTPMOD32] = { dynamic_linking_not_supported }, 541*8fd6c514SCharlie Jenkins [R_RISCV_TLS_DTPMOD64] = { dynamic_linking_not_supported }, 542*8fd6c514SCharlie Jenkins [R_RISCV_TLS_DTPREL32] = { dynamic_linking_not_supported }, 543*8fd6c514SCharlie Jenkins [R_RISCV_TLS_DTPREL64] = { dynamic_linking_not_supported }, 544*8fd6c514SCharlie Jenkins [R_RISCV_TLS_TPREL32] = { dynamic_linking_not_supported }, 545*8fd6c514SCharlie Jenkins [R_RISCV_TLS_TPREL64] = { dynamic_linking_not_supported }, 546*8fd6c514SCharlie Jenkins /* 12-15 undefined */ 547*8fd6c514SCharlie Jenkins [R_RISCV_BRANCH] = { apply_r_riscv_branch_rela }, 548*8fd6c514SCharlie Jenkins [R_RISCV_JAL] = { apply_r_riscv_jal_rela }, 549*8fd6c514SCharlie Jenkins [R_RISCV_CALL] = { apply_r_riscv_call_rela }, 550*8fd6c514SCharlie Jenkins [R_RISCV_CALL_PLT] = { apply_r_riscv_call_plt_rela }, 551*8fd6c514SCharlie Jenkins [R_RISCV_GOT_HI20] = { apply_r_riscv_got_hi20_rela }, 552*8fd6c514SCharlie Jenkins [R_RISCV_TLS_GOT_HI20] = { tls_not_supported }, 553*8fd6c514SCharlie Jenkins [R_RISCV_TLS_GD_HI20] = { tls_not_supported }, 554*8fd6c514SCharlie Jenkins [R_RISCV_PCREL_HI20] = { apply_r_riscv_pcrel_hi20_rela }, 555*8fd6c514SCharlie Jenkins [R_RISCV_PCREL_LO12_I] = { apply_r_riscv_pcrel_lo12_i_rela }, 556*8fd6c514SCharlie Jenkins [R_RISCV_PCREL_LO12_S] = { apply_r_riscv_pcrel_lo12_s_rela }, 557*8fd6c514SCharlie Jenkins [R_RISCV_HI20] = { apply_r_riscv_hi20_rela }, 558*8fd6c514SCharlie Jenkins [R_RISCV_LO12_I] = { apply_r_riscv_lo12_i_rela }, 559*8fd6c514SCharlie Jenkins [R_RISCV_LO12_S] = { apply_r_riscv_lo12_s_rela }, 560*8fd6c514SCharlie Jenkins [R_RISCV_TPREL_HI20] = { tls_not_supported }, 561*8fd6c514SCharlie Jenkins [R_RISCV_TPREL_LO12_I] = { tls_not_supported }, 562*8fd6c514SCharlie Jenkins [R_RISCV_TPREL_LO12_S] = { tls_not_supported }, 563*8fd6c514SCharlie Jenkins [R_RISCV_TPREL_ADD] = { tls_not_supported }, 564*8fd6c514SCharlie Jenkins [R_RISCV_ADD8] = { apply_r_riscv_add8_rela, apply_8_bit_accumulation }, 565*8fd6c514SCharlie Jenkins [R_RISCV_ADD16] = { apply_r_riscv_add16_rela, 566*8fd6c514SCharlie Jenkins apply_16_bit_accumulation }, 567*8fd6c514SCharlie Jenkins [R_RISCV_ADD32] = { apply_r_riscv_add32_rela, 568*8fd6c514SCharlie Jenkins apply_32_bit_accumulation }, 569*8fd6c514SCharlie Jenkins [R_RISCV_ADD64] = { apply_r_riscv_add64_rela, 570*8fd6c514SCharlie Jenkins apply_64_bit_accumulation }, 571*8fd6c514SCharlie Jenkins [R_RISCV_SUB8] = { apply_r_riscv_sub8_rela, apply_8_bit_accumulation }, 572*8fd6c514SCharlie Jenkins [R_RISCV_SUB16] = { apply_r_riscv_sub16_rela, 573*8fd6c514SCharlie Jenkins apply_16_bit_accumulation }, 574*8fd6c514SCharlie Jenkins [R_RISCV_SUB32] = { apply_r_riscv_sub32_rela, 575*8fd6c514SCharlie Jenkins apply_32_bit_accumulation }, 576*8fd6c514SCharlie Jenkins [R_RISCV_SUB64] = { apply_r_riscv_sub64_rela, 577*8fd6c514SCharlie Jenkins apply_64_bit_accumulation }, 578*8fd6c514SCharlie Jenkins /* 41-42 reserved for future standard use */ 579*8fd6c514SCharlie Jenkins [R_RISCV_ALIGN] = { apply_r_riscv_align_rela }, 580*8fd6c514SCharlie Jenkins [R_RISCV_RVC_BRANCH] = { apply_r_riscv_rvc_branch_rela }, 581*8fd6c514SCharlie Jenkins [R_RISCV_RVC_JUMP] = { apply_r_riscv_rvc_jump_rela }, 582*8fd6c514SCharlie Jenkins /* 46-50 reserved for future standard use */ 583*8fd6c514SCharlie Jenkins [R_RISCV_RELAX] = { apply_r_riscv_relax_rela }, 584*8fd6c514SCharlie Jenkins [R_RISCV_SUB6] = { apply_r_riscv_sub6_rela, apply_6_bit_accumulation }, 585*8fd6c514SCharlie Jenkins [R_RISCV_SET6] = { apply_r_riscv_set6_rela, apply_6_bit_accumulation }, 586*8fd6c514SCharlie Jenkins [R_RISCV_SET8] = { apply_r_riscv_set8_rela, apply_8_bit_accumulation }, 587*8fd6c514SCharlie Jenkins [R_RISCV_SET16] = { apply_r_riscv_set16_rela, 588*8fd6c514SCharlie Jenkins apply_16_bit_accumulation }, 589*8fd6c514SCharlie Jenkins [R_RISCV_SET32] = { apply_r_riscv_set32_rela, 590*8fd6c514SCharlie Jenkins apply_32_bit_accumulation }, 591*8fd6c514SCharlie Jenkins [R_RISCV_32_PCREL] = { apply_r_riscv_32_pcrel_rela }, 592*8fd6c514SCharlie Jenkins [R_RISCV_IRELATIVE] = { dynamic_linking_not_supported }, 593*8fd6c514SCharlie Jenkins [R_RISCV_PLT32] = { apply_r_riscv_plt32_rela }, 594*8fd6c514SCharlie Jenkins [R_RISCV_SET_ULEB128] = { apply_r_riscv_set_uleb128, 595*8fd6c514SCharlie Jenkins apply_uleb128_accumulation }, 596*8fd6c514SCharlie Jenkins [R_RISCV_SUB_ULEB128] = { apply_r_riscv_sub_uleb128, 597*8fd6c514SCharlie Jenkins apply_uleb128_accumulation }, 598*8fd6c514SCharlie Jenkins /* 62-191 reserved for future standard use */ 599*8fd6c514SCharlie Jenkins /* 192-255 nonstandard ABI extensions */ 600e2c0cdfbSPalmer Dabbelt }; 601e2c0cdfbSPalmer Dabbelt 602*8fd6c514SCharlie Jenkins void process_accumulated_relocations(struct module *me) 603*8fd6c514SCharlie Jenkins { 604*8fd6c514SCharlie Jenkins /* 605*8fd6c514SCharlie Jenkins * Only ADD/SUB/SET/ULEB128 should end up here. 606*8fd6c514SCharlie Jenkins * 607*8fd6c514SCharlie Jenkins * Each bucket may have more than one relocation location. All 608*8fd6c514SCharlie Jenkins * relocations for a location are stored in a list in a bucket. 609*8fd6c514SCharlie Jenkins * 610*8fd6c514SCharlie Jenkins * Relocations are applied to a temp variable before being stored to the 611*8fd6c514SCharlie Jenkins * provided location to check for overflow. This also allows ULEB128 to 612*8fd6c514SCharlie Jenkins * properly decide how many entries are needed before storing to 613*8fd6c514SCharlie Jenkins * location. The final value is stored into location using the handler 614*8fd6c514SCharlie Jenkins * for the last relocation to an address. 615*8fd6c514SCharlie Jenkins * 616*8fd6c514SCharlie Jenkins * Three layers of indexing: 617*8fd6c514SCharlie Jenkins * - Each of the buckets in use 618*8fd6c514SCharlie Jenkins * - Groups of relocations in each bucket by location address 619*8fd6c514SCharlie Jenkins * - Each relocation entry for a location address 620*8fd6c514SCharlie Jenkins */ 621*8fd6c514SCharlie Jenkins struct used_bucket *bucket_iter; 622*8fd6c514SCharlie Jenkins struct relocation_head *rel_head_iter; 623*8fd6c514SCharlie Jenkins struct relocation_entry *rel_entry_iter; 624*8fd6c514SCharlie Jenkins int curr_type; 625*8fd6c514SCharlie Jenkins void *location; 626*8fd6c514SCharlie Jenkins long buffer; 627*8fd6c514SCharlie Jenkins 628*8fd6c514SCharlie Jenkins list_for_each_entry(bucket_iter, &used_buckets_list, head) { 629*8fd6c514SCharlie Jenkins hlist_for_each_entry(rel_head_iter, bucket_iter->bucket, node) { 630*8fd6c514SCharlie Jenkins buffer = 0; 631*8fd6c514SCharlie Jenkins location = rel_head_iter->location; 632*8fd6c514SCharlie Jenkins list_for_each_entry(rel_entry_iter, 633*8fd6c514SCharlie Jenkins rel_head_iter->rel_entry, head) { 634*8fd6c514SCharlie Jenkins curr_type = rel_entry_iter->type; 635*8fd6c514SCharlie Jenkins reloc_handlers[curr_type].reloc_handler( 636*8fd6c514SCharlie Jenkins me, &buffer, rel_entry_iter->value); 637*8fd6c514SCharlie Jenkins kfree(rel_entry_iter); 638*8fd6c514SCharlie Jenkins } 639*8fd6c514SCharlie Jenkins reloc_handlers[curr_type].accumulate_handler( 640*8fd6c514SCharlie Jenkins me, location, buffer); 641*8fd6c514SCharlie Jenkins kfree(rel_head_iter); 642*8fd6c514SCharlie Jenkins } 643*8fd6c514SCharlie Jenkins kfree(bucket_iter); 644*8fd6c514SCharlie Jenkins } 645*8fd6c514SCharlie Jenkins 646*8fd6c514SCharlie Jenkins kfree(relocation_hashtable); 647*8fd6c514SCharlie Jenkins } 648*8fd6c514SCharlie Jenkins 649*8fd6c514SCharlie Jenkins int add_relocation_to_accumulate(struct module *me, int type, void *location, 650*8fd6c514SCharlie Jenkins unsigned int hashtable_bits, Elf_Addr v) 651*8fd6c514SCharlie Jenkins { 652*8fd6c514SCharlie Jenkins struct relocation_entry *entry; 653*8fd6c514SCharlie Jenkins struct relocation_head *rel_head; 654*8fd6c514SCharlie Jenkins struct hlist_head *current_head; 655*8fd6c514SCharlie Jenkins struct used_bucket *bucket; 656*8fd6c514SCharlie Jenkins unsigned long hash; 657*8fd6c514SCharlie Jenkins 658*8fd6c514SCharlie Jenkins entry = kmalloc(sizeof(*entry), GFP_KERNEL); 659*8fd6c514SCharlie Jenkins INIT_LIST_HEAD(&entry->head); 660*8fd6c514SCharlie Jenkins entry->type = type; 661*8fd6c514SCharlie Jenkins entry->value = v; 662*8fd6c514SCharlie Jenkins 663*8fd6c514SCharlie Jenkins hash = hash_min((uintptr_t)location, hashtable_bits); 664*8fd6c514SCharlie Jenkins 665*8fd6c514SCharlie Jenkins current_head = &relocation_hashtable[hash]; 666*8fd6c514SCharlie Jenkins 667*8fd6c514SCharlie Jenkins /* Find matching location (if any) */ 668*8fd6c514SCharlie Jenkins bool found = false; 669*8fd6c514SCharlie Jenkins struct relocation_head *rel_head_iter; 670*8fd6c514SCharlie Jenkins 671*8fd6c514SCharlie Jenkins hlist_for_each_entry(rel_head_iter, current_head, node) { 672*8fd6c514SCharlie Jenkins if (rel_head_iter->location == location) { 673*8fd6c514SCharlie Jenkins found = true; 674*8fd6c514SCharlie Jenkins rel_head = rel_head_iter; 675*8fd6c514SCharlie Jenkins break; 676*8fd6c514SCharlie Jenkins } 677*8fd6c514SCharlie Jenkins } 678*8fd6c514SCharlie Jenkins 679*8fd6c514SCharlie Jenkins if (!found) { 680*8fd6c514SCharlie Jenkins rel_head = kmalloc(sizeof(*rel_head), GFP_KERNEL); 681*8fd6c514SCharlie Jenkins rel_head->rel_entry = 682*8fd6c514SCharlie Jenkins kmalloc(sizeof(struct list_head), GFP_KERNEL); 683*8fd6c514SCharlie Jenkins INIT_LIST_HEAD(rel_head->rel_entry); 684*8fd6c514SCharlie Jenkins rel_head->location = location; 685*8fd6c514SCharlie Jenkins INIT_HLIST_NODE(&rel_head->node); 686*8fd6c514SCharlie Jenkins if (!current_head->first) { 687*8fd6c514SCharlie Jenkins bucket = 688*8fd6c514SCharlie Jenkins kmalloc(sizeof(struct used_bucket), GFP_KERNEL); 689*8fd6c514SCharlie Jenkins INIT_LIST_HEAD(&bucket->head); 690*8fd6c514SCharlie Jenkins bucket->bucket = current_head; 691*8fd6c514SCharlie Jenkins list_add(&bucket->head, &used_buckets_list); 692*8fd6c514SCharlie Jenkins } 693*8fd6c514SCharlie Jenkins hlist_add_head(&rel_head->node, current_head); 694*8fd6c514SCharlie Jenkins } 695*8fd6c514SCharlie Jenkins 696*8fd6c514SCharlie Jenkins /* Add relocation to head of discovered rel_head */ 697*8fd6c514SCharlie Jenkins list_add_tail(&entry->head, rel_head->rel_entry); 698*8fd6c514SCharlie Jenkins 699*8fd6c514SCharlie Jenkins return 0; 700*8fd6c514SCharlie Jenkins } 701*8fd6c514SCharlie Jenkins 702*8fd6c514SCharlie Jenkins unsigned int initialize_relocation_hashtable(unsigned int num_relocations) 703*8fd6c514SCharlie Jenkins { 704*8fd6c514SCharlie Jenkins /* Can safely assume that bits is not greater than sizeof(long) */ 705*8fd6c514SCharlie Jenkins unsigned long hashtable_size = roundup_pow_of_two(num_relocations); 706*8fd6c514SCharlie Jenkins unsigned int hashtable_bits = ilog2(hashtable_size); 707*8fd6c514SCharlie Jenkins 708*8fd6c514SCharlie Jenkins /* 709*8fd6c514SCharlie Jenkins * Double size of hashtable if num_relocations * 1.25 is greater than 710*8fd6c514SCharlie Jenkins * hashtable_size. 711*8fd6c514SCharlie Jenkins */ 712*8fd6c514SCharlie Jenkins int should_double_size = ((num_relocations + (num_relocations >> 2)) > (hashtable_size)); 713*8fd6c514SCharlie Jenkins 714*8fd6c514SCharlie Jenkins hashtable_bits += should_double_size; 715*8fd6c514SCharlie Jenkins 716*8fd6c514SCharlie Jenkins hashtable_size <<= should_double_size; 717*8fd6c514SCharlie Jenkins 718*8fd6c514SCharlie Jenkins relocation_hashtable = kmalloc_array(hashtable_size, 719*8fd6c514SCharlie Jenkins sizeof(*relocation_hashtable), 720*8fd6c514SCharlie Jenkins GFP_KERNEL); 721*8fd6c514SCharlie Jenkins __hash_init(relocation_hashtable, hashtable_size); 722*8fd6c514SCharlie Jenkins 723*8fd6c514SCharlie Jenkins INIT_LIST_HEAD(&used_buckets_list); 724*8fd6c514SCharlie Jenkins 725*8fd6c514SCharlie Jenkins return hashtable_bits; 726*8fd6c514SCharlie Jenkins } 727*8fd6c514SCharlie Jenkins 728e2c0cdfbSPalmer Dabbelt int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, 729e2c0cdfbSPalmer Dabbelt unsigned int symindex, unsigned int relsec, 730e2c0cdfbSPalmer Dabbelt struct module *me) 731e2c0cdfbSPalmer Dabbelt { 732e2c0cdfbSPalmer Dabbelt Elf_Rela *rel = (void *) sechdrs[relsec].sh_addr; 7338cbe0accSEmil Renner Berthing int (*handler)(struct module *me, void *location, Elf_Addr v); 734e2c0cdfbSPalmer Dabbelt Elf_Sym *sym; 7358cbe0accSEmil Renner Berthing void *location; 736e2c0cdfbSPalmer Dabbelt unsigned int i, type; 737e2c0cdfbSPalmer Dabbelt Elf_Addr v; 738e2c0cdfbSPalmer Dabbelt int res; 739*8fd6c514SCharlie Jenkins unsigned int num_relocations = sechdrs[relsec].sh_size / sizeof(*rel); 740*8fd6c514SCharlie Jenkins unsigned int hashtable_bits = initialize_relocation_hashtable(num_relocations); 741e2c0cdfbSPalmer Dabbelt 742e2c0cdfbSPalmer Dabbelt pr_debug("Applying relocate section %u to %u\n", relsec, 743e2c0cdfbSPalmer Dabbelt sechdrs[relsec].sh_info); 744e2c0cdfbSPalmer Dabbelt 745*8fd6c514SCharlie Jenkins for (i = 0; i < num_relocations; i++) { 746e2c0cdfbSPalmer Dabbelt /* This is where to make the change */ 747e2c0cdfbSPalmer Dabbelt location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr 748e2c0cdfbSPalmer Dabbelt + rel[i].r_offset; 749e2c0cdfbSPalmer Dabbelt /* This is the symbol it is referring to */ 750e2c0cdfbSPalmer Dabbelt sym = (Elf_Sym *)sechdrs[symindex].sh_addr 751e2c0cdfbSPalmer Dabbelt + ELF_RISCV_R_SYM(rel[i].r_info); 752e2c0cdfbSPalmer Dabbelt if (IS_ERR_VALUE(sym->st_value)) { 753e2c0cdfbSPalmer Dabbelt /* Ignore unresolved weak symbol */ 754e2c0cdfbSPalmer Dabbelt if (ELF_ST_BIND(sym->st_info) == STB_WEAK) 755e2c0cdfbSPalmer Dabbelt continue; 75604ce8d3fSKefeng Wang pr_warn("%s: Unknown symbol %s\n", 757e2c0cdfbSPalmer Dabbelt me->name, strtab + sym->st_name); 758e2c0cdfbSPalmer Dabbelt return -ENOENT; 759e2c0cdfbSPalmer Dabbelt } 760e2c0cdfbSPalmer Dabbelt 761e2c0cdfbSPalmer Dabbelt type = ELF_RISCV_R_TYPE(rel[i].r_info); 762e2c0cdfbSPalmer Dabbelt 763*8fd6c514SCharlie Jenkins if (type < ARRAY_SIZE(reloc_handlers)) 764*8fd6c514SCharlie Jenkins handler = reloc_handlers[type].reloc_handler; 765e2c0cdfbSPalmer Dabbelt else 766e2c0cdfbSPalmer Dabbelt handler = NULL; 767e2c0cdfbSPalmer Dabbelt 768e2c0cdfbSPalmer Dabbelt if (!handler) { 769e2c0cdfbSPalmer Dabbelt pr_err("%s: Unknown relocation type %u\n", 770e2c0cdfbSPalmer Dabbelt me->name, type); 771e2c0cdfbSPalmer Dabbelt return -EINVAL; 772e2c0cdfbSPalmer Dabbelt } 773e2c0cdfbSPalmer Dabbelt 774e2c0cdfbSPalmer Dabbelt v = sym->st_value + rel[i].r_addend; 775e2c0cdfbSPalmer Dabbelt 776e2c0cdfbSPalmer Dabbelt if (type == R_RISCV_PCREL_LO12_I || type == R_RISCV_PCREL_LO12_S) { 777e2c0cdfbSPalmer Dabbelt unsigned int j; 778e2c0cdfbSPalmer Dabbelt 779e2c0cdfbSPalmer Dabbelt for (j = 0; j < sechdrs[relsec].sh_size / sizeof(*rel); j++) { 7807df85002SZong Li unsigned long hi20_loc = 781e2c0cdfbSPalmer Dabbelt sechdrs[sechdrs[relsec].sh_info].sh_addr 782e2c0cdfbSPalmer Dabbelt + rel[j].r_offset; 783da975dd4SZong Li u32 hi20_type = ELF_RISCV_R_TYPE(rel[j].r_info); 784da975dd4SZong Li 785da975dd4SZong Li /* Find the corresponding HI20 relocation entry */ 786da975dd4SZong Li if (hi20_loc == sym->st_value 787da975dd4SZong Li && (hi20_type == R_RISCV_PCREL_HI20 788da975dd4SZong Li || hi20_type == R_RISCV_GOT_HI20)) { 789da975dd4SZong Li s32 hi20, lo12; 790e2c0cdfbSPalmer Dabbelt Elf_Sym *hi20_sym = 791e2c0cdfbSPalmer Dabbelt (Elf_Sym *)sechdrs[symindex].sh_addr 792e2c0cdfbSPalmer Dabbelt + ELF_RISCV_R_SYM(rel[j].r_info); 7937df85002SZong Li unsigned long hi20_sym_val = 794e2c0cdfbSPalmer Dabbelt hi20_sym->st_value 795e2c0cdfbSPalmer Dabbelt + rel[j].r_addend; 796da975dd4SZong Li 797e2c0cdfbSPalmer Dabbelt /* Calculate lo12 */ 7987df85002SZong Li size_t offset = hi20_sym_val - hi20_loc; 799da975dd4SZong Li if (IS_ENABLED(CONFIG_MODULE_SECTIONS) 800da975dd4SZong Li && hi20_type == R_RISCV_GOT_HI20) { 801da975dd4SZong Li offset = module_emit_got_entry( 802da975dd4SZong Li me, hi20_sym_val); 803da975dd4SZong Li offset = offset - hi20_loc; 804da975dd4SZong Li } 805da975dd4SZong Li hi20 = (offset + 0x800) & 0xfffff000; 806da975dd4SZong Li lo12 = offset - hi20; 807e2c0cdfbSPalmer Dabbelt v = lo12; 808da975dd4SZong Li 809e2c0cdfbSPalmer Dabbelt break; 810e2c0cdfbSPalmer Dabbelt } 811e2c0cdfbSPalmer Dabbelt } 812e2c0cdfbSPalmer Dabbelt if (j == sechdrs[relsec].sh_size / sizeof(*rel)) { 813e2c0cdfbSPalmer Dabbelt pr_err( 814da975dd4SZong Li "%s: Can not find HI20 relocation information\n", 815e2c0cdfbSPalmer Dabbelt me->name); 816e2c0cdfbSPalmer Dabbelt return -EINVAL; 817e2c0cdfbSPalmer Dabbelt } 818e2c0cdfbSPalmer Dabbelt } 819e2c0cdfbSPalmer Dabbelt 820*8fd6c514SCharlie Jenkins if (reloc_handlers[type].accumulate_handler) 821*8fd6c514SCharlie Jenkins res = add_relocation_to_accumulate(me, type, location, hashtable_bits, v); 822*8fd6c514SCharlie Jenkins else 823e2c0cdfbSPalmer Dabbelt res = handler(me, location, v); 824e2c0cdfbSPalmer Dabbelt if (res) 825e2c0cdfbSPalmer Dabbelt return res; 826e2c0cdfbSPalmer Dabbelt } 827e2c0cdfbSPalmer Dabbelt 828*8fd6c514SCharlie Jenkins process_accumulated_relocations(me); 829*8fd6c514SCharlie Jenkins 830e2c0cdfbSPalmer Dabbelt return 0; 831e2c0cdfbSPalmer Dabbelt } 8320cff8bffSVincent Chen 8330cff8bffSVincent Chen #if defined(CONFIG_MMU) && defined(CONFIG_64BIT) 8340cff8bffSVincent Chen void *module_alloc(unsigned long size) 8350cff8bffSVincent Chen { 8362bfc6cd8SAlexandre Ghiti return __vmalloc_node_range(size, 1, MODULES_VADDR, 8372bfc6cd8SAlexandre Ghiti MODULES_END, GFP_KERNEL, 8385387054bSJisheng Zhang PAGE_KERNEL, 0, NUMA_NO_NODE, 8390cff8bffSVincent Chen __builtin_return_address(0)); 8400cff8bffSVincent Chen } 8410cff8bffSVincent Chen #endif 842a8e91016SHeiko Stuebner 843a8e91016SHeiko Stuebner int module_finalize(const Elf_Ehdr *hdr, 844a8e91016SHeiko Stuebner const Elf_Shdr *sechdrs, 845a8e91016SHeiko Stuebner struct module *me) 846a8e91016SHeiko Stuebner { 847a8e91016SHeiko Stuebner const Elf_Shdr *s; 848a8e91016SHeiko Stuebner 849a8e91016SHeiko Stuebner s = find_section(hdr, sechdrs, ".alternative"); 850a8e91016SHeiko Stuebner if (s) 851a8e91016SHeiko Stuebner apply_module_alternatives((void *)s->sh_addr, s->sh_size); 852a8e91016SHeiko Stuebner 853a8e91016SHeiko Stuebner return 0; 854a8e91016SHeiko Stuebner } 855