diff options
| author | Ard Biesheuvel <ard.biesheuvel@linaro.org> | 2017-11-20 12:41:29 -0500 |
|---|---|---|
| committer | Will Deacon <will.deacon@arm.com> | 2017-12-01 07:30:21 -0500 |
| commit | 7e8b9c1d2e2f5f45db7d40b50d14f606097c25de (patch) | |
| tree | bbce43dfb8ebcfc44fcfb837363205628a608592 | |
| parent | f81a348728ec5ac43f3bbcf81c97d52baba253f7 (diff) | |
arm64: module-plts: factor out PLT generation code for ftrace
To allow the ftrace trampoline code to reuse the PLT entry routines,
factor it out and move it into asm/module.h.
Cc: <stable@vger.kernel.org>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Will Deacon <will.deacon@arm.com>
| -rw-r--r-- | arch/arm64/include/asm/module.h | 44 | ||||
| -rw-r--r-- | arch/arm64/kernel/module-plts.c | 38 |
2 files changed, 46 insertions, 36 deletions
diff --git a/arch/arm64/include/asm/module.h b/arch/arm64/include/asm/module.h index 19bd97671bb8..11d4aaee82e1 100644 --- a/arch/arm64/include/asm/module.h +++ b/arch/arm64/include/asm/module.h | |||
| @@ -45,4 +45,48 @@ extern u64 module_alloc_base; | |||
| 45 | #define module_alloc_base ((u64)_etext - MODULES_VSIZE) | 45 | #define module_alloc_base ((u64)_etext - MODULES_VSIZE) |
| 46 | #endif | 46 | #endif |
| 47 | 47 | ||
| 48 | struct plt_entry { | ||
| 49 | /* | ||
| 50 | * A program that conforms to the AArch64 Procedure Call Standard | ||
| 51 | * (AAPCS64) must assume that a veneer that alters IP0 (x16) and/or | ||
| 52 | * IP1 (x17) may be inserted at any branch instruction that is | ||
| 53 | * exposed to a relocation that supports long branches. Since that | ||
| 54 | * is exactly what we are dealing with here, we are free to use x16 | ||
| 55 | * as a scratch register in the PLT veneers. | ||
| 56 | */ | ||
| 57 | __le32 mov0; /* movn x16, #0x.... */ | ||
| 58 | __le32 mov1; /* movk x16, #0x...., lsl #16 */ | ||
| 59 | __le32 mov2; /* movk x16, #0x...., lsl #32 */ | ||
| 60 | __le32 br; /* br x16 */ | ||
| 61 | }; | ||
| 62 | |||
| 63 | static inline struct plt_entry get_plt_entry(u64 val) | ||
| 64 | { | ||
| 65 | /* | ||
| 66 | * MOVK/MOVN/MOVZ opcode: | ||
| 67 | * +--------+------------+--------+-----------+-------------+---------+ | ||
| 68 | * | sf[31] | opc[30:29] | 100101 | hw[22:21] | imm16[20:5] | Rd[4:0] | | ||
| 69 | * +--------+------------+--------+-----------+-------------+---------+ | ||
| 70 | * | ||
| 71 | * Rd := 0x10 (x16) | ||
| 72 | * hw := 0b00 (no shift), 0b01 (lsl #16), 0b10 (lsl #32) | ||
| 73 | * opc := 0b11 (MOVK), 0b00 (MOVN), 0b10 (MOVZ) | ||
| 74 | * sf := 1 (64-bit variant) | ||
| 75 | */ | ||
| 76 | return (struct plt_entry){ | ||
| 77 | cpu_to_le32(0x92800010 | (((~val ) & 0xffff)) << 5), | ||
| 78 | cpu_to_le32(0xf2a00010 | ((( val >> 16) & 0xffff)) << 5), | ||
| 79 | cpu_to_le32(0xf2c00010 | ((( val >> 32) & 0xffff)) << 5), | ||
| 80 | cpu_to_le32(0xd61f0200) | ||
| 81 | }; | ||
| 82 | } | ||
| 83 | |||
| 84 | static inline bool plt_entries_equal(const struct plt_entry *a, | ||
| 85 | const struct plt_entry *b) | ||
| 86 | { | ||
| 87 | return a->mov0 == b->mov0 && | ||
| 88 | a->mov1 == b->mov1 && | ||
| 89 | a->mov2 == b->mov2; | ||
| 90 | } | ||
| 91 | |||
| 48 | #endif /* __ASM_MODULE_H */ | 92 | #endif /* __ASM_MODULE_H */ |
diff --git a/arch/arm64/kernel/module-plts.c b/arch/arm64/kernel/module-plts.c index d05dbe658409..ebff6c155cac 100644 --- a/arch/arm64/kernel/module-plts.c +++ b/arch/arm64/kernel/module-plts.c | |||
| @@ -11,21 +11,6 @@ | |||
| 11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
| 12 | #include <linux/sort.h> | 12 | #include <linux/sort.h> |
| 13 | 13 | ||
| 14 | struct plt_entry { | ||
| 15 | /* | ||
| 16 | * A program that conforms to the AArch64 Procedure Call Standard | ||
| 17 | * (AAPCS64) must assume that a veneer that alters IP0 (x16) and/or | ||
| 18 | * IP1 (x17) may be inserted at any branch instruction that is | ||
| 19 | * exposed to a relocation that supports long branches. Since that | ||
| 20 | * is exactly what we are dealing with here, we are free to use x16 | ||
| 21 | * as a scratch register in the PLT veneers. | ||
| 22 | */ | ||
| 23 | __le32 mov0; /* movn x16, #0x.... */ | ||
| 24 | __le32 mov1; /* movk x16, #0x...., lsl #16 */ | ||
| 25 | __le32 mov2; /* movk x16, #0x...., lsl #32 */ | ||
| 26 | __le32 br; /* br x16 */ | ||
| 27 | }; | ||
| 28 | |||
| 29 | static bool in_init(const struct module *mod, void *loc) | 14 | static bool in_init(const struct module *mod, void *loc) |
| 30 | { | 15 | { |
| 31 | return (u64)loc - (u64)mod->init_layout.base < mod->init_layout.size; | 16 | return (u64)loc - (u64)mod->init_layout.base < mod->init_layout.size; |
| @@ -40,33 +25,14 @@ u64 module_emit_plt_entry(struct module *mod, void *loc, const Elf64_Rela *rela, | |||
| 40 | int i = pltsec->plt_num_entries; | 25 | int i = pltsec->plt_num_entries; |
| 41 | u64 val = sym->st_value + rela->r_addend; | 26 | u64 val = sym->st_value + rela->r_addend; |
| 42 | 27 | ||
| 43 | /* | 28 | plt[i] = get_plt_entry(val); |
| 44 | * MOVK/MOVN/MOVZ opcode: | ||
| 45 | * +--------+------------+--------+-----------+-------------+---------+ | ||
| 46 | * | sf[31] | opc[30:29] | 100101 | hw[22:21] | imm16[20:5] | Rd[4:0] | | ||
| 47 | * +--------+------------+--------+-----------+-------------+---------+ | ||
| 48 | * | ||
| 49 | * Rd := 0x10 (x16) | ||
| 50 | * hw := 0b00 (no shift), 0b01 (lsl #16), 0b10 (lsl #32) | ||
| 51 | * opc := 0b11 (MOVK), 0b00 (MOVN), 0b10 (MOVZ) | ||
| 52 | * sf := 1 (64-bit variant) | ||
| 53 | */ | ||
| 54 | plt[i] = (struct plt_entry){ | ||
| 55 | cpu_to_le32(0x92800010 | (((~val ) & 0xffff)) << 5), | ||
| 56 | cpu_to_le32(0xf2a00010 | ((( val >> 16) & 0xffff)) << 5), | ||
| 57 | cpu_to_le32(0xf2c00010 | ((( val >> 32) & 0xffff)) << 5), | ||
| 58 | cpu_to_le32(0xd61f0200) | ||
| 59 | }; | ||
| 60 | 29 | ||
| 61 | /* | 30 | /* |
| 62 | * Check if the entry we just created is a duplicate. Given that the | 31 | * Check if the entry we just created is a duplicate. Given that the |
| 63 | * relocations are sorted, this will be the last entry we allocated. | 32 | * relocations are sorted, this will be the last entry we allocated. |
| 64 | * (if one exists). | 33 | * (if one exists). |
| 65 | */ | 34 | */ |
| 66 | if (i > 0 && | 35 | if (i > 0 && plt_entries_equal(plt + i, plt + i - 1)) |
| 67 | plt[i].mov0 == plt[i - 1].mov0 && | ||
| 68 | plt[i].mov1 == plt[i - 1].mov1 && | ||
| 69 | plt[i].mov2 == plt[i - 1].mov2) | ||
| 70 | return (u64)&plt[i - 1]; | 36 | return (u64)&plt[i - 1]; |
| 71 | 37 | ||
| 72 | pltsec->plt_num_entries++; | 38 | pltsec->plt_num_entries++; |
