Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit abacc500 authored by Kevin Hilman's avatar Kevin Hilman
Browse files
Merge branch 'pan-3.18' of https://git.linaro.org/people/david.brown/linux-lsk into linux-linaro-lsk-v3.18

* 'pan-3.18' of https://git.linaro.org/people/david.brown/linux-lsk: (27 commits)
  arm64: kernel: Add support for Privileged Access Never
  arm64: Generalise msr_s/mrs_s operations
  arm64: kernel: Add cpufeature 'enable' callback
  arm64: kernel: Add cpuid_feature_extract_field() for 4bit sign extension
  arm64: kernel: Add min_field_value and use '>=' for feature detection
  arm64: kernel: Add optional CONFIG_ parameter to ALTERNATIVE()
  arm64: alternative: Provide if/else/endif assembler macros
  arm64: alternative: Work around .inst assembler bugs
  arm64: alternative: Merge alternative-asm.h into alternative.h
  arm64: Add AArch32 instruction set condition code checks
  arm64: lib: use pair accessors for copy_*_user routines
  arm64/uaccess: fix sparse errors
  arm64: kernel: Move config_sctlr_el1
  arm64: Emulate SETEND for AArch32 tasks
  arm64: kconfig: move emulation option under kernel features
  arm64: Consolidate hotplug notifier for instruction emulation
  arm64: fix return code check when changing emulation handler
  arm64: Trace emulation of AArch32 legacy instructions
  arm64: Emulate CP15 Barrier instructions
  arm64: Port SWP/SWPB emulation support from arm
  ...

Conflicts:
	arch/arm64/kernel/Makefile
parents e46761bb 20af5400
Loading
Loading
Loading
Loading
+57 −0
Original line number Diff line number Diff line
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.

Note: Instruction emulation may not be possible in all cases. See
individual instruction notes for further information.

Supported legacy instructions
-----------------------------
* SWP{B}
Node: /proc/sys/abi/swp
Status: Obsolete
Default: Undef (0)

* CP15 Barriers
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.
+81 −0
Original line number Diff line number Diff line
@@ -496,6 +496,87 @@ 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
	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

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

menu "Boot options"
+0 −29
Original line number Diff line number Diff line
#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 */
+105 −4
Original line number Diff line number Diff line
#ifndef __ASM_ALTERNATIVE_H
#define __ASM_ALTERNATIVE_H

#ifndef __ASSEMBLY__

#include <linux/kconfig.h>
#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/stringify.h>
@@ -23,8 +26,22 @@ void free_alternatives_memory(void);
	" .byte 662b-661b\n"				/* source len      */ \
	" .byte 664f-663f\n"				/* replacement len */

/* alternative assembly primitive: */
#define ALTERNATIVE(oldinstr, newinstr, feature)			\
/*
 * 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_CFG(oldinstr, newinstr, feature, cfg_enabled)	\
	".if "__stringify(cfg_enabled)" == 1\n"				\
	"661:\n\t"							\
	oldinstr "\n"							\
	"662:\n"							\
@@ -36,8 +53,92 @@ 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"\
	".org	. - (664b-663b) + (662b-661b)\n\t"			\
	".org	. - (662b-661b) + (664b-663b)\n"			\
	".endif\n"

#define _ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg, ...)	\
	__ALTERNATIVE_CFG(oldinstr, newinstr, feature, IS_ENABLED(cfg))

#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, enable = 1
	.if \enable
661:	\insn1
662:	.pushsection .altinstructions, "a"
	altinstruction_entry 661b, 663f, \cap, 662b-661b, 664f-663f
	.popsection
	.pushsection .altinstr_replacement, "ax"
663:	\insn2
664:	.popsection
	.org	. - (664b-663b) + (662b-661b)
	.org	. - (662b-661b) + (664b-663b)
	.endif
.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

#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 */
+37 −5
Original line number Diff line number Diff line
@@ -24,12 +24,32 @@
#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_HAS_PAN				4

#define NCAPS					3
#define ARM64_NCAPS				5

#ifndef __ASSEMBLY__

extern DECLARE_BITMAP(cpu_hwcaps, NCAPS);
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;
			u32 midr_range_min, midr_range_max;
		};

		struct {	/* Feature register checking */
			int field_pos;
			int min_field_value;
		};
	};
};

extern DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS);

static inline bool cpu_have_feature(unsigned int num)
{
@@ -38,21 +58,33 @@ 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);
}

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);
void check_local_cpu_features(void);
bool cpu_supports_mixed_endian_el0(void);
bool system_supports_mixed_endian_el0(void);

#endif /* __ASSEMBLY__ */

Loading