diff options
-rw-r--r-- | arch/arm64/kernel/alternative.c | 53 |
1 files changed, 1 insertions, 52 deletions
diff --git a/arch/arm64/kernel/alternative.c b/arch/arm64/kernel/alternative.c index 21033bba9390..28f8365edc4c 100644 --- a/arch/arm64/kernel/alternative.c +++ b/arch/arm64/kernel/alternative.c | |||
@@ -24,7 +24,6 @@ | |||
24 | #include <asm/cacheflush.h> | 24 | #include <asm/cacheflush.h> |
25 | #include <asm/alternative.h> | 25 | #include <asm/alternative.h> |
26 | #include <asm/cpufeature.h> | 26 | #include <asm/cpufeature.h> |
27 | #include <asm/insn.h> | ||
28 | #include <linux/stop_machine.h> | 27 | #include <linux/stop_machine.h> |
29 | 28 | ||
30 | extern struct alt_instr __alt_instructions[], __alt_instructions_end[]; | 29 | extern struct alt_instr __alt_instructions[], __alt_instructions_end[]; |
@@ -34,48 +33,6 @@ struct alt_region { | |||
34 | struct alt_instr *end; | 33 | struct alt_instr *end; |
35 | }; | 34 | }; |
36 | 35 | ||
37 | /* | ||
38 | * Decode the imm field of a b/bl instruction, and return the byte | ||
39 | * offset as a signed value (so it can be used when computing a new | ||
40 | * branch target). | ||
41 | */ | ||
42 | static s32 get_branch_offset(u32 insn) | ||
43 | { | ||
44 | s32 imm = aarch64_insn_decode_immediate(AARCH64_INSN_IMM_26, insn); | ||
45 | |||
46 | /* sign-extend the immediate before turning it into a byte offset */ | ||
47 | return (imm << 6) >> 4; | ||
48 | } | ||
49 | |||
50 | static u32 get_alt_insn(u8 *insnptr, u8 *altinsnptr) | ||
51 | { | ||
52 | u32 insn; | ||
53 | |||
54 | aarch64_insn_read(altinsnptr, &insn); | ||
55 | |||
56 | /* Stop the world on instructions we don't support... */ | ||
57 | BUG_ON(aarch64_insn_is_cbz(insn)); | ||
58 | BUG_ON(aarch64_insn_is_cbnz(insn)); | ||
59 | BUG_ON(aarch64_insn_is_bcond(insn)); | ||
60 | /* ... and there is probably more. */ | ||
61 | |||
62 | if (aarch64_insn_is_b(insn) || aarch64_insn_is_bl(insn)) { | ||
63 | enum aarch64_insn_branch_type type; | ||
64 | unsigned long target; | ||
65 | |||
66 | if (aarch64_insn_is_b(insn)) | ||
67 | type = AARCH64_INSN_BRANCH_NOLINK; | ||
68 | else | ||
69 | type = AARCH64_INSN_BRANCH_LINK; | ||
70 | |||
71 | target = (unsigned long)altinsnptr + get_branch_offset(insn); | ||
72 | insn = aarch64_insn_gen_branch_imm((unsigned long)insnptr, | ||
73 | target, type); | ||
74 | } | ||
75 | |||
76 | return insn; | ||
77 | } | ||
78 | |||
79 | static int __apply_alternatives(void *alt_region) | 36 | static int __apply_alternatives(void *alt_region) |
80 | { | 37 | { |
81 | struct alt_instr *alt; | 38 | struct alt_instr *alt; |
@@ -83,9 +40,6 @@ static int __apply_alternatives(void *alt_region) | |||
83 | u8 *origptr, *replptr; | 40 | u8 *origptr, *replptr; |
84 | 41 | ||
85 | for (alt = region->begin; alt < region->end; alt++) { | 42 | for (alt = region->begin; alt < region->end; alt++) { |
86 | u32 insn; | ||
87 | int i; | ||
88 | |||
89 | if (!cpus_have_cap(alt->cpufeature)) | 43 | if (!cpus_have_cap(alt->cpufeature)) |
90 | continue; | 44 | continue; |
91 | 45 | ||
@@ -95,12 +49,7 @@ static int __apply_alternatives(void *alt_region) | |||
95 | 49 | ||
96 | origptr = (u8 *)&alt->orig_offset + alt->orig_offset; | 50 | origptr = (u8 *)&alt->orig_offset + alt->orig_offset; |
97 | replptr = (u8 *)&alt->alt_offset + alt->alt_offset; | 51 | replptr = (u8 *)&alt->alt_offset + alt->alt_offset; |
98 | 52 | memcpy(origptr, replptr, alt->alt_len); | |
99 | for (i = 0; i < alt->alt_len; i += sizeof(insn)) { | ||
100 | insn = get_alt_insn(origptr + i, replptr + i); | ||
101 | aarch64_insn_write(origptr + i, insn); | ||
102 | } | ||
103 | |||
104 | flush_icache_range((uintptr_t)origptr, | 53 | flush_icache_range((uintptr_t)origptr, |
105 | (uintptr_t)(origptr + alt->alt_len)); | 54 | (uintptr_t)(origptr + alt->alt_len)); |
106 | } | 55 | } |