The following patches bring in
commit 20af540051e1c1f7a7d9b9e4613c1ecc53ded4a6 Author: James Morse james.morse@arm.com Date: Wed Jul 22 19:05:54 2015 +0100
arm64: kernel: Add support for Privileged Access Never commit 338d4f49d6f7114a017d294ccf7374df4f998edc upstream. 'Privileged Access Never' is a new arm8.1 feature which prevents privileged code from accessing any virtual address where read or write access is also permitted at EL0. This patch enables the PAN feature on all CPUs, and modifies {get,put}_user helpers temporarily to permit access. This will catch kernel bugs where user memory is accessed directly. 'Unprivileged loads and stores' using ldtrb et al are unaffected by PAN.
along with an additional 26 patches it depends on.
Daniel Thompson (1): arm64: alternative: Provide if/else/endif assembler macros
Fabio Estevam (1): arm64: Provide a namespace to NCAPS
James Morse (6): arm64: kernel: Move config_sctlr_el1 arm64: kernel: Add optional CONFIG_ parameter to ALTERNATIVE() arm64: kernel: Add min_field_value and use '>=' for feature detection arm64: kernel: Add cpuid_feature_extract_field() for 4bit sign extension arm64: kernel: Add cpufeature 'enable' callback arm64: kernel: Add support for Privileged Access Never
Marc Zyngier (4): arm64: Extract feature parsing code from cpu_errata.c arm64: alternative: Introduce feature for GICv3 CPU interface arm64: alternative: Merge alternative-asm.h into alternative.h arm64: alternative: Work around .inst assembler bugs
Michael S. Tsirkin (1): arm64/uaccess: fix sparse errors
Punit Agrawal (6): arm64: Add framework for legacy instruction emulation arm64: Add support for hooks to handle undefined instructions arm64: Port SWP/SWPB emulation support from arm arm64: Emulate CP15 Barrier instructions arm64: Trace emulation of AArch32 legacy instructions arm64: Add AArch32 instruction set condition code checks
Suzuki K. Poulose (4): arm64: Track system support for mixed endian EL0 arm64: Consolidate hotplug notifier for instruction emulation arm64: Emulate SETEND for AArch32 tasks arm64: Generalise msr_s/mrs_s operations
Will Deacon (4): arm64: alternatives: fix pr_fmt string for consistency arm64: fix return code check when changing emulation handler arm64: kconfig: move emulation option under kernel features arm64: lib: use pair accessors for copy_*_user routines
Documentation/arm64/legacy_instructions.txt | 57 +++ arch/arm64/Kconfig | 81 ++++ arch/arm64/include/asm/alternative-asm.h | 29 -- arch/arm64/include/asm/alternative.h | 109 ++++- arch/arm64/include/asm/cpufeature.h | 42 +- arch/arm64/include/asm/cputype.h | 14 + arch/arm64/include/asm/futex.h | 8 + arch/arm64/include/asm/insn.h | 10 + arch/arm64/include/asm/opcodes.h | 1 + arch/arm64/include/asm/processor.h | 2 + arch/arm64/include/asm/ptrace.h | 7 + arch/arm64/include/asm/sysreg.h | 40 +- arch/arm64/include/asm/traps.h | 16 + arch/arm64/include/asm/uaccess.h | 13 +- arch/arm64/include/uapi/asm/ptrace.h | 1 + arch/arm64/kernel/Makefile | 7 +- arch/arm64/kernel/armv8_deprecated.c | 659 ++++++++++++++++++++++++++++ arch/arm64/kernel/cpu_errata.c | 36 +- arch/arm64/kernel/cpufeature.c | 97 ++++ arch/arm64/kernel/cpuinfo.c | 23 + arch/arm64/kernel/entry.S | 2 +- arch/arm64/kernel/insn.c | 26 ++ arch/arm64/kernel/setup.c | 2 +- arch/arm64/kernel/signal32.c | 5 +- arch/arm64/kernel/trace-events-emulation.h | 35 ++ arch/arm64/kernel/traps.c | 66 +++ arch/arm64/lib/clear_user.S | 8 + arch/arm64/lib/copy_from_user.S | 25 +- arch/arm64/lib/copy_in_user.S | 25 +- arch/arm64/lib/copy_to_user.S | 25 +- arch/arm64/mm/cache.S | 2 +- arch/arm64/mm/fault.c | 16 + 32 files changed, 1389 insertions(+), 100 deletions(-) create mode 100644 Documentation/arm64/legacy_instructions.txt delete mode 100644 arch/arm64/include/asm/alternative-asm.h create mode 100644 arch/arm64/include/asm/opcodes.h create mode 100644 arch/arm64/kernel/armv8_deprecated.c create mode 100644 arch/arm64/kernel/cpufeature.c create mode 100644 arch/arm64/kernel/trace-events-emulation.h
From: Fabio Estevam fabio.estevam@freescale.com
commit 06f9eb884be81431d54d7d37390043e3b5b7f14a upstream
Building arm64.allmodconfig leads to the following warning:
usb/gadget/function/f_ncm.c:203:0: warning: "NCAPS" redefined #define NCAPS (USB_CDC_NCM_NCAP_ETH_FILTER | USB_CDC_NCM_NCAP_CRC_MODE) ^ In file included from /home/build/work/batch/arch/arm64/include/asm/io.h:32:0, from /home/build/work/batch/include/linux/clocksource.h:19, from /home/build/work/batch/include/clocksource/arm_arch_timer.h:19, from /home/build/work/batch/arch/arm64/include/asm/arch_timer.h:27, from /home/build/work/batch/arch/arm64/include/asm/timex.h:19, from /home/build/work/batch/include/linux/timex.h:65, from /home/build/work/batch/include/linux/sched.h:19, from /home/build/work/batch/arch/arm64/include/asm/compat.h:25, from /home/build/work/batch/arch/arm64/include/asm/stat.h:23, from /home/build/work/batch/include/linux/stat.h:5, from /home/build/work/batch/include/linux/module.h:10, from /home/build/work/batch/drivers/usb/gadget/function/f_ncm.c:19: arch/arm64/include/asm/cpufeature.h:27:0: note: this is the location of the previous definition #define NCAPS 2
So add a ARM64 prefix to avoid such problem.
Reported-by: Olof's autobuilder build@lixom.net Signed-off-by: Fabio Estevam fabio.estevam@freescale.com Signed-off-by: Will Deacon will.deacon@arm.com [david: Resolve simple merge conflicts] Signed-off-by: David Brown david.brown@linaro.org --- arch/arm64/include/asm/cpufeature.h | 10 +++++----- arch/arm64/kernel/setup.c | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index c008bae..5fe4bef 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -25,11 +25,11 @@ #define ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE 1 #define ARM64_WORKAROUND_845719 2
-#define NCAPS 3 +#define ARM64_NCAPS 3
#ifndef __ASSEMBLY__
-extern DECLARE_BITMAP(cpu_hwcaps, NCAPS); +extern DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS);
static inline bool cpu_have_feature(unsigned int num) { @@ -38,16 +38,16 @@ static inline bool cpu_have_feature(unsigned int num)
static inline bool cpus_have_cap(unsigned int num) { - if (num >= NCAPS) + if (num >= ARM64_NCAPS) return false; return test_bit(num, cpu_hwcaps); }
static inline void cpus_set_cap(unsigned int num) { - if (num >= NCAPS) + if (num >= ARM64_NCAPS) pr_warn("Attempt to set an illegal CPU capability (%d >= %d)\n", - num, NCAPS); + num, ARM64_NCAPS); else __set_bit(num, cpu_hwcaps); } diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index d502a86..ef961ab 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -80,7 +80,7 @@ unsigned int compat_elf_hwcap __read_mostly = COMPAT_ELF_HWCAP_DEFAULT; unsigned int compat_elf_hwcap2 __read_mostly; #endif
-DECLARE_BITMAP(cpu_hwcaps, NCAPS); +DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS);
static const char *cpu_name; phys_addr_t __fdt_pointer __initdata;
From: "Suzuki K. Poulose" suzuki.poulose@arm.com
commit 04597a65c5efc207257a736d339c6f2f5b00250f upstream.
This patch keeps track of the mixed endian EL0 support across the system and provides helper functions to export it. The status is a boolean indicating whether all the CPUs on the system supports mixed endian at EL0.
Signed-off-by: Suzuki K. Poulose suzuki.poulose@arm.com Cc: Will Deacon will.deacon@arm.com Signed-off-by: Catalin Marinas catalin.marinas@arm.com Signed-off-by: David Brown david.brown@linaro.org --- arch/arm64/include/asm/cpufeature.h | 2 ++ arch/arm64/include/asm/cputype.h | 14 ++++++++++++++ arch/arm64/kernel/cpuinfo.c | 22 ++++++++++++++++++++++ 3 files changed, 38 insertions(+)
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 5fe4bef..3f0c53c 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -53,6 +53,8 @@ static inline void cpus_set_cap(unsigned int num) }
void check_local_cpu_errata(void); +bool cpu_supports_mixed_endian_el0(void); +bool system_supports_mixed_endian_el0(void);
#endif /* __ASSEMBLY__ */
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h index 8adb986..ee6403d 100644 --- a/arch/arm64/include/asm/cputype.h +++ b/arch/arm64/include/asm/cputype.h @@ -72,6 +72,15 @@
#define APM_CPU_PART_POTENZA 0x000
+#define ID_AA64MMFR0_BIGENDEL0_SHIFT 16 +#define ID_AA64MMFR0_BIGENDEL0_MASK (0xf << ID_AA64MMFR0_BIGENDEL0_SHIFT) +#define ID_AA64MMFR0_BIGENDEL0(mmfr0) \ + (((mmfr0) & ID_AA64MMFR0_BIGENDEL0_MASK) >> ID_AA64MMFR0_BIGENDEL0_SHIFT) +#define ID_AA64MMFR0_BIGEND_SHIFT 8 +#define ID_AA64MMFR0_BIGEND_MASK (0xf << ID_AA64MMFR0_BIGEND_SHIFT) +#define ID_AA64MMFR0_BIGEND(mmfr0) \ + (((mmfr0) & ID_AA64MMFR0_BIGEND_MASK) >> ID_AA64MMFR0_BIGEND_SHIFT) + #ifndef __ASSEMBLY__
/* @@ -104,6 +113,11 @@ static inline u32 __attribute_const__ read_cpuid_cachetype(void) return read_cpuid(CTR_EL0); }
+static inline bool id_aa64mmfr0_mixed_endian_el0(u64 mmfr0) +{ + return (ID_AA64MMFR0_BIGEND(mmfr0) == 0x1) || + (ID_AA64MMFR0_BIGENDEL0(mmfr0) == 0x1); +} #endif /* __ASSEMBLY__ */
#endif diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c index 16d6d03..618bf11 100644 --- a/arch/arm64/kernel/cpuinfo.c +++ b/arch/arm64/kernel/cpuinfo.c @@ -35,6 +35,7 @@ */ DEFINE_PER_CPU(struct cpuinfo_arm64, cpu_data); static struct cpuinfo_arm64 boot_cpu_data; +static bool mixed_endian_el0 = true;
static char *icache_policy_str[] = { [ICACHE_POLICY_RESERVED] = "RESERVED/UNKNOWN", @@ -68,6 +69,26 @@ static void cpuinfo_detect_icache_policy(struct cpuinfo_arm64 *info) pr_info("Detected %s I-cache on CPU%d\n", icache_policy_str[l1ip], cpu); }
+bool cpu_supports_mixed_endian_el0(void) +{ + return id_aa64mmfr0_mixed_endian_el0(read_cpuid(ID_AA64MMFR0_EL1)); +} + +bool system_supports_mixed_endian_el0(void) +{ + return mixed_endian_el0; +} + +static void update_mixed_endian_el0_support(struct cpuinfo_arm64 *info) +{ + mixed_endian_el0 &= id_aa64mmfr0_mixed_endian_el0(info->reg_id_aa64mmfr0); +} + +static void update_cpu_features(struct cpuinfo_arm64 *info) +{ + update_mixed_endian_el0_support(info); +} + static int check_reg_mask(char *name, u64 mask, u64 boot, u64 cur, int cpu) { if ((boot & mask) == (cur & mask)) @@ -189,6 +210,7 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info) cpuinfo_detect_icache_policy(info);
check_local_cpu_errata(); + update_cpu_features(info); }
void cpuinfo_store_cpu(void)
From: Will Deacon will.deacon@arm.com
commit c9453a3ab1a39230a18b3db1d677bbb2bd782baa upstream.
Consistently use the plural form for alternatives pr_fmt strings.
Signed-off-by: Will Deacon will.deacon@arm.com Signed-off-by: David Brown david.brown@linaro.org --- arch/arm64/kernel/cpu_errata.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index bbc710a..ad6d523 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -16,7 +16,7 @@ * along with this program. If not, see http://www.gnu.org/licenses/. */
-#define pr_fmt(fmt) "alternative: " fmt +#define pr_fmt(fmt) "alternatives: " fmt
#include <linux/types.h> #include <asm/cpu.h>
From: Marc Zyngier marc.zyngier@arm.com
commit 359b706473b47da3c93bd99fd10d798fe411ab67 upstream.
As we detect more architectural features at runtime, it makes sense to reuse the existing framework whilst avoiding to call a feature an erratum...
This patch extract the core capability parsing, moves it into a new file (cpufeature.c), and let the CPU errata detection code use it.
Reviewed-by: Andre Przywara andre.przywara@arm.com Acked-by: Will Deacon will.deacon@arm.com Signed-off-by: Marc Zyngier marc.zyngier@arm.com Signed-off-by: Will Deacon will.deacon@arm.com [david: trivial merge fixups] Signed-off-by: David Brown david.brown@linaro.org --- arch/arm64/include/asm/cpufeature.h | 15 ++++++++++++ arch/arm64/kernel/Makefile | 2 +- arch/arm64/kernel/cpu_errata.c | 36 ++++------------------------ arch/arm64/kernel/cpufeature.c | 47 +++++++++++++++++++++++++++++++++++++ arch/arm64/kernel/cpuinfo.c | 1 + 5 files changed, 68 insertions(+), 33 deletions(-) create mode 100644 arch/arm64/kernel/cpufeature.c
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 3f0c53c..82cb9f9 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -29,6 +29,18 @@
#ifndef __ASSEMBLY__
+struct arm64_cpu_capabilities { + const char *desc; + u16 capability; + bool (*matches)(const struct arm64_cpu_capabilities *); + union { + struct { /* To be used for erratum handling only */ + u32 midr_model; + u32 midr_range_min, midr_range_max; + }; + }; +}; + extern DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS);
static inline bool cpu_have_feature(unsigned int num) @@ -52,7 +64,10 @@ static inline void cpus_set_cap(unsigned int num) __set_bit(num, cpu_hwcaps); }
+void check_cpu_capabilities(const struct arm64_cpu_capabilities *caps, + const char *info); void check_local_cpu_errata(void); +void check_local_cpu_features(void); bool cpu_supports_mixed_endian_el0(void); bool system_supports_mixed_endian_el0(void);
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index da22728..0dbdb22 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 cpu_errata.o alternative.o + cpuinfo.o cpu_errata.o cpufeature.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 index ad6d523..6ffd914 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -16,8 +16,6 @@ * along with this program. If not, see http://www.gnu.org/licenses/. */
-#define pr_fmt(fmt) "alternatives: " fmt - #include <linux/types.h> #include <asm/cpu.h> #include <asm/cputype.h> @@ -26,27 +24,11 @@ #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 - * 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; - }; - }; -}; - #define CPU_MODEL_MASK (MIDR_IMPLEMENTOR_MASK | MIDR_PARTNUM_MASK | \ MIDR_ARCHITECTURE_MASK)
static bool __maybe_unused -is_affected_midr_range(struct arm64_cpu_capabilities *entry) +is_affected_midr_range(const struct arm64_cpu_capabilities *entry) { u32 midr = read_cpuid_id();
@@ -59,12 +41,12 @@ is_affected_midr_range(struct arm64_cpu_capabilities *entry) }
#define MIDR_RANGE(model, min, max) \ - .is_affected = is_affected_midr_range, \ + .matches = is_affected_midr_range, \ .midr_model = model, \ .midr_range_min = min, \ .midr_range_max = max
-struct arm64_cpu_capabilities arm64_errata[] = { +const struct arm64_cpu_capabilities arm64_errata[] = { #if defined(CONFIG_ARM64_ERRATUM_826319) || \ defined(CONFIG_ARM64_ERRATUM_827319) || \ defined(CONFIG_ARM64_ERRATUM_824069) @@ -106,15 +88,5 @@ 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); - } + check_cpu_capabilities(arm64_errata, "enabling workaround for"); } diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c new file mode 100644 index 0000000..3d9967e --- /dev/null +++ b/arch/arm64/kernel/cpufeature.c @@ -0,0 +1,47 @@ +/* + * Contains CPU feature definitions + * + * Copyright (C) 2015 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) "alternatives: " fmt + +#include <linux/types.h> +#include <asm/cpu.h> +#include <asm/cpufeature.h> + +static const struct arm64_cpu_capabilities arm64_features[] = { + {}, +}; + +void check_cpu_capabilities(const struct arm64_cpu_capabilities *caps, + const char *info) +{ + int i; + + for (i = 0; caps[i].desc; i++) { + if (!caps[i].matches(&caps[i])) + continue; + + if (!cpus_have_cap(caps[i].capability)) + pr_info("%s %s\n", info, caps[i].desc); + cpus_set_cap(caps[i].capability); + } +} + +void check_local_cpu_features(void) +{ + check_cpu_capabilities(arm64_features, "detected feature"); +} diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c index 618bf11..faf5cad 100644 --- a/arch/arm64/kernel/cpuinfo.c +++ b/arch/arm64/kernel/cpuinfo.c @@ -210,6 +210,7 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info) cpuinfo_detect_icache_policy(info);
check_local_cpu_errata(); + check_local_cpu_features(); update_cpu_features(info); }
From: Marc Zyngier marc.zyngier@arm.com
commit 94a9e04aa16abd1194d9b4158c618ba87f5d01e6 upstream.
Add a new item to the feature set (ARM64_HAS_SYSREG_GIC_CPUIF) to indicate that we have a system register GIC CPU interface
This will help KVM switching to alternative instruction patching.
Reviewed-by: Andre Przywara andre.przywara@arm.com Reviewed-by: Christoffer Dall christoffer.dall@linaro.org Acked-by: Will Deacon will.deacon@arm.com Signed-off-by: Marc Zyngier marc.zyngier@arm.com Signed-off-by: Catalin Marinas catalin.marinas@arm.com Signed-off-by: David Brown david.brown@linaro.org --- arch/arm64/include/asm/cpufeature.h | 8 +++++++- arch/arm64/kernel/cpufeature.c | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 82cb9f9..c104421 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -24,8 +24,9 @@ #define ARM64_WORKAROUND_CLEAN_CACHE 0 #define ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE 1 #define ARM64_WORKAROUND_845719 2 +#define ARM64_HAS_SYSREG_GIC_CPUIF 3
-#define ARM64_NCAPS 3 +#define ARM64_NCAPS 4
#ifndef __ASSEMBLY__
@@ -38,6 +39,11 @@ struct arm64_cpu_capabilities { u32 midr_model; u32 midr_range_min, midr_range_max; }; + + struct { /* Feature register checking */ + u64 register_mask; + u64 register_value; + }; }; };
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 3d9967e..5ad86ce 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -22,7 +22,23 @@ #include <asm/cpu.h> #include <asm/cpufeature.h>
+static bool +has_id_aa64pfr0_feature(const struct arm64_cpu_capabilities *entry) +{ + u64 val; + + val = read_cpuid(id_aa64pfr0_el1); + return (val & entry->register_mask) == entry->register_value; +} + static const struct arm64_cpu_capabilities arm64_features[] = { + { + .desc = "GIC system register CPU interface", + .capability = ARM64_HAS_SYSREG_GIC_CPUIF, + .matches = has_id_aa64pfr0_feature, + .register_mask = (0xf << 24), + .register_value = (1 << 24), + }, {}, };
From: Punit Agrawal punit.agrawal@arm.com
commit 587064b610c703f259317d00dc37bf6d40f4fc74 upstream.
Typically, providing support for legacy instructions requires emulating the behaviour of instructions whose encodings have become undefined. If the instructions haven't been removed from the architecture, there maybe an option in the implementation to turn on/off the support for these instructions.
Create common infrastructure to support legacy instruction emulation. In addition to emulation, also provide an option to support hardware execution when supported. The default execution mode (one of undef, emulate, hw exeuction) is dependent on the state of the instruction (deprecated or obsolete) in the architecture and can specified at the time of registering the instruction handlers. The runtime state of the emulation can be controlled by writing to individual nodes in sysctl. The expected default behaviour is documented as part of this patch.
Reviewed-by: Catalin Marinas catalin.marinas@arm.com Signed-off-by: Punit Agrawal punit.agrawal@arm.com Signed-off-by: Will Deacon will.deacon@arm.com Signed-off-by: David Brown david.brown@linaro.org --- Documentation/arm64/legacy_instructions.txt | 33 +++++ arch/arm64/Kconfig | 18 +++ arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/armv8_deprecated.c | 216 ++++++++++++++++++++++++++++ 4 files changed, 268 insertions(+) create mode 100644 Documentation/arm64/legacy_instructions.txt create mode 100644 arch/arm64/kernel/armv8_deprecated.c
diff --git a/Documentation/arm64/legacy_instructions.txt b/Documentation/arm64/legacy_instructions.txt new file mode 100644 index 0000000..49d4867 --- /dev/null +++ b/Documentation/arm64/legacy_instructions.txt @@ -0,0 +1,33 @@ +The arm64 port of the Linux kernel provides infrastructure to support +emulation of instructions which have been deprecated, or obsoleted in +the architecture. The infrastructure code uses undefined instruction +hooks to support emulation. Where available it also allows turning on +the instruction execution in hardware. + +The emulation mode can be controlled by writing to sysctl nodes +(/proc/sys/abi). The following explains the different execution +behaviours and the corresponding values of the sysctl nodes - + +* Undef + Value: 0 + Generates undefined instruction abort. Default for instructions that + have been obsoleted in the architecture, e.g., SWP + +* Emulate + Value: 1 + Uses software emulation. To aid migration of software, in this mode + usage of emulated instruction is traced as well as rate limited + warnings are issued. This is the default for deprecated + instructions, .e.g., CP15 barriers + +* Hardware Execution + Value: 2 + Although marked as deprecated, some implementations may support the + enabling/disabling of hardware support for the execution of these + instructions. Using hardware execution generally provides better + performance, but at the loss of ability to gather runtime statistics + about the use of the deprecated instructions. + +The default mode depends on the status of the instruction in the +architecture. Deprecated instructions should default to emulation +while obsolete instructions must be undefined by default. diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 00b9c48..d512762 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -166,6 +166,24 @@ config ARCH_XGENE help This enables support for AppliedMicro X-Gene SOC Family
+comment "Processor Features" + +menuconfig ARMV8_DEPRECATED + bool "Emulate deprecated/obsolete ARMv8 instructions" + depends on COMPAT + help + Legacy software support may require certain instructions + that have been deprecated or obsoleted in the architecture. + + Enable this config to enable selective emulation of these + features. + + If unsure, say Y + +if ARMV8_DEPRECATED + +endif + endmenu
menu "Bus support" diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 0dbdb22..60c7865 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -31,6 +31,7 @@ arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o arm64-obj-$(CONFIG_KGDB) += kgdb.o arm64-obj-$(CONFIG_EFI) += efi.o efi-stub.o efi-entry.o arm64-obj-$(CONFIG_PCI) += pci.o +arm64-obj-$(CONFIG_ARMV8_DEPRECATED) += armv8_deprecated.o
obj-y += $(arm64-obj-y) vdso/ obj-m += $(arm64-obj-m) diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c new file mode 100644 index 0000000..db3b79d --- /dev/null +++ b/arch/arm64/kernel/armv8_deprecated.c @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2014 ARM Limited + * + * 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. + */ + +#include <linux/init.h> +#include <linux/list.h> +#include <linux/slab.h> +#include <linux/sysctl.h> + +#include <asm/traps.h> + +/* + * The runtime support for deprecated instruction support can be in one of + * following three states - + * + * 0 = undef + * 1 = emulate (software emulation) + * 2 = hw (supported in hardware) + */ +enum insn_emulation_mode { + INSN_UNDEF, + INSN_EMULATE, + INSN_HW, +}; + +enum legacy_insn_status { + INSN_DEPRECATED, + INSN_OBSOLETE, +}; + +struct insn_emulation_ops { + const char *name; + enum legacy_insn_status status; + struct undef_hook *hooks; + int (*set_hw_mode)(bool enable); +}; + +struct insn_emulation { + struct list_head node; + struct insn_emulation_ops *ops; + int current_mode; + int min; + int max; +}; + +static LIST_HEAD(insn_emulation); +static int nr_insn_emulated; +static DEFINE_RAW_SPINLOCK(insn_emulation_lock); + +static void register_emulation_hooks(struct insn_emulation_ops *ops) +{ + struct undef_hook *hook; + + BUG_ON(!ops->hooks); + + for (hook = ops->hooks; hook->instr_mask; hook++) + register_undef_hook(hook); + + pr_notice("Registered %s emulation handler\n", ops->name); +} + +static void remove_emulation_hooks(struct insn_emulation_ops *ops) +{ + struct undef_hook *hook; + + BUG_ON(!ops->hooks); + + for (hook = ops->hooks; hook->instr_mask; hook++) + unregister_undef_hook(hook); + + pr_notice("Removed %s emulation handler\n", ops->name); +} + +static int update_insn_emulation_mode(struct insn_emulation *insn, + enum insn_emulation_mode prev) +{ + int ret = 0; + + switch (prev) { + case INSN_UNDEF: /* Nothing to be done */ + break; + case INSN_EMULATE: + remove_emulation_hooks(insn->ops); + break; + case INSN_HW: + if (insn->ops->set_hw_mode) { + insn->ops->set_hw_mode(false); + pr_notice("Disabled %s support\n", insn->ops->name); + } + break; + } + + switch (insn->current_mode) { + case INSN_UNDEF: + break; + case INSN_EMULATE: + register_emulation_hooks(insn->ops); + break; + case INSN_HW: + if (insn->ops->set_hw_mode && insn->ops->set_hw_mode(true)) + pr_notice("Enabled %s support\n", insn->ops->name); + else + ret = -EINVAL; + break; + } + + return ret; +} + +static void register_insn_emulation(struct insn_emulation_ops *ops) +{ + unsigned long flags; + struct insn_emulation *insn; + + insn = kzalloc(sizeof(*insn), GFP_KERNEL); + insn->ops = ops; + insn->min = INSN_UNDEF; + + switch (ops->status) { + case INSN_DEPRECATED: + insn->current_mode = INSN_EMULATE; + insn->max = INSN_HW; + break; + case INSN_OBSOLETE: + insn->current_mode = INSN_UNDEF; + insn->max = INSN_EMULATE; + break; + } + + raw_spin_lock_irqsave(&insn_emulation_lock, flags); + list_add(&insn->node, &insn_emulation); + nr_insn_emulated++; + raw_spin_unlock_irqrestore(&insn_emulation_lock, flags); + + /* Register any handlers if required */ + update_insn_emulation_mode(insn, INSN_UNDEF); +} + +static int emulation_proc_handler(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, + loff_t *ppos) +{ + int ret = 0; + struct insn_emulation *insn = (struct insn_emulation *) table->data; + enum insn_emulation_mode prev_mode = insn->current_mode; + + table->data = &insn->current_mode; + ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); + + if (ret || !write || prev_mode == insn->current_mode) + goto ret; + + ret = update_insn_emulation_mode(insn, prev_mode); + if (!ret) { + /* Mode change failed, revert to previous mode. */ + insn->current_mode = prev_mode; + update_insn_emulation_mode(insn, INSN_UNDEF); + } +ret: + table->data = insn; + return ret; +} + +static struct ctl_table ctl_abi[] = { + { + .procname = "abi", + .mode = 0555, + }, + { } +}; + +static void register_insn_emulation_sysctl(struct ctl_table *table) +{ + unsigned long flags; + int i = 0; + struct insn_emulation *insn; + struct ctl_table *insns_sysctl, *sysctl; + + insns_sysctl = kzalloc(sizeof(*sysctl) * (nr_insn_emulated + 1), + GFP_KERNEL); + + raw_spin_lock_irqsave(&insn_emulation_lock, flags); + list_for_each_entry(insn, &insn_emulation, node) { + sysctl = &insns_sysctl[i]; + + sysctl->mode = 0644; + sysctl->maxlen = sizeof(int); + + sysctl->procname = insn->ops->name; + sysctl->data = insn; + sysctl->extra1 = &insn->min; + sysctl->extra2 = &insn->max; + sysctl->proc_handler = emulation_proc_handler; + i++; + } + raw_spin_unlock_irqrestore(&insn_emulation_lock, flags); + + table->child = insns_sysctl; + register_sysctl_table(table); +} + +/* + * Invoked as late_initcall, since not needed before init spawned. + */ +static int __init armv8_deprecated_init(void) +{ + register_insn_emulation_sysctl(ctl_abi); + + return 0; +} + +late_initcall(armv8_deprecated_init);
From: Punit Agrawal punit.agrawal@arm.com
commit 9b79f52d1a702dd5b160f9d2ee0199c3122809bb upstream.
Add support to register hooks for undefined instructions. The handlers will be called when the undefined instruction and the processor state (as contained in pstate) match criteria used at registration.
Signed-off-by: Punit Agrawal punit.agrawal@arm.com Reviewed-by: Catalin Marinas catalin.marinas@arm.com Signed-off-by: Will Deacon will.deacon@arm.com Signed-off-by: David Brown david.brown@linaro.org --- arch/arm64/include/asm/insn.h | 2 ++ arch/arm64/include/asm/traps.h | 16 ++++++++++ arch/arm64/kernel/insn.c | 5 ++++ arch/arm64/kernel/traps.c | 66 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 89 insertions(+)
diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h index 56a9e63..1bb0430 100644 --- a/arch/arm64/include/asm/insn.h +++ b/arch/arm64/include/asm/insn.h @@ -354,6 +354,8 @@ bool aarch64_insn_hotpatch_safe(u32 old_insn, u32 new_insn); int aarch64_insn_patch_text_nosync(void *addr, u32 insn); int aarch64_insn_patch_text_sync(void *addrs[], u32 insns[], int cnt); int aarch64_insn_patch_text(void *addrs[], u32 insns[], int cnt); + +bool aarch32_insn_is_wide(u32 insn); #endif /* __ASSEMBLY__ */
#endif /* __ASM_INSN_H */ diff --git a/arch/arm64/include/asm/traps.h b/arch/arm64/include/asm/traps.h index 10ca8ff..232e4ba 100644 --- a/arch/arm64/include/asm/traps.h +++ b/arch/arm64/include/asm/traps.h @@ -18,6 +18,22 @@ #ifndef __ASM_TRAP_H #define __ASM_TRAP_H
+#include <linux/list.h> + +struct pt_regs; + +struct undef_hook { + struct list_head node; + u32 instr_mask; + u32 instr_val; + u64 pstate_mask; + u64 pstate_val; + int (*fn)(struct pt_regs *regs, u32 instr); +}; + +void register_undef_hook(struct undef_hook *hook); +void unregister_undef_hook(struct undef_hook *hook); + static inline int in_exception_text(unsigned long ptr) { extern char __exception_text_start[]; diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c index 8cd27fe..abb0870 100644 --- a/arch/arm64/kernel/insn.c +++ b/arch/arm64/kernel/insn.c @@ -960,3 +960,8 @@ u32 aarch64_insn_gen_logical_shifted_reg(enum aarch64_insn_register dst,
return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_6, insn, shift); } + +bool aarch32_insn_is_wide(u32 insn) +{ + return insn >= 0xe800; +} diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index de1b085..0a801e3 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -259,6 +259,69 @@ void arm64_notify_die(const char *str, struct pt_regs *regs, } }
+static LIST_HEAD(undef_hook); +static DEFINE_RAW_SPINLOCK(undef_lock); + +void register_undef_hook(struct undef_hook *hook) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&undef_lock, flags); + list_add(&hook->node, &undef_hook); + raw_spin_unlock_irqrestore(&undef_lock, flags); +} + +void unregister_undef_hook(struct undef_hook *hook) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&undef_lock, flags); + list_del(&hook->node); + raw_spin_unlock_irqrestore(&undef_lock, flags); +} + +static int call_undef_hook(struct pt_regs *regs) +{ + struct undef_hook *hook; + unsigned long flags; + u32 instr; + int (*fn)(struct pt_regs *regs, u32 instr) = NULL; + void __user *pc = (void __user *)instruction_pointer(regs); + + if (!user_mode(regs)) + return 1; + + if (compat_thumb_mode(regs)) { + /* 16-bit Thumb instruction */ + if (get_user(instr, (u16 __user *)pc)) + goto exit; + instr = le16_to_cpu(instr); + if (aarch32_insn_is_wide(instr)) { + u32 instr2; + + if (get_user(instr2, (u16 __user *)(pc + 2))) + goto exit; + instr2 = le16_to_cpu(instr2); + instr = (instr << 16) | instr2; + } + } else { + /* 32-bit ARM instruction */ + if (get_user(instr, (u32 __user *)pc)) + goto exit; + instr = le32_to_cpu(instr); + } + + raw_spin_lock_irqsave(&undef_lock, flags); + list_for_each_entry(hook, &undef_hook, node) + if ((instr & hook->instr_mask) == hook->instr_val && + (regs->pstate & hook->pstate_mask) == hook->pstate_val) + fn = hook->fn; + + raw_spin_unlock_irqrestore(&undef_lock, flags); +exit: + return fn ? fn(regs, instr) : 1; +} + asmlinkage void __exception do_undefinstr(struct pt_regs *regs) { siginfo_t info; @@ -268,6 +331,9 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs) if (!aarch32_break_handler(regs)) return;
+ if (call_undef_hook(regs) == 0) + return; + if (show_unhandled_signals && unhandled_signal(current, SIGILL) && printk_ratelimit()) { pr_info("%s[%d]: undefined instruction: pc=%p\n",
From: Punit Agrawal punit.agrawal@arm.com
commit bd35a4adc4131c530ec7d90242555eac7b3dbe3f upstream.
The SWP instruction was deprecated in the ARMv6 architecture. The ARMv7 multiprocessing extensions mandate that SWP/SWPB instructions are treated as undefined from reset, with the ability to enable them through the System Control Register SW bit. With ARMv8, the option to enable these instructions through System Control Register was dropped as well.
To support legacy applications using these instructions, port the emulation of the SWP and SWPB instructions from the arm port to arm64.
Reviewed-by: Catalin Marinas catalin.marinas@arm.com Signed-off-by: Punit Agrawal punit.agrawal@arm.com Signed-off-by: Will Deacon will.deacon@arm.com Signed-off-by: David Brown david.brown@linaro.org --- Documentation/arm64/legacy_instructions.txt | 7 + arch/arm64/Kconfig | 21 +++ arch/arm64/include/asm/insn.h | 6 + arch/arm64/kernel/armv8_deprecated.c | 191 ++++++++++++++++++++++++++++ arch/arm64/kernel/insn.c | 8 ++ 5 files changed, 233 insertions(+)
diff --git a/Documentation/arm64/legacy_instructions.txt b/Documentation/arm64/legacy_instructions.txt index 49d4867..5ab5861 100644 --- a/Documentation/arm64/legacy_instructions.txt +++ b/Documentation/arm64/legacy_instructions.txt @@ -31,3 +31,10 @@ behaviours and the corresponding values of the sysctl nodes - The default mode depends on the status of the instruction in the architecture. Deprecated instructions should default to emulation while obsolete instructions must be undefined by default. + +Supported legacy instructions +----------------------------- +* SWP{B} +Node: /proc/sys/abi/swp +Status: Obsolete +Default: Undef (0) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index d512762..6f0548e 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -182,6 +182,27 @@ menuconfig ARMV8_DEPRECATED
if ARMV8_DEPRECATED
+config SWP_EMULATION + bool "Emulate SWP/SWPB instructions" + help + ARMv8 obsoletes the use of A32 SWP/SWPB instructions such that + they are always undefined. Say Y here to enable software + emulation of these instructions for userspace using LDXR/STXR. + + In some older versions of glibc [<=2.8] SWP is used during futex + trylock() operations with the assumption that the code will not + be preempted. This invalid assumption may be more likely to fail + with SWP emulation enabled, leading to deadlock of the user + application. + + NOTE: when accessing uncached shared regions, LDXR/STXR rely + on an external transaction monitoring block called a global + monitor to maintain update atomicity. If your system does not + implement a global monitor, this option can cause programs that + perform SWP operations to uncached memory to deadlock. + + If unsure, say Y + endif
endmenu diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h index 1bb0430..3ecc57c 100644 --- a/arch/arm64/include/asm/insn.h +++ b/arch/arm64/include/asm/insn.h @@ -356,6 +356,12 @@ int aarch64_insn_patch_text_sync(void *addrs[], u32 insns[], int cnt); int aarch64_insn_patch_text(void *addrs[], u32 insns[], int cnt);
bool aarch32_insn_is_wide(u32 insn); + +#define A32_RN_OFFSET 16 +#define A32_RT_OFFSET 12 +#define A32_RT2_OFFSET 0 + +u32 aarch32_insn_extract_reg_num(u32 insn, int offset); #endif /* __ASSEMBLY__ */
#endif /* __ASM_INSN_H */ diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c index db3b79d..98865a7 100644 --- a/arch/arm64/kernel/armv8_deprecated.c +++ b/arch/arm64/kernel/armv8_deprecated.c @@ -8,10 +8,16 @@
#include <linux/init.h> #include <linux/list.h> +#include <linux/perf_event.h> +#include <linux/sched.h> #include <linux/slab.h> #include <linux/sysctl.h>
+#include <asm/insn.h> +#include <asm/opcodes.h> +#include <asm/system_misc.h> #include <asm/traps.h> +#include <asm/uaccess.h>
/* * The runtime support for deprecated instruction support can be in one of @@ -204,10 +210,195 @@ static void register_insn_emulation_sysctl(struct ctl_table *table) }
/* + * Implement emulation of the SWP/SWPB instructions using load-exclusive and + * store-exclusive. + * + * Syntax of SWP{B} instruction: SWP{B}<c> <Rt>, <Rt2>, [<Rn>] + * Where: Rt = destination + * Rt2 = source + * Rn = address + */ + +/* + * Error-checking SWP macros implemented using ldxr{b}/stxr{b} + */ +#define __user_swpX_asm(data, addr, res, temp, B) \ + __asm__ __volatile__( \ + " mov %w2, %w1\n" \ + "0: ldxr"B" %w1, [%3]\n" \ + "1: stxr"B" %w0, %w2, [%3]\n" \ + " cbz %w0, 2f\n" \ + " mov %w0, %w4\n" \ + "2:\n" \ + " .pushsection .fixup,"ax"\n" \ + " .align 2\n" \ + "3: mov %w0, %w5\n" \ + " b 2b\n" \ + " .popsection" \ + " .pushsection __ex_table,"a"\n" \ + " .align 3\n" \ + " .quad 0b, 3b\n" \ + " .quad 1b, 3b\n" \ + " .popsection" \ + : "=&r" (res), "+r" (data), "=&r" (temp) \ + : "r" (addr), "i" (-EAGAIN), "i" (-EFAULT) \ + : "memory") + +#define __user_swp_asm(data, addr, res, temp) \ + __user_swpX_asm(data, addr, res, temp, "") +#define __user_swpb_asm(data, addr, res, temp) \ + __user_swpX_asm(data, addr, res, temp, "b") + +/* + * Bit 22 of the instruction encoding distinguishes between + * the SWP and SWPB variants (bit set means SWPB). + */ +#define TYPE_SWPB (1 << 22) + +/* + * Set up process info to signal segmentation fault - called on access error. + */ +static void set_segfault(struct pt_regs *regs, unsigned long addr) +{ + siginfo_t info; + + down_read(¤t->mm->mmap_sem); + if (find_vma(current->mm, addr) == NULL) + info.si_code = SEGV_MAPERR; + else + info.si_code = SEGV_ACCERR; + up_read(¤t->mm->mmap_sem); + + info.si_signo = SIGSEGV; + info.si_errno = 0; + info.si_addr = (void *) instruction_pointer(regs); + + pr_debug("SWP{B} emulation: access caused memory abort!\n"); + arm64_notify_die("Illegal memory access", regs, &info, 0); +} + +static int emulate_swpX(unsigned int address, unsigned int *data, + unsigned int type) +{ + unsigned int res = 0; + + if ((type != TYPE_SWPB) && (address & 0x3)) { + /* SWP to unaligned address not permitted */ + pr_debug("SWP instruction on unaligned pointer!\n"); + return -EFAULT; + } + + while (1) { + unsigned long temp; + + if (type == TYPE_SWPB) + __user_swpb_asm(*data, address, res, temp); + else + __user_swp_asm(*data, address, res, temp); + + if (likely(res != -EAGAIN) || signal_pending(current)) + break; + + cond_resched(); + } + + return res; +} + +/* + * swp_handler logs the id of calling process, dissects the instruction, sanity + * checks the memory location, calls emulate_swpX for the actual operation and + * deals with fixup/error handling before returning + */ +static int swp_handler(struct pt_regs *regs, u32 instr) +{ + u32 destreg, data, type, address = 0; + int rn, rt2, res = 0; + + perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc); + + type = instr & TYPE_SWPB; + + switch (arm_check_condition(instr, regs->pstate)) { + case ARM_OPCODE_CONDTEST_PASS: + break; + case ARM_OPCODE_CONDTEST_FAIL: + /* Condition failed - return to next instruction */ + goto ret; + case ARM_OPCODE_CONDTEST_UNCOND: + /* If unconditional encoding - not a SWP, undef */ + return -EFAULT; + default: + return -EINVAL; + } + + rn = aarch32_insn_extract_reg_num(instr, A32_RN_OFFSET); + rt2 = aarch32_insn_extract_reg_num(instr, A32_RT2_OFFSET); + + address = (u32)regs->user_regs.regs[rn]; + data = (u32)regs->user_regs.regs[rt2]; + destreg = aarch32_insn_extract_reg_num(instr, A32_RT_OFFSET); + + pr_debug("addr in r%d->0x%08x, dest is r%d, source in r%d->0x%08x)\n", + rn, address, destreg, + aarch32_insn_extract_reg_num(instr, A32_RT2_OFFSET), data); + + /* Check access in reasonable access range for both SWP and SWPB */ + if (!access_ok(VERIFY_WRITE, (address & ~3), 4)) { + pr_debug("SWP{B} emulation: access to 0x%08x not allowed!\n", + address); + goto fault; + } + + res = emulate_swpX(address, &data, type); + if (res == -EFAULT) + goto fault; + else if (res == 0) + regs->user_regs.regs[destreg] = data; + +ret: + pr_warn_ratelimited(""%s" (%ld) uses obsolete SWP{B} instruction at 0x%llx\n", + current->comm, (unsigned long)current->pid, regs->pc); + + regs->pc += 4; + return 0; + +fault: + set_segfault(regs, address); + + return 0; +} + +/* + * Only emulate SWP/SWPB executed in ARM state/User mode. + * The kernel must be SWP free and SWP{B} does not exist in Thumb. + */ +static struct undef_hook swp_hooks[] = { + { + .instr_mask = 0x0fb00ff0, + .instr_val = 0x01000090, + .pstate_mask = COMPAT_PSR_MODE_MASK, + .pstate_val = COMPAT_PSR_MODE_USR, + .fn = swp_handler + }, + { } +}; + +static struct insn_emulation_ops swp_ops = { + .name = "swp", + .status = INSN_OBSOLETE, + .hooks = swp_hooks, + .set_hw_mode = NULL, +}; + +/* * Invoked as late_initcall, since not needed before init spawned. */ static int __init armv8_deprecated_init(void) { + if (IS_ENABLED(CONFIG_SWP_EMULATION)) + register_insn_emulation(&swp_ops); + register_insn_emulation_sysctl(ctl_abi);
return 0; diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c index abb0870..23ad9c1 100644 --- a/arch/arm64/kernel/insn.c +++ b/arch/arm64/kernel/insn.c @@ -965,3 +965,11 @@ bool aarch32_insn_is_wide(u32 insn) { return insn >= 0xe800; } + +/* + * Macros/defines for extracting register numbers from instruction. + */ +u32 aarch32_insn_extract_reg_num(u32 insn, int offset) +{ + return (insn & (0xf << offset)) >> offset; +}
From: Punit Agrawal punit.agrawal@arm.com
commit c852f320584600a372646055d8229e063949eee7 upstream.
The CP15 barrier instructions (CP15ISB, CP15DSB and CP15DMB) are deprecated in the ARMv7 architecture, superseded by ISB, DSB and DMB instructions respectively. Some implementations may provide the ability to disable the CP15 barriers by disabling the CP15BEN bit in SCTLR_EL1. If not enabled, the encodings for these instructions become undefined.
To support legacy software using these instructions, this patch register hooks to - * emulate CP15 barriers and warn the user about their use * toggle CP15BEN in SCTLR_EL1
Signed-off-by: Punit Agrawal punit.agrawal@arm.com Reviewed-by: Catalin Marinas catalin.marinas@arm.com Signed-off-by: Will Deacon will.deacon@arm.com Signed-off-by: David Brown david.brown@linaro.org --- Documentation/arm64/legacy_instructions.txt | 5 ++ arch/arm64/Kconfig | 15 ++++ arch/arm64/include/asm/insn.h | 2 + arch/arm64/kernel/armv8_deprecated.c | 131 ++++++++++++++++++++++++++++ arch/arm64/kernel/insn.c | 13 +++ 5 files changed, 166 insertions(+)
diff --git a/Documentation/arm64/legacy_instructions.txt b/Documentation/arm64/legacy_instructions.txt index 5ab5861..a3b3da2 100644 --- a/Documentation/arm64/legacy_instructions.txt +++ b/Documentation/arm64/legacy_instructions.txt @@ -38,3 +38,8 @@ Supported legacy instructions Node: /proc/sys/abi/swp Status: Obsolete Default: Undef (0) + +* CP15 Barriers +Node: /proc/sys/abi/cp15_barrier +Status: Deprecated +Default: Emulate (1) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 6f0548e..b62bf4c 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -203,6 +203,21 @@ config SWP_EMULATION
If unsure, say Y
+config CP15_BARRIER_EMULATION + bool "Emulate CP15 Barrier instructions" + help + The CP15 barrier instructions - CP15ISB, CP15DSB, and + CP15DMB - are deprecated in ARMv8 (and ARMv7). It is + strongly recommended to use the ISB, DSB, and DMB + instructions instead. + + Say Y here to enable software emulation of these + instructions for AArch32 userspace code. When this option is + enabled, CP15 barrier usage is traced which can help + identify software that needs updating. + + If unsure, say Y + endif
endmenu diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h index 3ecc57c..e2ff32a 100644 --- a/arch/arm64/include/asm/insn.h +++ b/arch/arm64/include/asm/insn.h @@ -362,6 +362,8 @@ bool aarch32_insn_is_wide(u32 insn); #define A32_RT2_OFFSET 0
u32 aarch32_insn_extract_reg_num(u32 insn, int offset); +u32 aarch32_insn_mcr_extract_opc2(u32 insn); +u32 aarch32_insn_mcr_extract_crm(u32 insn); #endif /* __ASSEMBLY__ */
#endif /* __ASM_INSN_H */ diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c index 98865a7..401c2e5 100644 --- a/arch/arm64/kernel/armv8_deprecated.c +++ b/arch/arm64/kernel/armv8_deprecated.c @@ -6,6 +6,7 @@ * published by the Free Software Foundation. */
+#include <linux/cpu.h> #include <linux/init.h> #include <linux/list.h> #include <linux/perf_event.h> @@ -391,6 +392,133 @@ static struct insn_emulation_ops swp_ops = { .set_hw_mode = NULL, };
+static int cp15barrier_handler(struct pt_regs *regs, u32 instr) +{ + perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc); + + switch (arm_check_condition(instr, regs->pstate)) { + case ARM_OPCODE_CONDTEST_PASS: + break; + case ARM_OPCODE_CONDTEST_FAIL: + /* Condition failed - return to next instruction */ + goto ret; + case ARM_OPCODE_CONDTEST_UNCOND: + /* If unconditional encoding - not a barrier instruction */ + return -EFAULT; + default: + return -EINVAL; + } + + switch (aarch32_insn_mcr_extract_crm(instr)) { + case 10: + /* + * dmb - mcr p15, 0, Rt, c7, c10, 5 + * dsb - mcr p15, 0, Rt, c7, c10, 4 + */ + if (aarch32_insn_mcr_extract_opc2(instr) == 5) + dmb(sy); + else + dsb(sy); + break; + case 5: + /* + * isb - mcr p15, 0, Rt, c7, c5, 4 + * + * Taking an exception or returning from one acts as an + * instruction barrier. So no explicit barrier needed here. + */ + break; + } + +ret: + pr_warn_ratelimited(""%s" (%ld) uses deprecated CP15 Barrier instruction at 0x%llx\n", + current->comm, (unsigned long)current->pid, regs->pc); + + regs->pc += 4; + return 0; +} + +#define SCTLR_EL1_CP15BEN (1 << 5) + +static inline void config_sctlr_el1(u32 clear, u32 set) +{ + u32 val; + + asm volatile("mrs %0, sctlr_el1" : "=r" (val)); + val &= ~clear; + val |= set; + asm volatile("msr sctlr_el1, %0" : : "r" (val)); +} + +static void enable_cp15_ben(void *info) +{ + config_sctlr_el1(0, SCTLR_EL1_CP15BEN); +} + +static void disable_cp15_ben(void *info) +{ + config_sctlr_el1(SCTLR_EL1_CP15BEN, 0); +} + +static int cpu_hotplug_notify(struct notifier_block *b, + unsigned long action, void *hcpu) +{ + switch (action) { + case CPU_STARTING: + case CPU_STARTING_FROZEN: + enable_cp15_ben(NULL); + return NOTIFY_DONE; + case CPU_DYING: + case CPU_DYING_FROZEN: + disable_cp15_ben(NULL); + return NOTIFY_DONE; + } + + return NOTIFY_OK; +} + +static struct notifier_block cpu_hotplug_notifier = { + .notifier_call = cpu_hotplug_notify, +}; + +static int cp15_barrier_set_hw_mode(bool enable) +{ + if (enable) { + register_cpu_notifier(&cpu_hotplug_notifier); + on_each_cpu(enable_cp15_ben, NULL, true); + } else { + unregister_cpu_notifier(&cpu_hotplug_notifier); + on_each_cpu(disable_cp15_ben, NULL, true); + } + + return true; +} + +static struct undef_hook cp15_barrier_hooks[] = { + { + .instr_mask = 0x0fff0fdf, + .instr_val = 0x0e070f9a, + .pstate_mask = COMPAT_PSR_MODE_MASK, + .pstate_val = COMPAT_PSR_MODE_USR, + .fn = cp15barrier_handler, + }, + { + .instr_mask = 0x0fff0fff, + .instr_val = 0x0e070f95, + .pstate_mask = COMPAT_PSR_MODE_MASK, + .pstate_val = COMPAT_PSR_MODE_USR, + .fn = cp15barrier_handler, + }, + { } +}; + +static struct insn_emulation_ops cp15_barrier_ops = { + .name = "cp15_barrier", + .status = INSN_DEPRECATED, + .hooks = cp15_barrier_hooks, + .set_hw_mode = cp15_barrier_set_hw_mode, +}; + /* * Invoked as late_initcall, since not needed before init spawned. */ @@ -399,6 +527,9 @@ static int __init armv8_deprecated_init(void) if (IS_ENABLED(CONFIG_SWP_EMULATION)) register_insn_emulation(&swp_ops);
+ if (IS_ENABLED(CONFIG_CP15_BARRIER_EMULATION)) + register_insn_emulation(&cp15_barrier_ops); + register_insn_emulation_sysctl(ctl_abi);
return 0; diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c index 23ad9c1..7e9327a 100644 --- a/arch/arm64/kernel/insn.c +++ b/arch/arm64/kernel/insn.c @@ -973,3 +973,16 @@ u32 aarch32_insn_extract_reg_num(u32 insn, int offset) { return (insn & (0xf << offset)) >> offset; } + +#define OPC2_MASK 0x7 +#define OPC2_OFFSET 5 +u32 aarch32_insn_mcr_extract_opc2(u32 insn) +{ + return (insn & (OPC2_MASK << OPC2_OFFSET)) >> OPC2_OFFSET; +} + +#define CRM_MASK 0xf +u32 aarch32_insn_mcr_extract_crm(u32 insn) +{ + return insn & CRM_MASK; +}
From: Punit Agrawal punit.agrawal@arm.com
commit d784e2988a3e70a6f1047e80e01465a903ea2eba upstream.
Introduce an event to trace the usage of emulated instructions. The trace event is intended to help identify and encourage the migration of legacy software using the emulation features.
Use this event to trace usage of swp and CP15 barrier emulation.
Acked-by: Steven Rostedt rostedt@goodmis.org Acked-by: Catalin Marinas catalin.marinas@arm.com Signed-off-by: Punit Agrawal punit.agrawal@arm.com Signed-off-by: Will Deacon will.deacon@arm.com Signed-off-by: David Brown david.brown@linaro.org --- arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/armv8_deprecated.c | 19 ++++++++++++++-- arch/arm64/kernel/trace-events-emulation.h | 35 ++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 arch/arm64/kernel/trace-events-emulation.h
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 60c7865..259126a 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -5,6 +5,7 @@ CPPFLAGS_vmlinux.lds := -DTEXT_OFFSET=$(TEXT_OFFSET) AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET) CFLAGS_efi-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) +CFLAGS_armv8_deprecated.o := -I$(src)
CFLAGS_REMOVE_ftrace.o = -pg CFLAGS_REMOVE_insn.o = -pg diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c index 401c2e5..529aad9 100644 --- a/arch/arm64/kernel/armv8_deprecated.c +++ b/arch/arm64/kernel/armv8_deprecated.c @@ -20,6 +20,9 @@ #include <asm/traps.h> #include <asm/uaccess.h>
+#define CREATE_TRACE_POINTS +#include "trace-events-emulation.h" + /* * The runtime support for deprecated instruction support can be in one of * following three states - @@ -358,6 +361,11 @@ static int swp_handler(struct pt_regs *regs, u32 instr) regs->user_regs.regs[destreg] = data;
ret: + if (type == TYPE_SWPB) + trace_instruction_emulation("swpb", regs->pc); + else + trace_instruction_emulation("swp", regs->pc); + pr_warn_ratelimited(""%s" (%ld) uses obsolete SWP{B} instruction at 0x%llx\n", current->comm, (unsigned long)current->pid, regs->pc);
@@ -415,10 +423,15 @@ static int cp15barrier_handler(struct pt_regs *regs, u32 instr) * dmb - mcr p15, 0, Rt, c7, c10, 5 * dsb - mcr p15, 0, Rt, c7, c10, 4 */ - if (aarch32_insn_mcr_extract_opc2(instr) == 5) + if (aarch32_insn_mcr_extract_opc2(instr) == 5) { dmb(sy); - else + trace_instruction_emulation( + "mcr p15, 0, Rt, c7, c10, 5 ; dmb", regs->pc); + } else { dsb(sy); + trace_instruction_emulation( + "mcr p15, 0, Rt, c7, c10, 4 ; dsb", regs->pc); + } break; case 5: /* @@ -427,6 +440,8 @@ static int cp15barrier_handler(struct pt_regs *regs, u32 instr) * Taking an exception or returning from one acts as an * instruction barrier. So no explicit barrier needed here. */ + trace_instruction_emulation( + "mcr p15, 0, Rt, c7, c5, 4 ; isb", regs->pc); break; }
diff --git a/arch/arm64/kernel/trace-events-emulation.h b/arch/arm64/kernel/trace-events-emulation.h new file mode 100644 index 0000000..ae1dd59 --- /dev/null +++ b/arch/arm64/kernel/trace-events-emulation.h @@ -0,0 +1,35 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM emulation + +#if !defined(_TRACE_EMULATION_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_EMULATION_H + +#include <linux/tracepoint.h> + +TRACE_EVENT(instruction_emulation, + + TP_PROTO(const char *instr, u64 addr), + TP_ARGS(instr, addr), + + TP_STRUCT__entry( + __string(instr, instr) + __field(u64, addr) + ), + + TP_fast_assign( + __assign_str(instr, instr); + __entry->addr = addr; + ), + + TP_printk("instr="%s" addr=0x%llx", __get_str(instr), __entry->addr) +); + +#endif /* _TRACE_EMULATION_H */ + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_PATH . + +#define TRACE_INCLUDE_FILE trace-events-emulation +#include <trace/define_trace.h>
From: Will Deacon will.deacon@arm.com
commit 909633957d85561dab7655d69a9d17dd16231d92 upstream.
update_insn_emulation_mode() returns 0 on success, so we should be treating any non-zero values as failure, rather than the other way around. Otherwise, writes to the sysctl file controlling the emulation are ignored and immediately rolled back.
Reported-by: Gene Hackmann ghackmann@google.com Signed-off-by: Will Deacon will.deacon@arm.com Signed-off-by: David Brown david.brown@linaro.org --- arch/arm64/kernel/armv8_deprecated.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c index 529aad9..c363671 100644 --- a/arch/arm64/kernel/armv8_deprecated.c +++ b/arch/arm64/kernel/armv8_deprecated.c @@ -165,7 +165,7 @@ static int emulation_proc_handler(struct ctl_table *table, int write, goto ret;
ret = update_insn_emulation_mode(insn, prev_mode); - if (!ret) { + if (ret) { /* Mode change failed, revert to previous mode. */ insn->current_mode = prev_mode; update_insn_emulation_mode(insn, INSN_UNDEF);
From: "Suzuki K. Poulose" suzuki.poulose@arm.com
commit 736d474f0fafd1486f178570bc47660ee9dfdef8 upstream.
As of now each insn_emulation has a cpu hotplug notifier that enables/disables the CPU feature bit for the functionality. This patch re-arranges the code, such that there is only one notifier that runs through the list of registered emulation hooks and runs their corresponding set_hw_mode.
We do nothing when a CPU is dying as we will set the appropriate bits as it comes back online based on the state of the hooks.
Signed-off-by: Mark Rutland mark.rutland@arm.com Signed-off-by: Suzuki K. Poulose suzuki.poulose@arm.com Cc: Will Deacon will.deacon@arm.com Cc: Punit Agrawal punit.agrawal@arm.com [catalin.marinas@arm.com: fix pr_warn compilation error] [catalin.marinas@arm.com: remove unnecessary "insn" check] Signed-off-by: Catalin Marinas catalin.marinas@arm.com Signed-off-by: David Brown david.brown@linaro.org --- arch/arm64/include/asm/cputype.h | 2 + arch/arm64/kernel/armv8_deprecated.c | 125 +++++++++++++++++++++-------------- 2 files changed, 79 insertions(+), 48 deletions(-)
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h index ee6403d..68732e9 100644 --- a/arch/arm64/include/asm/cputype.h +++ b/arch/arm64/include/asm/cputype.h @@ -81,6 +81,8 @@ #define ID_AA64MMFR0_BIGEND(mmfr0) \ (((mmfr0) & ID_AA64MMFR0_BIGEND_MASK) >> ID_AA64MMFR0_BIGEND_SHIFT)
+#define SCTLR_EL1_CP15BEN (0x1 << 5) + #ifndef __ASSEMBLY__
/* diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c index c363671..68b955e 100644 --- a/arch/arm64/kernel/armv8_deprecated.c +++ b/arch/arm64/kernel/armv8_deprecated.c @@ -19,6 +19,7 @@ #include <asm/system_misc.h> #include <asm/traps.h> #include <asm/uaccess.h> +#include <asm/cpufeature.h>
#define CREATE_TRACE_POINTS #include "trace-events-emulation.h" @@ -85,6 +86,57 @@ static void remove_emulation_hooks(struct insn_emulation_ops *ops) pr_notice("Removed %s emulation handler\n", ops->name); }
+static void enable_insn_hw_mode(void *data) +{ + struct insn_emulation *insn = (struct insn_emulation *)data; + if (insn->ops->set_hw_mode) + insn->ops->set_hw_mode(true); +} + +static void disable_insn_hw_mode(void *data) +{ + struct insn_emulation *insn = (struct insn_emulation *)data; + if (insn->ops->set_hw_mode) + insn->ops->set_hw_mode(false); +} + +/* Run set_hw_mode(mode) on all active CPUs */ +static int run_all_cpu_set_hw_mode(struct insn_emulation *insn, bool enable) +{ + if (!insn->ops->set_hw_mode) + return -EINVAL; + if (enable) + on_each_cpu(enable_insn_hw_mode, (void *)insn, true); + else + on_each_cpu(disable_insn_hw_mode, (void *)insn, true); + return 0; +} + +/* + * Run set_hw_mode for all insns on a starting CPU. + * Returns: + * 0 - If all the hooks ran successfully. + * -EINVAL - At least one hook is not supported by the CPU. + */ +static int run_all_insn_set_hw_mode(unsigned long cpu) +{ + int rc = 0; + unsigned long flags; + struct insn_emulation *insn; + + raw_spin_lock_irqsave(&insn_emulation_lock, flags); + list_for_each_entry(insn, &insn_emulation, node) { + bool enable = (insn->current_mode == INSN_HW); + if (insn->ops->set_hw_mode && insn->ops->set_hw_mode(enable)) { + pr_warn("CPU[%ld] cannot support the emulation of %s", + cpu, insn->ops->name); + rc = -EINVAL; + } + } + raw_spin_unlock_irqrestore(&insn_emulation_lock, flags); + return rc; +} + static int update_insn_emulation_mode(struct insn_emulation *insn, enum insn_emulation_mode prev) { @@ -97,10 +149,8 @@ static int update_insn_emulation_mode(struct insn_emulation *insn, remove_emulation_hooks(insn->ops); break; case INSN_HW: - if (insn->ops->set_hw_mode) { - insn->ops->set_hw_mode(false); + if (!run_all_cpu_set_hw_mode(insn, false)) pr_notice("Disabled %s support\n", insn->ops->name); - } break; }
@@ -111,10 +161,9 @@ static int update_insn_emulation_mode(struct insn_emulation *insn, register_emulation_hooks(insn->ops); break; case INSN_HW: - if (insn->ops->set_hw_mode && insn->ops->set_hw_mode(true)) + ret = run_all_cpu_set_hw_mode(insn, true); + if (!ret) pr_notice("Enabled %s support\n", insn->ops->name); - else - ret = -EINVAL; break; }
@@ -133,6 +182,8 @@ static void register_insn_emulation(struct insn_emulation_ops *ops) switch (ops->status) { case INSN_DEPRECATED: insn->current_mode = INSN_EMULATE; + /* Disable the HW mode if it was turned on at early boot time */ + run_all_cpu_set_hw_mode(insn, false); insn->max = INSN_HW; break; case INSN_OBSOLETE: @@ -453,8 +504,6 @@ ret: return 0; }
-#define SCTLR_EL1_CP15BEN (1 << 5) - static inline void config_sctlr_el1(u32 clear, u32 set) { u32 val; @@ -465,48 +514,13 @@ static inline void config_sctlr_el1(u32 clear, u32 set) asm volatile("msr sctlr_el1, %0" : : "r" (val)); }
-static void enable_cp15_ben(void *info) -{ - config_sctlr_el1(0, SCTLR_EL1_CP15BEN); -} - -static void disable_cp15_ben(void *info) -{ - config_sctlr_el1(SCTLR_EL1_CP15BEN, 0); -} - -static int cpu_hotplug_notify(struct notifier_block *b, - unsigned long action, void *hcpu) -{ - switch (action) { - case CPU_STARTING: - case CPU_STARTING_FROZEN: - enable_cp15_ben(NULL); - return NOTIFY_DONE; - case CPU_DYING: - case CPU_DYING_FROZEN: - disable_cp15_ben(NULL); - return NOTIFY_DONE; - } - - return NOTIFY_OK; -} - -static struct notifier_block cpu_hotplug_notifier = { - .notifier_call = cpu_hotplug_notify, -}; - static int cp15_barrier_set_hw_mode(bool enable) { - if (enable) { - register_cpu_notifier(&cpu_hotplug_notifier); - on_each_cpu(enable_cp15_ben, NULL, true); - } else { - unregister_cpu_notifier(&cpu_hotplug_notifier); - on_each_cpu(disable_cp15_ben, NULL, true); - } - - return true; + if (enable) + config_sctlr_el1(0, SCTLR_EL1_CP15BEN); + else + config_sctlr_el1(SCTLR_EL1_CP15BEN, 0); + return 0; }
static struct undef_hook cp15_barrier_hooks[] = { @@ -534,6 +548,20 @@ static struct insn_emulation_ops cp15_barrier_ops = { .set_hw_mode = cp15_barrier_set_hw_mode, };
+static int insn_cpu_hotplug_notify(struct notifier_block *b, + unsigned long action, void *hcpu) +{ + int rc = 0; + if ((action & ~CPU_TASKS_FROZEN) == CPU_STARTING) + rc = run_all_insn_set_hw_mode((unsigned long)hcpu); + + return notifier_from_errno(rc); +} + +static struct notifier_block insn_cpu_hotplug_notifier = { + .notifier_call = insn_cpu_hotplug_notify, +}; + /* * Invoked as late_initcall, since not needed before init spawned. */ @@ -545,6 +573,7 @@ static int __init armv8_deprecated_init(void) if (IS_ENABLED(CONFIG_CP15_BARRIER_EMULATION)) register_insn_emulation(&cp15_barrier_ops);
+ register_cpu_notifier(&insn_cpu_hotplug_notifier); register_insn_emulation_sysctl(ctl_abi);
return 0;
From: Will Deacon will.deacon@arm.com
commit 1b907f46db07405b6676addb91b32c546d772fcd upstream.
Having the instruction emulation submenu underneath "platform selection" is a great way to hide options we don't want people to use, but somewhat confusing when you stumble across it there.
Move the menuconfig option underneath "kernel features", where it makes a bit more sense.
Signed-off-by: Will Deacon will.deacon@arm.com Signed-off-by: David Brown david.brown@linaro.org --- arch/arm64/Kconfig | 106 ++++++++++++++++++++++++++--------------------------- 1 file changed, 52 insertions(+), 54 deletions(-)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index b62bf4c..4c79862 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -166,60 +166,6 @@ config ARCH_XGENE help This enables support for AppliedMicro X-Gene SOC Family
-comment "Processor Features" - -menuconfig ARMV8_DEPRECATED - bool "Emulate deprecated/obsolete ARMv8 instructions" - depends on COMPAT - help - Legacy software support may require certain instructions - that have been deprecated or obsoleted in the architecture. - - Enable this config to enable selective emulation of these - features. - - If unsure, say Y - -if ARMV8_DEPRECATED - -config SWP_EMULATION - bool "Emulate SWP/SWPB instructions" - help - ARMv8 obsoletes the use of A32 SWP/SWPB instructions such that - they are always undefined. Say Y here to enable software - emulation of these instructions for userspace using LDXR/STXR. - - In some older versions of glibc [<=2.8] SWP is used during futex - trylock() operations with the assumption that the code will not - be preempted. This invalid assumption may be more likely to fail - with SWP emulation enabled, leading to deadlock of the user - application. - - NOTE: when accessing uncached shared regions, LDXR/STXR rely - on an external transaction monitoring block called a global - monitor to maintain update atomicity. If your system does not - implement a global monitor, this option can cause programs that - perform SWP operations to uncached memory to deadlock. - - If unsure, say Y - -config CP15_BARRIER_EMULATION - bool "Emulate CP15 Barrier instructions" - help - The CP15 barrier instructions - CP15ISB, CP15DSB, and - CP15DMB - are deprecated in ARMv8 (and ARMv7). It is - strongly recommended to use the ISB, DSB, and DMB - instructions instead. - - Say Y here to enable software emulation of these - instructions for AArch32 userspace code. When this option is - enabled, CP15 barrier usage is traced which can help - identify software that needs updating. - - If unsure, say Y - -endif - endmenu
menu "Bus support" @@ -548,6 +494,58 @@ config FORCE_MAX_ZONEORDER default "14" if (ARM64_64K_PAGES && TRANSPARENT_HUGEPAGE) default "11"
+menuconfig ARMV8_DEPRECATED + bool "Emulate deprecated/obsolete ARMv8 instructions" + depends on COMPAT + help + Legacy software support may require certain instructions + that have been deprecated or obsoleted in the architecture. + + Enable this config to enable selective emulation of these + features. + + If unsure, say Y + +if ARMV8_DEPRECATED + +config SWP_EMULATION + bool "Emulate SWP/SWPB instructions" + help + ARMv8 obsoletes the use of A32 SWP/SWPB instructions such that + they are always undefined. Say Y here to enable software + emulation of these instructions for userspace using LDXR/STXR. + + In some older versions of glibc [<=2.8] SWP is used during futex + trylock() operations with the assumption that the code will not + be preempted. This invalid assumption may be more likely to fail + with SWP emulation enabled, leading to deadlock of the user + application. + + NOTE: when accessing uncached shared regions, LDXR/STXR rely + on an external transaction monitoring block called a global + monitor to maintain update atomicity. If your system does not + implement a global monitor, this option can cause programs that + perform SWP operations to uncached memory to deadlock. + + If unsure, say Y + +config CP15_BARRIER_EMULATION + bool "Emulate CP15 Barrier instructions" + help + The CP15 barrier instructions - CP15ISB, CP15DSB, and + CP15DMB - are deprecated in ARMv8 (and ARMv7). It is + strongly recommended to use the ISB, DSB, and DMB + instructions instead. + + Say Y here to enable software emulation of these + instructions for AArch32 userspace code. When this option is + enabled, CP15 barrier usage is traced which can help + identify software that needs updating. + + If unsure, say Y + +endif + endmenu
menu "Boot options"
From: "Suzuki K. Poulose" suzuki.poulose@arm.com
commit 2d888f48e056119495847a269a435d5c3d9df349 upstream.
Emulate deprecated 'setend' instruction for AArch32 bit tasks.
setend [le/be] - Sets the endianness of EL0
On systems with CPUs which support mixed endian at EL0, the hardware support for the instruction can be enabled by setting the SCTLR_EL1.SED bit. Like the other emulated instructions it is controlled by an entry in /proc/sys/abi/. For more information see : Documentation/arm64/legacy_instructions.txt
The instruction is emulated by setting/clearing the SPSR_EL1.E bit, which will be reflected in the PSTATE.E in AArch32 context.
This patch also restores the native endianness for the execution of signal handlers, since the process could have changed the endianness.
Note: All CPUs on the system must have mixed endian support at EL0. Once the handler is registered, hotplugging a CPU which doesn't support mixed endian, could lead to unexpected results/behavior in applications.
Signed-off-by: Suzuki K. Poulose suzuki.poulose@arm.com Cc: Will Deacon will.deacon@arm.com Cc: Punit Agrawal punit.agrawal@arm.com Signed-off-by: Catalin Marinas catalin.marinas@arm.com Signed-off-by: David Brown david.brown@linaro.org --- Documentation/arm64/legacy_instructions.txt | 12 +++++ arch/arm64/Kconfig | 15 ++++++ arch/arm64/include/asm/cputype.h | 1 + arch/arm64/include/asm/ptrace.h | 7 +++ arch/arm64/kernel/armv8_deprecated.c | 80 +++++++++++++++++++++++++++++ arch/arm64/kernel/signal32.c | 5 +- 6 files changed, 119 insertions(+), 1 deletion(-)
diff --git a/Documentation/arm64/legacy_instructions.txt b/Documentation/arm64/legacy_instructions.txt index a3b3da2..01bf3d9 100644 --- a/Documentation/arm64/legacy_instructions.txt +++ b/Documentation/arm64/legacy_instructions.txt @@ -32,6 +32,9 @@ The default mode depends on the status of the instruction in the architecture. Deprecated instructions should default to emulation while obsolete instructions must be undefined by default.
+Note: Instruction emulation may not be possible in all cases. See +individual instruction notes for further information. + Supported legacy instructions ----------------------------- * SWP{B} @@ -43,3 +46,12 @@ Default: Undef (0) Node: /proc/sys/abi/cp15_barrier Status: Deprecated Default: Emulate (1) + +* SETEND +Node: /proc/sys/abi/setend +Status: Deprecated +Default: Emulate (1)* +Note: All the cpus on the system must have mixed endian support at EL0 +for this feature to be enabled. If a new CPU - which doesn't support mixed +endian - is hotplugged in after this feature has been enabled, there could +be unexpected results in the application. diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 4c79862..7f74b4c 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -544,6 +544,21 @@ config CP15_BARRIER_EMULATION
If unsure, say Y
+config SETEND_EMULATION + bool "Emulate SETEND instruction" + help + The SETEND instruction alters the data-endianness of the + AArch32 EL0, and is deprecated in ARMv8. + + Say Y here to enable software emulation of the instruction + for AArch32 userspace code. + + Note: All the cpus on the system must have mixed endian support at EL0 + for this feature to be enabled. If a new CPU - which doesn't support mixed + endian - is hotplugged in after this feature has been enabled, there could + be unexpected results in the applications. + + If unsure, say Y endif
endmenu diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h index 68732e9..a84ec60 100644 --- a/arch/arm64/include/asm/cputype.h +++ b/arch/arm64/include/asm/cputype.h @@ -82,6 +82,7 @@ (((mmfr0) & ID_AA64MMFR0_BIGEND_MASK) >> ID_AA64MMFR0_BIGEND_SHIFT)
#define SCTLR_EL1_CP15BEN (0x1 << 5) +#define SCTLR_EL1_SED (0x1 << 8)
#ifndef __ASSEMBLY__
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h index 41ed9e1..d6dd9fd 100644 --- a/arch/arm64/include/asm/ptrace.h +++ b/arch/arm64/include/asm/ptrace.h @@ -58,6 +58,13 @@ #define COMPAT_PSR_Z_BIT 0x40000000 #define COMPAT_PSR_N_BIT 0x80000000 #define COMPAT_PSR_IT_MASK 0x0600fc00 /* If-Then execution state mask */ + +#ifdef CONFIG_CPU_BIG_ENDIAN +#define COMPAT_PSR_ENDSTATE COMPAT_PSR_E_BIT +#else +#define COMPAT_PSR_ENDSTATE 0 +#endif + /* * These are 'magic' values for PTRACE_PEEKUSR that return info about where a * process is located in memory. diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c index 68b955e..7922c2e 100644 --- a/arch/arm64/kernel/armv8_deprecated.c +++ b/arch/arm64/kernel/armv8_deprecated.c @@ -548,6 +548,79 @@ static struct insn_emulation_ops cp15_barrier_ops = { .set_hw_mode = cp15_barrier_set_hw_mode, };
+static int setend_set_hw_mode(bool enable) +{ + if (!cpu_supports_mixed_endian_el0()) + return -EINVAL; + + if (enable) + config_sctlr_el1(SCTLR_EL1_SED, 0); + else + config_sctlr_el1(0, SCTLR_EL1_SED); + return 0; +} + +static int compat_setend_handler(struct pt_regs *regs, u32 big_endian) +{ + char *insn; + + perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc); + + if (big_endian) { + insn = "setend be"; + regs->pstate |= COMPAT_PSR_E_BIT; + } else { + insn = "setend le"; + regs->pstate &= ~COMPAT_PSR_E_BIT; + } + + trace_instruction_emulation(insn, regs->pc); + pr_warn_ratelimited(""%s" (%ld) uses deprecated setend instruction at 0x%llx\n", + current->comm, (unsigned long)current->pid, regs->pc); + + return 0; +} + +static int a32_setend_handler(struct pt_regs *regs, u32 instr) +{ + int rc = compat_setend_handler(regs, (instr >> 9) & 1); + regs->pc += 4; + return rc; +} + +static int t16_setend_handler(struct pt_regs *regs, u32 instr) +{ + int rc = compat_setend_handler(regs, (instr >> 3) & 1); + regs->pc += 2; + return rc; +} + +static struct undef_hook setend_hooks[] = { + { + .instr_mask = 0xfffffdff, + .instr_val = 0xf1010000, + .pstate_mask = COMPAT_PSR_MODE_MASK, + .pstate_val = COMPAT_PSR_MODE_USR, + .fn = a32_setend_handler, + }, + { + /* Thumb mode */ + .instr_mask = 0x0000fff7, + .instr_val = 0x0000b650, + .pstate_mask = (COMPAT_PSR_T_BIT | COMPAT_PSR_MODE_MASK), + .pstate_val = (COMPAT_PSR_T_BIT | COMPAT_PSR_MODE_USR), + .fn = t16_setend_handler, + }, + {} +}; + +static struct insn_emulation_ops setend_ops = { + .name = "setend", + .status = INSN_DEPRECATED, + .hooks = setend_hooks, + .set_hw_mode = setend_set_hw_mode, +}; + static int insn_cpu_hotplug_notify(struct notifier_block *b, unsigned long action, void *hcpu) { @@ -573,6 +646,13 @@ static int __init armv8_deprecated_init(void) if (IS_ENABLED(CONFIG_CP15_BARRIER_EMULATION)) register_insn_emulation(&cp15_barrier_ops);
+ if (IS_ENABLED(CONFIG_SETEND_EMULATION)) { + if(system_supports_mixed_endian_el0()) + register_insn_emulation(&setend_ops); + else + pr_info("setend instruction emulation is not supported on the system"); + } + register_cpu_notifier(&insn_cpu_hotplug_notifier); register_insn_emulation_sysctl(ctl_abi);
diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c index 15dd021..b6da20f 100644 --- a/arch/arm64/kernel/signal32.c +++ b/arch/arm64/kernel/signal32.c @@ -457,7 +457,7 @@ static void compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka, { compat_ulong_t handler = ptr_to_compat(ka->sa.sa_handler); compat_ulong_t retcode; - compat_ulong_t spsr = regs->pstate & ~PSR_f; + compat_ulong_t spsr = regs->pstate & ~(PSR_f | COMPAT_PSR_E_BIT); int thumb;
/* Check if the handler is written for ARM or Thumb */ @@ -471,6 +471,9 @@ static void compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka, /* The IT state must be cleared for both ARM and Thumb-2 */ spsr &= ~COMPAT_PSR_IT_MASK;
+ /* Restore the original endianness */ + spsr |= COMPAT_PSR_ENDSTATE; + if (ka->sa.sa_flags & SA_RESTORER) { retcode = ptr_to_compat(ka->sa.sa_restorer); } else {
From: James Morse james.morse@arm.com
commit 870828e57b141eff76a5325f20e4691dd2a599b1 upstream
Later patches need config_sctlr_el1 to set/clear bits in the sctlr_el1 register.
This patch moves this function into header a file.
Acked-by: Catalin Marinas catalin.marinas@arm.com Signed-off-by: James Morse james.morse@arm.com Signed-off-by: Will Deacon will.deacon@arm.com Signed-off-by: David Brown david.brown@linaro.org --- arch/arm64/include/asm/cputype.h | 3 --- arch/arm64/include/asm/sysreg.h | 12 ++++++++++++ arch/arm64/kernel/armv8_deprecated.c | 11 +---------- 3 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h index a84ec60..ee6403d 100644 --- a/arch/arm64/include/asm/cputype.h +++ b/arch/arm64/include/asm/cputype.h @@ -81,9 +81,6 @@ #define ID_AA64MMFR0_BIGEND(mmfr0) \ (((mmfr0) & ID_AA64MMFR0_BIGEND_MASK) >> ID_AA64MMFR0_BIGEND_SHIFT)
-#define SCTLR_EL1_CP15BEN (0x1 << 5) -#define SCTLR_EL1_SED (0x1 << 8) - #ifndef __ASSEMBLY__
/* diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index 5c89df0..56391fb 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -20,6 +20,9 @@ #ifndef __ASM_SYSREG_H #define __ASM_SYSREG_H
+#define SCTLR_EL1_CP15BEN (0x1 << 5) +#define SCTLR_EL1_SED (0x1 << 8) + #define sys_reg(op0, op1, crn, crm, op2) \ ((((op0)-2)<<19)|((op1)<<16)|((crn)<<12)|((crm)<<8)|((op2)<<5))
@@ -55,6 +58,15 @@ asm( " .endm\n" );
+static inline void config_sctlr_el1(u32 clear, u32 set) +{ + u32 val; + + asm volatile("mrs %0, sctlr_el1" : "=r" (val)); + val &= ~clear; + val |= set; + asm volatile("msr sctlr_el1, %0" : : "r" (val)); +} #endif
#endif /* __ASM_SYSREG_H */ diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c index 7922c2e..78d56bf 100644 --- a/arch/arm64/kernel/armv8_deprecated.c +++ b/arch/arm64/kernel/armv8_deprecated.c @@ -16,6 +16,7 @@
#include <asm/insn.h> #include <asm/opcodes.h> +#include <asm/sysreg.h> #include <asm/system_misc.h> #include <asm/traps.h> #include <asm/uaccess.h> @@ -504,16 +505,6 @@ ret: return 0; }
-static inline void config_sctlr_el1(u32 clear, u32 set) -{ - u32 val; - - asm volatile("mrs %0, sctlr_el1" : "=r" (val)); - val &= ~clear; - val |= set; - asm volatile("msr sctlr_el1, %0" : : "r" (val)); -} - static int cp15_barrier_set_hw_mode(bool enable) { if (enable)
From: "Michael S. Tsirkin" mst@redhat.com
commit 58fff51784cb5e1bcc06a1417be26eec4288507c upstream.
virtio wants to read bitwise types from userspace using get_user. At the moment this triggers sparse errors, since the value is passed through an integer.
Fix that up using __force.
Signed-off-by: Michael S. Tsirkin mst@redhat.com Acked-by: Will Deacon will.deacon@arm.com Signed-off-by: David Brown david.brown@linaro.org --- arch/arm64/include/asm/uaccess.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h index 3bf8f4e..9a2069b 100644 --- a/arch/arm64/include/asm/uaccess.h +++ b/arch/arm64/include/asm/uaccess.h @@ -147,7 +147,7 @@ do { \ default: \ BUILD_BUG(); \ } \ - (x) = (__typeof__(*(ptr)))__gu_val; \ + (x) = (__force __typeof__(*(ptr)))__gu_val; \ } while (0)
#define __get_user(x, ptr) \
From: Will Deacon will.deacon@arm.com
commit 23e94994464a7281838785675e09c8ed1055f62f upstream.
The AArch64 instruction set contains load/store pair memory accessors, so use these in our copy_*_user routines to transfer 16 bytes per iteration.
Reviewed-by: Catalin Marinas catalin.marinas@arm.com Signed-off-by: Will Deacon will.deacon@arm.com Signed-off-by: David Brown david.brown@linaro.org --- arch/arm64/lib/copy_from_user.S | 17 +++++++++++------ arch/arm64/lib/copy_in_user.S | 17 +++++++++++------ arch/arm64/lib/copy_to_user.S | 17 +++++++++++------ 3 files changed, 33 insertions(+), 18 deletions(-)
diff --git a/arch/arm64/lib/copy_from_user.S b/arch/arm64/lib/copy_from_user.S index 5e27add..47c3fa5 100644 --- a/arch/arm64/lib/copy_from_user.S +++ b/arch/arm64/lib/copy_from_user.S @@ -28,14 +28,19 @@ * x0 - bytes not copied */ ENTRY(__copy_from_user) - add x4, x1, x2 // upper user buffer boundary - subs x2, x2, #8 + add x5, x1, x2 // upper user buffer boundary + subs x2, x2, #16 + b.mi 1f +0: +USER(9f, ldp x3, x4, [x1], #16) + subs x2, x2, #16 + stp x3, x4, [x0], #16 + b.pl 0b +1: adds x2, x2, #8 b.mi 2f -1: USER(9f, ldr x3, [x1], #8 ) - subs x2, x2, #8 + sub x2, x2, #8 str x3, [x0], #8 - b.pl 1b 2: adds x2, x2, #4 b.mi 3f USER(9f, ldr w3, [x1], #4 ) @@ -56,7 +61,7 @@ ENDPROC(__copy_from_user)
.section .fixup,"ax" .align 2 -9: sub x2, x4, x1 +9: sub x2, x5, x1 mov x3, x2 10: strb wzr, [x0], #1 // zero remaining buffer space subs x3, x3, #1 diff --git a/arch/arm64/lib/copy_in_user.S b/arch/arm64/lib/copy_in_user.S index 84b6c9b..436bcc5 100644 --- a/arch/arm64/lib/copy_in_user.S +++ b/arch/arm64/lib/copy_in_user.S @@ -30,14 +30,19 @@ * x0 - bytes not copied */ ENTRY(__copy_in_user) - add x4, x0, x2 // upper user buffer boundary - subs x2, x2, #8 + add x5, x0, x2 // upper user buffer boundary + subs x2, x2, #16 + b.mi 1f +0: +USER(9f, ldp x3, x4, [x1], #16) + subs x2, x2, #16 +USER(9f, stp x3, x4, [x0], #16) + b.pl 0b +1: adds x2, x2, #8 b.mi 2f -1: USER(9f, ldr x3, [x1], #8 ) - subs x2, x2, #8 + sub x2, x2, #8 USER(9f, str x3, [x0], #8 ) - b.pl 1b 2: adds x2, x2, #4 b.mi 3f USER(9f, ldr w3, [x1], #4 ) @@ -58,6 +63,6 @@ ENDPROC(__copy_in_user)
.section .fixup,"ax" .align 2 -9: sub x0, x4, x0 // bytes not copied +9: sub x0, x5, x0 // bytes not copied ret .previous diff --git a/arch/arm64/lib/copy_to_user.S b/arch/arm64/lib/copy_to_user.S index a0aeeb9..f5e1f52 100644 --- a/arch/arm64/lib/copy_to_user.S +++ b/arch/arm64/lib/copy_to_user.S @@ -28,14 +28,19 @@ * x0 - bytes not copied */ ENTRY(__copy_to_user) - add x4, x0, x2 // upper user buffer boundary - subs x2, x2, #8 + add x5, x0, x2 // upper user buffer boundary + subs x2, x2, #16 + b.mi 1f +0: + ldp x3, x4, [x1], #16 + subs x2, x2, #16 +USER(9f, stp x3, x4, [x0], #16) + b.pl 0b +1: adds x2, x2, #8 b.mi 2f -1: ldr x3, [x1], #8 - subs x2, x2, #8 + sub x2, x2, #8 USER(9f, str x3, [x0], #8 ) - b.pl 1b 2: adds x2, x2, #4 b.mi 3f ldr w3, [x1], #4 @@ -56,6 +61,6 @@ ENDPROC(__copy_to_user)
.section .fixup,"ax" .align 2 -9: sub x0, x4, x0 // bytes not copied +9: sub x0, x5, x0 // bytes not copied ret .previous
From: Punit Agrawal punit.agrawal@arm.com
commit 0be0e44c182c4f13df13903fd1377671d157d7b7 upstream.
Port support for AArch32 instruction condition code checking from arm to arm64.
Signed-off-by: Punit Agrawal punit.agrawal@arm.com Reviewed-by: Catalin Marinas catalin.marinas@arm.com Signed-off-by: Will Deacon will.deacon@arm.com Signed-off-by: David Brown david.brown@linaro.org --- arch/arm64/include/asm/opcodes.h | 1 + arch/arm64/kernel/Makefile | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/include/asm/opcodes.h
diff --git a/arch/arm64/include/asm/opcodes.h b/arch/arm64/include/asm/opcodes.h new file mode 100644 index 0000000..4e603ea --- /dev/null +++ b/arch/arm64/include/asm/opcodes.h @@ -0,0 +1 @@ +#include <../../arm/include/asm/opcodes.h> diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 259126a..5e68564 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -19,7 +19,8 @@ arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \ cpuinfo.o cpu_errata.o cpufeature.o alternative.o
arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \ - sys_compat.o + sys_compat.o \ + ../../arm/kernel/opcodes.o arm64-obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o topology.o
From: Marc Zyngier marc.zyngier@arm.com
commit 8d883b23aed73cad844ba48051c7e96eddf0f51c upstream.
asm/alternative-asm.h and asm/alternative.h are extremely similar, and really deserve to live in the same file (as this makes further modufications a bit easier).
Fold the content of alternative-asm.h into alternative.h, and update the few users.
Acked-by: Will Deacon will.deacon@arm.com Signed-off-by: Marc Zyngier marc.zyngier@arm.com Signed-off-by: Catalin Marinas catalin.marinas@arm.com Signed-off-by: David Brown david.brown@linaro.org --- arch/arm64/include/asm/alternative-asm.h | 29 ----------------------------- arch/arm64/include/asm/alternative.h | 27 +++++++++++++++++++++++++++ arch/arm64/kernel/entry.S | 2 +- arch/arm64/mm/cache.S | 2 +- 4 files changed, 29 insertions(+), 31 deletions(-) delete mode 100644 arch/arm64/include/asm/alternative-asm.h
diff --git a/arch/arm64/include/asm/alternative-asm.h b/arch/arm64/include/asm/alternative-asm.h deleted file mode 100644 index 919a678..0000000 --- a/arch/arm64/include/asm/alternative-asm.h +++ /dev/null @@ -1,29 +0,0 @@ -#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 - -.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/alternative.h b/arch/arm64/include/asm/alternative.h index f6d206e..1c2ec68 100644 --- a/arch/arm64/include/asm/alternative.h +++ b/arch/arm64/include/asm/alternative.h @@ -1,6 +1,8 @@ #ifndef __ASM_ALTERNATIVE_H #define __ASM_ALTERNATIVE_H
+#ifndef __ASSEMBLY__ + #include <linux/types.h> #include <linux/stddef.h> #include <linux/stringify.h> @@ -40,4 +42,29 @@ void free_alternatives_memory(void); " .error "Alternatives instruction length mismatch"\n\t"\ ".endif\n"
+#else + +.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 + +.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_H */ diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 6c99b46..b5d2f23 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -21,7 +21,7 @@ #include <linux/init.h> #include <linux/linkage.h>
-#include <asm/alternative-asm.h> +#include <asm/alternative.h> #include <asm/assembler.h> #include <asm/asm-offsets.h> #include <asm/cpufeature.h> diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S index 8eaf185..de1e66b 100644 --- a/arch/arm64/mm/cache.S +++ b/arch/arm64/mm/cache.S @@ -21,7 +21,7 @@ #include <linux/init.h> #include <asm/assembler.h> #include <asm/cpufeature.h> -#include <asm/alternative-asm.h> +#include <asm/alternative.h>
#include "proc-macros.S"
From: Marc Zyngier marc.zyngier@arm.com
commit eb7c11ee3c5ce6c45ac28a5015a8e60ed458b412 upstream.
AArch64 toolchains suffer from the following bug:
$ cat blah.S 1: .inst 0x01020304 .if ((. - 1b) != 4) .error "blah" .endif $ aarch64-linux-gnu-gcc -c blah.S blah.S: Assembler messages: blah.S:3: Error: non-constant expression in ".if" statement
which precludes the use of msr_s and co as part of alternatives.
We workaround this issue by not directly testing the labels themselves, but by moving the current output pointer by a value that should always be zero. If this value is not null, then we will trigger a backward move, which is expclicitely forbidden. This triggers the error we're after:
AS arch/arm64/kvm/hyp.o arch/arm64/kvm/hyp.S: Assembler messages: arch/arm64/kvm/hyp.S:1377: Error: attempt to move .org backwards scripts/Makefile.build:294: recipe for target 'arch/arm64/kvm/hyp.o' failed make[1]: *** [arch/arm64/kvm/hyp.o] Error 1 Makefile:946: recipe for target 'arch/arm64/kvm' failed
Not pretty, but at least works on the current toolchains.
Acked-by: Will Deacon will.deacon@arm.com Signed-off-by: Marc Zyngier marc.zyngier@arm.com Signed-off-by: Catalin Marinas catalin.marinas@arm.com Signed-off-by: David Brown david.brown@linaro.org --- arch/arm64/include/asm/alternative.h | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-)
diff --git a/arch/arm64/include/asm/alternative.h b/arch/arm64/include/asm/alternative.h index 1c2ec68..ec12951 100644 --- a/arch/arm64/include/asm/alternative.h +++ b/arch/arm64/include/asm/alternative.h @@ -25,7 +25,20 @@ void free_alternatives_memory(void); " .byte 662b-661b\n" /* source len */ \ " .byte 664f-663f\n" /* replacement len */
-/* alternative assembly primitive: */ +/* + * alternative assembly primitive: + * + * If any of these .org directive fail, it means that insn1 and insn2 + * don't have the same length. This used to be written as + * + * .if ((664b-663b) != (662b-661b)) + * .error "Alternatives instruction length mismatch" + * .endif + * + * but most assemblers die if insn1 or insn2 have a .inst. This should + * be fixed in a binutils release posterior to 2.25.51.0.2 (anything + * containing commit 4e4d08cf7399b606 or c1baaddf8861). + */ #define ALTERNATIVE(oldinstr, newinstr, feature) \ "661:\n\t" \ oldinstr "\n" \ @@ -38,9 +51,8 @@ void free_alternatives_memory(void); newinstr "\n" \ "664:\n\t" \ ".popsection\n\t" \ - ".if ((664b-663b) != (662b-661b))\n\t" \ - " .error "Alternatives instruction length mismatch"\n\t"\ - ".endif\n" + ".org . - (664b-663b) + (662b-661b)\n\t" \ + ".org . - (662b-661b) + (664b-663b)\n"
#else
@@ -60,9 +72,8 @@ void free_alternatives_memory(void); .pushsection .altinstr_replacement, "ax" 663: \insn2 664: .popsection - .if ((664b-663b) != (662b-661b)) - .error "Alternatives instruction length mismatch" - .endif + .org . - (664b-663b) + (662b-661b) + .org . - (662b-661b) + (664b-663b) .endm
#endif /* __ASSEMBLY__ */
From: Daniel Thompson daniel.thompson@linaro.org
commit 63e40815f02584ba8174e0f6af40924b2b335cae upstream.
The existing alternative_insn macro has some limitations that make it hard to work with. In particular the fact it takes instructions from it own macro arguments means it doesn't play very nicely with C pre-processor macros because the macro arguments look like a string to the C pre-processor. Workarounds are (probably) possible but things start to look ugly.
Introduce an alternative set of macros that allows instructions to be presented to the assembler as normal and switch everything over to the new macros.
Signed-off-by: Daniel Thompson daniel.thompson@linaro.org Signed-off-by: Will Deacon will.deacon@arm.com Signed-off-by: David Brown david.brown@linaro.org --- arch/arm64/include/asm/alternative.h | 41 ++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+)
diff --git a/arch/arm64/include/asm/alternative.h b/arch/arm64/include/asm/alternative.h index ec12951..c4243a4 100644 --- a/arch/arm64/include/asm/alternative.h +++ b/arch/arm64/include/asm/alternative.h @@ -76,6 +76,47 @@ void free_alternatives_memory(void); .org . - (662b-661b) + (664b-663b) .endm
+/* + * Begin an alternative code sequence. + * + * The code that follows this macro will be assembled and linked as + * normal. There are no restrictions on this code. + */ +.macro alternative_if_not cap + .pushsection .altinstructions, "a" + altinstruction_entry 661f, 663f, \cap, 662f-661f, 664f-663f + .popsection +661: +.endm + +/* + * Provide the alternative code sequence. + * + * The code that follows this macro is assembled into a special + * section to be used for dynamic patching. Code that follows this + * macro must: + * + * 1. Be exactly the same length (in bytes) as the default code + * sequence. + * + * 2. Not contain a branch target that is used outside of the + * alternative sequence it is defined in (branches into an + * alternative sequence are not fixed up). + */ +.macro alternative_else +662: .pushsection .altinstr_replacement, "ax" +663: +.endm + +/* + * Complete an alternative code sequence. + */ +.macro alternative_endif +664: .popsection + .org . - (664b-663b) + (662b-661b) + .org . - (662b-661b) + (664b-663b) +.endm + #endif /* __ASSEMBLY__ */
#endif /* __ASM_ALTERNATIVE_H */
From: James Morse james.morse@arm.com
commit 91a5cefa2f98bdd3404c2fba57048c4fa225cc37 upstream.
Some uses of ALTERNATIVE() may depend on a feature that is disabled at compile time by a Kconfig option. In this case the unused alternative instructions waste space, and if the original instruction is a nop, it wastes time and space.
This patch adds an optional 'config' option to ALTERNATIVE() and alternative_insn that allows the compiler to remove both the original and alternative instructions if the config option is not defined.
Suggested-by: Catalin Marinas catalin.marinas@arm.com Acked-by: Catalin Marinas catalin.marinas@arm.com Signed-off-by: James Morse james.morse@arm.com Signed-off-by: Will Deacon will.deacon@arm.com Signed-off-by: David Brown david.brown@linaro.org --- arch/arm64/include/asm/alternative.h | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/include/asm/alternative.h b/arch/arm64/include/asm/alternative.h index c4243a4..4e3d4c8 100644 --- a/arch/arm64/include/asm/alternative.h +++ b/arch/arm64/include/asm/alternative.h @@ -3,6 +3,7 @@
#ifndef __ASSEMBLY__
+#include <linux/kconfig.h> #include <linux/types.h> #include <linux/stddef.h> #include <linux/stringify.h> @@ -39,7 +40,8 @@ void free_alternatives_memory(void); * be fixed in a binutils release posterior to 2.25.51.0.2 (anything * containing commit 4e4d08cf7399b606 or c1baaddf8861). */ -#define ALTERNATIVE(oldinstr, newinstr, feature) \ +#define __ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg_enabled) \ + ".if "__stringify(cfg_enabled)" == 1\n" \ "661:\n\t" \ oldinstr "\n" \ "662:\n" \ @@ -52,7 +54,11 @@ void free_alternatives_memory(void); "664:\n\t" \ ".popsection\n\t" \ ".org . - (664b-663b) + (662b-661b)\n\t" \ - ".org . - (662b-661b) + (664b-663b)\n" + ".org . - (662b-661b) + (664b-663b)\n" \ + ".endif\n" + +#define _ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg, ...) \ + __ALTERNATIVE_CFG(oldinstr, newinstr, feature, IS_ENABLED(cfg))
#else
@@ -64,7 +70,8 @@ void free_alternatives_memory(void); .byte \alt_len .endm
-.macro alternative_insn insn1 insn2 cap +.macro alternative_insn insn1, insn2, cap, enable = 1 + .if \enable 661: \insn1 662: .pushsection .altinstructions, "a" altinstruction_entry 661b, 663f, \cap, 662b-661b, 664f-663f @@ -74,6 +81,7 @@ void free_alternatives_memory(void); 664: .popsection .org . - (664b-663b) + (662b-661b) .org . - (662b-661b) + (664b-663b) + .endif .endm
/* @@ -117,6 +125,20 @@ void free_alternatives_memory(void); .org . - (662b-661b) + (664b-663b) .endm
+#define _ALTERNATIVE_CFG(insn1, insn2, cap, cfg, ...) \ + alternative_insn insn1, insn2, cap, IS_ENABLED(cfg) + + #endif /* __ASSEMBLY__ */
+/* + * Usage: asm(ALTERNATIVE(oldinstr, newinstr, feature)); + * + * Usage: asm(ALTERNATIVE(oldinstr, newinstr, feature, CONFIG_FOO)); + * N.B. If CONFIG_FOO is specified, but not selected, the whole block + * will be omitted, including oldinstr. + */ +#define ALTERNATIVE(oldinstr, newinstr, ...) \ + _ALTERNATIVE_CFG(oldinstr, newinstr, __VA_ARGS__, 1) + #endif /* __ASM_ALTERNATIVE_H */
From: James Morse james.morse@arm.com
commit 18ffa046c509d0cd011eeea2c0418f2d014771fc upstream.
When a new cpu feature is available, the cpu feature bits will have some initial value, which is incremented when the feature is updated. This patch changes 'register_value' to be 'min_field_value', and checks the feature bits value (interpreted as a signed int) is greater than this minimum.
Acked-by: Catalin Marinas catalin.marinas@arm.com Signed-off-by: James Morse james.morse@arm.com Signed-off-by: Will Deacon will.deacon@arm.com Signed-off-by: David Brown david.brown@linaro.org --- arch/arm64/include/asm/cpufeature.h | 4 ++-- arch/arm64/kernel/cpufeature.c | 14 +++++++++++--- 2 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index c104421..ad54dbf 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -41,8 +41,8 @@ struct arm64_cpu_capabilities { };
struct { /* Feature register checking */ - u64 register_mask; - u64 register_value; + int field_pos; + int min_field_value; }; }; }; diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 5ad86ce..7542a07 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -23,12 +23,20 @@ #include <asm/cpufeature.h>
static bool +feature_matches(u64 reg, const struct arm64_cpu_capabilities *entry) +{ + int val = cpuid_feature_extract_field(reg, entry->field_pos); + + return val >= entry->min_field_value; +} + +static bool has_id_aa64pfr0_feature(const struct arm64_cpu_capabilities *entry) { u64 val;
val = read_cpuid(id_aa64pfr0_el1); - return (val & entry->register_mask) == entry->register_value; + return feature_matches(val, entry); }
static const struct arm64_cpu_capabilities arm64_features[] = { @@ -36,8 +44,8 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .desc = "GIC system register CPU interface", .capability = ARM64_HAS_SYSREG_GIC_CPUIF, .matches = has_id_aa64pfr0_feature, - .register_mask = (0xf << 24), - .register_value = (1 << 24), + .field_pos = 24, + .min_field_value = 1, }, {}, };
From: James Morse james.morse@arm.com
commit 79b0e09a3c9bd74ee54582efdb351179d7c00351 upstream.
Based on arch/arm/include/asm/cputype.h, this function does the shifting and sign extension necessary when accessing cpu feature fields.
Signed-off-by: James Morse james.morse@arm.com Suggested-by: Russell King linux@arm.linux.org.uk Acked-by: Catalin Marinas catalin.marinas@arm.com Signed-off-by: Will Deacon will.deacon@arm.com Signed-off-by: David Brown david.brown@linaro.org --- arch/arm64/include/asm/cpufeature.h | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index ad54dbf..674cadd 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -70,6 +70,13 @@ static inline void cpus_set_cap(unsigned int num) __set_bit(num, cpu_hwcaps); }
+static inline int __attribute_const__ cpuid_feature_extract_field(u64 features, + int field) +{ + return (s64)(features << (64 - 4 - field)) >> (64 - 4); +} + + void check_cpu_capabilities(const struct arm64_cpu_capabilities *caps, const char *info); void check_local_cpu_errata(void);
From: James Morse james.morse@arm.com
commit 1c0763037f1e1caef739e36e09c6d41ed7b61b2d upstream.
This patch adds an 'enable()' callback to cpu capability/feature detection, allowing features that require some setup or configuration to get this opportunity once the feature has been detected.
Acked-by: Catalin Marinas catalin.marinas@arm.com Signed-off-by: James Morse james.morse@arm.com Signed-off-by: Will Deacon will.deacon@arm.com Signed-off-by: David Brown david.brown@linaro.org --- arch/arm64/include/asm/cpufeature.h | 1 + arch/arm64/kernel/cpufeature.c | 6 ++++++ 2 files changed, 7 insertions(+)
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 674cadd..f595f7d 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -34,6 +34,7 @@ struct arm64_cpu_capabilities { const char *desc; u16 capability; bool (*matches)(const struct arm64_cpu_capabilities *); + void (*enable)(void); union { struct { /* To be used for erratum handling only */ u32 midr_model; diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 7542a07..74fd0f7 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -63,6 +63,12 @@ void check_cpu_capabilities(const struct arm64_cpu_capabilities *caps, pr_info("%s %s\n", info, caps[i].desc); cpus_set_cap(caps[i].capability); } + + /* second pass allows enable() to consider interacting capabilities */ + for (i = 0; caps[i].desc; i++) { + if (cpus_have_cap(caps[i].capability) && caps[i].enable) + caps[i].enable(); + } }
void check_local_cpu_features(void)
From: "Suzuki K. Poulose" suzuki.poulose@arm.com
commit 9ded63aaf83eba76e1a54ac02581c2badc497f1a upstream.
The system register encoding generated by sys_reg() works only for MRS/MSR(Register) operations, as we hardcode Bit20 to 1 in mrs_s/msr_s mask. This makes it unusable for generating instructions accessing registers with Op0 < 2(e.g, PSTATE.x with Op0=0).
As per ARMv8 ARM, (Ref: ARMv8 ARM, Section: "System instruction class encoding overview", C5.2, version:ARM DDI 0487A.f), the instruction encoding reserves bits [20-19] for Op0.
This patch generalises the sys_reg, mrs_s and msr_s macros, so that we could use them to access any of the supported system register.
Cc: James Morse james.morse@arm.com Cc: Catalin Marinas catalin.marinas@arm.com Signed-off-by: Suzuki K. Poulose suzuki.poulose@arm.com Reviewed-by: Catalin Marinas catalin.marinas@arm.com Signed-off-by: Will Deacon will.deacon@arm.com Signed-off-by: David Brown david.brown@linaro.org --- arch/arm64/include/asm/sysreg.h | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-)
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index 56391fb..5295bcb 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -23,8 +23,18 @@ #define SCTLR_EL1_CP15BEN (0x1 << 5) #define SCTLR_EL1_SED (0x1 << 8)
+/* + * ARMv8 ARM reserves the following encoding for system registers: + * (Ref: ARMv8 ARM, Section: "System instruction class encoding overview", + * C5.2, version:ARM DDI 0487A.f) + * [20-19] : Op0 + * [18-16] : Op1 + * [15-12] : CRn + * [11-8] : CRm + * [7-5] : Op2 + */ #define sys_reg(op0, op1, crn, crm, op2) \ - ((((op0)-2)<<19)|((op1)<<16)|((crn)<<12)|((crm)<<8)|((op2)<<5)) + ((((op0)&3)<<19)|((op1)<<16)|((crn)<<12)|((crm)<<8)|((op2)<<5))
#ifdef __ASSEMBLY__
@@ -34,11 +44,11 @@ .equ __reg_num_xzr, 31
.macro mrs_s, rt, sreg - .inst 0xd5300000|(\sreg)|(__reg_num_\rt) + .inst 0xd5200000|(\sreg)|(__reg_num_\rt) .endm
.macro msr_s, sreg, rt - .inst 0xd5100000|(\sreg)|(__reg_num_\rt) + .inst 0xd5000000|(\sreg)|(__reg_num_\rt) .endm
#else @@ -50,11 +60,11 @@ asm( " .equ __reg_num_xzr, 31\n" "\n" " .macro mrs_s, rt, sreg\n" -" .inst 0xd5300000|(\sreg)|(__reg_num_\rt)\n" +" .inst 0xd5200000|(\sreg)|(__reg_num_\rt)\n" " .endm\n" "\n" " .macro msr_s, sreg, rt\n" -" .inst 0xd5100000|(\sreg)|(__reg_num_\rt)\n" +" .inst 0xd5000000|(\sreg)|(__reg_num_\rt)\n" " .endm\n" );
From: James Morse james.morse@arm.com
commit 338d4f49d6f7114a017d294ccf7374df4f998edc upstream.
'Privileged Access Never' is a new arm8.1 feature which prevents privileged code from accessing any virtual address where read or write access is also permitted at EL0.
This patch enables the PAN feature on all CPUs, and modifies {get,put}_user helpers temporarily to permit access.
This will catch kernel bugs where user memory is accessed directly. 'Unprivileged loads and stores' using ldtrb et al are unaffected by PAN.
Reviewed-by: Catalin Marinas catalin.marinas@arm.com Signed-off-by: James Morse james.morse@arm.com [will: use ALTERNATIVE in asm and tidy up pan_enable check] Signed-off-by: Will Deacon will.deacon@arm.com Signed-off-by: David Brown david.brown@linaro.org --- arch/arm64/Kconfig | 14 ++++++++++++++ arch/arm64/include/asm/cpufeature.h | 3 ++- arch/arm64/include/asm/futex.h | 8 ++++++++ arch/arm64/include/asm/processor.h | 2 ++ arch/arm64/include/asm/sysreg.h | 8 ++++++++ arch/arm64/include/asm/uaccess.h | 11 +++++++++++ arch/arm64/include/uapi/asm/ptrace.h | 1 + arch/arm64/kernel/armv8_deprecated.c | 8 +++++++- arch/arm64/kernel/cpufeature.c | 20 ++++++++++++++++++++ arch/arm64/lib/clear_user.S | 8 ++++++++ arch/arm64/lib/copy_from_user.S | 8 ++++++++ arch/arm64/lib/copy_in_user.S | 8 ++++++++ arch/arm64/lib/copy_to_user.S | 8 ++++++++ arch/arm64/mm/fault.c | 16 ++++++++++++++++ 14 files changed, 121 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 7f74b4c..131dedc 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -494,6 +494,20 @@ config FORCE_MAX_ZONEORDER default "14" if (ARM64_64K_PAGES && TRANSPARENT_HUGEPAGE) default "11"
+config ARM64_PAN + bool "Enable support for Privileged Access Never (PAN)" + default y + help + Privileged Access Never (PAN; part of the ARMv8.1 Extensions) + prevents the kernel or hypervisor from accessing user-space (EL0) + memory directly. + + Choosing this option will cause any unprotected (not using + copy_to_user et al) memory access to fail with a permission fault. + + The feature is detected at runtime, and will remain as a 'nop' + instruction if the cpu does not implement the feature. + menuconfig ARMV8_DEPRECATED bool "Emulate deprecated/obsolete ARMv8 instructions" depends on COMPAT diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index f595f7d..d71140b 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -25,8 +25,9 @@ #define ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE 1 #define ARM64_WORKAROUND_845719 2 #define ARM64_HAS_SYSREG_GIC_CPUIF 3 +#define ARM64_HAS_PAN 4
-#define ARM64_NCAPS 4 +#define ARM64_NCAPS 5
#ifndef __ASSEMBLY__
diff --git a/arch/arm64/include/asm/futex.h b/arch/arm64/include/asm/futex.h index 5f750dc..6673462 100644 --- a/arch/arm64/include/asm/futex.h +++ b/arch/arm64/include/asm/futex.h @@ -20,10 +20,16 @@
#include <linux/futex.h> #include <linux/uaccess.h> + +#include <asm/alternative.h> +#include <asm/cpufeature.h> #include <asm/errno.h> +#include <asm/sysreg.h>
#define __futex_atomic_op(insn, ret, oldval, uaddr, tmp, oparg) \ asm volatile( \ + ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN) \ "1: ldxr %w1, %2\n" \ insn "\n" \ "2: stlxr %w3, %w0, %2\n" \ @@ -39,6 +45,8 @@ " .align 3\n" \ " .quad 1b, 4b, 2b, 4b\n" \ " .popsection\n" \ + ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN) \ : "=&r" (ret), "=&r" (oldval), "+Q" (*uaddr), "=&r" (tmp) \ : "r" (oparg), "Ir" (-EFAULT) \ : "memory") diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h index 286b1be..f3a965e 100644 --- a/arch/arm64/include/asm/processor.h +++ b/arch/arm64/include/asm/processor.h @@ -166,4 +166,6 @@ static inline void spin_lock_prefetch(const void *x)
#endif
+void cpu_enable_pan(void); + #endif /* __ASM_PROCESSOR_H */ diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index 5295bcb..a7f3d4b 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -20,6 +20,8 @@ #ifndef __ASM_SYSREG_H #define __ASM_SYSREG_H
+#include <asm/opcodes.h> + #define SCTLR_EL1_CP15BEN (0x1 << 5) #define SCTLR_EL1_SED (0x1 << 8)
@@ -36,6 +38,12 @@ #define sys_reg(op0, op1, crn, crm, op2) \ ((((op0)&3)<<19)|((op1)<<16)|((crn)<<12)|((crm)<<8)|((op2)<<5))
+#define REG_PSTATE_PAN_IMM sys_reg(0, 0, 4, 0, 4) +#define SCTLR_EL1_SPAN (1 << 23) + +#define SET_PSTATE_PAN(x) __inst_arm(0xd5000000 | REG_PSTATE_PAN_IMM |\ + (!!x)<<8 | 0x1f) + #ifdef __ASSEMBLY__
.irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30 diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h index 9a2069b..cb8dab4 100644 --- a/arch/arm64/include/asm/uaccess.h +++ b/arch/arm64/include/asm/uaccess.h @@ -24,7 +24,10 @@ #include <linux/string.h> #include <linux/thread_info.h>
+#include <asm/alternative.h> +#include <asm/cpufeature.h> #include <asm/ptrace.h> +#include <asm/sysreg.h> #include <asm/errno.h> #include <asm/memory.h> #include <asm/compiler.h> @@ -131,6 +134,8 @@ static inline void set_fs(mm_segment_t fs) do { \ unsigned long __gu_val; \ __chk_user_ptr(ptr); \ + asm(ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN)); \ switch (sizeof(*(ptr))) { \ case 1: \ __get_user_asm("ldrb", "%w", __gu_val, (ptr), (err)); \ @@ -148,6 +153,8 @@ do { \ BUILD_BUG(); \ } \ (x) = (__force __typeof__(*(ptr)))__gu_val; \ + asm(ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN)); \ } while (0)
#define __get_user(x, ptr) \ @@ -194,6 +201,8 @@ do { \ do { \ __typeof__(*(ptr)) __pu_val = (x); \ __chk_user_ptr(ptr); \ + asm(ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN)); \ switch (sizeof(*(ptr))) { \ case 1: \ __put_user_asm("strb", "%w", __pu_val, (ptr), (err)); \ @@ -210,6 +219,8 @@ do { \ default: \ BUILD_BUG(); \ } \ + asm(ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN)); \ } while (0)
#define __put_user(x, ptr) \ diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h index 6913643..208db3d 100644 --- a/arch/arm64/include/uapi/asm/ptrace.h +++ b/arch/arm64/include/uapi/asm/ptrace.h @@ -44,6 +44,7 @@ #define PSR_I_BIT 0x00000080 #define PSR_A_BIT 0x00000100 #define PSR_D_BIT 0x00000200 +#define PSR_PAN_BIT 0x00400000 #define PSR_Q_BIT 0x08000000 #define PSR_V_BIT 0x10000000 #define PSR_C_BIT 0x20000000 diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c index 78d56bf..bcee7ab 100644 --- a/arch/arm64/kernel/armv8_deprecated.c +++ b/arch/arm64/kernel/armv8_deprecated.c @@ -14,6 +14,8 @@ #include <linux/slab.h> #include <linux/sysctl.h>
+#include <asm/alternative.h> +#include <asm/cpufeature.h> #include <asm/insn.h> #include <asm/opcodes.h> #include <asm/sysreg.h> @@ -280,6 +282,8 @@ static void register_insn_emulation_sysctl(struct ctl_table *table) */ #define __user_swpX_asm(data, addr, res, temp, B) \ __asm__ __volatile__( \ + ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN) \ " mov %w2, %w1\n" \ "0: ldxr"B" %w1, [%3]\n" \ "1: stxr"B" %w0, %w2, [%3]\n" \ @@ -295,7 +299,9 @@ static void register_insn_emulation_sysctl(struct ctl_table *table) " .align 3\n" \ " .quad 0b, 3b\n" \ " .quad 1b, 3b\n" \ - " .popsection" \ + " .popsection\n" \ + ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN) \ : "=&r" (res), "+r" (data), "=&r" (temp) \ : "r" (addr), "i" (-EAGAIN), "i" (-EFAULT) \ : "memory") diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 74fd0f7..978fa16 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -21,6 +21,7 @@ #include <linux/types.h> #include <asm/cpu.h> #include <asm/cpufeature.h> +#include <asm/processor.h>
static bool feature_matches(u64 reg, const struct arm64_cpu_capabilities *entry) @@ -39,6 +40,15 @@ has_id_aa64pfr0_feature(const struct arm64_cpu_capabilities *entry) return feature_matches(val, entry); }
+static bool __maybe_unused +has_id_aa64mmfr1_feature(const struct arm64_cpu_capabilities *entry) +{ + u64 val; + + val = read_cpuid(id_aa64mmfr1_el1); + return feature_matches(val, entry); +} + static const struct arm64_cpu_capabilities arm64_features[] = { { .desc = "GIC system register CPU interface", @@ -47,6 +57,16 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .field_pos = 24, .min_field_value = 1, }, +#ifdef CONFIG_ARM64_PAN + { + .desc = "Privileged Access Never", + .capability = ARM64_HAS_PAN, + .matches = has_id_aa64mmfr1_feature, + .field_pos = 20, + .min_field_value = 1, + .enable = cpu_enable_pan, + }, +#endif /* CONFIG_ARM64_PAN */ {}, };
diff --git a/arch/arm64/lib/clear_user.S b/arch/arm64/lib/clear_user.S index c17967f..a9723c7 100644 --- a/arch/arm64/lib/clear_user.S +++ b/arch/arm64/lib/clear_user.S @@ -16,7 +16,11 @@ * along with this program. If not, see http://www.gnu.org/licenses/. */ #include <linux/linkage.h> + +#include <asm/alternative.h> #include <asm/assembler.h> +#include <asm/cpufeature.h> +#include <asm/sysreg.h>
.text
@@ -29,6 +33,8 @@ * Alignment fixed up by hardware. */ ENTRY(__clear_user) +ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN) mov x2, x1 // save the size for fixup return subs x1, x1, #8 b.mi 2f @@ -48,6 +54,8 @@ USER(9f, strh wzr, [x0], #2 ) b.mi 5f USER(9f, strb wzr, [x0] ) 5: mov x0, #0 +ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN) ret ENDPROC(__clear_user)
diff --git a/arch/arm64/lib/copy_from_user.S b/arch/arm64/lib/copy_from_user.S index 47c3fa5..1be9ef2 100644 --- a/arch/arm64/lib/copy_from_user.S +++ b/arch/arm64/lib/copy_from_user.S @@ -15,7 +15,11 @@ */
#include <linux/linkage.h> + +#include <asm/alternative.h> #include <asm/assembler.h> +#include <asm/cpufeature.h> +#include <asm/sysreg.h>
/* * Copy from user space to a kernel buffer (alignment handled by the hardware) @@ -28,6 +32,8 @@ * x0 - bytes not copied */ ENTRY(__copy_from_user) +ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN) add x5, x1, x2 // upper user buffer boundary subs x2, x2, #16 b.mi 1f @@ -56,6 +62,8 @@ USER(9f, ldrh w3, [x1], #2 ) USER(9f, ldrb w3, [x1] ) strb w3, [x0] 5: mov x0, #0 +ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN) ret ENDPROC(__copy_from_user)
diff --git a/arch/arm64/lib/copy_in_user.S b/arch/arm64/lib/copy_in_user.S index 436bcc5..1b94661e 100644 --- a/arch/arm64/lib/copy_in_user.S +++ b/arch/arm64/lib/copy_in_user.S @@ -17,7 +17,11 @@ */
#include <linux/linkage.h> + +#include <asm/alternative.h> #include <asm/assembler.h> +#include <asm/cpufeature.h> +#include <asm/sysreg.h>
/* * Copy from user space to user space (alignment handled by the hardware) @@ -30,6 +34,8 @@ * x0 - bytes not copied */ ENTRY(__copy_in_user) +ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN) add x5, x0, x2 // upper user buffer boundary subs x2, x2, #16 b.mi 1f @@ -58,6 +64,8 @@ USER(9f, strh w3, [x0], #2 ) USER(9f, ldrb w3, [x1] ) USER(9f, strb w3, [x0] ) 5: mov x0, #0 +ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN) ret ENDPROC(__copy_in_user)
diff --git a/arch/arm64/lib/copy_to_user.S b/arch/arm64/lib/copy_to_user.S index f5e1f52..a257b47 100644 --- a/arch/arm64/lib/copy_to_user.S +++ b/arch/arm64/lib/copy_to_user.S @@ -15,7 +15,11 @@ */
#include <linux/linkage.h> + +#include <asm/alternative.h> #include <asm/assembler.h> +#include <asm/cpufeature.h> +#include <asm/sysreg.h>
/* * Copy to user space from a kernel buffer (alignment handled by the hardware) @@ -28,6 +32,8 @@ * x0 - bytes not copied */ ENTRY(__copy_to_user) +ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN) add x5, x0, x2 // upper user buffer boundary subs x2, x2, #16 b.mi 1f @@ -56,6 +62,8 @@ USER(9f, strh w3, [x0], #2 ) ldrb w3, [x1] USER(9f, strb w3, [x0] ) 5: mov x0, #0 +ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN) ret ENDPROC(__copy_to_user)
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 6094c64..71e5707 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -30,9 +30,11 @@ #include <linux/highmem.h> #include <linux/perf_event.h>
+#include <asm/cpufeature.h> #include <asm/exception.h> #include <asm/debug-monitors.h> #include <asm/esr.h> +#include <asm/sysreg.h> #include <asm/system_misc.h> #include <asm/pgtable.h> #include <asm/tlbflush.h> @@ -225,6 +227,13 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, }
/* + * PAN bit set implies the fault happened in kernel space, but not + * in the arch's user access functions. + */ + if (IS_ENABLED(CONFIG_ARM64_PAN) && (regs->pstate & PSR_PAN_BIT)) + goto no_context; + + /* * As per x86, we may deadlock here. However, since the kernel only * validly references user space from well defined areas of the code, * we can bug out early if this is from code which shouldn't. @@ -531,3 +540,10 @@ asmlinkage int __exception do_debug_exception(unsigned long addr,
return 0; } + +#ifdef CONFIG_ARM64_PAN +void cpu_enable_pan(void) +{ + config_sctlr_el1(SCTLR_EL1_SPAN, 0); +} +#endif /* CONFIG_ARM64_PAN */
Thanks a lot, David!
Did you have a git tree for pull?
Regards Alex
On 12/04/2015 10:47 AM, David Brown wrote:
The following patches bring in
commit 20af540051e1c1f7a7d9b9e4613c1ecc53ded4a6 Author: James Morse <james.morse@arm.com> Date: Wed Jul 22 19:05:54 2015 +0100
arm64: kernel: Add support for Privileged Access Never commit 338d4f49d6f7114a017d294ccf7374df4f998edc upstream. 'Privileged Access Never' is a new arm8.1 feature which prevents privileged code from accessing any virtual address where read or write access is also permitted at EL0. This patch enables the PAN feature on all CPUs, and modifies {get,put}_user helpers temporarily to permit access. This will catch kernel bugs where user memory is accessed directly. 'Unprivileged loads and stores' using ldtrb et al are unaffected by PAN.
along with an additional 26 patches it depends on.
Daniel Thompson (1): arm64: alternative: Provide if/else/endif assembler macros
Fabio Estevam (1): arm64: Provide a namespace to NCAPS
James Morse (6): arm64: kernel: Move config_sctlr_el1 arm64: kernel: Add optional CONFIG_ parameter to ALTERNATIVE() arm64: kernel: Add min_field_value and use '>=' for feature detection arm64: kernel: Add cpuid_feature_extract_field() for 4bit sign extension arm64: kernel: Add cpufeature 'enable' callback arm64: kernel: Add support for Privileged Access Never
Marc Zyngier (4): arm64: Extract feature parsing code from cpu_errata.c arm64: alternative: Introduce feature for GICv3 CPU interface arm64: alternative: Merge alternative-asm.h into alternative.h arm64: alternative: Work around .inst assembler bugs
Michael S. Tsirkin (1): arm64/uaccess: fix sparse errors
Punit Agrawal (6): arm64: Add framework for legacy instruction emulation arm64: Add support for hooks to handle undefined instructions arm64: Port SWP/SWPB emulation support from arm arm64: Emulate CP15 Barrier instructions arm64: Trace emulation of AArch32 legacy instructions arm64: Add AArch32 instruction set condition code checks
Suzuki K. Poulose (4): arm64: Track system support for mixed endian EL0 arm64: Consolidate hotplug notifier for instruction emulation arm64: Emulate SETEND for AArch32 tasks arm64: Generalise msr_s/mrs_s operations
Will Deacon (4): arm64: alternatives: fix pr_fmt string for consistency arm64: fix return code check when changing emulation handler arm64: kconfig: move emulation option under kernel features arm64: lib: use pair accessors for copy_*_user routines
Documentation/arm64/legacy_instructions.txt | 57 +++ arch/arm64/Kconfig | 81 ++++ arch/arm64/include/asm/alternative-asm.h | 29 -- arch/arm64/include/asm/alternative.h | 109 ++++- arch/arm64/include/asm/cpufeature.h | 42 +- arch/arm64/include/asm/cputype.h | 14 + arch/arm64/include/asm/futex.h | 8 + arch/arm64/include/asm/insn.h | 10 + arch/arm64/include/asm/opcodes.h | 1 + arch/arm64/include/asm/processor.h | 2 + arch/arm64/include/asm/ptrace.h | 7 + arch/arm64/include/asm/sysreg.h | 40 +- arch/arm64/include/asm/traps.h | 16 + arch/arm64/include/asm/uaccess.h | 13 +- arch/arm64/include/uapi/asm/ptrace.h | 1 + arch/arm64/kernel/Makefile | 7 +- arch/arm64/kernel/armv8_deprecated.c | 659 ++++++++++++++++++++++++++++ arch/arm64/kernel/cpu_errata.c | 36 +- arch/arm64/kernel/cpufeature.c | 97 ++++ arch/arm64/kernel/cpuinfo.c | 23 + arch/arm64/kernel/entry.S | 2 +- arch/arm64/kernel/insn.c | 26 ++ arch/arm64/kernel/setup.c | 2 +- arch/arm64/kernel/signal32.c | 5 +- arch/arm64/kernel/trace-events-emulation.h | 35 ++ arch/arm64/kernel/traps.c | 66 +++ arch/arm64/lib/clear_user.S | 8 + arch/arm64/lib/copy_from_user.S | 25 +- arch/arm64/lib/copy_in_user.S | 25 +- arch/arm64/lib/copy_to_user.S | 25 +- arch/arm64/mm/cache.S | 2 +- arch/arm64/mm/fault.c | 16 + 32 files changed, 1389 insertions(+), 100 deletions(-) create mode 100644 Documentation/arm64/legacy_instructions.txt delete mode 100644 arch/arm64/include/asm/alternative-asm.h create mode 100644 arch/arm64/include/asm/opcodes.h create mode 100644 arch/arm64/kernel/armv8_deprecated.c create mode 100644 arch/arm64/kernel/cpufeature.c create mode 100644 arch/arm64/kernel/trace-events-emulation.h
On Fri, Dec 04, 2015 at 11:07:58AM +0800, Alex Shi wrote:
Thanks a lot, David!
Did you have a git tree for pull?
I have trees ready. I was wondering if I should push to:
git.linaro.org git.davidb.org git.kernel.org
if you have any preferences.
I think we were probably wanting these to just be on a branch for now, until they can go through some more testing. Especially the 3.18 might be a bit heavy for 'stable', so we may just want to make it available as a branch.
I'll send out a pull request in a little bit.
David
On 12/04/2015 11:12 AM, David Brown wrote:
On Fri, Dec 04, 2015 at 11:07:58AM +0800, Alex Shi wrote:
Thanks a lot, David!
Did you have a git tree for pull?
I have trees ready. I was wondering if I should push to:
git.linaro.org git.davidb.org git.kernel.org
if you have any preferences.
Is linaro.org better?
I think we were probably wanting these to just be on a branch for now, until they can go through some more testing. Especially the 3.18 might be a bit heavy for 'stable', so we may just want to make it available as a branch.
Yes, I will push it on lsk-v4.1/v3.18-test branch first to see the report from kernelci.org
I'll send out a pull request in a little bit.
thanks!
David
On Fri, Dec 04, 2015 at 11:14:08AM +0800, Alex Shi wrote:
Did you have a git tree for pull?
I have trees ready. I was wondering if I should push to:
git.linaro.org git.davidb.org git.kernel.org
if you have any preferences.
Is linaro.org better?
That probably makes the most sense. I just have to figure out how to push there :-)
David
The following changes since commit b12403044336e7d567f309eb443aa9acf76380af:
Linux 3.18.24 (2015-10-31 16:39:51 -0400)
are available in the git repository at:
https://git.linaro.org/people/david.brown/linux-lsk pan-3.18
for you to fetch changes up to 20af540051e1c1f7a7d9b9e4613c1ecc53ded4a6:
arm64: kernel: Add support for Privileged Access Never (2015-12-03 16:53:53 -0800)
---------------------------------------------------------------- Daniel Thompson (1): arm64: alternative: Provide if/else/endif assembler macros
Fabio Estevam (1): arm64: Provide a namespace to NCAPS
James Morse (6): arm64: kernel: Move config_sctlr_el1 arm64: kernel: Add optional CONFIG_ parameter to ALTERNATIVE() arm64: kernel: Add min_field_value and use '>=' for feature detection arm64: kernel: Add cpuid_feature_extract_field() for 4bit sign extension arm64: kernel: Add cpufeature 'enable' callback arm64: kernel: Add support for Privileged Access Never
Marc Zyngier (4): arm64: Extract feature parsing code from cpu_errata.c arm64: alternative: Introduce feature for GICv3 CPU interface arm64: alternative: Merge alternative-asm.h into alternative.h arm64: alternative: Work around .inst assembler bugs
Michael S. Tsirkin (1): arm64/uaccess: fix sparse errors
Punit Agrawal (6): arm64: Add framework for legacy instruction emulation arm64: Add support for hooks to handle undefined instructions arm64: Port SWP/SWPB emulation support from arm arm64: Emulate CP15 Barrier instructions arm64: Trace emulation of AArch32 legacy instructions arm64: Add AArch32 instruction set condition code checks
Suzuki K. Poulose (4): arm64: Track system support for mixed endian EL0 arm64: Consolidate hotplug notifier for instruction emulation arm64: Emulate SETEND for AArch32 tasks arm64: Generalise msr_s/mrs_s operations
Will Deacon (4): arm64: alternatives: fix pr_fmt string for consistency arm64: fix return code check when changing emulation handler arm64: kconfig: move emulation option under kernel features arm64: lib: use pair accessors for copy_*_user routines
Documentation/arm64/legacy_instructions.txt | 57 +++ arch/arm64/Kconfig | 81 ++++ arch/arm64/include/asm/alternative-asm.h | 29 -- arch/arm64/include/asm/alternative.h | 109 ++++- arch/arm64/include/asm/cpufeature.h | 42 +- arch/arm64/include/asm/cputype.h | 14 + arch/arm64/include/asm/futex.h | 8 + arch/arm64/include/asm/insn.h | 10 + arch/arm64/include/asm/opcodes.h | 1 + arch/arm64/include/asm/processor.h | 2 + arch/arm64/include/asm/ptrace.h | 7 + arch/arm64/include/asm/sysreg.h | 40 +- arch/arm64/include/asm/traps.h | 16 + arch/arm64/include/asm/uaccess.h | 13 +- arch/arm64/include/uapi/asm/ptrace.h | 1 + arch/arm64/kernel/Makefile | 7 +- arch/arm64/kernel/armv8_deprecated.c | 659 ++++++++++++++++++++++++++++ arch/arm64/kernel/cpu_errata.c | 36 +- arch/arm64/kernel/cpufeature.c | 97 ++++ arch/arm64/kernel/cpuinfo.c | 23 + arch/arm64/kernel/entry.S | 2 +- arch/arm64/kernel/insn.c | 26 ++ arch/arm64/kernel/setup.c | 2 +- arch/arm64/kernel/signal32.c | 5 +- arch/arm64/kernel/trace-events-emulation.h | 35 ++ arch/arm64/kernel/traps.c | 66 +++ arch/arm64/lib/clear_user.S | 8 + arch/arm64/lib/copy_from_user.S | 25 +- arch/arm64/lib/copy_in_user.S | 25 +- arch/arm64/lib/copy_to_user.S | 25 +- arch/arm64/mm/cache.S | 2 +- arch/arm64/mm/fault.c | 16 + 32 files changed, 1389 insertions(+), 100 deletions(-) create mode 100644 Documentation/arm64/legacy_instructions.txt delete mode 100644 arch/arm64/include/asm/alternative-asm.h create mode 100644 arch/arm64/include/asm/opcodes.h create mode 100644 arch/arm64/kernel/armv8_deprecated.c create mode 100644 arch/arm64/kernel/cpufeature.c create mode 100644 arch/arm64/kernel/trace-events-emulation.h
David Brown david.brown@linaro.org writes:
The following changes since commit b12403044336e7d567f309eb443aa9acf76380af:
Linux 3.18.24 (2015-10-31 16:39:51 -0400)
are available in the git repository at:
https://git.linaro.org/people/david.brown/linux-lsk pan-3.18
I'm not seeing this branch, but I do see a davidb/pan-3.18. Presumably the same thing?
Kevin
It should be. Looks like I have a few things to figure out with Linaro's git.
I can resend both pull requests a little later today after I finish some testing on the rebased 4.1.
David
On Tuesday, December 8, 2015, Kevin Hilman khilman@linaro.org wrote:
David Brown <david.brown@linaro.org javascript:;> writes:
The following changes since commit
b12403044336e7d567f309eb443aa9acf76380af:
Linux 3.18.24 (2015-10-31 16:39:51 -0400)
are available in the git repository at:
https://git.linaro.org/people/david.brown/linux-lsk pan-3.18
I'm not seeing this branch, but I do see a davidb/pan-3.18. Presumably the same thing?
Kevin
On Tue, Dec 08, 2015 at 12:01:04PM -0800, Kevin Hilman wrote:
David Brown david.brown@linaro.org writes:
The following changes since commit b12403044336e7d567f309eb443aa9acf76380af:
Linux 3.18.24 (2015-10-31 16:39:51 -0400)
are available in the git repository at:
https://git.linaro.org/people/david.brown/linux-lsk pan-3.18
I'm not seeing this branch, but I do see a davidb/pan-3.18. Presumably the same thing?
Yes, although I've also pushed it to pan-3.18 directly.
I also sent an update to the 4.1 pull request, based on 4.1.13, which resolves the merge conflict Alex was seeing.
David
David Brown david.brown@linaro.org writes:
On Tue, Dec 08, 2015 at 12:01:04PM -0800, Kevin Hilman wrote:
David Brown david.brown@linaro.org writes:
The following changes since commit b12403044336e7d567f309eb443aa9acf76380af:
Linux 3.18.24 (2015-10-31 16:39:51 -0400)
are available in the git repository at:
https://git.linaro.org/people/david.brown/linux-lsk pan-3.18
I'm not seeing this branch, but I do see a davidb/pan-3.18. Presumably the same thing?
Yes, although I've also pushed it to pan-3.18 directly.
OK, I've pulled this in to the v3.18/topic/PAN branch, merged it with the current lsk-v3.18 and pushed it into the test branch (lsk-v3.18-test) so it can have a spin through kernelci.org: http://kernelci.org/job/lsk/
Kevin
linaro-kernel@lists.linaro.org