root/arch/riscv/kernel/module.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. apply_r_riscv_32_rela
  2. apply_r_riscv_64_rela
  3. apply_r_riscv_branch_rela
  4. apply_r_riscv_jal_rela
  5. apply_r_riscv_rcv_branch_rela
  6. apply_r_riscv_rvc_jump_rela
  7. apply_r_riscv_pcrel_hi20_rela
  8. apply_r_riscv_pcrel_lo12_i_rela
  9. apply_r_riscv_pcrel_lo12_s_rela
  10. apply_r_riscv_hi20_rela
  11. apply_r_riscv_lo12_i_rela
  12. apply_r_riscv_lo12_s_rela
  13. apply_r_riscv_got_hi20_rela
  14. apply_r_riscv_call_plt_rela
  15. apply_r_riscv_call_rela
  16. apply_r_riscv_relax_rela
  17. apply_r_riscv_align_rela
  18. apply_r_riscv_add32_rela
  19. apply_r_riscv_sub32_rela
  20. apply_relocate_add
  21. module_alloc

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *
   4  *  Copyright (C) 2017 Zihao Yu
   5  */
   6 
   7 #include <linux/elf.h>
   8 #include <linux/err.h>
   9 #include <linux/errno.h>
  10 #include <linux/moduleloader.h>
  11 #include <linux/vmalloc.h>
  12 #include <linux/sizes.h>
  13 #include <asm/pgtable.h>
  14 #include <asm/sections.h>
  15 
  16 static int apply_r_riscv_32_rela(struct module *me, u32 *location, Elf_Addr v)
  17 {
  18         if (v != (u32)v) {
  19                 pr_err("%s: value %016llx out of range for 32-bit field\n",
  20                        me->name, (long long)v);
  21                 return -EINVAL;
  22         }
  23         *location = v;
  24         return 0;
  25 }
  26 
  27 static int apply_r_riscv_64_rela(struct module *me, u32 *location, Elf_Addr v)
  28 {
  29         *(u64 *)location = v;
  30         return 0;
  31 }
  32 
  33 static int apply_r_riscv_branch_rela(struct module *me, u32 *location,
  34                                      Elf_Addr v)
  35 {
  36         ptrdiff_t offset = (void *)v - (void *)location;
  37         u32 imm12 = (offset & 0x1000) << (31 - 12);
  38         u32 imm11 = (offset & 0x800) >> (11 - 7);
  39         u32 imm10_5 = (offset & 0x7e0) << (30 - 10);
  40         u32 imm4_1 = (offset & 0x1e) << (11 - 4);
  41 
  42         *location = (*location & 0x1fff07f) | imm12 | imm11 | imm10_5 | imm4_1;
  43         return 0;
  44 }
  45 
  46 static int apply_r_riscv_jal_rela(struct module *me, u32 *location,
  47                                   Elf_Addr v)
  48 {
  49         ptrdiff_t offset = (void *)v - (void *)location;
  50         u32 imm20 = (offset & 0x100000) << (31 - 20);
  51         u32 imm19_12 = (offset & 0xff000);
  52         u32 imm11 = (offset & 0x800) << (20 - 11);
  53         u32 imm10_1 = (offset & 0x7fe) << (30 - 10);
  54 
  55         *location = (*location & 0xfff) | imm20 | imm19_12 | imm11 | imm10_1;
  56         return 0;
  57 }
  58 
  59 static int apply_r_riscv_rcv_branch_rela(struct module *me, u32 *location,
  60                                          Elf_Addr v)
  61 {
  62         ptrdiff_t offset = (void *)v - (void *)location;
  63         u16 imm8 = (offset & 0x100) << (12 - 8);
  64         u16 imm7_6 = (offset & 0xc0) >> (6 - 5);
  65         u16 imm5 = (offset & 0x20) >> (5 - 2);
  66         u16 imm4_3 = (offset & 0x18) << (12 - 5);
  67         u16 imm2_1 = (offset & 0x6) << (12 - 10);
  68 
  69         *(u16 *)location = (*(u16 *)location & 0xe383) |
  70                     imm8 | imm7_6 | imm5 | imm4_3 | imm2_1;
  71         return 0;
  72 }
  73 
  74 static int apply_r_riscv_rvc_jump_rela(struct module *me, u32 *location,
  75                                        Elf_Addr v)
  76 {
  77         ptrdiff_t offset = (void *)v - (void *)location;
  78         u16 imm11 = (offset & 0x800) << (12 - 11);
  79         u16 imm10 = (offset & 0x400) >> (10 - 8);
  80         u16 imm9_8 = (offset & 0x300) << (12 - 11);
  81         u16 imm7 = (offset & 0x80) >> (7 - 6);
  82         u16 imm6 = (offset & 0x40) << (12 - 11);
  83         u16 imm5 = (offset & 0x20) >> (5 - 2);
  84         u16 imm4 = (offset & 0x10) << (12 - 5);
  85         u16 imm3_1 = (offset & 0xe) << (12 - 10);
  86 
  87         *(u16 *)location = (*(u16 *)location & 0xe003) |
  88                     imm11 | imm10 | imm9_8 | imm7 | imm6 | imm5 | imm4 | imm3_1;
  89         return 0;
  90 }
  91 
  92 static int apply_r_riscv_pcrel_hi20_rela(struct module *me, u32 *location,
  93                                          Elf_Addr v)
  94 {
  95         ptrdiff_t offset = (void *)v - (void *)location;
  96         s32 hi20;
  97 
  98         if (offset != (s32)offset) {
  99                 pr_err(
 100                   "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n",
 101                   me->name, (long long)v, location);
 102                 return -EINVAL;
 103         }
 104 
 105         hi20 = (offset + 0x800) & 0xfffff000;
 106         *location = (*location & 0xfff) | hi20;
 107         return 0;
 108 }
 109 
 110 static int apply_r_riscv_pcrel_lo12_i_rela(struct module *me, u32 *location,
 111                                            Elf_Addr v)
 112 {
 113         /*
 114          * v is the lo12 value to fill. It is calculated before calling this
 115          * handler.
 116          */
 117         *location = (*location & 0xfffff) | ((v & 0xfff) << 20);
 118         return 0;
 119 }
 120 
 121 static int apply_r_riscv_pcrel_lo12_s_rela(struct module *me, u32 *location,
 122                                            Elf_Addr v)
 123 {
 124         /*
 125          * v is the lo12 value to fill. It is calculated before calling this
 126          * handler.
 127          */
 128         u32 imm11_5 = (v & 0xfe0) << (31 - 11);
 129         u32 imm4_0 = (v & 0x1f) << (11 - 4);
 130 
 131         *location = (*location & 0x1fff07f) | imm11_5 | imm4_0;
 132         return 0;
 133 }
 134 
 135 static int apply_r_riscv_hi20_rela(struct module *me, u32 *location,
 136                                    Elf_Addr v)
 137 {
 138         s32 hi20;
 139 
 140         if (IS_ENABLED(CONFIG_CMODEL_MEDLOW)) {
 141                 pr_err(
 142                   "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n",
 143                   me->name, (long long)v, location);
 144                 return -EINVAL;
 145         }
 146 
 147         hi20 = ((s32)v + 0x800) & 0xfffff000;
 148         *location = (*location & 0xfff) | hi20;
 149         return 0;
 150 }
 151 
 152 static int apply_r_riscv_lo12_i_rela(struct module *me, u32 *location,
 153                                      Elf_Addr v)
 154 {
 155         /* Skip medlow checking because of filtering by HI20 already */
 156         s32 hi20 = ((s32)v + 0x800) & 0xfffff000;
 157         s32 lo12 = ((s32)v - hi20);
 158         *location = (*location & 0xfffff) | ((lo12 & 0xfff) << 20);
 159         return 0;
 160 }
 161 
 162 static int apply_r_riscv_lo12_s_rela(struct module *me, u32 *location,
 163                                      Elf_Addr v)
 164 {
 165         /* Skip medlow checking because of filtering by HI20 already */
 166         s32 hi20 = ((s32)v + 0x800) & 0xfffff000;
 167         s32 lo12 = ((s32)v - hi20);
 168         u32 imm11_5 = (lo12 & 0xfe0) << (31 - 11);
 169         u32 imm4_0 = (lo12 & 0x1f) << (11 - 4);
 170         *location = (*location & 0x1fff07f) | imm11_5 | imm4_0;
 171         return 0;
 172 }
 173 
 174 static int apply_r_riscv_got_hi20_rela(struct module *me, u32 *location,
 175                                        Elf_Addr v)
 176 {
 177         ptrdiff_t offset = (void *)v - (void *)location;
 178         s32 hi20;
 179 
 180         /* Always emit the got entry */
 181         if (IS_ENABLED(CONFIG_MODULE_SECTIONS)) {
 182                 offset = module_emit_got_entry(me, v);
 183                 offset = (void *)offset - (void *)location;
 184         } else {
 185                 pr_err(
 186                   "%s: can not generate the GOT entry for symbol = %016llx from PC = %p\n",
 187                   me->name, (long long)v, location);
 188                 return -EINVAL;
 189         }
 190 
 191         hi20 = (offset + 0x800) & 0xfffff000;
 192         *location = (*location & 0xfff) | hi20;
 193         return 0;
 194 }
 195 
 196 static int apply_r_riscv_call_plt_rela(struct module *me, u32 *location,
 197                                        Elf_Addr v)
 198 {
 199         ptrdiff_t offset = (void *)v - (void *)location;
 200         s32 fill_v = offset;
 201         u32 hi20, lo12;
 202 
 203         if (offset != fill_v) {
 204                 /* Only emit the plt entry if offset over 32-bit range */
 205                 if (IS_ENABLED(CONFIG_MODULE_SECTIONS)) {
 206                         offset = module_emit_plt_entry(me, v);
 207                         offset = (void *)offset - (void *)location;
 208                 } else {
 209                         pr_err(
 210                           "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n",
 211                           me->name, (long long)v, location);
 212                         return -EINVAL;
 213                 }
 214         }
 215 
 216         hi20 = (offset + 0x800) & 0xfffff000;
 217         lo12 = (offset - hi20) & 0xfff;
 218         *location = (*location & 0xfff) | hi20;
 219         *(location + 1) = (*(location + 1) & 0xfffff) | (lo12 << 20);
 220         return 0;
 221 }
 222 
 223 static int apply_r_riscv_call_rela(struct module *me, u32 *location,
 224                                    Elf_Addr v)
 225 {
 226         ptrdiff_t offset = (void *)v - (void *)location;
 227         s32 fill_v = offset;
 228         u32 hi20, lo12;
 229 
 230         if (offset != fill_v) {
 231                 pr_err(
 232                   "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n",
 233                   me->name, (long long)v, location);
 234                 return -EINVAL;
 235         }
 236 
 237         hi20 = (offset + 0x800) & 0xfffff000;
 238         lo12 = (offset - hi20) & 0xfff;
 239         *location = (*location & 0xfff) | hi20;
 240         *(location + 1) = (*(location + 1) & 0xfffff) | (lo12 << 20);
 241         return 0;
 242 }
 243 
 244 static int apply_r_riscv_relax_rela(struct module *me, u32 *location,
 245                                     Elf_Addr v)
 246 {
 247         return 0;
 248 }
 249 
 250 static int apply_r_riscv_align_rela(struct module *me, u32 *location,
 251                                     Elf_Addr v)
 252 {
 253         pr_err(
 254           "%s: The unexpected relocation type 'R_RISCV_ALIGN' from PC = %p\n",
 255           me->name, location);
 256         return -EINVAL;
 257 }
 258 
 259 static int apply_r_riscv_add32_rela(struct module *me, u32 *location,
 260                                     Elf_Addr v)
 261 {
 262         *(u32 *)location += (u32)v;
 263         return 0;
 264 }
 265 
 266 static int apply_r_riscv_sub32_rela(struct module *me, u32 *location,
 267                                     Elf_Addr v)
 268 {
 269         *(u32 *)location -= (u32)v;
 270         return 0;
 271 }
 272 
 273 static int (*reloc_handlers_rela[]) (struct module *me, u32 *location,
 274                                 Elf_Addr v) = {
 275         [R_RISCV_32]                    = apply_r_riscv_32_rela,
 276         [R_RISCV_64]                    = apply_r_riscv_64_rela,
 277         [R_RISCV_BRANCH]                = apply_r_riscv_branch_rela,
 278         [R_RISCV_JAL]                   = apply_r_riscv_jal_rela,
 279         [R_RISCV_RVC_BRANCH]            = apply_r_riscv_rcv_branch_rela,
 280         [R_RISCV_RVC_JUMP]              = apply_r_riscv_rvc_jump_rela,
 281         [R_RISCV_PCREL_HI20]            = apply_r_riscv_pcrel_hi20_rela,
 282         [R_RISCV_PCREL_LO12_I]          = apply_r_riscv_pcrel_lo12_i_rela,
 283         [R_RISCV_PCREL_LO12_S]          = apply_r_riscv_pcrel_lo12_s_rela,
 284         [R_RISCV_HI20]                  = apply_r_riscv_hi20_rela,
 285         [R_RISCV_LO12_I]                = apply_r_riscv_lo12_i_rela,
 286         [R_RISCV_LO12_S]                = apply_r_riscv_lo12_s_rela,
 287         [R_RISCV_GOT_HI20]              = apply_r_riscv_got_hi20_rela,
 288         [R_RISCV_CALL_PLT]              = apply_r_riscv_call_plt_rela,
 289         [R_RISCV_CALL]                  = apply_r_riscv_call_rela,
 290         [R_RISCV_RELAX]                 = apply_r_riscv_relax_rela,
 291         [R_RISCV_ALIGN]                 = apply_r_riscv_align_rela,
 292         [R_RISCV_ADD32]                 = apply_r_riscv_add32_rela,
 293         [R_RISCV_SUB32]                 = apply_r_riscv_sub32_rela,
 294 };
 295 
 296 int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
 297                        unsigned int symindex, unsigned int relsec,
 298                        struct module *me)
 299 {
 300         Elf_Rela *rel = (void *) sechdrs[relsec].sh_addr;
 301         int (*handler)(struct module *me, u32 *location, Elf_Addr v);
 302         Elf_Sym *sym;
 303         u32 *location;
 304         unsigned int i, type;
 305         Elf_Addr v;
 306         int res;
 307 
 308         pr_debug("Applying relocate section %u to %u\n", relsec,
 309                sechdrs[relsec].sh_info);
 310 
 311         for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
 312                 /* This is where to make the change */
 313                 location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
 314                         + rel[i].r_offset;
 315                 /* This is the symbol it is referring to */
 316                 sym = (Elf_Sym *)sechdrs[symindex].sh_addr
 317                         + ELF_RISCV_R_SYM(rel[i].r_info);
 318                 if (IS_ERR_VALUE(sym->st_value)) {
 319                         /* Ignore unresolved weak symbol */
 320                         if (ELF_ST_BIND(sym->st_info) == STB_WEAK)
 321                                 continue;
 322                         pr_warning("%s: Unknown symbol %s\n",
 323                                    me->name, strtab + sym->st_name);
 324                         return -ENOENT;
 325                 }
 326 
 327                 type = ELF_RISCV_R_TYPE(rel[i].r_info);
 328 
 329                 if (type < ARRAY_SIZE(reloc_handlers_rela))
 330                         handler = reloc_handlers_rela[type];
 331                 else
 332                         handler = NULL;
 333 
 334                 if (!handler) {
 335                         pr_err("%s: Unknown relocation type %u\n",
 336                                me->name, type);
 337                         return -EINVAL;
 338                 }
 339 
 340                 v = sym->st_value + rel[i].r_addend;
 341 
 342                 if (type == R_RISCV_PCREL_LO12_I || type == R_RISCV_PCREL_LO12_S) {
 343                         unsigned int j;
 344 
 345                         for (j = 0; j < sechdrs[relsec].sh_size / sizeof(*rel); j++) {
 346                                 unsigned long hi20_loc =
 347                                         sechdrs[sechdrs[relsec].sh_info].sh_addr
 348                                         + rel[j].r_offset;
 349                                 u32 hi20_type = ELF_RISCV_R_TYPE(rel[j].r_info);
 350 
 351                                 /* Find the corresponding HI20 relocation entry */
 352                                 if (hi20_loc == sym->st_value
 353                                     && (hi20_type == R_RISCV_PCREL_HI20
 354                                         || hi20_type == R_RISCV_GOT_HI20)) {
 355                                         s32 hi20, lo12;
 356                                         Elf_Sym *hi20_sym =
 357                                                 (Elf_Sym *)sechdrs[symindex].sh_addr
 358                                                 + ELF_RISCV_R_SYM(rel[j].r_info);
 359                                         unsigned long hi20_sym_val =
 360                                                 hi20_sym->st_value
 361                                                 + rel[j].r_addend;
 362 
 363                                         /* Calculate lo12 */
 364                                         size_t offset = hi20_sym_val - hi20_loc;
 365                                         if (IS_ENABLED(CONFIG_MODULE_SECTIONS)
 366                                             && hi20_type == R_RISCV_GOT_HI20) {
 367                                                 offset = module_emit_got_entry(
 368                                                          me, hi20_sym_val);
 369                                                 offset = offset - hi20_loc;
 370                                         }
 371                                         hi20 = (offset + 0x800) & 0xfffff000;
 372                                         lo12 = offset - hi20;
 373                                         v = lo12;
 374 
 375                                         break;
 376                                 }
 377                         }
 378                         if (j == sechdrs[relsec].sh_size / sizeof(*rel)) {
 379                                 pr_err(
 380                                   "%s: Can not find HI20 relocation information\n",
 381                                   me->name);
 382                                 return -EINVAL;
 383                         }
 384                 }
 385 
 386                 res = handler(me, location, v);
 387                 if (res)
 388                         return res;
 389         }
 390 
 391         return 0;
 392 }
 393 
 394 #if defined(CONFIG_MMU) && defined(CONFIG_64BIT)
 395 #define VMALLOC_MODULE_START \
 396          max(PFN_ALIGN((unsigned long)&_end - SZ_2G), VMALLOC_START)
 397 void *module_alloc(unsigned long size)
 398 {
 399         return __vmalloc_node_range(size, 1, VMALLOC_MODULE_START,
 400                                     VMALLOC_END, GFP_KERNEL,
 401                                     PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE,
 402                                     __builtin_return_address(0));
 403 }
 404 #endif

/* [<][>][^][v][top][bottom][index][help] */