diff options
-rw-r--r-- | arch/arm64/include/asm/alternative.h | 3 | ||||
-rw-r--r-- | arch/arm64/kernel/alternative.c | 29 | ||||
-rw-r--r-- | arch/arm64/kernel/module.c | 18 | ||||
-rw-r--r-- | arch/arm64/kernel/smp.c | 2 |
4 files changed, 46 insertions, 6 deletions
diff --git a/arch/arm64/include/asm/alternative.h b/arch/arm64/include/asm/alternative.h index f6d206e7f9e9..d261f01e2bae 100644 --- a/arch/arm64/include/asm/alternative.h +++ b/arch/arm64/include/asm/alternative.h | |||
@@ -13,7 +13,8 @@ struct alt_instr { | |||
13 | u8 alt_len; /* size of new instruction(s), <= orig_len */ | 13 | u8 alt_len; /* size of new instruction(s), <= orig_len */ |
14 | }; | 14 | }; |
15 | 15 | ||
16 | void apply_alternatives(void); | 16 | void apply_alternatives_all(void); |
17 | void apply_alternatives(void *start, size_t length); | ||
17 | void free_alternatives_memory(void); | 18 | void free_alternatives_memory(void); |
18 | 19 | ||
19 | #define ALTINSTR_ENTRY(feature) \ | 20 | #define ALTINSTR_ENTRY(feature) \ |
diff --git a/arch/arm64/kernel/alternative.c b/arch/arm64/kernel/alternative.c index 1a3badab800a..ad7821d64a1d 100644 --- a/arch/arm64/kernel/alternative.c +++ b/arch/arm64/kernel/alternative.c | |||
@@ -28,12 +28,18 @@ | |||
28 | 28 | ||
29 | extern struct alt_instr __alt_instructions[], __alt_instructions_end[]; | 29 | extern struct alt_instr __alt_instructions[], __alt_instructions_end[]; |
30 | 30 | ||
31 | static int __apply_alternatives(void *dummy) | 31 | struct alt_region { |
32 | struct alt_instr *begin; | ||
33 | struct alt_instr *end; | ||
34 | }; | ||
35 | |||
36 | static int __apply_alternatives(void *alt_region) | ||
32 | { | 37 | { |
33 | struct alt_instr *alt; | 38 | struct alt_instr *alt; |
39 | struct alt_region *region = alt_region; | ||
34 | u8 *origptr, *replptr; | 40 | u8 *origptr, *replptr; |
35 | 41 | ||
36 | for (alt = __alt_instructions; alt < __alt_instructions_end; alt++) { | 42 | for (alt = region->begin; alt < region->end; alt++) { |
37 | if (!cpus_have_cap(alt->cpufeature)) | 43 | if (!cpus_have_cap(alt->cpufeature)) |
38 | continue; | 44 | continue; |
39 | 45 | ||
@@ -51,10 +57,25 @@ static int __apply_alternatives(void *dummy) | |||
51 | return 0; | 57 | return 0; |
52 | } | 58 | } |
53 | 59 | ||
54 | void apply_alternatives(void) | 60 | void apply_alternatives_all(void) |
55 | { | 61 | { |
62 | struct alt_region region = { | ||
63 | .begin = __alt_instructions, | ||
64 | .end = __alt_instructions_end, | ||
65 | }; | ||
66 | |||
56 | /* better not try code patching on a live SMP system */ | 67 | /* better not try code patching on a live SMP system */ |
57 | stop_machine(__apply_alternatives, NULL, NULL); | 68 | stop_machine(__apply_alternatives, ®ion, NULL); |
69 | } | ||
70 | |||
71 | void apply_alternatives(void *start, size_t length) | ||
72 | { | ||
73 | struct alt_region region = { | ||
74 | .begin = start, | ||
75 | .end = start + length, | ||
76 | }; | ||
77 | |||
78 | __apply_alternatives(®ion); | ||
58 | } | 79 | } |
59 | 80 | ||
60 | void free_alternatives_memory(void) | 81 | void free_alternatives_memory(void) |
diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c index 1eb1cc955139..fd027b101de5 100644 --- a/arch/arm64/kernel/module.c +++ b/arch/arm64/kernel/module.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/moduleloader.h> | 26 | #include <linux/moduleloader.h> |
27 | #include <linux/vmalloc.h> | 27 | #include <linux/vmalloc.h> |
28 | #include <asm/insn.h> | 28 | #include <asm/insn.h> |
29 | #include <asm/sections.h> | ||
29 | 30 | ||
30 | #define AARCH64_INSN_IMM_MOVNZ AARCH64_INSN_IMM_MAX | 31 | #define AARCH64_INSN_IMM_MOVNZ AARCH64_INSN_IMM_MAX |
31 | #define AARCH64_INSN_IMM_MOVK AARCH64_INSN_IMM_16 | 32 | #define AARCH64_INSN_IMM_MOVK AARCH64_INSN_IMM_16 |
@@ -394,3 +395,20 @@ overflow: | |||
394 | me->name, (int)ELF64_R_TYPE(rel[i].r_info), val); | 395 | me->name, (int)ELF64_R_TYPE(rel[i].r_info), val); |
395 | return -ENOEXEC; | 396 | return -ENOEXEC; |
396 | } | 397 | } |
398 | |||
399 | int module_finalize(const Elf_Ehdr *hdr, | ||
400 | const Elf_Shdr *sechdrs, | ||
401 | struct module *me) | ||
402 | { | ||
403 | const Elf_Shdr *s, *se; | ||
404 | const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; | ||
405 | |||
406 | for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++) { | ||
407 | if (strcmp(".altinstructions", secstrs + s->sh_name) == 0) { | ||
408 | apply_alternatives((void *)s->sh_addr, s->sh_size); | ||
409 | return 0; | ||
410 | } | ||
411 | } | ||
412 | |||
413 | return 0; | ||
414 | } | ||
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 0ef87896e4ae..7ae6ee085261 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c | |||
@@ -310,7 +310,7 @@ void cpu_die(void) | |||
310 | void __init smp_cpus_done(unsigned int max_cpus) | 310 | void __init smp_cpus_done(unsigned int max_cpus) |
311 | { | 311 | { |
312 | pr_info("SMP: Total of %d processors activated.\n", num_online_cpus()); | 312 | pr_info("SMP: Total of %d processors activated.\n", num_online_cpus()); |
313 | apply_alternatives(); | 313 | apply_alternatives_all(); |
314 | } | 314 | } |
315 | 315 | ||
316 | void __init smp_prepare_boot_cpu(void) | 316 | void __init smp_prepare_boot_cpu(void) |