.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* Kernel module help for PPC64. |
---|
2 | 3 | Copyright (C) 2001, 2003 Rusty Russell IBM Corporation. |
---|
3 | 4 | |
---|
4 | | - This program is free software; you can redistribute it and/or modify |
---|
5 | | - it under the terms of the GNU General Public License as published by |
---|
6 | | - the Free Software Foundation; either version 2 of the License, or |
---|
7 | | - (at your option) any later version. |
---|
8 | | - |
---|
9 | | - This program is distributed in the hope that it will be useful, |
---|
10 | | - but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
11 | | - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
12 | | - GNU General Public License for more details. |
---|
13 | | - |
---|
14 | | - You should have received a copy of the GNU General Public License |
---|
15 | | - along with this program; if not, write to the Free Software |
---|
16 | | - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
17 | 5 | */ |
---|
18 | 6 | |
---|
19 | 7 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
---|
.. | .. |
---|
32 | 20 | #include <linux/sort.h> |
---|
33 | 21 | #include <asm/setup.h> |
---|
34 | 22 | #include <asm/sections.h> |
---|
| 23 | +#include <asm/inst.h> |
---|
35 | 24 | |
---|
36 | 25 | /* FIXME: We don't do .init separately. To do this, we'd need to have |
---|
37 | 26 | a separate r2 value in the init and core section, and stub between |
---|
.. | .. |
---|
133 | 122 | * the stub, but it's significantly shorter to put these values at the |
---|
134 | 123 | * end of the stub code, and patch the stub address (32-bits relative |
---|
135 | 124 | * to the TOC ptr, r2) into the stub. |
---|
| 125 | + * |
---|
| 126 | + * addis r11,r2, <high> |
---|
| 127 | + * addi r11,r11, <low> |
---|
| 128 | + * std r2,R2_STACK_OFFSET(r1) |
---|
| 129 | + * ld r12,32(r11) |
---|
| 130 | + * ld r2,40(r11) |
---|
| 131 | + * mtctr r12 |
---|
| 132 | + * bctr |
---|
136 | 133 | */ |
---|
137 | | - |
---|
138 | 134 | static u32 ppc64_stub_insns[] = { |
---|
139 | | - 0x3d620000, /* addis r11,r2, <high> */ |
---|
140 | | - 0x396b0000, /* addi r11,r11, <low> */ |
---|
| 135 | + PPC_INST_ADDIS | __PPC_RT(R11) | __PPC_RA(R2), |
---|
| 136 | + PPC_INST_ADDI | __PPC_RT(R11) | __PPC_RA(R11), |
---|
141 | 137 | /* Save current r2 value in magic place on the stack. */ |
---|
142 | | - 0xf8410000|R2_STACK_OFFSET, /* std r2,R2_STACK_OFFSET(r1) */ |
---|
143 | | - 0xe98b0020, /* ld r12,32(r11) */ |
---|
| 138 | + PPC_INST_STD | __PPC_RS(R2) | __PPC_RA(R1) | R2_STACK_OFFSET, |
---|
| 139 | + PPC_INST_LD | __PPC_RT(R12) | __PPC_RA(R11) | 32, |
---|
144 | 140 | #ifdef PPC64_ELF_ABI_v1 |
---|
145 | 141 | /* Set up new r2 from function descriptor */ |
---|
146 | | - 0xe84b0028, /* ld r2,40(r11) */ |
---|
| 142 | + PPC_INST_LD | __PPC_RT(R2) | __PPC_RA(R11) | 40, |
---|
147 | 143 | #endif |
---|
148 | | - 0x7d8903a6, /* mtctr r12 */ |
---|
149 | | - 0x4e800420 /* bctr */ |
---|
| 144 | + PPC_INST_MTCTR | __PPC_RS(R12), |
---|
| 145 | + PPC_INST_BCTR, |
---|
150 | 146 | }; |
---|
151 | | - |
---|
152 | | -#ifdef CONFIG_DYNAMIC_FTRACE |
---|
153 | | -int module_trampoline_target(struct module *mod, unsigned long addr, |
---|
154 | | - unsigned long *target) |
---|
155 | | -{ |
---|
156 | | - struct ppc64_stub_entry *stub; |
---|
157 | | - func_desc_t funcdata; |
---|
158 | | - u32 magic; |
---|
159 | | - |
---|
160 | | - if (!within_module_core(addr, mod)) { |
---|
161 | | - pr_err("%s: stub %lx not in module %s\n", __func__, addr, mod->name); |
---|
162 | | - return -EFAULT; |
---|
163 | | - } |
---|
164 | | - |
---|
165 | | - stub = (struct ppc64_stub_entry *)addr; |
---|
166 | | - |
---|
167 | | - if (probe_kernel_read(&magic, &stub->magic, sizeof(magic))) { |
---|
168 | | - pr_err("%s: fault reading magic for stub %lx for %s\n", __func__, addr, mod->name); |
---|
169 | | - return -EFAULT; |
---|
170 | | - } |
---|
171 | | - |
---|
172 | | - if (magic != STUB_MAGIC) { |
---|
173 | | - pr_err("%s: bad magic for stub %lx for %s\n", __func__, addr, mod->name); |
---|
174 | | - return -EFAULT; |
---|
175 | | - } |
---|
176 | | - |
---|
177 | | - if (probe_kernel_read(&funcdata, &stub->funcdata, sizeof(funcdata))) { |
---|
178 | | - pr_err("%s: fault reading funcdata for stub %lx for %s\n", __func__, addr, mod->name); |
---|
179 | | - return -EFAULT; |
---|
180 | | - } |
---|
181 | | - |
---|
182 | | - *target = stub_func_addr(funcdata); |
---|
183 | | - |
---|
184 | | - return 0; |
---|
185 | | -} |
---|
186 | | -#endif |
---|
187 | 147 | |
---|
188 | 148 | /* Count how many different 24-bit relocations (different symbol, |
---|
189 | 149 | different addend) */ |
---|
.. | .. |
---|
231 | 191 | return 0; |
---|
232 | 192 | } |
---|
233 | 193 | |
---|
234 | | -static void relaswap(void *_x, void *_y, int size) |
---|
235 | | -{ |
---|
236 | | - uint64_t *x, *y, tmp; |
---|
237 | | - int i; |
---|
238 | | - |
---|
239 | | - y = (uint64_t *)_x; |
---|
240 | | - x = (uint64_t *)_y; |
---|
241 | | - |
---|
242 | | - for (i = 0; i < sizeof(Elf64_Rela) / sizeof(uint64_t); i++) { |
---|
243 | | - tmp = x[i]; |
---|
244 | | - x[i] = y[i]; |
---|
245 | | - y[i] = tmp; |
---|
246 | | - } |
---|
247 | | -} |
---|
248 | | - |
---|
249 | 194 | /* Get size of potential trampolines required. */ |
---|
250 | 195 | static unsigned long get_stubs_size(const Elf64_Ehdr *hdr, |
---|
251 | 196 | const Elf64_Shdr *sechdrs) |
---|
.. | .. |
---|
269 | 214 | */ |
---|
270 | 215 | sort((void *)sechdrs[i].sh_addr, |
---|
271 | 216 | sechdrs[i].sh_size / sizeof(Elf64_Rela), |
---|
272 | | - sizeof(Elf64_Rela), relacmp, relaswap); |
---|
| 217 | + sizeof(Elf64_Rela), relacmp, NULL); |
---|
273 | 218 | |
---|
274 | 219 | relocs += count_relocs((void *)sechdrs[i].sh_addr, |
---|
275 | 220 | sechdrs[i].sh_size |
---|
.. | .. |
---|
389 | 334 | return 0; |
---|
390 | 335 | } |
---|
391 | 336 | |
---|
| 337 | +#ifdef CONFIG_MPROFILE_KERNEL |
---|
| 338 | + |
---|
| 339 | +#define PACATOC offsetof(struct paca_struct, kernel_toc) |
---|
| 340 | + |
---|
| 341 | +/* |
---|
| 342 | + * ld r12,PACATOC(r13) |
---|
| 343 | + * addis r12,r12,<high> |
---|
| 344 | + * addi r12,r12,<low> |
---|
| 345 | + * mtctr r12 |
---|
| 346 | + * bctr |
---|
| 347 | + */ |
---|
| 348 | +static u32 stub_insns[] = { |
---|
| 349 | + PPC_INST_LD | __PPC_RT(R12) | __PPC_RA(R13) | PACATOC, |
---|
| 350 | + PPC_INST_ADDIS | __PPC_RT(R12) | __PPC_RA(R12), |
---|
| 351 | + PPC_INST_ADDI | __PPC_RT(R12) | __PPC_RA(R12), |
---|
| 352 | + PPC_INST_MTCTR | __PPC_RS(R12), |
---|
| 353 | + PPC_INST_BCTR, |
---|
| 354 | +}; |
---|
| 355 | + |
---|
| 356 | +/* |
---|
| 357 | + * For mprofile-kernel we use a special stub for ftrace_caller() because we |
---|
| 358 | + * can't rely on r2 containing this module's TOC when we enter the stub. |
---|
| 359 | + * |
---|
| 360 | + * That can happen if the function calling us didn't need to use the toc. In |
---|
| 361 | + * that case it won't have setup r2, and the r2 value will be either the |
---|
| 362 | + * kernel's toc, or possibly another modules toc. |
---|
| 363 | + * |
---|
| 364 | + * To deal with that this stub uses the kernel toc, which is always accessible |
---|
| 365 | + * via the paca (in r13). The target (ftrace_caller()) is responsible for |
---|
| 366 | + * saving and restoring the toc before returning. |
---|
| 367 | + */ |
---|
| 368 | +static inline int create_ftrace_stub(struct ppc64_stub_entry *entry, |
---|
| 369 | + unsigned long addr, |
---|
| 370 | + struct module *me) |
---|
| 371 | +{ |
---|
| 372 | + long reladdr; |
---|
| 373 | + |
---|
| 374 | + memcpy(entry->jump, stub_insns, sizeof(stub_insns)); |
---|
| 375 | + |
---|
| 376 | + /* Stub uses address relative to kernel toc (from the paca) */ |
---|
| 377 | + reladdr = addr - kernel_toc_addr(); |
---|
| 378 | + if (reladdr > 0x7FFFFFFF || reladdr < -(0x80000000L)) { |
---|
| 379 | + pr_err("%s: Address of %ps out of range of kernel_toc.\n", |
---|
| 380 | + me->name, (void *)addr); |
---|
| 381 | + return 0; |
---|
| 382 | + } |
---|
| 383 | + |
---|
| 384 | + entry->jump[1] |= PPC_HA(reladdr); |
---|
| 385 | + entry->jump[2] |= PPC_LO(reladdr); |
---|
| 386 | + |
---|
| 387 | + /* Eventhough we don't use funcdata in the stub, it's needed elsewhere. */ |
---|
| 388 | + entry->funcdata = func_desc(addr); |
---|
| 389 | + entry->magic = STUB_MAGIC; |
---|
| 390 | + |
---|
| 391 | + return 1; |
---|
| 392 | +} |
---|
| 393 | + |
---|
| 394 | +static bool is_mprofile_ftrace_call(const char *name) |
---|
| 395 | +{ |
---|
| 396 | + if (!strcmp("_mcount", name)) |
---|
| 397 | + return true; |
---|
| 398 | +#ifdef CONFIG_DYNAMIC_FTRACE |
---|
| 399 | + if (!strcmp("ftrace_caller", name)) |
---|
| 400 | + return true; |
---|
| 401 | +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS |
---|
| 402 | + if (!strcmp("ftrace_regs_caller", name)) |
---|
| 403 | + return true; |
---|
| 404 | +#endif |
---|
| 405 | +#endif |
---|
| 406 | + |
---|
| 407 | + return false; |
---|
| 408 | +} |
---|
| 409 | +#else |
---|
| 410 | +static inline int create_ftrace_stub(struct ppc64_stub_entry *entry, |
---|
| 411 | + unsigned long addr, |
---|
| 412 | + struct module *me) |
---|
| 413 | +{ |
---|
| 414 | + return 0; |
---|
| 415 | +} |
---|
| 416 | + |
---|
| 417 | +static bool is_mprofile_ftrace_call(const char *name) |
---|
| 418 | +{ |
---|
| 419 | + return false; |
---|
| 420 | +} |
---|
| 421 | +#endif |
---|
| 422 | + |
---|
392 | 423 | /* |
---|
393 | 424 | * r2 is the TOC pointer: it actually points 0x8000 into the TOC (this gives the |
---|
394 | 425 | * value maximum span in an instruction which uses a signed offset). Round down |
---|
.. | .. |
---|
400 | 431 | return (sechdrs[me->arch.toc_section].sh_addr & ~0xfful) + 0x8000; |
---|
401 | 432 | } |
---|
402 | 433 | |
---|
403 | | -/* Both low and high 16 bits are added as SIGNED additions, so if low |
---|
404 | | - 16 bits has high bit set, high 16 bits must be adjusted. These |
---|
405 | | - macros do that (stolen from binutils). */ |
---|
406 | | -#define PPC_LO(v) ((v) & 0xffff) |
---|
407 | | -#define PPC_HI(v) (((v) >> 16) & 0xffff) |
---|
408 | | -#define PPC_HA(v) PPC_HI ((v) + 0x8000) |
---|
409 | | - |
---|
410 | 434 | /* Patch stub to reference function and correct r2 value. */ |
---|
411 | 435 | static inline int create_stub(const Elf64_Shdr *sechdrs, |
---|
412 | 436 | struct ppc64_stub_entry *entry, |
---|
413 | 437 | unsigned long addr, |
---|
414 | | - struct module *me) |
---|
| 438 | + struct module *me, |
---|
| 439 | + const char *name) |
---|
415 | 440 | { |
---|
416 | 441 | long reladdr; |
---|
| 442 | + |
---|
| 443 | + if (is_mprofile_ftrace_call(name)) |
---|
| 444 | + return create_ftrace_stub(entry, addr, me); |
---|
417 | 445 | |
---|
418 | 446 | memcpy(entry->jump, ppc64_stub_insns, sizeof(ppc64_stub_insns)); |
---|
419 | 447 | |
---|
.. | .. |
---|
438 | 466 | stub to set up the TOC ptr (r2) for the function. */ |
---|
439 | 467 | static unsigned long stub_for_addr(const Elf64_Shdr *sechdrs, |
---|
440 | 468 | unsigned long addr, |
---|
441 | | - struct module *me) |
---|
| 469 | + struct module *me, |
---|
| 470 | + const char *name) |
---|
442 | 471 | { |
---|
443 | 472 | struct ppc64_stub_entry *stubs; |
---|
444 | 473 | unsigned int i, num_stubs; |
---|
.. | .. |
---|
455 | 484 | return (unsigned long)&stubs[i]; |
---|
456 | 485 | } |
---|
457 | 486 | |
---|
458 | | - if (!create_stub(sechdrs, &stubs[i], addr, me)) |
---|
| 487 | + if (!create_stub(sechdrs, &stubs[i], addr, me, name)) |
---|
459 | 488 | return 0; |
---|
460 | 489 | |
---|
461 | 490 | return (unsigned long)&stubs[i]; |
---|
462 | 491 | } |
---|
463 | | - |
---|
464 | | -#ifdef CONFIG_MPROFILE_KERNEL |
---|
465 | | -static bool is_mprofile_mcount_callsite(const char *name, u32 *instruction) |
---|
466 | | -{ |
---|
467 | | - if (strcmp("_mcount", name)) |
---|
468 | | - return false; |
---|
469 | | - |
---|
470 | | - /* |
---|
471 | | - * Check if this is one of the -mprofile-kernel sequences. |
---|
472 | | - */ |
---|
473 | | - if (instruction[-1] == PPC_INST_STD_LR && |
---|
474 | | - instruction[-2] == PPC_INST_MFLR) |
---|
475 | | - return true; |
---|
476 | | - |
---|
477 | | - if (instruction[-1] == PPC_INST_MFLR) |
---|
478 | | - return true; |
---|
479 | | - |
---|
480 | | - return false; |
---|
481 | | -} |
---|
482 | | - |
---|
483 | | -/* |
---|
484 | | - * In case of _mcount calls, do not save the current callee's TOC (in r2) into |
---|
485 | | - * the original caller's stack frame. If we did we would clobber the saved TOC |
---|
486 | | - * value of the original caller. |
---|
487 | | - */ |
---|
488 | | -static void squash_toc_save_inst(const char *name, unsigned long addr) |
---|
489 | | -{ |
---|
490 | | - struct ppc64_stub_entry *stub = (struct ppc64_stub_entry *)addr; |
---|
491 | | - |
---|
492 | | - /* Only for calls to _mcount */ |
---|
493 | | - if (strcmp("_mcount", name) != 0) |
---|
494 | | - return; |
---|
495 | | - |
---|
496 | | - stub->jump[2] = PPC_INST_NOP; |
---|
497 | | -} |
---|
498 | | -#else |
---|
499 | | -static void squash_toc_save_inst(const char *name, unsigned long addr) { } |
---|
500 | | - |
---|
501 | | -static bool is_mprofile_mcount_callsite(const char *name, u32 *instruction) |
---|
502 | | -{ |
---|
503 | | - return false; |
---|
504 | | -} |
---|
505 | | -#endif |
---|
506 | 492 | |
---|
507 | 493 | /* We expect a noop next: if it is, replace it with instruction to |
---|
508 | 494 | restore r2. */ |
---|
.. | .. |
---|
510 | 496 | { |
---|
511 | 497 | u32 *prev_insn = instruction - 1; |
---|
512 | 498 | |
---|
513 | | - if (is_mprofile_mcount_callsite(name, prev_insn)) |
---|
| 499 | + if (is_mprofile_ftrace_call(name)) |
---|
514 | 500 | return 1; |
---|
515 | 501 | |
---|
516 | 502 | /* |
---|
.. | .. |
---|
518 | 504 | * "link" branches and they don't return, so they don't need the r2 |
---|
519 | 505 | * restore afterwards. |
---|
520 | 506 | */ |
---|
521 | | - if (!instr_is_relative_link_branch(*prev_insn)) |
---|
| 507 | + if (!instr_is_relative_link_branch(ppc_inst(*prev_insn))) |
---|
522 | 508 | return 1; |
---|
523 | 509 | |
---|
524 | 510 | if (*instruction != PPC_INST_NOP) { |
---|
.. | .. |
---|
648 | 634 | if (sym->st_shndx == SHN_UNDEF || |
---|
649 | 635 | sym->st_shndx == SHN_LIVEPATCH) { |
---|
650 | 636 | /* External: go via stub */ |
---|
651 | | - value = stub_for_addr(sechdrs, value, me); |
---|
| 637 | + value = stub_for_addr(sechdrs, value, me, |
---|
| 638 | + strtab + sym->st_name); |
---|
652 | 639 | if (!value) |
---|
653 | 640 | return -ENOENT; |
---|
654 | 641 | if (!restore_r2(strtab + sym->st_name, |
---|
655 | 642 | (u32 *)location + 1, me)) |
---|
656 | 643 | return -ENOEXEC; |
---|
657 | | - |
---|
658 | | - squash_toc_save_inst(strtab + sym->st_name, value); |
---|
659 | 644 | } else |
---|
660 | 645 | value += local_entry_offset(sym); |
---|
661 | 646 | |
---|
.. | .. |
---|
711 | 696 | * ld r2, ...(r12) |
---|
712 | 697 | * add r2, r2, r12 |
---|
713 | 698 | */ |
---|
714 | | - if ((((uint32_t *)location)[0] & ~0xfffc) |
---|
715 | | - != 0xe84c0000) |
---|
| 699 | + if ((((uint32_t *)location)[0] & ~0xfffc) != |
---|
| 700 | + (PPC_INST_LD | __PPC_RT(R2) | __PPC_RA(R12))) |
---|
716 | 701 | break; |
---|
717 | | - if (((uint32_t *)location)[1] != 0x7c426214) |
---|
| 702 | + if (((uint32_t *)location)[1] != |
---|
| 703 | + (PPC_INST_ADD | __PPC_RT(R2) | __PPC_RA(R2) | __PPC_RB(R12))) |
---|
718 | 704 | break; |
---|
719 | 705 | /* |
---|
720 | 706 | * If found, replace it with: |
---|
721 | 707 | * addis r2, r12, (.TOC.-func)@ha |
---|
722 | 708 | * addi r2, r2, (.TOC.-func)@l |
---|
723 | 709 | */ |
---|
724 | | - ((uint32_t *)location)[0] = 0x3c4c0000 + PPC_HA(value); |
---|
725 | | - ((uint32_t *)location)[1] = 0x38420000 + PPC_LO(value); |
---|
| 710 | + ((uint32_t *)location)[0] = PPC_INST_ADDIS | __PPC_RT(R2) | |
---|
| 711 | + __PPC_RA(R12) | PPC_HA(value); |
---|
| 712 | + ((uint32_t *)location)[1] = PPC_INST_ADDI | __PPC_RT(R2) | |
---|
| 713 | + __PPC_RA(R2) | PPC_LO(value); |
---|
726 | 714 | break; |
---|
727 | 715 | |
---|
728 | 716 | case R_PPC64_REL16_HA: |
---|
.. | .. |
---|
754 | 742 | } |
---|
755 | 743 | |
---|
756 | 744 | #ifdef CONFIG_DYNAMIC_FTRACE |
---|
757 | | - |
---|
758 | | -#ifdef CONFIG_MPROFILE_KERNEL |
---|
759 | | - |
---|
760 | | -#define PACATOC offsetof(struct paca_struct, kernel_toc) |
---|
761 | | - |
---|
762 | | -/* |
---|
763 | | - * For mprofile-kernel we use a special stub for ftrace_caller() because we |
---|
764 | | - * can't rely on r2 containing this module's TOC when we enter the stub. |
---|
765 | | - * |
---|
766 | | - * That can happen if the function calling us didn't need to use the toc. In |
---|
767 | | - * that case it won't have setup r2, and the r2 value will be either the |
---|
768 | | - * kernel's toc, or possibly another modules toc. |
---|
769 | | - * |
---|
770 | | - * To deal with that this stub uses the kernel toc, which is always accessible |
---|
771 | | - * via the paca (in r13). The target (ftrace_caller()) is responsible for |
---|
772 | | - * saving and restoring the toc before returning. |
---|
773 | | - */ |
---|
774 | | -static unsigned long create_ftrace_stub(const Elf64_Shdr *sechdrs, |
---|
775 | | - struct module *me, unsigned long addr) |
---|
| 745 | +int module_trampoline_target(struct module *mod, unsigned long addr, |
---|
| 746 | + unsigned long *target) |
---|
776 | 747 | { |
---|
777 | | - struct ppc64_stub_entry *entry; |
---|
778 | | - unsigned int i, num_stubs; |
---|
779 | | - static u32 stub_insns[] = { |
---|
780 | | - 0xe98d0000 | PACATOC, /* ld r12,PACATOC(r13) */ |
---|
781 | | - 0x3d8c0000, /* addis r12,r12,<high> */ |
---|
782 | | - 0x398c0000, /* addi r12,r12,<low> */ |
---|
783 | | - 0x7d8903a6, /* mtctr r12 */ |
---|
784 | | - 0x4e800420, /* bctr */ |
---|
785 | | - }; |
---|
786 | | - long reladdr; |
---|
| 748 | + struct ppc64_stub_entry *stub; |
---|
| 749 | + func_desc_t funcdata; |
---|
| 750 | + u32 magic; |
---|
787 | 751 | |
---|
788 | | - num_stubs = sechdrs[me->arch.stubs_section].sh_size / sizeof(*entry); |
---|
789 | | - |
---|
790 | | - /* Find the next available stub entry */ |
---|
791 | | - entry = (void *)sechdrs[me->arch.stubs_section].sh_addr; |
---|
792 | | - for (i = 0; i < num_stubs && stub_func_addr(entry->funcdata); i++, entry++); |
---|
793 | | - |
---|
794 | | - if (i >= num_stubs) { |
---|
795 | | - pr_err("%s: Unable to find a free slot for ftrace stub.\n", me->name); |
---|
796 | | - return 0; |
---|
| 752 | + if (!within_module_core(addr, mod)) { |
---|
| 753 | + pr_err("%s: stub %lx not in module %s\n", __func__, addr, mod->name); |
---|
| 754 | + return -EFAULT; |
---|
797 | 755 | } |
---|
798 | 756 | |
---|
799 | | - memcpy(entry->jump, stub_insns, sizeof(stub_insns)); |
---|
| 757 | + stub = (struct ppc64_stub_entry *)addr; |
---|
800 | 758 | |
---|
801 | | - /* Stub uses address relative to kernel toc (from the paca) */ |
---|
802 | | - reladdr = addr - kernel_toc_addr(); |
---|
803 | | - if (reladdr > 0x7FFFFFFF || reladdr < -(0x80000000L)) { |
---|
804 | | - pr_err("%s: Address of %ps out of range of kernel_toc.\n", |
---|
805 | | - me->name, (void *)addr); |
---|
806 | | - return 0; |
---|
| 759 | + if (copy_from_kernel_nofault(&magic, &stub->magic, |
---|
| 760 | + sizeof(magic))) { |
---|
| 761 | + pr_err("%s: fault reading magic for stub %lx for %s\n", __func__, addr, mod->name); |
---|
| 762 | + return -EFAULT; |
---|
807 | 763 | } |
---|
808 | 764 | |
---|
809 | | - entry->jump[1] |= PPC_HA(reladdr); |
---|
810 | | - entry->jump[2] |= PPC_LO(reladdr); |
---|
| 765 | + if (magic != STUB_MAGIC) { |
---|
| 766 | + pr_err("%s: bad magic for stub %lx for %s\n", __func__, addr, mod->name); |
---|
| 767 | + return -EFAULT; |
---|
| 768 | + } |
---|
811 | 769 | |
---|
812 | | - /* Eventhough we don't use funcdata in the stub, it's needed elsewhere. */ |
---|
813 | | - entry->funcdata = func_desc(addr); |
---|
814 | | - entry->magic = STUB_MAGIC; |
---|
| 770 | + if (copy_from_kernel_nofault(&funcdata, &stub->funcdata, |
---|
| 771 | + sizeof(funcdata))) { |
---|
| 772 | + pr_err("%s: fault reading funcdata for stub %lx for %s\n", __func__, addr, mod->name); |
---|
| 773 | + return -EFAULT; |
---|
| 774 | + } |
---|
815 | 775 | |
---|
816 | | - return (unsigned long)entry; |
---|
| 776 | + *target = stub_func_addr(funcdata); |
---|
| 777 | + |
---|
| 778 | + return 0; |
---|
817 | 779 | } |
---|
818 | | -#else |
---|
819 | | -static unsigned long create_ftrace_stub(const Elf64_Shdr *sechdrs, |
---|
820 | | - struct module *me, unsigned long addr) |
---|
821 | | -{ |
---|
822 | | - return stub_for_addr(sechdrs, addr, me); |
---|
823 | | -} |
---|
824 | | -#endif |
---|
825 | 780 | |
---|
826 | 781 | int module_finalize_ftrace(struct module *mod, const Elf_Shdr *sechdrs) |
---|
827 | 782 | { |
---|
828 | | - mod->arch.tramp = create_ftrace_stub(sechdrs, mod, |
---|
829 | | - (unsigned long)ftrace_caller); |
---|
| 783 | + mod->arch.tramp = stub_for_addr(sechdrs, |
---|
| 784 | + (unsigned long)ftrace_caller, |
---|
| 785 | + mod, |
---|
| 786 | + "ftrace_caller"); |
---|
830 | 787 | #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS |
---|
831 | | - mod->arch.tramp_regs = create_ftrace_stub(sechdrs, mod, |
---|
832 | | - (unsigned long)ftrace_regs_caller); |
---|
| 788 | + mod->arch.tramp_regs = stub_for_addr(sechdrs, |
---|
| 789 | + (unsigned long)ftrace_regs_caller, |
---|
| 790 | + mod, |
---|
| 791 | + "ftrace_regs_caller"); |
---|
833 | 792 | if (!mod->arch.tramp_regs) |
---|
834 | 793 | return -ENOENT; |
---|
835 | 794 | #endif |
---|