2015-12-15 21:43:10

by Yury Norov

[permalink] [raw]
Subject: [RFC3 PATCH v6 00/20] ILP32 for ARM64

This is still RFC because we have no glibc yet, that correspnds new ABI
introduced here. And so we cannot run tests. LP64 and AARCH32 tests show
no regression though.

v3: https://lkml.org/lkml/2014/9/3/704
v4: https://lkml.org/lkml/2015/4/13/691
v5: https://lkml.org/lkml/2015/9/29/911

v6:
- time_t, __kenel_off_t and other types turned to be 32-bit
for compatibility reasons (after v5 discussion);
- related changes applied to ILP32 syscall table and handlers;
- ILP32 VDSO code excluded. It's not mandatory, and caused questions
during review process. We definitely make sure we will follow up
with a VDSO later on because it is needed for performance reasons;
- fixed build issues with different combinations of AARCH32 / ILP32
enabling in config;
- ILP32 TLS bug fixed;
- entry32-common.S introduced to hold wrappers needed for both ILP32
and AARCH32_EL0;
- documentation updated according to latest changes;
- rebased to the current head;
- coding style re-checked;
- ILP32 syscall table turned around.

rfc3:
- all structures and system calls are just like AARCH32 ones now. with 2
exceptions: syscalls that take 64-bit parameter in 2 32-bit regosters
are replaced with LP64 version; struct rt_sigframe is constructed both
from LP64 and AARCH32 fields to be consistent with AARCH64 register set;
- documentation rewritten accordingly;
- common code for all 3 ABIs is moved to separated files for easy use,
new headers and objects are introduced, incl: is_compat.h, thread_bits.h,
signal_common.h, signal32_common.h.
- ILP32 VDSO code restored, Nathans comments are addressed;
- patch "arm64: ilp32: force IPC_64 in msgctl, shmctl, semctl" removed, as
Arnd suggested general solution for IPC_64 problem.


Andrew Pinski (9):
arm64: ensure the kernel is compiled for LP64
arm64: rename COMPAT to AARCH32_EL0 in Kconfig
arm64: change some CONFIG_COMPAT over to use CONFIG_AARCH32_EL0
instead
arm64:uapi: set __BITS_PER_LONG correctly for ILP32 and LP64
arm64:ilp32: share HWCAP between LP64 and ILP32
arm64:ilp32 use the native LP64 'start_thread' for ILP32 threads
arm64:ilp32: support core dump generation for ILP32
arm64:ilp32: add sys_ilp32.c and a separate table (in entry.S) to use
it
arm64:ilp32: add ARM64_ILP32 to Kconfig

Jan Dakinevich (1):
arm64: ilp32: share aarch32 syscall wrappers to ilp32

Philipp Tomsich (2):
arm64:ilp32: add vdso-ilp32 and use for signal return
arm64:ilp32: change COMPAT_ELF_PLATFORM to report a a subplatform for
ILP32

Yury Norov (8):
arm64: ilp32: add documentation on the ILP32 ABI for ARM64
thread: move thread bits accessors to separated file
arm64: introduce is_a32_task and is_a32_thread (for AArch32 compat)
arm64: ilp32: add is_ilp32_compat_{task,thread} and TIF_32BIT_AARCH64
arm64: signal: wrap struct ucontext, fp and lr with struct sigframe
arm64: signal: move ilp32 and lp64 common code to separated file
arm64: signal32: move ilp32 and aarch32 common code to separated file
arm64: ilp32: introduce ilp32-specific handlers for sigframe

Documentation/arm64/ilp32.txt | 17 +++
arch/arm64/Kconfig | 12 ++
arch/arm64/Makefile | 5 +
arch/arm64/include/asm/compat.h | 19 +--
arch/arm64/include/asm/elf.h | 118 +++++++++++++++--
arch/arm64/include/asm/fpsimd.h | 2 +-
arch/arm64/include/asm/hwcap.h | 12 +-
arch/arm64/include/asm/is_compat.h | 86 +++++++++++++
arch/arm64/include/asm/memory.h | 3 +-
arch/arm64/include/asm/processor.h | 16 ++-
arch/arm64/include/asm/ptrace.h | 2 +-
arch/arm64/include/asm/signal32.h | 6 +-
arch/arm64/include/asm/signal32_common.h | 30 +++++
arch/arm64/include/asm/signal_common.h | 39 ++++++
arch/arm64/include/asm/signal_ilp32.h | 38 ++++++
arch/arm64/include/asm/thread_info.h | 3 +-
arch/arm64/include/asm/unistd.h | 13 +-
arch/arm64/include/asm/vdso.h | 4 +
arch/arm64/include/uapi/asm/bitsperlong.h | 9 +-
arch/arm64/kernel/Makefile | 11 +-
arch/arm64/kernel/asm-offsets.c | 2 +-
arch/arm64/kernel/entry.S | 18 ++-
arch/arm64/kernel/entry32-common.S | 37 ++++++
arch/arm64/kernel/entry32.S | 29 -----
arch/arm64/kernel/entry_ilp32.S | 32 +++++
arch/arm64/kernel/head.S | 2 +-
arch/arm64/kernel/hw_breakpoint.c | 6 +-
arch/arm64/kernel/perf_regs.c | 2 +-
arch/arm64/kernel/process.c | 5 +-
arch/arm64/kernel/ptrace.c | 48 ++++---
arch/arm64/kernel/signal.c | 176 +++-----------------------
arch/arm64/kernel/signal32.c | 85 -------------
arch/arm64/kernel/signal32_common.c | 116 +++++++++++++++++
arch/arm64/kernel/signal_common.c | 174 +++++++++++++++++++++++++
arch/arm64/kernel/signal_ilp32.c | 126 ++++++++++++++++++
arch/arm64/kernel/sys_ilp32.c | 77 +++++++++++
arch/arm64/kernel/traps.c | 5 +-
arch/arm64/kernel/vdso-ilp32/.gitignore | 2 +
arch/arm64/kernel/vdso-ilp32/Makefile | 72 +++++++++++
arch/arm64/kernel/vdso-ilp32/vdso-ilp32.S | 33 +++++
arch/arm64/kernel/vdso-ilp32/vdso-ilp32.lds.S | 95 ++++++++++++++
arch/arm64/kernel/vdso.c | 65 ++++++++--
include/linux/thread_bits.h | 57 +++++++++
include/linux/thread_info.h | 44 +------
44 files changed, 1343 insertions(+), 410 deletions(-)
create mode 100644 Documentation/arm64/ilp32.txt
create mode 100644 arch/arm64/include/asm/is_compat.h
create mode 100644 arch/arm64/include/asm/signal32_common.h
create mode 100644 arch/arm64/include/asm/signal_common.h
create mode 100644 arch/arm64/include/asm/signal_ilp32.h
create mode 100644 arch/arm64/kernel/entry32-common.S
create mode 100644 arch/arm64/kernel/entry_ilp32.S
create mode 100644 arch/arm64/kernel/signal32_common.c
create mode 100644 arch/arm64/kernel/signal_common.c
create mode 100644 arch/arm64/kernel/signal_ilp32.c
create mode 100644 arch/arm64/kernel/sys_ilp32.c
create mode 100644 arch/arm64/kernel/vdso-ilp32/.gitignore
create mode 100644 arch/arm64/kernel/vdso-ilp32/Makefile
create mode 100644 arch/arm64/kernel/vdso-ilp32/vdso-ilp32.S
create mode 100644 arch/arm64/kernel/vdso-ilp32/vdso-ilp32.lds.S
create mode 100644 include/linux/thread_bits.h

--
2.5.0


2015-12-15 21:43:28

by Yury Norov

[permalink] [raw]
Subject: [PATCH v6 01/20] arm64: ilp32: add documentation on the ILP32 ABI for ARM64

Based on Andrew Pinski's patch-series.

Signed-off-by: Yury Norov <[email protected]>
---
Documentation/arm64/ilp32.txt | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
create mode 100644 Documentation/arm64/ilp32.txt

diff --git a/Documentation/arm64/ilp32.txt b/Documentation/arm64/ilp32.txt
new file mode 100644
index 0000000..ad3a48e
--- /dev/null
+++ b/Documentation/arm64/ilp32.txt
@@ -0,0 +1,17 @@
+ILP32 AARCH64 SYSCALL ABI
+=========================
+
+This document describes the ILP32 syscall ABI and where it differs
+from the generic compat linux syscall interface.
+
+Syscalls which normally would pass 64bit values as two arguments;
+now pass the 64bit value as one argument.
+
+struct rt_sigframe is redefined and contains struct compat_siginfo,
+as compat syscalls expects, and struct sigframe, taken from lp64 to
+handle AARCH64 register set.
+
+Syscalls openat and open_by_handle_at are as non-compat as, it's
+temporary solution. There is expected global refactoring for all
+platforms.
+
--
2.5.0

2015-12-15 21:43:42

by Yury Norov

[permalink] [raw]
Subject: [PATCH v6 02/20] arm64: ensure the kernel is compiled for LP64

From: Andrew Pinski <[email protected]>

The kernel needs to be compiled as a LP64 binary for ARM64, even when
using a compiler that defaults to code-generation for the ILP32 ABI.
Consequently, we need to explicitly pass '-mabi=lp64' (supported on
gcc-4.9 and newer).

Reviewed-by: David Daney <[email protected]>
Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
Signed-off-by: Yury Norov <[email protected]>
Signed-off-by: Andrew Pinski <[email protected]>
---
arch/arm64/Makefile | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
index d10b5d4..432b69a 100644
--- a/arch/arm64/Makefile
+++ b/arch/arm64/Makefile
@@ -29,14 +29,19 @@ endif
KBUILD_CFLAGS += -mgeneral-regs-only $(lseinstr)
KBUILD_AFLAGS += $(lseinstr)

+KBUILD_CFLAGS += $(call cc-option,-mabi=lp64)
+KBUILD_AFLAGS += $(call cc-option,-mabi=lp64)
+
ifeq ($(CONFIG_CPU_BIG_ENDIAN), y)
KBUILD_CPPFLAGS += -mbig-endian
AS += -EB
LD += -EB
+LDFLAGS += -maarch64linuxb
else
KBUILD_CPPFLAGS += -mlittle-endian
AS += -EL
LD += -EL
+LDFLAGS += -maarch64linux
endif

CHECKFLAGS += -D__aarch64__
--
2.5.0

2015-12-15 21:44:01

by Yury Norov

[permalink] [raw]
Subject: [PATCH v6 03/20] arm64: rename COMPAT to AARCH32_EL0 in Kconfig

From: Andrew Pinski <[email protected]>

Reviewed-by: David Daney <[email protected]>
Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
Signed-off-by: Yury Norov <[email protected]>
Signed-off-by: Andrew Pinski <[email protected]>
---
arch/arm64/Kconfig | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 07d1811..4753d435 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -679,6 +679,11 @@ menu "Userspace binary formats"
source "fs/Kconfig.binfmt"

config COMPAT
+ def_bool y
+ depends on AARCH32_EL0
+ select COMPAT_BINFMT_ELF
+
+config AARCH32_EL0
bool "Kernel support for 32-bit EL0"
depends on !ARM64_64K_PAGES || EXPERT
select COMPAT_BINFMT_ELF
--
2.5.0

2015-12-15 21:44:30

by Yury Norov

[permalink] [raw]
Subject: [PATCH v6 04/20] arm64: change some CONFIG_COMPAT over to use CONFIG_AARCH32_EL0 instead

From: Andrew Pinski <[email protected]>

Reviewed-by: David Daney <[email protected]>
Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
Signed-off-by: Yury Norov <[email protected]>
Signed-off-by: Andrew Pinski <[email protected]>
---
arch/arm64/include/asm/elf.h | 11 ++++++++---
arch/arm64/include/asm/fpsimd.h | 2 +-
arch/arm64/include/asm/processor.h | 4 ++--
arch/arm64/include/asm/ptrace.h | 2 +-
arch/arm64/include/asm/signal32.h | 6 ++++--
arch/arm64/include/asm/unistd.h | 7 +++++--
arch/arm64/kernel/Makefile | 2 +-
arch/arm64/kernel/asm-offsets.c | 2 +-
arch/arm64/kernel/entry.S | 6 +++---
arch/arm64/kernel/head.S | 2 +-
arch/arm64/kernel/ptrace.c | 27 ++++++++++++++++++++-------
arch/arm64/kernel/traps.c | 2 +-
arch/arm64/kernel/vdso.c | 4 ++--
13 files changed, 50 insertions(+), 27 deletions(-)

diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
index faad6df..d255764 100644
--- a/arch/arm64/include/asm/elf.h
+++ b/arch/arm64/include/asm/elf.h
@@ -166,14 +166,16 @@ extern int arch_setup_additional_pages(struct linux_binprm *bprm,

#define COMPAT_ELF_ET_DYN_BASE (2 * TASK_SIZE_32 / 3)

+#ifdef CONFIG_AARCH32_EL0
+
/* AArch32 registers. */
-#define COMPAT_ELF_NGREG 18
+#define COMPAT_A32_ELF_NGREG 18
typedef unsigned int compat_elf_greg_t;
-typedef compat_elf_greg_t compat_elf_gregset_t[COMPAT_ELF_NGREG];
+typedef compat_elf_greg_t compat_elf_gregset_t[COMPAT_A32_ELF_NGREG];

/* AArch32 EABI. */
#define EF_ARM_EABI_MASK 0xff000000
-#define compat_elf_check_arch(x) (((x)->e_machine == EM_ARM) && \
+#define compat_a32_elf_check_arch(x) (((x)->e_machine == EM_ARM) && \
((x)->e_flags & EF_ARM_EABI_MASK))

#define compat_start_thread compat_start_thread
@@ -183,6 +185,9 @@ extern int aarch32_setup_vectors_page(struct linux_binprm *bprm,
int uses_interp);
#define compat_arch_setup_additional_pages \
aarch32_setup_vectors_page
+#endif
+
+#define compat_elf_check_arch(x) compat_a32_elf_check_arch(x)

#endif /* CONFIG_COMPAT */

diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index 50f559f..63b19f1 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -52,7 +52,7 @@ struct fpsimd_partial_state {
};


-#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
+#if defined(__KERNEL__) && defined(CONFIG_AARCH32_EL0)
/* Masks for extracting the FPSR and FPCR from the FPSCR */
#define VFP_FPSCR_STAT_MASK 0xf800009f
#define VFP_FPSCR_CTRL_MASK 0x07f79f00
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index 98f3235..ff4abec 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -79,7 +79,7 @@ struct cpu_context {
struct thread_struct {
struct cpu_context cpu_context; /* cpu context */
unsigned long tp_value; /* TLS register */
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_AARCH32_EL0
unsigned long tp2_value;
#endif
struct fpsimd_state fpsimd_state;
@@ -88,7 +88,7 @@ struct thread_struct {
struct debug_info debug; /* debugging */
};

-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_AARCH32_EL0
#define task_user_tls(t) \
({ \
unsigned long *__tls; \
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
index 536274e..1059b3f 100644
--- a/arch/arm64/include/asm/ptrace.h
+++ b/arch/arm64/include/asm/ptrace.h
@@ -120,7 +120,7 @@ struct pt_regs {

#define arch_has_single_step() (1)

-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_AARCH32_EL0
#define compat_thumb_mode(regs) \
(((regs)->pstate & COMPAT_PSR_T_BIT))
#else
diff --git a/arch/arm64/include/asm/signal32.h b/arch/arm64/include/asm/signal32.h
index eeaa975..e68fcce 100644
--- a/arch/arm64/include/asm/signal32.h
+++ b/arch/arm64/include/asm/signal32.h
@@ -17,7 +17,9 @@
#define __ASM_SIGNAL32_H

#ifdef __KERNEL__
-#ifdef CONFIG_COMPAT
+
+#ifdef CONFIG_AARCH32_EL0
+
#include <linux/compat.h>

#define AARCH32_KERN_SIGRET_CODE_OFFSET 0x500
@@ -47,6 +49,6 @@ static inline int compat_setup_rt_frame(int usig, struct ksignal *ksig, sigset_t
static inline void compat_setup_restart_syscall(struct pt_regs *regs)
{
}
-#endif /* CONFIG_COMPAT */
+#endif /* CONFIG_AARCH32_EL0 */
#endif /* __KERNEL__ */
#endif /* __ASM_SIGNAL32_H */
diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h
index 41e58fe..e6216ef 100644
--- a/arch/arm64/include/asm/unistd.h
+++ b/arch/arm64/include/asm/unistd.h
@@ -13,9 +13,8 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_AARCH32_EL0
#define __ARCH_WANT_COMPAT_SYS_GETDENTS64
-#define __ARCH_WANT_COMPAT_STAT64
#define __ARCH_WANT_SYS_GETHOSTNAME
#define __ARCH_WANT_SYS_PAUSE
#define __ARCH_WANT_SYS_GETPGRP
@@ -26,7 +25,9 @@
#define __ARCH_WANT_COMPAT_SYS_SENDFILE
#define __ARCH_WANT_SYS_FORK
#define __ARCH_WANT_SYS_VFORK
+#endif

+#ifdef CONFIG_COMPAT
/*
* Compat syscall numbers used by the AArch64 kernel.
*/
@@ -44,6 +45,8 @@
#define __ARM_NR_compat_cacheflush (__ARM_NR_COMPAT_BASE+2)
#define __ARM_NR_compat_set_tls (__ARM_NR_COMPAT_BASE+5)

+#define __ARCH_WANT_COMPAT_STAT64
+
#define __NR_compat_syscalls 390
#endif

diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 22dc9bc..1470332 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -20,7 +20,7 @@ arm64-obj-y := debug-monitors.o entry.o irq.o fpsimd.o \
cpufeature.o alternative.o cacheinfo.o \
smp.o smp_spin_table.o topology.o

-arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \
+arm64-obj-$(CONFIG_AARCH32_EL0) += sys32.o kuser32.o signal32.o \
sys_compat.o entry32.o \
../../arm/kernel/opcodes.o
arm64-obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o
diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
index 8d89cf8..e3bcf77 100644
--- a/arch/arm64/kernel/asm-offsets.c
+++ b/arch/arm64/kernel/asm-offsets.c
@@ -51,7 +51,7 @@ int main(void)
DEFINE(S_X7, offsetof(struct pt_regs, regs[7]));
DEFINE(S_LR, offsetof(struct pt_regs, regs[30]));
DEFINE(S_SP, offsetof(struct pt_regs, sp));
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_AARCH32_EL0
DEFINE(S_COMPAT_SP, offsetof(struct pt_regs, compat_sp));
#endif
DEFINE(S_PSTATE, offsetof(struct pt_regs, pstate));
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 4306c93..52be5c8 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -212,7 +212,7 @@ ENTRY(vectors)
ventry el0_fiq_invalid // FIQ 64-bit EL0
ventry el0_error_invalid // Error 64-bit EL0

-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_AARCH32_EL0
ventry el0_sync_compat // Synchronous 32-bit EL0
ventry el0_irq_compat // IRQ 32-bit EL0
ventry el0_fiq_invalid_compat // FIQ 32-bit EL0
@@ -252,7 +252,7 @@ el0_error_invalid:
inv_entry 0, BAD_ERROR
ENDPROC(el0_error_invalid)

-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_AARCH32_EL0
el0_fiq_invalid_compat:
inv_entry 0, BAD_FIQ, 32
ENDPROC(el0_fiq_invalid_compat)
@@ -414,7 +414,7 @@ el0_sync:
b.ge el0_dbg
b el0_inv

-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_AARCH32_EL0
.align 6
el0_sync_compat:
kernel_entry 0, 32
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 90d09ed..d11d0b2 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -519,7 +519,7 @@ CPU_LE( movk x0, #0x30d0, lsl #16 ) // Clear EE and E0E on LE systems
mov x0, #0x33ff
msr cptr_el2, x0 // Disable copro. traps to EL2

-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_AARCH32_EL0
msr hstr_el2, xzr // Disable CP15 traps to EL2
#endif

diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 1971f49..2a39b5d 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -76,7 +76,7 @@ static void ptrace_hbptriggered(struct perf_event *bp,
.si_addr = (void __user *)(bkpt->trigger),
};

-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_AARCH32_EL0
int i;

if (!is_compat_task())
@@ -651,7 +651,7 @@ static const struct user_regset_view user_aarch64_view = {
.regsets = aarch64_regsets, .n = ARRAY_SIZE(aarch64_regsets)
};

-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_AARCH32_EL0
#include <linux/compat.h>

enum compat_regset {
@@ -853,7 +853,7 @@ static int compat_tls_set(struct task_struct *target,
static const struct user_regset aarch32_regsets[] = {
[REGSET_COMPAT_GPR] = {
.core_note_type = NT_PRSTATUS,
- .n = COMPAT_ELF_NGREG,
+ .n = COMPAT_A32_ELF_NGREG,
.size = sizeof(compat_elf_greg_t),
.align = sizeof(compat_elf_greg_t),
.get = compat_gpr_get,
@@ -877,7 +877,7 @@ static const struct user_regset_view user_aarch32_view = {
static const struct user_regset aarch32_ptrace_regsets[] = {
[REGSET_GPR] = {
.core_note_type = NT_PRSTATUS,
- .n = COMPAT_ELF_NGREG,
+ .n = COMPAT_A32_ELF_NGREG,
.size = sizeof(compat_elf_greg_t),
.align = sizeof(compat_elf_greg_t),
.get = compat_gpr_get,
@@ -1109,7 +1109,7 @@ static int compat_ptrace_sethbpregs(struct task_struct *tsk, compat_long_t num,
}
#endif /* CONFIG_HAVE_HW_BREAKPOINT */

-long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
+long compat_a32_arch_ptrace(struct task_struct *child, compat_long_t request,
compat_ulong_t caddr, compat_ulong_t cdata)
{
unsigned long addr = caddr;
@@ -1186,11 +1186,24 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,

return ret;
}
-#endif /* CONFIG_COMPAT */
+#else /* !CONFIG_AARCH32_EL0 */
+#define compat_a32_arch_ptrace(child, request, caddr, cdata) (-1)
+#endif /* !CONFIG_AARCH32_EL0 */
+
+#ifdef CONFIG_COMPAT
+long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
+ compat_ulong_t caddr, compat_ulong_t cdata)
+{
+ if (is_compat_task())
+ return compat_a32_arch_ptrace(child, request, caddr, cdata);
+ return compat_ptrace_request(child, request, caddr, cdata);
+}
+#endif
+

const struct user_regset_view *task_user_regset_view(struct task_struct *task)
{
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_AARCH32_EL0
/*
* Core dumping of 32-bit tasks or compat ptrace requests must use the
* user_aarch32_view compatible with arm32. Native ptrace requests on
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index f93aae5..9ce9894 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -363,7 +363,7 @@ long compat_arm_syscall(struct pt_regs *regs);

asmlinkage long do_ni_syscall(struct pt_regs *regs)
{
-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_AARCH32_EL0
long ret;
if (is_compat_task()) {
ret = compat_arm_syscall(regs);
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index 97bc68f..26352a6 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -49,7 +49,7 @@ static union {
} vdso_data_store __page_aligned_data;
struct vdso_data *vdso_data = &vdso_data_store.data;

-#ifdef CONFIG_COMPAT
+#ifdef CONFIG_AARCH32_EL0
/*
* Create and map the vectors page for AArch32 tasks.
*/
@@ -107,7 +107,7 @@ int aarch32_setup_vectors_page(struct linux_binprm *bprm, int uses_interp)

return PTR_ERR_OR_ZERO(ret);
}
-#endif /* CONFIG_COMPAT */
+#endif /* CONFIG_AARCH32_EL0 */

static struct vm_special_mapping vdso_spec[2];

--
2.5.0

2015-12-15 21:44:41

by Yury Norov

[permalink] [raw]
Subject: [PATCH v6 05/20] arm64:uapi: set __BITS_PER_LONG correctly for ILP32 and LP64

From: Andrew Pinski <[email protected]>

Define __BITS_PER_LONG depending on the ABI used (i.e. check whether
__ILP32__ or __LP64__ is defined). This is necessary for glibc to
determine the appropriate type definitions for the system call interface.

Reviewed-by: David Daney <[email protected]>
Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
Signed-off-by: Yury Norov <[email protected]>
Signed-off-by: Andrew Pinski <[email protected]>
---
arch/arm64/include/uapi/asm/bitsperlong.h | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/uapi/asm/bitsperlong.h b/arch/arm64/include/uapi/asm/bitsperlong.h
index fce9c29..4265243 100644
--- a/arch/arm64/include/uapi/asm/bitsperlong.h
+++ b/arch/arm64/include/uapi/asm/bitsperlong.h
@@ -16,7 +16,14 @@
#ifndef __ASM_BITSPERLONG_H
#define __ASM_BITSPERLONG_H

-#define __BITS_PER_LONG 64
+#if defined(__LP64__)
+/* Assuming __LP64__ will be defined for native ELF64's and not for ILP32. */
+# define __BITS_PER_LONG 64
+#elif defined(__ILP32__)
+# define __BITS_PER_LONG 32
+#else
+# error "Neither LP64 nor ILP32: unsupported ABI in asm/bitsperlong.h"
+#endif

#include <asm-generic/bitsperlong.h>

--
2.5.0

2015-12-15 21:45:07

by Yury Norov

[permalink] [raw]
Subject: [PATCH v6 06/20] thread: move thread bits accessors to separated file

They may be accessed from low-level code, so isolating is a measure to
avoid circular dependencies in header files.

The exact reason for circular dependency is WARN_ON() macro added by Al
Viro in patch "set_restore_sigmask() is never called without SIGPENDING
(and never should be)" [edd63a27]

Signed-off-by: Yury Norov <[email protected]>
---
include/linux/thread_bits.h | 57 +++++++++++++++++++++++++++++++++++++++++++++
include/linux/thread_info.h | 44 +---------------------------------
2 files changed, 58 insertions(+), 43 deletions(-)
create mode 100644 include/linux/thread_bits.h

diff --git a/include/linux/thread_bits.h b/include/linux/thread_bits.h
new file mode 100644
index 0000000..8d1e3be
--- /dev/null
+++ b/include/linux/thread_bits.h
@@ -0,0 +1,57 @@
+
+/* thread_bits.h: common low-level thread bits accessors */
+
+#ifndef _LINUX_THREAD_BITS_H
+#define _LINUX_THREAD_BITS_H
+
+#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
+
+#include <linux/bitops.h>
+#include <asm/thread_info.h>
+
+/*
+ * flag set/clear/test wrappers
+ * - pass TIF_xxxx constants to these functions
+ */
+
+static inline void set_ti_thread_flag(struct thread_info *ti, int flag)
+{
+ set_bit(flag, (unsigned long *)&ti->flags);
+}
+
+static inline void clear_ti_thread_flag(struct thread_info *ti, int flag)
+{
+ clear_bit(flag, (unsigned long *)&ti->flags);
+}
+
+static inline int test_and_set_ti_thread_flag(struct thread_info *ti, int flag)
+{
+ return test_and_set_bit(flag, (unsigned long *)&ti->flags);
+}
+
+static inline int test_and_clear_ti_thread_flag(struct thread_info *ti, int flag)
+{
+ return test_and_clear_bit(flag, (unsigned long *)&ti->flags);
+}
+
+static inline int test_ti_thread_flag(struct thread_info *ti, int flag)
+{
+ return test_bit(flag, (unsigned long *)&ti->flags);
+}
+
+#define set_thread_flag(flag) \
+ set_ti_thread_flag(current_thread_info(), flag)
+#define clear_thread_flag(flag) \
+ clear_ti_thread_flag(current_thread_info(), flag)
+#define test_and_set_thread_flag(flag) \
+ test_and_set_ti_thread_flag(current_thread_info(), flag)
+#define test_and_clear_thread_flag(flag) \
+ test_and_clear_ti_thread_flag(current_thread_info(), flag)
+#define test_thread_flag(flag) \
+ test_ti_thread_flag(current_thread_info(), flag)
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __KERNEL_ */
+#endif /* _LINUX_THREAD_BITS_H */
+
diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h
index ff307b5..c905fec 100644
--- a/include/linux/thread_info.h
+++ b/include/linux/thread_info.h
@@ -50,8 +50,7 @@ struct restart_block {

extern long do_no_restart_syscall(struct restart_block *parm);

-#include <linux/bitops.h>
-#include <asm/thread_info.h>
+#include <linux/thread_bits.h>

#ifdef __KERNEL__

@@ -61,47 +60,6 @@ extern long do_no_restart_syscall(struct restart_block *parm);
# define THREADINFO_GFP (GFP_KERNEL | __GFP_NOTRACK)
#endif

-/*
- * flag set/clear/test wrappers
- * - pass TIF_xxxx constants to these functions
- */
-
-static inline void set_ti_thread_flag(struct thread_info *ti, int flag)
-{
- set_bit(flag, (unsigned long *)&ti->flags);
-}
-
-static inline void clear_ti_thread_flag(struct thread_info *ti, int flag)
-{
- clear_bit(flag, (unsigned long *)&ti->flags);
-}
-
-static inline int test_and_set_ti_thread_flag(struct thread_info *ti, int flag)
-{
- return test_and_set_bit(flag, (unsigned long *)&ti->flags);
-}
-
-static inline int test_and_clear_ti_thread_flag(struct thread_info *ti, int flag)
-{
- return test_and_clear_bit(flag, (unsigned long *)&ti->flags);
-}
-
-static inline int test_ti_thread_flag(struct thread_info *ti, int flag)
-{
- return test_bit(flag, (unsigned long *)&ti->flags);
-}
-
-#define set_thread_flag(flag) \
- set_ti_thread_flag(current_thread_info(), flag)
-#define clear_thread_flag(flag) \
- clear_ti_thread_flag(current_thread_info(), flag)
-#define test_and_set_thread_flag(flag) \
- test_and_set_ti_thread_flag(current_thread_info(), flag)
-#define test_and_clear_thread_flag(flag) \
- test_and_clear_ti_thread_flag(current_thread_info(), flag)
-#define test_thread_flag(flag) \
- test_ti_thread_flag(current_thread_info(), flag)
-
#define tif_need_resched() test_thread_flag(TIF_NEED_RESCHED)

#if defined TIF_RESTORE_SIGMASK && !defined HAVE_SET_RESTORE_SIGMASK
--
2.5.0

2015-12-15 21:47:25

by Yury Norov

[permalink] [raw]
Subject: [PATCH v6 07/20] arm64: introduce is_a32_task and is_a32_thread (for AArch32 compat)

Based on patch of Andrew Pinski.

This patch introduces is_a32_compat_task and is_a32_thread so it is
easier to say this is a a32 specific thread or a generic compat thread/task.
Corresponding functions are located in <asm/is_compat.h> to avoid mess in
headers.

Some files invlude both <linux/compat.h> and <asm/compat.h>,
and this is wrong because <linux/compat.h> has <asm/compat.h> already
included. It was fixed too.

Reviewed-by: David Daney <[email protected]>
Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
Signed-off-by: Yury Norov <[email protected]>
Signed-off-by: Andrew Pinski <[email protected]>
---
arch/arm64/include/asm/compat.h | 19 ++---------
arch/arm64/include/asm/elf.h | 3 +-
arch/arm64/include/asm/is_compat.h | 62 ++++++++++++++++++++++++++++++++++++
arch/arm64/include/asm/memory.h | 3 +-
arch/arm64/include/asm/processor.h | 5 +--
arch/arm64/include/asm/thread_info.h | 2 +-
arch/arm64/kernel/hw_breakpoint.c | 6 ++--
arch/arm64/kernel/perf_regs.c | 2 +-
arch/arm64/kernel/process.c | 5 ++-
arch/arm64/kernel/ptrace.c | 11 +++----
arch/arm64/kernel/signal.c | 4 +--
arch/arm64/kernel/traps.c | 3 +-
12 files changed, 87 insertions(+), 38 deletions(-)
create mode 100644 arch/arm64/include/asm/is_compat.h

diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h
index 7fbed69..8e40dec 100644
--- a/arch/arm64/include/asm/compat.h
+++ b/arch/arm64/include/asm/compat.h
@@ -25,6 +25,8 @@
#include <linux/sched.h>
#include <linux/ptrace.h>

+#include <asm/is_compat.h>
+
#define COMPAT_USER_HZ 100
#ifdef __AARCH64EB__
#define COMPAT_UTS_MACHINE "armv8b\0\0"
@@ -299,23 +301,6 @@ struct compat_shmid64_ds {
compat_ulong_t __unused5;
};

-static inline int is_compat_task(void)
-{
- return test_thread_flag(TIF_32BIT);
-}
-
-static inline int is_compat_thread(struct thread_info *thread)
-{
- return test_ti_thread_flag(thread, TIF_32BIT);
-}
-
-#else /* !CONFIG_COMPAT */
-
-static inline int is_compat_thread(struct thread_info *thread)
-{
- return 0;
-}
-
#endif /* CONFIG_COMPAT */
#endif /* __KERNEL__ */
#endif /* __ASM_COMPAT_H */
diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
index d255764..8786ca5 100644
--- a/arch/arm64/include/asm/elf.h
+++ b/arch/arm64/include/asm/elf.h
@@ -16,6 +16,7 @@
#ifndef __ASM_ELF_H
#define __ASM_ELF_H

+#include <asm/is_compat.h>
#include <asm/hwcap.h>

/*
@@ -149,7 +150,7 @@ extern int arch_setup_additional_pages(struct linux_binprm *bprm,

/* 1GB of VA */
#ifdef CONFIG_COMPAT
-#define STACK_RND_MASK (test_thread_flag(TIF_32BIT) ? \
+#define STACK_RND_MASK (is_compat_task() ? \
0x7ff >> (PAGE_SHIFT - 12) : \
0x3ffff >> (PAGE_SHIFT - 12))
#else
diff --git a/arch/arm64/include/asm/is_compat.h b/arch/arm64/include/asm/is_compat.h
new file mode 100644
index 0000000..476db90
--- /dev/null
+++ b/arch/arm64/include/asm/is_compat.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 Cavium Inc.
+ *
+ * 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 __ASM_IS_COMPAT_H
+#define __ASM_IS_COMPAT_H
+#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
+
+#include <linux/thread_bits.h>
+
+#ifdef CONFIG_AARCH32_EL0
+
+static inline int is_a32_compat_task(void)
+{
+ return test_thread_flag(TIF_32BIT);
+}
+
+static inline int is_a32_compat_thread(struct thread_info *thread)
+{
+ return test_ti_thread_flag(thread, TIF_32BIT);
+}
+
+#else
+
+static inline int is_a32_compat_task(void)
+
+{
+ return 0;
+}
+
+static inline int is_a32_compat_thread(struct thread_info *thread)
+{
+ return 0;
+}
+
+#endif /* CONFIG_AARCH32_EL0 */
+
+#ifdef CONFIG_COMPAT
+
+static inline int is_compat_task(void)
+{
+ return is_a32_compat_task();
+}
+
+#endif /* CONFIG_COMPAT */
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __KERNEL__ */
+#endif /* __ASM_IS_COMPAT_H */
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index 6b4c3ad..ea4b10d 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -25,6 +25,7 @@
#include <linux/const.h>
#include <linux/types.h>
#include <asm/sizes.h>
+#include <asm/is_compat.h>

/*
* Allow for constants defined here to be used from assembly code
@@ -58,7 +59,7 @@

#ifdef CONFIG_COMPAT
#define TASK_SIZE_32 UL(0x100000000)
-#define TASK_SIZE (test_thread_flag(TIF_32BIT) ? \
+#define TASK_SIZE (is_compat_task() ? \
TASK_SIZE_32 : TASK_SIZE_64)
#define TASK_SIZE_OF(tsk) (test_tsk_thread_flag(tsk, TIF_32BIT) ? \
TASK_SIZE_32 : TASK_SIZE_64)
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index ff4abec..f1ba514 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -29,6 +29,7 @@

#include <linux/string.h>

+#include <asm/is_compat.h>
#include <asm/fpsimd.h>
#include <asm/hw_breakpoint.h>
#include <asm/pgtable-hwdef.h>
@@ -39,7 +40,7 @@
#define STACK_TOP_MAX TASK_SIZE_64
#ifdef CONFIG_COMPAT
#define AARCH32_VECTORS_BASE 0xffff0000
-#define STACK_TOP (test_thread_flag(TIF_32BIT) ? \
+#define STACK_TOP (is_compat_task() ? \
AARCH32_VECTORS_BASE : STACK_TOP_MAX)
#else
#define STACK_TOP STACK_TOP_MAX
@@ -92,7 +93,7 @@ struct thread_struct {
#define task_user_tls(t) \
({ \
unsigned long *__tls; \
- if (is_compat_thread(task_thread_info(t))) \
+ if (is_a32_compat_thread(task_thread_info(t))) \
__tls = &(t)->thread.tp2_value; \
else \
__tls = &(t)->thread.tp_value; \
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index dcd06d1..7d03565 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -110,7 +110,7 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_FREEZE 19
#define TIF_RESTORE_SIGMASK 20
#define TIF_SINGLESTEP 21
-#define TIF_32BIT 22 /* 32bit process */
+#define TIF_32BIT 22 /* AARCH32 process */
#define TIF_SWITCH_MM 23 /* deferred switch_mm */

#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c
index bba85c8..917f6e1 100644
--- a/arch/arm64/kernel/hw_breakpoint.c
+++ b/arch/arm64/kernel/hw_breakpoint.c
@@ -420,7 +420,7 @@ static int arch_build_bp_info(struct perf_event *bp)
* Watchpoints can be of length 1, 2, 4 or 8 bytes.
*/
if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) {
- if (is_compat_task()) {
+ if (is_a32_compat_task()) {
if (info->ctrl.len != ARM_BREAKPOINT_LEN_2 &&
info->ctrl.len != ARM_BREAKPOINT_LEN_4)
return -EINVAL;
@@ -477,7 +477,7 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
* AArch32 tasks expect some simple alignment fixups, so emulate
* that here.
*/
- if (is_compat_task()) {
+ if (is_a32_compat_task()) {
if (info->ctrl.len == ARM_BREAKPOINT_LEN_8)
alignment_mask = 0x7;
else
@@ -664,7 +664,7 @@ static int watchpoint_handler(unsigned long addr, unsigned int esr,

info = counter_arch_bp(wp);
/* AArch32 watchpoints are either 4 or 8 bytes aligned. */
- if (is_compat_task()) {
+ if (is_a32_compat_task()) {
if (info->ctrl.len == ARM_BREAKPOINT_LEN_8)
alignment_mask = 0x7;
else
diff --git a/arch/arm64/kernel/perf_regs.c b/arch/arm64/kernel/perf_regs.c
index 3f62b35..a79058f 100644
--- a/arch/arm64/kernel/perf_regs.c
+++ b/arch/arm64/kernel/perf_regs.c
@@ -45,7 +45,7 @@ int perf_reg_validate(u64 mask)

u64 perf_reg_abi(struct task_struct *task)
{
- if (is_compat_thread(task_thread_info(task)))
+ if (is_a32_compat_thread(task_thread_info(task)))
return PERF_SAMPLE_REGS_ABI_32;
else
return PERF_SAMPLE_REGS_ABI_64;
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index 223b093..e109f49 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -45,7 +45,6 @@
#include <linux/personality.h>
#include <linux/notifier.h>

-#include <asm/compat.h>
#include <asm/cacheflush.h>
#include <asm/fpsimd.h>
#include <asm/mmu_context.h>
@@ -259,7 +258,7 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
asm("mrs %0, tpidr_el0" : "=r" (*task_user_tls(p)));

if (stack_start) {
- if (is_compat_thread(task_thread_info(p)))
+ if (is_a32_compat_thread(task_thread_info(p)))
childregs->compat_sp = stack_start;
/* 16-byte aligned stack mandatory on AArch64 */
else if (stack_start & 15)
@@ -296,7 +295,7 @@ static void tls_thread_switch(struct task_struct *next)
*task_user_tls(current) = tpidr;

tpidr = *task_user_tls(next);
- tpidrro = is_compat_thread(task_thread_info(next)) ?
+ tpidrro = is_a32_compat_thread(task_thread_info(next)) ?
next->thread.tp_value : 0;

asm(
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 2a39b5d..816b432 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -38,7 +38,6 @@
#include <linux/tracehook.h>
#include <linux/elf.h>

-#include <asm/compat.h>
#include <asm/debug-monitors.h>
#include <asm/pgtable.h>
#include <asm/syscall.h>
@@ -79,7 +78,7 @@ static void ptrace_hbptriggered(struct perf_event *bp,
#ifdef CONFIG_AARCH32_EL0
int i;

- if (!is_compat_task())
+ if (!is_a32_compat_task())
goto send_sig;

for (i = 0; i < ARM_MAX_BRP; ++i) {
@@ -1194,7 +1193,7 @@ long compat_a32_arch_ptrace(struct task_struct *child, compat_long_t request,
long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
compat_ulong_t caddr, compat_ulong_t cdata)
{
- if (is_compat_task())
+ if (is_a32_compat_task())
return compat_a32_arch_ptrace(child, request, caddr, cdata);
return compat_ptrace_request(child, request, caddr, cdata);
}
@@ -1210,9 +1209,9 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task)
* 32-bit children use an extended user_aarch32_ptrace_view to allow
* access to the TLS register.
*/
- if (is_compat_task())
+ if (is_a32_compat_task())
return &user_aarch32_view;
- else if (is_compat_thread(task_thread_info(task)))
+ else if (is_a32_compat_thread(task_thread_info(task)))
return &user_aarch32_ptrace_view;
#endif
return &user_aarch64_view;
@@ -1239,7 +1238,7 @@ static void tracehook_report_syscall(struct pt_regs *regs,
* A scratch register (ip(r12) on AArch32, x7 on AArch64) is
* used to denote syscall entry/exit:
*/
- regno = (is_compat_task() ? 12 : 7);
+ regno = (is_a32_compat_task() ? 12 : 7);
saved_reg = regs->regs[regno];
regs->regs[regno] = dir;

diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index e18c48c..65baaef 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -276,7 +276,7 @@ static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,

static void setup_restart_syscall(struct pt_regs *regs)
{
- if (is_compat_task())
+ if (is_a32_compat_task())
compat_setup_restart_syscall(regs);
else
regs->regs[8] = __NR_restart_syscall;
@@ -295,7 +295,7 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
/*
* Set up the stack frame
*/
- if (is_compat_task()) {
+ if (is_a32_compat_task()) {
if (ksig->ka.sa.sa_flags & SA_SIGINFO)
ret = compat_setup_rt_frame(usig, ksig, oldset, regs);
else
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index 9ce9894..0afab39 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -18,6 +18,7 @@
*/

#include <linux/bug.h>
+#include <linux/compat.h>
#include <linux/signal.h>
#include <linux/personality.h>
#include <linux/kallsyms.h>
@@ -365,7 +366,7 @@ asmlinkage long do_ni_syscall(struct pt_regs *regs)
{
#ifdef CONFIG_AARCH32_EL0
long ret;
- if (is_compat_task()) {
+ if (is_a32_compat_task()) {
ret = compat_arm_syscall(regs);
if (ret != -ENOSYS)
return ret;
--
2.5.0

2015-12-15 21:48:05

by Yury Norov

[permalink] [raw]
Subject: [PATCH v6 08/20] arm64: ilp32: add is_ilp32_compat_{task,thread} and TIF_32BIT_AARCH64

Reviewed-by: David Daney <[email protected]>
Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
Signed-off-by: Yury Norov <[email protected]>
Signed-off-by: Andrew Pinski <[email protected]>
---
arch/arm64/include/asm/is_compat.h | 30 +++++++++++++++++++++++++++---
arch/arm64/include/asm/thread_info.h | 1 +
2 files changed, 28 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/include/asm/is_compat.h b/arch/arm64/include/asm/is_compat.h
index 476db90..89b1f65 100644
--- a/arch/arm64/include/asm/is_compat.h
+++ b/arch/arm64/include/asm/is_compat.h
@@ -36,7 +36,6 @@ static inline int is_a32_compat_thread(struct thread_info *thread)
#else

static inline int is_a32_compat_task(void)
-
{
return 0;
}
@@ -45,14 +44,39 @@ static inline int is_a32_compat_thread(struct thread_info *thread)
{
return 0;
}
-
#endif /* CONFIG_AARCH32_EL0 */

+#ifdef CONFIG_ARM64_ILP32
+
+static inline int is_ilp32_compat_task(void)
+{
+ return test_thread_flag(TIF_32BIT_AARCH64);
+}
+
+static inline int is_ilp32_compat_thread(struct thread_info *thread)
+{
+ return test_ti_thread_flag(thread, TIF_32BIT_AARCH64);
+}
+
+#else
+
+static inline int is_ilp32_compat_task(void)
+{
+ return 0;
+}
+
+static inline int is_ilp32_compat_thread(struct thread_info *thread)
+{
+ return 0;
+}
+
+#endif /* CONFIG_ARM64_ILP32 */
+
#ifdef CONFIG_COMPAT

static inline int is_compat_task(void)
{
- return is_a32_compat_task();
+ return is_a32_compat_task() || is_ilp32_compat_task();
}

#endif /* CONFIG_COMPAT */
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index 7d03565..e72de74 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -112,6 +112,7 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_SINGLESTEP 21
#define TIF_32BIT 22 /* AARCH32 process */
#define TIF_SWITCH_MM 23 /* deferred switch_mm */
+#define TIF_32BIT_AARCH64 24 /* 32 bit process on AArch64(ILP32) */

#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
--
2.5.0

2015-12-15 21:48:22

by Yury Norov

[permalink] [raw]
Subject: [PATCH v6 09/20] arm64:ilp32: share HWCAP between LP64 and ILP32

From: Andrew Pinski <[email protected]>

Reviewed-by: David Daney <[email protected]>
Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
Signed-off-by: Yury Norov <[email protected]>
Signed-off-by: Andrew Pinski <[email protected]>
---
arch/arm64/include/asm/hwcap.h | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h
index 0ad7351..1e5361e 100644
--- a/arch/arm64/include/asm/hwcap.h
+++ b/arch/arm64/include/asm/hwcap.h
@@ -47,9 +47,17 @@
#define ELF_HWCAP (elf_hwcap)

#ifdef CONFIG_COMPAT
-#define COMPAT_ELF_HWCAP (compat_elf_hwcap)
-#define COMPAT_ELF_HWCAP2 (compat_elf_hwcap2)
extern unsigned int compat_elf_hwcap, compat_elf_hwcap2;
+#define COMPAT_ELF_HWCAP \
+ (is_a32_compat_task() \
+ ? compat_elf_hwcap \
+ : elf_hwcap)
+
+#define COMPAT_ELF_HWCAP2 \
+ (is_a32_compat_task() \
+ ? compat_elf_hwcap2 \
+ : 0)
+
#endif

extern unsigned long elf_hwcap;
--
2.5.0

2015-12-15 21:48:34

by Yury Norov

[permalink] [raw]
Subject: [PATCH v6 10/20] arm64:ilp32 use the native LP64 'start_thread' for ILP32 threads

From: Andrew Pinski <[email protected]>

If we have both ILP32 and AARCH32 compiled in, we need use the non compat start
thread for ILP32.

Reviewed-by: David Daney <[email protected]>
Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
Signed-off-by: Yury Norov <[email protected]>
Signed-off-by: Andrew Pinski <[email protected]>
---
arch/arm64/include/asm/processor.h | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index f1ba514..e365280 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -124,6 +124,13 @@ static inline void start_thread(struct pt_regs *regs, unsigned long pc,
static inline void compat_start_thread(struct pt_regs *regs, unsigned long pc,
unsigned long sp)
{
+#ifdef CONFIG_ARM64_ILP32
+ /* ILP32 threads are started the same way as LP64 threads. */
+ if (is_ilp32_compat_task()) {
+ start_thread(regs, pc, sp);
+ return;
+ }
+#endif
start_thread_common(regs, pc);
regs->pstate = COMPAT_PSR_MODE_USR;
if (pc & 1)
--
2.5.0

2015-12-15 21:48:41

by Yury Norov

[permalink] [raw]
Subject: [PATCH v6 11/20] arm64:ilp32: support core dump generation for ILP32

From: Andrew Pinski <[email protected]>

This patch supports core dumping on ILP32.
We need a few extra macros (COMPAT_PR_REG_SIZE and COMPAT_PRSTATUS_SIZE) due
to size differences of the register sets.

Reviewed-by: David Daney <[email protected]>
Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
Signed-off-by: Yury Norov <[email protected]>
Signed-off-by: Andrew Pinski <[email protected]>
---
arch/arm64/include/asm/elf.h | 104 ++++++++++++++++++++++++++++++++++++++-----
arch/arm64/kernel/ptrace.c | 12 ++---
2 files changed, 100 insertions(+), 16 deletions(-)

diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
index 8786ca5..4e2e3c0 100644
--- a/arch/arm64/include/asm/elf.h
+++ b/arch/arm64/include/asm/elf.h
@@ -135,7 +135,11 @@ typedef struct user_fpsimd_state elf_fpregset_t;
*/
#define ELF_PLAT_INIT(_r, load_addr) (_r)->regs[0] = 0

-#define SET_PERSONALITY(ex) clear_thread_flag(TIF_32BIT);
+#define SET_PERSONALITY(ex) \
+do { \
+ clear_thread_flag(TIF_32BIT_AARCH64); \
+ clear_thread_flag(TIF_32BIT); \
+} while (0)

#define ARCH_DLINFO \
do { \
@@ -167,12 +171,15 @@ extern int arch_setup_additional_pages(struct linux_binprm *bprm,

#define COMPAT_ELF_ET_DYN_BASE (2 * TASK_SIZE_32 / 3)

+extern int aarch32_setup_vectors_page(struct linux_binprm *bprm,
+ int uses_interp);
+
#ifdef CONFIG_AARCH32_EL0

/* AArch32 registers. */
#define COMPAT_A32_ELF_NGREG 18
-typedef unsigned int compat_elf_greg_t;
-typedef compat_elf_greg_t compat_elf_gregset_t[COMPAT_A32_ELF_NGREG];
+typedef unsigned int compat_a32_elf_greg_t;
+typedef compat_a32_elf_greg_t compat_a32_elf_gregset_t[COMPAT_A32_ELF_NGREG];

/* AArch32 EABI. */
#define EF_ARM_EABI_MASK 0xff000000
@@ -180,15 +187,92 @@ typedef compat_elf_greg_t compat_elf_gregset_t[COMPAT_A32_ELF_NGREG];
((x)->e_flags & EF_ARM_EABI_MASK))

#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);
-#define compat_arch_setup_additional_pages \
- aarch32_setup_vectors_page
+#define COMPAT_A32_SET_PERSONALITY(ex) \
+do { \
+ clear_thread_flag(TIF_32BIT_AARCH64); \
+ set_thread_flag(TIF_32BIT); \
+} while (0)
+#define COMPAT_A32_ARCH_DLINFO do {} while (0)
+
+#else
+
+typedef elf_greg_t compat_elf_greg_t;
+typedef elf_gregset_t compat_elf_gregset_t;
+#define compat_a32_elf_check_arch(x) 0
+#define COMPAT_A32_SET_PERSONALITY(ex) do {} while (0)
+#define COMPAT_A32_ARCH_DLINFO do {} while (0)
+#endif
+
+/*
+ * If ILP32 is turned on, we want to define the compat_elf_greg_t to the non compat
+ * one and define PR_REG_SIZE/PRSTATUS_SIZE/SET_PR_FPVALID so we pick up the correct
+ * ones for AARCH32. Note also the definition of the macros have to be correct for
+ * LP64 as this file is included in the standard binfmt_elf.c.
+ */
+#ifdef CONFIG_ARM64_ILP32
+typedef elf_greg_t compat_elf_greg_t;
+typedef elf_gregset_t compat_elf_gregset_t;
+#ifdef CONFIG_AARCH32_EL0
+#define PR_REG_SIZE(S) (is_a32_compat_task() \
+ ? sizeof(compat_a32_elf_gregset_t) \
+ : sizeof(elf_gregset_t))
+#endif
+
+/*
+ * struct elf_prstatus is defined in include/uapi/linux/elfcore.h,
+ * and has different sise for supported ABIs
+ */
+#define PRSTATUS_SIZE(S) (is_a32_compat_task() ? 124 : (is_ilp32_compat_task() ? 352 : 392))
+
+#define SET_PR_FPVALID(S, V) \
+do { \
+ *(int *) (((void *) &((S)->pr_reg)) + PR_REG_SIZE((S)->pr_reg)) = (V); \
+} while (0)
+#else
+typedef compat_a32_elf_greg_t compat_elf_greg_t;
+typedef compat_a32_elf_gregset_t compat_elf_gregset_t;
+#endif
+
+#ifdef CONFIG_ARM64_ILP32
+#define compat_ilp32_elf_check_arch(x) ((x)->e_machine == EM_AARCH64)
+#define COMPAT_ILP32_SET_PERSONALITY(ex) \
+do { \
+ set_thread_flag(TIF_32BIT_AARCH64); \
+ clear_thread_flag(TIF_32BIT); \
+} while (0)
+#define COMPAT_ILP32_ARCH_DLINFO \
+do { \
+ NEW_AUX_ENT(AT_SYSINFO_EHDR, \
+ (elf_addr_t)(long)current->mm->context.vdso); \
+} while (0)
+#else
+#define compat_ilp32_elf_check_arch(x) 0
+#define COMPAT_ILP32_SET_PERSONALITY(ex) do {} while (0)
+#define COMPAT_ILP32_ARCH_DLINFO do {} while (0)
#endif

-#define compat_elf_check_arch(x) compat_a32_elf_check_arch(x)
+#define compat_elf_check_arch(x) (compat_a32_elf_check_arch(x) || compat_ilp32_elf_check_arch(x))
+#define COMPAT_SET_PERSONALITY(ex) \
+do { \
+ if (compat_a32_elf_check_arch(&ex)) \
+ COMPAT_A32_SET_PERSONALITY(ex); \
+ else \
+ COMPAT_ILP32_SET_PERSONALITY(ex); \
+} while (0)
+
+/* ILP32 uses the "LP64-like" vdso pages */
+#define compat_arch_setup_additional_pages \
+ (is_a32_compat_task() \
+ ? &aarch32_setup_vectors_page \
+ : &(arch_setup_additional_pages))
+
+#define COMPAT_ARCH_DLINFO \
+do { \
+ if (is_a32_compat_task()) \
+ COMPAT_A32_ARCH_DLINFO; \
+ else \
+ COMPAT_ILP32_ARCH_DLINFO; \
+} while (0)

#endif /* CONFIG_COMPAT */

diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 816b432..a9d07a9 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -853,8 +853,8 @@ static const struct user_regset aarch32_regsets[] = {
[REGSET_COMPAT_GPR] = {
.core_note_type = NT_PRSTATUS,
.n = COMPAT_A32_ELF_NGREG,
- .size = sizeof(compat_elf_greg_t),
- .align = sizeof(compat_elf_greg_t),
+ .size = sizeof(compat_a32_elf_greg_t),
+ .align = sizeof(compat_a32_elf_greg_t),
.get = compat_gpr_get,
.set = compat_gpr_set
},
@@ -945,7 +945,7 @@ static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off,
tmp = tsk->mm->start_data;
else if (off == COMPAT_PT_TEXT_END_ADDR)
tmp = tsk->mm->end_code;
- else if (off < sizeof(compat_elf_gregset_t))
+ else if (off < sizeof(compat_a32_elf_gregset_t))
return copy_regset_to_user(tsk, &user_aarch32_view,
REGSET_COMPAT_GPR, off,
sizeof(compat_ulong_t), ret);
@@ -966,7 +966,7 @@ static int compat_ptrace_write_user(struct task_struct *tsk, compat_ulong_t off,
if (off & 3 || off >= COMPAT_USER_SZ)
return -EIO;

- if (off >= sizeof(compat_elf_gregset_t))
+ if (off >= sizeof(compat_a32_elf_gregset_t))
return 0;

set_fs(KERNEL_DS);
@@ -1129,7 +1129,7 @@ long compat_a32_arch_ptrace(struct task_struct *child, compat_long_t request,
ret = copy_regset_to_user(child,
&user_aarch32_view,
REGSET_COMPAT_GPR,
- 0, sizeof(compat_elf_gregset_t),
+ 0, sizeof(compat_a32_elf_gregset_t),
datap);
break;

@@ -1137,7 +1137,7 @@ long compat_a32_arch_ptrace(struct task_struct *child, compat_long_t request,
ret = copy_regset_from_user(child,
&user_aarch32_view,
REGSET_COMPAT_GPR,
- 0, sizeof(compat_elf_gregset_t),
+ 0, sizeof(compat_a32_elf_gregset_t),
datap);
break;

--
2.5.0

2015-12-15 21:49:06

by Yury Norov

[permalink] [raw]
Subject: [PATCH v6 12/20] arm64:ilp32: add sys_ilp32.c and a separate table (in entry.S) to use it

From: Andrew Pinski <[email protected]>

Add a separate syscall-table for ILP32, which dispatches either to native
LP64 system call implementation or to compat-syscalls, as appropriate.

Reviewed-by: David Daney <[email protected]>
Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
Signed-off-by: Yury Norov <[email protected]>
Signed-off-by: Andrew Pinski <[email protected]>
---
arch/arm64/include/asm/unistd.h | 6 ++++
arch/arm64/kernel/Makefile | 1 +
arch/arm64/kernel/entry.S | 12 +++++++-
arch/arm64/kernel/sys_ilp32.c | 65 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 83 insertions(+), 1 deletion(-)
create mode 100644 arch/arm64/kernel/sys_ilp32.c

diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h
index e6216ef..230db54 100644
--- a/arch/arm64/include/asm/unistd.h
+++ b/arch/arm64/include/asm/unistd.h
@@ -13,6 +13,12 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
+#ifdef CONFIG_ARM64_ILP32
+#define __ARCH_WANT_COMPAT_SYS_PREADV64
+#define __ARCH_WANT_COMPAT_SYS_PWRITEV64
+#endif
+
#ifdef CONFIG_AARCH32_EL0
#define __ARCH_WANT_COMPAT_SYS_GETDENTS64
#define __ARCH_WANT_SYS_GETHOSTNAME
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 1470332..8787347 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -24,6 +24,7 @@ arm64-obj-$(CONFIG_AARCH32_EL0) += sys32.o kuser32.o signal32.o \
sys_compat.o entry32.o \
../../arm/kernel/opcodes.o
arm64-obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o
+arm64-obj-$(CONFIG_ARM64_ILP32) += sys_ilp32.o
arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o
arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o perf_callchain.o
arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 52be5c8..bcd921a 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -664,9 +664,13 @@ ENDPROC(ret_from_fork)
*/
.align 6
el0_svc:
- adrp stbl, sys_call_table // load syscall table pointer
uxtw scno, w8 // syscall number in w8
mov sc_nr, #__NR_syscalls
+#ifdef CONFIG_ARM64_ILP32
+ ldr x16, [tsk, #TI_FLAGS]
+ tbnz x16, #TIF_32BIT_AARCH64, el0_ilp32_svc // We are using ILP32
+#endif
+ adrp stbl, sys_call_table // load syscall table pointer
el0_svc_naked: // compat entry point
stp x0, scno, [sp, #S_ORIG_X0] // save the original x0 and syscall number
enable_dbg_and_irq
@@ -686,6 +690,12 @@ ni_sys:
b ret_fast_syscall
ENDPROC(el0_svc)

+#ifdef CONFIG_ARM64_ILP32
+el0_ilp32_svc:
+ adrp stbl, sys_call_ilp32_table // load syscall table pointer
+ b el0_svc_naked
+#endif
+
/*
* This is the really slow path. We're going to be doing context
* switches, and waiting for our parent to respond.
diff --git a/arch/arm64/kernel/sys_ilp32.c b/arch/arm64/kernel/sys_ilp32.c
new file mode 100644
index 0000000..8ce79db
--- /dev/null
+++ b/arch/arm64/kernel/sys_ilp32.c
@@ -0,0 +1,65 @@
+/*
+ * AArch64- ILP32 specific system calls implementation
+ *
+ * Copyright (C) 2015 Cavium Inc.
+ * Author: Andrew Pinski <[email protected]>
+ *
+ * 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/>.
+ */
+
+#include <linux/compiler.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/msg.h>
+#include <linux/export.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/syscalls.h>
+#include <linux/compat.h>
+
+/* Using non-compat syscalls where necessary */
+#define compat_sys_fadvise64_64 sys_fadvise64_64
+#define compat_sys_fallocate sys_fallocate
+#define compat_sys_ftruncate64 sys_ftruncate
+#define compat_sys_lookup_dcookie sys_lookup_dcookie
+#define compat_sys_pread64 sys_pread64
+#define compat_sys_pwrite64 sys_pwrite64
+#define compat_sys_readahead sys_readahead
+#define compat_sys_shmat sys_shmat
+#define compat_sys_sigaltstack sys_sigaltstack
+#define compat_sys_sync_file_range sys_sync_file_range
+#define compat_sys_truncate64 sys_truncate
+#define sys_llseek sys_lseek
+
+#define compat_sys_open_by_handle_at sys_open_by_handle_at
+#define compat_sys_openat sys_openat
+
+#include <asm/syscall.h>
+
+#undef __SYSCALL
+#undef __SC_COMP
+#undef __SC_3264
+#undef __SC_COMP_3264
+
+#define __SYSCALL_COMPAT
+#define __SYSCALL(nr, sym) [nr] = sym,
+
+/*
+ * The sys_call_ilp32_table array must be 4K aligned to be accessible from
+ * kernel/entry.S.
+ */
+void *sys_call_ilp32_table[__NR_syscalls] __aligned(4096) = {
+ [0 ... __NR_syscalls - 1] = sys_ni_syscall,
+#include <asm/unistd.h>
+};
--
2.5.0

2015-12-15 21:49:18

by Yury Norov

[permalink] [raw]
Subject: [PATCH v6 13/20] arm64: ilp32: share aarch32 syscall wrappers to ilp32

From: Jan Dakinevich <[email protected]>

statfs64, fstat64 and mmap_pgoff has wrappers that needed both by aarch32 and
ilp32 to workaround some issues. Here we create common file to share aarch32
workarounds to with ilp32 code.

Reviewed-by: David Daney <[email protected]>
Signed-off-by: Yury Norov <[email protected]>
Signed-off-by: Jan Dakinevich <[email protected]>
---
arch/arm64/kernel/Makefile | 1 +
arch/arm64/kernel/entry32-common.S | 37 +++++++++++++++++++++++++++++++++++++
arch/arm64/kernel/entry32.S | 29 -----------------------------
arch/arm64/kernel/sys_ilp32.c | 9 +++++++++
4 files changed, 47 insertions(+), 29 deletions(-)
create mode 100644 arch/arm64/kernel/entry32-common.S

diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 8787347..837d730 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -25,6 +25,7 @@ arm64-obj-$(CONFIG_AARCH32_EL0) += sys32.o kuser32.o signal32.o \
../../arm/kernel/opcodes.o
arm64-obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o
arm64-obj-$(CONFIG_ARM64_ILP32) += sys_ilp32.o
+arm64-obj-$(CONFIG_COMPAT) += entry32-common.o
arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o
arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o perf_callchain.o
arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
diff --git a/arch/arm64/kernel/entry32-common.S b/arch/arm64/kernel/entry32-common.S
new file mode 100644
index 0000000..2ad5912
--- /dev/null
+++ b/arch/arm64/kernel/entry32-common.S
@@ -0,0 +1,37 @@
+#include <linux/linkage.h>
+#include <linux/const.h>
+
+#include <asm/assembler.h>
+#include <asm/asm-offsets.h>
+#include <asm/errno.h>
+#include <asm/page.h>
+
+ENTRY(compat_sys_statfs64_wrapper)
+ mov w3, #84
+ cmp w1, #88
+ csel w1, w3, w1, eq
+ b compat_sys_statfs64
+ENDPROC(compat_sys_statfs64_wrapper)
+
+ENTRY(compat_sys_fstatfs64_wrapper)
+ mov w3, #84
+ cmp w1, #88
+ csel w1, w3, w1, eq
+ b compat_sys_fstatfs64
+ENDPROC(compat_sys_fstatfs64_wrapper)
+
+/*
+ * Note: off_4k (w5) is always in units of 4K. If we can't do the
+ * requested offset because it is not page-aligned, we return -EINVAL.
+ */
+ENTRY(compat_sys_mmap2_wrapper)
+#if PAGE_SHIFT > 12
+ tst w5, #~PAGE_MASK >> 12
+ b.ne 1f
+ lsr w5, w5, #PAGE_SHIFT - 12
+#endif
+ b sys_mmap_pgoff
+1: mov x0, #-EINVAL
+ ret
+ENDPROC(compat_sys_mmap2_wrapper)
+
diff --git a/arch/arm64/kernel/entry32.S b/arch/arm64/kernel/entry32.S
index f332d5d..8026129 100644
--- a/arch/arm64/kernel/entry32.S
+++ b/arch/arm64/kernel/entry32.S
@@ -40,35 +40,6 @@ ENTRY(compat_sys_rt_sigreturn_wrapper)
b compat_sys_rt_sigreturn
ENDPROC(compat_sys_rt_sigreturn_wrapper)

-ENTRY(compat_sys_statfs64_wrapper)
- mov w3, #84
- cmp w1, #88
- csel w1, w3, w1, eq
- b compat_sys_statfs64
-ENDPROC(compat_sys_statfs64_wrapper)
-
-ENTRY(compat_sys_fstatfs64_wrapper)
- mov w3, #84
- cmp w1, #88
- csel w1, w3, w1, eq
- b compat_sys_fstatfs64
-ENDPROC(compat_sys_fstatfs64_wrapper)
-
-/*
- * Note: off_4k (w5) is always in units of 4K. If we can't do the
- * requested offset because it is not page-aligned, we return -EINVAL.
- */
-ENTRY(compat_sys_mmap2_wrapper)
-#if PAGE_SHIFT > 12
- tst w5, #~PAGE_MASK >> 12
- b.ne 1f
- lsr w5, w5, #PAGE_SHIFT - 12
-#endif
- b sys_mmap_pgoff
-1: mov x0, #-EINVAL
- ret
-ENDPROC(compat_sys_mmap2_wrapper)
-
/*
* Wrappers for AArch32 syscalls that either take 64-bit parameters
* in registers or that take 32-bit parameters which require sign
diff --git a/arch/arm64/kernel/sys_ilp32.c b/arch/arm64/kernel/sys_ilp32.c
index 8ce79db..c282fa2 100644
--- a/arch/arm64/kernel/sys_ilp32.c
+++ b/arch/arm64/kernel/sys_ilp32.c
@@ -45,6 +45,15 @@
#define compat_sys_open_by_handle_at sys_open_by_handle_at
#define compat_sys_openat sys_openat

+asmlinkage long compat_sys_mmap2_wrapper(void);
+#define sys_mmap2 compat_sys_mmap2_wrapper
+
+asmlinkage long compat_sys_fstatfs64_wrapper(void);
+#define compat_sys_fstatfs64 compat_sys_fstatfs64_wrapper
+
+asmlinkage long compat_sys_statfs64_wrapper(void);
+#define compat_sys_statfs64 compat_sys_statfs64_wrapper
+
#include <asm/syscall.h>

#undef __SYSCALL
--
2.5.0

2015-12-15 21:49:40

by Yury Norov

[permalink] [raw]
Subject: [PATCH v6 14/20] arm64: signal: wrap struct ucontext, fp and lr with struct sigframe

It helps to move common code for lp64 and ilp32 to separated header.

Signed-off-by: Yury Norov <[email protected]>
---
arch/arm64/kernel/signal.c | 35 ++++++++++++++++++++---------------
1 file changed, 20 insertions(+), 15 deletions(-)

diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 65baaef..20dca65 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -35,14 +35,18 @@
#include <asm/signal32.h>
#include <asm/vdso.h>

+struct sigframe {
+ struct ucontext uc;
+ u64 fp;
+ u64 lr;
+};
+
/*
* Do a signal return; undo the signal stack. These are aligned to 128-bit.
*/
struct rt_sigframe {
struct siginfo info;
- struct ucontext uc;
- u64 fp;
- u64 lr;
+ struct sigframe sig;
};

static int preserve_fpsimd_context(struct fpsimd_context __user *ctx)
@@ -93,7 +97,7 @@ static int restore_fpsimd_context(struct fpsimd_context __user *ctx)
}

static int restore_sigframe(struct pt_regs *regs,
- struct rt_sigframe __user *sf)
+ struct sigframe __user *sf)
{
sigset_t set;
int i, err;
@@ -145,10 +149,10 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
if (!access_ok(VERIFY_READ, frame, sizeof (*frame)))
goto badframe;

- if (restore_sigframe(regs, frame))
+ if (restore_sigframe(regs, &frame->sig))
goto badframe;

- if (restore_altstack(&frame->uc.uc_stack))
+ if (restore_altstack(&frame->sig.uc.uc_stack))
goto badframe;

return regs->regs[0];
@@ -162,7 +166,7 @@ badframe:
return 0;
}

-static int setup_sigframe(struct rt_sigframe __user *sf,
+static int setup_sigframe(struct sigframe __user *sf,
struct pt_regs *regs, sigset_t *set)
{
int i, err = 0;
@@ -230,13 +234,13 @@ static struct rt_sigframe __user *get_sigframe(struct ksignal *ksig,
}

static void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
- void __user *frame, int usig)
+ void __user *frame, off_t sigframe_off, int usig)
{
__sigrestore_t sigtramp;

regs->regs[0] = usig;
regs->sp = (unsigned long)frame;
- regs->regs[29] = regs->sp + offsetof(struct rt_sigframe, fp);
+ regs->regs[29] = regs->sp + sigframe_off + offsetof(struct sigframe, fp);
regs->pc = (unsigned long)ka->sa.sa_handler;

if (ka->sa.sa_flags & SA_RESTORER)
@@ -257,17 +261,18 @@ static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
if (!frame)
return 1;

- __put_user_error(0, &frame->uc.uc_flags, err);
- __put_user_error(NULL, &frame->uc.uc_link, err);
+ __put_user_error(0, &frame->sig.uc.uc_flags, err);
+ __put_user_error(NULL, &frame->sig.uc.uc_link, err);

- err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
- err |= setup_sigframe(frame, regs, set);
+ err |= __save_altstack(&frame->sig.uc.uc_stack, regs->sp);
+ err |= setup_sigframe(&frame->sig, regs, set);
if (err == 0) {
- setup_return(regs, &ksig->ka, frame, usig);
+ setup_return(regs, &ksig->ka, frame,
+ offsetof(struct rt_sigframe, sig), usig);
if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
err |= copy_siginfo_to_user(&frame->info, &ksig->info);
regs->regs[1] = (unsigned long)&frame->info;
- regs->regs[2] = (unsigned long)&frame->uc;
+ regs->regs[2] = (unsigned long)&frame->sig.uc;
}
}

--
2.5.0

2015-12-15 21:49:52

by Yury Norov

[permalink] [raw]
Subject: [PATCH v6 15/20] arm64: signal: move ilp32 and lp64 common code to separated file

After that, it will be possible to reuse it in ILP32.

Signed-off-by: Yury Norov <[email protected]>
---
arch/arm64/include/asm/signal_common.h | 39 ++++++++
arch/arm64/kernel/Makefile | 2 +-
arch/arm64/kernel/signal.c | 154 +----------------------------
arch/arm64/kernel/signal_common.c | 174 +++++++++++++++++++++++++++++++++
4 files changed, 215 insertions(+), 154 deletions(-)
create mode 100644 arch/arm64/include/asm/signal_common.h
create mode 100644 arch/arm64/kernel/signal_common.c

diff --git a/arch/arm64/include/asm/signal_common.h b/arch/arm64/include/asm/signal_common.h
new file mode 100644
index 0000000..2fb3997
--- /dev/null
+++ b/arch/arm64/include/asm/signal_common.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 1995-2009 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ * Copyright (C) 2015 Cavium Networks.
+ *
+ * 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 __ASM_SIGNAL_COMMON_H
+#define __ASM_SIGNAL_COMMON_H
+
+#include <linux/uaccess.h>
+#include <asm/ucontext.h>
+#include <asm/fpsimd.h>
+
+struct sigframe {
+ struct ucontext uc;
+ u64 fp;
+ u64 lr;
+};
+
+int preserve_fpsimd_context(struct fpsimd_context __user *ctx);
+int restore_fpsimd_context(struct fpsimd_context __user *ctx);
+int setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set);
+int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf);
+void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
+ void __user *frame, off_t sigframe_off, int usig);
+
+#endif /* __ASM_SIGNAL_COMMON_H */
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 837d730..94b8b84 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -18,7 +18,7 @@ arm64-obj-y := debug-monitors.o entry.o irq.o fpsimd.o \
hyp-stub.o psci.o psci-call.o cpu_ops.o insn.o \
return_address.o cpuinfo.o cpu_errata.o \
cpufeature.o alternative.o cacheinfo.o \
- smp.o smp_spin_table.o topology.o
+ smp.o smp_spin_table.o topology.o signal_common.o

arm64-obj-$(CONFIG_AARCH32_EL0) += sys32.o kuser32.o signal32.o \
sys_compat.o entry32.o \
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 20dca65..4b8efe5 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -33,13 +33,7 @@
#include <asm/unistd.h>
#include <asm/fpsimd.h>
#include <asm/signal32.h>
-#include <asm/vdso.h>
-
-struct sigframe {
- struct ucontext uc;
- u64 fp;
- u64 lr;
-};
+#include <asm/signal_common.h>

/*
* Do a signal return; undo the signal stack. These are aligned to 128-bit.
@@ -49,87 +43,6 @@ struct rt_sigframe {
struct sigframe sig;
};

-static int preserve_fpsimd_context(struct fpsimd_context __user *ctx)
-{
- struct fpsimd_state *fpsimd = &current->thread.fpsimd_state;
- int err;
-
- /* dump the hardware registers to the fpsimd_state structure */
- fpsimd_preserve_current_state();
-
- /* copy the FP and status/control registers */
- err = __copy_to_user(ctx->vregs, fpsimd->vregs, sizeof(fpsimd->vregs));
- __put_user_error(fpsimd->fpsr, &ctx->fpsr, err);
- __put_user_error(fpsimd->fpcr, &ctx->fpcr, err);
-
- /* copy the magic/size information */
- __put_user_error(FPSIMD_MAGIC, &ctx->head.magic, err);
- __put_user_error(sizeof(struct fpsimd_context), &ctx->head.size, err);
-
- return err ? -EFAULT : 0;
-}
-
-static int restore_fpsimd_context(struct fpsimd_context __user *ctx)
-{
- struct fpsimd_state fpsimd;
- __u32 magic, size;
- int err = 0;
-
- /* check the magic/size information */
- __get_user_error(magic, &ctx->head.magic, err);
- __get_user_error(size, &ctx->head.size, err);
- if (err)
- return -EFAULT;
- if (magic != FPSIMD_MAGIC || size != sizeof(struct fpsimd_context))
- return -EINVAL;
-
- /* copy the FP and status/control registers */
- err = __copy_from_user(fpsimd.vregs, ctx->vregs,
- sizeof(fpsimd.vregs));
- __get_user_error(fpsimd.fpsr, &ctx->fpsr, err);
- __get_user_error(fpsimd.fpcr, &ctx->fpcr, err);
-
- /* load the hardware registers from the fpsimd_state structure */
- if (!err)
- fpsimd_update_current_state(&fpsimd);
-
- return err ? -EFAULT : 0;
-}
-
-static int restore_sigframe(struct pt_regs *regs,
- struct sigframe __user *sf)
-{
- sigset_t set;
- int i, err;
- void *aux = sf->uc.uc_mcontext.__reserved;
-
- err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set));
- if (err == 0)
- set_current_blocked(&set);
-
- for (i = 0; i < 31; i++)
- __get_user_error(regs->regs[i], &sf->uc.uc_mcontext.regs[i],
- err);
- __get_user_error(regs->sp, &sf->uc.uc_mcontext.sp, err);
- __get_user_error(regs->pc, &sf->uc.uc_mcontext.pc, err);
- __get_user_error(regs->pstate, &sf->uc.uc_mcontext.pstate, err);
-
- /*
- * Avoid sys_rt_sigreturn() restarting.
- */
- regs->syscallno = ~0UL;
-
- err |= !valid_user_regs(&regs->user_regs);
-
- if (err == 0) {
- struct fpsimd_context *fpsimd_ctx =
- container_of(aux, struct fpsimd_context, head);
- err |= restore_fpsimd_context(fpsimd_ctx);
- }
-
- return err;
-}
-
asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
@@ -166,53 +79,6 @@ badframe:
return 0;
}

-static int setup_sigframe(struct sigframe __user *sf,
- struct pt_regs *regs, sigset_t *set)
-{
- int i, err = 0;
- void *aux = sf->uc.uc_mcontext.__reserved;
- struct _aarch64_ctx *end;
-
- /* set up the stack frame for unwinding */
- __put_user_error(regs->regs[29], &sf->fp, err);
- __put_user_error(regs->regs[30], &sf->lr, err);
-
- for (i = 0; i < 31; i++)
- __put_user_error(regs->regs[i], &sf->uc.uc_mcontext.regs[i],
- err);
- __put_user_error(regs->sp, &sf->uc.uc_mcontext.sp, err);
- __put_user_error(regs->pc, &sf->uc.uc_mcontext.pc, err);
- __put_user_error(regs->pstate, &sf->uc.uc_mcontext.pstate, err);
-
- __put_user_error(current->thread.fault_address, &sf->uc.uc_mcontext.fault_address, err);
-
- err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set));
-
- if (err == 0) {
- struct fpsimd_context *fpsimd_ctx =
- container_of(aux, struct fpsimd_context, head);
- err |= preserve_fpsimd_context(fpsimd_ctx);
- aux += sizeof(*fpsimd_ctx);
- }
-
- /* fault information, if valid */
- if (current->thread.fault_code) {
- struct esr_context *esr_ctx =
- container_of(aux, struct esr_context, head);
- __put_user_error(ESR_MAGIC, &esr_ctx->head.magic, err);
- __put_user_error(sizeof(*esr_ctx), &esr_ctx->head.size, err);
- __put_user_error(current->thread.fault_code, &esr_ctx->esr, err);
- aux += sizeof(*esr_ctx);
- }
-
- /* set the "end" magic */
- end = aux;
- __put_user_error(0, &end->magic, err);
- __put_user_error(0, &end->size, err);
-
- return err;
-}
-
static struct rt_sigframe __user *get_sigframe(struct ksignal *ksig,
struct pt_regs *regs)
{
@@ -233,24 +99,6 @@ static struct rt_sigframe __user *get_sigframe(struct ksignal *ksig,
return frame;
}

-static void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
- void __user *frame, off_t sigframe_off, int usig)
-{
- __sigrestore_t sigtramp;
-
- regs->regs[0] = usig;
- regs->sp = (unsigned long)frame;
- regs->regs[29] = regs->sp + sigframe_off + offsetof(struct sigframe, fp);
- regs->pc = (unsigned long)ka->sa.sa_handler;
-
- if (ka->sa.sa_flags & SA_RESTORER)
- sigtramp = ka->sa.sa_restorer;
- else
- sigtramp = VDSO_SYMBOL(current->mm->context.vdso, sigtramp);
-
- regs->regs[30] = (unsigned long)sigtramp;
-}
-
static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
struct pt_regs *regs)
{
diff --git a/arch/arm64/kernel/signal_common.c b/arch/arm64/kernel/signal_common.c
new file mode 100644
index 0000000..7043e5c
--- /dev/null
+++ b/arch/arm64/kernel/signal_common.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 1995-2009 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ * Copyright (C) 2015 Cavium Networks.
+ *
+ * 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/>.
+ */
+
+#include <linux/uaccess.h>
+#include <asm/ucontext.h>
+#include <asm/fpsimd.h>
+#include <asm/vdso.h>
+#include <asm/signal_common.h>
+
+int preserve_fpsimd_context(struct fpsimd_context __user *ctx)
+{
+ struct fpsimd_state *fpsimd = &current->thread.fpsimd_state;
+ int err;
+
+ /* dump the hardware registers to the fpsimd_state structure */
+ fpsimd_preserve_current_state();
+
+ /* copy the FP and status/control registers */
+ err = __copy_to_user(ctx->vregs, fpsimd->vregs, sizeof(fpsimd->vregs));
+ __put_user_error(fpsimd->fpsr, &ctx->fpsr, err);
+ __put_user_error(fpsimd->fpcr, &ctx->fpcr, err);
+
+ /* copy the magic/size information */
+ __put_user_error(FPSIMD_MAGIC, &ctx->head.magic, err);
+ __put_user_error(sizeof(struct fpsimd_context), &ctx->head.size, err);
+
+ return err ? -EFAULT : 0;
+}
+
+int restore_fpsimd_context(struct fpsimd_context __user *ctx)
+{
+ struct fpsimd_state fpsimd;
+ __u32 magic, size;
+ int err = 0;
+
+ /* check the magic/size information */
+ __get_user_error(magic, &ctx->head.magic, err);
+ __get_user_error(size, &ctx->head.size, err);
+ if (err)
+ return -EFAULT;
+ if (magic != FPSIMD_MAGIC || size != sizeof(struct fpsimd_context))
+ return -EINVAL;
+
+ /* copy the FP and status/control registers */
+ err = __copy_from_user(fpsimd.vregs, ctx->vregs,
+ sizeof(fpsimd.vregs));
+ __get_user_error(fpsimd.fpsr, &ctx->fpsr, err);
+ __get_user_error(fpsimd.fpcr, &ctx->fpcr, err);
+
+ /* load the hardware registers from the fpsimd_state structure */
+ if (!err)
+ fpsimd_update_current_state(&fpsimd);
+
+ return err ? -EFAULT : 0;
+}
+
+int setup_sigframe(struct sigframe __user *sf,
+ struct pt_regs *regs, sigset_t *set)
+{
+ int i, err = 0;
+ void *aux = sf->uc.uc_mcontext.__reserved;
+ struct _aarch64_ctx *end;
+
+ /* set up the stack frame for unwinding */
+ __put_user_error(regs->regs[29], &sf->fp, err);
+ __put_user_error(regs->regs[30], &sf->lr, err);
+
+ for (i = 0; i < 31; i++)
+ __put_user_error(regs->regs[i], &sf->uc.uc_mcontext.regs[i],
+ err);
+ __put_user_error(regs->sp, &sf->uc.uc_mcontext.sp, err);
+ __put_user_error(regs->pc, &sf->uc.uc_mcontext.pc, err);
+ __put_user_error(regs->pstate, &sf->uc.uc_mcontext.pstate, err);
+
+ __put_user_error(current->thread.fault_address, &sf->uc.uc_mcontext.fault_address, err);
+
+ err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set));
+
+ if (err == 0) {
+ struct fpsimd_context *fpsimd_ctx =
+ container_of(aux, struct fpsimd_context, head);
+ err |= preserve_fpsimd_context(fpsimd_ctx);
+ aux += sizeof(*fpsimd_ctx);
+ }
+
+ /* fault information, if valid */
+ if (current->thread.fault_code) {
+ struct esr_context *esr_ctx =
+ container_of(aux, struct esr_context, head);
+ __put_user_error(ESR_MAGIC, &esr_ctx->head.magic, err);
+ __put_user_error(sizeof(*esr_ctx), &esr_ctx->head.size, err);
+ __put_user_error(current->thread.fault_code, &esr_ctx->esr, err);
+ aux += sizeof(*esr_ctx);
+ }
+
+ /* set the "end" magic */
+ end = aux;
+ __put_user_error(0, &end->magic, err);
+ __put_user_error(0, &end->size, err);
+
+ return err;
+}
+
+int restore_sigframe(struct pt_regs *regs,
+ struct sigframe __user *sf)
+{
+ sigset_t set;
+ int i, err;
+ void *aux = sf->uc.uc_mcontext.__reserved;
+
+ err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set));
+ if (err == 0)
+ set_current_blocked(&set);
+
+ for (i = 0; i < 31; i++)
+ __get_user_error(regs->regs[i], &sf->uc.uc_mcontext.regs[i],
+ err);
+ __get_user_error(regs->sp, &sf->uc.uc_mcontext.sp, err);
+ __get_user_error(regs->pc, &sf->uc.uc_mcontext.pc, err);
+ __get_user_error(regs->pstate, &sf->uc.uc_mcontext.pstate, err);
+
+ /*
+ * Avoid sys_rt_sigreturn() restarting.
+ */
+ regs->syscallno = ~0UL;
+
+ err |= !valid_user_regs(&regs->user_regs);
+
+ if (err == 0) {
+ struct fpsimd_context *fpsimd_ctx =
+ container_of(aux, struct fpsimd_context, head);
+ err |= restore_fpsimd_context(fpsimd_ctx);
+ }
+
+ return err;
+}
+
+void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
+ void __user *frame, off_t sigframe_off, int usig)
+{
+ __sigrestore_t sigtramp;
+
+ regs->regs[0] = usig;
+ regs->sp = (unsigned long)frame;
+ regs->regs[29] = regs->sp + sigframe_off + offsetof(struct sigframe, fp);
+ regs->pc = (unsigned long)ka->sa.sa_handler;
+
+ if (ka->sa.sa_flags & SA_RESTORER)
+ sigtramp = ka->sa.sa_restorer;
+#ifdef CONFIG_ARM64_ILP32
+ else if (is_ilp32_compat_task())
+ sigtramp = VDSO_SYMBOL(current->mm->context.vdso, sigtramp_ilp32);
+#endif
+ else
+ sigtramp = VDSO_SYMBOL(current->mm->context.vdso, sigtramp);
+
+ regs->regs[30] = (unsigned long)sigtramp;
+}
+
--
2.5.0

2015-12-15 21:51:06

by Yury Norov

[permalink] [raw]
Subject: [PATCH v6 16/20] arm64: signal32: move ilp32 and aarch32 common code to separated file

Signed-off-by: Yury Norov <[email protected]>
---
arch/arm64/include/asm/signal32_common.h | 30 ++++++++
arch/arm64/kernel/Makefile | 2 +-
arch/arm64/kernel/signal32.c | 85 ----------------------
arch/arm64/kernel/signal32_common.c | 116 +++++++++++++++++++++++++++++++
4 files changed, 147 insertions(+), 86 deletions(-)
create mode 100644 arch/arm64/include/asm/signal32_common.h
create mode 100644 arch/arm64/kernel/signal32_common.c

diff --git a/arch/arm64/include/asm/signal32_common.h b/arch/arm64/include/asm/signal32_common.h
new file mode 100644
index 0000000..37a3a3c
--- /dev/null
+++ b/arch/arm64/include/asm/signal32_common.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 Cavium Networks.
+ *
+ * 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 __ASM_SIGNAL32_COMMON_H
+#define __ASM_SIGNAL32_COMMON_H
+
+#ifdef __KERNEL__
+
+#ifdef CONFIG_COMPAT
+
+int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from);
+int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from);
+
+#endif /* CONFIG_COMPAT*/
+
+#endif /* __KERNEL__ */
+#endif /* __ASM_SIGNAL32_COMMON_H */
+
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 94b8b84..f90fb08 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -25,7 +25,7 @@ arm64-obj-$(CONFIG_AARCH32_EL0) += sys32.o kuser32.o signal32.o \
../../arm/kernel/opcodes.o
arm64-obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o
arm64-obj-$(CONFIG_ARM64_ILP32) += sys_ilp32.o
-arm64-obj-$(CONFIG_COMPAT) += entry32-common.o
+arm64-obj-$(CONFIG_COMPAT) += entry32-common.o signal32_common.o
arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o
arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o perf_callchain.o
arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c
index 71ef6dc..2a69815 100644
--- a/arch/arm64/kernel/signal32.c
+++ b/arch/arm64/kernel/signal32.c
@@ -125,91 +125,6 @@ static inline int get_sigset_t(sigset_t *set,
return 0;
}

-int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
-{
- int err;
-
- if (!access_ok(VERIFY_WRITE, to, sizeof(*to)))
- return -EFAULT;
-
- /* If you change siginfo_t structure, please be sure
- * this code is fixed accordingly.
- * It should never copy any pad contained in the structure
- * to avoid security leaks, but must copy the generic
- * 3 ints plus the relevant union member.
- * This routine must convert siginfo from 64bit to 32bit as well
- * at the same time.
- */
- err = __put_user(from->si_signo, &to->si_signo);
- err |= __put_user(from->si_errno, &to->si_errno);
- err |= __put_user((short)from->si_code, &to->si_code);
- if (from->si_code < 0)
- err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad,
- SI_PAD_SIZE);
- else switch (from->si_code & __SI_MASK) {
- case __SI_KILL:
- err |= __put_user(from->si_pid, &to->si_pid);
- err |= __put_user(from->si_uid, &to->si_uid);
- break;
- case __SI_TIMER:
- err |= __put_user(from->si_tid, &to->si_tid);
- err |= __put_user(from->si_overrun, &to->si_overrun);
- err |= __put_user(from->si_int, &to->si_int);
- break;
- case __SI_POLL:
- err |= __put_user(from->si_band, &to->si_band);
- err |= __put_user(from->si_fd, &to->si_fd);
- break;
- case __SI_FAULT:
- err |= __put_user((compat_uptr_t)(unsigned long)from->si_addr,
- &to->si_addr);
-#ifdef BUS_MCEERR_AO
- /*
- * Other callers might not initialize the si_lsb field,
- * so check explicitely for the right codes here.
- */
- if (from->si_signo == SIGBUS &&
- (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO))
- err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb);
-#endif
- break;
- case __SI_CHLD:
- err |= __put_user(from->si_pid, &to->si_pid);
- err |= __put_user(from->si_uid, &to->si_uid);
- err |= __put_user(from->si_status, &to->si_status);
- err |= __put_user(from->si_utime, &to->si_utime);
- err |= __put_user(from->si_stime, &to->si_stime);
- break;
- case __SI_RT: /* This is not generated by the kernel as of now. */
- case __SI_MESGQ: /* But this is */
- err |= __put_user(from->si_pid, &to->si_pid);
- err |= __put_user(from->si_uid, &to->si_uid);
- err |= __put_user(from->si_int, &to->si_int);
- break;
- case __SI_SYS:
- err |= __put_user((compat_uptr_t)(unsigned long)
- from->si_call_addr, &to->si_call_addr);
- err |= __put_user(from->si_syscall, &to->si_syscall);
- err |= __put_user(from->si_arch, &to->si_arch);
- break;
- default: /* this is just in case for now ... */
- err |= __put_user(from->si_pid, &to->si_pid);
- err |= __put_user(from->si_uid, &to->si_uid);
- break;
- }
- return err;
-}
-
-int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
-{
- if (copy_from_user(to, from, __ARCH_SI_PREAMBLE_SIZE) ||
- copy_from_user(to->_sifields._pad,
- from->_sifields._pad, SI_PAD_SIZE))
- return -EFAULT;
-
- return 0;
-}
-
/*
* VFP save/restore code.
*
diff --git a/arch/arm64/kernel/signal32_common.c b/arch/arm64/kernel/signal32_common.c
new file mode 100644
index 0000000..446c7c0
--- /dev/null
+++ b/arch/arm64/kernel/signal32_common.c
@@ -0,0 +1,116 @@
+/*
+ * Based on arch/arm/kernel/signal.c
+ *
+ * Copyright (C) 1995-2009 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ * Copyright (C) 2015 Cavium Metworks.
+ * Modified by Will Deacon <[email protected]>
+ *
+ * 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/>.
+ */
+
+#include <linux/compat.h>
+#include <linux/signal.h>
+#include <linux/ratelimit.h>
+
+#include <asm/esr.h>
+#include <asm/fpsimd.h>
+#include <asm/signal32_common.h>
+#include <asm/uaccess.h>
+#include <asm/unistd.h>
+
+int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
+{
+ int err;
+
+ if (!access_ok(VERIFY_WRITE, to, sizeof(*to)))
+ return -EFAULT;
+
+ /* If you change siginfo_t structure, please be sure
+ * this code is fixed accordingly.
+ * It should never copy any pad contained in the structure
+ * to avoid security leaks, but must copy the generic
+ * 3 ints plus the relevant union member.
+ * This routine must convert siginfo from 64bit to 32bit as well
+ * at the same time.
+ */
+ err = __put_user(from->si_signo, &to->si_signo);
+ err |= __put_user(from->si_errno, &to->si_errno);
+ err |= __put_user((short)from->si_code, &to->si_code);
+ if (from->si_code < 0)
+ err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad,
+ SI_PAD_SIZE);
+ else switch (from->si_code & __SI_MASK) {
+ case __SI_KILL:
+ err |= __put_user(from->si_pid, &to->si_pid);
+ err |= __put_user(from->si_uid, &to->si_uid);
+ break;
+ case __SI_TIMER:
+ err |= __put_user(from->si_tid, &to->si_tid);
+ err |= __put_user(from->si_overrun, &to->si_overrun);
+ err |= __put_user(from->si_int, &to->si_int);
+ break;
+ case __SI_POLL:
+ err |= __put_user(from->si_band, &to->si_band);
+ err |= __put_user(from->si_fd, &to->si_fd);
+ break;
+ case __SI_FAULT:
+ err |= __put_user((compat_uptr_t)(unsigned long)from->si_addr,
+ &to->si_addr);
+#ifdef BUS_MCEERR_AO
+ /*
+ * Other callers might not initialize the si_lsb field,
+ * so check explicitely for the right codes here.
+ */
+ if (from->si_signo == SIGBUS &&
+ (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO))
+ err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb);
+#endif
+ break;
+ case __SI_CHLD:
+ err |= __put_user(from->si_pid, &to->si_pid);
+ err |= __put_user(from->si_uid, &to->si_uid);
+ err |= __put_user(from->si_status, &to->si_status);
+ err |= __put_user(from->si_utime, &to->si_utime);
+ err |= __put_user(from->si_stime, &to->si_stime);
+ break;
+ case __SI_RT: /* This is not generated by the kernel as of now. */
+ case __SI_MESGQ: /* But this is */
+ err |= __put_user(from->si_pid, &to->si_pid);
+ err |= __put_user(from->si_uid, &to->si_uid);
+ err |= __put_user(from->si_int, &to->si_int);
+ break;
+ case __SI_SYS:
+ err |= __put_user((compat_uptr_t)(unsigned long)
+ from->si_call_addr, &to->si_call_addr);
+ err |= __put_user(from->si_syscall, &to->si_syscall);
+ err |= __put_user(from->si_arch, &to->si_arch);
+ break;
+ default: /* this is just in case for now ... */
+ err |= __put_user(from->si_pid, &to->si_pid);
+ err |= __put_user(from->si_uid, &to->si_uid);
+ break;
+ }
+ return err;
+}
+
+int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
+{
+ if (copy_from_user(to, from, __ARCH_SI_PREAMBLE_SIZE) ||
+ copy_from_user(to->_sifields._pad,
+ from->_sifields._pad, SI_PAD_SIZE))
+ return -EFAULT;
+
+ return 0;
+}
+
--
2.5.0

2015-12-15 21:51:18

by Yury Norov

[permalink] [raw]
Subject: [PATCH v6 17/20] arm64: ilp32: introduce ilp32-specific handlers for sigframe

ILP32 uses AARCH32 compat structures and syscall handlers for signals.
But ILP32 struct rt_sigframe differs from both LP64 and AARCH32. So some
specific mechanism is needed to take care of it.

Signed-off-by: Yury Norov <[email protected]>
---
arch/arm64/include/asm/signal_ilp32.h | 38 ++++++++++
arch/arm64/kernel/Makefile | 2 +-
arch/arm64/kernel/entry_ilp32.S | 32 +++++++++
arch/arm64/kernel/signal.c | 3 +
arch/arm64/kernel/signal_ilp32.c | 126 ++++++++++++++++++++++++++++++++++
arch/arm64/kernel/sys_ilp32.c | 3 +
6 files changed, 203 insertions(+), 1 deletion(-)
create mode 100644 arch/arm64/include/asm/signal_ilp32.h
create mode 100644 arch/arm64/kernel/entry_ilp32.S
create mode 100644 arch/arm64/kernel/signal_ilp32.c

diff --git a/arch/arm64/include/asm/signal_ilp32.h b/arch/arm64/include/asm/signal_ilp32.h
new file mode 100644
index 0000000..81e1909
--- /dev/null
+++ b/arch/arm64/include/asm/signal_ilp32.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 Cavium Networks.
+ *
+ * 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 __ASM_SIGNAL_ILP32_H
+#define __ASM_SIGNAL_ILP32_H
+
+#ifdef __KERNEL__
+#ifdef CONFIG_ARM64_ILP32
+
+#include <linux/compat.h>
+
+int ilp32_setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
+ struct pt_regs *regs);
+
+#else
+
+static inline int ilp32_setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
+ struct pt_regs *regs)
+{
+ return -ENOSYS;
+}
+
+#endif /* CONFIG_ARM64_ILP32 */
+
+#endif /* __KERNEL__ */
+#endif /* __ASM_SIGNAL_ILP32_H */
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index f90fb08..f92e707 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -24,7 +24,7 @@ arm64-obj-$(CONFIG_AARCH32_EL0) += sys32.o kuser32.o signal32.o \
sys_compat.o entry32.o \
../../arm/kernel/opcodes.o
arm64-obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o
-arm64-obj-$(CONFIG_ARM64_ILP32) += sys_ilp32.o
+arm64-obj-$(CONFIG_ARM64_ILP32) += signal_ilp32.o sys_ilp32.o entry_ilp32.o
arm64-obj-$(CONFIG_COMPAT) += entry32-common.o signal32_common.o
arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o
arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o perf_callchain.o
diff --git a/arch/arm64/kernel/entry_ilp32.S b/arch/arm64/kernel/entry_ilp32.S
new file mode 100644
index 0000000..424060f
--- /dev/null
+++ b/arch/arm64/kernel/entry_ilp32.S
@@ -0,0 +1,32 @@
+/*
+ * ILP32 system call wrappers
+ *
+ * Copyright (C) 2015 Cavium Networks.
+ * Author: Yury Norov <[email protected]>
+ *
+ * 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/>.
+ */
+
+#include <linux/linkage.h>
+#include <linux/const.h>
+
+#include <asm/assembler.h>
+#include <asm/asm-offsets.h>
+#include <asm/errno.h>
+#include <asm/page.h>
+
+ENTRY(ilp32_sys_rt_sigreturn_wrapper)
+ mov x0, sp
+ b ilp32_sys_rt_sigreturn
+ENDPROC(ilp32_sys_rt_sigreturn_wrapper)
+
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 4b8efe5..d67a9b8 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -34,6 +34,7 @@
#include <asm/fpsimd.h>
#include <asm/signal32.h>
#include <asm/signal_common.h>
+#include <asm/signal_ilp32.h>

/*
* Do a signal return; undo the signal stack. These are aligned to 128-bit.
@@ -153,6 +154,8 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
ret = compat_setup_rt_frame(usig, ksig, oldset, regs);
else
ret = compat_setup_frame(usig, ksig, oldset, regs);
+ } else if (is_ilp32_compat_task()) {
+ ret = ilp32_setup_rt_frame(usig, ksig, oldset, regs);
} else {
ret = setup_rt_frame(usig, ksig, oldset, regs);
}
diff --git a/arch/arm64/kernel/signal_ilp32.c b/arch/arm64/kernel/signal_ilp32.c
new file mode 100644
index 0000000..d38434b
--- /dev/null
+++ b/arch/arm64/kernel/signal_ilp32.c
@@ -0,0 +1,126 @@
+/*
+ * Based on arch/arm/kernel/signal.c
+ *
+ * Copyright (C) 2015 Cavium Networks.
+ * Yury Norov <[email protected]>
+ *
+ * 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/>.
+ */
+
+#include <linux/compat.h>
+#include <linux/signal.h>
+#include <linux/syscalls.h>
+#include <linux/ratelimit.h>
+
+#include <asm/esr.h>
+#include <asm/fpsimd.h>
+#include <asm/signal32_common.h>
+#include <asm/signal_common.h>
+#include <asm/uaccess.h>
+#include <asm/unistd.h>
+#include <asm/ucontext.h>
+
+struct ilp32_rt_sigframe {
+ struct compat_siginfo info;
+ struct sigframe sig;
+};
+
+asmlinkage int ilp32_sys_rt_sigreturn(struct pt_regs *regs)
+{
+ struct ilp32_rt_sigframe __user *frame;
+
+ /* Always make any pending restarted system calls return -EINTR */
+ current->restart_block.fn = do_no_restart_syscall;
+
+ /*
+ * Since we stacked the signal on a 64-bit boundary,
+ * then 'sp' should be word aligned here. If it's
+ * not, then the user is trying to mess with us.
+ */
+ if (regs->sp & 15)
+ goto badframe;
+
+ frame = (struct ilp32_rt_sigframe __user *)regs->sp;
+
+ if (!access_ok(VERIFY_READ, frame, sizeof (*frame)))
+ goto badframe;
+
+ if (restore_sigframe(regs, &frame->sig))
+ goto badframe;
+
+ if (restore_altstack(&frame->sig.uc.uc_stack))
+ goto badframe;
+
+ return regs->regs[0];
+
+badframe:
+ if (show_unhandled_signals)
+ pr_info_ratelimited("%s[%d]: bad frame in %s: pc=%08llx sp=%08llx\n",
+ current->comm, task_pid_nr(current), __func__,
+ regs->pc, regs->compat_sp);
+ force_sig(SIGSEGV, current);
+ return 0;
+}
+
+static struct ilp32_rt_sigframe __user *ilp32_get_sigframe(struct ksignal *ksig,
+ struct pt_regs *regs)
+{
+ unsigned long sp, sp_top;
+ struct ilp32_rt_sigframe __user *frame;
+
+ sp = sp_top = sigsp(regs->sp, ksig);
+
+ sp = (sp - sizeof(struct ilp32_rt_sigframe)) & ~15;
+ frame = (struct ilp32_rt_sigframe __user *)sp;
+
+ /*
+ * Check that we can actually write to the signal frame.
+ */
+ if (!access_ok(VERIFY_WRITE, frame, sp_top - sp))
+ frame = NULL;
+
+ return frame;
+}
+
+/*
+ * ILP32 signal handling routines called from signal.c
+ */
+int ilp32_setup_rt_frame(int usig, struct ksignal *ksig,
+ sigset_t *set, struct pt_regs *regs)
+{
+ struct ilp32_rt_sigframe __user *frame;
+ int err = 0;
+
+ frame = ilp32_get_sigframe(ksig, regs);
+
+ if (!frame)
+ return 1;
+
+ __put_user_error(0, &frame->sig.uc.uc_flags, err);
+ __put_user_error(NULL, &frame->sig.uc.uc_link, err);
+
+ err |= __save_altstack(&frame->sig.uc.uc_stack, regs->sp);
+ err |= setup_sigframe(&frame->sig, regs, set);
+ if (err == 0) {
+ setup_return(regs, &ksig->ka, frame,
+ offsetof(struct ilp32_rt_sigframe, sig), usig);
+ if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
+ err |= copy_siginfo_to_user32(&frame->info, &ksig->info);
+ regs->regs[1] = (unsigned long)&frame->info;
+ regs->regs[2] = (unsigned long)&frame->sig.uc;
+ }
+ }
+
+ return err;
+}
+
diff --git a/arch/arm64/kernel/sys_ilp32.c b/arch/arm64/kernel/sys_ilp32.c
index c282fa2..1882bb3 100644
--- a/arch/arm64/kernel/sys_ilp32.c
+++ b/arch/arm64/kernel/sys_ilp32.c
@@ -54,6 +54,9 @@ asmlinkage long compat_sys_fstatfs64_wrapper(void);
asmlinkage long compat_sys_statfs64_wrapper(void);
#define compat_sys_statfs64 compat_sys_statfs64_wrapper

+asmlinkage long ilp32_sys_rt_sigreturn_wrapper(void);
+#define compat_sys_rt_sigreturn ilp32_sys_rt_sigreturn_wrapper
+
#include <asm/syscall.h>

#undef __SYSCALL
--
2.5.0

2015-12-15 21:51:28

by Yury Norov

[permalink] [raw]
Subject: [PATCH v6 18/20] arm64:ilp32: add vdso-ilp32 and use for signal return

From: Philipp Tomsich <[email protected]>

ILP32 VDSO exports next symbols:
__kernel_rt_sigreturn;
__kernel_gettimeofday;
__kernel_clock_gettime;
__kernel_clock_getres;

What shared object to use, kernel selects depending on result of
is_ilp32_compat_task() in arch/arm64/kernel/vdso.c, so it substitutes
correct pages and spec.

Adjusted to move the move data page before code pages in sync with
commit 601255ae3c98fdeeee3a8bb4696425e4f868b4f1

Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
Signed-off-by: Yury Norov <[email protected]>
---
arch/arm64/include/asm/vdso.h | 4 ++
arch/arm64/kernel/Makefile | 5 ++
arch/arm64/kernel/vdso-ilp32/.gitignore | 2 +
arch/arm64/kernel/vdso-ilp32/Makefile | 72 ++++++++++++++++++++
arch/arm64/kernel/vdso-ilp32/vdso-ilp32.S | 33 ++++++++++
arch/arm64/kernel/vdso-ilp32/vdso-ilp32.lds.S | 95 +++++++++++++++++++++++++++
arch/arm64/kernel/vdso.c | 61 ++++++++++++++---
7 files changed, 262 insertions(+), 10 deletions(-)
create mode 100644 arch/arm64/kernel/vdso-ilp32/.gitignore
create mode 100644 arch/arm64/kernel/vdso-ilp32/Makefile
create mode 100644 arch/arm64/kernel/vdso-ilp32/vdso-ilp32.S
create mode 100644 arch/arm64/kernel/vdso-ilp32/vdso-ilp32.lds.S

diff --git a/arch/arm64/include/asm/vdso.h b/arch/arm64/include/asm/vdso.h
index 839ce00..84050c6 100644
--- a/arch/arm64/include/asm/vdso.h
+++ b/arch/arm64/include/asm/vdso.h
@@ -29,6 +29,10 @@

#include <generated/vdso-offsets.h>

+#ifdef CONFIG_ARM64_ILP32
+#include <generated/vdso-ilp32-offsets.h>
+#endif
+
#define VDSO_SYMBOL(base, name) \
({ \
(void *)(vdso_offset_##name - VDSO_LBASE + (unsigned long)(base)); \
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index f92e707..2ef91c2 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -40,6 +40,7 @@ arm64-obj-$(CONFIG_ARMV8_DEPRECATED) += armv8_deprecated.o
arm64-obj-$(CONFIG_ACPI) += acpi.o

obj-y += $(arm64-obj-y) vdso/
+obj-$(CONFIG_ARM64_ILP32) += vdso-ilp32/
obj-m += $(arm64-obj-m)
head-y := head.o
extra-y := $(head-y) vmlinux.lds
@@ -47,3 +48,7 @@ extra-y := $(head-y) vmlinux.lds
# vDSO - this must be built first to generate the symbol offsets
$(call objectify,$(arm64-obj-y)): $(obj)/vdso/vdso-offsets.h
$(obj)/vdso/vdso-offsets.h: $(obj)/vdso
+
+# vDSO - this must be built first to generate the symbol offsets
+$(call objectify,$(arm64-obj-y)): $(obj)/vdso-ilp32/vdso-ilp32-offsets.h
+$(obj)/vdso-ilp32/vdso-ilp32-offsets.h: $(obj)/vdso-ilp32
diff --git a/arch/arm64/kernel/vdso-ilp32/.gitignore b/arch/arm64/kernel/vdso-ilp32/.gitignore
new file mode 100644
index 0000000..61806c3
--- /dev/null
+++ b/arch/arm64/kernel/vdso-ilp32/.gitignore
@@ -0,0 +1,2 @@
+vdso-ilp32.lds
+vdso-ilp32-offsets.h
diff --git a/arch/arm64/kernel/vdso-ilp32/Makefile b/arch/arm64/kernel/vdso-ilp32/Makefile
new file mode 100644
index 0000000..c8f5472
--- /dev/null
+++ b/arch/arm64/kernel/vdso-ilp32/Makefile
@@ -0,0 +1,72 @@
+#
+# Building a vDSO image for AArch64.
+#
+# Author: Will Deacon <[email protected]>
+# Heavily based on the vDSO Makefiles for other archs.
+#
+
+obj-ilp32-vdso := gettimeofday-ilp32.o note-ilp32.o sigreturn-ilp32.o
+
+# Build rules
+targets := $(obj-ilp32-vdso) vdso-ilp32.so vdso-ilp32.so.dbg
+obj-ilp32-vdso := $(addprefix $(obj)/, $(obj-ilp32-vdso))
+
+ccflags-y := -shared -fno-common -fno-builtin
+ccflags-y += -nostdlib -Wl,-soname=linux-ilp32-vdso.so.1 \
+ $(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
+
+obj-y += vdso-ilp32.o
+extra-y += vdso-ilp32.lds vdso-ilp32-offsets.h
+CPPFLAGS_vdso-ilp32.lds += -P -C -U$(ARCH) -mabi=ilp32
+
+# Force dependency (incbin is bad)
+$(obj)/vdso-ilp32.o : $(obj)/vdso-ilp32.so
+
+# Link rule for the .so file, .lds has to be first
+$(obj)/vdso-ilp32.so.dbg: $(src)/vdso-ilp32.lds $(obj-ilp32-vdso)
+ $(call if_changed,vdso-ilp32ld)
+
+# Strip rule for the .so file
+$(obj)/%.so: OBJCOPYFLAGS := -S
+$(obj)/%.so: $(obj)/%.so.dbg FORCE
+ $(call if_changed,objcopy)
+
+# Generate VDSO offsets using helper script
+gen-vdsosym := $(srctree)/$(src)/../vdso/gen_vdso_offsets.sh
+quiet_cmd_vdsosym = VDSOSYM $@
+define cmd_vdsosym
+ $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@ && \
+ cp $@ include/generated/
+endef
+
+$(obj)/vdso-ilp32-offsets.h: $(obj)/vdso-ilp32.so.dbg FORCE
+ $(call if_changed,vdsosym)
+
+# Assembly rules for the .S files
+#$(obj-ilp32-vdso): %.o: $(src)/../vdso/$(subst -ilp32,,%.S)
+# $(call if_changed_dep,vdso-ilp32as)
+
+$(obj)/gettimeofday-ilp32.o: $(src)/../vdso/gettimeofday.S
+ $(call if_changed_dep,vdso-ilp32as)
+
+$(obj)/note-ilp32.o: $(src)/../vdso/note.S
+ $(call if_changed_dep,vdso-ilp32as)
+
+$(obj)/sigreturn-ilp32.o: $(src)/../vdso/sigreturn.S
+ $(call if_changed_dep,vdso-ilp32as)
+
+# Actual build commands
+quiet_cmd_vdso-ilp32ld = VDSOILP32L $@
+ cmd_vdso-ilp32ld = $(CC) $(c_flags) -mabi=ilp32 -Wl,-n -Wl,-T $^ -o $@
+quiet_cmd_vdso-ilp32as = VDSOILP32A $@
+ cmd_vdso-ilp32as = $(CC) $(a_flags) -mabi=ilp32 -c -o $@ $<
+
+# Install commands for the unstripped file
+quiet_cmd_vdso_install = INSTALL $@
+ cmd_vdso_install = cp $(obj)/[email protected] $(MODLIB)/vdso/$@
+
+vdso-ilp32.so: $(obj)/vdso-ilp32.so.dbg
+ @mkdir -p $(MODLIB)/vdso
+ $(call cmd,vdso_install)
+
+vdso_install: vdso-ilp32.so
diff --git a/arch/arm64/kernel/vdso-ilp32/vdso-ilp32.S b/arch/arm64/kernel/vdso-ilp32/vdso-ilp32.S
new file mode 100644
index 0000000..46ac072
--- /dev/null
+++ b/arch/arm64/kernel/vdso-ilp32/vdso-ilp32.S
@@ -0,0 +1,33 @@
+/*
+ * 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 <[email protected]>
+ */
+
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <linux/const.h>
+#include <asm/page.h>
+
+ __PAGE_ALIGNED_DATA
+
+ .globl vdso_ilp32_start, vdso_ilp32_end
+ .balign PAGE_SIZE
+vdso_ilp32_start:
+ .incbin "arch/arm64/kernel/vdso-ilp32/vdso-ilp32.so"
+ .balign PAGE_SIZE
+vdso_ilp32_end:
+
+ .previous
diff --git a/arch/arm64/kernel/vdso-ilp32/vdso-ilp32.lds.S b/arch/arm64/kernel/vdso-ilp32/vdso-ilp32.lds.S
new file mode 100644
index 0000000..ddc63fd
--- /dev/null
+++ b/arch/arm64/kernel/vdso-ilp32/vdso-ilp32.lds.S
@@ -0,0 +1,95 @@
+/*
+ * 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 <[email protected]>
+ * Heavily based on the vDSO linker scripts for other archs.
+ */
+
+#include <linux/const.h>
+#include <asm/page.h>
+#include <asm/vdso.h>
+
+SECTIONS
+{
+ PROVIDE(_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
+
+ . = ALIGN(16);
+
+ .text : { *(.text*) } :text =0xd503201f
+ PROVIDE (__etext = .);
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+
+ .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
+ .eh_frame : { KEEP (*(.eh_frame)) } :text
+
+ .dynamic : { *(.dynamic) } :text :dynamic
+
+ .rodata : { *(.rodata*) } :text
+
+ _end = .;
+ PROVIDE(end = .);
+
+ /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 */
+ eh_frame_hdr PT_GNU_EH_FRAME;
+}
+
+/*
+ * This controls what symbols we export from the DSO.
+ */
+VERSION
+{
+ LINUX_2.6 {
+ global:
+ __kernel_rt_sigreturn;
+ __kernel_gettimeofday;
+ __kernel_clock_gettime;
+ __kernel_clock_getres;
+ local: *;
+ };
+}
+
+/*
+ * Make the sigreturn code visible to the kernel.
+ */
+VDSO_sigtramp_ilp32 = __kernel_rt_sigreturn;
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index 26352a6..521a8e4 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -40,6 +40,12 @@ extern char vdso_start, vdso_end;
static unsigned long vdso_pages;
static struct page **vdso_pagelist;

+#ifdef CONFIG_ARM64_ILP32
+extern char vdso_ilp32_start, vdso_ilp32_end;
+static unsigned long vdso_ilp32_pages;
+static struct page **vdso_ilp32_pagelist;
+#endif
+
/*
* The vDSO data page.
*/
@@ -109,24 +115,29 @@ int aarch32_setup_vectors_page(struct linux_binprm *bprm, int uses_interp)
}
#endif /* CONFIG_AARCH32_EL0 */

-static struct vm_special_mapping vdso_spec[2];
-
-static int __init vdso_init(void)
+static int __init vdso_init_common(char *vdso_start, char *vdso_end,
+ unsigned long *vdso_pagesp,
+ struct page ***vdso_pagelistp,
+ struct vm_special_mapping* vdso_spec)
{
int i;
+ unsigned long vdso_pages;
+ struct page **vdso_pagelist;

- if (memcmp(&vdso_start, "\177ELF", 4)) {
+ if (memcmp(vdso_start, "\177ELF", 4)) {
pr_err("vDSO is not a valid ELF object!\n");
return -EINVAL;
}

- vdso_pages = (&vdso_end - &vdso_start) >> PAGE_SHIFT;
+ vdso_pages = (vdso_end - vdso_start) >> PAGE_SHIFT;
+ *vdso_pagesp = vdso_pages;
pr_info("vdso: %ld pages (%ld code @ %p, %ld data @ %p)\n",
- vdso_pages + 1, vdso_pages, &vdso_start, 1L, vdso_data);
+ 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);
+ *vdso_pagelistp = vdso_pagelist;
if (vdso_pagelist == NULL)
return -ENOMEM;

@@ -135,7 +146,7 @@ static int __init vdso_init(void)

/* Grab the vDSO code pages. */
for (i = 0; i < vdso_pages; i++)
- vdso_pagelist[i + 1] = virt_to_page(&vdso_start + i * PAGE_SIZE);
+ vdso_pagelist[i + 1] = virt_to_page(vdso_start + i * PAGE_SIZE);

/* Populate the special mapping structures */
vdso_spec[0] = (struct vm_special_mapping) {
@@ -150,16 +161,46 @@ static int __init vdso_init(void)

return 0;
}
+
+static struct vm_special_mapping vdso_spec[2];
+
+static int __init vdso_init(void)
+{
+ return vdso_init_common(&vdso_start, &vdso_end,
+ &vdso_pages, &vdso_pagelist,
+ vdso_spec);
+}
arch_initcall(vdso_init);

+#ifdef CONFIG_ARM64_ILP32
+static struct vm_special_mapping vdso_ilp32_spec[2];
+
+static int __init vdso_ilp32_init(void)
+{
+ return vdso_init_common(&vdso_ilp32_start, &vdso_ilp32_end,
+ &vdso_ilp32_pages, &vdso_ilp32_pagelist,
+ vdso_ilp32_spec);
+}
+arch_initcall(vdso_ilp32_init);
+#endif
+
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;
+ unsigned long pages = vdso_pages;
+ struct vm_special_mapping *spec = vdso_spec;
+
+#ifdef CONFIG_ARM64_ILP32
+ if (is_ilp32_compat_task()) {
+ pages = vdso_ilp32_pages;
+ spec = vdso_ilp32_spec;
+ }
+#endif

- vdso_text_len = vdso_pages << PAGE_SHIFT;
+ vdso_text_len = pages << PAGE_SHIFT;
/* Be sure to map the data page */
vdso_mapping_len = vdso_text_len + PAGE_SIZE;

@@ -171,7 +212,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
}
ret = _install_special_mapping(mm, vdso_base, PAGE_SIZE,
VM_READ|VM_MAYREAD,
- &vdso_spec[0]);
+ &spec[0]);
if (IS_ERR(ret))
goto up_fail;

@@ -180,7 +221,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
ret = _install_special_mapping(mm, vdso_base, vdso_text_len,
VM_READ|VM_EXEC|
VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
- &vdso_spec[1]);
+ &spec[1]);
if (IS_ERR(ret))
goto up_fail;

--
2.5.0

2015-12-15 21:51:38

by Yury Norov

[permalink] [raw]
Subject: [PATCH v6 19/20] arm64:ilp32: change COMPAT_ELF_PLATFORM to report a a subplatform for ILP32

From: Philipp Tomsich <[email protected]>

To make life for tools (such as gdb) easier when dealing with ILP32 processes,
we report a proper subarchitecture for ILP32 in the ELF auxiliary vectors.

Reviewed-by: David Daney <[email protected]>
Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
Signed-off-by: Yury Norov <[email protected]>
Signed-off-by: Andrew Pinski <[email protected]>
---
arch/arm64/include/asm/elf.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
index 4e2e3c0..1fc6b48 100644
--- a/arch/arm64/include/asm/elf.h
+++ b/arch/arm64/include/asm/elf.h
@@ -164,9 +164,9 @@ extern int arch_setup_additional_pages(struct linux_binprm *bprm,
#ifdef CONFIG_COMPAT

#ifdef __AARCH64EB__
-#define COMPAT_ELF_PLATFORM ("v8b")
+#define COMPAT_ELF_PLATFORM (is_ilp32_compat_task() ? "aarch64_be:ilp32" : "v8b")
#else
-#define COMPAT_ELF_PLATFORM ("v8l")
+#define COMPAT_ELF_PLATFORM (is_ilp32_compat_task() ? "aarch64:ilp32" : "v8l")
#endif

#define COMPAT_ELF_ET_DYN_BASE (2 * TASK_SIZE_32 / 3)
--
2.5.0

2015-12-15 21:51:56

by Yury Norov

[permalink] [raw]
Subject: [PATCH v6 20/20] arm64:ilp32: add ARM64_ILP32 to Kconfig

From: Andrew Pinski <[email protected]>

This patch adds the config option for ILP32.

Reviewed-by: David Daney <[email protected]>
Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
Signed-off-by: Yury Norov <[email protected]>
Signed-off-by: Andrew Pinski <[email protected]>
---
arch/arm64/Kconfig | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 4753d435..deec37a 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -680,7 +680,7 @@ source "fs/Kconfig.binfmt"

config COMPAT
def_bool y
- depends on AARCH32_EL0
+ depends on AARCH32_EL0 || ARM64_ILP32
select COMPAT_BINFMT_ELF

config AARCH32_EL0
@@ -702,6 +702,13 @@ config AARCH32_EL0

If you want to execute 32-bit userspace applications, say Y.

+config ARM64_ILP32
+ bool "Kernel support for ILP32"
+ help
+ This option enables support for AArch64 ILP32 user space. ILP32
+ is an ABI where long and pointers are 32bits but it uses the AARCH64
+ instruction set.
+
config SYSVIPC_COMPAT
def_bool y
depends on COMPAT && SYSVIPC
--
2.5.0

2015-12-16 15:51:16

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v6 10/20] arm64:ilp32 use the native LP64 'start_thread' for ILP32 threads

On Wednesday 16 December 2015 00:42:36 Yury Norov wrote:
> +#ifdef CONFIG_ARM64_ILP32
> + /* ILP32 threads are started the same way as LP64 threads. */
> + if (is_ilp32_compat_task()) {
> + start_thread(regs, pc, sp);
> + return;
> + }
> +#endif
>

Just a small style comment, but I think you can just leave out the #ifdef,
as is_ilp32_compat_task() will already return false if that is disabled.

Arnd

2015-12-16 15:55:44

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v6 09/20] arm64:ilp32: share HWCAP between LP64 and ILP32

On Wednesday 16 December 2015 00:42:35 Yury Norov wrote:
>
> #ifdef CONFIG_COMPAT
> -#define COMPAT_ELF_HWCAP (compat_elf_hwcap)
> -#define COMPAT_ELF_HWCAP2 (compat_elf_hwcap2)
> extern unsigned int compat_elf_hwcap, compat_elf_hwcap2;
> +#define COMPAT_ELF_HWCAP \
> + (is_a32_compat_task() \
> + ? compat_elf_hwcap \
> + : elf_hwcap)
> +
> +#define COMPAT_ELF_HWCAP2 \
> + (is_a32_compat_task() \
> + ? compat_elf_hwcap2 \
> + : 0)
> +
> #endif
>
>

I'm trying to understand how this is used. Are you compiling
fs/compat_binfmt_elf.c twice to handle both 32-bit ELF types?

Would it be easier to use a separate arch/arm64/kernel/binfmt_elf32.c
as a copy of fs/compat_binfmt_elf.c, with all the right macros defined
for ilp32 mode in there?

Arnd

2015-12-16 16:08:17

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v6 12/20] arm64:ilp32: add sys_ilp32.c and a separate table (in entry.S) to use it

On Wednesday 16 December 2015 00:42:38 Yury Norov wrote:
> +/* Using non-compat syscalls where necessary */
> +#define compat_sys_fadvise64_64 sys_fadvise64_64
> +#define compat_sys_fallocate sys_fallocate
> +#define compat_sys_ftruncate64 sys_ftruncate
> +#define compat_sys_lookup_dcookie sys_lookup_dcookie
> +#define compat_sys_pread64 sys_pread64
> +#define compat_sys_pwrite64 sys_pwrite64
> +#define compat_sys_readahead sys_readahead
> +#define compat_sys_shmat sys_shmat
> +#define compat_sys_sigaltstack sys_sigaltstack
> +#define compat_sys_sync_file_range sys_sync_file_range
> +#define compat_sys_truncate64 sys_truncate
> +#define sys_llseek sys_lseek
> +
> +#define compat_sys_open_by_handle_at sys_open_by_handle_at
> +#define compat_sys_openat sys_openat

Very nice and short list now!

I've double-checked all calls and the only one I'm not sure about is
sys_sigaltstack. Did we discuss that one earlier?
My first guess would be that it's easier to use the compat
version of that.

I would probably also group sys_shmat with sys_openat, because it's
different from the other ones in the first block as this is not
about passing 64-bit arguments as registers, but instead it's about
the behavior of the system call.

Arnd

2015-12-16 16:09:27

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v6 15/20] arm64: signal: move ilp32 and lp64 common code to separated file

On Wednesday 16 December 2015 00:42:41 Yury Norov wrote:
> + sigtramp = ka->sa.sa_restorer;
> +#ifdef CONFIG_ARM64_ILP32
> + else if (is_ilp32_compat_task())
> + sigtramp = VDSO_SYMBOL(current->mm->context.vdso, sigtramp_ilp32);
> +#endif
> + else
> + sigtramp = VDSO_SYMBOL(current->mm->context.vdso, sigtramp);
>

This is another case where I think it's more readable to remove the #ifdef,
with no change in behavior.

Arnd

2015-12-16 16:25:37

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [RFC3 PATCH v6 00/20] ILP32 for ARM64

On Wednesday 16 December 2015 00:42:26 Yury Norov wrote:
> This is still RFC because we have no glibc yet, that correspnds new ABI
> introduced here. And so we cannot run tests. LP64 and AARCH32 tests show
> no regression though.
>
> v3: https://lkml.org/lkml/2014/9/3/704
> v4: https://lkml.org/lkml/2015/4/13/691
> v5: https://lkml.org/lkml/2015/9/29/911
>
> v6:
> - time_t, __kenel_off_t and other types turned to be 32-bit
> for compatibility reasons (after v5 discussion);
> - related changes applied to ILP32 syscall table and handlers;
> - ILP32 VDSO code excluded. It's not mandatory, and caused questions
> during review process. We definitely make sure we will follow up
> with a VDSO later on because it is needed for performance reasons;
> - fixed build issues with different combinations of AARCH32 / ILP32
> enabling in config;
> - ILP32 TLS bug fixed;
> - entry32-common.S introduced to hold wrappers needed for both ILP32
> and AARCH32_EL0;
> - documentation updated according to latest changes;
> - rebased to the current head;
> - coding style re-checked;
> - ILP32 syscall table turned around.

Hi Yury,

This version looks very good overall, thanks for addressing all my previous
comments!

I've commented on a few things, but it's mostly about style, and there
are no show-stoppers. Please reply to my questions about the binfmt_elf.c,
I must be missing something here as I can't even find which patch adds
support for the new ELF32 executable format.

Regarding my sys_sigaltstack comment, I've looked at the compat handling
in kernel/signal.c and see that it's really ugly. Is that the reason
you didn't want to use it? I think it's a good idea to clean that up
so we don't need the get_fs()/set_fs() hack, but that can be done
independent from your series and would benefit all 32-bit compat handling.

Arnd

2015-12-16 16:58:30

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v6 09/20] arm64:ilp32: share HWCAP between LP64 and ILP32

On Wed, Dec 16, 2015 at 04:54:34PM +0100, Arnd Bergmann wrote:
> On Wednesday 16 December 2015 00:42:35 Yury Norov wrote:
> >
> > #ifdef CONFIG_COMPAT
> > -#define COMPAT_ELF_HWCAP (compat_elf_hwcap)
> > -#define COMPAT_ELF_HWCAP2 (compat_elf_hwcap2)
> > extern unsigned int compat_elf_hwcap, compat_elf_hwcap2;
> > +#define COMPAT_ELF_HWCAP \
> > + (is_a32_compat_task() \
> > + ? compat_elf_hwcap \
> > + : elf_hwcap)
> > +
> > +#define COMPAT_ELF_HWCAP2 \
> > + (is_a32_compat_task() \
> > + ? compat_elf_hwcap2 \
> > + : 0)
> > +
> > #endif
>
> I'm trying to understand how this is used. Are you compiling
> fs/compat_binfmt_elf.c twice to handle both 32-bit ELF types?

It's the same compat_binfmt_elf.c which handles all 32-bit ELF types,
i.e. AArch32 and A64/ILP32. The above macros are not constants, so they
are evaluated every time a new ELF file is loaded. We do a similar trick
with COMPAT_SET_PERSONALITY in patch 11.

--
Catalin

2015-12-16 17:19:12

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v6 09/20] arm64:ilp32: share HWCAP between LP64 and ILP32

On Wed, Dec 16, 2015 at 04:58:20PM +0000, Catalin Marinas wrote:
> On Wed, Dec 16, 2015 at 04:54:34PM +0100, Arnd Bergmann wrote:
> > On Wednesday 16 December 2015 00:42:35 Yury Norov wrote:
> > >
> > > #ifdef CONFIG_COMPAT
> > > -#define COMPAT_ELF_HWCAP (compat_elf_hwcap)
> > > -#define COMPAT_ELF_HWCAP2 (compat_elf_hwcap2)
> > > extern unsigned int compat_elf_hwcap, compat_elf_hwcap2;
> > > +#define COMPAT_ELF_HWCAP \
> > > + (is_a32_compat_task() \
> > > + ? compat_elf_hwcap \
> > > + : elf_hwcap)
> > > +
> > > +#define COMPAT_ELF_HWCAP2 \
> > > + (is_a32_compat_task() \
> > > + ? compat_elf_hwcap2 \
> > > + : 0)
> > > +
> > > #endif
> >
> > I'm trying to understand how this is used. Are you compiling
> > fs/compat_binfmt_elf.c twice to handle both 32-bit ELF types?
>
> It's the same compat_binfmt_elf.c which handles all 32-bit ELF types,
> i.e. AArch32 and A64/ILP32. The above macros are not constants, so they
> are evaluated every time a new ELF file is loaded. We do a similar trick
> with COMPAT_SET_PERSONALITY in patch 11.

IIUC, we may have a problem with this. elf_hwcap is 64-bit long while
elf_info[n] is 32-bit (Elf32_Addr), so we truncate AT_HWCAP if we ever
go beyond bit 31. The above may need to look something like:

#define COMPAT_ELF_HWCAP \
(is_a32_compat_task() \
? compat_elf_hwcap \
: (u32)elf_hwcap)

#define COMPAT_ELF_HWCAP2 \
(is_a32_compat_task() \
? compat_elf_hwcap2 \
: (u32)(elf_hwcap >> 32))

--
Catalin

2015-12-16 19:18:27

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v6 09/20] arm64:ilp32: share HWCAP between LP64 and ILP32

On Wednesday 16 December 2015 17:19:05 Catalin Marinas wrote:
> On Wed, Dec 16, 2015 at 04:58:20PM +0000, Catalin Marinas wrote:
> > On Wed, Dec 16, 2015 at 04:54:34PM +0100, Arnd Bergmann wrote:
> > > On Wednesday 16 December 2015 00:42:35 Yury Norov wrote:
> > > >
> > > > #ifdef CONFIG_COMPAT
> > > > -#define COMPAT_ELF_HWCAP (compat_elf_hwcap)
> > > > -#define COMPAT_ELF_HWCAP2 (compat_elf_hwcap2)
> > > > extern unsigned int compat_elf_hwcap, compat_elf_hwcap2;
> > > > +#define COMPAT_ELF_HWCAP \
> > > > + (is_a32_compat_task() \
> > > > + ? compat_elf_hwcap \
> > > > + : elf_hwcap)
> > > > +
> > > > +#define COMPAT_ELF_HWCAP2 \
> > > > + (is_a32_compat_task() \
> > > > + ? compat_elf_hwcap2 \
> > > > + : 0)
> > > > +
> > > > #endif
> > >
> > > I'm trying to understand how this is used. Are you compiling
> > > fs/compat_binfmt_elf.c twice to handle both 32-bit ELF types?
> >
> > It's the same compat_binfmt_elf.c which handles all 32-bit ELF types,
> > i.e. AArch32 and A64/ILP32. The above macros are not constants, so they
> > are evaluated every time a new ELF file is loaded. We do a similar trick
> > with COMPAT_SET_PERSONALITY in patch 11.

Ok, I see. I've also looked at other architectures, and found that
MIPS does it the way I thought it would be

git grep -w binfmt_elf.c
arch/mips/kernel/binfmt_elfn32.c:#include "../../../fs/binfmt_elf.c"
arch/mips/kernel/binfmt_elfo32.c:#include "../../../fs/binfmt_elf.c"

I still think doing the same for arm64 would result in more maintainable
code, because it completely separates the two different formats into
separate files. We'd obviously leave the existing compat handling as
it is, and just add one more file, not do both of them separately as
MIPS does.

Do you see any downsides of that approach?

> IIUC, we may have a problem with this. elf_hwcap is 64-bit long while
> elf_info[n] is 32-bit (Elf32_Addr), so we truncate AT_HWCAP if we ever
> go beyond bit 31. The above may need to look something like:
>
> #define COMPAT_ELF_HWCAP \
> (is_a32_compat_task() \
> ? compat_elf_hwcap \
> : (u32)elf_hwcap)
>
> #define COMPAT_ELF_HWCAP2 \
> (is_a32_compat_task() \
> ? compat_elf_hwcap2 \
> : (u32)(elf_hwcap >> 32))

Yes, interesting find.

Arnd

2015-12-17 10:54:55

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v6 09/20] arm64:ilp32: share HWCAP between LP64 and ILP32

On Wed, Dec 16, 2015 at 08:17:25PM +0100, Arnd Bergmann wrote:
> On Wednesday 16 December 2015 17:19:05 Catalin Marinas wrote:
> > On Wed, Dec 16, 2015 at 04:58:20PM +0000, Catalin Marinas wrote:
> > > On Wed, Dec 16, 2015 at 04:54:34PM +0100, Arnd Bergmann wrote:
> > > > On Wednesday 16 December 2015 00:42:35 Yury Norov wrote:
> > > > >
> > > > > #ifdef CONFIG_COMPAT
> > > > > -#define COMPAT_ELF_HWCAP (compat_elf_hwcap)
> > > > > -#define COMPAT_ELF_HWCAP2 (compat_elf_hwcap2)
> > > > > extern unsigned int compat_elf_hwcap, compat_elf_hwcap2;
> > > > > +#define COMPAT_ELF_HWCAP \
> > > > > + (is_a32_compat_task() \
> > > > > + ? compat_elf_hwcap \
> > > > > + : elf_hwcap)
> > > > > +
> > > > > +#define COMPAT_ELF_HWCAP2 \
> > > > > + (is_a32_compat_task() \
> > > > > + ? compat_elf_hwcap2 \
> > > > > + : 0)
> > > > > +
> > > > > #endif
> > > >
> > > > I'm trying to understand how this is used. Are you compiling
> > > > fs/compat_binfmt_elf.c twice to handle both 32-bit ELF types?
> > >
> > > It's the same compat_binfmt_elf.c which handles all 32-bit ELF types,
> > > i.e. AArch32 and A64/ILP32. The above macros are not constants, so they
> > > are evaluated every time a new ELF file is loaded. We do a similar trick
> > > with COMPAT_SET_PERSONALITY in patch 11.
>
> Ok, I see. I've also looked at other architectures, and found that
> MIPS does it the way I thought it would be
>
> git grep -w binfmt_elf.c
> arch/mips/kernel/binfmt_elfn32.c:#include "../../../fs/binfmt_elf.c"
> arch/mips/kernel/binfmt_elfo32.c:#include "../../../fs/binfmt_elf.c"
>
> I still think doing the same for arm64 would result in more maintainable
> code, because it completely separates the two different formats into
> separate files. We'd obviously leave the existing compat handling as
> it is, and just add one more file, not do both of them separately as
> MIPS does.

It will probably simplify some of the code like setting personality,
COMPAT_ELF_HWCAP, elf_check_arch.

> Do you see any downsides of that approach?

Not really. execve may take just a little bit longer to search the right
binfmt but that's lost in the noise anyway, the execve operation itself
is expensive.

AFAICT, the main decision on choosing the ELF binfmt comes from
elf_check_arch() and sizeof(struct elf_phdr). The ILP32 would use the
EM_AARCH64 class but a smaller struct elf_phdr (with 32-bit members). So
there won't be any confusion with the AArch32 (compat) and AArch64
(native) binfmt elf loaders.

> > IIUC, we may have a problem with this. elf_hwcap is 64-bit long while
> > elf_info[n] is 32-bit (Elf32_Addr), so we truncate AT_HWCAP if we ever
> > go beyond bit 31. The above may need to look something like:
> >
> > #define COMPAT_ELF_HWCAP \
> > (is_a32_compat_task() \
> > ? compat_elf_hwcap \
> > : (u32)elf_hwcap)
> >
> > #define COMPAT_ELF_HWCAP2 \
> > (is_a32_compat_task() \
> > ? compat_elf_hwcap2 \
> > : (u32)(elf_hwcap >> 32))
>
> Yes, interesting find.

BTW, we need to make sure this series (primarily the ABI) is big-endian
safe. I know it is not targeted at this initially but given that the
reason for doing it is legacy networking code, I wouldn't be surprised
if someone asks for BE at some point in the future.

--
Catalin

2015-12-17 11:23:20

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v6 03/20] arm64: rename COMPAT to AARCH32_EL0 in Kconfig

On Wed, Dec 16, 2015 at 12:42:29AM +0300, Yury Norov wrote:
> From: Andrew Pinski <[email protected]>
>
> Reviewed-by: David Daney <[email protected]>
> Signed-off-by: Philipp Tomsich <[email protected]>
> Signed-off-by: Christoph Muellner <[email protected]>
> Signed-off-by: Yury Norov <[email protected]>
> Signed-off-by: Andrew Pinski <[email protected]>

I already asked here to add a long patch description:

http://article.gmane.org/gmane.linux.kernel/2099414

--
Catalin

2015-12-17 11:38:09

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v6 07/20] arm64: introduce is_a32_task and is_a32_thread (for AArch32 compat)

On Wed, Dec 16, 2015 at 12:42:33AM +0300, Yury Norov wrote:
> diff --git a/arch/arm64/include/asm/is_compat.h b/arch/arm64/include/asm/is_compat.h
> new file mode 100644
> index 0000000..476db90
> --- /dev/null
> +++ b/arch/arm64/include/asm/is_compat.h
> @@ -0,0 +1,62 @@
> +/*
> + * Copyright (C) 2015 Cavium Inc.

Moving code around and changing function names doesn't exactly mean a
change in copyright (though it's not that much code).

> + *
> + * 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 __ASM_IS_COMPAT_H
> +#define __ASM_IS_COMPAT_H
> +#ifdef __KERNEL__

Nitpick: I thought we no longer need __KERNEL__ for non-uapi header files.

--
Catalin

2015-12-17 11:42:02

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v6 08/20] arm64: ilp32: add is_ilp32_compat_{task, thread} and TIF_32BIT_AARCH64

On Wed, Dec 16, 2015 at 12:42:34AM +0300, Yury Norov wrote:
> Reviewed-by: David Daney <[email protected]>
> Signed-off-by: Philipp Tomsich <[email protected]>
> Signed-off-by: Christoph Muellner <[email protected]>
> Signed-off-by: Yury Norov <[email protected]>
> Signed-off-by: Andrew Pinski <[email protected]>

Long description missing.

> diff --git a/arch/arm64/include/asm/is_compat.h b/arch/arm64/include/asm/is_compat.h
> index 476db90..89b1f65 100644
> --- a/arch/arm64/include/asm/is_compat.h
> +++ b/arch/arm64/include/asm/is_compat.h
> @@ -36,7 +36,6 @@ static inline int is_a32_compat_thread(struct thread_info *thread)
> #else
>
> static inline int is_a32_compat_task(void)
> -
> {
> return 0;
> }

You should move this to the previous patch.

> @@ -45,14 +44,39 @@ static inline int is_a32_compat_thread(struct thread_info *thread)
> {
> return 0;
> }
> -
> #endif /* CONFIG_AARCH32_EL0 */

Maybe this one as well, though I like an empty line before the last
#endif (i.e. drop this hunk).

--
Catalin

2015-12-17 13:57:36

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v6 09/20] arm64:ilp32: share HWCAP between LP64 and ILP32

On Thursday 17 December 2015 10:54:47 Catalin Marinas wrote:
> > > IIUC, we may have a problem with this. elf_hwcap is 64-bit long while
> > > elf_info[n] is 32-bit (Elf32_Addr), so we truncate AT_HWCAP if we ever
> > > go beyond bit 31. The above may need to look something like:
> > >
> > > #define COMPAT_ELF_HWCAP \
> > > (is_a32_compat_task() \
> > > ? compat_elf_hwcap \
> > > : (u32)elf_hwcap)
> > >
> > > #define COMPAT_ELF_HWCAP2 \
> > > (is_a32_compat_task() \
> > > ? compat_elf_hwcap2 \
> > > : (u32)(elf_hwcap >> 32))
> >
> > Yes, interesting find.
>
> BTW, we need to make sure this series (primarily the ABI) is big-endian
> safe. I know it is not targeted at this initially but given that the
> reason for doing it is legacy networking code, I wouldn't be surprised
> if someone asks for BE at some point in the future.

Yes, I'm sure that will be needed.

Arnd

2015-12-17 14:05:31

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v6 11/20] arm64:ilp32: support core dump generation for ILP32

On Wed, Dec 16, 2015 at 12:42:37AM +0300, Yury Norov wrote:
> diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
> index 8786ca5..4e2e3c0 100644
> --- a/arch/arm64/include/asm/elf.h
> +++ b/arch/arm64/include/asm/elf.h
[...]
> +/*
> + * struct elf_prstatus is defined in include/uapi/linux/elfcore.h,
> + * and has different sise for supported ABIs
> + */
> +#define PRSTATUS_SIZE(S) (is_a32_compat_task() ? 124 : (is_ilp32_compat_task() ? 352 : 392))

It's the *third* time I ask this: can you not use some sizeof instead of
the magic numbers?

--
Catalin

2015-12-17 14:38:19

by Andreas Schwab

[permalink] [raw]
Subject: Re: [PATCH v6 13/20] arm64: ilp32: share aarch32 syscall wrappers to ilp32

Yury Norov <[email protected]> writes:

> From: Jan Dakinevich <[email protected]>
>
> statfs64, fstat64 and mmap_pgoff has wrappers that needed both by aarch32 and

Typo: s/fstat64/fstatfs64/

Andreas.

--
Andreas Schwab, SUSE Labs, [email protected]
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE 1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."

2015-12-17 18:28:02

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v6 12/20] arm64:ilp32: add sys_ilp32.c and a separate table (in entry.S) to use it

On Wed, Dec 16, 2015 at 12:42:38AM +0300, Yury Norov wrote:
> +/* Using non-compat syscalls where necessary */
> +#define compat_sys_fadvise64_64 sys_fadvise64_64
> +#define compat_sys_fallocate sys_fallocate
> +#define compat_sys_ftruncate64 sys_ftruncate

I initially thought this should be sys_ftruncate64 (or a wrapper to pass
small == 0) but we rely on sys_openat to set O_LARGEFILE.

arch/arm has ftruncate and ftruncate64, but it looks like we route both
via sys_ftruncate(). The difference is the "small" argument which
imposes a limit on the length without O_LARGEFILE, so we may have a bug
here.

> +#define compat_sys_lookup_dcookie sys_lookup_dcookie
> +#define compat_sys_pread64 sys_pread64
> +#define compat_sys_pwrite64 sys_pwrite64
> +#define compat_sys_readahead sys_readahead
> +#define compat_sys_shmat sys_shmat

I wonder whether we need wrappers (actually, not only for these but
sys_read etc.). These functions take either a pointer or a size_t
argument which are 32-bit with ILP32 but treated as 64-bit by an LP64
kernel. Can we guarantee that user space zeros the top 32-bit of the
arguments passed here?

With compat/AArch32, this is guaranteed by the kernel since EL0 won't be
able to touch the top part but here I'm not entirely sure. As long as
user space used Wn registers for 32-bit types, we are probably fine (the
architecture guarantees the top 32-bit zeroing following a MOV, LDR etc.
instruction into a Wn register). We just need to mention this in the ABI
document (ilp32.txt).

> +#define compat_sys_sigaltstack sys_sigaltstack

I think Arnd is right here in using the compat function. The stack_t
would differ between LP64 and ILP32. compat_sys_sigaltstack() uses
compat_user_stack_pointer() but this should work correctly as it checks
pt_regs for the right mode.

> +#define compat_sys_sync_file_range sys_sync_file_range
> +#define compat_sys_truncate64 sys_truncate
> +#define sys_llseek sys_lseek

I think this makes sense since we have 64-bit registers.

> +
> +#define compat_sys_open_by_handle_at sys_open_by_handle_at
> +#define compat_sys_openat sys_openat

So using sys_openat() forces O_LARGEFILE and we don't have a problem
with (f)truncate. We may have an issue with AArch32 compat though.

--
Catalin

2015-12-17 20:11:23

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v6 12/20] arm64:ilp32: add sys_ilp32.c and a separate table (in entry.S) to use it

On Thursday 17 December 2015 18:27:53 Catalin Marinas wrote:
> On Wed, Dec 16, 2015 at 12:42:38AM +0300, Yury Norov wrote:

> > +#define compat_sys_lookup_dcookie sys_lookup_dcookie
> > +#define compat_sys_pread64 sys_pread64
> > +#define compat_sys_pwrite64 sys_pwrite64
> > +#define compat_sys_readahead sys_readahead
> > +#define compat_sys_shmat sys_shmat
>
> I wonder whether we need wrappers (actually, not only for these but
> sys_read etc.). These functions take either a pointer or a size_t
> argument which are 32-bit with ILP32 but treated as 64-bit by an LP64
> kernel. Can we guarantee that user space zeros the top 32-bit of the
> arguments passed here?

I'm pretty sure that is safe. I haven't read the calling conventions
specification for arm64 ilp32, but usually all function arguments are
passed as 64-bit registers with proper sign-extend or zero-extend.

Most other syscalls rely on this behavior too, not just the ones that
are being modified here.

> With compat/AArch32, this is guaranteed by the kernel since EL0 won't be
> able to touch the top part but here I'm not entirely sure. As long as
> user space used Wn registers for 32-bit types, we are probably fine (the
> architecture guarantees the top 32-bit zeroing following a MOV, LDR etc.
> instruction into a Wn register). We just need to mention this in the ABI
> document (ilp32.txt).

I think the aarch32 case is actually the hard one, because it has to
worry about explicitly sign-extending 32-bit arguments (signed int or
signed long) that might be negative, e.g. user space passes -1
as 0xffffffff, which the kernel entry turns into 0x00000000ffffffff
when it should use 0xffffffffffffffff. The COMPAT_SYSCALL_DEFINEx
macros take care of this.

> > +
> > +#define compat_sys_open_by_handle_at sys_open_by_handle_at
> > +#define compat_sys_openat sys_openat
>
> So using sys_openat() forces O_LARGEFILE and we don't have a problem
> with (f)truncate. We may have an issue with AArch32 compat though.

aarch32 uses the correct compat functions in asm/unistd32.h

Arnd

2015-12-17 20:14:23

by Andrew Pinski

[permalink] [raw]
Subject: Re: [PATCH v6 12/20] arm64:ilp32: add sys_ilp32.c and a separate table (in entry.S) to use it

On Thu, Dec 17, 2015 at 12:10 PM, Arnd Bergmann <[email protected]> wrote:
> On Thursday 17 December 2015 18:27:53 Catalin Marinas wrote:
>> On Wed, Dec 16, 2015 at 12:42:38AM +0300, Yury Norov wrote:
>
>> > +#define compat_sys_lookup_dcookie sys_lookup_dcookie
>> > +#define compat_sys_pread64 sys_pread64
>> > +#define compat_sys_pwrite64 sys_pwrite64
>> > +#define compat_sys_readahead sys_readahead
>> > +#define compat_sys_shmat sys_shmat
>>
>> I wonder whether we need wrappers (actually, not only for these but
>> sys_read etc.). These functions take either a pointer or a size_t
>> argument which are 32-bit with ILP32 but treated as 64-bit by an LP64
>> kernel. Can we guarantee that user space zeros the top 32-bit of the
>> arguments passed here?
>
> I'm pretty sure that is safe. I haven't read the calling conventions
> specification for arm64 ilp32, but usually all function arguments are
> passed as 64-bit registers with proper sign-extend or zero-extend.

Well (just like LP64 on AARCH64), when passing a 32bit value to a
function, the upper 32bits are undefined. I ran into this when I was
debugging the GCC go library on ILP32 (though reproduced with pure C
code) and the assembly functions inside glibc where pointers are
passed with the upper 32bits as undefined.
So we have an issue if called with syscall function or using pure
assembly to create the syscall functions (which glibc does).

Thanks,
Andrew

>
> Most other syscalls rely on this behavior too, not just the ones that
> are being modified here.
>
>> With compat/AArch32, this is guaranteed by the kernel since EL0 won't be
>> able to touch the top part but here I'm not entirely sure. As long as
>> user space used Wn registers for 32-bit types, we are probably fine (the
>> architecture guarantees the top 32-bit zeroing following a MOV, LDR etc.
>> instruction into a Wn register). We just need to mention this in the ABI
>> document (ilp32.txt).
>
> I think the aarch32 case is actually the hard one, because it has to
> worry about explicitly sign-extending 32-bit arguments (signed int or
> signed long) that might be negative, e.g. user space passes -1
> as 0xffffffff, which the kernel entry turns into 0x00000000ffffffff
> when it should use 0xffffffffffffffff. The COMPAT_SYSCALL_DEFINEx
> macros take care of this.
>
>> > +
>> > +#define compat_sys_open_by_handle_at sys_open_by_handle_at
>> > +#define compat_sys_openat sys_openat
>>
>> So using sys_openat() forces O_LARGEFILE and we don't have a problem
>> with (f)truncate. We may have an issue with AArch32 compat though.
>
> aarch32 uses the correct compat functions in asm/unistd32.h
>
> Arnd

2015-12-17 20:52:14

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v6 12/20] arm64:ilp32: add sys_ilp32.c and a separate table (in entry.S) to use it

On Thursday 17 December 2015 12:14:20 Andrew Pinski wrote:
> On Thu, Dec 17, 2015 at 12:10 PM, Arnd Bergmann <[email protected]> wrote:
> > On Thursday 17 December 2015 18:27:53 Catalin Marinas wrote:
> >> On Wed, Dec 16, 2015 at 12:42:38AM +0300, Yury Norov wrote:
> >
> >> > +#define compat_sys_lookup_dcookie sys_lookup_dcookie
> >> > +#define compat_sys_pread64 sys_pread64
> >> > +#define compat_sys_pwrite64 sys_pwrite64
> >> > +#define compat_sys_readahead sys_readahead
> >> > +#define compat_sys_shmat sys_shmat
> >>
> >> I wonder whether we need wrappers (actually, not only for these but
> >> sys_read etc.). These functions take either a pointer or a size_t
> >> argument which are 32-bit with ILP32 but treated as 64-bit by an LP64
> >> kernel. Can we guarantee that user space zeros the top 32-bit of the
> >> arguments passed here?
> >
> > I'm pretty sure that is safe. I haven't read the calling conventions
> > specification for arm64 ilp32, but usually all function arguments are
> > passed as 64-bit registers with proper sign-extend or zero-extend.
>
> Well (just like LP64 on AARCH64), when passing a 32bit value to a
> function, the upper 32bits are undefined. I ran into this when I was
> debugging the GCC go library on ILP32 (though reproduced with pure C
> code) and the assembly functions inside glibc where pointers are
> passed with the upper 32bits as undefined.
> So we have an issue if called with syscall function or using pure
> assembly to create the syscall functions (which glibc does).

Ok, I see :-(

So the calling conventions avoid the problem of being able to set
the upper bits from malicious user space when the kernel assumes they
are zeroed out (we had security bugs in this area, before we introduced
SYSCALL_DEFINEx()), but it means that we need wrappers around each
syscall that takes an argument that is different length between user
and kernel space (as Catalin guessed). arch/s390 has the same problem and
works around it with code in arch/s390/kernel/compat_wrapper.c, while
other architectures (at least powerpc, x86 and tile IIRC, don't know much
about mips, parisc and sparc) don't have the problem because of their
calling conventions.

This also means that we cannot work around it in glibc at all, because
we have to be able to handle malicious user space, so it has to be
done in the kernel using something similar to what s390 does.

Arnd

2015-12-18 11:42:47

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v6 12/20] arm64:ilp32: add sys_ilp32.c and a separate table (in entry.S) to use it

(cc'ing Marcus for more insight on the tools side)

On Thu, Dec 17, 2015 at 12:14:20PM -0800, Andrew Pinski wrote:
> On Thu, Dec 17, 2015 at 12:10 PM, Arnd Bergmann <[email protected]> wrote:
> > On Thursday 17 December 2015 18:27:53 Catalin Marinas wrote:
> >> On Wed, Dec 16, 2015 at 12:42:38AM +0300, Yury Norov wrote:
> >
> >> > +#define compat_sys_lookup_dcookie sys_lookup_dcookie
> >> > +#define compat_sys_pread64 sys_pread64
> >> > +#define compat_sys_pwrite64 sys_pwrite64
> >> > +#define compat_sys_readahead sys_readahead
> >> > +#define compat_sys_shmat sys_shmat
> >>
> >> I wonder whether we need wrappers (actually, not only for these but
> >> sys_read etc.). These functions take either a pointer or a size_t
> >> argument which are 32-bit with ILP32 but treated as 64-bit by an LP64
> >> kernel. Can we guarantee that user space zeros the top 32-bit of the
> >> arguments passed here?
> >
> > I'm pretty sure that is safe. I haven't read the calling conventions
> > specification for arm64 ilp32, but usually all function arguments are
> > passed as 64-bit registers with proper sign-extend or zero-extend.
>
> Well (just like LP64 on AARCH64), when passing a 32bit value to a
> function, the upper 32bits are undefined. I ran into this when I was
> debugging the GCC go library on ILP32 (though reproduced with pure C
> code) and the assembly functions inside glibc where pointers are
> passed with the upper 32bits as undefined.
> So we have an issue if called with syscall function or using pure
> assembly to create the syscall functions (which glibc does).

I think the ILP32 syscall ABI should follow the PCS convention where the
top 32-bit of a register is not guaranteed 0 when the size of the
argument is 32-bit. So take the read(2) syscall:

ssize_t read(int fd, void *buf, size_t count);

>From the ILP32 code perspective, void * and size_t are both 32-bit. It
would call into the kernel leaving the top 32-bit as undefined (if we
follow the PCS). Normally, calling a function with the same size
arguments is not a problem since the compiler generates the callee code
accordingly. However, we route the syscall directly into the native
sys_read() where void * and size_t are 64-bit with the top 32-bit left
undefined.

We have three options here:

1. Always follow PCS convention across user/kernel call and add wrappers
in the kernel (preferred)

2. Follow the PCS up to glibc and get glibc to zero the top part (not
always safe with hand-written assembly, though we already do this for
AArch32 where the PCS only specifies 4 arguments in registers, the
rest go on the stack)

3. Follow the PCS up to glibc but always pass syscall arguments in W
registers, like AArch32 compat support (the least preferred option,
the only advantage is a single wrapper for all syscalls but it would
be doing unnecessary zeroing even for syscalls where it isn't needed)

My preference, as stated above, is (1). You can write the wrappers in C
directly and let the compiler upgrade the types when calling the native
syscall. But any other option would be fine (take some inspiration from
other architectures). Unfortunately we don't have COMPAT_SYSCALL_DEFINE
for all functions that we need to wrap, it would have been easier (so we
need to add them but probably in the arch/arm64 code).

--
Catalin

2015-12-18 12:54:13

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v6 12/20] arm64:ilp32: add sys_ilp32.c and a separate table (in entry.S) to use it

On Friday 18 December 2015 11:42:19 Catalin Marinas wrote:
> On Thu, Dec 17, 2015 at 12:14:20PM -0800, Andrew Pinski wrote:
> > Well (just like LP64 on AARCH64), when passing a 32bit value to a
> > function, the upper 32bits are undefined. I ran into this when I was
> > debugging the GCC go library on ILP32 (though reproduced with pure C
> > code) and the assembly functions inside glibc where pointers are
> > passed with the upper 32bits as undefined.
> > So we have an issue if called with syscall function or using pure
> > assembly to create the syscall functions (which glibc does).
>
> I think the ILP32 syscall ABI should follow the PCS convention where the
> top 32-bit of a register is not guaranteed 0 when the size of the
> argument is 32-bit. So take the read(2) syscall:
>
> ssize_t read(int fd, void *buf, size_t count);
>
> From the ILP32 code perspective, void * and size_t are both 32-bit. It
> would call into the kernel leaving the top 32-bit as undefined (if we
> follow the PCS). Normally, calling a function with the same size
> arguments is not a problem since the compiler generates the callee code
> accordingly. However, we route the syscall directly into the native
> sys_read() where void * and size_t are 64-bit with the top 32-bit left
> undefined.
>
> We have three options here:
>
> 1. Always follow PCS convention across user/kernel call and add wrappers
> in the kernel (preferred)

Yes, I also think this is best.

> 2. Follow the PCS up to glibc and get glibc to zero the top part (not
> always safe with hand-written assembly, though we already do this for
> AArch32 where the PCS only specifies 4 arguments in registers, the
> rest go on the stack)

I assume this needs special handling for syscalls with 64-bit arguments
in both glibc and kernel.

> 3. Follow the PCS up to glibc but always pass syscall arguments in W
> registers, like AArch32 compat support (the least preferred option,
> the only advantage is a single wrapper for all syscalls but it would
> be doing unnecessary zeroing even for syscalls where it isn't needed)

This would mean we cannot pass 64-bit arguments in registers, right?

> My preference, as stated above, is (1). You can write the wrappers in C
> directly and let the compiler upgrade the types when calling the native
> syscall. But any other option would be fine (take some inspiration from
> other architectures). Unfortunately we don't have COMPAT_SYSCALL_DEFINE
> for all functions that we need to wrap, it would have been easier (so we
> need to add them but probably in the arch/arm64 code).

It would be nice to have that code architecture-independent, so we can
share it with s390 and only need to update one place when new syscalls
get added.

Arnd

2015-12-18 13:49:20

by Yury Norov

[permalink] [raw]
Subject: Re: [PATCH v6 15/20] arm64: signal: move ilp32 and lp64 common code to separated file

On Wed, Dec 16, 2015 at 05:08:35PM +0100, Arnd Bergmann wrote:
> On Wednesday 16 December 2015 00:42:41 Yury Norov wrote:
> > + sigtramp = ka->sa.sa_restorer;
> > +#ifdef CONFIG_ARM64_ILP32
> > + else if (is_ilp32_compat_task())
> > + sigtramp = VDSO_SYMBOL(current->mm->context.vdso, sigtramp_ilp32);
> > +#endif
> > + else
> > + sigtramp = VDSO_SYMBOL(current->mm->context.vdso, sigtramp);
> >
>
> This is another case where I think it's more readable to remove the #ifdef,
> with no change in behavior.
>
> Arnd

No actually. symbol sigtramp_ilp32 is declared in
arch/arm64/kernel/vdso-ilp32/vdso-ilp32.lds.S

And so it does not exist if CONFIG_ARM64_ILP32 is not set.

2015-12-18 13:56:26

by Yury Norov

[permalink] [raw]
Subject: Re: [PATCH v6 13/20] arm64: ilp32: share aarch32 syscall wrappers to ilp32

On Thu, Dec 17, 2015 at 03:38:16PM +0100, Andreas Schwab wrote:
> Yury Norov <[email protected]> writes:
>
> > From: Jan Dakinevich <[email protected]>
> >
> > statfs64, fstat64 and mmap_pgoff has wrappers that needed both by aarch32 and
>
> Typo: s/fstat64/fstatfs64/
>
> Andreas.

Thank you.

2015-12-18 13:57:55

by Yury Norov

[permalink] [raw]
Subject: Re: [PATCH v6 10/20] arm64:ilp32 use the native LP64 'start_thread' for ILP32 threads

On Wed, Dec 16, 2015 at 04:50:18PM +0100, Arnd Bergmann wrote:
> On Wednesday 16 December 2015 00:42:36 Yury Norov wrote:
> > +#ifdef CONFIG_ARM64_ILP32
> > + /* ILP32 threads are started the same way as LP64 threads. */
> > + if (is_ilp32_compat_task()) {
> > + start_thread(regs, pc, sp);
> > + return;
> > + }
> > +#endif
> >
>
> Just a small style comment, but I think you can just leave out the #ifdef,
> as is_ilp32_compat_task() will already return false if that is disabled.
>
> Arnd

Missed it, thank you.

2015-12-18 14:11:09

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v6 15/20] arm64: signal: move ilp32 and lp64 common code to separated file

On Friday 18 December 2015 16:48:55 Yury Norov wrote:
> On Wed, Dec 16, 2015 at 05:08:35PM +0100, Arnd Bergmann wrote:
> > On Wednesday 16 December 2015 00:42:41 Yury Norov wrote:
> > > + sigtramp = ka->sa.sa_restorer;
> > > +#ifdef CONFIG_ARM64_ILP32
> > > + else if (is_ilp32_compat_task())
> > > + sigtramp = VDSO_SYMBOL(current->mm->context.vdso, sigtramp_ilp32);
> > > +#endif
> > > + else
> > > + sigtramp = VDSO_SYMBOL(current->mm->context.vdso, sigtramp);
> > >
> >
> > This is another case where I think it's more readable to remove the #ifdef,
> > with no change in behavior.
> >
> > Arnd
>
> No actually. symbol sigtramp_ilp32 is declared in
> arch/arm64/kernel/vdso-ilp32/vdso-ilp32.lds.S
>
> And so it does not exist if CONFIG_ARM64_ILP32 is not set.

You only need the declaration of that symbol, the compiler's dead code
elimination will ensure that no symbol reference is generated when
the condition is always false at compile time.

Arnd

2015-12-18 14:11:47

by Yury Norov

[permalink] [raw]
Subject: Re: [PATCH v6 08/20] arm64: ilp32: add is_ilp32_compat_{task, thread} and TIF_32BIT_AARCH64

On Thu, Dec 17, 2015 at 11:41:53AM +0000, Catalin Marinas wrote:
> On Wed, Dec 16, 2015 at 12:42:34AM +0300, Yury Norov wrote:
> > Reviewed-by: David Daney <[email protected]>
> > Signed-off-by: Philipp Tomsich <[email protected]>
> > Signed-off-by: Christoph Muellner <[email protected]>
> > Signed-off-by: Yury Norov <[email protected]>
> > Signed-off-by: Andrew Pinski <[email protected]>
>
> Long description missing.

Hi, Catalin,

I think this patch (and patch #3 too) is trivial, and
explanation in patch name is clear enougth. So, I just do not
understand what else to explain here. Could you point me, and then I
will do it.

>
> > diff --git a/arch/arm64/include/asm/is_compat.h b/arch/arm64/include/asm/is_compat.h
> > index 476db90..89b1f65 100644
> > --- a/arch/arm64/include/asm/is_compat.h
> > +++ b/arch/arm64/include/asm/is_compat.h
> > @@ -36,7 +36,6 @@ static inline int is_a32_compat_thread(struct thread_info *thread)
> > #else
> >
> > static inline int is_a32_compat_task(void)
> > -
> > {
> > return 0;
> > }
>
> You should move this to the previous patch.
>
> > @@ -45,14 +44,39 @@ static inline int is_a32_compat_thread(struct thread_info *thread)
> > {
> > return 0;
> > }
> > -
> > #endif /* CONFIG_AARCH32_EL0 */
>
> Maybe this one as well, though I like an empty line before the last
> #endif (i.e. drop this hunk).

It's just dirt, I'll clean it. Thank you.

Yury.

2015-12-18 14:47:28

by Yury Norov

[permalink] [raw]
Subject: Re: [PATCH v6 08/20] arm64: ilp32: add is_ilp32_compat_{task, thread} and TIF_32BIT_AARCH64

On Fri, Dec 18, 2015 at 05:11:12PM +0300, Yury Norov wrote:
> On Thu, Dec 17, 2015 at 11:41:53AM +0000, Catalin Marinas wrote:
> > On Wed, Dec 16, 2015 at 12:42:34AM +0300, Yury Norov wrote:
> > > Reviewed-by: David Daney <[email protected]>
> > > Signed-off-by: Philipp Tomsich <[email protected]>
> > > Signed-off-by: Christoph Muellner <[email protected]>
> > > Signed-off-by: Yury Norov <[email protected]>
> > > Signed-off-by: Andrew Pinski <[email protected]>
> >
> > Long description missing.
>
> Hi, Catalin,
>
> I think this patch (and patch #3 too) is trivial, and
> explanation in patch name is clear enougth. So, I just do not
> understand what else to explain here. Could you point me, and then I
> will do it.
>

Is it OK?

arm64: ilp32: add is_ilp32_compat_{task,thread} and TIF_32BIT_AARCH64

ILP32 tasks are needed to be distinguished from lp64 and aarch32.
This patch adds helper functions is_ilp32_compat_{task,thread} and
thread flag TIF_32BIT_AARCH64 to address this. This patch is
preparation for following patches in ilp32 patchset.

2015-12-21 17:42:12

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v6 08/20] arm64: ilp32: add is_ilp32_compat_{task, thread} and TIF_32BIT_AARCH64

On Fri, Dec 18, 2015 at 05:44:37PM +0300, Yury Norov wrote:
> On Fri, Dec 18, 2015 at 05:11:12PM +0300, Yury Norov wrote:
> > On Thu, Dec 17, 2015 at 11:41:53AM +0000, Catalin Marinas wrote:
> > > On Wed, Dec 16, 2015 at 12:42:34AM +0300, Yury Norov wrote:
> > > > Reviewed-by: David Daney <[email protected]>
> > > > Signed-off-by: Philipp Tomsich <[email protected]>
> > > > Signed-off-by: Christoph Muellner <[email protected]>
> > > > Signed-off-by: Yury Norov <[email protected]>
> > > > Signed-off-by: Andrew Pinski <[email protected]>
> > >
> > > Long description missing.
> >
> > Hi, Catalin,
> >
> > I think this patch (and patch #3 too) is trivial, and
> > explanation in patch name is clear enougth. So, I just do not
> > understand what else to explain here. Could you point me, and then I
> > will do it.
> >
>
> Is it OK?
>
> arm64: ilp32: add is_ilp32_compat_{task,thread} and TIF_32BIT_AARCH64
>
> ILP32 tasks are needed to be distinguished from lp64 and aarch32.
> This patch adds helper functions is_ilp32_compat_{task,thread} and
> thread flag TIF_32BIT_AARCH64 to address this. This patch is
> preparation for following patches in ilp32 patchset.

It looks fine to me.

--
Catalin

2015-12-21 18:31:26

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v6 12/20] arm64:ilp32: add sys_ilp32.c and a separate table (in entry.S) to use it

On Fri, Dec 18, 2015 at 01:47:55PM +0100, Arnd Bergmann wrote:
> On Friday 18 December 2015 11:42:19 Catalin Marinas wrote:
> > On Thu, Dec 17, 2015 at 12:14:20PM -0800, Andrew Pinski wrote:
> > > Well (just like LP64 on AARCH64), when passing a 32bit value to a
> > > function, the upper 32bits are undefined. I ran into this when I was
> > > debugging the GCC go library on ILP32 (though reproduced with pure C
> > > code) and the assembly functions inside glibc where pointers are
> > > passed with the upper 32bits as undefined.
> > > So we have an issue if called with syscall function or using pure
> > > assembly to create the syscall functions (which glibc does).
> >
> > I think the ILP32 syscall ABI should follow the PCS convention where the
> > top 32-bit of a register is not guaranteed 0 when the size of the
> > argument is 32-bit. So take the read(2) syscall:
> >
> > ssize_t read(int fd, void *buf, size_t count);
> >
> > From the ILP32 code perspective, void * and size_t are both 32-bit. It
> > would call into the kernel leaving the top 32-bit as undefined (if we
> > follow the PCS). Normally, calling a function with the same size
> > arguments is not a problem since the compiler generates the callee code
> > accordingly. However, we route the syscall directly into the native
> > sys_read() where void * and size_t are 64-bit with the top 32-bit left
> > undefined.
> >
> > We have three options here:
> >
> > 1. Always follow PCS convention across user/kernel call and add wrappers
> > in the kernel (preferred)
>
> Yes, I also think this is best.
>
> > 2. Follow the PCS up to glibc and get glibc to zero the top part (not
> > always safe with hand-written assembly, though we already do this for
> > AArch32 where the PCS only specifies 4 arguments in registers, the
> > rest go on the stack)
>
> I assume this needs special handling for syscalls with 64-bit arguments
> in both glibc and kernel.

I think glibc only should suffice, if it is its responsibility to zero
the top 32-bit part.

> > 3. Follow the PCS up to glibc but always pass syscall arguments in W
> > registers, like AArch32 compat support (the least preferred option,
> > the only advantage is a single wrapper for all syscalls but it would
> > be doing unnecessary zeroing even for syscalls where it isn't needed)
>
> This would mean we cannot pass 64-bit arguments in registers, right?

Not in a single register but two (like we do on AArch32).

> > My preference, as stated above, is (1). You can write the wrappers in C
> > directly and let the compiler upgrade the types when calling the native
> > syscall. But any other option would be fine (take some inspiration from
> > other architectures). Unfortunately we don't have COMPAT_SYSCALL_DEFINE
> > for all functions that we need to wrap, it would have been easier (so we
> > need to add them but probably in the arch/arm64 code).
>
> It would be nice to have that code architecture-independent, so we can
> share it with s390 and only need to update one place when new syscalls
> get added.

We could indeed move things like:

COMPAT_SYSCALL_DEFINE3(s390_read, unsigned int, fd, char __user *, buf, compat_size_t, count)

to the core code and share them between s390 and arm64/ILP32. So let's
stick to option 1.

--
Catalin

2015-12-21 18:39:53

by Philipp Tomsich

[permalink] [raw]
Subject: Re: [PATCH v6 12/20] arm64:ilp32: add sys_ilp32.c and a separate table (in entry.S) to use it


> On 18 Dec 2015, at 13:47, Arnd Bergmann <[email protected]> wrote:
>
>> 3. Follow the PCS up to glibc but always pass syscall arguments in W
>> registers, like AArch32 compat support (the least preferred option,
>> the only advantage is a single wrapper for all syscalls but it would
>> be doing unnecessary zeroing even for syscalls where it isn't needed)
>
> This would mean we cannot pass 64-bit arguments in registers, right?

Note that there’s no 32bit registers (the ‘w’-form always refers to the lower
32bits of a 64bit register, with implicit zero-extension)… and load/store
instructions always use the full base-register (‘x’-form) for address calculation.
I.e. a load/store would inadvertently pickup “random garbage” in the upper
32bits, if no explicit zero-extension is applied.

In other words: all zero-extensions for 32bit arguments should be explicit
on the kernel side.

Regards,
Philipp.

2015-12-21 22:14:49

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v6 12/20] arm64:ilp32: add sys_ilp32.c and a separate table (in entry.S) to use it

On Monday 21 December 2015, Dr. Philipp Tomsich wrote:
>
> > On 18 Dec 2015, at 13:47, Arnd Bergmann <[email protected]> wrote:
> >
> >> 3. Follow the PCS up to glibc but always pass syscall arguments in W
> >> registers, like AArch32 compat support (the least preferred option,
> >> the only advantage is a single wrapper for all syscalls but it would
> >> be doing unnecessary zeroing even for syscalls where it isn't needed)
> >
> > This would mean we cannot pass 64-bit arguments in registers, right?
>
> Note that there’s no 32bit registers (the ‘w’-form always refers to the lower
> 32bits of a 64bit register, with implicit zero-extension)… and load/store
> instructions always use the full base-register (‘x’-form) for address calculation.
> I.e. a load/store would inadvertently pickup “random garbage” in the upper
> 32bits, if no explicit zero-extension is applied.
>
> In other words: all zero-extensions for 32bit arguments should be explicit
> on the kernel side.

I think that is what Catalin meant with the single wrapper in the description:
the kernel always zeroes out the upper 32 bits in the initial trap, and then
we only need to do sign-extensions for the few cases that need it, and pass 64-bit
arguments in two lower halves. In contrast, approach 1 adds a separate wrapper
for each syscall that takes care of both sign-extending where necessary and
zero-extending all othe 32-bit arguments but not the 64-bit arguments.

Arnd

2015-12-21 22:19:57

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v6 12/20] arm64:ilp32: add sys_ilp32.c and a separate table (in entry.S) to use it

On Monday 21 December 2015, Catalin Marinas wrote:
> On Fri, Dec 18, 2015 at 01:47:55PM +0100, Arnd Bergmann wrote:
> > On Friday 18 December 2015 11:42:19 Catalin Marinas wrote:
> > > 2. Follow the PCS up to glibc and get glibc to zero the top part (not
> > > always safe with hand-written assembly, though we already do this for
> > > AArch32 where the PCS only specifies 4 arguments in registers, the
> > > rest go on the stack)
> >
> > I assume this needs special handling for syscalls with 64-bit arguments
> > in both glibc and kernel.
>
> I think glibc only should suffice, if it is its responsibility to zero
> the top 32-bit part.

The kernel still needs to know about whether to call e.g. sys_llseek or
sys_lseek. The default syscall table contains llseek for 32-bit architectures,
but the current patch set uses lseek because that makes more sense when
you have 64-bit registers.

> > > 3. Follow the PCS up to glibc but always pass syscall arguments in W
> > > registers, like AArch32 compat support (the least preferred option,
> > > the only advantage is a single wrapper for all syscalls but it would
> > > be doing unnecessary zeroing even for syscalls where it isn't needed)
> >
> > This would mean we cannot pass 64-bit arguments in registers, right?
>
> Not in a single register but two (like we do on AArch32).

Yes, that's what I mean. Essentially we'd use the unmodified 32-bit API
here.

> > > My preference, as stated above, is (1). You can write the wrappers in C
> > > directly and let the compiler upgrade the types when calling the native
> > > syscall. But any other option would be fine (take some inspiration from
> > > other architectures). Unfortunately we don't have COMPAT_SYSCALL_DEFINE
> > > for all functions that we need to wrap, it would have been easier (so we
> > > need to add them but probably in the arch/arm64 code).
> >
> > It would be nice to have that code architecture-independent, so we can
> > share it with s390 and only need to update one place when new syscalls
> > get added.
>
> We could indeed move things like:
>
> COMPAT_SYSCALL_DEFINE3(s390_read, unsigned int, fd, char __user *, buf, compat_size_t, count)
>
> to the core code and share them between s390 and arm64/ILP32. So let's
> stick to option 1.

Ok.

Arnd

2015-12-21 22:33:26

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v6 12/20] arm64:ilp32: add sys_ilp32.c and a separate table (in entry.S) to use it

On Tuesday 15 December 2015, Yury Norov wrote:
> +
> +#define compat_sys_open_by_handle_at sys_open_by_handle_at
> +#define compat_sys_openat sys_openat
> +

One more thing I just remembered: I think we want this behavior for all new
32-bit architectures, it was a bug to call compat_sys_openat for the generic
syscall table, as we don't support 32-bit off_t.

Could you split this out into a separate patch that does these changes:

- change the default asm-generic/unistd.h to use sys_openat/sys_open_by_handle_at
- change tile to override those two to keep the current (suboptimal) behavior
- change the force_o_largefile() definition so it defaults to true for all future
architectures. The easiest way is probably to add a Kconfig symbol for this
that gets selected by all 32-bit architectures, so we can use

#define force_o_largefile() ((BITS_PER_LONG != 32) || !IS_ENABLED(CONFIG_ARCH_32BIT_OFF_T))

Arnd

2015-12-22 12:25:22

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v6 13/20] arm64: ilp32: share aarch32 syscall wrappers to ilp32

On Wed, Dec 16, 2015 at 12:42:39AM +0300, Yury Norov wrote:
> statfs64, fstat64 and mmap_pgoff has wrappers that needed both by aarch32 and
> ilp32 to workaround some issues. Here we create common file to share aarch32
> workarounds to with ilp32 code.
[...]
> --- /dev/null
> +++ b/arch/arm64/kernel/entry32-common.S
> @@ -0,0 +1,37 @@
> +#include <linux/linkage.h>
> +#include <linux/const.h>
> +
> +#include <asm/assembler.h>
> +#include <asm/asm-offsets.h>
> +#include <asm/errno.h>
> +#include <asm/page.h>
> +
> +ENTRY(compat_sys_statfs64_wrapper)
> + mov w3, #84
> + cmp w1, #88
> + csel w1, w3, w1, eq
> + b compat_sys_statfs64
> +ENDPROC(compat_sys_statfs64_wrapper)
> +
> +ENTRY(compat_sys_fstatfs64_wrapper)
> + mov w3, #84
> + cmp w1, #88
> + csel w1, w3, w1, eq
> + b compat_sys_fstatfs64
> +ENDPROC(compat_sys_fstatfs64_wrapper)

I'm not convinced we need these wrappers for ILP32. They've been
introduced on arch/arm many years ago by commit Fixes: 713c481519f1
([ARM] 3108/2: old ABI compat: statfs64 and fstatfs64) to deal with user
space passing a size of 88 (the EABI size of struct compat_statfs64
without the packing and alignment attribute). Since that commit, the
sizeof(struct compat_statfs64) is 84 already. This should be the case
with the new ILP32 exported headers (no backwards compatibility), so
user space should never pass 88 as size. Therefore we could call
compat_sys_(f)statfs64 directly without wrappers.

--
Catalin

2015-12-22 14:29:29

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v6 16/20] arm64: signal32: move ilp32 and aarch32 common code to separated file

On Wed, Dec 16, 2015 at 12:42:42AM +0300, Yury Norov wrote:
> diff --git a/arch/arm64/kernel/signal32_common.c b/arch/arm64/kernel/signal32_common.c
> new file mode 100644
> index 0000000..446c7c0
> --- /dev/null
> +++ b/arch/arm64/kernel/signal32_common.c
> @@ -0,0 +1,116 @@
> +/*
> + * Based on arch/arm/kernel/signal.c
> + *
> + * Copyright (C) 1995-2009 Russell King
> + * Copyright (C) 2012 ARM Ltd.
> + * Copyright (C) 2015 Cavium Metworks.

I mentioned this before - moving unmodified code around shouldn't grant
Cavium new rights (but IANAL).

--
Catalin

2015-12-22 17:11:10

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v6 17/20] arm64: ilp32: introduce ilp32-specific handlers for sigframe

On Wed, Dec 16, 2015 at 12:42:43AM +0300, Yury Norov wrote:
> diff --git a/arch/arm64/kernel/entry_ilp32.S b/arch/arm64/kernel/entry_ilp32.S
> new file mode 100644
> index 0000000..424060f
> --- /dev/null
> +++ b/arch/arm64/kernel/entry_ilp32.S
> @@ -0,0 +1,32 @@
> +/*
> + * ILP32 system call wrappers
> + *
> + * Copyright (C) 2015 Cavium Networks.
> + * Author: Yury Norov <[email protected]>
> + *
> + * 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/>.
> + */
> +
> +#include <linux/linkage.h>
> +#include <linux/const.h>
> +
> +#include <asm/assembler.h>
> +#include <asm/asm-offsets.h>
> +#include <asm/errno.h>
> +#include <asm/page.h>
> +
> +ENTRY(ilp32_sys_rt_sigreturn_wrapper)
> + mov x0, sp
> + b ilp32_sys_rt_sigreturn
> +ENDPROC(ilp32_sys_rt_sigreturn_wrapper)

Do you need all these header includes?

> diff --git a/arch/arm64/kernel/signal_ilp32.c b/arch/arm64/kernel/signal_ilp32.c
> new file mode 100644
> index 0000000..d38434b
> --- /dev/null
> +++ b/arch/arm64/kernel/signal_ilp32.c
> @@ -0,0 +1,126 @@
> +/*
> + * Based on arch/arm/kernel/signal.c
> + *
> + * Copyright (C) 2015 Cavium Networks.

And missing extra copyright lines.

> + * Yury Norov <[email protected]>
> + *
> + * 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/>.
> + */
> +
> +#include <linux/compat.h>
> +#include <linux/signal.h>
> +#include <linux/syscalls.h>
> +#include <linux/ratelimit.h>
> +
> +#include <asm/esr.h>
> +#include <asm/fpsimd.h>
> +#include <asm/signal32_common.h>
> +#include <asm/signal_common.h>
> +#include <asm/uaccess.h>
> +#include <asm/unistd.h>
> +#include <asm/ucontext.h>
> +
> +struct ilp32_rt_sigframe {
> + struct compat_siginfo info;
> + struct sigframe sig;
> +};
> +
> +asmlinkage int ilp32_sys_rt_sigreturn(struct pt_regs *regs)
> +{
> + struct ilp32_rt_sigframe __user *frame;
> +
> + /* Always make any pending restarted system calls return -EINTR */
> + current->restart_block.fn = do_no_restart_syscall;
> +
> + /*
> + * Since we stacked the signal on a 64-bit boundary,
> + * then 'sp' should be word aligned here. If it's
> + * not, then the user is trying to mess with us.
> + */

The stack alignment is still 128-bit even with ILP32 (architecture
requirement).

> + if (regs->sp & 15)
> + goto badframe;

The check here is correct though.

--
Catalin

2015-12-22 17:12:08

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v6 15/20] arm64: signal: move ilp32 and lp64 common code to separated file

On Wed, Dec 16, 2015 at 12:42:41AM +0300, Yury Norov wrote:
> After that, it will be possible to reuse it in ILP32.
>
> Signed-off-by: Yury Norov <[email protected]>
> ---
> arch/arm64/include/asm/signal_common.h | 39 ++++++++
> arch/arm64/kernel/Makefile | 2 +-
> arch/arm64/kernel/signal.c | 154 +----------------------------
> arch/arm64/kernel/signal_common.c | 174 +++++++++++++++++++++++++++++++++

signal.c is always compiled, so I don't see the point of a
signal_common.c, just export the functions from signal.c
(signal32_common.c is a different story since we may not always compile
AArch32 support in).

--
Catalin

2015-12-22 21:45:15

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v6 13/20] arm64: ilp32: share aarch32 syscall wrappers to ilp32

On Tuesday 22 December 2015, Catalin Marinas wrote:
> > +
> > +ENTRY(compat_sys_statfs64_wrapper)
> > + mov w3, #84
> > + cmp w1, #88
> > + csel w1, w3, w1, eq
> > + b compat_sys_statfs64
> > +ENDPROC(compat_sys_statfs64_wrapper)
> > +
> > +ENTRY(compat_sys_fstatfs64_wrapper)
> > + mov w3, #84
> > + cmp w1, #88
> > + csel w1, w3, w1, eq
> > + b compat_sys_fstatfs64
> > +ENDPROC(compat_sys_fstatfs64_wrapper)
>
> I'm not convinced we need these wrappers for ILP32. They've been
> introduced on arch/arm many years ago by commit Fixes: 713c481519f1
> ([ARM] 3108/2: old ABI compat: statfs64 and fstatfs64) to deal with user
> space passing a size of 88 (the EABI size of struct compat_statfs64
> without the packing and alignment attribute). Since that commit, the
> sizeof(struct compat_statfs64) is 84 already. This should be the case
> with the new ILP32 exported headers (no backwards compatibility), so
> user space should never pass 88 as size. Therefore we could call
> compat_sys_(f)statfs64 directly without wrappers.

That means we have to set ARCH_PACK_STATFS64 in the arm64 header files
though, and propagate the OABI alignment to arm64/ilp32 as well, rather
than using the 88-byte version that every other 32-bit architecture
except for x86-32 and arm32 has.

Another option would be to set "#define __statfs_word __u64" and use
the 64-bit statfs call, instead of compat_sys_statfs64, but that in turn
requires special-casing statfs in libc.

Arnd

2015-12-23 04:24:20

by Yury Norov

[permalink] [raw]
Subject: Re: [PATCH v6 13/20] arm64: ilp32: share aarch32 syscall wrappers to ilp32

On Tue, Dec 22, 2015 at 12:25:15PM +0000, Catalin Marinas wrote:
> On Wed, Dec 16, 2015 at 12:42:39AM +0300, Yury Norov wrote:
> > statfs64, fstat64 and mmap_pgoff has wrappers that needed both by aarch32 and
> > ilp32 to workaround some issues. Here we create common file to share aarch32
> > workarounds to with ilp32 code.
> [...]
> > --- /dev/null
> > +++ b/arch/arm64/kernel/entry32-common.S
> > @@ -0,0 +1,37 @@
> > +#include <linux/linkage.h>
> > +#include <linux/const.h>
> > +
> > +#include <asm/assembler.h>
> > +#include <asm/asm-offsets.h>
> > +#include <asm/errno.h>
> > +#include <asm/page.h>
> > +
> > +ENTRY(compat_sys_statfs64_wrapper)
> > + mov w3, #84
> > + cmp w1, #88
> > + csel w1, w3, w1, eq
> > + b compat_sys_statfs64
> > +ENDPROC(compat_sys_statfs64_wrapper)
> > +
> > +ENTRY(compat_sys_fstatfs64_wrapper)
> > + mov w3, #84
> > + cmp w1, #88
> > + csel w1, w3, w1, eq
> > + b compat_sys_fstatfs64
> > +ENDPROC(compat_sys_fstatfs64_wrapper)
>
> I'm not convinced we need these wrappers for ILP32. They've been
> introduced on arch/arm many years ago by commit Fixes: 713c481519f1
> ([ARM] 3108/2: old ABI compat: statfs64 and fstatfs64) to deal with user
> space passing a size of 88 (the EABI size of struct compat_statfs64
> without the packing and alignment attribute). Since that commit, the
> sizeof(struct compat_statfs64) is 84 already. This should be the case
> with the new ILP32 exported headers (no backwards compatibility), so
> user space should never pass 88 as size. Therefore we could call
> compat_sys_(f)statfs64 directly without wrappers.
>

With current glibc, sizeof(struct compat_statfs64) is 88, so I added
wrappers just to make this couple of syscalls work. AFAIR, glibc
doesn't use exported headers here, so we'd change it. Maybe Andrew
will share more details.

> --
> Catalin

2015-12-23 13:37:44

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v6 13/20] arm64: ilp32: share aarch32 syscall wrappers to ilp32

On Tue, Dec 22, 2015 at 10:44:14PM +0100, Arnd Bergmann wrote:
> On Tuesday 22 December 2015, Catalin Marinas wrote:
> > > +
> > > +ENTRY(compat_sys_statfs64_wrapper)
> > > + mov w3, #84
> > > + cmp w1, #88
> > > + csel w1, w3, w1, eq
> > > + b compat_sys_statfs64
> > > +ENDPROC(compat_sys_statfs64_wrapper)
> > > +
> > > +ENTRY(compat_sys_fstatfs64_wrapper)
> > > + mov w3, #84
> > > + cmp w1, #88
> > > + csel w1, w3, w1, eq
> > > + b compat_sys_fstatfs64
> > > +ENDPROC(compat_sys_fstatfs64_wrapper)
> >
> > I'm not convinced we need these wrappers for ILP32. They've been
> > introduced on arch/arm many years ago by commit Fixes: 713c481519f1
> > ([ARM] 3108/2: old ABI compat: statfs64 and fstatfs64) to deal with user
> > space passing a size of 88 (the EABI size of struct compat_statfs64
> > without the packing and alignment attribute). Since that commit, the
> > sizeof(struct compat_statfs64) is 84 already. This should be the case
> > with the new ILP32 exported headers (no backwards compatibility), so
> > user space should never pass 88 as size. Therefore we could call
> > compat_sys_(f)statfs64 directly without wrappers.
>
> That means we have to set ARCH_PACK_STATFS64 in the arm64 header files
> though, and propagate the OABI alignment to arm64/ilp32 as well, rather
> than using the 88-byte version that every other 32-bit architecture
> except for x86-32 and arm32 has.

Yuri replied that for EABI glibc, sizeof(struct statfs64) is already 88.
If that's correct and the packing attribute is ignored by glibc, we
could drop ARCH_PACK_COMPAT_STATFS64 as well (OABI not supported by
arm64). But I would be slightly worried since glibc is not the only user
of the kernel ABI.

For ILP32, I think we can skip defining ARCH_PACK_STATFS64 (of course,
only if __ILP32__) and state that sizeof(struct statfs64) is 88
(unpacked). In which case we need the wrappers above to be able to reuse
the compat_sys_statfs64 code.

> Another option would be to set "#define __statfs_word __u64" and use
> the 64-bit statfs call, instead of compat_sys_statfs64, but that in turn
> requires special-casing statfs in libc.

I wouldn't go this route as we kind of agreed that ILP32 should look
like any other 32-bit ABI.

--
Catalin

2015-12-23 14:18:34

by Yury Norov

[permalink] [raw]
Subject: Re: [PATCH v6 04/20] arm64: change some CONFIG_COMPAT over to use CONFIG_AARCH32_EL0 instead

On Wed, Dec 16, 2015 at 12:42:30AM +0300, Yury Norov wrote:
> --- a/arch/arm64/include/asm/unistd.h
> +++ b/arch/arm64/include/asm/unistd.h
> @@ -13,9 +13,8 @@
> * You should have received a copy of the GNU General Public License
> * along with this program. If not, see <http://www.gnu.org/licenses/>.
> */
> -#ifdef CONFIG_COMPAT
> +#ifdef CONFIG_AARCH32_EL0
> #define __ARCH_WANT_COMPAT_SYS_GETDENTS64
> -#define __ARCH_WANT_COMPAT_STAT64
> #define __ARCH_WANT_SYS_GETHOSTNAME
> #define __ARCH_WANT_SYS_PAUSE
> #define __ARCH_WANT_SYS_GETPGRP
> @@ -26,7 +25,9 @@
> #define __ARCH_WANT_COMPAT_SYS_SENDFILE
> #define __ARCH_WANT_SYS_FORK
> #define __ARCH_WANT_SYS_VFORK
> +#endif
>
> +#ifdef CONFIG_COMPAT

It seems like __NR_compat_* and __ARM_NR_compat_*
are needed by aarch32 only. If so, it should not be
defined for ilp32. And the only common definition
here would be __ARCH_WANT_COMPAT_STAT64.

> /*
> * Compat syscall numbers used by the AArch64 kernel.
> */
> @@ -44,6 +45,8 @@
> #define __ARM_NR_compat_cacheflush (__ARM_NR_COMPAT_BASE+2)
> #define __ARM_NR_compat_set_tls (__ARM_NR_COMPAT_BASE+5)
>
> +#define __ARCH_WANT_COMPAT_STAT64
> +
> #define __NR_compat_syscalls 390
> #endif

2015-12-23 18:32:21

by Yury Norov

[permalink] [raw]
Subject: Re: [PATCH v6 12/20] arm64:ilp32: add sys_ilp32.c and a separate table (in entry.S) to use it

On Mon, Dec 21, 2015 at 11:31:57PM +0100, Arnd Bergmann wrote:
> On Tuesday 15 December 2015, Yury Norov wrote:
> > +
> > +#define compat_sys_open_by_handle_at sys_open_by_handle_at
> > +#define compat_sys_openat sys_openat
> > +
>
> One more thing I just remembered: I think we want this behavior for all new
> 32-bit architectures, it was a bug to call compat_sys_openat for the generic
> syscall table, as we don't support 32-bit off_t.
>
> Could you split this out into a separate patch that does these changes:
>
> - change the default asm-generic/unistd.h to use sys_openat/sys_open_by_handle_at
> - change tile to override those two to keep the current (suboptimal) behavior
> - change the force_o_largefile() definition so it defaults to true for all future
> architectures. The easiest way is probably to add a Kconfig symbol for this
> that gets selected by all 32-bit architectures, so we can use
>
> #define force_o_largefile() ((BITS_PER_LONG != 32) || !IS_ENABLED(CONFIG_ARCH_32BIT_OFF_T))
>

Hi Arnd,

First two items are OK. The last one... Do you need it to remove
compat_sys_openat and compat_sys_open_by_handle_at?

The patch that introduces CONFIG_ARCH_32BIT_OFF_T will affect all
architectures, and so I need to get ack from each maintainer.

I will also have to ask them to test that change, because I have no
access to all the hardware. (Even with QEMU, I cannot test them all.)
I think the only man who is able to success with it is Linus :)...

Some arches has more than one compat mode. For example ARM64: aarch32
requires this config enabled, but ilp32 needs it disabled. Now we can
enable both features, but this will make them mutual exclusive. We can
instead (un)define __ARCH_WANT_32BIT_OFF_T for each ABI of each platform,
but it's even more work. And we'd think twice how to do it because
it's not mechanical work. For example, on aarch64 it will look like:

#define __ARCH_WANT_32BIT_OFF_T is_a32_compat_task()

I have no idea how it will look on x86 or ppc.

In your previous email (Nov 18) you write that tile is the only user
of asm-generic/unistd.h that needs compat behaviour. If so, why not
just to turn it around, as you initially suggested, and fix tile. And
do nothing with force_o_largefile()?

By the way, is there a comprehensive list of linux platforms/abis, or
at least ones that use asm-generic/unistd.h?

BR,
Yury.

> Arnd
>
> _______________________________________________
> linux-arm-kernel mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

2015-12-23 20:43:15

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v6 13/20] arm64: ilp32: share aarch32 syscall wrappers to ilp32

On Wednesday 23 December 2015, Catalin Marinas wrote:
> > That means we have to set ARCH_PACK_STATFS64 in the arm64 header files
> > though, and propagate the OABI alignment to arm64/ilp32 as well, rather
> > than using the 88-byte version that every other 32-bit architecture
> > except for x86-32 and arm32 has.
>
> Yuri replied that for EABI glibc, sizeof(struct statfs64) is already 88.
> If that's correct and the packing attribute is ignored by glibc, we
> could drop ARCH_PACK_COMPAT_STATFS64 as well (OABI not supported by
> arm64). But I would be slightly worried since glibc is not the only user
> of the kernel ABI.

It looks like glibc has its own definition of 'struct statfs64', which
is incompatible with the one in the kernel headers for ARM EABI.

However, there are other libc implementations besides glibc, and we
can't assume that they all do it the same way, so we clearly have to
keep using the wrapper for ARM EABI. For ARM64/ILP32, we are probably
better off defining it the same way in kernel and libc without that
wrapper.

> For ILP32, I think we can skip defining ARCH_PACK_STATFS64 (of course,
> only if __ILP32__) and state that sizeof(struct statfs64) is 88
> (unpacked). In which case we need the wrappers above to be able to reuse
> the compat_sys_statfs64 code.
>
> > Another option would be to set "#define __statfs_word __u64" and use
> > the 64-bit statfs call, instead of compat_sys_statfs64, but that in turn
> > requires special-casing statfs in libc.
>
> I wouldn't go this route as we kind of agreed that ILP32 should look
> like any other 32-bit ABI.

It's really tricky then: in order to support EABI binaries from a libc
that uses the kernel headers with the OABI compatible definition, we
must not copy the 88 byte structure to user space, because that would
overwrite user space stack data, and that in turn means we have to set
ARCH_PACK_COMPAT_STATFS64, but that in turn prevents us from using the
generic 32-bit syscall ABI for the arm64/ilp32 fstatfs64 call.

It seems that today, put_compat_statfs64() doesn't actually use
the size argument, and it just copies the individual fields, which
is fine either way. This means we could turn around the logic
in the arm32 wrapper, remove ARCH_PACK_COMPAT_STATFS64, and make
the ilp32 code call directly into compat_sys_fstatfs64(), but it
would be a bit fragile, as we rely on put_compat_statfs64() not
actually writing the padding fields that the native do_statfs64()
writes. If someone changed them to both use copy_to_user, we'd
silently introduce data corruption on rarely used libc implementations.

Arnd

2015-12-23 21:49:45

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v6 12/20] arm64:ilp32: add sys_ilp32.c and a separate table (in entry.S) to use it

On Wednesday 23 December 2015, Yury Norov wrote:
> On Mon, Dec 21, 2015 at 11:31:57PM +0100, Arnd Bergmann wrote:
> > On Tuesday 15 December 2015, Yury Norov wrote:
> > > +
> > > +#define compat_sys_open_by_handle_at sys_open_by_handle_at
> > > +#define compat_sys_openat sys_openat
> > > +
> >
> > One more thing I just remembered: I think we want this behavior for all new
> > 32-bit architectures, it was a bug to call compat_sys_openat for the generic
> > syscall table, as we don't support 32-bit off_t.
> >
> > Could you split this out into a separate patch that does these changes:
> >
> > - change the default asm-generic/unistd.h to use sys_openat/sys_open_by_handle_at
> > - change tile to override those two to keep the current (suboptimal) behavior
> > - change the force_o_largefile() definition so it defaults to true for all future
> > architectures. The easiest way is probably to add a Kconfig symbol for this
> > that gets selected by all 32-bit architectures, so we can use
> >
> > #define force_o_largefile() ((BITS_PER_LONG != 32) || !IS_ENABLED(CONFIG_ARCH_32BIT_OFF_T))
> >
>
> Hi Arnd,
>
> First two items are OK. The last one... Do you need it to remove
> compat_sys_openat and compat_sys_open_by_handle_at?

It's needed so all future architectures get it right.

> The patch that introduces CONFIG_ARCH_32BIT_OFF_T will affect all
> architectures, and so I need to get ack from each maintainer.

Just post it to the linux-arch and linux-kernel mailing lists.
You are not actually changing behavior, so my Ack should be sufficient
here, as long as we make sure we handle all architectures the same
way.

> I will also have to ask them to test that change, because I have no
> access to all the hardware. (Even with QEMU, I cannot test them all.)
> I think the only man who is able to success with it is Linus :)...
>
> Some arches has more than one compat mode. For example ARM64: aarch32
> requires this config enabled, but ilp32 needs it disabled. Now we can
> enable both features, but this will make them mutual exclusive. We can
> instead (un)define __ARCH_WANT_32BIT_OFF_T for each ABI of each platform,
> but it's even more work. And we'd think twice how to do it because
> it's not mechanical work. For example, on aarch64 it will look like:
>
> #define __ARCH_WANT_32BIT_OFF_T is_a32_compat_task()
>
> I have no idea how it will look on x86 or ppc.

arm64 is not affected at all, because it's a 64-bit-only architecture
and force_o_largefile() already returns true here.

> In your previous email (Nov 18) you write that tile is the only user
> of asm-generic/unistd.h that needs compat behaviour. If so, why not
> just to turn it around, as you initially suggested, and fix tile. And
> do nothing with force_o_largefile()?

The first two of the three changes I listed above are for the
compat ABI, and there it is enough to change tile.

The third change has nothing to do with compat mode, but is about
native 32-bit architectures. However, we should change both in sync,
so the next architecture that gets added with both native 32-bit
mode and compat 32-bit mode on a 64-bit kernel behaves the same
way for all 32-bit user space, independent of what the kernel does.

We can have two separate patches to clarify that these don't have to
be done atomically, but we need to do both for consistency.

> By the way, is there a comprehensive list of linux platforms/abis, or
> at least ones that use asm-generic/unistd.h?

Just the source code.

Arnd

2015-12-28 08:43:42

by Bamvor Zhang Jian

[permalink] [raw]
Subject: > diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile

I feel we need something like this to avoid the failure of compiling
when build with ARM64_ILP32(which will select COMPAT) and
ARMV8_DEPRECATED (which depends on the opcodes.o).

>From f8b8ffdb449491ecf8ba465238bbdb4625a74ac0 Mon Sep 17 00:00:00 2001
From: Bamvor Jian Zhang <[email protected]>
Date: Mon, 28 Dec 2015 12:57:46 +0800
Subject: [PATCH] arm64: compat: fix wrong dependency of ARMV8_DEPRECATED

When compile with ARM64_ILP32, ARMV8_DEPRECATED will be selected due
to the dependency of COMPAT. It leads to the following error:
LD init/built-in.o
arch/arm64/kernel/built-in.o: In function `cp15barrier_handler':
/home/bamvor/works/source/kernel/linux_ilp32/arch/arm64/kernel/armv8_deprecated.c:467: undefined reference to `arm_check_condition'
/home/bamvor/works/source/kernel/linux_ilp32/arch/arm64/kernel/armv8_deprecated.c:467: undefined reference to `arm_check_condition'
arch/arm64/kernel/built-in.o: In function `swp_handler':
/home/bamvor/works/source/kernel/linux_ilp32/arch/arm64/kernel/armv8_deprecated.c:386: undefined reference to `arm_check_condition'
/home/bamvor/works/source/kernel/linux_ilp32/arch/arm64/kernel/armv8_deprecated.c:386: undefined reference to `arm_check_condition'
Makefile:927: recipe for target 'vmlinux' failed
make: *** [vmlinux] Error 1

This patch fix this by updating the dependency from COMPAT to
AARCH32_EL0.

Signed-off-by: Bamvor Jian Zhang <[email protected]>
---
arch/arm64/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index deec37a..e52fd03 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -509,7 +509,7 @@ config FORCE_MAX_ZONEORDER

menuconfig ARMV8_DEPRECATED
bool "Emulate deprecated/obsolete ARMv8 instructions"
- depends on COMPAT
+ depends on AARCH32_EL0
help
Legacy software support may require certain instructions
that have been deprecated or obsoleted in the architecture.
--
2.1.4

2015-12-28 09:01:44

by Zhangjian (Bamvor)

[permalink] [raw]
Subject: Re: [PATCH v6 04/20] arm64: change some CONFIG_COMPAT over to use CONFIG_AARCH32_EL0 instead

Fix the title.

On 16:43 2015/12/28, Bamvor Jian Zhang wrote:
> I feel we need something like this to avoid the failure of compiling
> when build with ARM64_ILP32(which will select COMPAT) and
> ARMV8_DEPRECATED (which depends on the opcodes.o).
>
> From f8b8ffdb449491ecf8ba465238bbdb4625a74ac0 Mon Sep 17 00:00:00 2001
> From: Bamvor Jian Zhang <[email protected]>
> Date: Mon, 28 Dec 2015 12:57:46 +0800
> Subject: [PATCH] arm64: compat: fix wrong dependency of ARMV8_DEPRECATED
>
> When compile with ARM64_ILP32, ARMV8_DEPRECATED will be selected due
> to the dependency of COMPAT. It leads to the following error:
> LD init/built-in.o
> arch/arm64/kernel/built-in.o: In function `cp15barrier_handler':
> /home/bamvor/works/source/kernel/linux_ilp32/arch/arm64/kernel/armv8_deprecated.c:467: undefined reference to `arm_check_condition'
> /home/bamvor/works/source/kernel/linux_ilp32/arch/arm64/kernel/armv8_deprecated.c:467: undefined reference to `arm_check_condition'
> arch/arm64/kernel/built-in.o: In function `swp_handler':
> /home/bamvor/works/source/kernel/linux_ilp32/arch/arm64/kernel/armv8_deprecated.c:386: undefined reference to `arm_check_condition'
> /home/bamvor/works/source/kernel/linux_ilp32/arch/arm64/kernel/armv8_deprecated.c:386: undefined reference to `arm_check_condition'
> Makefile:927: recipe for target 'vmlinux' failed
> make: *** [vmlinux] Error 1
>
> This patch fix this by updating the dependency from COMPAT to
> AARCH32_EL0.
>
> Signed-off-by: Bamvor Jian Zhang <[email protected]>
> ---
> arch/arm64/Kconfig | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index deec37a..e52fd03 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -509,7 +509,7 @@ config FORCE_MAX_ZONEORDER
>
> menuconfig ARMV8_DEPRECATED
> bool "Emulate deprecated/obsolete ARMv8 instructions"
> - depends on COMPAT
> + depends on AARCH32_EL0
> help
> Legacy software support may require certain instructions
> that have been deprecated or obsoleted in the architecture.
>

2015-12-29 12:31:59

by Yury Norov

[permalink] [raw]
Subject: Re: [PATCH v6 04/20] arm64: change some CONFIG_COMPAT over to use CONFIG_AARCH32_EL0 instead

On Mon, Dec 28, 2015 at 05:01:15PM +0800, Zhangjian (Bamvor) wrote:
> Fix the title.
>
> On 16:43 2015/12/28, Bamvor Jian Zhang wrote:
> >I feel we need something like this to avoid the failure of compiling
> >when build with ARM64_ILP32(which will select COMPAT) and
> >ARMV8_DEPRECATED (which depends on the opcodes.o).
> >
> > From f8b8ffdb449491ecf8ba465238bbdb4625a74ac0 Mon Sep 17 00:00:00 2001
> >From: Bamvor Jian Zhang <[email protected]>
> >Date: Mon, 28 Dec 2015 12:57:46 +0800
> >Subject: [PATCH] arm64: compat: fix wrong dependency of ARMV8_DEPRECATED
> >
> >When compile with ARM64_ILP32, ARMV8_DEPRECATED will be selected due
> >to the dependency of COMPAT. It leads to the following error:
> > LD init/built-in.o
> > arch/arm64/kernel/built-in.o: In function `cp15barrier_handler':
> > /home/bamvor/works/source/kernel/linux_ilp32/arch/arm64/kernel/armv8_deprecated.c:467: undefined reference to `arm_check_condition'
> > /home/bamvor/works/source/kernel/linux_ilp32/arch/arm64/kernel/armv8_deprecated.c:467: undefined reference to `arm_check_condition'
> > arch/arm64/kernel/built-in.o: In function `swp_handler':
> > /home/bamvor/works/source/kernel/linux_ilp32/arch/arm64/kernel/armv8_deprecated.c:386: undefined reference to `arm_check_condition'
> > /home/bamvor/works/source/kernel/linux_ilp32/arch/arm64/kernel/armv8_deprecated.c:386: undefined reference to `arm_check_condition'
> > Makefile:927: recipe for target 'vmlinux' failed
> > make: *** [vmlinux] Error 1
> >
> >This patch fix this by updating the dependency from COMPAT to
> >AARCH32_EL0.
> >
> >Signed-off-by: Bamvor Jian Zhang <[email protected]>
> >---
> > arch/arm64/Kconfig | 2 +-
> > 1 file changed, 1 insertion(+), 1 deletion(-)
> >
> >diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> >index deec37a..e52fd03 100644
> >--- a/arch/arm64/Kconfig
> >+++ b/arch/arm64/Kconfig
> >@@ -509,7 +509,7 @@ config FORCE_MAX_ZONEORDER
> >
> > menuconfig ARMV8_DEPRECATED
> > bool "Emulate deprecated/obsolete ARMv8 instructions"
> >- depends on COMPAT
> >+ depends on AARCH32_EL0
> > help
> > Legacy software support may require certain instructions
> > that have been deprecated or obsoleted in the architecture.
> >

Thanks for catch. I will incorporate it to next submission. I also
think, config ARM64_ERRATUM_845719 should depend on AARCH32_EL0 as
well.

2015-12-29 13:15:54

by Yury Norov

[permalink] [raw]
Subject: Re: [PATCH v6 04/20] arm64: change some CONFIG_COMPAT over to use CONFIG_AARCH32_EL0 instead

On Mon, Dec 28, 2015 at 05:01:15PM +0800, Zhangjian (Bamvor) wrote:
> Fix the title.

Hi,

Could you re-send your patch, as previous version has wrong subject,
and this - commented body. Or, I can just meld your change to patch #4.

Yury.

>
> On 16:43 2015/12/28, Bamvor Jian Zhang wrote:
> >I feel we need something like this to avoid the failure of compiling
> >when build with ARM64_ILP32(which will select COMPAT) and
> >ARMV8_DEPRECATED (which depends on the opcodes.o).
> >
> > From f8b8ffdb449491ecf8ba465238bbdb4625a74ac0 Mon Sep 17 00:00:00 2001
> >From: Bamvor Jian Zhang <[email protected]>
> >Date: Mon, 28 Dec 2015 12:57:46 +0800
> >Subject: [PATCH] arm64: compat: fix wrong dependency of ARMV8_DEPRECATED
> >
> >When compile with ARM64_ILP32, ARMV8_DEPRECATED will be selected due
> >to the dependency of COMPAT. It leads to the following error:
> > LD init/built-in.o
> > arch/arm64/kernel/built-in.o: In function `cp15barrier_handler':
> > /home/bamvor/works/source/kernel/linux_ilp32/arch/arm64/kernel/armv8_deprecated.c:467: undefined reference to `arm_check_condition'
> > /home/bamvor/works/source/kernel/linux_ilp32/arch/arm64/kernel/armv8_deprecated.c:467: undefined reference to `arm_check_condition'
> > arch/arm64/kernel/built-in.o: In function `swp_handler':
> > /home/bamvor/works/source/kernel/linux_ilp32/arch/arm64/kernel/armv8_deprecated.c:386: undefined reference to `arm_check_condition'
> > /home/bamvor/works/source/kernel/linux_ilp32/arch/arm64/kernel/armv8_deprecated.c:386: undefined reference to `arm_check_condition'
> > Makefile:927: recipe for target 'vmlinux' failed
> > make: *** [vmlinux] Error 1
> >
> >This patch fix this by updating the dependency from COMPAT to
> >AARCH32_EL0.
> >
> >Signed-off-by: Bamvor Jian Zhang <[email protected]>
> >---
> > arch/arm64/Kconfig | 2 +-
> > 1 file changed, 1 insertion(+), 1 deletion(-)
> >
> >diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> >index deec37a..e52fd03 100644
> >--- a/arch/arm64/Kconfig
> >+++ b/arch/arm64/Kconfig
> >@@ -509,7 +509,7 @@ config FORCE_MAX_ZONEORDER
> >
> > menuconfig ARMV8_DEPRECATED
> > bool "Emulate deprecated/obsolete ARMv8 instructions"
> >- depends on COMPAT
> >+ depends on AARCH32_EL0
> > help
> > Legacy software support may require certain instructions
> > that have been deprecated or obsoleted in the architecture.
> >

2015-12-29 15:00:44

by Bamvor Zhang Jian

[permalink] [raw]
Subject: [PATCH] arm64: compat: fix wrong dependency

With the patches of ILP32, COMPAT is not equivalent to AARCH32 in EL0.
This patch fix this by updating the dependency from COMPAT to
AARCH32_EL0 for ARMV8_DEPRECATED and ARM64_ERRATUM_845719.

Signed-off-by: Bamvor Jian Zhang <[email protected]>
---
arch/arm64/Kconfig | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index deec37a..7ea783b 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -313,7 +313,7 @@ config ARM64_ERRATUM_832075

config ARM64_ERRATUM_845719
bool "Cortex-A53: 845719: a load might read incorrect data"
- depends on COMPAT
+ depends on AARCH32_EL0
default y
help
This option adds an alternative code sequence to work around ARM
@@ -509,7 +509,7 @@ config FORCE_MAX_ZONEORDER

menuconfig ARMV8_DEPRECATED
bool "Emulate deprecated/obsolete ARMv8 instructions"
- depends on COMPAT
+ depends on AARCH32_EL0
help
Legacy software support may require certain instructions
that have been deprecated or obsoleted in the architecture.
--
2.1.4

2015-12-30 17:29:23

by Yury Norov

[permalink] [raw]
Subject: Re: [PATCH v6 13/20] arm64: ilp32: share aarch32 syscall wrappers to ilp32

On Wed, Dec 23, 2015 at 09:41:54PM +0100, Arnd Bergmann wrote:
> On Wednesday 23 December 2015, Catalin Marinas wrote:
> > > That means we have to set ARCH_PACK_STATFS64 in the arm64 header files
> > > though, and propagate the OABI alignment to arm64/ilp32 as well, rather
> > > than using the 88-byte version that every other 32-bit architecture
> > > except for x86-32 and arm32 has.
> >
> > Yuri replied that for EABI glibc, sizeof(struct statfs64) is already 88.
> > If that's correct and the packing attribute is ignored by glibc, we
> > could drop ARCH_PACK_COMPAT_STATFS64 as well (OABI not supported by
> > arm64). But I would be slightly worried since glibc is not the only user
> > of the kernel ABI.
>
> It looks like glibc has its own definition of 'struct statfs64', which
> is incompatible with the one in the kernel headers for ARM EABI.
>
> However, there are other libc implementations besides glibc, and we
> can't assume that they all do it the same way, so we clearly have to
> keep using the wrapper for ARM EABI. For ARM64/ILP32, we are probably
> better off defining it the same way in kernel and libc without that
> wrapper.
>
> > For ILP32, I think we can skip defining ARCH_PACK_STATFS64 (of course,
> > only if __ILP32__) and state that sizeof(struct statfs64) is 88
> > (unpacked). In which case we need the wrappers above to be able to reuse
> > the compat_sys_statfs64 code.
> >
> > > Another option would be to set "#define __statfs_word __u64" and use
> > > the 64-bit statfs call, instead of compat_sys_statfs64, but that in turn
> > > requires special-casing statfs in libc.
> >
> > I wouldn't go this route as we kind of agreed that ILP32 should look
> > like any other 32-bit ABI.
>
> It's really tricky then: in order to support EABI binaries from a libc
> that uses the kernel headers with the OABI compatible definition, we
> must not copy the 88 byte structure to user space, because that would
> overwrite user space stack data, and that in turn means we have to set
> ARCH_PACK_COMPAT_STATFS64, but that in turn prevents us from using the
> generic 32-bit syscall ABI for the arm64/ilp32 fstatfs64 call.
>
> It seems that today, put_compat_statfs64() doesn't actually use
> the size argument, and it just copies the individual fields, which
> is fine either way. This means we could turn around the logic
> in the arm32 wrapper, remove ARCH_PACK_COMPAT_STATFS64, and make
> the ilp32 code call directly into compat_sys_fstatfs64(), but it
> would be a bit fragile, as we rely on put_compat_statfs64() not
> actually writing the padding fields that the native do_statfs64()
> writes. If someone changed them to both use copy_to_user, we'd
> silently introduce data corruption on rarely used libc implementations.
>
> Arnd

So. For ilp32, the only wrapper left here, is compat_sys_mmap2_wrapper.
But this is workaroud, as comment tells:
Note: off_4k (w5) is always in units of 4K. If we can't do the
requested offset because it is not page-aligned, we return -EINVAL.

Not sure we should pull it to ILP32. If so, we can call sys_mmap_pgoff()
directly. And we don't need this patch at all therefore. Any throughts?

Yury.

2015-12-30 22:37:21

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v6 13/20] arm64: ilp32: share aarch32 syscall wrappers to ilp32

On Wednesday 30 December 2015 20:29:05 Yury Norov wrote:
>
> So. For ilp32, the only wrapper left here, is compat_sys_mmap2_wrapper.
> But this is workaroud, as comment tells:
> Note: off_4k (w5) is always in units of 4K. If we can't do the
> requested offset because it is not page-aligned, we return -EINVAL.
>
> Not sure we should pull it to ILP32. If so, we can call sys_mmap_pgoff()
> directly. And we don't need this patch at all therefore. Any throughts?
>
>

I think providing the 64-bit version of sys_mmap() would be the simplest
API, as that avoids any possible confusion about the shift amount (hardcoded
12 bits vs PAGE_BITS). It fits in with the other syscalls that pass an loff_t
value here.

Arnd