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