Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH v3 10/11] arm64: compat: Use vDSO sigreturn trampolines if available
From: Kevin Brodsky @ 2016-12-06 16:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161206160353.14581-1-kevin.brodsky@arm.com>

If the compat vDSO is enabled, it replaces the sigreturn page.
Therefore, we use the sigreturn trampolines the vDSO provides instead.

Cc: Will Deacon <will.deacon@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Nathan Lynch <nathan_lynch@mentor.com>
Cc: Christopher Covington <cov@codeaurora.org>
Cc: Dmitry Safonov <dsafonov@virtuozzo.com>
Cc: Jisheng Zhang <jszhang@marvell.com>
Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
---
 arch/arm64/include/asm/vdso.h |  3 +++
 arch/arm64/kernel/signal32.c  | 15 +++++++++++++++
 2 files changed, 18 insertions(+)

diff --git a/arch/arm64/include/asm/vdso.h b/arch/arm64/include/asm/vdso.h
index 839ce0031bd5..f2a952338f1e 100644
--- a/arch/arm64/include/asm/vdso.h
+++ b/arch/arm64/include/asm/vdso.h
@@ -28,6 +28,9 @@
 #ifndef __ASSEMBLY__
 
 #include <generated/vdso-offsets.h>
+#ifdef CONFIG_VDSO32
+#include <generated/vdso32-offsets.h>
+#endif
 
 #define VDSO_SYMBOL(base, name)						   \
 ({									   \
diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c
index 281df761e208..b6e8ff7949a4 100644
--- a/arch/arm64/kernel/signal32.c
+++ b/arch/arm64/kernel/signal32.c
@@ -28,6 +28,7 @@
 #include <asm/signal32.h>
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
+#include <asm/vdso.h>
 
 struct compat_vfp_sigframe {
 	compat_ulong_t	magic;
@@ -438,6 +439,19 @@ static void compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka,
 		retcode = ptr_to_compat(ka->sa.sa_restorer);
 	} else {
 		/* Set up sigreturn pointer */
+#ifdef CONFIG_VDSO32
+		void *vdso_base = current->mm->context.vdso;
+		void *trampoline =
+			(ka->sa.sa_flags & SA_SIGINFO
+			 ? (thumb
+			    ? VDSO_SYMBOL(vdso_base, compat_rt_sigreturn_thumb)
+			    : VDSO_SYMBOL(vdso_base, compat_rt_sigreturn_arm))
+			 : (thumb
+			    ? VDSO_SYMBOL(vdso_base, compat_sigreturn_thumb)
+			    : VDSO_SYMBOL(vdso_base, compat_sigreturn_arm)));
+
+		retcode = ptr_to_compat(trampoline) + thumb;
+#else
 		void *sigreturn_base = current->mm->context.vdso;
 		unsigned int idx = thumb << 1;
 
@@ -445,6 +459,7 @@ static void compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka,
 			idx += 3;
 
 		retcode = ptr_to_compat(sigreturn_base) + (idx << 2) + thumb;
+#endif
 	}
 
 	regs->regs[0]	= usig;
-- 
2.10.2

^ permalink raw reply related

* [RFC PATCH v3 09/11] arm64: elf: Set AT_SYSINFO_EHDR in compat processes
From: Kevin Brodsky @ 2016-12-06 16:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161206160353.14581-1-kevin.brodsky@arm.com>

If the compat vDSO is enabled, we need to set AT_SYSINFO_EHDR in the
auxiliary vector of compat processes to the address of the vDSO code
page, so that the dynamic linker can find it (just like the regular vDSO).

Note that we cast context.vdso to unsigned long, instead of elf_addr_t,
because elf_addr_t is 32-bit in compat_binfmt_elf.c, and casting to u32
would trigger a pointer narrowing warning.

Cc: Will Deacon <will.deacon@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Nathan Lynch <nathan_lynch@mentor.com>
Cc: Christopher Covington <cov@codeaurora.org>
Cc: Dmitry Safonov <dsafonov@virtuozzo.com>
Cc: Jisheng Zhang <jszhang@marvell.com>
Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
---
 arch/arm64/include/asm/elf.h | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
index 7da9452596ad..765c633950b7 100644
--- a/arch/arm64/include/asm/elf.h
+++ b/arch/arm64/include/asm/elf.h
@@ -141,11 +141,12 @@ typedef struct user_fpsimd_state elf_fpregset_t;
 #define SET_PERSONALITY(ex)		clear_thread_flag(TIF_32BIT);
 
 /* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT entries changes */
-#define ARCH_DLINFO							\
+#define _SET_AUX_ENT_VDSO						\
 do {									\
 	NEW_AUX_ENT(AT_SYSINFO_EHDR,					\
-		    (elf_addr_t)current->mm->context.vdso);		\
+		    (unsigned long)current->mm->context.vdso);		\
 } while (0)
+#define ARCH_DLINFO _SET_AUX_ENT_VDSO
 
 #define ARCH_HAS_SETUP_ADDITIONAL_PAGES
 struct linux_binprm;
@@ -184,7 +185,11 @@ typedef compat_elf_greg_t		compat_elf_gregset_t[COMPAT_ELF_NGREG];
 
 #define compat_start_thread		compat_start_thread
 #define COMPAT_SET_PERSONALITY(ex)	set_thread_flag(TIF_32BIT);
+#ifdef CONFIG_VDSO32
+#define COMPAT_ARCH_DLINFO		_SET_AUX_ENT_VDSO
+#else
 #define COMPAT_ARCH_DLINFO
+#endif
 extern int aarch32_setup_additional_pages(struct linux_binprm *bprm,
 					  int uses_interp);
 #define compat_arch_setup_additional_pages \
-- 
2.10.2

^ permalink raw reply related

* [RFC PATCH v3 08/11] arm64: compat: 32-bit vDSO setup
From: Kevin Brodsky @ 2016-12-06 16:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161206160353.14581-1-kevin.brodsky@arm.com>

If the compat vDSO is enabled, install it in compat processes. In this
case, the compat vDSO replaces the sigreturn page (it provides its own
sigreturn trampolines).

Cc: Will Deacon <will.deacon@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Nathan Lynch <nathan_lynch@mentor.com>
Cc: Christopher Covington <cov@codeaurora.org>
Cc: Dmitry Safonov <dsafonov@virtuozzo.com>
Cc: Jisheng Zhang <jszhang@marvell.com>
Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
---
 arch/arm64/kernel/vdso.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index 4d3048619be8..473492f3ab2a 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -141,6 +141,20 @@ static int vdso_setup(struct mm_struct *mm,
 }
 
 #ifdef CONFIG_COMPAT
+#ifdef CONFIG_VDSO32
+
+static struct vdso_mappings vdso32_mappings __ro_after_init;
+
+static int __init vdso32_init(void)
+{
+	extern char vdso32_start, vdso32_end;
+
+	return vdso_mappings_init("vdso32", &vdso32_start, &vdso32_end,
+				  &vdso32_mappings);
+}
+arch_initcall(vdso32_init);
+
+#else /* CONFIG_VDSO32 */
 
 /* sigreturn trampolines page */
 static struct page *sigreturn_page __ro_after_init;
@@ -196,6 +210,8 @@ static int sigreturn_setup(struct mm_struct *mm)
 	return PTR_ERR_OR_ZERO(ret);
 }
 
+#endif /* CONFIG_VDSO32 */
+
 #ifdef CONFIG_KUSER_HELPERS
 
 /* kuser helpers page */
@@ -249,7 +265,11 @@ int aarch32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 	if (down_write_killable(&mm->mmap_sem))
 		return -EINTR;
 
+#ifdef CONFIG_VDSO32
+	ret = vdso_setup(mm, &vdso32_mappings);
+#else
 	ret = sigreturn_setup(mm);
+#endif
 	if (ret)
 		goto out;
 
-- 
2.10.2

^ permalink raw reply related

* [RFC PATCH v3 07/11] arm64: compat: Add a 32-bit vDSO
From: Kevin Brodsky @ 2016-12-06 16:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161206160353.14581-1-kevin.brodsky@arm.com>

Provide the files necessary for building a compat (AArch32) vDSO in
kernel/vdso32.

This is mostly an adaptation of the arm vDSO. The most significant
change in vgettimeofday.c is the use of the arm64 vdso_data struct,
allowing the vDSO data page to be shared between the 32 and 64-bit
vDSOs. Additionally, a different set of barrier macros is used (see
aarch32-barrier.h), as we want to support old 32-bit compilers that
may not support ARMv8 and its new barrier arguments (*ld).

In addition to the time functions, sigreturn trampolines are also
provided, aiming at replacing those in the sigreturn page as the
latter don't provide any unwinding information (and it's easier to
have just one "user code" page). arm-specific unwinding directives are
used, based on glibc's implementation. Symbol offsets are made
available to the kernel using the same method as the 64-bit vDSO.

There is unfortunately an important caveat: we cannot get away with
hand-coding 32-bit instructions like in kernel/kuser32.S, this time we
really need a 32-bit compiler. The compat vDSO Makefile relies on
CROSS_COMPILE_ARM32 to provide a 32-bit compiler, appropriate logic
will be added to the arm64 Makefile later on to ensure that an attempt
to build the compat vDSO is made only if this variable has been set
properly.

Cc: Will Deacon <will.deacon@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Nathan Lynch <nathan_lynch@mentor.com>
Cc: Christopher Covington <cov@codeaurora.org>
Cc: Dmitry Safonov <dsafonov@virtuozzo.com>
Cc: Jisheng Zhang <jszhang@marvell.com>
Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
---
Note regarding the sigreturn trampolines: they should now have proper unwinding
information. I tested them by recompiling glibc to make it use the kernel
sigreturn (instead of setting its own sa_restorer), and then use glibc's
backtrace() inside a signal handler, or in C++ throw an exception from a signal
handler (hopefully nobody actually uses this "feature", but who knows...). Note
that in C, you must compile your application with -fasynchronous-unwind-tables
(which is the default on x86 but not arm), so that backtrace() actually uses the
unwinder to derive the stack trace. gdb is not very useful in this case, because
it has some magic to detect sigreturn trampolines based on the exact sequence of
instructions, and can derive the stack trace from there, without debug/unwinding
information.

The only remaining issue (AFAIK) is that backtrace() doesn't manage to print
the name of the Thumb trampolines, and gdb is also confused (the frame shows up
as "#1  0x... in ?? ()"). This seems to be a bug somewhere in the unwinder (and
gdb can't use its magic instruction matching because it expects slightly
different instructions), but I can't tell for sure. Given their limited use, an
option would be to only keep the ARM trampolines; but for now they will remain
there for compatibility with arch/arm.

 arch/arm64/kernel/vdso32/Makefile          | 166 ++++++++++++++++
 arch/arm64/kernel/vdso32/aarch32-barrier.h |  33 ++++
 arch/arm64/kernel/vdso32/sigreturn.S       |  76 ++++++++
 arch/arm64/kernel/vdso32/vdso.S            |  32 ++++
 arch/arm64/kernel/vdso32/vdso.lds.S        |  93 +++++++++
 arch/arm64/kernel/vdso32/vgettimeofday.c   | 295 +++++++++++++++++++++++++++++
 6 files changed, 695 insertions(+)
 create mode 100644 arch/arm64/kernel/vdso32/Makefile
 create mode 100644 arch/arm64/kernel/vdso32/aarch32-barrier.h
 create mode 100644 arch/arm64/kernel/vdso32/sigreturn.S
 create mode 100644 arch/arm64/kernel/vdso32/vdso.S
 create mode 100644 arch/arm64/kernel/vdso32/vdso.lds.S
 create mode 100644 arch/arm64/kernel/vdso32/vgettimeofday.c

diff --git a/arch/arm64/kernel/vdso32/Makefile b/arch/arm64/kernel/vdso32/Makefile
new file mode 100644
index 000000000000..87cb8f01d8b7
--- /dev/null
+++ b/arch/arm64/kernel/vdso32/Makefile
@@ -0,0 +1,166 @@
+#
+# Building a vDSO image for AArch32.
+#
+# Author: Kevin Brodsky <kevin.brodsky@arm.com>
+# A mix between the arm64 and arm vDSO Makefiles.
+
+CC_ARM32 := $(CROSS_COMPILE_ARM32)gcc
+
+# Same as cc-*option, but using CC_ARM32 instead of CC
+cc32-option = $(call try-run,\
+        $(CC_ARM32) $(1) -c -x c /dev/null -o "$$TMP",$(1),$(2))
+cc32-disable-warning = $(call try-run,\
+	$(CC_ARM32) -W$(strip $(1)) -c -x c /dev/null -o "$$TMP",-Wno-$(strip $(1)))
+cc32-ldoption = $(call try-run,\
+        $(CC_ARM32) $(1) -nostdlib -x c /dev/null -o "$$TMP",$(1),$(2))
+
+# We cannot use the global flags to compile the vDSO files, the main reason
+# being that the 32-bit compiler may be older than the main (64-bit) compiler
+# and therefore may not understand flags set using $(cc-option ...). Besides,
+# arch-specific options should be taken from the arm Makefile instead of the
+# arm64 one.
+# As a result we set our own flags here.
+
+# From top-level Makefile
+# NOSTDINC_FLAGS
+VDSO_CPPFLAGS := -nostdinc -isystem $(shell $(CC_ARM32) -print-file-name=include)
+VDSO_CPPFLAGS += $(LINUXINCLUDE)
+VDSO_CPPFLAGS += $(KBUILD_CPPFLAGS)
+
+# Common C and assembly flags
+# From top-level Makefile
+VDSO_CAFLAGS := $(VDSO_CPPFLAGS)
+VDSO_CAFLAGS += $(call cc32-option,-fno-PIE)
+ifdef CONFIG_DEBUG_INFO
+VDSO_CAFLAGS += -g
+endif
+ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC_ARM32)), y)
+VDSO_CAFLAGS += -DCC_HAVE_ASM_GOTO
+endif
+
+# From arm Makefile
+VDSO_CAFLAGS += $(call cc32-option,-fno-dwarf2-cfi-asm)
+VDSO_CAFLAGS += -mabi=aapcs-linux -mfloat-abi=soft
+ifeq ($(CONFIG_CPU_BIG_ENDIAN), y)
+VDSO_CAFLAGS += -mbig-endian
+else
+VDSO_CAFLAGS += -mlittle-endian
+endif
+
+# From arm vDSO Makefile
+VDSO_CAFLAGS += -fPIC -fno-builtin -fno-stack-protector
+VDSO_CAFLAGS += -DDISABLE_BRANCH_PROFILING
+
+# Try to compile for ARMv8. If the compiler is too old and doesn't support it,
+# fall back to v7. There is no easy way to check for what architecture the code
+# is being compiled, so define a macro specifying that (see arch/arm/Makefile).
+VDSO_CAFLAGS += $(call cc32-option,-march=armv8-a -D__LINUX_ARM_ARCH__=8,\
+                                   -march=armv7-a -D__LINUX_ARM_ARCH__=7)
+
+VDSO_CFLAGS := $(VDSO_CAFLAGS)
+# KBUILD_CFLAGS from top-level Makefile
+VDSO_CFLAGS += -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
+               -fno-strict-aliasing -fno-common \
+               -Werror-implicit-function-declaration \
+               -Wno-format-security \
+               -std=gnu89
+VDSO_CFLAGS  += -O2
+# Some useful compiler-dependent flags from top-level Makefile
+VDSO_CFLAGS += $(call cc32-option,-Wdeclaration-after-statement,)
+VDSO_CFLAGS += $(call cc32-option,-Wno-pointer-sign)
+VDSO_CFLAGS += $(call cc32-option,-fno-strict-overflow)
+VDSO_CFLAGS += $(call cc32-option,-Werror=strict-prototypes)
+VDSO_CFLAGS += $(call cc32-option,-Werror=date-time)
+VDSO_CFLAGS += $(call cc32-option,-Werror=incompatible-pointer-types)
+
+# The 32-bit compiler does not provide 128-bit integers, which are used in
+# some headers that are indirectly included from the vDSO code.
+# This hack makes the compiler happy and should trigger a warning/error if
+# variables of such type are referenced.
+VDSO_CFLAGS += -D__uint128_t='void*'
+# Silence some warnings coming from headers that operate on long's
+# (on GCC 4.8 or older, there is unfortunately no way to silence this warning)
+VDSO_CFLAGS += $(call cc32-disable-warning,shift-count-overflow)
+VDSO_CFLAGS += -Wno-int-to-pointer-cast
+
+VDSO_AFLAGS := $(VDSO_CAFLAGS)
+VDSO_AFLAGS += -D__ASSEMBLY__
+
+VDSO_LDFLAGS := $(VDSO_CPPFLAGS)
+# From arm vDSO Makefile
+VDSO_LDFLAGS += -Wl,-Bsymbolic -Wl,--no-undefined -Wl,-soname=linux-vdso.so.1
+VDSO_LDFLAGS += -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096
+VDSO_LDFLAGS += -nostdlib -shared -mfloat-abi=soft
+VDSO_LDFLAGS += $(call cc32-ldoption,-Wl$(comma)--hash-style=sysv)
+VDSO_LDFLAGS += $(call cc32-ldoption,-Wl$(comma)--build-id)
+VDSO_LDFLAGS += $(call cc32-ldoption,-fuse-ld=bfd)
+
+
+# Borrow vdsomunge.c from the arm vDSO
+munge := arch/arm/vdso/vdsomunge
+hostprogs-y := $(srctree)/$(munge)
+
+c-obj-vdso := vgettimeofday.o
+asm-obj-vdso := sigreturn.o
+
+# Build rules
+targets := $(c-obj-vdso) $(asm-obj-vdso) vdso.so vdso.so.dbg vdso.so.raw
+c-obj-vdso := $(addprefix $(obj)/, $(c-obj-vdso))
+asm-obj-vdso := $(addprefix $(obj)/, $(asm-obj-vdso))
+obj-vdso := $(c-obj-vdso) $(asm-obj-vdso)
+
+obj-y += vdso.o
+extra-y += vdso.lds
+CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
+
+# Force dependency (vdso.s includes vdso.so through incbin)
+$(obj)/vdso.o: $(obj)/vdso.so
+
+include/generated/vdso32-offsets.h: $(obj)/vdso.so.dbg FORCE
+	$(call if_changed,vdsosym)
+
+# Strip rule for vdso.so
+$(obj)/vdso.so: OBJCOPYFLAGS := -S
+$(obj)/vdso.so: $(obj)/vdso.so.dbg FORCE
+	$(call if_changed,objcopy)
+
+$(obj)/vdso.so.dbg: $(obj)/vdso.so.raw $(objtree)/$(munge) FORCE
+	$(call if_changed,vdsomunge)
+
+# Link rule for the .so file, .lds has to be first
+$(obj)/vdso.so.raw: $(src)/vdso.lds $(obj-vdso) FORCE
+	$(call if_changed,vdsold)
+
+# Compilation rules for the vDSO sources
+$(c-obj-vdso): %.o: %.c FORCE
+	$(call if_changed_dep,vdsocc)
+$(asm-obj-vdso): %.o: %.S FORCE
+	$(call if_changed_dep,vdsoas)
+
+# Actual build commands
+quiet_cmd_vdsold = VDSOL   $@
+      cmd_vdsold = $(CC_ARM32) -Wp,-MD,$(depfile) $(VDSO_LDFLAGS) \
+                   -Wl,-T $(filter %.lds,$^) $(filter %.o,$^) -o $@
+quiet_cmd_vdsocc = VDSOC   $@
+      cmd_vdsocc = $(CC_ARM32) -Wp,-MD,$(depfile) $(VDSO_CFLAGS) -c -o $@ $<
+quiet_cmd_vdsoas = VDSOA   $@
+      cmd_vdsoas = $(CC_ARM32) -Wp,-MD,$(depfile) $(VDSO_AFLAGS) -c -o $@ $<
+
+quiet_cmd_vdsomunge = MUNGE   $@
+      cmd_vdsomunge = $(objtree)/$(munge) $< $@
+
+# Generate vDSO offsets using helper script (borrowed from the 64-bit vDSO)
+gen-vdsosym := $(srctree)/$(src)/../vdso/gen_vdso_offsets.sh
+quiet_cmd_vdsosym = VDSOSYM $@
+# The AArch64 nm should be able to read an AArch32 binary
+      cmd_vdsosym = $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@
+
+# Install commands for the unstripped file
+quiet_cmd_vdso_install = INSTALL $@
+      cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/vdso32.so
+
+vdso.so: $(obj)/vdso.so.dbg
+	@mkdir -p $(MODLIB)/vdso
+	$(call cmd,vdso_install)
+
+vdso_install: vdso.so
diff --git a/arch/arm64/kernel/vdso32/aarch32-barrier.h b/arch/arm64/kernel/vdso32/aarch32-barrier.h
new file mode 100644
index 000000000000..31bfee63d59d
--- /dev/null
+++ b/arch/arm64/kernel/vdso32/aarch32-barrier.h
@@ -0,0 +1,33 @@
+/*
+ * Barriers for AArch32 code.
+ *
+ * Copyright (C) 2016 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/>.
+ */
+#ifndef __VDSO32_AARCH32_BARRIER_H
+#define __VDSO32_AARCH32_BARRIER_H
+
+#include <asm/barrier.h>
+
+#if __LINUX_ARM_ARCH__ >= 8
+#define aarch32_smp_mb()	dmb(ish)
+#define aarch32_smp_rmb()	dmb(ishld)
+#define aarch32_smp_wmb()	dmb(ishst)
+#else
+#define aarch32_smp_mb()	dmb(ish)
+#define aarch32_smp_rmb()	dmb(ish) /* ishld does not exist on ARMv7 */
+#define aarch32_smp_wmb()	dmb(ishst)
+#endif
+
+#endif	/* __VDSO32_AARCH32_BARRIER_H */
diff --git a/arch/arm64/kernel/vdso32/sigreturn.S b/arch/arm64/kernel/vdso32/sigreturn.S
new file mode 100644
index 000000000000..9267a4d78404
--- /dev/null
+++ b/arch/arm64/kernel/vdso32/sigreturn.S
@@ -0,0 +1,76 @@
+/*
+ * Sigreturn trampolines for returning from a signal when the SA_RESTORER
+ * flag is not set.
+ *
+ * Copyright (C) 2016 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.
+ *
+ * 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/>.
+ *
+ * Based on glibc's arm sa_restorer. While this is not strictly necessary, we
+ * provide both A32 and T32 versions, in accordance with the arm sigreturn
+ * code.
+ */
+
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include <asm/unistd.h>
+
+.macro sigreturn_trampoline name, syscall, regs_offset
+	/*
+	 * We provide directives for enabling stack unwinding through the
+	 * trampoline. On arm, CFI directives are only used for debugging (and
+	 * the vDSO is stripped of debug information), so only the arm-specific
+	 * unwinding directives are useful here.
+	 */
+	.fnstart
+	.save {r0-r15}
+	.pad #\regs_offset
+	/*
+	 * It is necessary to start the unwind tables at least one instruction
+	 * before the trampoline, as the unwinder will assume that the signal
+	 * handler has been called from the trampoline, that is just before
+	 * where the signal handler returns (mov r7, ...).
+	 */
+	nop
+ENTRY(\name)
+	mov	r7, #\syscall
+	svc	#0
+	.fnend
+	/*
+	 * We would like to use ENDPROC, but the macro uses @ which is a
+	 * comment symbol for arm assemblers, so directly use .type with %
+	 * instead.
+	 */
+	.type \name, %function
+END(\name)
+.endm
+
+	.text
+
+	.arm
+	sigreturn_trampoline __kernel_sigreturn_arm, \
+			     __NR_compat_sigreturn, \
+			     COMPAT_SIGFRAME_REGS_OFFSET
+
+	sigreturn_trampoline __kernel_rt_sigreturn_arm, \
+			     __NR_compat_rt_sigreturn, \
+			     COMPAT_RT_SIGFRAME_REGS_OFFSET
+
+	.thumb
+	sigreturn_trampoline __kernel_sigreturn_thumb, \
+			     __NR_compat_sigreturn, \
+			     COMPAT_SIGFRAME_REGS_OFFSET
+
+	sigreturn_trampoline __kernel_rt_sigreturn_thumb, \
+			     __NR_compat_rt_sigreturn, \
+			     COMPAT_RT_SIGFRAME_REGS_OFFSET
diff --git a/arch/arm64/kernel/vdso32/vdso.S b/arch/arm64/kernel/vdso32/vdso.S
new file mode 100644
index 000000000000..fe19ff70eb76
--- /dev/null
+++ b/arch/arm64/kernel/vdso32/vdso.S
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012 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.
+ *
+ * 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/>.
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ */
+
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <linux/const.h>
+#include <asm/page.h>
+
+	.globl vdso32_start, vdso32_end
+	.section .rodata
+	.balign PAGE_SIZE
+vdso32_start:
+	.incbin "arch/arm64/kernel/vdso32/vdso.so"
+	.balign PAGE_SIZE
+vdso32_end:
+
+	.previous
diff --git a/arch/arm64/kernel/vdso32/vdso.lds.S b/arch/arm64/kernel/vdso32/vdso.lds.S
new file mode 100644
index 000000000000..89560e80bd21
--- /dev/null
+++ b/arch/arm64/kernel/vdso32/vdso.lds.S
@@ -0,0 +1,93 @@
+/*
+ * Adapted from arm64 version.
+ *
+ * GNU linker script for the VDSO library.
+ *
+ * Copyright (C) 2012 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.
+ *
+ * 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/>.
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ * Heavily based on the vDSO linker scripts for other archs.
+ */
+
+#include <linux/const.h>
+#include <asm/page.h>
+#include <asm/vdso.h>
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+
+SECTIONS
+{
+	PROVIDE_HIDDEN(_vdso_data = . - PAGE_SIZE);
+	. = VDSO_LBASE + SIZEOF_HEADERS;
+
+	.hash		: { *(.hash) }			:text
+	.gnu.hash	: { *(.gnu.hash) }
+	.dynsym		: { *(.dynsym) }
+	.dynstr		: { *(.dynstr) }
+	.gnu.version	: { *(.gnu.version) }
+	.gnu.version_d	: { *(.gnu.version_d) }
+	.gnu.version_r	: { *(.gnu.version_r) }
+
+	.note		: { *(.note.*) }		:text	:note
+
+	.dynamic	: { *(.dynamic) }		:text	:dynamic
+
+	.rodata		: { *(.rodata*) }		:text
+
+	.text		: { *(.text*) }			:text	=0xe7f001f2
+
+	.got		: { *(.got) }
+	.rel.plt	: { *(.rel.plt) }
+
+	/DISCARD/	: {
+		*(.note.GNU-stack)
+		*(.data .data.* .gnu.linkonce.d.* .sdata*)
+		*(.bss .sbss .dynbss .dynsbss)
+	}
+}
+
+/*
+ * We must supply the ELF program headers explicitly to get just one
+ * PT_LOAD segment, and set the flags explicitly to make segments read-only.
+ */
+PHDRS
+{
+	text		PT_LOAD		FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */
+	dynamic		PT_DYNAMIC	FLAGS(4);		/* PF_R */
+	note		PT_NOTE		FLAGS(4);		/* PF_R */
+}
+
+VERSION
+{
+	LINUX_2.6 {
+	global:
+		__vdso_clock_gettime;
+		__vdso_gettimeofday;
+		__kernel_sigreturn_arm;
+		__kernel_sigreturn_thumb;
+		__kernel_rt_sigreturn_arm;
+		__kernel_rt_sigreturn_thumb;
+	local: *;
+	};
+}
+
+/*
+ * Make the sigreturn code visible to the kernel.
+ */
+VDSO_compat_sigreturn_arm	= __kernel_sigreturn_arm;
+VDSO_compat_sigreturn_thumb	= __kernel_sigreturn_thumb;
+VDSO_compat_rt_sigreturn_arm	= __kernel_rt_sigreturn_arm;
+VDSO_compat_rt_sigreturn_thumb	= __kernel_rt_sigreturn_thumb;
diff --git a/arch/arm64/kernel/vdso32/vgettimeofday.c b/arch/arm64/kernel/vdso32/vgettimeofday.c
new file mode 100644
index 000000000000..53c3d1f82b26
--- /dev/null
+++ b/arch/arm64/kernel/vdso32/vgettimeofday.c
@@ -0,0 +1,295 @@
+/*
+ * Copyright 2015 Mentor Graphics Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ * 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/>.
+ */
+
+#include <linux/clocksource.h>
+#include <linux/compiler.h>
+#include <linux/time.h>
+#include <asm/unistd.h>
+#include <asm/vdso_datapage.h>
+
+#include "aarch32-barrier.h"
+
+/*
+ * We use the hidden visibility to prevent the compiler from generating a GOT
+ * relocation. Not only is going through a GOT useless (the entry couldn't and
+ * musn't be overridden by another library), it does not even work: the linker
+ * cannot generate an absolute address to the data page.
+ *
+ * With the hidden visibility, the compiler simply generates a PC-relative
+ * relocation (R_ARM_REL32), and this is what we need.
+ */
+extern const struct vdso_data _vdso_data __attribute__((visibility("hidden")));
+
+static inline const struct vdso_data *get_vdso_data(void)
+{
+	const struct vdso_data *ret;
+	/*
+	 * This simply puts &_vdso_data into ret. The reason why we don't use
+	 * `ret = &_vdso_data` is that the compiler tends to optimise this in a
+	 * very suboptimal way: instead of keeping &_vdso_data in a register,
+	 * it goes through a relocation almost every time _vdso_data must be
+	 * accessed (even in subfunctions). This is both time and space
+	 * consuming: each relocation uses a word in the code section, and it
+	 * has to be loaded at runtime.
+	 *
+	 * This trick hides the assignment from the compiler. Since it cannot
+	 * track where the pointer comes from, it will only use one relocation
+	 * where get_vdso_data() is called, and then keep the result in a
+	 * register.
+	 */
+	asm("mov %0, %1" : "=r"(ret) : "r"(&_vdso_data));
+	return ret;
+}
+
+static notrace u32 __vdso_read_begin(const struct vdso_data *vdata)
+{
+	u32 seq;
+repeat:
+	seq = ACCESS_ONCE(vdata->tb_seq_count);
+	if (seq & 1) {
+		cpu_relax();
+		goto repeat;
+	}
+	return seq;
+}
+
+static notrace u32 vdso_read_begin(const struct vdso_data *vdata)
+{
+	u32 seq;
+
+	seq = __vdso_read_begin(vdata);
+
+	aarch32_smp_rmb();
+	return seq;
+}
+
+static notrace int vdso_read_retry(const struct vdso_data *vdata, u32 start)
+{
+	aarch32_smp_rmb();
+	return vdata->tb_seq_count != start;
+}
+
+/*
+ * Note: only AEABI is supported by the compat layer, we can assume AEABI
+ * syscall conventions are used.
+ */
+static notrace long clock_gettime_fallback(clockid_t _clkid,
+					   struct timespec *_ts)
+{
+	register struct timespec *ts asm("r1") = _ts;
+	register clockid_t clkid asm("r0") = _clkid;
+	register long ret asm ("r0");
+	register long nr asm("r7") = __NR_compat_clock_gettime;
+
+	asm volatile(
+	"	svc #0\n"
+	: "=r" (ret)
+	: "r" (clkid), "r" (ts), "r" (nr)
+	: "memory");
+
+	return ret;
+}
+
+static notrace int do_realtime_coarse(struct timespec *ts,
+				      const struct vdso_data *vdata)
+{
+	u32 seq;
+
+	do {
+		seq = vdso_read_begin(vdata);
+
+		ts->tv_sec = vdata->xtime_coarse_sec;
+		ts->tv_nsec = vdata->xtime_coarse_nsec;
+
+	} while (vdso_read_retry(vdata, seq));
+
+	return 0;
+}
+
+static notrace int do_monotonic_coarse(struct timespec *ts,
+				       const struct vdso_data *vdata)
+{
+	struct timespec tomono;
+	u32 seq;
+
+	do {
+		seq = vdso_read_begin(vdata);
+
+		ts->tv_sec = vdata->xtime_coarse_sec;
+		ts->tv_nsec = vdata->xtime_coarse_nsec;
+
+		tomono.tv_sec = vdata->wtm_clock_sec;
+		tomono.tv_nsec = vdata->wtm_clock_nsec;
+
+	} while (vdso_read_retry(vdata, seq));
+
+	ts->tv_sec += tomono.tv_sec;
+	timespec_add_ns(ts, tomono.tv_nsec);
+
+	return 0;
+}
+
+static notrace u64 get_ns(const struct vdso_data *vdata)
+{
+	u64 cycle_delta;
+	u64 cycle_now;
+	u64 nsec;
+
+	/* AArch32 implementation of arch_counter_get_cntvct() */
+	isb();
+	asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (cycle_now));
+
+	/* The virtual counter provides 56 significant bits. */
+	cycle_delta = (cycle_now - vdata->cs_cycle_last) & CLOCKSOURCE_MASK(56);
+
+	nsec = (cycle_delta * vdata->cs_mono_mult) + vdata->xtime_clock_nsec;
+	nsec >>= vdata->cs_shift;
+
+	return nsec;
+}
+
+static notrace int do_realtime(struct timespec *ts,
+			       const struct vdso_data *vdata)
+{
+	u64 nsecs;
+	u32 seq;
+
+	do {
+		seq = vdso_read_begin(vdata);
+
+		if (vdata->use_syscall)
+			return -1;
+
+		ts->tv_sec = vdata->xtime_clock_sec;
+		nsecs = get_ns(vdata);
+
+	} while (vdso_read_retry(vdata, seq));
+
+	ts->tv_nsec = 0;
+	timespec_add_ns(ts, nsecs);
+
+	return 0;
+}
+
+static notrace int do_monotonic(struct timespec *ts,
+				const struct vdso_data *vdata)
+{
+	struct timespec tomono;
+	u64 nsecs;
+	u32 seq;
+
+	do {
+		seq = vdso_read_begin(vdata);
+
+		if (vdata->use_syscall)
+			return -1;
+
+		ts->tv_sec = vdata->xtime_clock_sec;
+		nsecs = get_ns(vdata);
+
+		tomono.tv_sec = vdata->wtm_clock_sec;
+		tomono.tv_nsec = vdata->wtm_clock_nsec;
+
+	} while (vdso_read_retry(vdata, seq));
+
+	ts->tv_sec += tomono.tv_sec;
+	ts->tv_nsec = 0;
+	timespec_add_ns(ts, nsecs + tomono.tv_nsec);
+
+	return 0;
+}
+
+notrace int __vdso_clock_gettime(clockid_t clkid, struct timespec *ts)
+{
+	const struct vdso_data *vdata = get_vdso_data();
+	int ret = -1;
+
+	switch (clkid) {
+	case CLOCK_REALTIME_COARSE:
+		ret = do_realtime_coarse(ts, vdata);
+		break;
+	case CLOCK_MONOTONIC_COARSE:
+		ret = do_monotonic_coarse(ts, vdata);
+		break;
+	case CLOCK_REALTIME:
+		ret = do_realtime(ts, vdata);
+		break;
+	case CLOCK_MONOTONIC:
+		ret = do_monotonic(ts, vdata);
+		break;
+	default:
+		break;
+	}
+
+	if (ret)
+		ret = clock_gettime_fallback(clkid, ts);
+
+	return ret;
+}
+
+static notrace long gettimeofday_fallback(struct timeval *_tv,
+					  struct timezone *_tz)
+{
+	register struct timezone *tz asm("r1") = _tz;
+	register struct timeval *tv asm("r0") = _tv;
+	register long ret asm ("r0");
+	register long nr asm("r7") = __NR_compat_gettimeofday;
+
+	asm volatile(
+	"	svc #0\n"
+	: "=r" (ret)
+	: "r" (tv), "r" (tz), "r" (nr)
+	: "memory");
+
+	return ret;
+}
+
+notrace int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+	struct timespec ts;
+	const struct vdso_data *vdata = get_vdso_data();
+	int ret;
+
+	ret = do_realtime(&ts, vdata);
+	if (ret)
+		return gettimeofday_fallback(tv, tz);
+
+	if (tv) {
+		tv->tv_sec = ts.tv_sec;
+		tv->tv_usec = ts.tv_nsec / 1000;
+	}
+	if (tz) {
+		tz->tz_minuteswest = vdata->tz_minuteswest;
+		tz->tz_dsttime = vdata->tz_dsttime;
+	}
+
+	return ret;
+}
+
+/* Avoid unresolved references emitted by GCC */
+
+void __aeabi_unwind_cpp_pr0(void)
+{
+}
+
+void __aeabi_unwind_cpp_pr1(void)
+{
+}
+
+void __aeabi_unwind_cpp_pr2(void)
+{
+}
-- 
2.10.2

^ permalink raw reply related

* [RFC PATCH v3 06/11] arm64: compat: Expose offset to registers in sigframes
From: Kevin Brodsky @ 2016-12-06 16:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161206160353.14581-1-kevin.brodsky@arm.com>

This will be needed to provide unwinding information in compat
sigreturn trampolines, part of the future compat vDSO. There is no
obvious header the compat_sig* struct's should be moved to, so let's
put them in signal32.h.

Also fix minor style issues reported by checkpatch.

Cc: Will Deacon <will.deacon@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Nathan Lynch <nathan_lynch@mentor.com>
Cc: Christopher Covington <cov@codeaurora.org>
Cc: Dmitry Safonov <dsafonov@virtuozzo.com>
Cc: Jisheng Zhang <jszhang@marvell.com>
Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
---
 arch/arm64/include/asm/signal32.h | 46 +++++++++++++++++++++++++++++++++++++++
 arch/arm64/kernel/asm-offsets.c   | 13 +++++++++++
 arch/arm64/kernel/signal32.c      | 46 ---------------------------------------
 3 files changed, 59 insertions(+), 46 deletions(-)

diff --git a/arch/arm64/include/asm/signal32.h b/arch/arm64/include/asm/signal32.h
index 58e288aaf0ba..bcd0e139ee4a 100644
--- a/arch/arm64/include/asm/signal32.h
+++ b/arch/arm64/include/asm/signal32.h
@@ -20,6 +20,52 @@
 #ifdef CONFIG_COMPAT
 #include <linux/compat.h>
 
+struct compat_sigcontext {
+	/* We always set these two fields to 0 */
+	compat_ulong_t			trap_no;
+	compat_ulong_t			error_code;
+
+	compat_ulong_t			oldmask;
+	compat_ulong_t			arm_r0;
+	compat_ulong_t			arm_r1;
+	compat_ulong_t			arm_r2;
+	compat_ulong_t			arm_r3;
+	compat_ulong_t			arm_r4;
+	compat_ulong_t			arm_r5;
+	compat_ulong_t			arm_r6;
+	compat_ulong_t			arm_r7;
+	compat_ulong_t			arm_r8;
+	compat_ulong_t			arm_r9;
+	compat_ulong_t			arm_r10;
+	compat_ulong_t			arm_fp;
+	compat_ulong_t			arm_ip;
+	compat_ulong_t			arm_sp;
+	compat_ulong_t			arm_lr;
+	compat_ulong_t			arm_pc;
+	compat_ulong_t			arm_cpsr;
+	compat_ulong_t			fault_address;
+};
+
+struct compat_ucontext {
+	compat_ulong_t			uc_flags;
+	compat_uptr_t			uc_link;
+	compat_stack_t			uc_stack;
+	struct compat_sigcontext	uc_mcontext;
+	compat_sigset_t			uc_sigmask;
+	int __unused[32 - (sizeof(compat_sigset_t) / sizeof(int))];
+	compat_ulong_t			uc_regspace[128] __aligned(8);
+};
+
+struct compat_sigframe {
+	struct compat_ucontext		uc;
+	compat_ulong_t			retcode[2];
+};
+
+struct compat_rt_sigframe {
+	struct compat_siginfo		info;
+	struct compat_sigframe		sig;
+};
+
 int compat_setup_frame(int usig, struct ksignal *ksig, sigset_t *set,
 		       struct pt_regs *regs);
 int compat_setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
index 4a2f0f0fef32..965371186a5a 100644
--- a/arch/arm64/kernel/asm-offsets.c
+++ b/arch/arm64/kernel/asm-offsets.c
@@ -26,6 +26,7 @@
 #include <asm/cpufeature.h>
 #include <asm/thread_info.h>
 #include <asm/memory.h>
+#include <asm/signal32.h>
 #include <asm/smp_plat.h>
 #include <asm/suspend.h>
 #include <asm/vdso_datapage.h>
@@ -75,6 +76,18 @@ int main(void)
   DEFINE(S_ORIG_ADDR_LIMIT,	offsetof(struct pt_regs, orig_addr_limit));
   DEFINE(S_FRAME_SIZE,		sizeof(struct pt_regs));
   BLANK();
+#ifdef CONFIG_COMPAT
+  DEFINE(COMPAT_SIGFRAME_REGS_OFFSET,
+				offsetof(struct compat_sigframe, uc) +
+				offsetof(struct compat_ucontext, uc_mcontext) +
+				offsetof(struct compat_sigcontext, arm_r0));
+  DEFINE(COMPAT_RT_SIGFRAME_REGS_OFFSET,
+				offsetof(struct compat_rt_sigframe, sig) +
+				offsetof(struct compat_sigframe, uc) +
+				offsetof(struct compat_ucontext, uc_mcontext) +
+				offsetof(struct compat_sigcontext, arm_r0));
+  BLANK();
+#endif
   DEFINE(MM_CONTEXT_ID,		offsetof(struct mm_struct, context.id.counter));
   BLANK();
   DEFINE(VMA_VM_MM,		offsetof(struct vm_area_struct, vm_mm));
diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c
index 49396a2b6e11..281df761e208 100644
--- a/arch/arm64/kernel/signal32.c
+++ b/arch/arm64/kernel/signal32.c
@@ -29,42 +29,6 @@
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
 
-struct compat_sigcontext {
-	/* We always set these two fields to 0 */
-	compat_ulong_t			trap_no;
-	compat_ulong_t			error_code;
-
-	compat_ulong_t			oldmask;
-	compat_ulong_t			arm_r0;
-	compat_ulong_t			arm_r1;
-	compat_ulong_t			arm_r2;
-	compat_ulong_t			arm_r3;
-	compat_ulong_t			arm_r4;
-	compat_ulong_t			arm_r5;
-	compat_ulong_t			arm_r6;
-	compat_ulong_t			arm_r7;
-	compat_ulong_t			arm_r8;
-	compat_ulong_t			arm_r9;
-	compat_ulong_t			arm_r10;
-	compat_ulong_t			arm_fp;
-	compat_ulong_t			arm_ip;
-	compat_ulong_t			arm_sp;
-	compat_ulong_t			arm_lr;
-	compat_ulong_t			arm_pc;
-	compat_ulong_t			arm_cpsr;
-	compat_ulong_t			fault_address;
-};
-
-struct compat_ucontext {
-	compat_ulong_t			uc_flags;
-	compat_uptr_t			uc_link;
-	compat_stack_t			uc_stack;
-	struct compat_sigcontext	uc_mcontext;
-	compat_sigset_t			uc_sigmask;
-	int		__unused[32 - (sizeof (compat_sigset_t) / sizeof (int))];
-	compat_ulong_t	uc_regspace[128] __attribute__((__aligned__(8)));
-};
-
 struct compat_vfp_sigframe {
 	compat_ulong_t	magic;
 	compat_ulong_t	size;
@@ -91,16 +55,6 @@ struct compat_aux_sigframe {
 	unsigned long			end_magic;
 } __attribute__((__aligned__(8)));
 
-struct compat_sigframe {
-	struct compat_ucontext	uc;
-	compat_ulong_t		retcode[2];
-};
-
-struct compat_rt_sigframe {
-	struct compat_siginfo info;
-	struct compat_sigframe sig;
-};
-
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
 static inline int put_sigset_t(compat_sigset_t __user *uset, sigset_t *set)
-- 
2.10.2

^ permalink raw reply related

* [RFC PATCH v3 05/11] arm64: compat: Add time-related syscall numbers
From: Kevin Brodsky @ 2016-12-06 16:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161206160353.14581-1-kevin.brodsky@arm.com>

They will be used by the future compat vDSO.

The compat syscall numbers correspond to the arm syscall numbers, see
arch/arm/include/uapi/asm/unistd.h.

Cc: Will Deacon <will.deacon@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Nathan Lynch <nathan_lynch@mentor.com>
Cc: Christopher Covington <cov@codeaurora.org>
Cc: Dmitry Safonov <dsafonov@virtuozzo.com>
Cc: Jisheng Zhang <jszhang@marvell.com>
Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
---
 arch/arm64/include/asm/unistd.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h
index e78ac26324bd..8d1c5f5e58f3 100644
--- a/arch/arm64/include/asm/unistd.h
+++ b/arch/arm64/include/asm/unistd.h
@@ -34,8 +34,10 @@
 #define __NR_compat_exit		1
 #define __NR_compat_read		3
 #define __NR_compat_write		4
+#define __NR_compat_gettimeofday	78
 #define __NR_compat_sigreturn		119
 #define __NR_compat_rt_sigreturn	173
+#define __NR_compat_clock_gettime	263
 
 /*
  * The following SVCs are ARM private.
-- 
2.10.2

^ permalink raw reply related

* [RFC PATCH v3 04/11] arm64: Refactor vDSO init/setup
From: Kevin Brodsky @ 2016-12-06 16:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161206160353.14581-1-kevin.brodsky@arm.com>

Move the logic for setting up mappings and pages for the vDSO into
static functions. This makes the vDSO setup code more consistent with
the compat side and will allow to reuse it for the future compat vDSO.

Cc: Will Deacon <will.deacon@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Nathan Lynch <nathan_lynch@mentor.com>
Cc: Christopher Covington <cov@codeaurora.org>
Cc: Dmitry Safonov <dsafonov@virtuozzo.com>
Cc: Jisheng Zhang <jszhang@marvell.com>
Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
---
 arch/arm64/kernel/vdso.c | 170 +++++++++++++++++++++++++++--------------------
 1 file changed, 99 insertions(+), 71 deletions(-)

diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index d189e5be5039..4d3048619be8 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -39,8 +39,10 @@
 #include <asm/vdso.h>
 #include <asm/vdso_datapage.h>
 
-extern char vdso_start, vdso_end;
-static unsigned long vdso_pages __ro_after_init;
+struct vdso_mappings {
+	unsigned long num_code_pages;
+	struct vm_special_mapping data_mapping, code_mapping;
+};
 
 /*
  * The vDSO data page.
@@ -51,6 +53,93 @@ static union {
 } vdso_data_store __page_aligned_data;
 struct vdso_data *vdso_data = &vdso_data_store.data;
 
+static int __init vdso_mappings_init(const char *name,
+				      const char *code_start,
+				      const char *code_end,
+				      struct vdso_mappings *mappings)
+{
+	unsigned long i, num_code_pages;
+	struct page **pages;
+
+	if (memcmp(code_start, "\177ELF", 4)) {
+		pr_err("%s is not a valid ELF object!\n", name);
+		return -EINVAL;
+	}
+
+	num_code_pages = (code_end - code_start) >> PAGE_SHIFT;
+	pr_info("%s: %ld pages (%ld code @ %p, %ld data @ %p)\n",
+		name, num_code_pages + 1, num_code_pages, code_start, 1L,
+		vdso_data);
+
+	/*
+	 * Allocate space for storing pointers to the vDSO code pages + the
+	 * data page. The pointers must have the same lifetime as the mappings,
+	 * which are static, so there is no need to keep track of the pointer
+	 * array to free it.
+	 */
+	pages = kmalloc_array(num_code_pages + 1, sizeof(struct page *),
+			      GFP_KERNEL);
+	if (pages == NULL)
+		return -ENOMEM;
+
+	/* Grab the vDSO data page */
+	pages[0] = pfn_to_page(PHYS_PFN(__pa(vdso_data)));
+
+	/* Grab the vDSO code pages */
+	for (i = 0; i < num_code_pages; i++)
+		pages[i + 1] = pfn_to_page(PHYS_PFN(__pa(code_start)) + i);
+
+	/* Populate the special mapping structures */
+	mappings->data_mapping = (struct vm_special_mapping) {
+		.name	= "[vvar]",
+		.pages	= &pages[0],
+	};
+
+	mappings->code_mapping = (struct vm_special_mapping) {
+		.name	= "[vdso]",
+		.pages	= &pages[1],
+	};
+
+	mappings->num_code_pages = num_code_pages;
+	return 0;
+}
+
+static int vdso_setup(struct mm_struct *mm,
+		      const struct vdso_mappings *mappings)
+{
+	unsigned long vdso_base, vdso_text_len, vdso_mapping_len;
+	void *ret;
+
+	vdso_text_len = mappings->num_code_pages << PAGE_SHIFT;
+	/* Be sure to map the data page */
+	vdso_mapping_len = vdso_text_len + PAGE_SIZE;
+
+	vdso_base = get_unmapped_area(NULL, 0, vdso_mapping_len, 0, 0);
+	if (IS_ERR_VALUE(vdso_base)) {
+		ret = ERR_PTR(vdso_base);
+		goto out;
+	}
+
+	ret = _install_special_mapping(mm, vdso_base, PAGE_SIZE,
+				       VM_READ|VM_MAYREAD,
+				       &mappings->data_mapping);
+	if (IS_ERR(ret))
+		goto out;
+
+	vdso_base += PAGE_SIZE;
+	ret = _install_special_mapping(mm, vdso_base, vdso_text_len,
+				       VM_READ|VM_EXEC|
+				       VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
+				       &mappings->code_mapping);
+	if (IS_ERR(ret))
+		goto out;
+
+	mm->context.vdso = (void *)vdso_base;
+
+out:
+	return PTR_ERR_OR_ZERO(ret);
+}
+
 #ifdef CONFIG_COMPAT
 
 /* sigreturn trampolines page */
@@ -175,90 +264,29 @@ int aarch32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 
 #endif /* CONFIG_COMPAT */
 
-static struct vm_special_mapping vdso_spec[2] __ro_after_init = {
-	{
-		.name	= "[vvar]",
-	},
-	{
-		.name	= "[vdso]",
-	},
-};
+static struct vdso_mappings vdso_mappings __ro_after_init;
 
 static int __init vdso_init(void)
 {
-	int i;
-	struct page **vdso_pagelist;
-
-	if (memcmp(&vdso_start, "\177ELF", 4)) {
-		pr_err("vDSO is not a valid ELF object!\n");
-		return -EINVAL;
-	}
+	extern char vdso_start, vdso_end;
 
-	vdso_pages = (&vdso_end - &vdso_start) >> PAGE_SHIFT;
-	pr_info("vdso: %ld pages (%ld code @ %p, %ld data @ %p)\n",
-		vdso_pages + 1, vdso_pages, &vdso_start, 1L, vdso_data);
-
-	/* Allocate the vDSO pagelist, plus a page for the data. */
-	vdso_pagelist = kcalloc(vdso_pages + 1, sizeof(struct page *),
-				GFP_KERNEL);
-	if (vdso_pagelist == NULL)
-		return -ENOMEM;
-
-	/* Grab the vDSO data page. */
-	vdso_pagelist[0] = pfn_to_page(PHYS_PFN(__pa(vdso_data)));
-
-	/* Grab the vDSO code pages. */
-	for (i = 0; i < vdso_pages; i++)
-		vdso_pagelist[i + 1] = pfn_to_page(PHYS_PFN(__pa(&vdso_start)) + i);
-
-	vdso_spec[0].pages = &vdso_pagelist[0];
-	vdso_spec[1].pages = &vdso_pagelist[1];
-
-	return 0;
+	return vdso_mappings_init("vdso", &vdso_start, &vdso_end,
+				   &vdso_mappings);
 }
 arch_initcall(vdso_init);
 
-int arch_setup_additional_pages(struct linux_binprm *bprm,
-				int uses_interp)
+int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 {
 	struct mm_struct *mm = current->mm;
-	unsigned long vdso_base, vdso_text_len, vdso_mapping_len;
-	void *ret;
-
-	vdso_text_len = vdso_pages << PAGE_SHIFT;
-	/* Be sure to map the data page */
-	vdso_mapping_len = vdso_text_len + PAGE_SIZE;
+	int ret;
 
 	if (down_write_killable(&mm->mmap_sem))
 		return -EINTR;
-	vdso_base = get_unmapped_area(NULL, 0, vdso_mapping_len, 0, 0);
-	if (IS_ERR_VALUE(vdso_base)) {
-		ret = ERR_PTR(vdso_base);
-		goto up_fail;
-	}
-	ret = _install_special_mapping(mm, vdso_base, PAGE_SIZE,
-				       VM_READ|VM_MAYREAD,
-				       &vdso_spec[0]);
-	if (IS_ERR(ret))
-		goto up_fail;
-
-	vdso_base += PAGE_SIZE;
-	mm->context.vdso = (void *)vdso_base;
-	ret = _install_special_mapping(mm, vdso_base, vdso_text_len,
-				       VM_READ|VM_EXEC|
-				       VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
-				       &vdso_spec[1]);
-	if (IS_ERR(ret))
-		goto up_fail;
 
+	ret = vdso_setup(mm, &vdso_mappings);
 
 	up_write(&mm->mmap_sem);
-	return 0;
-
-up_fail:
-	mm->context.vdso = NULL;
-	up_write(&mm->mmap_sem);
-	return PTR_ERR(ret);
+	return ret;
 }
 
 /*
-- 
2.10.2

^ permalink raw reply related

* [RFC PATCH v3 03/11] arm64: compat: Add CONFIG_KUSER_HELPERS
From: Kevin Brodsky @ 2016-12-06 16:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161206160353.14581-1-kevin.brodsky@arm.com>

Make it possible to disable the kuser helpers by adding a KUSER_HELPERS
config option (enabled by default). When disabled, all kuser
helpers-related code is removed from the kernel and no mapping is done
at the fixed high address (0xffff0000); any attempt to use a kuser
helper from a 32-bit process will result in a segfault.

Cc: Will Deacon <will.deacon@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Nathan Lynch <nathan_lynch@mentor.com>
Cc: Christopher Covington <cov@codeaurora.org>
Cc: Dmitry Safonov <dsafonov@virtuozzo.com>
Cc: Jisheng Zhang <jszhang@marvell.com>
Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
---
 arch/arm64/Kconfig              | 29 ++++++++++++++++++++
 arch/arm64/kernel/Makefile      |  3 ++-
 arch/arm64/kernel/kuser32.S     | 48 +++------------------------------
 arch/arm64/kernel/sigreturn32.S | 59 +++++++++++++++++++++++++++++++++++++++++
 arch/arm64/kernel/vdso.c        |  6 +++++
 5 files changed, 99 insertions(+), 46 deletions(-)
 create mode 100644 arch/arm64/kernel/sigreturn32.S

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 969ef880d234..265d88c44cfc 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1013,6 +1013,35 @@ config COMPAT
 
 	  If you want to execute 32-bit userspace applications, say Y.
 
+config KUSER_HELPERS
+	bool "Enable the kuser helpers page in 32-bit processes"
+	depends on COMPAT
+	default y
+	help
+	  Warning: disabling this option may break 32-bit applications.
+
+	  Provide kuser helpers in a special purpose fixed-address page. The
+	  kernel provides helper code to userspace in read-only form at a fixed
+	  location to allow userspace to be independent of the CPU type fitted
+	  to the system. This permits 32-bit binaries to be run on ARMv4 through
+	  to ARMv8 without modification.
+
+	  See Documentation/arm/kernel_user_helpers.txt for details.
+
+	  However, the fixed-address nature of these helpers can be used by ROP
+	  (return-orientated programming) authors when creating exploits.
+
+	  If all of the 32-bit binaries and libraries which run on your platform
+	  are built specifically for your platform, and make no use of these
+	  helpers, then you can turn this option off to hinder such exploits.
+	  However, in that case, if a binary or library relying on those helpers
+	  is run, it will receive a SIGSEGV signal, which will terminate the
+	  program. Typically, binaries compiled for ARMv7 or later do not use
+	  the kuser helpers.
+
+	  Say N here only if you are absolutely certain that you do not need
+	  these helpers; otherwise, the safe option is to say Y.
+
 config SYSVIPC_COMPAT
 	def_bool y
 	depends on COMPAT && SYSVIPC
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 7d66bbaafc0c..0850506d0217 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -27,8 +27,9 @@ OBJCOPYFLAGS := --prefix-symbols=__efistub_
 $(obj)/%.stub.o: $(obj)/%.o FORCE
 	$(call if_changed,objcopy)
 
-arm64-obj-$(CONFIG_COMPAT)		+= sys32.o kuser32.o signal32.o 	\
+arm64-obj-$(CONFIG_COMPAT)		+= sys32.o sigreturn32.o signal32.o	\
 					   sys_compat.o entry32.o
+arm64-obj-$(CONFIG_KUSER_HELPERS)	+= kuser32.o
 arm64-obj-$(CONFIG_FUNCTION_TRACER)	+= ftrace.o entry-ftrace.o
 arm64-obj-$(CONFIG_MODULES)		+= arm64ksyms.o module.o
 arm64-obj-$(CONFIG_ARM64_MODULE_PLTS)	+= module-plts.o
diff --git a/arch/arm64/kernel/kuser32.S b/arch/arm64/kernel/kuser32.S
index 997e6b27ff6a..d15b5c2935b3 100644
--- a/arch/arm64/kernel/kuser32.S
+++ b/arch/arm64/kernel/kuser32.S
@@ -20,16 +20,13 @@
  *
  * AArch32 user helpers.
  *
- * Each segment is 32-byte aligned and will be moved to the top of the high
- * vector page.  New segments (if ever needed) must be added in front of
- * existing ones.  This mechanism should be used only for things that are
- * really small and justified, and not be abused freely.
+ * These helpers are provided for compatibility with AArch32 binaries that
+ * still need them. They are installed at a fixed address by
+ * aarch32_setup_additional_pages().
  *
  * See Documentation/arm/kernel_user_helpers.txt for formal definitions.
  */
 
-#include <asm/unistd.h>
-
 	.align	5
 	.globl	__kuser_helper_start
 __kuser_helper_start:
@@ -77,42 +74,3 @@ __kuser_helper_version:			// 0xffff0ffc
 	.word	((__kuser_helper_end - __kuser_helper_start) >> 5)
 	.globl	__kuser_helper_end
 __kuser_helper_end:
-
-/*
- * AArch32 sigreturn code
- *
- * For ARM syscalls, the syscall number has to be loaded into r7.
- * We do not support an OABI userspace.
- *
- * For Thumb syscalls, we also pass the syscall number via r7. We therefore
- * need two 16-bit instructions.
- */
-	.globl __aarch32_sigret_code_start
-__aarch32_sigret_code_start:
-
-	/*
-	 * ARM Code
-	 */
-	.byte	__NR_compat_sigreturn, 0x70, 0xa0, 0xe3	// mov	r7, #__NR_compat_sigreturn
-	.byte	__NR_compat_sigreturn, 0x00, 0x00, 0xef	// svc	#__NR_compat_sigreturn
-
-	/*
-	 * Thumb code
-	 */
-	.byte	__NR_compat_sigreturn, 0x27			// svc	#__NR_compat_sigreturn
-	.byte	__NR_compat_sigreturn, 0xdf			// mov	r7, #__NR_compat_sigreturn
-
-	/*
-	 * ARM code
-	 */
-	.byte	__NR_compat_rt_sigreturn, 0x70, 0xa0, 0xe3	// mov	r7, #__NR_compat_rt_sigreturn
-	.byte	__NR_compat_rt_sigreturn, 0x00, 0x00, 0xef	// svc	#__NR_compat_rt_sigreturn
-
-	/*
-	 * Thumb code
-	 */
-	.byte	__NR_compat_rt_sigreturn, 0x27			// svc	#__NR_compat_rt_sigreturn
-	.byte	__NR_compat_rt_sigreturn, 0xdf			// mov	r7, #__NR_compat_rt_sigreturn
-
-        .globl __aarch32_sigret_code_end
-__aarch32_sigret_code_end:
diff --git a/arch/arm64/kernel/sigreturn32.S b/arch/arm64/kernel/sigreturn32.S
new file mode 100644
index 000000000000..f2615e2286c5
--- /dev/null
+++ b/arch/arm64/kernel/sigreturn32.S
@@ -0,0 +1,59 @@
+/*
+ * sigreturn trampolines for AArch32.
+ *
+ * Copyright (C) 2005-2011 Nicolas Pitre <nico@fluxnic.net>
+ * Copyright (C) 2012 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/>.
+ *
+ *
+ * AArch32 sigreturn code
+ *
+ * For ARM syscalls, the syscall number has to be loaded into r7.
+ * We do not support an OABI userspace.
+ *
+ * For Thumb syscalls, we also pass the syscall number via r7. We therefore
+ * need two 16-bit instructions.
+ */
+
+#include <asm/unistd.h>
+
+	.globl __aarch32_sigret_code_start
+__aarch32_sigret_code_start:
+
+	/*
+	 * ARM Code
+	 */
+	.byte	__NR_compat_sigreturn, 0x70, 0xa0, 0xe3		// mov	r7, #__NR_compat_sigreturn
+	.byte	__NR_compat_sigreturn, 0x00, 0x00, 0xef		// svc	#__NR_compat_sigreturn
+
+	/*
+	 * Thumb code
+	 */
+	.byte	__NR_compat_sigreturn, 0x27			// svc	#__NR_compat_sigreturn
+	.byte	__NR_compat_sigreturn, 0xdf			// mov	r7, #__NR_compat_sigreturn
+
+	/*
+	 * ARM code
+	 */
+	.byte	__NR_compat_rt_sigreturn, 0x70, 0xa0, 0xe3	// mov	r7, #__NR_compat_rt_sigreturn
+	.byte	__NR_compat_rt_sigreturn, 0x00, 0x00, 0xef	// svc	#__NR_compat_rt_sigreturn
+
+	/*
+	 * Thumb code
+	 */
+	.byte	__NR_compat_rt_sigreturn, 0x27			// svc	#__NR_compat_rt_sigreturn
+	.byte	__NR_compat_rt_sigreturn, 0xdf			// mov	r7, #__NR_compat_rt_sigreturn
+
+        .globl __aarch32_sigret_code_end
+__aarch32_sigret_code_end:
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index 6208b7ba4593..d189e5be5039 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -107,6 +107,8 @@ static int sigreturn_setup(struct mm_struct *mm)
 	return PTR_ERR_OR_ZERO(ret);
 }
 
+#ifdef CONFIG_KUSER_HELPERS
+
 /* kuser helpers page */
 static struct page *kuser_helpers_page __ro_after_init;
 static const struct vm_special_mapping kuser_helpers_spec = {
@@ -148,6 +150,8 @@ static int kuser_helpers_setup(struct mm_struct *mm)
 	return PTR_ERR_OR_ZERO(ret);
 }
 
+#endif /* CONFIG_KUSER_HELPERS */
+
 int aarch32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 {
 	struct mm_struct *mm = current->mm;
@@ -160,7 +164,9 @@ int aarch32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 	if (ret)
 		goto out;
 
+#ifdef CONFIG_KUSER_HELPERS
 	ret = kuser_helpers_setup(mm);
+#endif
 
 out:
 	up_write(&mm->mmap_sem);
-- 
2.10.2

^ permalink raw reply related

* [RFC PATCH v3 02/11] arm64: compat: Split the sigreturn trampolines and kuser helpers
From: Kevin Brodsky @ 2016-12-06 16:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161206160353.14581-1-kevin.brodsky@arm.com>

AArch32 processes are currently installed a special [vectors] page that
contains the sigreturn trampolines and the kuser helpers, at the fixed
address mandated by the kuser helpers ABI.

Having both functionalities in the same page is becoming problematic,
because:

* It makes it impossible to disable the kuser helpers (the sigreturn
  trampolines cannot be removed), which is possible in arm.

* A future 32-bit vDSO would provide the sigreturn trampolines itself,
  making those in [vectors] redundant.

This patch addresses the problem by moving the sigreturn trampolines to
a separate [sigreturn] page, in similar fashion to [sigpage] in arm.

[vectors] has always been a misnomer on arm64/compat, as there is no
AArch32 vector there. Now that only the kuser helpers are left there,
we can rename it to [kuserhelpers].

mm->context.vdso used to point to the [vectors] page, which is
unnecessary (as its address is fixed). It now points to the [sigreturn]
page (whose address is randomized like a vDSO).

Finally aarch32_setup_vectors_page() has been renamed to the more
generic aarch32_setup_additional_pages().

Cc: Will Deacon <will.deacon@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Nathan Lynch <nathan_lynch@mentor.com>
Cc: Christopher Covington <cov@codeaurora.org>
Cc: Dmitry Safonov <dsafonov@virtuozzo.com>
Cc: Jisheng Zhang <jszhang@marvell.com>
Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
---
 arch/arm64/include/asm/elf.h       |   6 +-
 arch/arm64/include/asm/processor.h |   4 +-
 arch/arm64/include/asm/signal32.h  |   2 -
 arch/arm64/kernel/signal32.c       |   5 +-
 arch/arm64/kernel/vdso.c           | 135 ++++++++++++++++++++++++++-----------
 5 files changed, 104 insertions(+), 48 deletions(-)

diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
index a55384f4a5d7..7da9452596ad 100644
--- a/arch/arm64/include/asm/elf.h
+++ b/arch/arm64/include/asm/elf.h
@@ -185,10 +185,10 @@ typedef compat_elf_greg_t		compat_elf_gregset_t[COMPAT_ELF_NGREG];
 #define compat_start_thread		compat_start_thread
 #define COMPAT_SET_PERSONALITY(ex)	set_thread_flag(TIF_32BIT);
 #define COMPAT_ARCH_DLINFO
-extern int aarch32_setup_vectors_page(struct linux_binprm *bprm,
-				      int uses_interp);
+extern int aarch32_setup_additional_pages(struct linux_binprm *bprm,
+					  int uses_interp);
 #define compat_arch_setup_additional_pages \
-					aarch32_setup_vectors_page
+					aarch32_setup_additional_pages
 
 #endif /* CONFIG_COMPAT */
 
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index 60e34824e18c..b976060b1113 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -39,9 +39,9 @@
 
 #define STACK_TOP_MAX		TASK_SIZE_64
 #ifdef CONFIG_COMPAT
-#define AARCH32_VECTORS_BASE	0xffff0000
+#define AARCH32_KUSER_HELPERS_BASE 0xffff0000
 #define STACK_TOP		(test_thread_flag(TIF_32BIT) ? \
-				AARCH32_VECTORS_BASE : STACK_TOP_MAX)
+				AARCH32_KUSER_HELPERS_BASE : STACK_TOP_MAX)
 #else
 #define STACK_TOP		STACK_TOP_MAX
 #endif /* CONFIG_COMPAT */
diff --git a/arch/arm64/include/asm/signal32.h b/arch/arm64/include/asm/signal32.h
index 81abea0b7650..58e288aaf0ba 100644
--- a/arch/arm64/include/asm/signal32.h
+++ b/arch/arm64/include/asm/signal32.h
@@ -20,8 +20,6 @@
 #ifdef CONFIG_COMPAT
 #include <linux/compat.h>
 
-#define AARCH32_KERN_SIGRET_CODE_OFFSET	0x500
-
 int compat_setup_frame(int usig, struct ksignal *ksig, sigset_t *set,
 		       struct pt_regs *regs);
 int compat_setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c
index b7063de792f7..49396a2b6e11 100644
--- a/arch/arm64/kernel/signal32.c
+++ b/arch/arm64/kernel/signal32.c
@@ -484,14 +484,13 @@ static void compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka,
 		retcode = ptr_to_compat(ka->sa.sa_restorer);
 	} else {
 		/* Set up sigreturn pointer */
+		void *sigreturn_base = current->mm->context.vdso;
 		unsigned int idx = thumb << 1;
 
 		if (ka->sa.sa_flags & SA_SIGINFO)
 			idx += 3;
 
-		retcode = AARCH32_VECTORS_BASE +
-			  AARCH32_KERN_SIGRET_CODE_OFFSET +
-			  (idx << 2) + thumb;
+		retcode = ptr_to_compat(sigreturn_base) + (idx << 2) + thumb;
 	}
 
 	regs->regs[0]	= usig;
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index a2c2478e7d78..6208b7ba4593 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -1,5 +1,7 @@
 /*
- * VDSO implementation for AArch64 and vector page setup for AArch32.
+ * Additional userspace pages setup for AArch64 and AArch32.
+ * - AArch64: vDSO pages setup, vDSO data page update.
+ * - AArch32: sigreturn and kuser helpers pages setup.
  *
  * Copyright (C) 2012 ARM Limited
  *
@@ -50,64 +52,121 @@ static union {
 struct vdso_data *vdso_data = &vdso_data_store.data;
 
 #ifdef CONFIG_COMPAT
-/*
- * Create and map the vectors page for AArch32 tasks.
- */
-static struct page *vectors_page[1] __ro_after_init;
 
-static int __init alloc_vectors_page(void)
-{
-	extern char __kuser_helper_start[], __kuser_helper_end[];
-	extern char __aarch32_sigret_code_start[], __aarch32_sigret_code_end[];
+/* sigreturn trampolines page */
+static struct page *sigreturn_page __ro_after_init;
+static const struct vm_special_mapping sigreturn_spec = {
+	.name	= "[sigreturn]",
+	.pages	= &sigreturn_page,
+};
 
-	int kuser_sz = __kuser_helper_end - __kuser_helper_start;
-	int sigret_sz = __aarch32_sigret_code_end - __aarch32_sigret_code_start;
-	unsigned long vpage;
+static int __init aarch32_sigreturn_init(void)
+{
+	extern char __aarch32_sigret_code_start, __aarch32_sigret_code_end;
 
-	vpage = get_zeroed_page(GFP_ATOMIC);
+	size_t sigret_sz =
+		&__aarch32_sigret_code_end - &__aarch32_sigret_code_start;
+	struct page *page;
+	unsigned long page_addr;
 
-	if (!vpage)
+	page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+	if (!page)
 		return -ENOMEM;
+	page_addr = (unsigned long)page_address(page);
 
-	/* kuser helpers */
-	memcpy((void *)vpage + 0x1000 - kuser_sz, __kuser_helper_start,
-		kuser_sz);
-
-	/* sigreturn code */
-	memcpy((void *)vpage + AARCH32_KERN_SIGRET_CODE_OFFSET,
-               __aarch32_sigret_code_start, sigret_sz);
+	memcpy((void *)page_addr, &__aarch32_sigret_code_start, sigret_sz);
 
-	flush_icache_range(vpage, vpage + PAGE_SIZE);
-	vectors_page[0] = virt_to_page(vpage);
+	flush_icache_range(page_addr, page_addr + PAGE_SIZE);
 
+	sigreturn_page = page;
 	return 0;
 }
-arch_initcall(alloc_vectors_page);
+arch_initcall(aarch32_sigreturn_init);
 
-int aarch32_setup_vectors_page(struct linux_binprm *bprm, int uses_interp)
+static int sigreturn_setup(struct mm_struct *mm)
 {
-	struct mm_struct *mm = current->mm;
-	unsigned long addr = AARCH32_VECTORS_BASE;
-	static const struct vm_special_mapping spec = {
-		.name	= "[vectors]",
-		.pages	= vectors_page,
+	unsigned long addr;
+	void *ret;
+
+	addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0);
+	if (IS_ERR_VALUE(addr)) {
+		ret = ERR_PTR(addr);
+		goto out;
+	}
+
+	ret = _install_special_mapping(mm, addr, PAGE_SIZE,
+				       VM_READ|VM_EXEC|
+				       VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
+				       &sigreturn_spec);
+	if (IS_ERR(ret))
+		goto out;
+
+	mm->context.vdso = (void *)addr;
+
+out:
+	return PTR_ERR_OR_ZERO(ret);
+}
+
+/* kuser helpers page */
+static struct page *kuser_helpers_page __ro_after_init;
+static const struct vm_special_mapping kuser_helpers_spec = {
+	.name	= "[kuserhelpers]",
+	.pages	= &kuser_helpers_page,
+};
+
+static int __init aarch32_kuser_helpers_init(void)
+{
+	extern char __kuser_helper_start, __kuser_helper_end;
 
-	};
+	size_t kuser_sz = &__kuser_helper_end - &__kuser_helper_start;
+	struct page *page;
+	unsigned long page_addr;
+
+	page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+	if (!page)
+		return -ENOMEM;
+	page_addr = (unsigned long)page_address(page);
+
+	memcpy((void *)(page_addr + 0x1000 - kuser_sz), &__kuser_helper_start,
+	       kuser_sz);
+
+	flush_icache_range(page_addr, page_addr + PAGE_SIZE);
+
+	kuser_helpers_page = page;
+	return 0;
+}
+arch_initcall(aarch32_kuser_helpers_init);
+
+static int kuser_helpers_setup(struct mm_struct *mm)
+{
 	void *ret;
 
+	/* Map the kuser helpers at the ABI-defined high address */
+	ret = _install_special_mapping(mm, AARCH32_KUSER_HELPERS_BASE, PAGE_SIZE,
+				       VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC,
+				       &kuser_helpers_spec);
+	return PTR_ERR_OR_ZERO(ret);
+}
+
+int aarch32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
+{
+	struct mm_struct *mm = current->mm;
+	int ret;
+
 	if (down_write_killable(&mm->mmap_sem))
 		return -EINTR;
-	current->mm->context.vdso = (void *)addr;
 
-	/* Map vectors page at the high address. */
-	ret = _install_special_mapping(mm, addr, PAGE_SIZE,
-				       VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC,
-				       &spec);
+	ret = sigreturn_setup(mm);
+	if (ret)
+		goto out;
 
-	up_write(&mm->mmap_sem);
+	ret = kuser_helpers_setup(mm);
 
-	return PTR_ERR_OR_ZERO(ret);
+out:
+	up_write(&mm->mmap_sem);
+	return ret;
 }
+
 #endif /* CONFIG_COMPAT */
 
 static struct vm_special_mapping vdso_spec[2] __ro_after_init = {
-- 
2.10.2

^ permalink raw reply related

* [RFC PATCH v3 01/11] arm64: compat: Remove leftover variable declaration
From: Kevin Brodsky @ 2016-12-06 16:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161206160353.14581-1-kevin.brodsky@arm.com>

Commit a1d5ebaf8ccd ("arm64: big-endian: don't treat code as data when
copying sigret code") moved the 32-bit sigreturn trampoline code from
the aarch32_sigret_code array to kuser32.S. The commit removed the
array definition from signal32.c, but not its declaration in
signal32.h. Remove the leftover declaration.

Cc: Will Deacon <will.deacon@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Nathan Lynch <nathan_lynch@mentor.com>
Cc: Christopher Covington <cov@codeaurora.org>
Cc: Dmitry Safonov <dsafonov@virtuozzo.com>
Cc: Jisheng Zhang <jszhang@marvell.com>
Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
---
 arch/arm64/include/asm/signal32.h | 2 --
 1 file changed, 2 deletions(-)

diff --git a/arch/arm64/include/asm/signal32.h b/arch/arm64/include/asm/signal32.h
index eeaa97559bab..81abea0b7650 100644
--- a/arch/arm64/include/asm/signal32.h
+++ b/arch/arm64/include/asm/signal32.h
@@ -22,8 +22,6 @@
 
 #define AARCH32_KERN_SIGRET_CODE_OFFSET	0x500
 
-extern const compat_ulong_t aarch32_sigret_code[6];
-
 int compat_setup_frame(int usig, struct ksignal *ksig, sigset_t *set,
 		       struct pt_regs *regs);
 int compat_setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
-- 
2.10.2

^ permalink raw reply related

* [RFC PATCH v3 00/11] arm64: Add a compat vDSO
From: Kevin Brodsky @ 2016-12-06 16:03 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

This series adds support for a compat (AArch32) vDSO, providing two
userspace functionalities to compat processes:

* "Virtual" time syscalls (gettimeofday and clock_gettime). The
  implementation is an adaptation of the arm vDSO (vgettimeofday.c),
  sharing the data page with the 64-bit vDSO.

* sigreturn trampolines, following the example of the 64-bit vDSO
  (sigreturn.S), but slightly more complicated because we provide A32
  and T32 variants for both sigreturn and rt_sigreturn, and appropriate
  arm-specific unwinding directives.

The first point brings the performance improvement expected of a vDSO,
by implementing time syscalls directly in userspace. The second point
allows to provide unwinding information for sigreturn trampolines,
achieving feature parity with the trampolines provided by glibc.

Unfortunately, this time we cannot escape using a 32-bit toolchain. To
build the compat VDSO, CONFIG_COMPAT_VDSO must be set *and*
CROSS_COMPILE_ARM32 must be defined to the prefix of a 32-bit compiler.
Failure to do so will not prevent building the kernel, but a warning
will be printed and the compat vDSO will not be built.

v3 is a major refactor of the series. The main change is that the kuser
helpers are no longer mutually exclusive with the 32-bit vDSO, and can
be disabled independently of the 32-bit vDSO (they are kept enabled by
default). To this end, the "old" sigreturn trampolines have been moved
out of the [vectors] page into an independent [sigreturn] page, similar
to [sigpage] on arm. The [vectors] page is now [kuserhelpers], and its
presence is controlled by CONFIG_KUSER_HELPERS. The [sigreturn] page is
only present when the 32-bit vDSO is not included (the latter provides
its own sigreturn trampolines with unwinding information). The following
table summarises which pages are now added in 32-bit processes:

+----------------+----------------+----------------+
|     CONFIG     | !VDSO32        | VDSO32         |
+----------------+----------------+----------------+
| !KUSER_HELPERS | [sigreturn]    | [vvar]         |
|                |                | [vdso]         |
+----------------+----------------+----------------+
| KUSER_HELPERS  | [sigreturn]    | [vvar]         |
|                | [kuserhelpers] | [vdso]         |
|                |                | [kuserhelpers] |
+----------------+----------------+----------------+

Additionally, the 32-bit vDSO no longer requires a 32-bit compiler
supporting ARMv8, any compiler supporting ARMv7-A can now be used. The
only code change is to introduce separate AArch32 barriers, to stop
generating dmb ishld when using an ARMv7 assembler. However, a major
rework of the 32-bit vDSO Makefile was necessary, because mismatching
32/64-bit compiler versions prevent sharing flags (e.g.  recently
introduced warning flags). Copy/pasting flags is not nice or beautiful,
but filtering out flags is not practicable and may break when top-level
Makefiles are changed.

Patches overview:
*  1..3: split [vectors] -> [sigreturn] + [kuserhelpers], add
         CONFIG_KUSER_HELPERS
*  4..6: preparation patches
*     7: the 32-bit vDSO itself
* 8..10: plumbing for the 32-bit vDSO
*    11: Kconfig/Makefile wiring

Thanks,
Kevin

Changelog v2..v3:
* kuser helpers / sigreturn split.
* Rework/debug of the sigreturn trampolines in the 32-bit vDSO. The CFI
  directives have been removed, as they only provide debug information
  on arm (which is stripped from vdso.so). After adding a missing nop,
  unwinding now works properly with all the trampolines (see comment in
  patch 7).
* Some cleanup in vdso.c, to make the 32-bit and 64-bit setup more
  consistent.
* 32-bit vDSO Makefile refactor.
* AArch32 barriers, selected by the 32-bit compiler mode
  (armv7-a/armv8-a).
* Use PROVIDE_HIDDEN() instead of HIDDEN() in vdso32/vdso.lds.S, as
  HIDDEN() only exists since ld 2.23.

Cc: Will Deacon <will.deacon@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Nathan Lynch <nathan_lynch@mentor.com>
Cc: Christopher Covington <cov@codeaurora.org>
Cc: Dmitry Safonov <dsafonov@virtuozzo.com>
Cc: Jisheng Zhang <jszhang@marvell.com>

Kevin Brodsky (11):
  arm64: compat: Remove leftover variable declaration
  arm64: compat: Split the sigreturn trampolines and kuser helpers
  arm64: compat: Add CONFIG_KUSER_HELPERS
  arm64: Refactor vDSO init/setup
  arm64: compat: Add time-related syscall numbers
  arm64: compat: Expose offset to registers in sigframes
  arm64: compat: Add a 32-bit vDSO
  arm64: compat: 32-bit vDSO setup
  arm64: elf: Set AT_SYSINFO_EHDR in compat processes
  arm64: compat: Use vDSO sigreturn trampolines if available
  arm64: Wire up and expose the new compat vDSO

 arch/arm64/Kconfig                         |  52 +++++
 arch/arm64/Makefile                        |  28 ++-
 arch/arm64/include/asm/elf.h               |  15 +-
 arch/arm64/include/asm/processor.h         |   4 +-
 arch/arm64/include/asm/signal32.h          |  46 ++++-
 arch/arm64/include/asm/unistd.h            |   2 +
 arch/arm64/include/asm/vdso.h              |   3 +
 arch/arm64/kernel/Makefile                 |   9 +-
 arch/arm64/kernel/asm-offsets.c            |  13 ++
 arch/arm64/kernel/kuser32.S                |  48 +----
 arch/arm64/kernel/signal32.c               |  66 ++----
 arch/arm64/kernel/sigreturn32.S            |  59 ++++++
 arch/arm64/kernel/vdso.c                   | 315 ++++++++++++++++++++---------
 arch/arm64/kernel/vdso32/Makefile          | 166 +++++++++++++++
 arch/arm64/kernel/vdso32/aarch32-barrier.h |  33 +++
 arch/arm64/kernel/vdso32/sigreturn.S       |  76 +++++++
 arch/arm64/kernel/vdso32/vdso.S            |  32 +++
 arch/arm64/kernel/vdso32/vdso.lds.S        |  93 +++++++++
 arch/arm64/kernel/vdso32/vgettimeofday.c   | 295 +++++++++++++++++++++++++++
 19 files changed, 1147 insertions(+), 208 deletions(-)
 create mode 100644 arch/arm64/kernel/sigreturn32.S
 create mode 100644 arch/arm64/kernel/vdso32/Makefile
 create mode 100644 arch/arm64/kernel/vdso32/aarch32-barrier.h
 create mode 100644 arch/arm64/kernel/vdso32/sigreturn.S
 create mode 100644 arch/arm64/kernel/vdso32/vdso.S
 create mode 100644 arch/arm64/kernel/vdso32/vdso.lds.S
 create mode 100644 arch/arm64/kernel/vdso32/vgettimeofday.c

-- 
2.10.2

^ permalink raw reply

* [PATCH v2] ACPI/IORT: Make dma masks set-up IORT specific
From: Joerg Roedel @ 2016-12-06 15:58 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161206142011.11859-1-lorenzo.pieralisi@arm.com>

On Tue, Dec 06, 2016 at 02:20:11PM +0000, Lorenzo Pieralisi wrote:
>  drivers/acpi/arm64/iort.c | 22 ++++++++++++++++++++++
>  drivers/acpi/scan.c       | 14 +-------------
>  include/linux/acpi_iort.h |  2 ++
>  3 files changed, 25 insertions(+), 13 deletions(-)

Applied, thanks.

^ permalink raw reply

* [LINUX RFC v4 3/4] mtd: spi-nor: add stripe support
From: Naga Sureshkumar Relli @ 2016-12-06 15:58 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <c3dda4c6-c480-dc60-8d68-42804dbb7a4a@atmel.com>

Hi Mark and Cyrille,

> -----Original Message-----
> From: Cyrille Pitchen [mailto:cyrille.pitchen at atmel.com]
> Sent: Tuesday, December 06, 2016 4:30 PM
> To: Naga Sureshkumar Relli <nagasure@xilinx.com>; broonie at kernel.org;
> michal.simek at xilinx.com; Soren Brinkmann <sorenb@xilinx.com>; Harini
> Katakam <harinik@xilinx.com>; Punnaiah Choudary Kalluri
> <punnaia@xilinx.com>
> Cc: linux-spi at vger.kernel.org; linux-arm-kernel at lists.infradead.org; linux-
> kernel at vger.kernel.org; linux-mtd at lists.infradead.org
> Subject: Re: [LINUX RFC v4 3/4] mtd: spi-nor: add stripe support
>
> Le 06/12/2016 ? 07:54, Naga Sureshkumar Relli a ?crit :
> > Hi Cyrille,
> >
> >> -----Original Message-----
> >> From: Cyrille Pitchen [mailto:cyrille.pitchen at atmel.com]
> >> Sent: Monday, December 05, 2016 6:34 PM
> >> To: Naga Sureshkumar Relli <nagasure@xilinx.com>; broonie at kernel.org;
> >> michal.simek at xilinx.com; Soren Brinkmann <sorenb@xilinx.com>; Harini
> >> Katakam <harinik@xilinx.com>; Punnaiah Choudary Kalluri
> >> <punnaia@xilinx.com>
> >> Cc: linux-spi at vger.kernel.org; linux-arm-kernel at lists.infradead.org;
> >> linux- kernel at vger.kernel.org; linux-mtd at lists.infradead.org
> >> Subject: Re: [LINUX RFC v4 3/4] mtd: spi-nor: add stripe support
> >>
> >> Hi Naga,
> >>
> >> Le 05/12/2016 ? 08:02, Naga Sureshkumar Relli a ?crit :
> >>> Hi Cyrille,
> >>>
> >>>>> Hi Cyrille,
> >>>>>
> >>>>>> I have not finished to review the whole series yet but here some
> >>>>>> first
> >>>>>> comments:
> >>>>>
> >>>>> Thanks for reviewing these patch series.
> >>>>>
> >>>>>>
> >>>>>> Le 27/11/2016 ? 09:33, Naga Sureshkumar Relli a ?crit :
> >>>>>>> This patch adds stripe support and it is needed for GQSPI
> >>>>>>> parallel configuration mode by:
> >>>>>>>
> >>>>>>> - Adding required parameters like stripe and shift to spi_nor
> >>>>>>>   structure.
> >>>>>>> - Initializing all added parameters in spi_nor_scan()
> >>>>>>> - Updating read_sr() and read_fsr() for getting status from both
> >>>>>>>   flashes
> >>>>>>> - Increasing page_size, sector_size, erase_size and toatal flash
> >>>>>>>   size as and when required.
> >>>>>>> - Dividing address by 2
> >>>>>>> - Updating spi->master->flags for qspi driver to change CS
> >>>>>>>
> >>>>>>> Signed-off-by: Naga Sureshkumar Relli <nagasure@xilinx.com>
> >>>>>>> ---
> >>>>>>> Changes for v4:
> >>>>>>>  - rename isparallel to stripe
> >>>>>>> Changes for v3:
> >>>>>>>  - No change
> >>>>>>> Changes for v2:
> >>>>>>>  - Splitted to separate MTD layer changes from SPI core changes
> >>>>>>> ---
> >>>>>>>  drivers/mtd/spi-nor/spi-nor.c | 130
> >>>>>> ++++++++++++++++++++++++++++++++----------
> >>>>>>>  include/linux/mtd/spi-nor.h   |   2 +
> >>>>>>>  2 files changed, 103 insertions(+), 29 deletions(-)
> >>>>>>>
> >>>>>>> diff --git a/drivers/mtd/spi-nor/spi-nor.c
> >>>>>>> b/drivers/mtd/spi-nor/spi-nor.c index d0fc165..4252239 100644
> >>>>>>> --- a/drivers/mtd/spi-nor/spi-nor.c
> >>>>>>> +++ b/drivers/mtd/spi-nor/spi-nor.c
> >>>>>>> @@ -22,6 +22,7 @@
> >>>>>>>  #include <linux/of_platform.h>
> >>>>>>>  #include <linux/spi/flash.h>
> >>>>>>>  #include <linux/mtd/spi-nor.h>
> >>>>>>> +#include <linux/spi/spi.h>
> >>>>>>>
> >>>>>>>  /* Define max times to check status register before we give up.
> >>>>>>> */
> >>>>>>>
> >>>>>>> @@ -89,15 +90,24 @@ static const struct flash_info
> >>>>>>> *spi_nor_match_id(const char *name);  static int read_sr(struct
> >>>>>>> spi_nor *nor)  {
> >>>>>>>   int ret;
> >>>>>>> - u8 val;
> >>>>>>> + u8 val[2];
> >>>>>>>
> >>>>>>> - ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val, 1);
> >>>>>>> - if (ret < 0) {
> >>>>>>> -         pr_err("error %d reading SR\n", (int) ret);
> >>>>>>> -         return ret;
> >>>>>>> + if (nor->stripe) {
> >>>>>>> +         ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val[0], 2);
> >>>>>>> +         if (ret < 0) {
> >>>>>>> +                 pr_err("error %d reading SR\n", (int) ret);
> >>>>>>> +                 return ret;
> >>>>>>> +         }
> >>>>>>> +         val[0] |= val[1];
> >>>>>> Why '|' rather than '&' ?
> >>>>>> I guess because of the 'Write In Progress/Busy' bit: when called
> >>>>>> by spi_nor_sr_ready(), you want to be sure that this 'BUSY' bit
> >>>>>> is cleared on both memories.
> >>>>>>
> >>>>>> But what about when the Status Register is read for purpose other
> >>>>>> than checking the state of the 'BUSY' bit?
> >>>>>>
> >>>>> Yes you are correct, I will change this.
> >>>>>
> >>>>>> What about SPI controllers supporting more than 2 memories in
> >> parallel?
> >>>>>>
> >>>>>> This solution might fit the ZynqMP controller but doesn't look so
> >> generic.
> >>>>>>
> >>>>>>> + } else {
> >>>>>>> +         ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val[0], 1);
> >>>>>>> +         if (ret < 0) {
> >>>>>>> +                 pr_err("error %d reading SR\n", (int) ret);
> >>>>>>> +                 return ret;
> >>>>>>> +         }
> >>>>>>>   }
> >>>>>>>
> >>>>>>> - return val;
> >>>>>>> + return val[0];
> >>>>>>>  }
> >>>>>>>
> >>>>>>>  /*
> >>>>>>> @@ -108,15 +118,24 @@ static int read_sr(struct spi_nor *nor)
> >>>>>>> static int read_fsr(struct spi_nor *nor)  {
> >>>>>>>   int ret;
> >>>>>>> - u8 val;
> >>>>>>> + u8 val[2];
> >>>>>>>
> >>>>>>> - ret = nor->read_reg(nor, SPINOR_OP_RDFSR, &val, 1);
> >>>>>>> - if (ret < 0) {
> >>>>>>> -         pr_err("error %d reading FSR\n", ret);
> >>>>>>> -         return ret;
> >>>>>>> + if (nor->stripe) {
> >>>>>>> +         ret = nor->read_reg(nor, SPINOR_OP_RDFSR, &val[0], 2);
> >>>>>>> +         if (ret < 0) {
> >>>>>>> +                 pr_err("error %d reading FSR\n", ret);
> >>>>>>> +                 return ret;
> >>>>>>> +         }
> >>>>>>> +         val[0] &= val[1];
> >>>>>> Same comment here: why '&' rather than '|'?
> >>>>>> Surely because of the the 'READY' bit which should be set for
> >>>>>> both
> >>>> memories.
> >>>>> I will update this also.
> >>>>>>
> >>>>>>> + } else {
> >>>>>>> +         ret = nor->read_reg(nor, SPINOR_OP_RDFSR, &val[0], 1);
> >>>>>>> +         if (ret < 0) {
> >>>>>>> +                 pr_err("error %d reading FSR\n", ret);
> >>>>>>> +                 return ret;
> >>>>>>> +         }
> >>>>>>>   }
> >>>>>>>
> >>>>>>> - return val;
> >>>>>>> + return val[0];
> >>>>>>>  }
> >>>>>>>
> >>>>>>>  /*
> >>>>>>> @@ -290,9 +309,16 @@ static int spi_nor_wait_till_ready(struct
> >>>>>>> spi_nor
> >>>>>> *nor)
> >>>>>>>   */
> >>>>>>>  static int erase_chip(struct spi_nor *nor)  {
> >>>>>>> + u32 ret;
> >>>>>>> +
> >>>>>>>   dev_dbg(nor->dev, " %lldKiB\n", (long long)(nor->mtd.size >>
> >>>>>>> 10));
> >>>>>>>
> >>>>>>> - return nor->write_reg(nor, SPINOR_OP_CHIP_ERASE, NULL, 0);
> >>>>>>> + ret = nor->write_reg(nor, SPINOR_OP_CHIP_ERASE, NULL, 0); if
> >>>>>>> + (ret)
> >>>>>>> +         return ret;
> >>>>>>> +
> >>>>>>> + return ret;
> >>>>>>> +
> >>>>>>
> >>>>>>    if (ret)
> >>>>>>            return ret;
> >>>>>>    else
> >>>>>>            return ret;
> >>>>>>
> >>>>>> This chunk should be removed, it doesn't ease the patch review ;)
> >>>>> Ok, I will remove.
> >>>>>>
> >>>>>>>  }
> >>>>>>>
> >>>>>>>  static int spi_nor_lock_and_prep(struct spi_nor *nor, enum
> >>>>>>> spi_nor_ops ops) @@ -349,7 +375,7 @@ static int
> >>>>>>> spi_nor_erase_sector(struct spi_nor *nor, u32 addr)  static int
> >>>>>>> spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)  {
> >>>>>>>   struct spi_nor *nor = mtd_to_spi_nor(mtd);
> >>>>>>> - u32 addr, len;
> >>>>>>> + u32 addr, len, offset;
> >>>>>>>   uint32_t rem;
> >>>>>>>   int ret;
> >>>>>>>
> >>>>>>> @@ -399,9 +425,13 @@ static int spi_nor_erase(struct mtd_info
> >>>>>>> *mtd,
> >>>>>> struct erase_info *instr)
> >>>>>>>   /* "sector"-at-a-time erase */
> >>>>>>>   } else {
> >>>>>>>           while (len) {
> >>>>>>> +
> >>>>>>>                   write_enable(nor);
> >>>>>>> +                 offset = addr;
> >>>>>>> +                 if (nor->stripe)
> >>>>>>> +                         offset /= 2;
> >>>>>>
> >>>>>> I guess this should be /= 4 for controllers supporting 4 memories
> >>>>>> in
> >>>> parallel.
> >>>>>> Shouldn't you use nor->shift and define shift as an unsigned int
> >>>>>> instead of a bool?
> >>>>>> offset >>= nor->shift;
> >>>>>>
> >>>>> Yes we can use this shift, I will update
> >>>>>
> >>>>>> Anyway, by tuning the address here in spi-nor.c rather than in
> >>>>>> the SPI controller driver, you impose a model to support parallel
> >>>>>> memories that might not be suited to other controllers.
> >>>>>
> >>>>> For this ZynqMP GQSPI controller parallel configuration, globally
> >>>>> spi-nor should know about this stripe feature And based on that
> >>>>> address
> >>>> has to change.
> >>>>> As I mentioned in cover letter, this controller in parallel
> >>>>> configuration will
> >>>> work with even addresses only.
> >>>>> i.e. Before creating address format(m25p_addr2cmd) in mtd layer,
> >>>>> spi-nor
> >>>> should change that address based on stripe option.
> >>>>>
> >>>>> I am updating this offset based on stripe option, and stripe
> >>>>> option will
> >>>> update by reading dt property in nor_scan().
> >>>>> So the controller which doesn't support, then the stripe will be zero.
> >>>>> Or Can you please suggest any other way?
> >>>>>
> >>>>>>
> >>>>>>>
> >>>>>>> -                 ret = spi_nor_erase_sector(nor, addr);
> >>>>>>> +                 ret = spi_nor_erase_sector(nor, offset);
> >>>>>>>                   if (ret)
> >>>>>>>                           goto erase_err;
> >>>>>>>
> >>>>>>> @@ -525,6 +555,8 @@ static int stm_lock(struct spi_nor *nor,
> >>>>>>> loff_t ofs,
> >>>>>> uint64_t len)
> >>>>>>>   bool use_top;
> >>>>>>>   int ret;
> >>>>>>>
> >>>>>>> + ofs = ofs >> nor->shift;
> >>>>>>> +
> >>>>>>>   status_old = read_sr(nor);
> >>>>>>>   if (status_old < 0)
> >>>>>>>           return status_old;
> >>>>>>> @@ -610,6 +642,8 @@ static int stm_unlock(struct spi_nor *nor,
> >>>>>>> loff_t ofs,
> >>>>>> uint64_t len)
> >>>>>>>   bool use_top;
> >>>>>>>   int ret;
> >>>>>>>
> >>>>>>> + ofs = ofs >> nor->shift;
> >>>>>>> +
> >>>>>>>   status_old = read_sr(nor);
> >>>>>>>   if (status_old < 0)
> >>>>>>>           return status_old;
> >>>>>>> @@ -709,6 +743,8 @@ static int spi_nor_lock(struct mtd_info
> >>>>>>> *mtd, loff_t
> >>>>>> ofs, uint64_t len)
> >>>>>>>   if (ret)
> >>>>>>>           return ret;
> >>>>>>>
> >>>>>>> + ofs = ofs >> nor->shift;
> >>>>>>> +
> >>>>>>>   ret = nor->flash_lock(nor, ofs, len);
> >>>>>>>
> >>>>>>>   spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_UNLOCK); @@ -
> >>>>>> 724,6 +760,8
> >>>>>>> @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs,
> >>>>>>> uint64_t
> >>>>>> len)
> >>>>>>>   if (ret)
> >>>>>>>           return ret;
> >>>>>>>
> >>>>>>> + ofs = ofs >> nor->shift;
> >>>>>>> +
> >>>>>>>   ret = nor->flash_unlock(nor, ofs, len);
> >>>>>>>
> >>>>>>>   spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK); @@ -
> >>>>>> 1018,6 +1056,9
> >>>>>>> @@ static const struct flash_info *spi_nor_read_id(struct
> >>>>>>> spi_nor
> >> *nor)
> >>>>>>>   u8                      id[SPI_NOR_MAX_ID_LEN];
> >>>>>>>   const struct flash_info *info;
> >>>>>>>
> >>>>>>> + nor->spi->master->flags &= ~(SPI_MASTER_BOTH_CS |
> >>>>>>> +                                 SPI_MASTER_DATA_STRIPE);
> >>>>>>> +
> >>>>>>>   tmp = nor->read_reg(nor, SPINOR_OP_RDID, id,
> >>>>>> SPI_NOR_MAX_ID_LEN);
> >>>>>>>   if (tmp < 0) {
> >>>>>>>           dev_dbg(nor->dev, "error %d reading JEDEC ID\n", tmp);
> >>>>>> @@ -1041,6
> >>>>>>> +1082,7 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t
> >>>>>>> +from,
> >>>>>>> size_t len,  {
> >>>>>>>   struct spi_nor *nor = mtd_to_spi_nor(mtd);
> >>>>>>>   int ret;
> >>>>>>> + u32 offset = from;
> >>>>>>>
> >>>>>>>   dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len);
> >>>>>>>
> >>>>>>> @@ -1049,7 +1091,13 @@ static int spi_nor_read(struct mtd_info
> >>>>>>> *mtd,
> >>>>>> loff_t from, size_t len,
> >>>>>>>           return ret;
> >>>>>>>
> >>>>>>>   while (len) {
> >>>>>>> -         ret = nor->read(nor, from, len, buf);
> >>>>>>> +
> >>>>>>> +         offset = from;
> >>>>>>> +
> >>>>>>> +         if (nor->stripe)
> >>>>>>> +                 offset /= 2;
> >>>>>>> +
> >>>>>>> +         ret = nor->read(nor, offset, len, buf);
> >>>>>>>           if (ret == 0) {
> >>>>>>>                   /* We shouldn't see 0-length reads */
> >>>>>>>                   ret = -EIO;
> >>>>>>> @@ -1161,6 +1209,7 @@ static int spi_nor_write(struct mtd_info
> >>>>>>> *mtd,
> >>>>>> loff_t to, size_t len,
> >>>>>>>   struct spi_nor *nor = mtd_to_spi_nor(mtd);
> >>>>>>>   size_t page_offset, page_remain, i;
> >>>>>>>   ssize_t ret;
> >>>>>>> + u32 offset;
> >>>>>>>
> >>>>>>>   dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
> >>>>>>>
> >>>>>>> @@ -1178,9 +1227,13 @@ static int spi_nor_write(struct mtd_info
> >>>>>>> *mtd,
> >>>>>> loff_t to, size_t len,
> >>>>>>>           /* the size of data remaining on the first page */
> >>>>>>>           page_remain = min_t(size_t,
> >>>>>>>                               nor->page_size - page_offset, len
> >>>>>>> - i);
> >>>>>>> +         offset = (to + i);
> >>>>>>> +
> >>>>>>> +         if (nor->stripe)
> >>>>>>> +                 offset /= 2;
> >>>>>>>
> >>>>>>>           write_enable(nor);
> >>>>>>> -         ret = nor->write(nor, to + i, page_remain, buf + i);
> >>>>>>> +         ret = nor->write(nor, (offset), page_remain, buf + i);
> >>>>>>>           if (ret < 0)
> >>>>>>>                   goto write_err;
> >>>>>>>           written = ret;
> >>>>>>> @@ -1302,22 +1355,22 @@ static int spi_nor_check(struct spi_nor
> >>>>>>> *nor)
> >>>>>>>
> >>>>>>>  int spi_nor_scan(struct spi_nor *nor, const char *name, enum
> >>>>>>> read_mode mode)  {
> >>>>>>> - const struct flash_info *info = NULL;
> >>>>>>> + struct flash_info *info = NULL;
> >>>>>>
> >>>>>> You should not remove the const and should not try to modify
> >>>>>> members of *info.
> >>>>>>
> >>>>>>>   struct device *dev = nor->dev;
> >>>>>>>   struct mtd_info *mtd = &nor->mtd;
> >>>>>>>   struct device_node *np = spi_nor_get_flash_node(nor);
> >>>>>>> - int ret;
> >>>>>>> - int i;
> >>>>>>> + struct device_node *np_spi;
> >>>>>>> + int ret, i, xlnx_qspi_mode;
> >>>>>>>
> >>>>>>>   ret = spi_nor_check(nor);
> >>>>>>>   if (ret)
> >>>>>>>           return ret;
> >>>>>>>
> >>>>>>>   if (name)
> >>>>>>> -         info = spi_nor_match_id(name);
> >>>>>>> +         info = (struct flash_info *)spi_nor_match_id(name);
> >>>>>>>   /* Try to auto-detect if chip name wasn't specified or not found */
> >>>>>>>   if (!info)
> >>>>>>> -         info = spi_nor_read_id(nor);
> >>>>>>> +         info = (struct flash_info *)spi_nor_read_id(nor);
> >>>>>>>   if (IS_ERR_OR_NULL(info))
> >>>>>>>           return -ENOENT;
> >>>>>>>
> >>>>>> Both spi_nor_match_id() and spi_nor_read_id(), when they
> succeed,
> >>>>>> return a pointer to an entry of the spi_nor_ids[] array, which is
> >>>>>> located in a read- only memory area.
> >>>>>>
> >>>>>> Since your patch doesn't remove the const attribute of the
> >>>>>> spi_nor_ids[], I wonder whether it has been tested. I expect it
> >>>>>> not to work on most architecture.
> >>>>>>
> >>>>>> Anyway spi_nor_ids[] should remain const. Let's take the case of
> >>>>>> eXecution In Place (XIP) from an external memory: if
> >>>>>> spi_nor_ids[] is const, it can be read directly from this
> >>>>>> external (read-only) memory and we never need to copy the array
> >>>>>> in RAM, so we save
> >> some
> >>>>>> KB of
> >>>> RAM.
> >>>>>> This is just an example but I guess we can find other reasons to
> >>>>>> keep this array const.
> >>>>>>
> >>>>>>> @@ -1341,7 +1394,7 @@ int spi_nor_scan(struct spi_nor *nor,
> >>>>>>> const char
> >>>>>> *name, enum read_mode mode)
> >>>>>>>                    */
> >>>>>>>                   dev_warn(dev, "found %s, expected %s\n",
> >>>>>>>                            jinfo->name, info->name);
> >>>>>>> -                 info = jinfo;
> >>>>>>> +                 info = (struct flash_info *)jinfo;
> >>>>>>>           }
> >>>>>>>   }
> >>>>>>>
> >>>>>>> @@ -1370,6 +1423,27 @@ int spi_nor_scan(struct spi_nor *nor,
> >>>>>>> const char
> >>>>>> *name, enum read_mode mode)
> >>>>>>>   mtd->size = info->sector_size * info->n_sectors;
> >>>>>>>   mtd->_erase = spi_nor_erase;
> >>>>>>>   mtd->_read = spi_nor_read;
> >>>>>>> +#ifdef CONFIG_OF
> >>>>>>> + np_spi = of_get_next_parent(np);
> >>>>>>> +
> >>>>>>> + if (of_property_read_u32(np_spi, "xlnx,qspi-mode",
> >>>>>>> +                         &xlnx_qspi_mode) < 0) {
> >>>>>> This really looks controller specific so should not be placed in
> >>>>>> the generic spi- nor.c file.
> >>>>>
> >>>>> Const is removed in info struct, because to update info members
> >>>>> based
> >>>> parallel configuration.
> >>>>> As I mentioned above,  for this parallel configuration, mtd and
> >>>>> spi-nor should know the details like
> >>>>> mtd->size, info->sectors, sector_size and page_size.
> >>>>
> >>>> You can tune the values of nor->mtd.size, nor->mtd.erasesize, nor-
> >>>>> page_size or whatever member of nor/nor.mtd as needed without
> ever
> >>>> modifying members of *info.
> >>>>
> >>>> If you modify *info then spi_nor_scan() is called a 2nd time to
> >>>> probe and configure SPI memories of the same part but connected to
> >>>> another controller, the values of the modified members in this
> >>>> *info would not be those expected.
> >>>> So *info and the spi_nor_ids[] array must remain const.
> >>>>
> >>>> The *info structure is not used outside spi_nor_scan(); none of
> >>>> spi_nor_read(),
> >>>> spi_nor_write() and spi_nor_erase() refers to *info hence every
> >>>> relevant value can be set only nor or nor->mtd members.
> >>>>
> >>>>
> >>>> Anyway, I think OR'ing or AND'ing values of memory registers
> >>>> depending on the relevant bit we want to check is not the right
> solution.
> >>>> If done in spi-nor.c, there would be a specific case for each
> >>>> memory register we read, each register bit would have to be handled
> differently.
> >>>>
> >>>> spi-nor.c tries to support as much memory parts as possible, it
> >>>> deals with many registers and bits: Status/Control registers, Quad
> Enable bits...
> >>>>
> >>>> If we start to OR or AND each of these register values to support
> >>>> the stripping mode, spi-nor will become really hard to maintain.
> >>>>
> >>>> I don't know whether it could be done with the xilinx controller
> >>>> but I thought about first configuring the two memories
> >>>> independently calling
> >>>> spi_nor_scan() twice; one call for each memory.
> >>>>
> >>>> Then the xilinx driver could register only one struct mtd_info,
> >>>> overriding
> >>>> mtd->_read() [and likely mtd->_write() and mtd->_erase() too] set
> >>>> mtd->by
> >>>> spi_nor_scan() with a xilinx driver custom implementation so this
> >>>> driver supports its controller stripping mode as it wants.
> >>>>
> >>>> Of course, this solution assumes that the SPI controller has one
> >>>> dedicated chip-select line for each memory and not a single
> >>>> chip-select line shared by both memories. The memories should be
> >>>> configured independently: you can't assume multiple instances of
> >>>> the very same memory part always return the exact same value when
> >>>> reading one of their register. Logical AND/OR is not a generic solution,
> IMHO.
> >>>>
> >>>> If the xilinx controller has only one shared chip-select line then
> >>>> let's see whether 2 GPIO lines could be used as independent
> >>>> chip-select
> >> lines.
> >>>>
> >>>>
> >>> In parallel configuration, Physically we have two flashes but mtd
> >>> will see as single flash memory (sum of both memories) If we call
> >> spi_nor_scan(), twice then read/write will override but
> >> nor->mtd.size, nor-
> >>> mtd.erasesize, nor->page_size  will remain same, I,e they will also
> >>> override,
> >> they won't append.
> >>> I tried calling spi_nor_scan() twice by some hacks but
> >>> nor->mtd.size,
> >>> nor->mtd.erasesize, nor->page_size are not changing Also the same
> >>> nor->issue
> >> we are getting for flash address, need to shift the address to work
> >> in this configuration.
> >>> Also to tune  nor->mtd.size, nor->mtd.erasesize, nor->page_size, we
> >>> need to touch this spi-nor.c
> >>>
> >>> Please kindly suggest, if I am wrong.
> >>>
> >>
> >> What I've been suggesting is:
> >>
> >> {
> >>       struct spi_nor *nor1, *nor2;
> >>       struct mtd_info *mtd;
> >>       enum read_mode mode = SPI_NOR_QUAD;
> >>       int err;
> >>
> >>       [...]
> >>
> >>       err = spi_nor_scan(nor1, NULL, mode);
> >>       if (err)
> >>               return err; /* or handle error properly. */
> >>
> >>       err = spi_nor_scan(nor2, NULL, mode);
> >>       if (err)
> >>               return err;
> >>
> >>       mtd = &nor1->mtd;
> >>       mtd->erasesize <<= 1;
> >>       mtd->size <<= 1;
> >>       mtd->writebufsize <<= 1;
> >>       nor1->page_size <<= 1;
> >>       /* tune all other relevant members of nor1/mtd. */
> >>
> >>       /* override relevant mtd hooks. */
> >>       mtd->_read = stripping_read;
> >>       mtd->_erase = stripping_erase;
> >>       mtd->_write = stripping_write;
> >>       mtd->_lock = ...;
> >>       mtd->_unlock = ...;
> >>       mtd->_is_lock = ...;
> >>
> >>       /* register a single mtd_info structure. */
> >>       err = mtd_device_register(mtd, NULL, 0);
> >>       if (err)
> >>               return err;
> >>
> >>       [...]
> >> }
> >>
> >
> > It's really good for us to have our controller specific mtd hooks instead of
> changing the layer calls and thanks for this suggestion.
> > But spi-zynqmp-gqspi.c is spi driver and all above mentioned parameters
> and function pointers are related to flash layer.
> > So is it ok to update and change flash related stuff in our spi driver?
> >
>
> Check with the SPI sub-system people, especially Mark Brown, but I don't
> think would be good to put too much mtd/spi-nor stuff in the SPI sub-
> system.
>
> Anyway, the solution I've proposed is not suited if you use m25p80.c as an
> adaptation layer between spi-nor.c and the SPI controller driver.
> Indeed, in that case, spi_nor_scan() is called from m25p_probe() in m25p80.c
> and I still think there would be too many side effects if we modified either
> spi-nor.c or m25p80.c the way you propose to compute logical operations on
> register values. This solution is not maintainable regarding the number
> memory registers we already manage.
>
> You might need to develop a new driver to substitute m25p80.c and make
> the link between spi-nor, mostly spi_nor_scan(), and you SPI controller
> driver.
>
> Honestly I have no real idea how you could proceed to add support to such a
> feature: accessing 2 SPI flashes at the time to perform stripping operations
> doesn't sound really reliable to me because I don't see how you plan to
> handle errors properly and also cover all the features provided by SPI flash
> memory and supported by spi-nor.c (sector/block protection, ...).
>
> >> Best regards,
> >>
> >> Cyrille
> >>
> > Thanks,
> > Naga Sureshkumar Relli

Cyrille, thanks for info.
Mark, Could you please provide a way to add this stripe support for GQSPI controller?
We already sent patches to add this support by changing mtd layer, as we don't have any other way to do this
Because of controller limitation.
Cyrille provided some way to do this, but it involves spi-nor support in our spi driver.

Thanks,
Naga Sureshkumar Relli


This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.

^ permalink raw reply

* [PATCH 1/1] arm/module: maximum utilization of module area.
From: Nicolas Pitre @ 2016-12-06 15:57 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1481012975-44478-1-git-send-email-maninder1.s@samsung.com>

On Tue, 6 Dec 2016, Maninder Singh wrote:

> This patch defines new macro MODULE_START to ensure kernel text
> and module remains within 32 MB of address range.
> 
> Tried this patch by inserting 20 MB size module on 4.1 kernel:-
> 
> Earlier:-
> ==========
> sh# insmod size.ko
> ....
> insmod: ERROR: could not insert module size.ko: Cannot allocate memory
> sh#
> 
> With this patch
> ===============
> sh# insmod size.ko
> ...
> sh# lsmod
> Module                  Size  Used by
> size                20972425  0

Could you please try enabling CONFIG_ARM_MODULE_PLTS instead of this 
patch?


Nicolas

^ permalink raw reply

* [PATCH] serial: mxs-auart: support CMSPAR termios cflag
From: Wolfgang Ocker @ 2016-12-06 15:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <546f7a46-df39-778f-e148-75862f426ff2@i2se.com>

On Tue, 2016-12-06 at 14:36 +0100, Stefan Wahren wrote:
> Hi Wolfgang,
> 
> > --- a/drivers/tty/serial/mxs-auart.c
> > +++ b/drivers/tty/serial/mxs-auart.c
> > @@ -95,6 +95,7 @@
> > ?#define AUART_LINECTRL_BAUD_DIVFRAC_SHIFT	8
> > ?#define AUART_LINECTRL_BAUD_DIVFRAC_MASK	0x00003f00
> > ?#define AUART_LINECTRL_BAUD_DIVFRAC(v)		(((v) & 0x3f) << 8)
> > +#define AUART_LINECTRL_SPS			(1 << 7)
> > ?#define AUART_LINECTRL_WLEN_MASK		0x00000060
> > ?#define AUART_LINECTRL_WLEN(v)			(((v) & 0x3) << 5)
> > ?#define AUART_LINECTRL_FEN			(1 << 4)
> > @@ -1010,10 +1011,12 @@ static void mxs_auart_settermios(struct uart_port
> > *u,
> > 	ctrl |= AUART_LINECTRL_WLEN(bm);
> > 
> > 	/* parity */
> > -	if (cflag & PARENB) {
> > +	if (cflag & (PARENB|CMSPAR)) {
> 
> does it make sense to enable stick parity in case parity is disabled?
> 
> The i.MX28 reference manual doesn't describe this case explicit.

Thanks Stefan for the hint. I think it's okay on the hardware side since the
PEN bit is always set and therefore it can not happen that SPS is set but not
PEN.

But on the termios side it makes sense to require PARENB to be set in c_cflag
if CMSPAR is requested.

So I will provide an updated patch soon.

Wolfgang

^ permalink raw reply

* [PATCH 2/2] ASoC: atmel: tse850: rely on the ssc to register as a cpu dai by itself
From: Rob Herring @ 2016-12-06 15:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1480593549-6464-3-git-send-email-peda@axentia.se>

On Thu, Dec 01, 2016 at 12:59:09PM +0100, Peter Rosin wrote:
> Signed-off-by: Peter Rosin <peda@axentia.se>
> ---
>  .../bindings/sound/axentia,tse850-pcm5142.txt      |  5 ++---
>  sound/soc/atmel/tse850-pcm5142.c                   | 23 +++-------------------
>  2 files changed, 5 insertions(+), 23 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/sound/axentia,tse850-pcm5142.txt b/Documentation/devicetree/bindings/sound/axentia,tse850-pcm5142.txt
> index 5b9b38f578bb..fd12ecb35b5c 100644
> --- a/Documentation/devicetree/bindings/sound/axentia,tse850-pcm5142.txt
> +++ b/Documentation/devicetree/bindings/sound/axentia,tse850-pcm5142.txt
> @@ -2,8 +2,7 @@ Devicetree bindings for the Axentia TSE-850 audio complex
>  
>  Required properties:
>    - compatible: "axentia,tse850-pcm5142"
> -  - axentia,ssc-controller: The phandle of the atmel SSC controller used as
> -    cpu dai.
> +  - axentia,cpu-dai: The phandle of the cpu dai.

You are breaking backwards compatibility with old DTBs. You either need 
to not do that or explain in the commit why that is okay.

Rob

^ permalink raw reply

* [RFC PATCH v3 2/2] drm/panel: Add support for Chunghwa CLAA070WP03XG panel
From: Thierry Reding @ 2016-12-06 15:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1474311771-23321-3-git-send-email-ayaka@soulik.info>

On Tue, Sep 20, 2016 at 03:02:51AM +0800, Randy Li wrote:
> The Chunghwa CLAA070WP03XG is a 7" 1280x800 panel, which can be
> supported by the simple panel driver.
> 
> Signed-off-by: Randy Li <ayaka@soulik.info>
> ---
>  .../display/panel/chunghwa,claa070wp03xg.txt       |  7 ++++++
>  drivers/gpu/drm/panel/panel-simple.c               | 27 ++++++++++++++++++++++
>  2 files changed, 34 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/display/panel/chunghwa,claa070wp03xg.txt

Applied, thanks.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161206/1e6499f1/attachment.sig>

^ permalink raw reply

* [PATCH v2] arm64: KVM: pmu: Reset PMSELR_EL0.SEL to a sane value before entering the guest
From: Marc Zyngier @ 2016-12-06 15:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161206152708.GL2498@arm.com>

On 06/12/16 15:27, Will Deacon wrote:
> On Tue, Dec 06, 2016 at 02:56:50PM +0000, Marc Zyngier wrote:
>> The ARMv8 architecture allows the cycle counter to be configured
>> by setting PMSELR_EL0.SEL==0x1f and then accessing PMXEVTYPER_EL0,
>> hence accessing PMCCFILTR_EL0. But it disallows the use of
>> PMSELR_EL0.SEL==0x1f to access the cycle counter itself through
>> PMXEVCNTR_EL0.
>>
>> Linux itself doesn't violate this rule, but we may end up with
>> PMSELR_EL0.SEL being set to 0x1f when we enter a guest. If that
>> guest accesses PMXEVCNTR_EL0, the access may UNDEF at EL1,
>> despite the guest not having done anything wrong.
>>
>> In order to avoid this unfortunate course of events (haha!), let's
>> sanitize PMSELR_EL0 on guest entry. This ensures that the guest
>> won't explode unexpectedly.
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>> This is another approach to fix this issue, this time nuking PMSELR_EL0
>> on guest entry instead of relying on perf not to clobber the register.
>>
>> Tested on v4.9-rc8 with a Rev A3 X-Gene.
>>
>>  arch/arm64/kvm/hyp/switch.c | 8 +++++++-
>>  1 file changed, 7 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
>> index 83037cd..3b7cfbd 100644
>> --- a/arch/arm64/kvm/hyp/switch.c
>> +++ b/arch/arm64/kvm/hyp/switch.c
>> @@ -85,7 +85,13 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
>>  	write_sysreg(val, hcr_el2);
>>  	/* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
>>  	write_sysreg(1 << 15, hstr_el2);
>> -	/* Make sure we trap PMU access from EL0 to EL2 */
>> +	/*
>> +	 * Make sure we trap PMU access from EL0 to EL2. Also sanitize
>> +	 * PMSELR_EL0 to make sure it never contains the cycle
>> +	 * counter, which could make a PMXEVCNTR_EL0 access UNDEF.
> 
> "UNDEF at EL1, as opposed to trapping to EL2" might be clearer, but up to
> you.

Sure, that's a useful clarification.

>> +	 */
>> +	if (vcpu->arch.mdcr_el2 & MDCR_EL2_HPMN_MASK)
>> +		write_sysreg(0, pmselr_el0);
>>  	write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0);
> 
> Curious, but why do you check MDCR.HPMN for PMSELR_EL0, but not for
> PMUSERENR_EL0?

Why would PMUSERENR_EL0 be constrained by the number of counters
available to the guest?

> 
> Anyway:
> 
> Acked-by: Will Deacon <will.deacon@arm.com>

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply

* [RFC PATCH] arm64: fpsimd: improve stacking logic in non-interruptible context
From: Ard Biesheuvel @ 2016-12-06 15:39 UTC (permalink / raw)
  To: linux-arm-kernel

Currently, we allow kernel mode NEON in softirq or hardirq context by
stacking and unstacking a slice of the NEON register file for each call
to kernel_neon_begin() and kernel_neon_end(), respectively.

Given that
a) a CPU typically spends most of its time in userland, during which time
   no kernel mode NEON in process context is in progress,
b) a CPU spends most of its time in the kernel doing other things than
   kernel mode NEON when it gets interrupted to perform kernel mode NEON
   in softirq context

the stacking and subsequent unstacking is only necessary if we are
interrupting a thread while it is performing kernel mode NEON in process
context, which means that in all other cases, we can simply preserve the
userland FPSIMD state once, and only restore it upon return to userland,
even if we are being invoked from softirq or hardirq context.

So instead of checking whether we are running in interrupt context, keep
track of the level of nested kernel mode NEON calls in progress, and only
perform the eager stack/unstack of the level exceeds 1.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 arch/arm64/kernel/fpsimd.c | 40 +++++++++++++++++++++++++++-------------
 1 file changed, 27 insertions(+), 13 deletions(-)

diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 394c61db5566..2614a216ac5d 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -220,20 +220,31 @@ void fpsimd_flush_task_state(struct task_struct *t)
 
 #ifdef CONFIG_KERNEL_MODE_NEON
 
-static DEFINE_PER_CPU(struct fpsimd_partial_state, hardirq_fpsimdstate);
-static DEFINE_PER_CPU(struct fpsimd_partial_state, softirq_fpsimdstate);
+/*
+ * Although unlikely, it is possible for three kernel mode NEON contexts to
+ * be live at the same time: process context, softirq context and hardirq
+ * context. So while the userland context is stashed in the thread's fpsimd
+ * state structure, we need two additional levels of storage.
+ */
+static DEFINE_PER_CPU(struct fpsimd_partial_state, nested_fpsimdstate[2]);
+static DEFINE_PER_CPU(int, kernel_neon_nesting_level);
 
 /*
  * Kernel-side NEON support functions
  */
 void kernel_neon_begin_partial(u32 num_regs)
 {
-	if (in_interrupt()) {
-		struct fpsimd_partial_state *s = this_cpu_ptr(
-			in_irq() ? &hardirq_fpsimdstate : &softirq_fpsimdstate);
+	struct fpsimd_partial_state *s;
+	int level;
+
+	preempt_disable();
+
+	level = this_cpu_read(kernel_neon_nesting_level);
+	if (level > 0) {
+		s = this_cpu_ptr(nested_fpsimdstate);
 
 		BUG_ON(num_regs > 32);
-		fpsimd_save_partial_state(s, roundup(num_regs, 2));
+		fpsimd_save_partial_state(&s[level - 1], roundup(num_regs, 2));
 	} else {
 		/*
 		 * Save the userland FPSIMD state if we have one and if we
@@ -241,24 +252,27 @@ void kernel_neon_begin_partial(u32 num_regs)
 		 * that there is no longer userland FPSIMD state in the
 		 * registers.
 		 */
-		preempt_disable();
 		if (current->mm &&
 		    !test_and_set_thread_flag(TIF_FOREIGN_FPSTATE))
 			fpsimd_save_state(&current->thread.fpsimd_state);
 		this_cpu_write(fpsimd_last_state, NULL);
 	}
+	this_cpu_write(kernel_neon_nesting_level, level + 1);
 }
 EXPORT_SYMBOL(kernel_neon_begin_partial);
 
 void kernel_neon_end(void)
 {
-	if (in_interrupt()) {
-		struct fpsimd_partial_state *s = this_cpu_ptr(
-			in_irq() ? &hardirq_fpsimdstate : &softirq_fpsimdstate);
-		fpsimd_load_partial_state(s);
-	} else {
-		preempt_enable();
+	struct fpsimd_partial_state *s;
+	int level;
+
+	level = this_cpu_read(kernel_neon_nesting_level);
+	if (level > 1) {
+		s = this_cpu_ptr(nested_fpsimdstate);
+		fpsimd_load_partial_state(&s[level - 2]);
 	}
+	this_cpu_write(kernel_neon_nesting_level, level - 1);
+	preempt_enable();
 }
 EXPORT_SYMBOL(kernel_neon_end);
 
-- 
2.7.4

^ permalink raw reply related

* [RFC PATCH 13/29] arm64/sve: Basic support for KERNEL_MODE_NEON
From: Ard Biesheuvel @ 2016-12-06 15:36 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161128122937.GI1574@e103592.cambridge.arm.com>

On 28 November 2016 at 12:29, Dave Martin <Dave.Martin@arm.com> wrote:
> On Mon, Nov 28, 2016 at 12:06:24PM +0000, Catalin Marinas wrote:
>> On Mon, Nov 28, 2016 at 11:47:26AM +0000, Dave P Martin wrote:
>> > On Sat, Nov 26, 2016 at 11:30:42AM +0000, Catalin Marinas wrote:
>> > > On Fri, Nov 25, 2016 at 08:45:02PM +0000, Ard Biesheuvel wrote:
>> > > > On 25 November 2016 at 19:39, Dave Martin <Dave.Martin@arm.com> wrote:
>> > > > > --- a/arch/arm64/kernel/fpsimd.c
>> > > > > +++ b/arch/arm64/kernel/fpsimd.c
>> > > > > @@ -282,11 +282,26 @@ static DEFINE_PER_CPU(struct fpsimd_partial_state, softirq_fpsimdstate);
>> > > > >   */
>> > > > >  void kernel_neon_begin_partial(u32 num_regs)
>> > > > >  {
>> > > > > +       preempt_disable();
>> > > > > +
>> > > > > +       /*
>> > > > > +        * For now, we have no special storage for SVE registers in
>> > > > > +        * interrupt context, so always save the userland SVE state
>> > > > > +        * if there is any, even for interrupts.
>> > > > > +        */
>> > > > > +       if (IS_ENABLED(CONFIG_ARM64_SVE) && (elf_hwcap & HWCAP_SVE) &&
>> > > > > +           current->mm &&
>> > > > > +           !test_and_set_thread_flag(TIF_FOREIGN_FPSTATE)) {
>> > > > > +               fpsimd_save_state(&current->thread.fpsimd_state);
>> > > > > +               this_cpu_write(fpsimd_last_state, NULL);
>> > > > > +       }
>> > > > > +
>> > > >
>> > > > I am having trouble understanding why we need all of this if we don't
>> > > > support SVE in the kernel. Could you elaborate?
>> > >
>> > > Dave knows all the details but a reason is that touching a Neon register
>> > > zeros the upper SVE state in the same vector register. So we can't
>> > > safely save/restore just the Neon part without corrupting the SVE state.
>> >
>> > This is right -- this also means that EFI services can trash the upper
>> > bits of an SVE vector register (as a side-effect of FPSIMD/NEON usage).
>> >
>> > It's overkill to save/restore absolutely everything -- I ignore num_regs
>> > for example -- but I wanted to keep things as simple as possible
>> > initially.
>>

Actually, I think we could simplify this even further by always
preserving the userland state, instead of having two copies of the
statements above. The reason is that stacking and unstacking, as we do
for softirq/hardirq context, is only required if we happen to be
interrupting a thread while it is executing in the kernel *and* using
the NEON, in all other cases we can simply preserve the userland
context, and let the exit code take care of restoring the state upon
exit to userland (unless we're interrupting kernel mode NEON executing
in softirq context from an interrupt handler).

i will send out a separate RFC with a proposal to optimize this, which
I think will remove the need for this patch entirely.

^ permalink raw reply

* Tearing down DMA transfer setup after DMA client has finished
From: Måns Rullgård @ 2016-12-06 15:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <5846D814.9010106@free.fr>

Mason <slash.tmp@free.fr> writes:

> On 06/12/2016 14:14, M?ns Rullg?rd wrote:
>
>> Mason wrote:
>> 
>>> On 06/12/2016 06:12, Vinod Koul wrote:
>>>
>>>> On Tue, Nov 29, 2016 at 07:25:02PM +0100, Mason wrote:
>>>>
>>>>> Is there a way to write a driver within the existing framework?
>>>>
>>>> I think so, looking back at comments from Russell, I do tend to agree with
>>>> that. Is there a specific reason why sbox can't be tied to alloc and free
>>>> channels?
>>>
>>> Here's a recap of the situation.
>>>
>>> The "SBOX+MBUS" HW is used in several iterations of the tango SoC:
>>>
>>> tango3
>>>   2 memory channels available
>>>   6 devices ("clients"?) may request an MBUS channel
>>>
>>> tango4 (one more channel)
>>>   3 memory channels available
>>>   7 devices may request an MBUS channel :
>>>     NFC0, NFC1, SATA0, SATA1, memcpy, (IDE0, IDE1)
>>>
>>> Notes:
>>> The current NFC driver supports only one controller.
>> 
>> I consider that a bug.
>
> Meh. The two controller blocks share the I/O pins to the outside
> world, so it's not possible to have two concurrent accesses.

OK, you failed to mention that part.  Why are there two controllers at
all if only one or the other can be used?

>>> If I understand the current DMA driver (written by Mans), client
>>> drivers are instructed to use a specific channel in the DT, and
>>> the DMA driver muxes access to that channel.
>> 
>> Almost.  The DT indicates the sbox ID of each device.  The driver
>> multiplexes requests from all devices across all channels.
>
> Thanks for pointing that out. I misremembered the DT.
> So a client's DT node specifies the client's SBOX port.
> And the DMA node specifies all available MBUS channels.
>
> So when an interrupt fires, the DMA driver (re)uses that
> channel for the next transfer in line?

Correct.

>>> The DMA driver manages a per-channel queue of outstanding DMA transfer
>>> requests, and a new transfer is started from within the DMA ISR
>>> (modulo the fact that the interrupt does not signal completion of the
>>> transfer, as explained else-thread).
>> 
>> We need to somehow let the device driver signal the dma driver when a
>> transfer has been fully completed.  Currently the only post-transfer
>> interaction between the dma engine and the device driver is through the
>> descriptor callback, which is not suitable for this purpose.
>
> The callback is called from vchan_complete() right?
> Is that running from interrupt context?

It runs from a tasklet which is almost the same thing.

> What's the relationship between vchan_complete() and
> tangox_dma_irq() -- does one call the other? Are they
> asynchronous?
>
>> This is starting to look like one of those situations where someone just
>> needs to implement a solution, or we'll be forever bickering about
>> hypotheticals.
>
> I can give that a shot (if you're busy with real work).

I have an idea I'd like to try out over the weekend.  If I don't come
back with something by next week, go for it.

>>> What you're proposing, Vinod, is to make a channel exclusive
>>> to a driver, as long as the driver has not explicitly released
>>> the channel, via dma_release_channel(), right?
>> 
>> That's not going to work very well.  Device drivers typically request
>> dma channels in their probe functions or when the device is opened.
>> This means that reserving one of the few channels there will inevitably
>> make some other device fail to operate.
>
> This is true for tango3. Less so for tango4. And no longer
> an issue for tango5.
>
>> Doing a request/release per transfer really doesn't fit with the
>> intended usage of the dmaengine api.  For starters, what should a driver
>> do if all the channels are currently busy?
>
> Why can't we queue channel requests the same way we queue
> transfer requests?

That's in effect what we're doing.  Calling it by another name doesn't
really solve anything.

-- 
M?ns Rullg?rd

^ permalink raw reply

* [PATCH v2] arm/arm64: xen: Move shared architecture headers to include/xen/arm
From: Marc Zyngier @ 2016-12-06 15:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1481038065-32153-3-git-send-email-marc.zyngier@arm.com>

On 06/12/16 15:27, Marc Zyngier wrote:
> ARM and arm64 Xen ports share a number of headers, leading to
> packaging issues when these headers needs to be exported, as it
> breaks the reasonable requirement that an architecture port
> has self-contained headers.
> 
> Fix the issue by moving the 5 header files to include/xen/arm,
> and keep local placeholders to include the relevant files.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
> * From v1:
>   - Move offending include files to include/xen/arm

Duh. Apologies for the spurious resend, I messed up.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply

* [PATCH v2 0/2] arm64: Fix fallout of asm/opcodes.h removal
From: Will Deacon @ 2016-12-06 15:30 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1481038065-32153-1-git-send-email-marc.zyngier@arm.com>

On Tue, Dec 06, 2016 at 03:27:42PM +0000, Marc Zyngier wrote:
> As part of the asm/opcodes.h removal, the SET_PSTATE_{PAN,UAO} macros
> have been switch to using the .inst directive instead of .long (as
> this has the advantage of providing a correct disassembly). This
> had the side effect of bringing back an ugly gas bug that shows up
> when .inst is used within alternative sequences.
> 
> This series works around the problem by:
> - adding detection code for the broken binutils,
> - work around the issue by falling back to .long when using a buggy
>   assembler.
> 
> This has been tested with both binutils 2.25 (broken) and 2.27
> (fixed), with both LE and BE builds.
> 
> Marc Zyngier (2):
>   arm64: Add detection code for broken .inst support in binutils
>   arm64: Work around broken .inst when defective gas is detected

For the two patches (not the bonus xen one!):

Acked-by: Will Deacon <will.deacon@arm.com>

Thanks for sticking with this...

Will

^ permalink raw reply

* [PATCH 1/1] arm64: Correcting format specifier for printing 64 bit addresses
From: Will Deacon @ 2016-12-06 15:28 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161206152637.GC16701@e104818-lin.cambridge.arm.com>

On Tue, Dec 06, 2016 at 03:26:37PM +0000, Catalin Marinas wrote:
> On Mon, Dec 05, 2016 at 11:24:21AM +0000, Will Deacon wrote:
> > On Mon, Dec 05, 2016 at 01:39:53PM +0530, Maninder Singh wrote:
> > > This patch corrects format specifier for printing 64 bit addresses.
> > > 
> > > Signed-off-by: Maninder Singh <maninder1.s@samsung.com>
> > > Signed-off-by: Vaneet Narang <v.narang@samsung.com>
> > > ---
> > >  arch/arm64/kernel/signal.c |  2 +-
> > >  arch/arm64/kvm/sys_regs.c  |  8 ++++++--
> > >  arch/arm64/mm/fault.c      | 15 ++++++++++-----
> > >  arch/arm64/mm/mmu.c        |  4 ++--
> > >  4 files changed, 19 insertions(+), 10 deletions(-)
> > 
> > Any reason not to fix kvm/trace.h too?
> 
> If the KVM guys are ok, I can fold the hunk below into this patch:
> 
> diff --git a/arch/arm64/kvm/trace.h b/arch/arm64/kvm/trace.h
> index 7fb0008c4fa3..e117123d414b 100644
> --- a/arch/arm64/kvm/trace.h
> +++ b/arch/arm64/kvm/trace.h
> @@ -20,7 +20,7 @@ TRACE_EVENT(kvm_wfx_arm64,
>  		__entry->is_wfe  = is_wfe;
>  	),
>  
> -	TP_printk("guest executed wf%c at: 0x%08lx",
> +	TP_printk("guest executed wf%c at: 0x%016lx",
>  		  __entry->is_wfe ? 'e' : 'i', __entry->vcpu_pc)
>  );
>  
> @@ -40,7 +40,7 @@ TRACE_EVENT(kvm_hvc_arm64,
>  		__entry->imm = imm;
>  	),
>  
> -	TP_printk("HVC at 0x%08lx (r0: 0x%08lx, imm: 0x%lx)",
> +	TP_printk("HVC at 0x%016lx (r0: 0x%016lx, imm: 0x%lx)",

Not sure we need the 016 prefix for r0.

Will

^ permalink raw reply

* [PATCH v2 2/2] arm64: Work around broken .inst when defective gas is detected
From: Marc Zyngier @ 2016-12-06 15:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1481038065-32153-1-git-send-email-marc.zyngier@arm.com>

.inst being largely broken with older binutils, it'd be better not
to emit it altogether when detecting such configuration (as it
leads to all kind of horrors when using alternatives).

Generalize the __emit_inst macro and use it extensively in
asm/sysreg.h, and make it generate a .long when a broken gas is
detected. The disassembly will be crap, but at least we can write
semi-sane code.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/sysreg.h | 29 +++++++++++++++++++++++++----
 1 file changed, 25 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 9e16a18..98ae03f 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -35,12 +35,33 @@
 #define sys_reg(op0, op1, crn, crm, op2) \
 	((((op0)&3)<<19)|((op1)<<16)|((crn)<<12)|((crm)<<8)|((op2)<<5))
 
+#ifndef CONFIG_BROKEN_GAS_INST
+
 #ifdef __ASSEMBLY__
 #define __emit_inst(x)			.inst (x)
 #else
 #define __emit_inst(x)			".inst " __stringify((x)) "\n\t"
 #endif
 
+#else  /* CONFIG_BROKEN_GAS_INST */
+
+#ifndef CONFIG_CPU_BIG_ENDIAN
+#define __INSTR_BSWAP(x)		(x)
+#else  /* CONFIG_CPU_BIG_ENDIAN */
+#define __INSTR_BSWAP(x)		((((x) << 24) & 0xff000000)	| \
+					 (((x) <<  8) & 0x00ff0000)	| \
+					 (((x) >>  8) & 0x0000ff00)	| \
+					 (((x) >> 24) & 0x000000ff))
+#endif	/* CONFIG_CPU_BIG_ENDIAN */
+
+#ifdef __ASSEMBLY__
+#define __emit_inst(x)			.long __INSTR_BSWAP(x)
+#else  /* __ASSEMBLY__ */
+#define __emit_inst(x)			".long " __stringify(__INSTR_BSWAP(x)) "\n\t"
+#endif	/* __ASSEMBLY__ */
+
+#endif	/* CONFIG_BROKEN_GAS_INST */
+
 #define SYS_MIDR_EL1			sys_reg(3, 0, 0, 0, 0)
 #define SYS_MPIDR_EL1			sys_reg(3, 0, 0, 0, 5)
 #define SYS_REVIDR_EL1			sys_reg(3, 0, 0, 0, 6)
@@ -232,11 +253,11 @@
 	.equ	.L__reg_num_xzr, 31
 
 	.macro	mrs_s, rt, sreg
-	.inst	0xd5200000|(\sreg)|(.L__reg_num_\rt)
+	 __emit_inst(0xd5200000|(\sreg)|(.L__reg_num_\rt))
 	.endm
 
 	.macro	msr_s, sreg, rt
-	.inst	0xd5000000|(\sreg)|(.L__reg_num_\rt)
+	__emit_inst(0xd5000000|(\sreg)|(.L__reg_num_\rt))
 	.endm
 
 #else
@@ -250,11 +271,11 @@ asm(
 "	.equ	.L__reg_num_xzr, 31\n"
 "\n"
 "	.macro	mrs_s, rt, sreg\n"
-"	.inst	0xd5200000|(\\sreg)|(.L__reg_num_\\rt)\n"
+	__emit_inst(0xd5200000|(\\sreg)|(.L__reg_num_\\rt))
 "	.endm\n"
 "\n"
 "	.macro	msr_s, sreg, rt\n"
-"	.inst	0xd5000000|(\\sreg)|(.L__reg_num_\\rt)\n"
+	__emit_inst(0xd5000000|(\\sreg)|(.L__reg_num_\\rt))
 "	.endm\n"
 );
 
-- 
2.1.4

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox