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> 108fd6c514SCharlie Jenkins #include <linux/hashtable.h> 118fd6c514SCharlie Jenkins #include <linux/kernel.h> 128fd6c514SCharlie 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 208fd6c514SCharlie Jenkins struct used_bucket { 218fd6c514SCharlie Jenkins struct list_head head; 228fd6c514SCharlie Jenkins struct hlist_head *bucket; 238fd6c514SCharlie Jenkins }; 248fd6c514SCharlie Jenkins 258fd6c514SCharlie Jenkins struct relocation_head { 268fd6c514SCharlie Jenkins struct hlist_node node; 278fd6c514SCharlie Jenkins struct list_head *rel_entry; 288fd6c514SCharlie Jenkins void *location; 298fd6c514SCharlie Jenkins }; 308fd6c514SCharlie Jenkins 318fd6c514SCharlie Jenkins struct relocation_entry { 328fd6c514SCharlie Jenkins struct list_head head; 338fd6c514SCharlie Jenkins Elf_Addr value; 348fd6c514SCharlie Jenkins unsigned int type; 358fd6c514SCharlie Jenkins }; 368fd6c514SCharlie Jenkins 378fd6c514SCharlie Jenkins struct relocation_handlers { 388fd6c514SCharlie Jenkins int (*reloc_handler)(struct module *me, void *location, Elf_Addr v); 398fd6c514SCharlie Jenkins int (*accumulate_handler)(struct module *me, void *location, 408fd6c514SCharlie Jenkins long buffer); 418fd6c514SCharlie Jenkins }; 428fd6c514SCharlie Jenkins 438fd6c514SCharlie Jenkins unsigned int initialize_relocation_hashtable(unsigned int num_relocations); 448fd6c514SCharlie Jenkins void process_accumulated_relocations(struct module *me); 458fd6c514SCharlie Jenkins int add_relocation_to_accumulate(struct module *me, int type, void *location, 468fd6c514SCharlie Jenkins unsigned int hashtable_bits, Elf_Addr v); 478fd6c514SCharlie Jenkins 488fd6c514SCharlie Jenkins struct hlist_head *relocation_hashtable; 498fd6c514SCharlie Jenkins 508fd6c514SCharlie Jenkins struct list_head used_buckets_list; 518fd6c514SCharlie 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 3118fd6c514SCharlie Jenkins static int apply_r_riscv_add8_rela(struct module *me, void *location, Elf_Addr v) 3128fd6c514SCharlie Jenkins { 3138fd6c514SCharlie Jenkins *(u8 *)location += (u8)v; 3148fd6c514SCharlie Jenkins return 0; 3158fd6c514SCharlie Jenkins } 3168fd6c514SCharlie 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 3388fd6c514SCharlie Jenkins static int apply_r_riscv_sub8_rela(struct module *me, void *location, Elf_Addr v) 3398fd6c514SCharlie Jenkins { 3408fd6c514SCharlie Jenkins *(u8 *)location -= (u8)v; 3418fd6c514SCharlie Jenkins return 0; 3428fd6c514SCharlie Jenkins } 3438fd6c514SCharlie 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 3658fd6c514SCharlie Jenkins static int dynamic_linking_not_supported(struct module *me, void *location, 3668fd6c514SCharlie Jenkins Elf_Addr v) 3678fd6c514SCharlie Jenkins { 3688fd6c514SCharlie Jenkins pr_err("%s: Dynamic linking not supported in kernel modules PC = %p\n", 3698fd6c514SCharlie Jenkins me->name, location); 3708fd6c514SCharlie Jenkins return -EINVAL; 3718fd6c514SCharlie Jenkins } 3728fd6c514SCharlie Jenkins 3738fd6c514SCharlie Jenkins static int tls_not_supported(struct module *me, void *location, Elf_Addr v) 3748fd6c514SCharlie Jenkins { 3758fd6c514SCharlie Jenkins pr_err("%s: Thread local storage not supported in kernel modules PC = %p\n", 3768fd6c514SCharlie Jenkins me->name, location); 3778fd6c514SCharlie Jenkins return -EINVAL; 3788fd6c514SCharlie Jenkins } 3798fd6c514SCharlie Jenkins 3808fd6c514SCharlie Jenkins static int apply_r_riscv_sub6_rela(struct module *me, void *location, Elf_Addr v) 3818fd6c514SCharlie Jenkins { 3828fd6c514SCharlie Jenkins u8 *byte = location; 3838fd6c514SCharlie Jenkins u8 value = v; 3848fd6c514SCharlie Jenkins 3858fd6c514SCharlie Jenkins *byte = (*byte - (value & 0x3f)) & 0x3f; 3868fd6c514SCharlie Jenkins return 0; 3878fd6c514SCharlie Jenkins } 3888fd6c514SCharlie Jenkins 3898fd6c514SCharlie Jenkins static int apply_r_riscv_set6_rela(struct module *me, void *location, Elf_Addr v) 3908fd6c514SCharlie Jenkins { 3918fd6c514SCharlie Jenkins u8 *byte = location; 3928fd6c514SCharlie Jenkins u8 value = v; 3938fd6c514SCharlie Jenkins 3948fd6c514SCharlie Jenkins *byte = (*byte & 0xc0) | (value & 0x3f); 3958fd6c514SCharlie Jenkins return 0; 3968fd6c514SCharlie Jenkins } 3978fd6c514SCharlie Jenkins 3988fd6c514SCharlie Jenkins static int apply_r_riscv_set8_rela(struct module *me, void *location, Elf_Addr v) 3998fd6c514SCharlie Jenkins { 4008fd6c514SCharlie Jenkins *(u8 *)location = (u8)v; 4018fd6c514SCharlie Jenkins return 0; 4028fd6c514SCharlie Jenkins } 4038fd6c514SCharlie Jenkins 4048fd6c514SCharlie Jenkins static int apply_r_riscv_set16_rela(struct module *me, void *location, 4058fd6c514SCharlie Jenkins Elf_Addr v) 4068fd6c514SCharlie Jenkins { 4078fd6c514SCharlie Jenkins *(u16 *)location = (u16)v; 4088fd6c514SCharlie Jenkins return 0; 4098fd6c514SCharlie Jenkins } 4108fd6c514SCharlie Jenkins 4118fd6c514SCharlie Jenkins static int apply_r_riscv_set32_rela(struct module *me, void *location, 4128fd6c514SCharlie Jenkins Elf_Addr v) 4138fd6c514SCharlie Jenkins { 4148fd6c514SCharlie Jenkins *(u32 *)location = (u32)v; 4158fd6c514SCharlie Jenkins return 0; 4168fd6c514SCharlie Jenkins } 4178fd6c514SCharlie Jenkins 4188fd6c514SCharlie Jenkins static int apply_r_riscv_32_pcrel_rela(struct module *me, void *location, 4198fd6c514SCharlie Jenkins Elf_Addr v) 4208fd6c514SCharlie Jenkins { 4218fd6c514SCharlie Jenkins *(u32 *)location = v - (uintptr_t)location; 4228fd6c514SCharlie Jenkins return 0; 4238fd6c514SCharlie Jenkins } 4248fd6c514SCharlie Jenkins 4258fd6c514SCharlie Jenkins static int apply_r_riscv_plt32_rela(struct module *me, void *location, 4268fd6c514SCharlie Jenkins Elf_Addr v) 4278fd6c514SCharlie Jenkins { 4288fd6c514SCharlie Jenkins ptrdiff_t offset = (void *)v - location; 4298fd6c514SCharlie Jenkins 4308fd6c514SCharlie Jenkins if (!riscv_insn_valid_32bit_offset(offset)) { 4318fd6c514SCharlie Jenkins /* Only emit the plt entry if offset over 32-bit range */ 4328fd6c514SCharlie Jenkins if (IS_ENABLED(CONFIG_MODULE_SECTIONS)) { 4338fd6c514SCharlie Jenkins offset = (void *)module_emit_plt_entry(me, v) - location; 4348fd6c514SCharlie Jenkins } else { 4358fd6c514SCharlie Jenkins pr_err("%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n", 4368fd6c514SCharlie Jenkins me->name, (long long)v, location); 4378fd6c514SCharlie Jenkins return -EINVAL; 4388fd6c514SCharlie Jenkins } 4398fd6c514SCharlie Jenkins } 4408fd6c514SCharlie Jenkins 4418fd6c514SCharlie Jenkins *(u32 *)location = (u32)offset; 4428fd6c514SCharlie Jenkins return 0; 4438fd6c514SCharlie Jenkins } 4448fd6c514SCharlie Jenkins 4458fd6c514SCharlie Jenkins static int apply_r_riscv_set_uleb128(struct module *me, void *location, Elf_Addr v) 4468fd6c514SCharlie Jenkins { 4478fd6c514SCharlie Jenkins *(long *)location = v; 4488fd6c514SCharlie Jenkins return 0; 4498fd6c514SCharlie Jenkins } 4508fd6c514SCharlie Jenkins 4518fd6c514SCharlie Jenkins static int apply_r_riscv_sub_uleb128(struct module *me, void *location, Elf_Addr v) 4528fd6c514SCharlie Jenkins { 4538fd6c514SCharlie Jenkins *(long *)location -= v; 4548fd6c514SCharlie Jenkins return 0; 4558fd6c514SCharlie Jenkins } 4568fd6c514SCharlie Jenkins 4578fd6c514SCharlie Jenkins static int apply_6_bit_accumulation(struct module *me, void *location, long buffer) 4588fd6c514SCharlie Jenkins { 4598fd6c514SCharlie Jenkins u8 *byte = location; 4608fd6c514SCharlie Jenkins u8 value = buffer; 4618fd6c514SCharlie Jenkins 4628fd6c514SCharlie Jenkins if (buffer > 0x3f) { 4638fd6c514SCharlie Jenkins pr_err("%s: value %ld out of range for 6-bit relocation.\n", 4648fd6c514SCharlie Jenkins me->name, buffer); 4658fd6c514SCharlie Jenkins return -EINVAL; 4668fd6c514SCharlie Jenkins } 4678fd6c514SCharlie Jenkins 4688fd6c514SCharlie Jenkins *byte = (*byte & 0xc0) | (value & 0x3f); 4698fd6c514SCharlie Jenkins return 0; 4708fd6c514SCharlie Jenkins } 4718fd6c514SCharlie Jenkins 4728fd6c514SCharlie Jenkins static int apply_8_bit_accumulation(struct module *me, void *location, long buffer) 4738fd6c514SCharlie Jenkins { 4748fd6c514SCharlie Jenkins if (buffer > U8_MAX) { 4758fd6c514SCharlie Jenkins pr_err("%s: value %ld out of range for 8-bit relocation.\n", 4768fd6c514SCharlie Jenkins me->name, buffer); 4778fd6c514SCharlie Jenkins return -EINVAL; 4788fd6c514SCharlie Jenkins } 4798fd6c514SCharlie Jenkins *(u8 *)location = (u8)buffer; 4808fd6c514SCharlie Jenkins return 0; 4818fd6c514SCharlie Jenkins } 4828fd6c514SCharlie Jenkins 4838fd6c514SCharlie Jenkins static int apply_16_bit_accumulation(struct module *me, void *location, long buffer) 4848fd6c514SCharlie Jenkins { 4858fd6c514SCharlie Jenkins if (buffer > U16_MAX) { 4868fd6c514SCharlie Jenkins pr_err("%s: value %ld out of range for 16-bit relocation.\n", 4878fd6c514SCharlie Jenkins me->name, buffer); 4888fd6c514SCharlie Jenkins return -EINVAL; 4898fd6c514SCharlie Jenkins } 4908fd6c514SCharlie Jenkins *(u16 *)location = (u16)buffer; 4918fd6c514SCharlie Jenkins return 0; 4928fd6c514SCharlie Jenkins } 4938fd6c514SCharlie Jenkins 4948fd6c514SCharlie Jenkins static int apply_32_bit_accumulation(struct module *me, void *location, long buffer) 4958fd6c514SCharlie Jenkins { 4968fd6c514SCharlie Jenkins if (buffer > U32_MAX) { 4978fd6c514SCharlie Jenkins pr_err("%s: value %ld out of range for 32-bit relocation.\n", 4988fd6c514SCharlie Jenkins me->name, buffer); 4998fd6c514SCharlie Jenkins return -EINVAL; 5008fd6c514SCharlie Jenkins } 5018fd6c514SCharlie Jenkins *(u32 *)location = (u32)buffer; 5028fd6c514SCharlie Jenkins return 0; 5038fd6c514SCharlie Jenkins } 5048fd6c514SCharlie Jenkins 5058fd6c514SCharlie Jenkins static int apply_64_bit_accumulation(struct module *me, void *location, long buffer) 5068fd6c514SCharlie Jenkins { 5078fd6c514SCharlie Jenkins *(u64 *)location = (u64)buffer; 5088fd6c514SCharlie Jenkins return 0; 5098fd6c514SCharlie Jenkins } 5108fd6c514SCharlie Jenkins 5118fd6c514SCharlie Jenkins static int apply_uleb128_accumulation(struct module *me, void *location, long buffer) 5128fd6c514SCharlie Jenkins { 5138fd6c514SCharlie Jenkins /* 5148fd6c514SCharlie Jenkins * ULEB128 is a variable length encoding. Encode the buffer into 5158fd6c514SCharlie Jenkins * the ULEB128 data format. 5168fd6c514SCharlie Jenkins */ 5178fd6c514SCharlie Jenkins u8 *p = location; 5188fd6c514SCharlie Jenkins 5198fd6c514SCharlie Jenkins while (buffer != 0) { 5208fd6c514SCharlie Jenkins u8 value = buffer & 0x7f; 5218fd6c514SCharlie Jenkins 5228fd6c514SCharlie Jenkins buffer >>= 7; 5238fd6c514SCharlie Jenkins value |= (!!buffer) << 7; 5248fd6c514SCharlie Jenkins 5258fd6c514SCharlie Jenkins *p++ = value; 5268fd6c514SCharlie Jenkins } 5278fd6c514SCharlie Jenkins return 0; 5288fd6c514SCharlie Jenkins } 5298fd6c514SCharlie Jenkins 5308fd6c514SCharlie Jenkins /* 5318fd6c514SCharlie Jenkins * Relocations defined in the riscv-elf-psabi-doc. 5328fd6c514SCharlie Jenkins * This handles static linking only. 5338fd6c514SCharlie Jenkins */ 5348fd6c514SCharlie Jenkins static const struct relocation_handlers reloc_handlers[] = { 535*28ea54baSPalmer Dabbelt [R_RISCV_32] = { .reloc_handler = apply_r_riscv_32_rela }, 536*28ea54baSPalmer Dabbelt [R_RISCV_64] = { .reloc_handler = apply_r_riscv_64_rela }, 537*28ea54baSPalmer Dabbelt [R_RISCV_RELATIVE] = { .reloc_handler = dynamic_linking_not_supported }, 538*28ea54baSPalmer Dabbelt [R_RISCV_COPY] = { .reloc_handler = dynamic_linking_not_supported }, 539*28ea54baSPalmer Dabbelt [R_RISCV_JUMP_SLOT] = { .reloc_handler = dynamic_linking_not_supported }, 540*28ea54baSPalmer Dabbelt [R_RISCV_TLS_DTPMOD32] = { .reloc_handler = dynamic_linking_not_supported }, 541*28ea54baSPalmer Dabbelt [R_RISCV_TLS_DTPMOD64] = { .reloc_handler = dynamic_linking_not_supported }, 542*28ea54baSPalmer Dabbelt [R_RISCV_TLS_DTPREL32] = { .reloc_handler = dynamic_linking_not_supported }, 543*28ea54baSPalmer Dabbelt [R_RISCV_TLS_DTPREL64] = { .reloc_handler = dynamic_linking_not_supported }, 544*28ea54baSPalmer Dabbelt [R_RISCV_TLS_TPREL32] = { .reloc_handler = dynamic_linking_not_supported }, 545*28ea54baSPalmer Dabbelt [R_RISCV_TLS_TPREL64] = { .reloc_handler = dynamic_linking_not_supported }, 5468fd6c514SCharlie Jenkins /* 12-15 undefined */ 547*28ea54baSPalmer Dabbelt [R_RISCV_BRANCH] = { .reloc_handler = apply_r_riscv_branch_rela }, 548*28ea54baSPalmer Dabbelt [R_RISCV_JAL] = { .reloc_handler = apply_r_riscv_jal_rela }, 549*28ea54baSPalmer Dabbelt [R_RISCV_CALL] = { .reloc_handler = apply_r_riscv_call_rela }, 550*28ea54baSPalmer Dabbelt [R_RISCV_CALL_PLT] = { .reloc_handler = apply_r_riscv_call_plt_rela }, 551*28ea54baSPalmer Dabbelt [R_RISCV_GOT_HI20] = { .reloc_handler = apply_r_riscv_got_hi20_rela }, 552*28ea54baSPalmer Dabbelt [R_RISCV_TLS_GOT_HI20] = { .reloc_handler = tls_not_supported }, 553*28ea54baSPalmer Dabbelt [R_RISCV_TLS_GD_HI20] = { .reloc_handler = tls_not_supported }, 554*28ea54baSPalmer Dabbelt [R_RISCV_PCREL_HI20] = { .reloc_handler = apply_r_riscv_pcrel_hi20_rela }, 555*28ea54baSPalmer Dabbelt [R_RISCV_PCREL_LO12_I] = { .reloc_handler = apply_r_riscv_pcrel_lo12_i_rela }, 556*28ea54baSPalmer Dabbelt [R_RISCV_PCREL_LO12_S] = { .reloc_handler = apply_r_riscv_pcrel_lo12_s_rela }, 557*28ea54baSPalmer Dabbelt [R_RISCV_HI20] = { .reloc_handler = apply_r_riscv_hi20_rela }, 558*28ea54baSPalmer Dabbelt [R_RISCV_LO12_I] = { .reloc_handler = apply_r_riscv_lo12_i_rela }, 559*28ea54baSPalmer Dabbelt [R_RISCV_LO12_S] = { .reloc_handler = apply_r_riscv_lo12_s_rela }, 560*28ea54baSPalmer Dabbelt [R_RISCV_TPREL_HI20] = { .reloc_handler = tls_not_supported }, 561*28ea54baSPalmer Dabbelt [R_RISCV_TPREL_LO12_I] = { .reloc_handler = tls_not_supported }, 562*28ea54baSPalmer Dabbelt [R_RISCV_TPREL_LO12_S] = { .reloc_handler = tls_not_supported }, 563*28ea54baSPalmer Dabbelt [R_RISCV_TPREL_ADD] = { .reloc_handler = tls_not_supported }, 564*28ea54baSPalmer Dabbelt [R_RISCV_ADD8] = { .reloc_handler = apply_r_riscv_add8_rela, 565*28ea54baSPalmer Dabbelt .accumulate_handler = apply_8_bit_accumulation }, 566*28ea54baSPalmer Dabbelt [R_RISCV_ADD16] = { .reloc_handler = apply_r_riscv_add16_rela, 567*28ea54baSPalmer Dabbelt .accumulate_handler = apply_16_bit_accumulation }, 568*28ea54baSPalmer Dabbelt [R_RISCV_ADD32] = { .reloc_handler = apply_r_riscv_add32_rela, 569*28ea54baSPalmer Dabbelt .accumulate_handler = apply_32_bit_accumulation }, 570*28ea54baSPalmer Dabbelt [R_RISCV_ADD64] = { .reloc_handler = apply_r_riscv_add64_rela, 571*28ea54baSPalmer Dabbelt .accumulate_handler = apply_64_bit_accumulation }, 572*28ea54baSPalmer Dabbelt [R_RISCV_SUB8] = { .reloc_handler = apply_r_riscv_sub8_rela, 573*28ea54baSPalmer Dabbelt .accumulate_handler = apply_8_bit_accumulation }, 574*28ea54baSPalmer Dabbelt [R_RISCV_SUB16] = { .reloc_handler = apply_r_riscv_sub16_rela, 575*28ea54baSPalmer Dabbelt .accumulate_handler = apply_16_bit_accumulation }, 576*28ea54baSPalmer Dabbelt [R_RISCV_SUB32] = { .reloc_handler = apply_r_riscv_sub32_rela, 577*28ea54baSPalmer Dabbelt .accumulate_handler = apply_32_bit_accumulation }, 578*28ea54baSPalmer Dabbelt [R_RISCV_SUB64] = { .reloc_handler = apply_r_riscv_sub64_rela, 579*28ea54baSPalmer Dabbelt .accumulate_handler = apply_64_bit_accumulation }, 5808fd6c514SCharlie Jenkins /* 41-42 reserved for future standard use */ 581*28ea54baSPalmer Dabbelt [R_RISCV_ALIGN] = { .reloc_handler = apply_r_riscv_align_rela }, 582*28ea54baSPalmer Dabbelt [R_RISCV_RVC_BRANCH] = { .reloc_handler = apply_r_riscv_rvc_branch_rela }, 583*28ea54baSPalmer Dabbelt [R_RISCV_RVC_JUMP] = { .reloc_handler = apply_r_riscv_rvc_jump_rela }, 5848fd6c514SCharlie Jenkins /* 46-50 reserved for future standard use */ 585*28ea54baSPalmer Dabbelt [R_RISCV_RELAX] = { .reloc_handler = apply_r_riscv_relax_rela }, 586*28ea54baSPalmer Dabbelt [R_RISCV_SUB6] = { .reloc_handler = apply_r_riscv_sub6_rela, 587*28ea54baSPalmer Dabbelt .accumulate_handler = apply_6_bit_accumulation }, 588*28ea54baSPalmer Dabbelt [R_RISCV_SET6] = { .reloc_handler = apply_r_riscv_set6_rela, 589*28ea54baSPalmer Dabbelt .accumulate_handler = apply_6_bit_accumulation }, 590*28ea54baSPalmer Dabbelt [R_RISCV_SET8] = { .reloc_handler = apply_r_riscv_set8_rela, 591*28ea54baSPalmer Dabbelt .accumulate_handler = apply_8_bit_accumulation }, 592*28ea54baSPalmer Dabbelt [R_RISCV_SET16] = { .reloc_handler = apply_r_riscv_set16_rela, 593*28ea54baSPalmer Dabbelt .accumulate_handler = apply_16_bit_accumulation }, 594*28ea54baSPalmer Dabbelt [R_RISCV_SET32] = { .reloc_handler = apply_r_riscv_set32_rela, 595*28ea54baSPalmer Dabbelt .accumulate_handler = apply_32_bit_accumulation }, 596*28ea54baSPalmer Dabbelt [R_RISCV_32_PCREL] = { .reloc_handler = apply_r_riscv_32_pcrel_rela }, 597*28ea54baSPalmer Dabbelt [R_RISCV_IRELATIVE] = { .reloc_handler = dynamic_linking_not_supported }, 598*28ea54baSPalmer Dabbelt [R_RISCV_PLT32] = { .reloc_handler = apply_r_riscv_plt32_rela }, 599*28ea54baSPalmer Dabbelt [R_RISCV_SET_ULEB128] = { .reloc_handler = apply_r_riscv_set_uleb128, 600*28ea54baSPalmer Dabbelt .accumulate_handler = apply_uleb128_accumulation }, 601*28ea54baSPalmer Dabbelt [R_RISCV_SUB_ULEB128] = { .reloc_handler = apply_r_riscv_sub_uleb128, 602*28ea54baSPalmer Dabbelt .accumulate_handler = apply_uleb128_accumulation }, 6038fd6c514SCharlie Jenkins /* 62-191 reserved for future standard use */ 6048fd6c514SCharlie Jenkins /* 192-255 nonstandard ABI extensions */ 605e2c0cdfbSPalmer Dabbelt }; 606e2c0cdfbSPalmer Dabbelt 6078fd6c514SCharlie Jenkins void process_accumulated_relocations(struct module *me) 6088fd6c514SCharlie Jenkins { 6098fd6c514SCharlie Jenkins /* 6108fd6c514SCharlie Jenkins * Only ADD/SUB/SET/ULEB128 should end up here. 6118fd6c514SCharlie Jenkins * 6128fd6c514SCharlie Jenkins * Each bucket may have more than one relocation location. All 6138fd6c514SCharlie Jenkins * relocations for a location are stored in a list in a bucket. 6148fd6c514SCharlie Jenkins * 6158fd6c514SCharlie Jenkins * Relocations are applied to a temp variable before being stored to the 6168fd6c514SCharlie Jenkins * provided location to check for overflow. This also allows ULEB128 to 6178fd6c514SCharlie Jenkins * properly decide how many entries are needed before storing to 6188fd6c514SCharlie Jenkins * location. The final value is stored into location using the handler 6198fd6c514SCharlie Jenkins * for the last relocation to an address. 6208fd6c514SCharlie Jenkins * 6218fd6c514SCharlie Jenkins * Three layers of indexing: 6228fd6c514SCharlie Jenkins * - Each of the buckets in use 6238fd6c514SCharlie Jenkins * - Groups of relocations in each bucket by location address 6248fd6c514SCharlie Jenkins * - Each relocation entry for a location address 6258fd6c514SCharlie Jenkins */ 6268fd6c514SCharlie Jenkins struct used_bucket *bucket_iter; 6278fd6c514SCharlie Jenkins struct relocation_head *rel_head_iter; 6288fd6c514SCharlie Jenkins struct relocation_entry *rel_entry_iter; 6298fd6c514SCharlie Jenkins int curr_type; 6308fd6c514SCharlie Jenkins void *location; 6318fd6c514SCharlie Jenkins long buffer; 6328fd6c514SCharlie Jenkins 6338fd6c514SCharlie Jenkins list_for_each_entry(bucket_iter, &used_buckets_list, head) { 6348fd6c514SCharlie Jenkins hlist_for_each_entry(rel_head_iter, bucket_iter->bucket, node) { 6358fd6c514SCharlie Jenkins buffer = 0; 6368fd6c514SCharlie Jenkins location = rel_head_iter->location; 6378fd6c514SCharlie Jenkins list_for_each_entry(rel_entry_iter, 6388fd6c514SCharlie Jenkins rel_head_iter->rel_entry, head) { 6398fd6c514SCharlie Jenkins curr_type = rel_entry_iter->type; 6408fd6c514SCharlie Jenkins reloc_handlers[curr_type].reloc_handler( 6418fd6c514SCharlie Jenkins me, &buffer, rel_entry_iter->value); 6428fd6c514SCharlie Jenkins kfree(rel_entry_iter); 6438fd6c514SCharlie Jenkins } 6448fd6c514SCharlie Jenkins reloc_handlers[curr_type].accumulate_handler( 6458fd6c514SCharlie Jenkins me, location, buffer); 6468fd6c514SCharlie Jenkins kfree(rel_head_iter); 6478fd6c514SCharlie Jenkins } 6488fd6c514SCharlie Jenkins kfree(bucket_iter); 6498fd6c514SCharlie Jenkins } 6508fd6c514SCharlie Jenkins 6518fd6c514SCharlie Jenkins kfree(relocation_hashtable); 6528fd6c514SCharlie Jenkins } 6538fd6c514SCharlie Jenkins 6548fd6c514SCharlie Jenkins int add_relocation_to_accumulate(struct module *me, int type, void *location, 6558fd6c514SCharlie Jenkins unsigned int hashtable_bits, Elf_Addr v) 6568fd6c514SCharlie Jenkins { 6578fd6c514SCharlie Jenkins struct relocation_entry *entry; 6588fd6c514SCharlie Jenkins struct relocation_head *rel_head; 6598fd6c514SCharlie Jenkins struct hlist_head *current_head; 6608fd6c514SCharlie Jenkins struct used_bucket *bucket; 6618fd6c514SCharlie Jenkins unsigned long hash; 6628fd6c514SCharlie Jenkins 6638fd6c514SCharlie Jenkins entry = kmalloc(sizeof(*entry), GFP_KERNEL); 6648fd6c514SCharlie Jenkins INIT_LIST_HEAD(&entry->head); 6658fd6c514SCharlie Jenkins entry->type = type; 6668fd6c514SCharlie Jenkins entry->value = v; 6678fd6c514SCharlie Jenkins 6688fd6c514SCharlie Jenkins hash = hash_min((uintptr_t)location, hashtable_bits); 6698fd6c514SCharlie Jenkins 6708fd6c514SCharlie Jenkins current_head = &relocation_hashtable[hash]; 6718fd6c514SCharlie Jenkins 6728fd6c514SCharlie Jenkins /* Find matching location (if any) */ 6738fd6c514SCharlie Jenkins bool found = false; 6748fd6c514SCharlie Jenkins struct relocation_head *rel_head_iter; 6758fd6c514SCharlie Jenkins 6768fd6c514SCharlie Jenkins hlist_for_each_entry(rel_head_iter, current_head, node) { 6778fd6c514SCharlie Jenkins if (rel_head_iter->location == location) { 6788fd6c514SCharlie Jenkins found = true; 6798fd6c514SCharlie Jenkins rel_head = rel_head_iter; 6808fd6c514SCharlie Jenkins break; 6818fd6c514SCharlie Jenkins } 6828fd6c514SCharlie Jenkins } 6838fd6c514SCharlie Jenkins 6848fd6c514SCharlie Jenkins if (!found) { 6858fd6c514SCharlie Jenkins rel_head = kmalloc(sizeof(*rel_head), GFP_KERNEL); 6868fd6c514SCharlie Jenkins rel_head->rel_entry = 6878fd6c514SCharlie Jenkins kmalloc(sizeof(struct list_head), GFP_KERNEL); 6888fd6c514SCharlie Jenkins INIT_LIST_HEAD(rel_head->rel_entry); 6898fd6c514SCharlie Jenkins rel_head->location = location; 6908fd6c514SCharlie Jenkins INIT_HLIST_NODE(&rel_head->node); 6918fd6c514SCharlie Jenkins if (!current_head->first) { 6928fd6c514SCharlie Jenkins bucket = 6938fd6c514SCharlie Jenkins kmalloc(sizeof(struct used_bucket), GFP_KERNEL); 6948fd6c514SCharlie Jenkins INIT_LIST_HEAD(&bucket->head); 6958fd6c514SCharlie Jenkins bucket->bucket = current_head; 6968fd6c514SCharlie Jenkins list_add(&bucket->head, &used_buckets_list); 6978fd6c514SCharlie Jenkins } 6988fd6c514SCharlie Jenkins hlist_add_head(&rel_head->node, current_head); 6998fd6c514SCharlie Jenkins } 7008fd6c514SCharlie Jenkins 7018fd6c514SCharlie Jenkins /* Add relocation to head of discovered rel_head */ 7028fd6c514SCharlie Jenkins list_add_tail(&entry->head, rel_head->rel_entry); 7038fd6c514SCharlie Jenkins 7048fd6c514SCharlie Jenkins return 0; 7058fd6c514SCharlie Jenkins } 7068fd6c514SCharlie Jenkins 7078fd6c514SCharlie Jenkins unsigned int initialize_relocation_hashtable(unsigned int num_relocations) 7088fd6c514SCharlie Jenkins { 7098fd6c514SCharlie Jenkins /* Can safely assume that bits is not greater than sizeof(long) */ 7108fd6c514SCharlie Jenkins unsigned long hashtable_size = roundup_pow_of_two(num_relocations); 7118fd6c514SCharlie Jenkins unsigned int hashtable_bits = ilog2(hashtable_size); 7128fd6c514SCharlie Jenkins 7138fd6c514SCharlie Jenkins /* 7148fd6c514SCharlie Jenkins * Double size of hashtable if num_relocations * 1.25 is greater than 7158fd6c514SCharlie Jenkins * hashtable_size. 7168fd6c514SCharlie Jenkins */ 7178fd6c514SCharlie Jenkins int should_double_size = ((num_relocations + (num_relocations >> 2)) > (hashtable_size)); 7188fd6c514SCharlie Jenkins 7198fd6c514SCharlie Jenkins hashtable_bits += should_double_size; 7208fd6c514SCharlie Jenkins 7218fd6c514SCharlie Jenkins hashtable_size <<= should_double_size; 7228fd6c514SCharlie Jenkins 7238fd6c514SCharlie Jenkins relocation_hashtable = kmalloc_array(hashtable_size, 7248fd6c514SCharlie Jenkins sizeof(*relocation_hashtable), 7258fd6c514SCharlie Jenkins GFP_KERNEL); 7268fd6c514SCharlie Jenkins __hash_init(relocation_hashtable, hashtable_size); 7278fd6c514SCharlie Jenkins 7288fd6c514SCharlie Jenkins INIT_LIST_HEAD(&used_buckets_list); 7298fd6c514SCharlie Jenkins 7308fd6c514SCharlie Jenkins return hashtable_bits; 7318fd6c514SCharlie Jenkins } 7328fd6c514SCharlie Jenkins 733e2c0cdfbSPalmer Dabbelt int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, 734e2c0cdfbSPalmer Dabbelt unsigned int symindex, unsigned int relsec, 735e2c0cdfbSPalmer Dabbelt struct module *me) 736e2c0cdfbSPalmer Dabbelt { 737e2c0cdfbSPalmer Dabbelt Elf_Rela *rel = (void *) sechdrs[relsec].sh_addr; 7388cbe0accSEmil Renner Berthing int (*handler)(struct module *me, void *location, Elf_Addr v); 739e2c0cdfbSPalmer Dabbelt Elf_Sym *sym; 7408cbe0accSEmil Renner Berthing void *location; 741e2c0cdfbSPalmer Dabbelt unsigned int i, type; 742e2c0cdfbSPalmer Dabbelt Elf_Addr v; 743e2c0cdfbSPalmer Dabbelt int res; 7448fd6c514SCharlie Jenkins unsigned int num_relocations = sechdrs[relsec].sh_size / sizeof(*rel); 7458fd6c514SCharlie Jenkins unsigned int hashtable_bits = initialize_relocation_hashtable(num_relocations); 746e2c0cdfbSPalmer Dabbelt 747e2c0cdfbSPalmer Dabbelt pr_debug("Applying relocate section %u to %u\n", relsec, 748e2c0cdfbSPalmer Dabbelt sechdrs[relsec].sh_info); 749e2c0cdfbSPalmer Dabbelt 7508fd6c514SCharlie Jenkins for (i = 0; i < num_relocations; i++) { 751e2c0cdfbSPalmer Dabbelt /* This is where to make the change */ 752e2c0cdfbSPalmer Dabbelt location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr 753e2c0cdfbSPalmer Dabbelt + rel[i].r_offset; 754e2c0cdfbSPalmer Dabbelt /* This is the symbol it is referring to */ 755e2c0cdfbSPalmer Dabbelt sym = (Elf_Sym *)sechdrs[symindex].sh_addr 756e2c0cdfbSPalmer Dabbelt + ELF_RISCV_R_SYM(rel[i].r_info); 757e2c0cdfbSPalmer Dabbelt if (IS_ERR_VALUE(sym->st_value)) { 758e2c0cdfbSPalmer Dabbelt /* Ignore unresolved weak symbol */ 759e2c0cdfbSPalmer Dabbelt if (ELF_ST_BIND(sym->st_info) == STB_WEAK) 760e2c0cdfbSPalmer Dabbelt continue; 76104ce8d3fSKefeng Wang pr_warn("%s: Unknown symbol %s\n", 762e2c0cdfbSPalmer Dabbelt me->name, strtab + sym->st_name); 763e2c0cdfbSPalmer Dabbelt return -ENOENT; 764e2c0cdfbSPalmer Dabbelt } 765e2c0cdfbSPalmer Dabbelt 766e2c0cdfbSPalmer Dabbelt type = ELF_RISCV_R_TYPE(rel[i].r_info); 767e2c0cdfbSPalmer Dabbelt 7688fd6c514SCharlie Jenkins if (type < ARRAY_SIZE(reloc_handlers)) 7698fd6c514SCharlie Jenkins handler = reloc_handlers[type].reloc_handler; 770e2c0cdfbSPalmer Dabbelt else 771e2c0cdfbSPalmer Dabbelt handler = NULL; 772e2c0cdfbSPalmer Dabbelt 773e2c0cdfbSPalmer Dabbelt if (!handler) { 774e2c0cdfbSPalmer Dabbelt pr_err("%s: Unknown relocation type %u\n", 775e2c0cdfbSPalmer Dabbelt me->name, type); 776e2c0cdfbSPalmer Dabbelt return -EINVAL; 777e2c0cdfbSPalmer Dabbelt } 778e2c0cdfbSPalmer Dabbelt 779e2c0cdfbSPalmer Dabbelt v = sym->st_value + rel[i].r_addend; 780e2c0cdfbSPalmer Dabbelt 781e2c0cdfbSPalmer Dabbelt if (type == R_RISCV_PCREL_LO12_I || type == R_RISCV_PCREL_LO12_S) { 782e2c0cdfbSPalmer Dabbelt unsigned int j; 783e2c0cdfbSPalmer Dabbelt 784e2c0cdfbSPalmer Dabbelt for (j = 0; j < sechdrs[relsec].sh_size / sizeof(*rel); j++) { 7857df85002SZong Li unsigned long hi20_loc = 786e2c0cdfbSPalmer Dabbelt sechdrs[sechdrs[relsec].sh_info].sh_addr 787e2c0cdfbSPalmer Dabbelt + rel[j].r_offset; 788da975dd4SZong Li u32 hi20_type = ELF_RISCV_R_TYPE(rel[j].r_info); 789da975dd4SZong Li 790da975dd4SZong Li /* Find the corresponding HI20 relocation entry */ 791da975dd4SZong Li if (hi20_loc == sym->st_value 792da975dd4SZong Li && (hi20_type == R_RISCV_PCREL_HI20 793da975dd4SZong Li || hi20_type == R_RISCV_GOT_HI20)) { 794da975dd4SZong Li s32 hi20, lo12; 795e2c0cdfbSPalmer Dabbelt Elf_Sym *hi20_sym = 796e2c0cdfbSPalmer Dabbelt (Elf_Sym *)sechdrs[symindex].sh_addr 797e2c0cdfbSPalmer Dabbelt + ELF_RISCV_R_SYM(rel[j].r_info); 7987df85002SZong Li unsigned long hi20_sym_val = 799e2c0cdfbSPalmer Dabbelt hi20_sym->st_value 800e2c0cdfbSPalmer Dabbelt + rel[j].r_addend; 801da975dd4SZong Li 802e2c0cdfbSPalmer Dabbelt /* Calculate lo12 */ 8037df85002SZong Li size_t offset = hi20_sym_val - hi20_loc; 804da975dd4SZong Li if (IS_ENABLED(CONFIG_MODULE_SECTIONS) 805da975dd4SZong Li && hi20_type == R_RISCV_GOT_HI20) { 806da975dd4SZong Li offset = module_emit_got_entry( 807da975dd4SZong Li me, hi20_sym_val); 808da975dd4SZong Li offset = offset - hi20_loc; 809da975dd4SZong Li } 810da975dd4SZong Li hi20 = (offset + 0x800) & 0xfffff000; 811da975dd4SZong Li lo12 = offset - hi20; 812e2c0cdfbSPalmer Dabbelt v = lo12; 813da975dd4SZong Li 814e2c0cdfbSPalmer Dabbelt break; 815e2c0cdfbSPalmer Dabbelt } 816e2c0cdfbSPalmer Dabbelt } 817e2c0cdfbSPalmer Dabbelt if (j == sechdrs[relsec].sh_size / sizeof(*rel)) { 818e2c0cdfbSPalmer Dabbelt pr_err( 819da975dd4SZong Li "%s: Can not find HI20 relocation information\n", 820e2c0cdfbSPalmer Dabbelt me->name); 821e2c0cdfbSPalmer Dabbelt return -EINVAL; 822e2c0cdfbSPalmer Dabbelt } 823e2c0cdfbSPalmer Dabbelt } 824e2c0cdfbSPalmer Dabbelt 8258fd6c514SCharlie Jenkins if (reloc_handlers[type].accumulate_handler) 8268fd6c514SCharlie Jenkins res = add_relocation_to_accumulate(me, type, location, hashtable_bits, v); 8278fd6c514SCharlie Jenkins else 828e2c0cdfbSPalmer Dabbelt res = handler(me, location, v); 829e2c0cdfbSPalmer Dabbelt if (res) 830e2c0cdfbSPalmer Dabbelt return res; 831e2c0cdfbSPalmer Dabbelt } 832e2c0cdfbSPalmer Dabbelt 8338fd6c514SCharlie Jenkins process_accumulated_relocations(me); 8348fd6c514SCharlie Jenkins 835e2c0cdfbSPalmer Dabbelt return 0; 836e2c0cdfbSPalmer Dabbelt } 8370cff8bffSVincent Chen 8380cff8bffSVincent Chen #if defined(CONFIG_MMU) && defined(CONFIG_64BIT) 8390cff8bffSVincent Chen void *module_alloc(unsigned long size) 8400cff8bffSVincent Chen { 8412bfc6cd8SAlexandre Ghiti return __vmalloc_node_range(size, 1, MODULES_VADDR, 8422bfc6cd8SAlexandre Ghiti MODULES_END, GFP_KERNEL, 8435387054bSJisheng Zhang PAGE_KERNEL, 0, NUMA_NO_NODE, 8440cff8bffSVincent Chen __builtin_return_address(0)); 8450cff8bffSVincent Chen } 8460cff8bffSVincent Chen #endif 847a8e91016SHeiko Stuebner 848a8e91016SHeiko Stuebner int module_finalize(const Elf_Ehdr *hdr, 849a8e91016SHeiko Stuebner const Elf_Shdr *sechdrs, 850a8e91016SHeiko Stuebner struct module *me) 851a8e91016SHeiko Stuebner { 852a8e91016SHeiko Stuebner const Elf_Shdr *s; 853a8e91016SHeiko Stuebner 854a8e91016SHeiko Stuebner s = find_section(hdr, sechdrs, ".alternative"); 855a8e91016SHeiko Stuebner if (s) 856a8e91016SHeiko Stuebner apply_module_alternatives((void *)s->sh_addr, s->sh_size); 857a8e91016SHeiko Stuebner 858a8e91016SHeiko Stuebner return 0; 859a8e91016SHeiko Stuebner } 860