aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm64/include/asm/alternative.h3
-rw-r--r--arch/arm64/kernel/alternative.c29
-rw-r--r--arch/arm64/kernel/module.c18
-rw-r--r--arch/arm64/kernel/smp.c2
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
16void apply_alternatives(void); 16void apply_alternatives_all(void);
17void apply_alternatives(void *start, size_t length);
17void free_alternatives_memory(void); 18void 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
29extern struct alt_instr __alt_instructions[], __alt_instructions_end[]; 29extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
30 30
31static int __apply_alternatives(void *dummy) 31struct alt_region {
32 struct alt_instr *begin;
33 struct alt_instr *end;
34};
35
36static 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
54void apply_alternatives(void) 60void 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, &region, NULL);
69}
70
71void 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(&region);
58} 79}
59 80
60void free_alternatives_memory(void) 81void 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
399int 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)
310void __init smp_cpus_done(unsigned int max_cpus) 310void __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
316void __init smp_prepare_boot_cpu(void) 316void __init smp_prepare_boot_cpu(void)