Subject: [PATCHv2 3/5] arm64: Port SWP/SWPB emulation support from arm

From: [email-masked] (Will Deacon)
Date: Mon, 6 Oct 2014 11:52:16 +0100

On Wed, Oct 01, 2014 at 02:37:08PM +0100, Punit Agrawal wrote:
> The SWP instruction was deprecated in the ARMv6 architecture,
> superseded by the LDREX/STREX family of instructions for
> load-linked/store-conditional operations. 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.
> 
> This patch ports the alternate solution to emulate the SWP and SWPB
> instructions using LDXR/STXR sequences from the arm port to
> arm64. The emulation is turned off by default and can be enabled at
> runtime using sysctl.

[...]

> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index fd4e81a..89262da 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -149,6 +149,45 @@ 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 N
> +
> +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 N
> +
> +endif
> +
>  endmenu
>  
>  menu "Bus support"
> diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h
> index dc1f73b..c3b7c2f 100644
> --- a/arch/arm64/include/asm/insn.h
> +++ b/arch/arm64/include/asm/insn.h
> @@ -105,6 +105,14 @@ 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_instruction(u32 instr);
> +
> +#define RN_OFFSET	16
> +#define RT_OFFSET	12
> +#define RT2_OFFSET	 0

We should prefix these with A32_ or similar.

> +u32 aarch32_insn_extract_reg_num(u32 insn, int offset);
>  #endif /* __ASSEMBLY__ */
>  
>  #endif	/* __ASM_INSN_H */
> diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
> index e77dd61..39590f3 100644
> --- a/arch/arm64/kernel/Makefile
> +++ b/arch/arm64/kernel/Makefile
> @@ -31,6 +31,7 @@ arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND)	+= sleep.o suspend.o
>  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_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..23fc6f8
> --- /dev/null
> +++ b/arch/arm64/kernel/armv8_deprecated.c
> @@ -0,0 +1,287 @@
> +/*
> + *  Copied from arch/arm/kernel/swp_emulate.c and modified for ARMv8
> + *
> + *  Copyright (C) 2009,2012,2014 ARM Limited
> + *  __user_* functions adapted from include/asm/uaccess.h
> + *
> + * 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/kernel.h>
> +#include <linux/perf_event.h>
> +#include <linux/sched.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
> + * following two states -
> + *
> + * 0 = undef
> + * 1 = emulate (software emulation)
> + */
> +#define INSTR_UNDEF (0)
> +#define INSTR_EMULATE (1)

You don't need these brackets, but I think this is better off as an enum
anyway.

> +
> +/*
> + *  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
> + */
> +
> +/*
> + * SWP defaults to undef as it's been obsoleted in the architecture
> + */
> +static int swp_enable = 0;
> +static int swp_enable_min = INSTR_UNDEF;
> +static int swp_enable_max = INSTR_EMULATE;

Since we're going to be adding other emulations that need similar code,
perhaps it would be better to have a way to register an emulation?

E.g. something like:

enum insn_emulation_type {
	INSN_UNDEF,
	INSN_EMULATE,
	INSN_HW,
};

enum legacy_insn_status {
	INSN_DEPRECATED,
	INSN_OPTIONAL,
	INSN_OBSOLETE,
};

struct insn_emulation_ops {
	const char		*name;
	enum legacy_insn_type	status;
	struct undef_hook	hook;
	int			(*set_emulation_type)(enum insn_emulation_type type);
};

That way, we can move all the default behaviour handling, proc/sys
munging and undef hook handling into a single place.

Will