* [PATCH 1/6] arm64: add cpu_capabilities bitmap
2014-11-14 15:54 [PATCH 0/6] arm64: alternatives runtime patching Andre Przywara
@ 2014-11-14 15:54 ` Andre Przywara
2014-11-14 15:54 ` [PATCH 2/6] arm64: add alternative runtime patching Andre Przywara
` (6 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Andre Przywara @ 2014-11-14 15:54 UTC (permalink / raw)
To: linux-arm-kernel
For taking note if at least one CPU in the system needs a bug
workaround or would benefit from a code optimization, we create a new
bitmap to hold (artificial) feature bits.
Since elf_hwcap is part of the userland ABI, we keep it alone and
introduce a new data structure for that (along with some accessors).
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
arch/arm64/include/asm/cpufeature.h | 20 ++++++++++++++++++++
arch/arm64/kernel/setup.c | 3 +++
2 files changed, 23 insertions(+)
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index cd4ac05..20b2b3d6 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -21,9 +21,29 @@
#define MAX_CPU_FEATURES (8 * sizeof(elf_hwcap))
#define cpu_feature(x) ilog2(HWCAP_ ## x)
+#define NCAPS 0
+
+extern DECLARE_BITMAP(cpu_hwcaps, NCAPS);
+
static inline bool cpu_have_feature(unsigned int num)
{
return elf_hwcap & (1UL << num);
}
+static inline bool cpus_have_cap(unsigned int num)
+{
+ if (num >= NCAPS)
+ return false;
+ return test_bit(num, cpu_hwcaps);
+}
+
+static inline void cpus_set_cap(unsigned int num)
+{
+ if (num >= NCAPS)
+ pr_warn("Attempt to set an illegal CPU capability (%d >= %d)\n",
+ num, NCAPS);
+ else
+ __set_bit(num, cpu_hwcaps);
+}
+
#endif
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index 2437196..453acd6 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -49,6 +49,7 @@
#include <asm/cputype.h>
#include <asm/elf.h>
#include <asm/cputable.h>
+#include <asm/cpufeature.h>
#include <asm/cpu_ops.h>
#include <asm/sections.h>
#include <asm/setup.h>
@@ -77,6 +78,8 @@ unsigned int compat_elf_hwcap __read_mostly = COMPAT_ELF_HWCAP_DEFAULT;
unsigned int compat_elf_hwcap2 __read_mostly;
#endif
+DECLARE_BITMAP(cpu_hwcaps, NCAPS);
+
static const char *cpu_name;
static const char *machine_name;
phys_addr_t __fdt_pointer __initdata;
--
1.7.9.5
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 2/6] arm64: add alternative runtime patching
2014-11-14 15:54 [PATCH 0/6] arm64: alternatives runtime patching Andre Przywara
2014-11-14 15:54 ` [PATCH 1/6] arm64: add cpu_capabilities bitmap Andre Przywara
@ 2014-11-14 15:54 ` Andre Przywara
2014-11-14 15:54 ` [PATCH 3/6] arm64: detect silicon revisions and set cap bits accordingly Andre Przywara
` (5 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Andre Przywara @ 2014-11-14 15:54 UTC (permalink / raw)
To: linux-arm-kernel
With a blatant copy of some x86 bits we introduce the alternative
runtime patching "framework" to arm64.
This is quite basic for now and we only provide the functions we need
at this time.
This is connected to the newly introduced feature bits.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
arch/arm64/include/asm/alternative-asm.h | 16 ++++++++
arch/arm64/include/asm/alternative.h | 43 ++++++++++++++++++++
arch/arm64/kernel/Makefile | 2 +-
arch/arm64/kernel/alternative.c | 64 ++++++++++++++++++++++++++++++
arch/arm64/kernel/smp.c | 2 +
arch/arm64/kernel/vmlinux.lds.S | 11 +++++
arch/arm64/mm/init.c | 2 +
7 files changed, 139 insertions(+), 1 deletion(-)
create mode 100644 arch/arm64/include/asm/alternative-asm.h
create mode 100644 arch/arm64/include/asm/alternative.h
create mode 100644 arch/arm64/kernel/alternative.c
diff --git a/arch/arm64/include/asm/alternative-asm.h b/arch/arm64/include/asm/alternative-asm.h
new file mode 100644
index 0000000..5ee9340
--- /dev/null
+++ b/arch/arm64/include/asm/alternative-asm.h
@@ -0,0 +1,16 @@
+#ifndef __ASM_ALTERNATIVE_ASM_H
+#define __ASM_ALTERNATIVE_ASM_H
+
+#ifdef __ASSEMBLY__
+
+.macro altinstruction_entry orig_offset alt_offset feature orig_len alt_len
+ .word \orig_offset - .
+ .word \alt_offset - .
+ .hword \feature
+ .byte \orig_len
+ .byte \alt_len
+.endm
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_ALTERNATIVE_ASM_H */
diff --git a/arch/arm64/include/asm/alternative.h b/arch/arm64/include/asm/alternative.h
new file mode 100644
index 0000000..f6d206e
--- /dev/null
+++ b/arch/arm64/include/asm/alternative.h
@@ -0,0 +1,43 @@
+#ifndef __ASM_ALTERNATIVE_H
+#define __ASM_ALTERNATIVE_H
+
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/stringify.h>
+
+struct alt_instr {
+ s32 orig_offset; /* offset to original instruction */
+ s32 alt_offset; /* offset to replacement instruction */
+ u16 cpufeature; /* cpufeature bit set for replacement */
+ u8 orig_len; /* size of original instruction(s) */
+ u8 alt_len; /* size of new instruction(s), <= orig_len */
+};
+
+void apply_alternatives(void);
+void free_alternatives_memory(void);
+
+#define ALTINSTR_ENTRY(feature) \
+ " .word 661b - .\n" /* label */ \
+ " .word 663f - .\n" /* new instruction */ \
+ " .hword " __stringify(feature) "\n" /* feature bit */ \
+ " .byte 662b-661b\n" /* source len */ \
+ " .byte 664f-663f\n" /* replacement len */
+
+/* alternative assembly primitive: */
+#define ALTERNATIVE(oldinstr, newinstr, feature) \
+ "661:\n\t" \
+ oldinstr "\n" \
+ "662:\n" \
+ ".pushsection .altinstructions,\"a\"\n" \
+ ALTINSTR_ENTRY(feature) \
+ ".popsection\n" \
+ ".pushsection .altinstr_replacement, \"a\"\n" \
+ "663:\n\t" \
+ newinstr "\n" \
+ "664:\n\t" \
+ ".popsection\n\t" \
+ ".if ((664b-663b) != (662b-661b))\n\t" \
+ " .error \"Alternatives instruction length mismatch\"\n\t"\
+ ".endif\n"
+
+#endif /* __ASM_ALTERNATIVE_H */
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 5bd029b..65b5a8e 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -15,7 +15,7 @@ arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \
entry-fpsimd.o process.o ptrace.o setup.o signal.o \
sys.o stacktrace.o time.o traps.o io.o vdso.o \
hyp-stub.o psci.o cpu_ops.o insn.o return_address.o \
- cpuinfo.o
+ cpuinfo.o alternative.o
arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \
sys_compat.o
diff --git a/arch/arm64/kernel/alternative.c b/arch/arm64/kernel/alternative.c
new file mode 100644
index 0000000..5992ea4
--- /dev/null
+++ b/arch/arm64/kernel/alternative.c
@@ -0,0 +1,64 @@
+/*
+ * alternative runtime patching
+ * inspired by the x86 version
+ *
+ * Copyright (C) 2014 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define pr_fmt(fmt) "alternative: " fmt
+
+#include <linux/init.h>
+#include <linux/cpu.h>
+#include <asm/cacheflush.h>
+#include <asm/alternative.h>
+#include <asm/cpufeature.h>
+#include <linux/stop_machine.h>
+
+extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
+
+static int __apply_alternatives(void *dummy)
+{
+ struct alt_instr *alt;
+ u8 *origptr, *replptr;
+
+ for (alt = __alt_instructions; alt < __alt_instructions_end; alt++) {
+ if (!cpus_have_cap(alt->cpufeature))
+ continue;
+
+ BUG_ON(alt->alt_len > alt->orig_len);
+
+ pr_info_once("patching kernel code\n");
+
+ origptr = (u8 *)&alt->orig_offset + alt->orig_offset;
+ replptr = (u8 *)&alt->alt_offset + alt->alt_offset;
+ memcpy(origptr, replptr, alt->alt_len);
+ flush_icache_range((uintptr_t)origptr,
+ (uintptr_t)(origptr + alt->alt_len));
+ }
+
+ return 0;
+}
+
+void apply_alternatives(void)
+{
+ /* better not try code patching on a live SMP system */
+ stop_machine(__apply_alternatives, NULL, NULL);
+}
+
+void free_alternatives_memory(void)
+{
+ free_reserved_area(__alt_instructions, __alt_instructions_end,
+ 0, "alternatives");
+}
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index b06d1d9..0ef8789 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -37,6 +37,7 @@
#include <linux/of.h>
#include <linux/irq_work.h>
+#include <asm/alternative.h>
#include <asm/atomic.h>
#include <asm/cacheflush.h>
#include <asm/cpu.h>
@@ -309,6 +310,7 @@ void cpu_die(void)
void __init smp_cpus_done(unsigned int max_cpus)
{
pr_info("SMP: Total of %d processors activated.\n", num_online_cpus());
+ apply_alternatives();
}
void __init smp_prepare_boot_cpu(void)
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index edf8715..2f60029 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -100,6 +100,17 @@ SECTIONS
. = ALIGN(PAGE_SIZE);
__init_end = .;
+ . = ALIGN(4);
+ .altinstructions : {
+ __alt_instructions = .;
+ *(.altinstructions)
+ __alt_instructions_end = .;
+ }
+ .altinstr_replacement : {
+ *(.altinstr_replacement)
+ }
+
+ . = ALIGN(PAGE_SIZE);
_data = .;
_sdata = .;
RW_DATA_SECTION(64, PAGE_SIZE, THREAD_SIZE)
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 494297c..bac492c 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -39,6 +39,7 @@
#include <asm/setup.h>
#include <asm/sizes.h>
#include <asm/tlb.h>
+#include <asm/alternative.h>
#include "mm.h"
@@ -325,6 +326,7 @@ void __init mem_init(void)
void free_initmem(void)
{
free_initmem_default(0);
+ free_alternatives_memory();
}
#ifdef CONFIG_BLK_DEV_INITRD
--
1.7.9.5
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 3/6] arm64: detect silicon revisions and set cap bits accordingly
2014-11-14 15:54 [PATCH 0/6] arm64: alternatives runtime patching Andre Przywara
2014-11-14 15:54 ` [PATCH 1/6] arm64: add cpu_capabilities bitmap Andre Przywara
2014-11-14 15:54 ` [PATCH 2/6] arm64: add alternative runtime patching Andre Przywara
@ 2014-11-14 15:54 ` Andre Przywara
2014-11-14 15:54 ` [PATCH 4/6] arm64: add Cortex-A53 cache errata workaround Andre Przywara
` (4 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Andre Przywara @ 2014-11-14 15:54 UTC (permalink / raw)
To: linux-arm-kernel
After each CPU has been started, we iterate through a list of
CPU features or bugs to detect CPUs which need (or could benefit
from) kernel code patches.
For each feature/bug there is a function which checks if that
particular CPU is affected. We will later provide some more generic
functions for common things like testing for certain MIDR ranges.
We do this for every CPU to cover big.LITTLE systems properly as
well.
If a certain feature/bug has been detected, the capability bit will
be set, so that later the call to apply_alternatives() will trigger
the actual code patching.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
arch/arm64/include/asm/cpufeature.h | 2 ++
arch/arm64/kernel/Makefile | 2 +-
arch/arm64/kernel/cpu_errata.c | 59 +++++++++++++++++++++++++++++++++++
arch/arm64/kernel/cpuinfo.c | 3 ++
4 files changed, 65 insertions(+), 1 deletion(-)
create mode 100644 arch/arm64/kernel/cpu_errata.c
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index 20b2b3d6..744eaf7 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -46,4 +46,6 @@ static inline void cpus_set_cap(unsigned int num)
__set_bit(num, cpu_hwcaps);
}
+void check_local_cpu_errata(void);
+
#endif
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 65b5a8e..da22728 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -15,7 +15,7 @@ arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \
entry-fpsimd.o process.o ptrace.o setup.o signal.o \
sys.o stacktrace.o time.o traps.o io.o vdso.o \
hyp-stub.o psci.o cpu_ops.o insn.o return_address.o \
- cpuinfo.o alternative.o
+ cpuinfo.o cpu_errata.o alternative.o
arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \
sys_compat.o
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
new file mode 100644
index 0000000..9332cf7
--- /dev/null
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -0,0 +1,59 @@
+/*
+ * Contains CPU specific errata definitions
+ *
+ * Copyright (C) 2014 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define pr_fmt(fmt) "alternative: " fmt
+
+#include <linux/types.h>
+#include <asm/cpu.h>
+#include <asm/cputype.h>
+#include <asm/cpufeature.h>
+
+/*
+ * Add a struct or another datatype to the union below if you need
+ * different means to detect an affected CPU.
+ */
+struct arm64_cpu_capabilities {
+ const char *desc;
+ u16 capability;
+ bool (*is_affected)(struct arm64_cpu_capabilities *);
+ union {
+ struct {
+ u32 midr_model;
+ u32 midr_range_min, midr_range_max;
+ };
+ };
+};
+
+struct arm64_cpu_capabilities arm64_errata[] = {
+ {}
+};
+
+void check_local_cpu_errata(void)
+{
+ struct arm64_cpu_capabilities *cpus = arm64_errata;
+ int i;
+
+ for (i = 0; cpus[i].desc; i++) {
+ if (!cpus[i].is_affected(&cpus[i]))
+ continue;
+
+ if (!cpus_have_cap(cpus[i].capability))
+ pr_info("enabling workaround for %s\n", cpus[i].desc);
+ cpus_set_cap(cpus[i].capability);
+ }
+}
diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c
index 504fdaa..16d6d03 100644
--- a/arch/arm64/kernel/cpuinfo.c
+++ b/arch/arm64/kernel/cpuinfo.c
@@ -18,6 +18,7 @@
#include <asm/cachetype.h>
#include <asm/cpu.h>
#include <asm/cputype.h>
+#include <asm/cpufeature.h>
#include <linux/bitops.h>
#include <linux/bug.h>
@@ -186,6 +187,8 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
info->reg_id_pfr1 = read_cpuid(ID_PFR1_EL1);
cpuinfo_detect_icache_policy(info);
+
+ check_local_cpu_errata();
}
void cpuinfo_store_cpu(void)
--
1.7.9.5
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 4/6] arm64: add Cortex-A53 cache errata workaround
2014-11-14 15:54 [PATCH 0/6] arm64: alternatives runtime patching Andre Przywara
` (2 preceding siblings ...)
2014-11-14 15:54 ` [PATCH 3/6] arm64: detect silicon revisions and set cap bits accordingly Andre Przywara
@ 2014-11-14 15:54 ` Andre Przywara
2014-11-14 15:54 ` [PATCH 5/6] arm64: add Cortex-A57 erratum 832075 workaround Andre Przywara
` (3 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Andre Przywara @ 2014-11-14 15:54 UTC (permalink / raw)
To: linux-arm-kernel
The ARM errata 819472, 826319, 827319 and 824069 define the same
workaround for these hardware issues in certain Cortex-A53 parts.
Use the new alternatives framework and the CPU MIDR detection to
patch "cache clean" into "cache clean and invalidate" instructions if
an affected CPU is detected at runtime.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
arch/arm64/include/asm/alternative-asm.h | 13 ++++++++++++
arch/arm64/include/asm/cpufeature.h | 8 +++++++-
arch/arm64/include/asm/cputype.h | 5 +++++
arch/arm64/kernel/cpu_errata.c | 32 +++++++++++++++++++++++++++++-
arch/arm64/mm/cache.S | 4 +++-
5 files changed, 59 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/include/asm/alternative-asm.h b/arch/arm64/include/asm/alternative-asm.h
index 5ee9340..919a678 100644
--- a/arch/arm64/include/asm/alternative-asm.h
+++ b/arch/arm64/include/asm/alternative-asm.h
@@ -11,6 +11,19 @@
.byte \alt_len
.endm
+.macro alternative_insn insn1 insn2 cap
+661: \insn1
+662: .pushsection .altinstructions, "a"
+ altinstruction_entry 661b, 663f, \cap, 662b-661b, 664f-663f
+ .popsection
+ .pushsection .altinstr_replacement, "ax"
+663: \insn2
+664: .popsection
+ .if ((664b-663b) != (662b-661b))
+ .error "Alternatives instruction length mismatch"
+ .endif
+.endm
+
#endif /* __ASSEMBLY__ */
#endif /* __ASM_ALTERNATIVE_ASM_H */
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index 744eaf7..92b6ee4 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -21,7 +21,11 @@
#define MAX_CPU_FEATURES (8 * sizeof(elf_hwcap))
#define cpu_feature(x) ilog2(HWCAP_ ## x)
-#define NCAPS 0
+#define ARM64_WORKAROUND_CLEAN_CACHE 0
+
+#define NCAPS 1
+
+#ifndef __ASSEMBLY__
extern DECLARE_BITMAP(cpu_hwcaps, NCAPS);
@@ -48,4 +52,6 @@ static inline void cpus_set_cap(unsigned int num)
void check_local_cpu_errata(void);
+#endif /* __ASSEMBLY__ */
+
#endif
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h
index 379d0b8..8adb986 100644
--- a/arch/arm64/include/asm/cputype.h
+++ b/arch/arm64/include/asm/cputype.h
@@ -57,6 +57,11 @@
#define MIDR_IMPLEMENTOR(midr) \
(((midr) & MIDR_IMPLEMENTOR_MASK) >> MIDR_IMPLEMENTOR_SHIFT)
+#define MIDR_CPU_PART(imp, partnum) \
+ (((imp) << MIDR_IMPLEMENTOR_SHIFT) | \
+ (0xf << MIDR_ARCHITECTURE_SHIFT) | \
+ ((partnum) << MIDR_PARTNUM_SHIFT))
+
#define ARM_CPU_IMP_ARM 0x41
#define ARM_CPU_IMP_APM 0x50
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index 9332cf7..875fb2c 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -23,6 +23,8 @@
#include <asm/cputype.h>
#include <asm/cpufeature.h>
+#define MIDR_CORTEX_A53 MIDR_CPU_PART(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53)
+
/*
* Add a struct or another datatype to the union below if you need
* different means to detect an affected CPU.
@@ -39,8 +41,36 @@ struct arm64_cpu_capabilities {
};
};
+#define CPU_MODEL_MASK (MIDR_IMPLEMENTOR_MASK | MIDR_PARTNUM_MASK | \
+ MIDR_ARCHITECTURE_MASK)
+
+static bool is_affected_midr_range(struct arm64_cpu_capabilities *entry)
+{
+ u32 midr = read_cpuid_id();
+
+ if ((midr & CPU_MODEL_MASK) != entry->midr_model)
+ return false;
+
+ midr &= MIDR_REVISION_MASK | MIDR_VARIANT_MASK;
+
+ return (midr >= entry->midr_range_min && midr <= entry->midr_range_max);
+}
+
+#define MIDR_RANGE(model, min, max) \
+ .is_affected = is_affected_midr_range, \
+ .midr_model = model, \
+ .midr_range_min = min, \
+ .midr_range_max = max
+
struct arm64_cpu_capabilities arm64_errata[] = {
- {}
+ {
+ /* Cortex-A53 r0p[012] */
+ .desc = "ARM errata 826319, 827319, 824069",
+ .capability = ARM64_WORKAROUND_CLEAN_CACHE,
+ MIDR_RANGE(MIDR_CORTEX_A53, 0x00, 0x02),
+ },
+ {
+ }
};
void check_local_cpu_errata(void)
diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S
index 2366383..8eaf185 100644
--- a/arch/arm64/mm/cache.S
+++ b/arch/arm64/mm/cache.S
@@ -20,6 +20,8 @@
#include <linux/linkage.h>
#include <linux/init.h>
#include <asm/assembler.h>
+#include <asm/cpufeature.h>
+#include <asm/alternative-asm.h>
#include "proc-macros.S"
@@ -210,7 +212,7 @@ __dma_clean_range:
dcache_line_size x2, x3
sub x3, x2, #1
bic x0, x0, x3
-1: dc cvac, x0 // clean D / U line
+1: alternative_insn "dc cvac, x0", "dc civac, x0", ARM64_WORKAROUND_CLEAN_CACHE
add x0, x0, x2
cmp x0, x1
b.lo 1b
--
1.7.9.5
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 5/6] arm64: add Cortex-A57 erratum 832075 workaround
2014-11-14 15:54 [PATCH 0/6] arm64: alternatives runtime patching Andre Przywara
` (3 preceding siblings ...)
2014-11-14 15:54 ` [PATCH 4/6] arm64: add Cortex-A53 cache errata workaround Andre Przywara
@ 2014-11-14 15:54 ` Andre Przywara
2014-11-14 15:54 ` [PATCH 6/6] arm64: protect alternatives workarounds with Kconfig options Andre Przywara
` (2 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Andre Przywara @ 2014-11-14 15:54 UTC (permalink / raw)
To: linux-arm-kernel
The ARM erratum 832075 applies to certain revisions of Cortex-A57,
one of the workarounds is to change device loads into using
load-aquire semantics.
This is achieved using the alternatives framework.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
arch/arm64/include/asm/cpufeature.h | 5 +++--
arch/arm64/include/asm/io.h | 23 +++++++++++++++++++----
arch/arm64/kernel/cpu_errata.c | 7 +++++++
3 files changed, 29 insertions(+), 6 deletions(-)
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index 92b6ee4..0362f80 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -21,9 +21,10 @@
#define MAX_CPU_FEATURES (8 * sizeof(elf_hwcap))
#define cpu_feature(x) ilog2(HWCAP_ ## x)
-#define ARM64_WORKAROUND_CLEAN_CACHE 0
+#define ARM64_WORKAROUND_CLEAN_CACHE 0
+#define ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE 1
-#define NCAPS 1
+#define NCAPS 2
#ifndef __ASSEMBLY__
diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
index 79f1d519..75825b6 100644
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -28,6 +28,8 @@
#include <asm/barrier.h>
#include <asm/pgtable.h>
#include <asm/early_ioremap.h>
+#include <asm/alternative.h>
+#include <asm/cpufeature.h>
#include <xen/xen.h>
@@ -57,28 +59,41 @@ static inline void __raw_writeq(u64 val, volatile void __iomem *addr)
static inline u8 __raw_readb(const volatile void __iomem *addr)
{
u8 val;
- asm volatile("ldrb %w0, [%1]" : "=r" (val) : "r" (addr));
+ asm volatile(ALTERNATIVE("ldrb %w0, [%1]",
+ "ldarb %w0, [%1]",
+ ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE)
+ : "=r" (val) : "r" (addr));
return val;
}
static inline u16 __raw_readw(const volatile void __iomem *addr)
{
u16 val;
- asm volatile("ldrh %w0, [%1]" : "=r" (val) : "r" (addr));
+
+ asm volatile(ALTERNATIVE("ldrh %w0, [%1]",
+ "ldarh %w0, [%1]",
+ ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE)
+ : "=r" (val) : "r" (addr));
return val;
}
static inline u32 __raw_readl(const volatile void __iomem *addr)
{
u32 val;
- asm volatile("ldr %w0, [%1]" : "=r" (val) : "r" (addr));
+ asm volatile(ALTERNATIVE("ldr %w0, [%1]",
+ "ldar %w0, [%1]",
+ ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE)
+ : "=r" (val) : "r" (addr));
return val;
}
static inline u64 __raw_readq(const volatile void __iomem *addr)
{
u64 val;
- asm volatile("ldr %0, [%1]" : "=r" (val) : "r" (addr));
+ asm volatile(ALTERNATIVE("ldr %0, [%1]",
+ "ldar %0, [%1]",
+ ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE)
+ : "=r" (val) : "r" (addr));
return val;
}
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index 875fb2c..f232849 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -24,6 +24,7 @@
#include <asm/cpufeature.h>
#define MIDR_CORTEX_A53 MIDR_CPU_PART(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53)
+#define MIDR_CORTEX_A57 MIDR_CPU_PART(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57)
/*
* Add a struct or another datatype to the union below if you need
@@ -70,6 +71,12 @@ struct arm64_cpu_capabilities arm64_errata[] = {
MIDR_RANGE(MIDR_CORTEX_A53, 0x00, 0x02),
},
{
+ /* Cortex-A57 r0p0 - r1p2 */
+ .desc = "ARM erratum 832075",
+ .capability = ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE,
+ MIDR_RANGE(MIDR_CORTEX_A57, 0x00, 0x12),
+ },
+ {
}
};
--
1.7.9.5
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 6/6] arm64: protect alternatives workarounds with Kconfig options
2014-11-14 15:54 [PATCH 0/6] arm64: alternatives runtime patching Andre Przywara
` (4 preceding siblings ...)
2014-11-14 15:54 ` [PATCH 5/6] arm64: add Cortex-A57 erratum 832075 workaround Andre Przywara
@ 2014-11-14 15:54 ` Andre Przywara
2014-11-14 16:20 ` [PATCH 0/6] arm64: alternatives runtime patching Arnd Bergmann
2014-11-25 15:29 ` Will Deacon
7 siblings, 0 replies; 11+ messages in thread
From: Andre Przywara @ 2014-11-14 15:54 UTC (permalink / raw)
To: linux-arm-kernel
Not all of the errata we have workarounds for apply necessarily to all
SoCs, so people compiling a kernel for one very specific SoC may not
need to patch the kernel.
Introduce a new submenu in the "Platform selection" menu to allow
people to turn off certain bugs if they are not affected. By default
all of them are enabled.
Normal users or distribution kernels shouldn't bother to deselect any
bugs here, since the alternatives framework will take care of
patching them in only if needed.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
arch/arm64/Kconfig | 107 ++++++++++++++++++++++++++++++++++++++++
arch/arm64/kernel/cpu_errata.c | 14 ++++++
2 files changed, 121 insertions(+)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 9532f8d..e484aaa 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -162,6 +162,113 @@ config ARCH_XGENE
help
This enables support for AppliedMicro X-Gene SOC Family
+menu "ARM errata workarounds via the alternatives framework"
+
+config ARM64_ERRATUM_826319
+ bool "Cortex-A53: 826319: System might deadlock if a write cannot complete until read data is accepted"
+ default y
+ help
+ This option adds an alternative code sequence to work around ARM
+ erratum 826319 on Cortex-A53 parts up to r0p2 with an AMBA 4 ACE or
+ AXI master interface and an L2 cache.
+
+ If a Cortex-A53 uses an AMBA AXI4 ACE interface to other processors
+ and is unable to accept a certain write via this interface, it will
+ not progress on read data presented on the read data channel and the
+ system can deadlock.
+
+ The workaround promotes data cache clean instructions to
+ data cache clean-and-invalidate.
+ Please note that this does not necessarily enable the workaround,
+ as it depends on the alternative framework, which will only patch
+ the kernel if an affected CPU is detected.
+
+ If unsure, say Y.
+
+config ARM64_ERRATUM_827319
+ bool "Cortex-A53: 827319: Data cache clean instructions might cause overlapping transactions to the interconnect"
+ default y
+ help
+ This option adds an alternative code sequence to work around ARM
+ erratum 827319 on Cortex-A53 parts up to r0p2 with an AMBA 5 CHI
+ master interface and an L2 cache.
+
+ Under certain conditions this erratum can cause a clean line eviction
+ to occur at the same time as another transaction to the same address
+ on the AMBA 5 CHI interface, which can cause data corruption if the
+ interconnect reorders the two transactions.
+
+ The workaround promotes data cache clean instructions to
+ data cache clean-and-invalidate.
+ Please note that this does not necessarily enable the workaround,
+ as it depends on the alternative framework, which will only patch
+ the kernel if an affected CPU is detected.
+
+ If unsure, say Y.
+
+config ARM64_ERRATUM_824069
+ bool "Cortex-A53: 824069: Cache line might not be marked as clean after a CleanShared snoop"
+ default y
+ help
+ This option adds an alternative code sequence to work around ARM
+ erratum 824069 on Cortex-A53 parts up to r0p2 when it is connected
+ to a coherent interconnect.
+
+ If a Cortex-A53 processor is executing a store or prefetch for
+ write instruction at the same time as a processor in another
+ cluster is executing a cache maintenance operation to the same
+ address, then this erratum might cause a clean cache line to be
+ incorrectly marked as dirty.
+
+ The workaround promotes data cache clean instructions to
+ data cache clean-and-invalidate.
+ Please note that this option does not necessarily enable the
+ workaround, as it depends on the alternative framework, which will
+ only patch the kernel if an affected CPU is detected.
+
+ If unsure, say Y.
+
+config ARM64_ERRATUM_819472
+ bool "Cortex-A53: 819472: Store exclusive instructions might cause data corruption"
+ default y
+ help
+ This option adds an alternative code sequence to work around ARM
+ erratum 819472 on Cortex-A53 parts up to r0p1 with an L2 cache
+ present when it is connected to a coherent interconnect.
+
+ If the processor is executing a load and store exclusive sequence at
+ the same time as a processor in another cluster is executing a cache
+ maintenance operation to the same address, then this erratum might
+ cause data corruption.
+
+ The workaround promotes data cache clean instructions to
+ data cache clean-and-invalidate.
+ Please note that this does not necessarily enable the workaround,
+ as it depends on the alternative framework, which will only patch
+ the kernel if an affected CPU is detected.
+
+ If unsure, say Y.
+
+config ARM64_ERRATUM_832075
+ bool "Cortex-A57: possible deadlock on mixing exclusive memory accesses with device loads"
+ default y
+ help
+ This option adds an alternative code sequence to work around ARM
+ erratum 832075 on Cortex-A57 parts up to r1p2.
+
+ Affected Cortex-A57 parts might deadlock when exclusive load/store
+ instructions to Write-Back memory are mixed with Device loads.
+
+ The workaround is to promote device loads to use Load-Acquire
+ semantics.
+ Please note that this does not necessarily enable the workaround,
+ as it depends on the alternative framework, which will only patch
+ the kernel if an affected CPU is detected.
+
+ If unsure, say Y.
+
+endmenu
+
endmenu
menu "Bus support"
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index f232849..2a66456 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -64,18 +64,32 @@ static bool is_affected_midr_range(struct arm64_cpu_capabilities *entry)
.midr_range_max = max
struct arm64_cpu_capabilities arm64_errata[] = {
+#if defined(CONFIG_ARM64_ERRATUM_826319) || \
+ defined(CONFIG_ARM64_ERRATUM_827319) || \
+ defined(CONFIG_ARM64_ERRATUM_824069)
{
/* Cortex-A53 r0p[012] */
.desc = "ARM errata 826319, 827319, 824069",
.capability = ARM64_WORKAROUND_CLEAN_CACHE,
MIDR_RANGE(MIDR_CORTEX_A53, 0x00, 0x02),
},
+#endif
+#ifdef CONFIG_ARM64_ERRATUM_819472
+ {
+ /* Cortex-A53 r0p[01] */
+ .desc = "ARM errata 819472",
+ .capability = ARM64_WORKAROUND_CLEAN_CACHE,
+ MIDR_RANGE(MIDR_CORTEX_A53, 0x00, 0x01),
+ },
+#endif
+#ifdef CONFIG_ARM64_ERRATUM_832075
{
/* Cortex-A57 r0p0 - r1p2 */
.desc = "ARM erratum 832075",
.capability = ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE,
MIDR_RANGE(MIDR_CORTEX_A57, 0x00, 0x12),
},
+#endif
{
}
};
--
1.7.9.5
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 0/6] arm64: alternatives runtime patching
2014-11-14 15:54 [PATCH 0/6] arm64: alternatives runtime patching Andre Przywara
` (5 preceding siblings ...)
2014-11-14 15:54 ` [PATCH 6/6] arm64: protect alternatives workarounds with Kconfig options Andre Przywara
@ 2014-11-14 16:20 ` Arnd Bergmann
2014-11-14 16:31 ` Catalin Marinas
2014-11-25 15:29 ` Will Deacon
7 siblings, 1 reply; 11+ messages in thread
From: Arnd Bergmann @ 2014-11-14 16:20 UTC (permalink / raw)
To: linux-arm-kernel
On Friday 14 November 2014 15:54:06 Andre Przywara wrote:
> This series introduces alternatives runtime patching to arm64.
> This allows to patch assembly instruction at runtime to either
> fix hardware bugs or optimize for certain hardware features. Look
> at patch 5/6 for an example on how to use this.
>
Does it provide a measurable performance benefit? The implementation
seems ok, but we should only add the complexity for things that
actually need it and can't be handled just as well with a run-time
conditional.
Arnd
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 0/6] arm64: alternatives runtime patching
2014-11-14 16:20 ` [PATCH 0/6] arm64: alternatives runtime patching Arnd Bergmann
@ 2014-11-14 16:31 ` Catalin Marinas
0 siblings, 0 replies; 11+ messages in thread
From: Catalin Marinas @ 2014-11-14 16:31 UTC (permalink / raw)
To: linux-arm-kernel
On Fri, Nov 14, 2014 at 04:20:10PM +0000, Arnd Bergmann wrote:
> On Friday 14 November 2014 15:54:06 Andre Przywara wrote:
> > This series introduces alternatives runtime patching to arm64.
> > This allows to patch assembly instruction at runtime to either
> > fix hardware bugs or optimize for certain hardware features. Look
> > at patch 5/6 for an example on how to use this.
>
> Does it provide a measurable performance benefit? The implementation
> seems ok, but we should only add the complexity for things that
> actually need it and can't be handled just as well with a run-time
> conditional.
I'm not a fan of run-time code patching, however, I'm not sure we can
avoid them long term in an optimal way.
One example is errata workarounds we cannot predict. They may require
changing of a critical code path.
Another example is code like local_irq_disable which at some point we
may want to implement using GICv3 priority mask rather than PSTATE.I bit
change to allow NMI via standard IRQ.
And another big use-case I can't yet talk openly about is architecture
extensions.
What I would like to see at some point is a way to choose alternatives
at run-time via branches rather than code patching or even deciding at
compile time what features we have. These would help with debugging.
--
Catalin
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 0/6] arm64: alternatives runtime patching
2014-11-14 15:54 [PATCH 0/6] arm64: alternatives runtime patching Andre Przywara
` (6 preceding siblings ...)
2014-11-14 16:20 ` [PATCH 0/6] arm64: alternatives runtime patching Arnd Bergmann
@ 2014-11-25 15:29 ` Will Deacon
2014-11-28 13:40 ` [PATCH] arm64: add module support for alternatives fixups Andre Przywara
7 siblings, 1 reply; 11+ messages in thread
From: Will Deacon @ 2014-11-25 15:29 UTC (permalink / raw)
To: linux-arm-kernel
Hi Andre,
On Fri, Nov 14, 2014 at 03:54:06PM +0000, Andre Przywara wrote:
> This series introduces alternatives runtime patching to arm64.
> This allows to patch assembly instruction at runtime to either
> fix hardware bugs or optimize for certain hardware features. Look
> at patch 5/6 for an example on how to use this.
>
> The code is heavily based on the x86 implementation.
> Currently this is focussed on fixing CPU errata, but in the future
> runtime optimizations for new CPU features are planned.
>
> Patch 1/6 introduces a new cpu_hwcaps bitmap, which holds kernel
> internal CPU feature flags. Since elf_hwcaps is also a userspace ABI,
> I refrained from tinkering with this (tried this, gets messy).
>
> Based on bits in this bitmap, in patch 2/6 we provide a macro to
> replace (inline) assembly instructions at runtime with alternative
> instructions. As on x86, those bits go into separate ELF sections.
> The patching is done using stop_machine() to avoid mayhem in SMP.
>
> Patch 3/6 introduces means to set cpu_hwcaps bits based on detecting
> a certain CPU revision. Currently this is based on the architectural
> bits in the MIDR register, but the code is flexible enough to easily
> introduce more advanced criteria.
> To support a heterogenous CPU setup (e.g. big.LITTLE), we scan all
> CPUs in the system.
>
> Patch 4 and 5 use the new framework to introduce workarounds for two
> ARM-Cortex errata. Patch 4 introduces some more framework for the
> detection, while patch 5 should be used as a blueprint for how to add
> workarounds for CPU errata in the future.
>
> Patch 6/6 finally introduces Kconfig entries for the bugs.
> Those are meant to
> a) document the errata and workarounds and
> b) to allow system vendors to remove certain workarounds for custom
> build kernels.
> Though this shouldn't be strictly necessary, experience shows that
> people will do b) anyway and I deem it better to provide official
> means rather than provoking random hacks.
I just merged this and encountered a couple of issues in my testing:
(1) If patching occurs in a section that is discarded at compile time
(e.g. .exit.text) then we will fail to link:
`.exit.text' referenced in section `.altinstructions' of
drivers/built-in.o: defined in discarded section `.exit.text' of
drivers/built-in.o
(2) No patching occurs for modules
Please can you send me some additional patches on top of your series
to address these problems? The first issue can easily be solved by adding
a new Kconfig entry for the alternative framework, which causes
ARM_EXIT_{KEEP,DISCARD} to change their definitions. The second patch
needs a call from the module loader, in a similar manner to the SMP_ON_UP
patching in arch/arm/.
In the meantime, I've applied the diff below to keep allyesconfig happy.
Thanks,
Will
--->8
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index 3236727be2b9..9965ec87cbec 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -11,8 +11,9 @@
#include "image.h"
-#define ARM_EXIT_KEEP(x)
-#define ARM_EXIT_DISCARD(x) x
+/* .exit.text needed in case of alternative patching */
+#define ARM_EXIT_KEEP(x) x
+#define ARM_EXIT_DISCARD(x)
OUTPUT_ARCH(aarch64)
ENTRY(_text)
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH] arm64: add module support for alternatives fixups
2014-11-25 15:29 ` Will Deacon
@ 2014-11-28 13:40 ` Andre Przywara
0 siblings, 0 replies; 11+ messages in thread
From: Andre Przywara @ 2014-11-28 13:40 UTC (permalink / raw)
To: linux-arm-kernel
Currently the kernel patches all necessary instructions once at boot
time, so modules are not covered by this.
Change the apply_alternatives() function to take a beginning and an
end pointer and introduce a new variant (apply_alternatives_all()) to
cover the existing use case for the static kernel image section.
Add a module_finalize() function to arm64 to check for an
alternatives section in a module and patch only the instructions from
that specific area.
Since that module code is not touched before the module
initialization has ended, we don't need to halt the machine before
doing the patching in the module's code.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Hi Will,
so this patch make alternatives patching now work with modules. This
required some changes in the core alternatives code, so it would have
looked better when folded in (but it's already too late for this, I
guess). I have tested this quickly with modules with and without
alternatives sections in them, all seems to work fine.
Not sure if this is too much for -next at this time, though, so I
will leave this decision to you.
I will come up with a proper solution for the .exit.text issue later.
Cheers,
Andre.
arch/arm64/include/asm/alternative.h | 3 ++-
arch/arm64/kernel/alternative.c | 29 +++++++++++++++++++++++++----
arch/arm64/kernel/module.c | 18 ++++++++++++++++++
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 f6d206e..d261f01 100644
--- a/arch/arm64/include/asm/alternative.h
+++ b/arch/arm64/include/asm/alternative.h
@@ -13,7 +13,8 @@ struct alt_instr {
u8 alt_len; /* size of new instruction(s), <= orig_len */
};
-void apply_alternatives(void);
+void apply_alternatives_all(void);
+void apply_alternatives(void *start, size_t length);
void free_alternatives_memory(void);
#define ALTINSTR_ENTRY(feature) \
diff --git a/arch/arm64/kernel/alternative.c b/arch/arm64/kernel/alternative.c
index 5992ea4..f20cd5b 100644
--- a/arch/arm64/kernel/alternative.c
+++ b/arch/arm64/kernel/alternative.c
@@ -28,12 +28,18 @@
extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
-static int __apply_alternatives(void *dummy)
+struct alt_region {
+ struct alt_instr *begin;
+ struct alt_instr *end;
+};
+
+static int __apply_alternatives(void *alt_region)
{
struct alt_instr *alt;
+ struct alt_region *region = alt_region;
u8 *origptr, *replptr;
- for (alt = __alt_instructions; alt < __alt_instructions_end; alt++) {
+ for (alt = region->begin; alt < region->end; alt++) {
if (!cpus_have_cap(alt->cpufeature))
continue;
@@ -51,10 +57,25 @@ static int __apply_alternatives(void *dummy)
return 0;
}
-void apply_alternatives(void)
+void apply_alternatives_all(void)
{
+ struct alt_region region = {
+ .begin = __alt_instructions,
+ .end = __alt_instructions_end,
+ };
+
/* better not try code patching on a live SMP system */
- stop_machine(__apply_alternatives, NULL, NULL);
+ stop_machine(__apply_alternatives, ®ion, NULL);
+}
+
+void apply_alternatives(void *start, size_t length)
+{
+ struct alt_region region = {
+ .begin = start,
+ .end = start + length,
+ };
+
+ __apply_alternatives(®ion);
}
void free_alternatives_memory(void)
diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c
index 1eb1cc9..fd027b1 100644
--- a/arch/arm64/kernel/module.c
+++ b/arch/arm64/kernel/module.c
@@ -26,6 +26,7 @@
#include <linux/moduleloader.h>
#include <linux/vmalloc.h>
#include <asm/insn.h>
+#include <asm/sections.h>
#define AARCH64_INSN_IMM_MOVNZ AARCH64_INSN_IMM_MAX
#define AARCH64_INSN_IMM_MOVK AARCH64_INSN_IMM_16
@@ -394,3 +395,20 @@ overflow:
me->name, (int)ELF64_R_TYPE(rel[i].r_info), val);
return -ENOEXEC;
}
+
+int module_finalize(const Elf_Ehdr *hdr,
+ const Elf_Shdr *sechdrs,
+ struct module *me)
+{
+ const Elf_Shdr *s, *se;
+ const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+
+ for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++) {
+ if (strcmp(".altinstructions", secstrs + s->sh_name) == 0) {
+ apply_alternatives((void *)s->sh_addr, s->sh_size);
+ return 0;
+ }
+ }
+
+ return 0;
+}
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 0ef8789..7ae6ee0 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -310,7 +310,7 @@ void cpu_die(void)
void __init smp_cpus_done(unsigned int max_cpus)
{
pr_info("SMP: Total of %d processors activated.\n", num_online_cpus());
- apply_alternatives();
+ apply_alternatives_all();
}
void __init smp_prepare_boot_cpu(void)
--
1.7.9.5
^ permalink raw reply related [flat|nested] 11+ messages in thread