2015-04-13 20:14:06

by Philipp Tomsich

[permalink] [raw]
Subject: [PATCH v4 00/24] ILP32 for ARM64

This is an updated version of Andrew Pinski's ILP32 patch-series for ARM64
(see https://lkml.org/lkml/2014/9/3/704) which merges some changes from our
implementation of ILP32 with his.

I made sure to have Andrew as an author, wherever no significant
changes to his patches occurred and updated the author field on the
others, so it's easier for reviewers (and for Andrew) to track what
changed and what did not... we've also tried to address as outstanding
review comments against those patches if we were aware of those (as a
result and an exception to the aforementioned rule, some of original patches
may have been updated, even if we the below list doesn't make it apparent).

Note that we didn't resort to changing the time_t definition to 32bit for
ILP32 (related to https://sourceware.org/bugzilla/show_bug.cgi?id=16437).

This patch-series has been verified using LTP in a buildroot-environment
with no unexpected fails (note, that the io_submit test currently fails,
as we haven't updated the userspace data-structures in libaio for ILP32,
yet). There's a full set of matching changes to binutils, gdb, gcc, glibc,
strace, LTP and openssl (probably other packages,too) to be submitted, once
we have the kernel-level ABI changes committed.

If anybody wants to rerun LTP, let me know, so I can provide a
buildroot-generated rootfs-image via FTP.

The key differences from earlier changesets are:
* updated to 4.0
* fixes for functions using 'struct msgbuf' (using compat)
* deduplication of code by using a 32bit stack_t (using compat)
* updated the documentation to clarify the changes to stack_t
* introduced a sub-architecture (via COMPAT_ELF_PLATFORM) to make
life easier for tools (e.g. gdb) when attaching to a live process
(a corefile is easily distinguishable by being ELFCLASS32).

Any review comments are welcome.
--Phil.


Andrew Pinski (18):
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:ilp32: expose 'kernel_long' as 'long long' for ILP32
arm64:uapi: set __BITS_PER_LONG correctly for ILP32 and LP64
arm64:ilp32: share signal structures between ILP32 and LP64 ABIs
arm64:ilp32: use 64bit syscall-names for ILP32 when passing 64bit
registers
arm64:ilp32: use non-compat syscall names for ILP32 as for LP64
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: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: add support for starting ILP32 (ELFCLASS32) binaries
ptrace: Allow compat to use the native siginfo
arm64:ilp32: add sys_ilp32.c and a separate table (in entry.S) to use
it
arm64:ilp32: use the native siginfo instead of the compat siginfo
arm64:ilp32: add ARM64_ILP32 to Kconfig

Philipp Tomsich (6):
arm64:ilp32: add documentation on the ILP32 ABI for ARM64
arm64:ilp32: COMPAT_USE_64BIT_TIME is true for ILP32 tasks
arm64:ilp32: add vdso-ilp32 and use for signal return
arm64:ilp32: use compat-syscalls for msgsnd and msgrcv for ILP32
arm64:ilp32: use compat for stack_t
arm64:ilp32: change COMPAT_ELF_PLATFORM to report a a subplatform for
ILP32

Documentation/arm64/ilp32.txt | 64 ++++++++++++
arch/arm64/Kconfig | 15 ++-
arch/arm64/Makefile | 4 +
arch/arm64/include/asm/compat.h | 65 +++++++++++-
arch/arm64/include/asm/elf.h | 105 +++++++++++++++++---
arch/arm64/include/asm/fpsimd.h | 2 +-
arch/arm64/include/asm/hwcap.h | 12 ++-
arch/arm64/include/asm/memory.h | 2 +-
arch/arm64/include/asm/processor.h | 11 +-
arch/arm64/include/asm/ptrace.h | 2 +-
arch/arm64/include/asm/signal32.h | 2 +
arch/arm64/include/asm/stat.h | 2 +
arch/arm64/include/asm/thread_info.h | 3 +-
arch/arm64/include/asm/unistd.h | 6 +-
arch/arm64/include/asm/vdso.h | 4 +
arch/arm64/include/uapi/asm/bitsperlong.h | 9 +-
arch/arm64/include/uapi/asm/posix_types.h | 12 ++-
arch/arm64/include/uapi/asm/siginfo.h | 21 ++++
arch/arm64/include/uapi/asm/signal.h | 32 ++++++
arch/arm64/include/uapi/asm/unistd.h | 7 ++
arch/arm64/kernel/Makefile | 8 +-
arch/arm64/kernel/asm-offsets.c | 2 +-
arch/arm64/kernel/entry.S | 18 +++-
arch/arm64/kernel/head.S | 2 +-
arch/arm64/kernel/hw_breakpoint.c | 6 +-
arch/arm64/kernel/process.c | 6 +-
arch/arm64/kernel/ptrace.c | 49 ++++++---
arch/arm64/kernel/signal.c | 40 +++++++-
arch/arm64/kernel/sys_ilp32.c | 138 ++++++++++++++++++++++++++
arch/arm64/kernel/traps.c | 4 +-
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 | 98 ++++++++++++++++++
arch/arm64/kernel/vdso.c | 67 ++++++++++---
include/linux/compat.h | 4 +
include/uapi/asm-generic/siginfo.h | 17 +++-
include/uapi/asm-generic/signal.h | 27 ++++-
include/uapi/asm-generic/unistd.h | 5 +-
kernel/ptrace.c | 24 +++--
40 files changed, 913 insertions(+), 89 deletions(-)
create mode 100644 Documentation/arm64/ilp32.txt
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

--
1.9.1


2015-04-13 20:19:23

by Philipp Tomsich

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

Based on Andrew Pinski's original patch-series and adapted with changes
to reduce the duplication of code-paths and resolve issue found during
LTP testing.

Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
---
Documentation/arm64/ilp32.txt | 64 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 64 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..7524d06
--- /dev/null
+++ b/Documentation/arm64/ilp32.txt
@@ -0,0 +1,64 @@
+ILP32 AARCH64 SYSCALL ABI
+=========================
+Written by Andrew Pinski <[email protected]>
+Updated by Philipp Tomsich <[email protected]>
+
+
+This document describes the ILP32 syscall ABI and where it differs
+from the generic linux syscall interface.
+
+ILP32 sets __kernel_long_t and __kernel_ulong_t both to 64bit. This
+affects the following type definitions for ILP32 client programs:
+ * time_t unsigned long long
+ * clock_t unsigned long long
+ * fsword_t long long
+ * suseconds_t long long
+ * swblk_t long long
+ * fd_mask_t long long
+
+Some structures are changed to reduce the difference in the code path
+for both ILP32 and LP64 ABIs for signal handling.
+
+The following structures have been changed so the layout of the
+structures are the same between ILP32 and LP64 ABIs, including:
+ * timespec uses time_t and suseconds_t
+ * timeval uses time_t and suseconds_t
+ * stat uses timespec/time_t
+ * semid64_ds uses time_t.
+ * msqid64_ds uses time_t.
+ * shmid64_ds uses time_t.
+ * rt_sigframe uses siginfo and ucontext.
+ * siginfo_t uses clock_t and sigval_t
+ * ucontext uses stack_t and sigset_t
+ * sigval_t contains pointers
+ * sigevent Uses sigval_t which causes it to be the same. Special
+ handing is needed for reading; in the mq_notify syscall
+ * sigaction Conversion is handled in the userland (glibc), as the
+ userland data structures are defined in glibc anyway.
+ * fd_set This is done to avoid endian issues between ILP32 and
+ LP64. Syscalls consuming fd_set use timespec.
+
+A number of structures differ between ILP32 and LP64, including:
+ * struct msgbuf The specification of 'struct msgbuf' defines the 'mtype'
+ field as a 'long' (i.e. 32bit for ILP32, but 64bit for
+ LP64). Functions that operate on 'struct msgbuf' need
+ to be passed through the compat-syscalls to resolve
+ this.
+ * stack_t contains pointers (handled in the compatibility layer)
+
+Also the syscalls which normally would pass 64bit values as two arguments;
+now pass the 64bit value as one argument. Also they have been renamed
+(removing the 64 from the name) to avoid confusion.
+The list of these LP64 syscalls reused by ILP32 clients is:
+ * fcntl
+ * statfs
+ * fstatfs
+ * truncate
+ * ftruncate
+ * lseek
+ * sendfile
+ * newfstatat
+ * fstat
+ * mmap
+ * fadvise64
+
--
1.9.1

2015-04-13 20:17:06

by Philipp Tomsich

[permalink] [raw]
Subject: [PATCH v4 02/24] 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).

Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
---
arch/arm64/Makefile | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
index 69ceedc..2ad0c34 100644
--- a/arch/arm64/Makefile
+++ b/arch/arm64/Makefile
@@ -18,14 +18,18 @@ GZFLAGS :=-9
KBUILD_DEFCONFIG := defconfig

KBUILD_CFLAGS += -mgeneral-regs-only
+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__
--
1.9.1

2015-04-13 20:12:47

by Philipp Tomsich

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

From: Andrew Pinski <[email protected]>

Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
---
arch/arm64/Kconfig | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 1b8e9733..6211b3f 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -669,9 +669,13 @@ 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
- select COMPAT_BINFMT_ELF
select HAVE_UID16
select OLD_SIGSUSPEND3
select COMPAT_OLD_SIGACTION
@@ -685,7 +689,7 @@ config COMPAT

config SYSVIPC_COMPAT
def_bool y
- depends on COMPAT && SYSVIPC
+ depends on AARCH32_EL0 && SYSVIPC

endmenu

--
1.9.1

2015-04-13 20:17:31

by Philipp Tomsich

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

From: Andrew Pinski <[email protected]>

Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
---
arch/arm64/include/asm/elf.h | 23 ++++++++++++++++++++---
arch/arm64/include/asm/fpsimd.h | 2 +-
arch/arm64/include/asm/ptrace.h | 2 +-
arch/arm64/include/asm/signal32.h | 2 ++
arch/arm64/include/asm/stat.h | 2 ++
arch/arm64/include/asm/unistd.h | 2 +-
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 | 31 ++++++++++++++++++++++++-------
arch/arm64/kernel/signal.c | 13 +++++++++++++
arch/arm64/kernel/traps.c | 2 +-
arch/arm64/kernel/vdso.c | 4 ++--
14 files changed, 73 insertions(+), 22 deletions(-)

diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
index 1f65be3..b73c2e2 100644
--- a/arch/arm64/include/asm/elf.h
+++ b/arch/arm64/include/asm/elf.h
@@ -171,24 +171,41 @@ extern unsigned long arch_randomize_brk(struct mm_struct *mm);

#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
#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

+#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_SET_PERSONALITY(ex)
+#define COMPAT_ARCH_DLINFO
+
+#endif
+
+#define compat_elf_check_arch(x) compat_a32_elf_check_arch(x)
+
#endif /* CONFIG_COMPAT */

#endif
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/ptrace.h b/arch/arm64/include/asm/ptrace.h
index d6dd9fd..a379596 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..4302909 100644
--- a/arch/arm64/include/asm/signal32.h
+++ b/arch/arm64/include/asm/signal32.h
@@ -20,6 +20,7 @@
#ifdef CONFIG_COMPAT
#include <linux/compat.h>

+#ifdef CONFIG_AARCH32_EL0
#define AARCH32_KERN_SIGRET_CODE_OFFSET 0x500

extern const compat_ulong_t aarch32_sigret_code[6];
@@ -47,6 +48,7 @@ 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_AARCH32_EL0 */
#endif /* CONFIG_COMPAT */
#endif /* __KERNEL__ */
#endif /* __ASM_SIGNAL32_H */
diff --git a/arch/arm64/include/asm/stat.h b/arch/arm64/include/asm/stat.h
index 15e3559..af04276 100644
--- a/arch/arm64/include/asm/stat.h
+++ b/arch/arm64/include/asm/stat.h
@@ -22,6 +22,7 @@

#include <asm/compat.h>

+#ifdef CONFIG_AARCH32_EL0
/*
* struct stat64 is needed for compat tasks only. Its definition is different
* from the generic struct stat64.
@@ -59,3 +60,4 @@ struct stat64 {

#endif
#endif
+#endif
diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h
index 3bc498c..bed97c3 100644
--- a/arch/arm64/include/asm/unistd.h
+++ b/arch/arm64/include/asm/unistd.h
@@ -13,7 +13,7 @@
* 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
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 5ee07ee..61f8fbb 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -19,7 +19,7 @@ arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \
return_address.o cpuinfo.o cpu_errata.o \
alternative.o cacheinfo.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 f7fa65d..0d35135 100644
--- a/arch/arm64/kernel/asm-offsets.c
+++ b/arch/arm64/kernel/asm-offsets.c
@@ -53,7 +53,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 cf21bb3..0dce3d0 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -196,7 +196,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
@@ -236,7 +236,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)
@@ -398,7 +398,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 07f9305..9a4ef52 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -540,7 +540,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 d882b83..cac913e 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 {
@@ -829,7 +829,7 @@ static int compat_vfp_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,
@@ -1027,8 +1027,8 @@ 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,
- compat_ulong_t caddr, compat_ulong_t cdata)
+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;
unsigned long data = cdata;
@@ -1104,11 +1104,28 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,

return ret;
}
-#endif /* CONFIG_COMPAT */
+#else /* !CONFIG_AARCH32_EL0 */
+long compat_a32_arch_ptrace(struct task_struct *child, compat_long_t request,
+ compat_ulong_t caddr, compat_ulong_t cdata)
+{
+ return -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
if (is_compat_thread(task_thread_info(task)))
return &user_aarch32_view;
#endif
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 660ccf9..eed18b6 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -421,3 +421,16 @@ asmlinkage void do_notify_resume(struct pt_regs *regs,
fpsimd_restore_current_state();

}
+
+/* Some functions are needed for compat ptrace but we don't define
+ them if we don't have AARCH32 support compiled in */
+#if defined CONFIG_COMPAT && !defined CONFIG_AARCH32_EL0
+int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
+{
+ return -EFAULT;
+}
+int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
+{
+ return -EFAULT;
+}
+#endif
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index 1ef2940..848126d 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -354,7 +354,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 32aeea0..897981b 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];

--
1.9.1

2015-04-13 20:17:59

by Philipp Tomsich

[permalink] [raw]
Subject: [PATCH v4 05/24] arm64:ilp32: expose 'kernel_long' as 'long long' for ILP32

From: Andrew Pinski <[email protected]>

Since we want time_t and some other userland types to be the same
between ILP32 and LP64, we define __kernel_long_t to be long long.

To reuse the bulk of LP64 system calls (and data structures), the LP64
kernel data types ('kernel_long', 'kernel_ulong') are exposed as their
ILP32 'long long' and 'unsigned long long' equivalents to allow glibc
to correctly interpret most data-structures used in the kernel ABI
(i.el with the exception of those, that include pointers).

Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
---
arch/arm64/include/uapi/asm/posix_types.h | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/uapi/asm/posix_types.h b/arch/arm64/include/uapi/asm/posix_types.h
index 7985ff6..d6a7cb5 100644
--- a/arch/arm64/include/uapi/asm/posix_types.h
+++ b/arch/arm64/include/uapi/asm/posix_types.h
@@ -5,6 +5,16 @@ typedef unsigned short __kernel_old_uid_t;
typedef unsigned short __kernel_old_gid_t;
#define __kernel_old_uid_t __kernel_old_uid_t

+#if defined(__ILP32__)
+/* The ILP32 kernel ABI reuses LP64 system calls where possible; to
+ this end, the equivalent ILP32 type definitions are used (a 64bit
+ 'long'-type in LP64 corresponds to a 'long long' in LP64). */
+
+typedef long long __kernel_long_t;
+typedef unsigned long long __kernel_ulong_t;
+#define __kernel_long_t __kernel_long_t
+#endif /* defined(__ILP32__) */
+
#include <asm-generic/posix_types.h>

-#endif /* __ASM_POSIX_TYPES_H */
+#endif /* __ASM_POSIX_TYPES_H */
--
1.9.1

2015-04-13 20:18:27

by Philipp Tomsich

[permalink] [raw]
Subject: [PATCH v4 06/24] 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.

Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[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>

--
1.9.1

2015-04-13 20:15:23

by Philipp Tomsich

[permalink] [raw]
Subject: [PATCH v4 07/24] arm64:ilp32: share signal structures between ILP32 and LP64 ABIs

From: Andrew Pinski <[email protected]>

Defines the macros which allow the signal structures to be the same between
ILP32 and LP64.

Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
---
arch/arm64/include/uapi/asm/siginfo.h | 21 +++++++++++++++++++++
arch/arm64/include/uapi/asm/signal.h | 32 ++++++++++++++++++++++++++++++++
include/uapi/asm-generic/siginfo.h | 17 +++++++++++++----
include/uapi/asm-generic/signal.h | 27 +++++++++++++++++++++++----
4 files changed, 89 insertions(+), 8 deletions(-)

diff --git a/arch/arm64/include/uapi/asm/siginfo.h b/arch/arm64/include/uapi/asm/siginfo.h
index 5a74a08..1a6aa32 100644
--- a/arch/arm64/include/uapi/asm/siginfo.h
+++ b/arch/arm64/include/uapi/asm/siginfo.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2012 ARM Ltd.
+ * Copyright (C) 2014 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
@@ -18,6 +19,26 @@

#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))

+#ifdef __ILP32__
+# ifdef __AARCH64EB__
+# define __SIGINFO_INNER(type, field) \
+ int __pad#field; \
+ type field
+# else
+# define __SIGINFO_INNER(type, field) \
+ type field; \
+ int __pad#field
+# endif
+
+# undef __SIGINFO_VOIDPOINTER
+# define __SIGINFO_VOIDPOINTER(field) \
+ __SIGINFO_INNER(void __user*, field)
+# undef __SIGINFO_BAND
+
+# define __SIGINFO_BAND(field) \
+ __SIGINFO_INNER(long, field)
+#endif
+
#include <asm-generic/siginfo.h>

#endif
diff --git a/arch/arm64/include/uapi/asm/signal.h b/arch/arm64/include/uapi/asm/signal.h
index 8d1e723..d90d53b 100644
--- a/arch/arm64/include/uapi/asm/signal.h
+++ b/arch/arm64/include/uapi/asm/signal.h
@@ -19,6 +19,38 @@
/* Required for AArch32 compatibility. */
#define SA_RESTORER 0x04000000

+/* For ILP32, sigset should be the same size fields as LP64 so use
+ unsigned long long. */
+#ifdef __ILP32__
+#define __SIGSET_INNER_TYPE __extension__ unsigned long long
+#define _NSIG_BPW 64
+
+# ifdef __AARCH64EB__
+# define __SIGNAL_INNER(type, field) \
+ __extension__ struct { \
+ int __pad_##field; \
+ type field; \
+ } __attribute__((aligned(8)))
+# else
+# define __SIGNAL_INNER(type, field) \
+ __extension__ struct { \
+ type field; \
+ int __pad_##field; \
+ } __attribute__((aligned(8)))
+# endif
+
+# define __SIGACTION_HANDLER(field) \
+ __SIGNAL_INNER(__sighandler_t, field)
+
+
+#define __SIGACTION_FLAGS(field) \
+ __extension__ unsigned long long field
+
+#define __SIGACTION_RESTORER(field) \
+ __SIGNAL_INNER(__sigrestore_t, field)
+
+#endif
+
#include <asm-generic/signal.h>

#endif
diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h
index 1e35520..be640a9 100644
--- a/include/uapi/asm-generic/siginfo.h
+++ b/include/uapi/asm-generic/siginfo.h
@@ -4,9 +4,17 @@
#include <linux/compiler.h>
#include <linux/types.h>

+#ifndef __SIGINFO_VOIDPOINTER
+#define __SIGINFO_VOIDPOINTER(field) void __user *field
+#endif
+
+#ifndef __SIGINFO_BAND
+#define __SIGINFO_BAND(field) __ARCH_SI_BAND_T field
+#endif
+
typedef union sigval {
int sival_int;
- void __user *sival_ptr;
+ __SIGINFO_VOIDPOINTER(sival_ptr);
} sigval_t;

/*
@@ -86,7 +94,7 @@ typedef struct siginfo {

/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
struct {
- void __user *_addr; /* faulting insn/memory ref. */
+ __SIGINFO_VOIDPOINTER(_addr); /* faulting insn/memory ref. */
#ifdef __ARCH_SI_TRAPNO
int _trapno; /* TRAP # which caused the signal */
#endif
@@ -99,13 +107,13 @@ typedef struct siginfo {

/* SIGPOLL */
struct {
- __ARCH_SI_BAND_T _band; /* POLL_IN, POLL_OUT, POLL_MSG */
+ __SIGINFO_BAND(_band); /* POLL_IN, POLL_OUT, POLL_MSG */
int _fd;
} _sigpoll;

/* SIGSYS */
struct {
- void __user *_call_addr; /* calling user insn */
+ __SIGINFO_VOIDPOINTER(_call_addr); /* calling user insn */
int _syscall; /* triggering system call number */
unsigned int _arch; /* AUDIT_ARCH_* of syscall */
} _sigsys;
@@ -290,6 +298,7 @@ typedef struct sigevent {
int _pad[SIGEV_PAD_SIZE];
int _tid;

+ /* Note these two are handled only in userspace */
struct {
void (*_function)(sigval_t);
void *_attribute; /* really pthread_attr_t */
diff --git a/include/uapi/asm-generic/signal.h b/include/uapi/asm-generic/signal.h
index 9df61f1..c4ce238 100644
--- a/include/uapi/asm-generic/signal.h
+++ b/include/uapi/asm-generic/signal.h
@@ -4,7 +4,9 @@
#include <linux/types.h>

#define _NSIG 64
+#ifndef _NSIG_BPW
#define _NSIG_BPW __BITS_PER_LONG
+#endif
#define _NSIG_WORDS (_NSIG / _NSIG_BPW)

#define SIGHUP 1
@@ -83,9 +85,13 @@
#define MINSIGSTKSZ 2048
#define SIGSTKSZ 8192

+#ifndef __SIGSET_INNER_TYPE
+#define __SIGSET_INNER_TYPE unsigned long
+#endif
+
#ifndef __ASSEMBLY__
typedef struct {
- unsigned long sig[_NSIG_WORDS];
+ __SIGSET_INNER_TYPE sig[_NSIG_WORDS];
} sigset_t;

/* not actually used, but required for linux/syscalls.h */
@@ -98,11 +104,24 @@ typedef unsigned long old_sigset_t;
#endif

#ifndef __KERNEL__
+
+#ifndef __SIGACTION_HANDLER
+#define __SIGACTION_HANDLER(field) __sighandler_t field
+#endif
+
+#ifndef __SIGACTION_FLAGS
+#define __SIGACTION_FLAGS(field) unsigned long field
+#endif
+
+#ifndef __SIGACTION_RESTORER
+#define __SIGACTION_RESTORER(field) __sigrestore_t field
+#endif
+
struct sigaction {
- __sighandler_t sa_handler;
- unsigned long sa_flags;
+ __SIGACTION_HANDLER(sa_handler);
+ __SIGACTION_FLAGS(sa_flags);
#ifdef SA_RESTORER
- __sigrestore_t sa_restorer;
+ __SIGACTION_RESTORER(sa_restorer);
#endif
sigset_t sa_mask; /* mask last for extensibility */
};
--
1.9.1

2015-04-13 20:16:39

by Philipp Tomsich

[permalink] [raw]
Subject: [PATCH v4 08/24] arm64:ilp32: use 64bit syscall-names for ILP32 when passing 64bit registers

From: Andrew Pinski <[email protected]>

In the ARM64 ILP32 case, we want to say the syscalls that normally would pass
64bit as two arguments are now passing as one so want to use the 64bit
naming scheme.

Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
---
include/uapi/asm-generic/unistd.h | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h
index e016bd9..398a890 100644
--- a/include/uapi/asm-generic/unistd.h
+++ b/include/uapi/asm-generic/unistd.h
@@ -885,8 +885,11 @@ __SYSCALL(__NR_fork, sys_ni_syscall)
* they take different names.
* Here we map the numbers so that both versions
* use the same syscall table layout.
+ * For 32bit abis where 64bit can be passed via one
+ * register, use the same naming as the 64bit ones
+ * as they will only have a 64 bit off_t.
*/
-#if __BITS_PER_LONG == 64 && !defined(__SYSCALL_COMPAT)
+#if (__BITS_PER_LONG == 64 && !defined(__SYSCALL_COMPAT)) || defined(__SYSCALL_NONCOMPAT)
#define __NR_fcntl __NR3264_fcntl
#define __NR_statfs __NR3264_statfs
#define __NR_fstatfs __NR3264_fstatfs
--
1.9.1

2015-04-13 20:13:36

by Philipp Tomsich

[permalink] [raw]
Subject: [PATCH v4 09/24] arm64:ilp32: use non-compat syscall names for ILP32 as for LP64

From: Andrew Pinski <[email protected]>

Define __ARCH_WANT_64BIT_SYSCALLS for ILP32, so we (can) use the 64bit
syscall names for ILP32.

Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
---
arch/arm64/include/uapi/asm/unistd.h | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/arch/arm64/include/uapi/asm/unistd.h b/arch/arm64/include/uapi/asm/unistd.h
index 1caadc2..067eab0 100644
--- a/arch/arm64/include/uapi/asm/unistd.h
+++ b/arch/arm64/include/uapi/asm/unistd.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2012 ARM Ltd.
+ * Copyright (C) 2014 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
@@ -13,4 +14,10 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
+/* For ILP32 AARCH64, we want to use the non compat names. */
+#if defined(__aarch64__) && defined(__ILP32__)
+#define __SYSCALL_NONCOMPAT
+#endif
+
#include <asm-generic/unistd.h>
--
1.9.1

2015-04-13 20:17:36

by Philipp Tomsich

[permalink] [raw]
Subject: [PATCH v4 10/24] arm64: introduce is_a32_task and is_a32_thread (for AArch32 compat)

From: Andrew Pinski <[email protected]>

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.

Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
---
arch/arm64/include/asm/compat.h | 31 ++++++++++++++++++++++++++++---
arch/arm64/include/asm/elf.h | 2 +-
arch/arm64/include/asm/memory.h | 2 +-
arch/arm64/include/asm/processor.h | 2 +-
arch/arm64/include/asm/thread_info.h | 2 +-
arch/arm64/kernel/hw_breakpoint.c | 6 +++---
arch/arm64/kernel/process.c | 6 +++---
arch/arm64/kernel/ptrace.c | 8 ++++----
arch/arm64/kernel/signal.c | 4 ++--
arch/arm64/kernel/traps.c | 2 +-
10 files changed, 45 insertions(+), 20 deletions(-)

diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h
index 7fbed69..3a2976d 100644
--- a/arch/arm64/include/asm/compat.h
+++ b/arch/arm64/include/asm/compat.h
@@ -299,15 +299,25 @@ struct compat_shmid64_ds {
compat_ulong_t __unused5;
};

-static inline int is_compat_task(void)
+#ifdef CONFIG_AARCH32_EL0
+static inline int is_a32_compat_task(void)
{
return test_thread_flag(TIF_32BIT);
}
-
-static inline int is_compat_thread(struct thread_info *thread)
+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

#else /* !CONFIG_COMPAT */

@@ -316,6 +326,21 @@ static inline int is_compat_thread(struct thread_info *thread)
return 0;
}

+static inline int is_a32_compat_task(void)
+{
+ return 0;
+}
+
#endif /* CONFIG_COMPAT */
+
+static inline int is_compat_task(void)
+{
+ return is_a32_compat_task();
+}
+
+static inline int is_compat_thread(struct thread_info *thread)
+{
+ return is_a32_compat_thread(thread);
+}
#endif /* __KERNEL__ */
#endif /* __ASM_COMPAT_H */
diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
index b73c2e2..4e565dd 100644
--- a/arch/arm64/include/asm/elf.h
+++ b/arch/arm64/include/asm/elf.h
@@ -150,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/memory.h b/arch/arm64/include/asm/memory.h
index f800d45..960d059 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -58,7 +58,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 20e9591..ea80e86 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -39,7 +39,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
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index 702e1e6..75f8d56 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -113,7 +113,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 98bbe06..3fcfaa5 100644
--- a/arch/arm64/kernel/hw_breakpoint.c
+++ b/arch/arm64/kernel/hw_breakpoint.c
@@ -433,7 +433,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;
@@ -490,7 +490,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
@@ -677,7 +677,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/process.c b/arch/arm64/kernel/process.c
index c6b1f3b..84e62ef 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -261,7 +261,7 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
if (likely(!(p->flags & PF_KTHREAD))) {
*childregs = *current_pt_regs();
childregs->regs[0] = 0;
- if (is_compat_thread(task_thread_info(p))) {
+ if (is_a32_compat_thread(task_thread_info(p))) {
if (stack_start)
childregs->compat_sp = stack_start;
} else {
@@ -302,12 +302,12 @@ static void tls_thread_switch(struct task_struct *next)
{
unsigned long tpidr, tpidrro;

- if (!is_compat_task()) {
+ if (!is_a32_compat_task()) {
asm("mrs %0, tpidr_el0" : "=r" (tpidr));
current->thread.tp_value = tpidr;
}

- if (is_compat_thread(task_thread_info(next))) {
+ if (is_a32_compat_thread(task_thread_info(next))) {
tpidr = 0;
tpidrro = next->thread.tp_value;
} else {
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index cac913e..75f313a 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -79,7 +79,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) {
@@ -1116,7 +1116,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);
}
@@ -1126,7 +1126,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
const struct user_regset_view *task_user_regset_view(struct task_struct *task)
{
#ifdef CONFIG_AARCH32_EL0
- if (is_compat_thread(task_thread_info(task)))
+ if (is_a32_compat_thread(task_thread_info(task)))
return &user_aarch32_view;
#endif
return &user_aarch64_view;
@@ -1153,7 +1153,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 eed18b6..b91e6e1 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;
@@ -302,7 +302,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 848126d..4396d5c 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -356,7 +356,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;
--
1.9.1

2015-04-13 20:16:22

by Philipp Tomsich

[permalink] [raw]
Subject: [PATCH v4 11/24] arm64:ilp32: add is_ilp32_compat_{task,thread} and TIF_32BIT_AARCH64

From: Andrew Pinski <[email protected]>

Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
---
arch/arm64/include/asm/compat.h | 32 ++++++++++++++++++++++++++++++--
arch/arm64/include/asm/thread_info.h | 1 +
2 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h
index 3a2976d..f53c4e6 100644
--- a/arch/arm64/include/asm/compat.h
+++ b/arch/arm64/include/asm/compat.h
@@ -319,6 +319,26 @@ static inline int is_a32_compat_thread(struct thread_info *thread)
}
#endif

+#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
+
#else /* !CONFIG_COMPAT */

static inline int is_compat_thread(struct thread_info *thread)
@@ -330,17 +350,25 @@ static inline int is_a32_compat_task(void)
{
return 0;
}
+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_COMPAT */

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

static inline int is_compat_thread(struct thread_info *thread)
{
- return is_a32_compat_thread(thread);
+ return is_a32_compat_thread(thread) || is_ilp32_compat_thread(thread);
}
#endif /* __KERNEL__ */
#endif /* __ASM_COMPAT_H */
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index 75f8d56..d41586c 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -115,6 +115,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)
--
1.9.1

2015-04-13 20:14:10

by Philipp Tomsich

[permalink] [raw]
Subject: [PATCH v4 12/24] arm64:ilp32: COMPAT_USE_64BIT_TIME is true for ILP32 tasks

Since __kernel_long_t (time_t) is long long, we need to tell the rest of
kernel that we use 64bit time_t for compat when the task is not an
AARCH32 task. The reason why we check AARCH32 rather than ILP32 here is
because if we don't have AARCH32 compiled in (which is going to be the
common case due to AARCH32 requiring 4k pages).

Stricly speaking, a 'long long' time_t is not standards-compliant
(refer to https://sourceware.org/bugzilla/show_bug.cgi?id=16437 for
details), but there is precedent (i.e. x32) for such an implementation both
in the kernel and in glibc.

Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
---
arch/arm64/include/asm/compat.h | 3 +++
1 file changed, 3 insertions(+)

diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h
index f53c4e6..4b717df 100644
--- a/arch/arm64/include/asm/compat.h
+++ b/arch/arm64/include/asm/compat.h
@@ -76,6 +76,9 @@ struct compat_timeval {
s32 tv_usec;
};

+/* ILP32 uses 64bit time_t and not the above compat structures */
+#define COMPAT_USE_64BIT_TIME !is_a32_compat_task()
+
struct compat_stat {
#ifdef __AARCH64EB__
short st_dev;
--
1.9.1

2015-04-13 20:17:16

by Philipp Tomsich

[permalink] [raw]
Subject: [PATCH v4 13/24] arm64:ilp32: share HWCAP between LP64 and ILP32

From: Andrew Pinski <[email protected]>

Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[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;
--
1.9.1

2015-04-13 20:16:11

by Philipp Tomsich

[permalink] [raw]
Subject: [PATCH v4 14/24] 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.

Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
---
arch/arm64/include/asm/processor.h | 9 +++++++++
1 file changed, 9 insertions(+)

diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index ea80e86..29ca21a 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -106,6 +106,15 @@ 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 thread are started the same way as LP64 threads.
+ Note we cannot use is_ilp32_compat_task here as that
+ would introduce a header depency issue. */
+ if (test_thread_flag(TIF_32BIT_AARCH64)) {
+ start_thread(regs, pc, sp);
+ return;
+ }
+#endif
start_thread_common(regs, pc);
regs->pstate = COMPAT_PSR_MODE_USR;
if (pc & 1)
--
1.9.1

2015-04-13 20:19:00

by Philipp Tomsich

[permalink] [raw]
Subject: [PATCH v4 15/24] 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.

Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
---
arch/arm64/include/asm/elf.h | 22 ++++++++++++++++++++--
arch/arm64/kernel/ptrace.c | 12 ++++++------
2 files changed, 26 insertions(+), 8 deletions(-)

diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
index 4e565dd..8218925 100644
--- a/arch/arm64/include/asm/elf.h
+++ b/arch/arm64/include/asm/elf.h
@@ -176,8 +176,8 @@ extern unsigned long arch_randomize_brk(struct mm_struct *mm);

/* 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
@@ -204,6 +204,24 @@ typedef elf_gregset_t compat_elf_gregset_t;

#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;
+#define PR_REG_SIZE(S) (is_a32_compat_task() ? 72 : 272)
+#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
+
#define compat_elf_check_arch(x) compat_a32_elf_check_arch(x)

#endif /* CONFIG_COMPAT */
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 75f313a..efb9a54 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -830,8 +830,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
},
@@ -864,7 +864,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);
@@ -885,7 +885,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);
@@ -1048,7 +1048,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;

@@ -1056,7 +1056,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;

--
1.9.1

2015-04-13 20:14:34

by Philipp Tomsich

[permalink] [raw]
Subject: [PATCH v4 16/24] arm64: add support for starting ILP32 (ELFCLASS32) binaries

From: Andrew Pinski <[email protected]>

Handle ILP32 (AArch64, but ELFCLASS32) binaries on ARM64.

Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
---
arch/arm64/include/asm/elf.h | 66 +++++++++++++++++++++++++++++++++++++-------
1 file changed, 56 insertions(+), 10 deletions(-)

diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
index 8218925..ff005d9 100644
--- a/arch/arm64/include/asm/elf.h
+++ b/arch/arm64/include/asm/elf.h
@@ -135,7 +135,11 @@ extern unsigned long randomize_et_dyn(unsigned long base);
*/
#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 { \
@@ -185,25 +189,28 @@ typedef compat_a32_elf_greg_t compat_a32_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
+#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)


extern int aarch32_setup_vectors_page(struct linux_binprm *bprm,
int uses_interp);
-#define compat_arch_setup_additional_pages \
- aarch32_setup_vectors_page

#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_SET_PERSONALITY(ex)
-#define COMPAT_ARCH_DLINFO
-
+#define COMPAT_A32_SET_PERSONALITY(ex) do {} while (0)
+#define COMPAT_A32_ARCH_DLINFO do {} while (0)
+#define aarch32_setup_vectors_page(x, y) -EINVAL
#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
@@ -222,7 +229,46 @@ typedef compat_a32_elf_greg_t compat_elf_greg_t;
typedef compat_a32_elf_gregset_t compat_elf_gregset_t;
#endif

-#define compat_elf_check_arch(x) compat_a32_elf_check_arch(x)
+#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) || 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 */

--
1.9.1

2015-04-13 20:18:30

by Philipp Tomsich

[permalink] [raw]
Subject: [PATCH v4 17/24] arm64:ilp32: add vdso-ilp32 and use for signal return

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]>
---
arch/arm64/include/asm/vdso.h | 4 ++
arch/arm64/kernel/Makefile | 5 ++
arch/arm64/kernel/signal.c | 4 ++
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 | 98 +++++++++++++++++++++++++++
arch/arm64/kernel/vdso.c | 63 ++++++++++++++---
8 files changed, 270 insertions(+), 11 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 61f8fbb..3cf8120 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -37,6 +37,7 @@ arm64-obj-$(CONFIG_PCI) += pci.o
arm64-obj-$(CONFIG_ARMV8_DEPRECATED) += armv8_deprecated.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
@@ -44,3 +45,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/signal.c b/arch/arm64/kernel/signal.c
index b91e6e1..99e36be 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -241,6 +241,10 @@ static void setup_return(struct pt_regs *regs, struct k_sigaction *ka,

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);

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..ac8029b
--- /dev/null
+++ b/arch/arm64/kernel/vdso-ilp32/vdso-ilp32.lds.S
@@ -0,0 +1,98 @@
+/*
+ * 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>
+
+/*OUTPUT_FORMAT("elf32-littleaarch64", "elf32-bigaarch64", "elf32-littleaarch64")
+OUTPUT_ARCH(aarch64)
+*/
+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.39 {
+ 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 897981b..4b2d86e 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 inline 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;
+ 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;

--
1.9.1

2015-04-13 20:14:58

by Philipp Tomsich

[permalink] [raw]
Subject: [PATCH v4 18/24] ptrace: Allow compat to use the native siginfo

From: Andrew Pinski <[email protected]>

Set COMPAT_USE_NATIVE_SIGINFO to be true for non AARCH32 tasks.

With ARM64 ILP32 ABI, we want to use the non-compat
siginfo as we want to simplify signal handling for this new ABI.
This patch just adds a new define COMPAT_USE_NATIVE_SIGINFO and
if it is true then read/write in the compat case as it was the
non-compat case.

Signed-off-by: Christoph Muellner <[email protected]>
Signed-off-by: Philipp Tomsich <[email protected]>
---
include/linux/compat.h | 4 ++++
kernel/ptrace.c | 24 +++++++++++++++++-------
2 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/include/linux/compat.h b/include/linux/compat.h
index ab25814..d11c556 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -24,6 +24,10 @@
#define COMPAT_USE_64BIT_TIME 0
#endif

+#ifndef COMPAT_USE_NATIVE_SIGINFO
+#define COMPAT_USE_NATIVE_SIGINFO 0
+#endif
+
#ifndef __SC_DELOUSE
#define __SC_DELOUSE(t,v) ((t)(unsigned long)(v))
#endif
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 227fec3..5bea58b 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -640,7 +640,7 @@ static int ptrace_peek_siginfo(struct task_struct *child,
break;

#ifdef CONFIG_COMPAT
- if (unlikely(is_compat_task())) {
+ if (unlikely(is_compat_task() && !COMPAT_USE_NATIVE_SIGINFO)) {
compat_siginfo_t __user *uinfo = compat_ptr(data);

if (copy_siginfo_to_user32(uinfo, &info) ||
@@ -1108,16 +1108,26 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request,

case PTRACE_GETSIGINFO:
ret = ptrace_getsiginfo(child, &siginfo);
- if (!ret)
- ret = copy_siginfo_to_user32(
- (struct compat_siginfo __user *) datap,
- &siginfo);
+ if (!ret) {
+ if (COMPAT_USE_NATIVE_SIGINFO)
+ ret = copy_siginfo_to_user(
+ (struct siginfo __user *) datap,
+ &siginfo);
+ else
+ ret = copy_siginfo_to_user32(
+ (struct compat_siginfo __user *) datap,
+ &siginfo);
+ }
break;

case PTRACE_SETSIGINFO:
memset(&siginfo, 0, sizeof siginfo);
- if (copy_siginfo_from_user32(
- &siginfo, (struct compat_siginfo __user *) datap))
+ if (COMPAT_USE_NATIVE_SIGINFO)
+ ret = copy_from_user(&siginfo, datap, sizeof(siginfo));
+ else
+ ret = copy_siginfo_from_user32(
+ &siginfo, (struct compat_siginfo __user *) datap);
+ if (ret)
ret = -EFAULT;
else
ret = ptrace_setsiginfo(child, &siginfo);
--
1.9.1

2015-04-13 20:13:40

by Philipp Tomsich

[permalink] [raw]
Subject: [PATCH v4 19/24] 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.

This revision of the patch now addresses Catalin's comment regarding the
duplicate reading of the task-flags in the el0_svc-handler and simply
relies on the flags having been read by the kernel_entry macro.

Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
---
arch/arm64/include/asm/unistd.h | 4 +
arch/arm64/kernel/Makefile | 1 +
arch/arm64/kernel/entry.S | 12 ++-
arch/arm64/kernel/sys_ilp32.c | 173 ++++++++++++++++++++++++++++++++++++++++
4 files changed, 189 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 bed97c3..10397e8 100644
--- a/arch/arm64/include/asm/unistd.h
+++ b/arch/arm64/include/asm/unistd.h
@@ -13,6 +13,10 @@
* 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_COMPAT_STAT64
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 3cf8120..131996d 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -23,6 +23,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_SMP) += smp.o smp_spin_table.o topology.o
arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 0dce3d0..39fdf67 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -642,9 +642,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
@@ -664,6 +668,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..06c05ce
--- /dev/null
+++ b/arch/arm64/kernel/sys_ilp32.c
@@ -0,0 +1,173 @@
+/*
+ * AArch64- ILP32 specific system calls implementation
+ *
+ * Copyright (C) 2013 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/export.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/syscalls.h>
+#include <linux/compat.h>
+
+/*
+ * Wrappers to pass the pt_regs argument.
+ */
+#define sys_rt_sigreturn sys_rt_sigreturn_wrapper
+
+/* Using Compat syscalls where necessary */
+#define sys_ioctl compat_sys_ioctl
+/* iovec */
+#define sys_readv compat_sys_readv
+#define sys_writev compat_sys_writev
+#define sys_preadv compat_sys_preadv64
+#define sys_pwritev compat_sys_pwritev64
+#define sys_vmsplice compat_sys_vmsplice
+/* robust_list_head */
+#define sys_set_robust_list compat_sys_set_robust_list
+#define sys_get_robust_list compat_sys_get_robust_list
+
+/* kexec_segment */
+#define sys_kexec_load compat_sys_kexec_load
+
+/* Ptrace has some structures which are different between ILP32 and LP64 */
+#define sys_ptrace compat_sys_ptrace
+
+/* struct msghdr */
+#define sys_recvfrom compat_sys_recvfrom
+#define sys_recvmmsg compat_sys_recvmmsg
+#define sys_sendmmsg compat_sys_sendmmsg
+#define sys_sendmsg compat_sys_sendmsg
+#define sys_recvmsg compat_sys_recvmsg
+
+#define sys_setsockopt compat_sys_setsockopt
+#define sys_getsockopt compat_sys_getsockopt
+
+/* Array of pointers */
+#define sys_execve compat_sys_execve
+#define sys_move_pages compat_sys_move_pages
+
+/* iovec */
+#define sys_process_vm_readv compat_sys_process_vm_readv
+#define sys_process_vm_writev compat_sys_process_vm_writev
+
+/* Pointer in struct */
+#define sys_mount compat_sys_mount
+
+/* NUMA */
+/* unsigned long bitmaps */
+#define sys_get_mempolicy compat_sys_get_mempolicy
+#define sys_set_mempolicy compat_sys_set_mempolicy
+#define sys_mbind compat_sys_mbind
+/* array of pointers */
+/* unsigned long bitmaps */
+#define sys_migrate_pages compat_sys_migrate_pages
+
+/* Scheduler */
+/* unsigned long bitmaps */
+#define sys_sched_setaffinity compat_sys_sched_setaffinity
+#define sys_sched_getaffinity compat_sys_sched_getaffinity
+
+/* iov usage */
+#define sys_keyctl compat_sys_keyctl
+
+/* aio */
+/* Pointer to Pointer */
+#define sys_io_setup compat_sys_io_setup
+/* Array of pointers */
+#define sys_io_submit compat_sys_io_submit
+
+/* We need to make sure the pointer gets copied correctly. */
+asmlinkage long ilp32_sys_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification)
+{
+ struct sigevent __user *p = NULL;
+ if (u_notification) {
+ struct sigevent n;
+ p = compat_alloc_user_space(sizeof(*p));
+ if (copy_from_user(&n, u_notification, sizeof(*p)))
+ return -EFAULT;
+ if (n.sigev_notify == SIGEV_THREAD)
+ n.sigev_value.sival_ptr = compat_ptr((uintptr_t)n.sigev_value.sival_ptr);
+ if (copy_to_user(p, &n, sizeof(*p)))
+ return -EFAULT;
+ }
+ return sys_mq_notify(mqdes, p);
+}
+
+/* sigevent contains sigval_t which is now 64bit always
+ but need special handling due to padding for SIGEV_THREAD. */
+#define sys_mq_notify ilp32_sys_mq_notify
+
+
+/* sigaltstack needs some special handling as the
+ padding for stack_t might not be non-zero. */
+long ilp32_sys_sigaltstack(const stack_t __user *uss_ptr,
+ stack_t __user *uoss_ptr)
+{
+ stack_t uss, uoss;
+ int ret;
+ mm_segment_t seg;
+
+ if (uss_ptr) {
+ if (!access_ok(VERIFY_READ, uss_ptr, sizeof(*uss_ptr)))
+ return -EFAULT;
+ if (__get_user(uss.ss_sp, &uss_ptr->ss_sp) |
+ __get_user(uss.ss_flags, &uss_ptr->ss_flags) |
+ __get_user(uss.ss_size, &uss_ptr->ss_size))
+ return -EFAULT;
+ /* Zero extend the sp address and the size. */
+ uss.ss_sp = (void *)(uintptr_t)(unsigned int)(uintptr_t)uss.ss_sp;
+ uss.ss_size = (size_t)(unsigned int)uss.ss_size;
+ }
+ seg = get_fs();
+ set_fs(KERNEL_DS);
+ /* Note we need to use uoss as we have changed the segment to the
+ kernel one so passing an user one around is wrong. */
+ ret = sys_sigaltstack((stack_t __force __user *) (uss_ptr ? &uss : NULL),
+ (stack_t __force __user *) &uoss);
+ set_fs(seg);
+ if (ret >= 0 && uoss_ptr) {
+ if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_t)) ||
+ __put_user(uoss.ss_sp, &uoss_ptr->ss_sp) ||
+ __put_user(uoss.ss_flags, &uoss_ptr->ss_flags) ||
+ __put_user(uoss.ss_size, &uoss_ptr->ss_size))
+ ret = -EFAULT;
+ }
+ return ret;
+}
+
+/* sigaltstack needs some special handling as the padding
+ for stack_t might not be non-zero. */
+#define sys_sigaltstack ilp32_sys_sigaltstack
+
+
+#include <asm/syscalls.h>
+
+#undef __SYSCALL
+#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>
+};
--
1.9.1

2015-04-13 20:15:49

by Philipp Tomsich

[permalink] [raw]
Subject: [PATCH v4 20/24] arm64:ilp32: use compat-syscalls for msgsnd and msgrcv for ILP32

msgsnd and msgrcv require the compat-layer, as they are defined to
use data structures with a 'long' (32bit in ILP32, 64bit in LP64)
element.

Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
---
arch/arm64/kernel/sys_ilp32.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/sys_ilp32.c b/arch/arm64/kernel/sys_ilp32.c
index 06c05ce..3471f27 100644
--- a/arch/arm64/kernel/sys_ilp32.c
+++ b/arch/arm64/kernel/sys_ilp32.c
@@ -1,9 +1,12 @@
/*
- * AArch64- ILP32 specific system calls implementation
+ * AArch64: ILP32 specific system calls implementation
*
* Copyright (C) 2013 Cavium Inc.
* Author: Andrew Pinski <[email protected]>
*
+ * Copyright (C) 2014 Theobroma Systems GmbH
+ * <[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.
@@ -50,6 +53,10 @@
/* Ptrace has some structures which are different between ILP32 and LP64 */
#define sys_ptrace compat_sys_ptrace

+/* message type is 64bit in LP64 and 32bit in ILP32 */
+#define sys_msgsnd compat_sys_msgsnd
+#define sys_msgrcv compat_sys_msgrcv
+
/* struct msghdr */
#define sys_recvfrom compat_sys_recvfrom
#define sys_recvmmsg compat_sys_recvmmsg
--
1.9.1

2015-04-13 20:16:41

by Philipp Tomsich

[permalink] [raw]
Subject: [PATCH v4 21/24] arm64:ilp32: use the native siginfo instead of the compat siginfo

From: Andrew Pinski <[email protected]>

Set COMPAT_USE_NATIVE_SIGINFO to be true for non AARCH32 tasks.

Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
---
arch/arm64/include/asm/compat.h | 3 +++
1 file changed, 3 insertions(+)

diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h
index 4b717df..47f2b7a 100644
--- a/arch/arm64/include/asm/compat.h
+++ b/arch/arm64/include/asm/compat.h
@@ -217,6 +217,9 @@ typedef struct compat_siginfo {
} _sifields;
} compat_siginfo_t;

+/* ILP32 uses the native siginfo and not the compat struct */
+#define COMPAT_USE_NATIVE_SIGINFO !is_a32_compat_task()
+
#define COMPAT_OFF_T_MAX 0x7fffffff
#define COMPAT_LOFF_T_MAX 0x7fffffffffffffffL

--
1.9.1

2015-04-13 20:18:04

by Philipp Tomsich

[permalink] [raw]
Subject: [PATCH v4 22/24] arm64:ilp32: use compat for stack_t

We use a 'natively sized' stack_t in glibc (i.e. having a 32bit pointer for
ss_sp), which requires the invocation of the compat layer for the following
functionality:
* sigaltstack
* saving and restoring uc_stack during signal setup and returns

As the userspace stack_t is natively sized, we avoid code duplication in the
syscall table and can use the compat-functions to zero-extend the pointers
involved.

Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[email protected]>
---
arch/arm64/kernel/signal.c | 19 +++++++++++++++++++
arch/arm64/kernel/sys_ilp32.c | 44 +------------------------------------------
2 files changed, 20 insertions(+), 43 deletions(-)

diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 99e36be..b3f6e52 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/vdso.h>
+#include <asm/syscalls.h>

/*
* Do a signal return; undo the signal stack. These are aligned to 128-bit.
@@ -148,9 +149,22 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
if (restore_sigframe(regs, frame))
goto badframe;

+
+#if defined(CONFIG_ARM64_ILP32)
+ if (is_ilp32_compat_task()) {
+ /* For ILP32, we have a different stack_t (the ss_sp
+ field will be only 32bit sized), which fits into
+ the memory area reserved for the (larger) LP64
+ stack_t and which we place into uc_stack: this
+ implies padding after the ILP32 stack_t. */
+ if (compat_restore_altstack((compat_stack_t*)&frame->uc.uc_stack))
+ goto badframe;
+ } else
+#endif
if (restore_altstack(&frame->uc.uc_stack))
goto badframe;

+
return regs->regs[0];

badframe:
@@ -264,6 +278,11 @@ static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
__put_user_error(0, &frame->uc.uc_flags, err);
__put_user_error(NULL, &frame->uc.uc_link, err);

+#if defined(CONFIG_ARM64_ILP32)
+ if (is_ilp32_compat_task())
+ err |= __compat_save_altstack((compat_stack_t*)&frame->uc.uc_stack, regs->sp);
+ else
+#endif
err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
err |= setup_sigframe(frame, regs, set);
if (err == 0) {
diff --git a/arch/arm64/kernel/sys_ilp32.c b/arch/arm64/kernel/sys_ilp32.c
index 3471f27..31f82ca 100644
--- a/arch/arm64/kernel/sys_ilp32.c
+++ b/arch/arm64/kernel/sys_ilp32.c
@@ -77,6 +77,7 @@

/* Pointer in struct */
#define sys_mount compat_sys_mount
+#define sys_sigaltstack compat_sys_sigaltstack

/* NUMA */
/* unsigned long bitmaps */
@@ -122,49 +123,6 @@ asmlinkage long ilp32_sys_mq_notify(mqd_t mqdes, const struct sigevent __user *u
but need special handling due to padding for SIGEV_THREAD. */
#define sys_mq_notify ilp32_sys_mq_notify

-
-/* sigaltstack needs some special handling as the
- padding for stack_t might not be non-zero. */
-long ilp32_sys_sigaltstack(const stack_t __user *uss_ptr,
- stack_t __user *uoss_ptr)
-{
- stack_t uss, uoss;
- int ret;
- mm_segment_t seg;
-
- if (uss_ptr) {
- if (!access_ok(VERIFY_READ, uss_ptr, sizeof(*uss_ptr)))
- return -EFAULT;
- if (__get_user(uss.ss_sp, &uss_ptr->ss_sp) |
- __get_user(uss.ss_flags, &uss_ptr->ss_flags) |
- __get_user(uss.ss_size, &uss_ptr->ss_size))
- return -EFAULT;
- /* Zero extend the sp address and the size. */
- uss.ss_sp = (void *)(uintptr_t)(unsigned int)(uintptr_t)uss.ss_sp;
- uss.ss_size = (size_t)(unsigned int)uss.ss_size;
- }
- seg = get_fs();
- set_fs(KERNEL_DS);
- /* Note we need to use uoss as we have changed the segment to the
- kernel one so passing an user one around is wrong. */
- ret = sys_sigaltstack((stack_t __force __user *) (uss_ptr ? &uss : NULL),
- (stack_t __force __user *) &uoss);
- set_fs(seg);
- if (ret >= 0 && uoss_ptr) {
- if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_t)) ||
- __put_user(uoss.ss_sp, &uoss_ptr->ss_sp) ||
- __put_user(uoss.ss_flags, &uoss_ptr->ss_flags) ||
- __put_user(uoss.ss_size, &uoss_ptr->ss_size))
- ret = -EFAULT;
- }
- return ret;
-}
-
-/* sigaltstack needs some special handling as the padding
- for stack_t might not be non-zero. */
-#define sys_sigaltstack ilp32_sys_sigaltstack
-
-
#include <asm/syscalls.h>

#undef __SYSCALL
--
1.9.1

2015-04-13 20:13:17

by Philipp Tomsich

[permalink] [raw]
Subject: [PATCH v4 23/24] arm64:ilp32: change COMPAT_ELF_PLATFORM to report a a subplatform for ILP32

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.

Signed-off-by: Philipp Tomsich <[email protected]>
Signed-off-by: Christoph Muellner <[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 ff005d9..c35922c 100644
--- a/arch/arm64/include/asm/elf.h
+++ b/arch/arm64/include/asm/elf.h
@@ -168,9 +168,9 @@ extern unsigned long arch_randomize_brk(struct mm_struct *mm);
#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)
--
1.9.1

2015-04-13 20:12:50

by Philipp Tomsich

[permalink] [raw]
Subject: [PATCH v4 24/24] arm64:ilp32: add ARM64_ILP32 to Kconfig

From: Andrew Pinski <[email protected]>

This patch adds the config option for ILP32.

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

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 6211b3f..0725a60 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -670,7 +670,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
@@ -687,6 +687,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 AARCH32_EL0 && SYSVIPC
--
1.9.1

2015-04-13 21:01:45

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Monday 13 April 2015 21:44:10 Philipp Tomsich wrote:
> If anybody wants to rerun LTP, let me know, so I can provide a
> buildroot-generated rootfs-image via FTP.
>
> The key differences from earlier changesets are:
> * updated to 4.0
> * fixes for functions using 'struct msgbuf' (using compat)
> * deduplication of code by using a 32bit stack_t (using compat)
> * updated the documentation to clarify the changes to stack_t
> * introduced a sub-architecture (via COMPAT_ELF_PLATFORM) to make
> life easier for tools (e.g. gdb) when attaching to a live process
> (a corefile is easily distinguishable by being ELFCLASS32).
>
> Any review comments are welcome.

Hi Philipp,

Thanks for picking up these patches again. I have had a lot of conversations about
them recently, and have two very broad issues that we need to resolve before
merging them:

1. Adding a whole new ABI to the kernel is adding a long-term maintenance
burden, and we don't want to do that just because someone thinks it's a cute
hack or because it might add a few percent in performance of some low-level
benchmark. Please describe in the cover-letter for the patch series
specifically what applications you have in mind that would be using this, and
what the expected timeframe is before users could move to 64-bit user space.

2. The ABI follows what x86 has their "x32" ABI. This never saw a lot of
adoption and in retrospect the decision to have separate system calls seems
to not have helped them. My feeling now is that if we add support for the
ARM64 ILP32 ELF ABI, we should better stick to the existing system call ABI
as close as possible and reuse the existing system call table. I realize
that this is a bit controversial, but please let's talk about this now.

The most important aspect here I think is time_t, and while it means starting
out with a system call ABI that is not ready for y2038, at the same time the
purpose of ILP32 support is to support legacy source code that is not 64-bit
safe now, and using 32-bit time_t will make that easier in a lot of ways.
Note that I am also leading the effort to make 32-bit Linux ready for using
64-bit time_t on all architectures, so ARM64 ILP32 will be fixed as well, it
just won't be any better or worse than the others.

Arnd

2015-04-13 22:59:09

by Philipp Tomsich

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

Arnd,

> 1. Adding a whole new ABI to the kernel is adding a long-term maintenance
> burden, and we don't want to do that just because someone thinks it's a cute
> hack or because it might add a few percent in performance of some low-level
> benchmark. Please describe in the cover-letter for the patch series
> specifically what applications you have in mind that would be using this, and
> what the expected timeframe is before users could move to 64-bit user space.

There’s a couple of drivers behind getting ILP32 merged on ARM64:
(a) There’s plenty of applications (i.e. having a large code-base, but not requiring
a 64bit address space) that can’t readily be migrated to LP64 (typically networking
or data-storage applications) because they were written assuming an ILP32 data
model. Many of these applications will never become suitable for a LP64 data
model and will remain locked into ILP32 operating environments.
(b) A number of SPEC2006 components (i.e. not low-level benchmarks, but test
cases that have been derived from large application use cases) benefit from
having a denser data-representation—this includes the mcf, xalancbmk, astar
and ometpp. This not an observation specific to ARM64 and can be observed
on other architectures as well (e.g. [1] contains data for POWER from 2010).
(c) Using AArch32 (assuming that any given ARMv8 processor supports it),
is not a real alternative, as 64bit arithmetic is not supported on AArch32 and the
AArch32 register set is significantly smaller. Our experience shows that the
benefit of having 64bit registers, of a larger register file and of using 64bit
arithmetic makes ILP32 a worthwhile improvement over AArch32.

In summary, we believe that the need for ILP32 will never disappear on ARM64.
In fact, I rather expect the AArch32 compatibility to eventually disapper from
further processor designs… which will turn ILP32 into the only option for
legacy software.

> 2. The ABI follows what x86 has their "x32" ABI. This never saw a lot of
> adoption and in retrospect the decision to have separate system calls seems
> to not have helped them. My feeling now is that if we add support for the
> ARM64 ILP32 ELF ABI, we should better stick to the existing system call ABI
> as close as possible and reuse the existing system call table. I realize
> that this is a bit controversial, but please let's talk about this now.

I see benefits and drawback to merging the system tables. Our philosophy is
already somewhat different from x32 and from the original patch-series, as you
can see from the changes dealing with stack_t in the ‘sys_rt_sigreturn' and
‘setup_rt_frame’ functions. While these could have been duplicated and
specialized for each ABI (as on x32), the attempt was made to keep these
changes localized.

However, this approach can not always work: if you consider cases like
‘sys_msgsnd’ and ‘compat_sys_msgsnd’, there’s little to no benefit in having
just a ‘aarch64_sys_msgsnd’, which then calls either the LP64 or the compat
version of the underlying system call. Having a second system call table
helps to reduce the overheads in this case and keeps things readable.

This comes down to the fact, that a few calls will always be different due to
historical baggage in data structures shared between userspace and kernel:
'struct msgbuf’ immediatly comes to mind.

I would liken the situation with ARM64 more of MIPS64 with its 64bit ABI and
its n32 ABI than to x32… but even there it’s two separate system call tables
(although sequentially concatenated).

In other words: I fail to see the benefit from keeping the existing table.
I you elaborate on how such a solution should look, I might be better able
to follow.

> The most important aspect here I think is time_t, and while it means starting
> out with a system call ABI that is not ready for y2038, at the same time the
> purpose of ILP32 support is to support legacy source code that is not 64-bit
> safe now, and using 32-bit time_t will make that easier in a lot of ways.
> Note that I am also leading the effort to make 32-bit Linux ready for using
> 64-bit time_t on all architectures, so ARM64 ILP32 will be fixed as well, it
> just won't be any better or worse than the others.

The decision to use the 64bit time_t actually came out of Andrew’s earliest
patch-set from late 2013… we based the kernel-side of ILP32 on that one, while
we focussed on getting all the other components into a working shape.

Breaking the C specification (by redefining time_t) always remained a
controversial issue on our end, as we knew that the day of switching back
to a 32-bit time_t would eventually have to come.


Cheers,
Phil.

[1] https://gcc.gnu.org/wiki/summit2010?action=AttachFile&do=get&target=meissner2.pdf-

2015-04-14 09:40:52

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Tuesday 14 April 2015 00:58:59 Dr. Philipp Tomsich wrote:
> Arnd,
>
> > 1. Adding a whole new ABI to the kernel is adding a long-term maintenance
> > burden, and we don't want to do that just because someone thinks it's a cute
> > hack or because it might add a few percent in performance of some low-level
> > benchmark. Please describe in the cover-letter for the patch series
> > specifically what applications you have in mind that would be using this, and
> > what the expected timeframe is before users could move to 64-bit user space.
>
> There’s a couple of drivers behind getting ILP32 merged on ARM64:
> (a) There’s plenty of applications (i.e. having a large code-base, but not requiring
> a 64bit address space) that can’t readily be migrated to LP64 (typically networking
> or data-storage applications) because they were written assuming an ILP32 data
> model. Many of these applications will never become suitable for a LP64 data
> model and will remain locked into ILP32 operating environments.
> (b) A number of SPEC2006 components (i.e. not low-level benchmarks, but test
> cases that have been derived from large application use cases) benefit from
> having a denser data-representation—this includes the mcf, xalancbmk, astar
> and ometpp. This not an observation specific to ARM64 and can be observed
> on other architectures as well (e.g. [1] contains data for POWER from 2010).
> (c) Using AArch32 (assuming that any given ARMv8 processor supports it),
> is not a real alternative, as 64bit arithmetic is not supported on AArch32 and the
> AArch32 register set is significantly smaller. Our experience shows that the
> benefit of having 64bit registers, of a larger register file and of using 64bit
> arithmetic makes ILP32 a worthwhile improvement over AArch32.
>
> In summary, we believe that the need for ILP32 will never disappear on ARM64.
> In fact, I rather expect the AArch32 compatibility to eventually disapper from
> further processor designs… which will turn ILP32 into the only option for
> legacy software.

Ok, this is the kind of text that I was looking for to put in the cover letter,
and eventually into the git changelog when the branch gets merged.

Regarding a), listing specific applications would be helpful. I keep having
trouble coming up with examples that fit in all these categories:

- can be easily ported to a brand new CPU architecture
- is complex enough to to not be portable to 64-bit
- is performance sensitive enough to not work with full emulation
- fits within the memory constraints of a 32-bit task a few years from
now.
- must run on CPUs that are explicitly designed to not support 32-bit
(aarch32) tasks.

I have seen a lot of legacy code, but most of it fails at one of the
above. There is also a lot of legacy code (from MS Windows) that
already supports LLP64 but not LP64.


> > The most important aspect here I think is time_t, and while it means starting
> > out with a system call ABI that is not ready for y2038, at the same time the
> > purpose of ILP32 support is to support legacy source code that is not 64-bit
> > safe now, and using 32-bit time_t will make that easier in a lot of ways.
> > Note that I am also leading the effort to make 32-bit Linux ready for using
> > 64-bit time_t on all architectures, so ARM64 ILP32 will be fixed as well, it
> > just won't be any better or worse than the others.
>
> The decision to use the 64bit time_t actually came out of Andrew’s earliest
> patch-set from late 2013… we based the kernel-side of ILP32 on that one, while
> we focussed on getting all the other components into a working shape.
>
> Breaking the C specification (by redefining time_t) always remained a
> controversial issue on our end, as we knew that the day of switching back
> to a 32-bit time_t would eventually have to come.

Well, the reason that x32 uses a 64-bit time_t is because Linus Torvalds
intervened and asked for it to be done that way. I just think that today
we have a better plan for dealing with the issue on the whole.

I'd definitely want to get input from other parties on this. I know that
Rich Felker was particularly against the x32 definition of timespec, and
it using 32-bit time_t would let us avoid the controversy for the moment,
but of course we get to the same point later when we have to fix for
all architectures anyway.

Arnd

2015-04-14 10:08:49

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Tuesday 14 April 2015 11:33:13 Dr. Philipp Tomsich wrote:
> Arnd,
>
> After getting a good night’s sleep, the “reuse the existing system call table” comment
> makes a little more sense as I construe it as having just one merged system call table
> for both LP64 and ILP32 and handling the differences through a different system call
> numbering in unistd.h towards LP64 and ILP32 processes.
>
> If this is the intended implementation, I am not fully sold on the benefit: having a private
> copy of unistd.h for ARM64 seems to be a less readable and less maintenance-friendly
> solution to having separate tables.
>
> We’re open to input on this and—if merging the system call tables is the consensus—
> would like to get the change underway as soon as possible.

There are multiple ways of doing this:

a) separate syscall table for arm64: as you say, this is the current approach,
and I'd like to avoid that too
b) add syscalls for ilp32 as additional numbers in the normal lp64 version of
asm-generic/unistd.h, and share the binary tables between ilp32 and lp64
on aarch64
c) change asm-generic/unistd.h to generate three possible tables: instead of
just native (lp64 or ilp32 depending on the arch), compat (support for
existing ilp32 binaries on some architectures, there would also be a
"modern" ilp32 variant that is a mix of the two, as your table today
d) don't use the asm-generic/unistd.h table for aarch64-ilp32 at all, but instead
reuse the table from arch/arm64/include/asm/unistd32.h

I think you are referring to approach b) or c) above, but my preferred one
would actually be d).

> > On 14 Apr 2015, at 00:58, Dr. Philipp Tomsich <[email protected]> wrote:
> >
> >> 2. The ABI follows what x86 has their "x32" ABI. This never saw a lot of
> >> adoption and in retrospect the decision to have separate system calls seems
> >> to not have helped them. My feeling now is that if we add support for the
> >> ARM64 ILP32 ELF ABI, we should better stick to the existing system call ABI
> >> as close as possible and reuse the existing system call table. I realize
> >> that this is a bit controversial, but please let's talk about this now.
> >
> > I see benefits and drawback to merging the system tables. Our philosophy is
> > already somewhat different from x32 and from the original patch-series, as you
> > can see from the changes dealing with stack_t in the ‘sys_rt_sigreturn' and
> > ‘setup_rt_frame’ functions. While these could have been duplicated and
> > specialized for each ABI (as on x32), the attempt was made to keep these
> > changes localized.
> >
> > However, this approach can not always work: if you consider cases like
> > ‘sys_msgsnd’ and ‘compat_sys_msgsnd’, there’s little to no benefit in having
> > just a ‘aarch64_sys_msgsnd’, which then calls either the LP64 or the compat
> > version of the underlying system call. Having a second system call table
> > helps to reduce the overheads in this case and keeps things readable.
> >
> > This comes down to the fact, that a few calls will always be different due to
> > historical baggage in data structures shared between userspace and kernel:
> > 'struct msgbuf’ immediatly comes to mind.
> >
> > I would liken the situation with ARM64 more of MIPS64 with its 64bit ABI and
> > its n32 ABI than to x32… but even there it’s two separate system call tables
> > (although sequentially concatenated).
> >
> > In other words: I fail to see the benefit from keeping the existing table.
> > I you elaborate on how such a solution should look, I might be better able
> > to follow.

I mainly want to avoid accidentally creating new ABIs for syscalls and ioctls:
we have many drivers that today use ioctls with data structures derived from
'__kernel_ulong_t' in some form, often by including a timespec or time_t in
their own data structures. These are almost all broken today, because the
data structures are a mix of the aarch32 and aarch64 variants, while the
ioctl() system call in ilp32 always uses the aarch32 format by default.

An example here would be

struct cyclades_idle_stats {
__kernel_time_t in_use; /* Time device has been in use (secs) */
__kernel_time_t recv_idle; /* Time since last char received (secs) */
__kernel_time_t xmit_idle; /* Time since last char transmitted (secs) */
unsigned long recv_bytes; /* Bytes received */
unsigned long xmit_bytes; /* Bytes transmitted */
unsigned long overruns; /* Input overruns */
unsigned long frame_errs; /* Input framing errors */
unsigned long parity_errs; /* Input parity errors */
};

for a random ancient driver. Introducing a third set of data structures
and syscalls for aarch64-ilp32 means that any driver doing something like
this needs to be modified to support existing user space source code.

If we stick to the normal compat32 implementation for all data structures
and syscalls, we can support all drivers that work with aarch32 emulation
today, as well as any one that gains support later on a regular compat32
architecture (x86, powerpc, sparc, mips, arm, tile, parisc, s390), and
we don't have to watch all new ioctl interfaces that get added to the
kernel. Note that this does not just impact ioctl, but also things like
setsockopts and drivers that communicate with user space through a
mmapped data structure.

Using that existing table would also make it much easier to add support
for additional C libraries, which then just have to implement the ELF
format, but could reuse the arm32 kernel interfaces.

Finally, there is a certain set of security issues from each new syscall
we introduce. With the aarch32 syscall table, we have a higher degree
of reuse of existing code, so we won't introduce security bugs that
are only in one of the two ilp32 ABIs (aarch32 and aarch64).

One notable downside of this is that all system calls have to pass 64-bit
arguments (i.e. loff_t) in two registers instead of one, to match the
aarch32 calling conventions, but that would be limited to a small part
of the libc implementation that already does the same thing for arm32.

Arnd

2015-04-14 12:18:57

by Andrew Pinski

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64





> On Apr 14, 2015, at 3:08 AM, Arnd Bergmann <[email protected]> wrote:
>
>> On Tuesday 14 April 2015 11:33:13 Dr. Philipp Tomsich wrote:
>> Arnd,
>>
>> After getting a good night?s sleep, the ?reuse the existing system call table? comment
>> makes a little more sense as I construe it as having just one merged system call table
>> for both LP64 and ILP32 and handling the differences through a different system call
>> numbering in unistd.h towards LP64 and ILP32 processes.
>>
>> If this is the intended implementation, I am not fully sold on the benefit: having a private
>> copy of unistd.h for ARM64 seems to be a less readable and less maintenance-friendly
>> solution to having separate tables.
>>
>> We?re open to input on this and?if merging the system call tables is the consensus?
>> would like to get the change underway as soon as possible.
>
> There are multiple ways of doing this:
>
> a) separate syscall table for arm64: as you say, this is the current approach,
> and I'd like to avoid that too
> b) add syscalls for ilp32 as additional numbers in the normal lp64 version of
> asm-generic/unistd.h, and share the binary tables between ilp32 and lp64
> on aarch64
> c) change asm-generic/unistd.h to generate three possible tables: instead of
> just native (lp64 or ilp32 depending on the arch), compat (support for
> existing ilp32 binaries on some architectures, there would also be a
> "modern" ilp32 variant that is a mix of the two, as your table today
> d) don't use the asm-generic/unistd.h table for aarch64-ilp32 at all, but instead
> reuse the table from arch/arm64/include/asm/unistd32.h
>
> I think you are referring to approach b) or c) above, but my preferred one
> would actually be d).

D is the worst of all 4 options in my mind. The reason is when a new syscall is added, then you have to update that file too. Also d is worse than the rest as you no longer default to 64bit off_t which is not a good thing. B is just as bad and goes against using the generic syscall numbers.

I was trying to model ilp32 so there was less maintain hassle if a new syscall was added.

Also about time_t, my original patch had used 32bit but was asked to change it to the 64bit one. So now I am upset this being asked again to change it back. The review process for the linux kernel is much harder than the review process of gcc or even glibc now.

Thanks,
Andrew


>
>>>> On 14 Apr 2015, at 00:58, Dr. Philipp Tomsich <[email protected]> wrote:
>>>>
>>>> 2. The ABI follows what x86 has their "x32" ABI. This never saw a lot of
>>>> adoption and in retrospect the decision to have separate system calls seems
>>>> to not have helped them. My feeling now is that if we add support for the
>>>> ARM64 ILP32 ELF ABI, we should better stick to the existing system call ABI
>>>> as close as possible and reuse the existing system call table. I realize
>>>> that this is a bit controversial, but please let's talk about this now.
>>>
>>> I see benefits and drawback to merging the system tables. Our philosophy is
>>> already somewhat different from x32 and from the original patch-series, as you
>>> can see from the changes dealing with stack_t in the ?sys_rt_sigreturn' and
>>> ?setup_rt_frame? functions. While these could have been duplicated and
>>> specialized for each ABI (as on x32), the attempt was made to keep these
>>> changes localized.
>>>
>>> However, this approach can not always work: if you consider cases like
>>> ?sys_msgsnd? and ?compat_sys_msgsnd?, there?s little to no benefit in having
>>> just a ?aarch64_sys_msgsnd?, which then calls either the LP64 or the compat
>>> version of the underlying system call. Having a second system call table
>>> helps to reduce the overheads in this case and keeps things readable.
>>>
>>> This comes down to the fact, that a few calls will always be different due to
>>> historical baggage in data structures shared between userspace and kernel:
>>> 'struct msgbuf? immediatly comes to mind.
>>>
>>> I would liken the situation with ARM64 more of MIPS64 with its 64bit ABI and
>>> its n32 ABI than to x32? but even there it?s two separate system call tables
>>> (although sequentially concatenated).
>>>
>>> In other words: I fail to see the benefit from keeping the existing table.
>>> I you elaborate on how such a solution should look, I might be better able
>>> to follow.
>
> I mainly want to avoid accidentally creating new ABIs for syscalls and ioctls:
> we have many drivers that today use ioctls with data structures derived from
> '__kernel_ulong_t' in some form, often by including a timespec or time_t in
> their own data structures. These are almost all broken today, because the
> data structures are a mix of the aarch32 and aarch64 variants, while the
> ioctl() system call in ilp32 always uses the aarch32 format by default.
>
> An example here would be
>
> struct cyclades_idle_stats {
> __kernel_time_t in_use; /* Time device has been in use (secs) */
> __kernel_time_t recv_idle; /* Time since last char received (secs) */
> __kernel_time_t xmit_idle; /* Time since last char transmitted (secs) */
> unsigned long recv_bytes; /* Bytes received */
> unsigned long xmit_bytes; /* Bytes transmitted */
> unsigned long overruns; /* Input overruns */
> unsigned long frame_errs; /* Input framing errors */
> unsigned long parity_errs; /* Input parity errors */
> };
>
> for a random ancient driver. Introducing a third set of data structures
> and syscalls for aarch64-ilp32 means that any driver doing something like
> this needs to be modified to support existing user space source code.
>
> If we stick to the normal compat32 implementation for all data structures
> and syscalls, we can support all drivers that work with aarch32 emulation
> today, as well as any one that gains support later on a regular compat32
> architecture (x86, powerpc, sparc, mips, arm, tile, parisc, s390), and
> we don't have to watch all new ioctl interfaces that get added to the
> kernel. Note that this does not just impact ioctl, but also things like
> setsockopts and drivers that communicate with user space through a
> mmapped data structure.
>
> Using that existing table would also make it much easier to add support
> for additional C libraries, which then just have to implement the ELF
> format, but could reuse the arm32 kernel interfaces.
>
> Finally, there is a certain set of security issues from each new syscall
> we introduce. With the aarch32 syscall table, we have a higher degree
> of reuse of existing code, so we won't introduce security bugs that
> are only in one of the two ilp32 ABIs (aarch32 and aarch64).
>
> One notable downside of this is that all system calls have to pass 64-bit
> arguments (i.e. loff_t) in two registers instead of one, to match the
> aarch32 calling conventions, but that would be limited to a small part
> of the libc implementation that already does the same thing for arm32.
>
> Arnd

2015-04-14 11:15:07

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Tuesday 14 April 2015 10:45:43 Pinski, Andrew wrote:
> > On Apr 14, 2015, at 3:08 AM, Arnd Bergmann <[email protected]> wrote:
> >
> >> On Tuesday 14 April 2015 11:33:13 Dr. Philipp Tomsich wrote:
> >> Arnd,
> >>
> >> After getting a good night’s sleep, the “reuse the existing system call table” comment
> >> makes a little more sense as I construe it as having just one merged system call table
> >> for both LP64 and ILP32 and handling the differences through a different system call
> >> numbering in unistd.h towards LP64 and ILP32 processes.
> >>
> >> If this is the intended implementation, I am not fully sold on the benefit: having a private
> >> copy of unistd.h for ARM64 seems to be a less readable and less maintenance-friendly
> >> solution to having separate tables.
> >>
> >> We’re open to input on this and—if merging the system call tables is the consensus—
> >> would like to get the change underway as soon as possible.
> >
> > There are multiple ways of doing this:
> >
> > a) separate syscall table for arm64: as you say, this is the current approach,
> > and I'd like to avoid that too
> > b) add syscalls for ilp32 as additional numbers in the normal lp64 version of
> > asm-generic/unistd.h, and share the binary tables between ilp32 and lp64
> > on aarch64
> > c) change asm-generic/unistd.h to generate three possible tables: instead of
> > just native (lp64 or ilp32 depending on the arch), compat (support for
> > existing ilp32 binaries on some architectures, there would also be a
> > "modern" ilp32 variant that is a mix of the two, as your table today
> > d) don't use the asm-generic/unistd.h table for aarch64-ilp32 at all, but instead
> > reuse the table from arch/arm64/include/asm/unistd32.h
> >
> > I think you are referring to approach b) or c) above, but my preferred one
> > would actually be d).
>
> D is the worst of all 4 options in my mind. The reason is when a new syscall is
> added, then you have to update that file too.

I don't know what the miscommunication is here, but the advantage of d is
specifically that it is /less/ work to maintain: With the current approach,
each new syscall that gets added needs to be checked to see if the normal
aarch64 version works or if it needs another wrapper, while with d) we
get the update for free, because we follow exactly what aarch32 is doing.

> Also d is worse than the rest as
> you no longer default to 64bit off_t which is not a good thing.

That decision is up to the libc implementation, just as it is for the existing
aarch32 libc. The kernel just offers both versions and the libc can pick
one, or use the _LARGEFILE64_SOURCE hack that glibc has to also implement
both. It would probably be reasonable to use 64-bit off_t only for a libc
and ignore the old calls.

> B is just as bad and goes against using the generic syscall numbers.

How so? The newly introduce syscalls then would be the generic ones.

> I was trying to model ilp32 so there was less maintain hassle if a new syscall was added.
>
> Also about time_t, my original patch had used 32bit but was asked to change
> it to the 64bit one. So now I am upset this being asked again to change it back.
> The review process for the linux kernel is much harder than the review process
> of gcc or even glibc now.

For now, I'm just opening that discussion again, but the reason this
comes up again now is that a lot has happened in the meantime on this
front, and we have already decided to merge new architecture ports with
32-bit time_t since.

Arnd

2015-04-14 11:51:00

by Philipp Tomsich

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64


> On 14 Apr 2015, at 13:14, Arnd Bergmann <[email protected]> wrote:
>
> On Tuesday 14 April 2015 10:45:43 Pinski, Andrew wrote:
>>> On Apr 14, 2015, at 3:08 AM, Arnd Bergmann <[email protected]> wrote:
>>>
>>>> On Tuesday 14 April 2015 11:33:13 Dr. Philipp Tomsich wrote:
>>>> Arnd,
>>>>
>>>> After getting a good night’s sleep, the “reuse the existing system call table” comment
>>>> makes a little more sense as I construe it as having just one merged system call table
>>>> for both LP64 and ILP32 and handling the differences through a different system call
>>>> numbering in unistd.h towards LP64 and ILP32 processes.
>>>>
>>>> If this is the intended implementation, I am not fully sold on the benefit: having a private
>>>> copy of unistd.h for ARM64 seems to be a less readable and less maintenance-friendly
>>>> solution to having separate tables.
>>>>
>>>> We’re open to input on this and—if merging the system call tables is the consensus—
>>>> would like to get the change underway as soon as possible.
>>>
>>> There are multiple ways of doing this:
>>>
>>> a) separate syscall table for arm64: as you say, this is the current approach,
>>> and I'd like to avoid that too
>>> b) add syscalls for ilp32 as additional numbers in the normal lp64 version of
>>> asm-generic/unistd.h, and share the binary tables between ilp32 and lp64
>>> on aarch64
>>> c) change asm-generic/unistd.h to generate three possible tables: instead of
>>> just native (lp64 or ilp32 depending on the arch), compat (support for
>>> existing ilp32 binaries on some architectures, there would also be a
>>> "modern" ilp32 variant that is a mix of the two, as your table today
>>> d) don't use the asm-generic/unistd.h table for aarch64-ilp32 at all, but instead
>>> reuse the table from arch/arm64/include/asm/unistd32.h
>>>
>>> I think you are referring to approach b) or c) above, but my preferred one
>>> would actually be d).
>>
>> D is the worst of all 4 options in my mind. The reason is when a new syscall is
>> added, then you have to update that file too.
>
> I don't know what the miscommunication is here, but the advantage of d is
> specifically that it is /less/ work to maintain: With the current approach,
> each new syscall that gets added needs to be checked to see if the normal
> aarch64 version works or if it needs another wrapper, while with d) we
> get the update for free, because we follow exactly what aarch32 is doing.

I must agree with Andrew, that (d) seems like a bad fit for ILP32… after all the
ILP32 (ELF) ABI specifies that 64bit values are to be passed in a single register,
but the unistd32.h assumes a 32bit kernel that receives 64bit arguments split
over two registers (i.e. the 64-variants of the various system calls, such as
ftruncate64).

I strongly prefer (b) as this satisfies the largest number of requirements:
(i) it will be a single system call table for LP64 and ILP32
(ii) it’s easy to be make use of the 64bit capable system calls
(iii) it fits with the relationship of ILP32 to LP64 in the ILP32 ELF ABI definition

As we don’t support ILP32 without LP64, the resulting implementation will
be even simpler (i.e. no need to duplicate the entire table) than the n32
implementation on MIPS...

>> Also d is worse than the rest as
>> you no longer default to 64bit off_t which is not a good thing.
>
> That decision is up to the libc implementation, just as it is for the existing
> aarch32 libc. The kernel just offers both versions and the libc can pick
> one, or use the _LARGEFILE64_SOURCE hack that glibc has to also implement
> both. It would probably be reasonable to use 64-bit off_t only for a libc
> and ignore the old calls.

The glibc implementation, as we have it today, always uses the 64bit system call
and performs overflow-checking on results (on ILP32, we can’t perform overflow
checking on arguments, as the callee needs to sign-extend).

In other words: glibc uses the LP64 system calls and handles any pre- and
post-processing in the system-call wrappers.

>> B is just as bad and goes against using the generic syscall numbers.
>
> How so? The newly introduce syscalls then would be the generic ones.

By applying the “strace-test” (i.e. “How will this affect the implementation of strace,
when considering a ILP32-compiled and a LP64-compiled strace where both should
be capable of tracing either ILP32 or LP64 targets?”), option (b) appears the cleanest
choice, as no test on the dependent’s ABI would be necessary and all internal
dispatching could be performed on syscall numbers alone.

Using the same "strace-test", option (d) would be the least preferred, as it will make
the internal dispatching entirely dependent on the dependent’s ABI.

>> I was trying to model ilp32 so there was less maintain hassle if a new syscall was added.
>>
>> Also about time_t, my original patch had used 32bit but was asked to change
>> it to the 64bit one. So now I am upset this being asked again to change it back.
>> The review process for the linux kernel is much harder than the review process
>> of gcc or even glibc now.
>
> For now, I'm just opening that discussion again, but the reason this
> comes up again now is that a lot has happened in the meantime on this
> front, and we have already decided to merge new architecture ports with
> 32-bit time_t since.

I think my sloppy e-mail writing blew this out of proportion: I never intended to focus on
‘time_t’, but on ‘timespec’ as a whole (i.e. keeping ‘tv_nsec’ defined as a ‘long’ in
userspace). The problem, as far as I can see from the kernel source, is that
kernel/compat.c assumes that tv_sec (time_t) and tv_nsec (long) are of equal size.

My hope was that to resolve this by extending the compat-layer (in those places where
COMPAT_USE_64BIT_TIME is tested) with a COMPAT_USE_64BIT_TIME_COMPLIANT
path that supports a 64-bit time_t with a ILP32-long tv_nsecs.

We should not break C11-compliant programs by changing the size of tv_nsecs. As a
consequence, we shouldn’t propagate a questionable choice made for x32 into ILP32.
On the other hand, I don’t want to limit time_t to 32bits, as C11 permits any reasonable
define for it…

--Philipp.-

2015-04-14 11:52:05

by Andrew Pinski

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64





> On Apr 14, 2015, at 4:15 AM, Arnd Bergmann <[email protected]> wrote:
>
> On Tuesday 14 April 2015 10:45:43 Pinski, Andrew wrote:
>>> On Apr 14, 2015, at 3:08 AM, Arnd Bergmann <[email protected]> wrote:
>>>
>>>> On Tuesday 14 April 2015 11:33:13 Dr. Philipp Tomsich wrote:
>>>> Arnd,
>>>>
>>>> After getting a good night?s sleep, the ?reuse the existing system call table? comment
>>>> makes a little more sense as I construe it as having just one merged system call table
>>>> for both LP64 and ILP32 and handling the differences through a different system call
>>>> numbering in unistd.h towards LP64 and ILP32 processes.
>>>>
>>>> If this is the intended implementation, I am not fully sold on the benefit: having a private
>>>> copy of unistd.h for ARM64 seems to be a less readable and less maintenance-friendly
>>>> solution to having separate tables.
>>>>
>>>> We?re open to input on this and?if merging the system call tables is the consensus?
>>>> would like to get the change underway as soon as possible.
>>>
>>> There are multiple ways of doing this:
>>>
>>> a) separate syscall table for arm64: as you say, this is the current approach,
>>> and I'd like to avoid that too
>>> b) add syscalls for ilp32 as additional numbers in the normal lp64 version of
>>> asm-generic/unistd.h, and share the binary tables between ilp32 and lp64
>>> on aarch64
>>> c) change asm-generic/unistd.h to generate three possible tables: instead of
>>> just native (lp64 or ilp32 depending on the arch), compat (support for
>>> existing ilp32 binaries on some architectures, there would also be a
>>> "modern" ilp32 variant that is a mix of the two, as your table today
>>> d) don't use the asm-generic/unistd.h table for aarch64-ilp32 at all, but instead
>>> reuse the table from arch/arm64/include/asm/unistd32.h
>>>
>>> I think you are referring to approach b) or c) above, but my preferred one
>>> would actually be d).
>>
>> D is the worst of all 4 options in my mind. The reason is when a new syscall is
>> added, then you have to update that file too.
>
> I don't know what the miscommunication is here, but the advantage of d is
> specifically that it is /less/ work to maintain: With the current approach,
> each new syscall that gets added needs to be checked to see if the normal
> aarch64 version works or if it needs another wrapper, while with d) we
> get the update for free, because we follow exactly what aarch32 is doing.

More than that d won't work due to ucontext being different between aarch32 and aarch64. I still say the current way is the best approach and is better option than the rest and it was what was agreed upon when I wrote the patch. I don't see why you are agreeing a different way. The split 64bit long was decided not to be split too, there was a previous discussion about that too.

Also this abi is about to be used in a product so any changes need to happen fast and need to thought out why making changes to it make senses. Changing to use the aarch32 syscall #'s make less sense since this is not a legacy syscalls.

>
>> Also d is worse than the rest as
>> you no longer default to 64bit off_t which is not a good thing.
>
> That decision is up to the libc implementation, just as it is for the existing
> aarch32 libc. The kernel just offers both versions and the libc can pick
> one, or use the _LARGEFILE64_SOURCE hack that glibc has to also implement
> both. It would probably be reasonable to use 64-bit off_t only for a libc
> and ignore the old calls.
>
>> B is just as bad and goes against using the generic syscall numbers.
>
> How so? The newly introduce syscalls then would be the generic ones.
>
>> I was trying to model ilp32 so there was less maintain hassle if a new syscall was added.
>>
>> Also about time_t, my original patch had used 32bit but was asked to change
>> it to the 64bit one. So now I am upset this being asked again to change it back.
>> The review process for the linux kernel is much harder than the review process
>> of gcc or even glibc now.
>
> For now, I'm just opening that discussion again, but the reason this
> comes up again now is that a lot has happened in the meantime on this
> front, and we have already decided to merge new architecture ports with
> 32-bit time_t since.
>
> Arnd

2015-04-14 13:38:23

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Tue, Apr 14, 2015 at 10:45:43AM +0000, Pinski, Andrew wrote:
> Also about time_t, my original patch had used 32bit but was asked to
> change it to the 64bit one. So now I am upset this being asked again
> to change it back.

At the time, we were not aware of plans to fix existing 32-bit
architectures, so we followed Linus' similar request on x32.

> The review process for the linux kernel is much harder than the review
> process of gcc or even glibc now.

This is not really about kernel code review but about defining the
user/kernel ABI. It shouldn't even be a kernel-only decision, we need to
get the libc people involved. So yes, you get to prototype such ABI in
several kernel patch incarnations and code may be thrown away but that's
better than making the wrong decision on the long run.

As for gcc, the ILP32 ABI is clear to them, they only have to review
implementation details.

--
Catalin

2015-04-14 14:08:12

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Tuesday 14 April 2015 13:50:21 Dr. Philipp Tomsich wrote:
>
> > On 14 Apr 2015, at 13:14, Arnd Bergmann <[email protected]> wrote:
> >
> > On Tuesday 14 April 2015 10:45:43 Pinski, Andrew wrote:
> >>> On Apr 14, 2015, at 3:08 AM, Arnd Bergmann <[email protected]> wrote:
> >>>
> >>>> On Tuesday 14 April 2015 11:33:13 Dr. Philipp Tomsich wrote:
> >>>> Arnd,
> >>>>
> >>>> After getting a good night’s sleep, the “reuse the existing system call table” comment
> >>>> makes a little more sense as I construe it as having just one merged system call table
> >>>> for both LP64 and ILP32 and handling the differences through a different system call
> >>>> numbering in unistd.h towards LP64 and ILP32 processes.
> >>>>
> >>>> If this is the intended implementation, I am not fully sold on the benefit: having a private
> >>>> copy of unistd.h for ARM64 seems to be a less readable and less maintenance-friendly
> >>>> solution to having separate tables.
> >>>>
> >>>> We’re open to input on this and—if merging the system call tables is the consensus—
> >>>> would like to get the change underway as soon as possible.
> >>>
> >>> There are multiple ways of doing this:
> >>>
> >>> a) separate syscall table for arm64: as you say, this is the current approach,
> >>> and I'd like to avoid that too
> >>> b) add syscalls for ilp32 as additional numbers in the normal lp64 version of
> >>> asm-generic/unistd.h, and share the binary tables between ilp32 and lp64
> >>> on aarch64
> >>> c) change asm-generic/unistd.h to generate three possible tables: instead of
> >>> just native (lp64 or ilp32 depending on the arch), compat (support for
> >>> existing ilp32 binaries on some architectures, there would also be a
> >>> "modern" ilp32 variant that is a mix of the two, as your table today
> >>> d) don't use the asm-generic/unistd.h table for aarch64-ilp32 at all, but instead
> >>> reuse the table from arch/arm64/include/asm/unistd32.h
> >>>
> >>> I think you are referring to approach b) or c) above, but my preferred one
> >>> would actually be d).
> >>
> >> D is the worst of all 4 options in my mind. The reason is when a new syscall is
> >> added, then you have to update that file too.
> >
> > I don't know what the miscommunication is here, but the advantage of d is
> > specifically that it is /less/ work to maintain: With the current approach,
> > each new syscall that gets added needs to be checked to see if the normal
> > aarch64 version works or if it needs another wrapper, while with d) we
> > get the update for free, because we follow exactly what aarch32 is doing.
>
> I must agree with Andrew, that (d) seems like a bad fit for ILP32… after all the
> ILP32 (ELF) ABI specifies that 64bit values are to be passed in a single register,
> but the unistd32.h assumes a 32bit kernel that receives 64bit arguments split
> over two registers (i.e. the 64-variants of the various system calls, such as
> ftruncate64).
>
> I strongly prefer (b) as this satisfies the largest number of requirements:
> (i) it will be a single system call table for LP64 and ILP32
> (ii) it’s easy to be make use of the 64bit capable system calls
> (iii) it fits with the relationship of ILP32 to LP64 in the ILP32 ELF ABI definition

Ok, I see. I'd still like to hear other opinions on the matter, and my
preference remains D. Most importantly, I'd like Catalin and Will to
comment on this.

For completeness, there is yet another option, which would be to use the
exact system call table from arm64 and do all the emulation in user space
rather than the kernel. This would however be the least compatible with
existing source code, so you probably don't want to do that.

> As we don’t support ILP32 without LP64, the resulting implementation will
> be even simpler (i.e. no need to duplicate the entire table) than the n32
> implementation on MIPS...

Right. Andrew didn't like the idea that the syscall numbers are slightly
different in B, but I think that is not a significant downside, as the kernel
header would be done in a way to report the correct __NR_* macros here.

> >> Also d is worse than the rest as
> >> you no longer default to 64bit off_t which is not a good thing.
> >
> > That decision is up to the libc implementation, just as it is for the existing
> > aarch32 libc. The kernel just offers both versions and the libc can pick
> > one, or use the _LARGEFILE64_SOURCE hack that glibc has to also implement
> > both. It would probably be reasonable to use 64-bit off_t only for a libc
> > and ignore the old calls.
>
> The glibc implementation, as we have it today, always uses the 64bit system call
> and performs overflow-checking on results (on ILP32, we can’t perform overflow
> checking on arguments, as the callee needs to sign-extend).
>
> In other words: glibc uses the LP64 system calls and handles any pre- and
> post-processing in the system-call wrappers.

Hmm, that sounds like much more work you already do in glibc than
you'd need to split up the 64-bit arguments for the eight syscalls
that pass an loff_t in a register.

> >> B is just as bad and goes against using the generic syscall numbers.
> >
> > How so? The newly introduce syscalls then would be the generic ones.
>
> By applying the “strace-test” (i.e. “How will this affect the implementation of strace,
> when considering a ILP32-compiled and a LP64-compiled strace where both should
> be capable of tracing either ILP32 or LP64 targets?”), option (b) appears the cleanest
> choice, as no test on the dependent’s ABI would be necessary and all internal
> dispatching could be performed on syscall numbers alone.
>
> Using the same "strace-test", option (d) would be the least preferred, as it will make
> the internal dispatching entirely dependent on the dependent’s ABI.

I don't understand what you mean here, please elaborate. Why would an ABI that works
on aarch32 be wrong on aarch64-ilp32 user space when you are using the same header
files?

> >> I was trying to model ilp32 so there was less maintain hassle if a new syscall was added.
> >>
> >> Also about time_t, my original patch had used 32bit but was asked to change
> >> it to the 64bit one. So now I am upset this being asked again to change it back.
> >> The review process for the linux kernel is much harder than the review process
> >> of gcc or even glibc now.
> >
> > For now, I'm just opening that discussion again, but the reason this
> > comes up again now is that a lot has happened in the meantime on this
> > front, and we have already decided to merge new architecture ports with
> > 32-bit time_t since.
>
> I think my sloppy e-mail writing blew this out of proportion: I never intended to focus on
> ‘time_t’, but on ‘timespec’ as a whole (i.e. keeping ‘tv_nsec’ defined as a ‘long’ in
> userspace). The problem, as far as I can see from the kernel source, is that
> kernel/compat.c assumes that tv_sec (time_t) and tv_nsec (long) are of equal size.

There are multiple problems relating to time_t here, the padding in
timespec is one of them. There are similar problems relating to __kernel_size_t,
__kernel_ptrdiff_t, __kernel_off_t, __kernel_clock_t, __kernel_ino_t and
structs that build on top of these: whenever you have device driver using
these in an ioctl, you don't know what a user space tool passes, as they
might use a kernel header that contains a 64-bit definition for that type,
or they may have their own definition using the standard types, e.g. copied
from an older kernel, or written independently.

time_t is just special here, because we know that we have to extend it
to 64-bit eventually, while for the others, staying at 32-bit wide types
would generally help compatibility with existing source code bases, both
in kernel drivers and in user space.

> My hope was that to resolve this by extending the compat-layer (in those places where
> COMPAT_USE_64BIT_TIME is tested) with a COMPAT_USE_64BIT_TIME_COMPLIANT
> path that supports a 64-bit time_t with a ILP32-long tv_nsecs.
>
> We should not break C11-compliant programs by changing the size of tv_nsecs. As a
> consequence, we shouldn’t propagate a questionable choice made for x32 into ILP32.
> On the other hand, I don’t want to limit time_t to 32bits, as C11 permits any reasonable
> define for it…

Breaking C11 is one concern, but to me the much more valuable question is
whether we break existing user space code. This is about code that is
already not 64-bit clean, so it's also likely to not cope well with
e.g. a 64-bit __kernel_ulong_t.

Arnd

2015-04-14 14:47:13

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Tue, Apr 14, 2015 at 12:08:11PM +0200, Arnd Bergmann wrote:
> On Tuesday 14 April 2015 11:33:13 Dr. Philipp Tomsich wrote:
> > After getting a good night’s sleep, the “reuse the existing system call table” comment
> > makes a little more sense as I construe it as having just one merged system call table
> > for both LP64 and ILP32 and handling the differences through a different system call
> > numbering in unistd.h towards LP64 and ILP32 processes.
> >
> > If this is the intended implementation, I am not fully sold on the benefit: having a private
> > copy of unistd.h for ARM64 seems to be a less readable and less maintenance-friendly
> > solution to having separate tables.
> >
> > We’re open to input on this and—if merging the system call tables is the consensus—
> > would like to get the change underway as soon as possible.
>
> There are multiple ways of doing this:

It doesn't look like they are exclusive options. For example you can use
(a) together with (c) or (d). Some more comments below:

> a) separate syscall table for arm64: as you say, this is the current approach,
> and I'd like to avoid that too

What is the problem with this option? Is it cache locality affected by
having another table? A syscall table currently stands at around 2KB. We
could halve it by storing relative offsets but I don't think we would
notice much performance improvement.

> b) add syscalls for ilp32 as additional numbers in the normal lp64 version of
> asm-generic/unistd.h, and share the binary tables between ilp32 and lp64
> on aarch64

Does this mean that an ILP32 task can still call LP64-only syscalls? How
many new syscalls are we looking at? Would these ILP32 numbers be
interspersed with the LP64 ones or some high values (say bit 12 set)?
The former isn't workable since may leave gaps on LP64 architectures.
The latter could work better if the ILP32 specific options are not
sparse.

> c) change asm-generic/unistd.h to generate three possible tables: instead of
> just native (lp64 or ilp32 depending on the arch), compat (support for
> existing ilp32 binaries on some architectures, there would also be a
> "modern" ilp32 variant that is a mix of the two, as your table today

I don't fully understand this. It looks to me like we need to generate
at least the LP64 and native ILP32 unistd.h anyway if we go for option a
or possibly b.

> d) don't use the asm-generic/unistd.h table for aarch64-ilp32 at all, but instead
> reuse the table from arch/arm64/include/asm/unistd32.h

IMO, (d) only makes sense if we treat ILP32 as a temporary solution
(a.k.a. hack) hoping that such applications will be eventually built for
LP64. If we treat native ILP32 as a real long term alternative to LP64,
I would rather use the asm-generic/unistd.h for syscalls. For example,
use 'openat' instead of 'open' on the native ILP32 (based on the
assumption that ILP32 is a long term alternative).

Unless we are aware of performance impact with (a), that's my preferred
option with some form of (b) next.

The above is mainly about syscall numbers and tables but the ABI goes
beyond this. And the key point is whether we go for an AArch32-like ABI
(32-bit time_t) or we try to define one close to LP64. If we go for an
AArch32-like ABI, we'll have to use the compat layer for some of
syscalls and assess how many of the asm/compat.h structures are
different from the generic ones (I wouldn't expect many).

> I mainly want to avoid accidentally creating new ABIs for syscalls and ioctls:
> we have many drivers that today use ioctls with data structures derived from
> '__kernel_ulong_t' in some form, often by including a timespec or time_t in
> their own data structures. These are almost all broken today, because the
> data structures are a mix of the aarch32 and aarch64 variants, while the
> ioctl() system call in ilp32 always uses the aarch32 format by default.
>
> An example here would be
>
> struct cyclades_idle_stats {
> __kernel_time_t in_use; /* Time device has been in use (secs) */
> __kernel_time_t recv_idle; /* Time since last char received (secs) */
> __kernel_time_t xmit_idle; /* Time since last char transmitted (secs) */
> unsigned long recv_bytes; /* Bytes received */
> unsigned long xmit_bytes; /* Bytes transmitted */
> unsigned long overruns; /* Input overruns */
> unsigned long frame_errs; /* Input framing errors */
> unsigned long parity_errs; /* Input parity errors */
> };
>
> for a random ancient driver. Introducing a third set of data structures
> and syscalls for aarch64-ilp32 means that any driver doing something like
> this needs to be modified to support existing user space source code.

That's indeed a problem as ILP32 doesn't look like any of the other
options (the siginfo structure is another case that doesn't fit in any
of the ABI as long as time_t is 64-bit).

> If we stick to the normal compat32 implementation for all data structures
> and syscalls, we can support all drivers that work with aarch32 emulation
> today, as well as any one that gains support later on a regular compat32
> architecture (x86, powerpc, sparc, mips, arm, tile, parisc, s390), and
> we don't have to watch all new ioctl interfaces that get added to the
> kernel. Note that this does not just impact ioctl, but also things like
> setsockopts and drivers that communicate with user space through a
> mmapped data structure.

I'm fine with this but I would limit this compat32 similarity to data
structures rather than syscall numbers. Why do we need to support some
old syscalls when we can easily use new variants (e.g. open vs openat)?

> Using that existing table would also make it much easier to add support
> for additional C libraries, which then just have to implement the ELF
> format, but could reuse the arm32 kernel interfaces.

The existing compat32 ABI is a bit limiting on a 64-bit architecture. I
think we should really take advantage of the 64-bit register width and
avoid splitting 64-bit arguments in two registers. At which point, we
need a separate table anyway.

> Finally, there is a certain set of security issues from each new syscall
> we introduce. With the aarch32 syscall table, we have a higher degree
> of reuse of existing code, so we won't introduce security bugs that
> are only in one of the two ilp32 ABIs (aarch32 and aarch64).

Note that the current aarch32 compat ABI assumes that the top 32-bit of
every register is either zeroed or preserved by the architecture on
exception entry. We know that an AArch32 application cannot access the
top 32-bit of an AArch64 register. With native ILP32 however this is no
longer the case (it is running in AArch64 mode). I can't immediately
think of a problem (information leak) but it needs to be reviewed.

> One notable downside of this is that all system calls have to pass 64-bit
> arguments (i.e. loff_t) in two registers instead of one, to match the
> aarch32 calling conventions, but that would be limited to a small part
> of the libc implementation that already does the same thing for arm32.

There is this downside but I'm still not convinced what the advantages
of sharing the compat32 table are (not talking about the data structures
though, I'm fine with sharing those).

--
Catalin

2015-04-14 14:56:57

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Tue, Apr 14, 2015 at 11:51:54AM +0000, Pinski, Andrew wrote:
> > On Apr 14, 2015, at 4:15 AM, Arnd Bergmann <[email protected]> wrote:
> > On Tuesday 14 April 2015 10:45:43 Pinski, Andrew wrote:
> >>> On Apr 14, 2015, at 3:08 AM, Arnd Bergmann <[email protected]> wrote:
> >>> There are multiple ways of doing this:
> >>>
> >>> a) separate syscall table for arm64: as you say, this is the current approach,
> >>> and I'd like to avoid that too
> >>> b) add syscalls for ilp32 as additional numbers in the normal lp64 version of
> >>> asm-generic/unistd.h, and share the binary tables between ilp32 and lp64
> >>> on aarch64
> >>> c) change asm-generic/unistd.h to generate three possible tables: instead of
> >>> just native (lp64 or ilp32 depending on the arch), compat (support for
> >>> existing ilp32 binaries on some architectures, there would also be a
> >>> "modern" ilp32 variant that is a mix of the two, as your table today
> >>> d) don't use the asm-generic/unistd.h table for aarch64-ilp32 at all, but instead
> >>> reuse the table from arch/arm64/include/asm/unistd32.h
> >>>
> >>> I think you are referring to approach b) or c) above, but my preferred one
> >>> would actually be d).
> >>
> >> D is the worst of all 4 options in my mind. The reason is when a new syscall is
> >> added, then you have to update that file too.
> >
> > I don't know what the miscommunication is here, but the advantage of d is
> > specifically that it is /less/ work to maintain: With the current approach,
> > each new syscall that gets added needs to be checked to see if the normal
> > aarch64 version works or if it needs another wrapper, while with d) we
> > get the update for free, because we follow exactly what aarch32 is doing.
>
> More than that d won't work due to ucontext being different between
> aarch32 and aarch64.

This too, I forgot to mention it (unless we restrict ILP32 to only 15
registers, reduced FP bank; in summary, it won't work).

> Also this abi is about to be used in a product so any changes need to
> happen fast and need to thought out why making changes to it make
> senses.

This is not our problem really. It's been pretty quiet on the ILP32
front for the past 6 months or more and just because a product is going
to use it is not an argument to accept a long term ABI.

> Changing to use the aarch32 syscall #'s make less sense since this is
> not a legacy syscalls.

That I agree. I'm fine with 32-bit only data structures but I really
want to stick to the asm-generic/unistd.h syscalls for new ABIs.

--
Catalin

2015-04-14 15:00:46

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Tue, Apr 14, 2015 at 04:07:36PM +0200, Arnd Bergmann wrote:
> For completeness, there is yet another option, which would be to use the
> exact system call table from arm64 and do all the emulation in user space
> rather than the kernel. This would however be the least compatible with
> existing source code, so you probably don't want to do that.

It would be great if this worked but I think we looked at it before and
it seems nice until you hit the futex stuff and robust lists (I don't
fully remember the details). Some of the structures (siginfo) would no
longer be POSIX compliant and some of them aren't only accessed via libc
to be able to create shadow copies.

--
Catalin

2015-04-14 15:29:49

by Philipp Tomsich

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64


> On 14 Apr 2015, at 16:47, Catalin Marinas <[email protected]> wrote:
>
>> I mainly want to avoid accidentally creating new ABIs for syscalls and ioctls:
>> we have many drivers that today use ioctls with data structures derived from
>> '__kernel_ulong_t' in some form, often by including a timespec or time_t in
>> their own data structures. These are almost all broken today, because the
>> data structures are a mix of the aarch32 and aarch64 variants, while the
>> ioctl() system call in ilp32 always uses the aarch32 format by default.
>>
>> An example here would be
>>
>> struct cyclades_idle_stats {
>> __kernel_time_t in_use; /* Time device has been in use (secs) */
>> __kernel_time_t recv_idle; /* Time since last char received (secs) */
>> __kernel_time_t xmit_idle; /* Time since last char transmitted (secs) */
>> unsigned long recv_bytes; /* Bytes received */
>> unsigned long xmit_bytes; /* Bytes transmitted */
>> unsigned long overruns; /* Input overruns */
>> unsigned long frame_errs; /* Input framing errors */
>> unsigned long parity_errs; /* Input parity errors */
>> };
>>
>> for a random ancient driver. Introducing a third set of data structures
>> and syscalls for aarch64-ilp32 means that any driver doing something like
>> this needs to be modified to support existing user space source code.
>
> That's indeed a problem as ILP32 doesn't look like any of the other
> options (the siginfo structure is another case that doesn't fit in any
> of the ABI as long as time_t is 64-bit).

I believe we’ve already arrived at the conclusion that timespec needs to be
changed from what Andrew and I had submitted.

Let’s go back to the underlying definition of timespec:
"The range and precision of times representable in clock_t and time_t are
implementation-defined. The timespec structure shall contain at least the
following members, in any order.

time_t tv_sec; // whole seconds -- >= 0
long tv_nsec; // nanoseconds -- [0, 999999999]”

So tv_nsec needs to be 32bit on ILP32, as we would otherwise break the C
language. Any program that assumes that tv_nsec is sizeof(long) would be
correct and it would be unexpected and surprising behaviour [even though it
would be consider a good programming style] if one would need to explicitly
ask for the sizeof(ts.tv_nsec). Having the same problem on x32 doesn’t seem
like a good justification to do the same.

For time_t, I don’t see the need to have a 32bit type yet.
As long as the the type is properly exposed through header files (and user
programs can thus recreate the kernel’s data model), we should be safe.

Cases like the above data structure from an ioctl are clearly non-portable
and would break today on any architecture that supports ABIs with different
data models (say ILP32 and LP64)… so I would consider any attempt to
support this as trying to remain “bug-compatible”.

There are plenty of good examples in the uapi that will be nicely portable
between ILP32 and LP64. Let’s take aio_abi.h (I’ve intentionally chosen this,
as the userspace library libaio uses a broken redefinition instead of the
kernel header file) as an example:
> /*
> * we always use a 64bit off_t when communicating
> * with userland. its up to libraries to do the
> * proper padding and aio_error abstraction
> */
>
> struct iocb {
> /* these are internal to the kernel/libc. */
> __u64 aio_data; /* data to be returned in event's data */
> __u32 PADDED(aio_key, aio_reserved1);
> /* the kernel sets aio_key to the req # */
>
> /* common fields */
> __u16 aio_lio_opcode; /* see IOCB_CMD_ above */
> __s16 aio_reqprio;
> __u32 aio_fildes;
>
> __u64 aio_buf;
> __u64 aio_nbytes;
> __s64 aio_offset;
>
> /* extra parameters */
> __u64 aio_reserved2; /* TODO: use this for a (struct sigevent *) */
>
> /* flags for the "struct iocb" */
> __u32 aio_flags;
>
> /*
> * if the IOCB_FLAG_RESFD flag of "aio_flags" is set, this is an
> * eventfd to signal AIO readiness to
> */
> __u32 aio_resfd;
> }; /* 64 bytes */

The key to any design decision should be that we
(a) don’t break C11, POSIX or the Single UNIX Specification
(b) remain true to the definitions from the the AArch64 ILP32 ELF ABI
(which defines 64bit values transferable in registers to callees)

Can we thus agree on the following for the next revision of the patch-set:
(1) We retain a 64bit time_t, but implement different sizes (between ILP32 and
LP64) for ‘tv_nsec' in 'struct timespec’?
(2) We use the 64bit system calls whereever possible (i.e. no register splitting).

Best,
Phil.

2015-04-14 15:44:31

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Tuesday 14 April 2015 15:47:02 Catalin Marinas wrote:
> On Tue, Apr 14, 2015 at 12:08:11PM +0200, Arnd Bergmann wrote:
> > On Tuesday 14 April 2015 11:33:13 Dr. Philipp Tomsich wrote:
> > > After getting a good night’s sleep, the “reuse the existing system call table” comment
> > > makes a little more sense as I construe it as having just one merged system call table
> > > for both LP64 and ILP32 and handling the differences through a different system call
> > > numbering in unistd.h towards LP64 and ILP32 processes.
> > >
> > > If this is the intended implementation, I am not fully sold on the benefit: having a private
> > > copy of unistd.h for ARM64 seems to be a less readable and less maintenance-friendly
> > > solution to having separate tables.
> > >
> > > We’re open to input on this and—if merging the system call tables is the consensus—
> > > would like to get the change underway as soon as possible.
> >
> > There are multiple ways of doing this:
>
> It doesn't look like they are exclusive options. For example you can use
> (a) together with (c) or (d). Some more comments below:

I meant them to be exclusive, but you are right that the list
was not complete, and it's possible to interpret it different
from what I had in mind.

> > a) separate syscall table for arm64: as you say, this is the current approach,
> > and I'd like to avoid that too
>
> What is the problem with this option? Is it cache locality affected by
> having another table? A syscall table currently stands at around 2KB. We
> could halve it by storing relative offsets but I don't think we would
> notice much performance improvement.

No, I'm not worried about performance here, the main differences to b) and c)
here is that you have to maintain this list, and potentially duplicate it
for new 64-bit architectures coming in (x86, mips etc already have separate
copies, so that ship has sailed). I'd rather see that table being maintained
in asm-generic as architecture independent code than in arch/arm64.

The much bigger problem of data structures that are incompatible with both
existing ABIs is shared with approach b and c.

> > b) add syscalls for ilp32 as additional numbers in the normal lp64 version of
> > asm-generic/unistd.h, and share the binary tables between ilp32 and lp64
> > on aarch64
>
> Does this mean that an ILP32 task can still call LP64-only syscalls? How
> many new syscalls are we looking at? Would these ILP32 numbers be
> interspersed with the LP64 ones or some high values (say bit 12 set)?
> The former isn't workable since may leave gaps on LP64 architectures.
> The latter could work better if the ILP32 specific options are not
> sparse.

This would be the same list that patch 19/24 of this series adds, 32
system calls in total, possibly a few more getting added over the
years.

> > c) change asm-generic/unistd.h to generate three possible tables: instead of
> > just native (lp64 or ilp32 depending on the arch), compat (support for
> > existing ilp32 binaries on some architectures, there would also be a
> > "modern" ilp32 variant that is a mix of the two, as your table today
>
> I don't fully understand this. It looks to me like we need to generate
> at least the LP64 and native ILP32 unistd.h anyway if we go for option a
> or possibly b.

With option b), we'd generate one table from asm-generic/unistd.h and
another one from asm/unistd32.h, as we do today. The first would be
shared between both aarch64 ABIs (and extended with 32 new calls) while
the second continues unmodified.

With option c), we'd use the asm-generic/unistd.h source to generate
two independent tables, similar to what we do in
arch/tile/kernel/{sys,compat}.c, and the first table would be the same
as it is today.

> > d) don't use the asm-generic/unistd.h table for aarch64-ilp32 at all, but instead
> > reuse the table from arch/arm64/include/asm/unistd32.h
>
> IMO, (d) only makes sense if we treat ILP32 as a temporary solution
> (a.k.a. hack) hoping that such applications will be eventually built for
> LP64. If we treat native ILP32 as a real long term alternative to LP64,
> I would rather use the asm-generic/unistd.h for syscalls. For example,
> use 'openat' instead of 'open' on the native ILP32 (based on the
> assumption that ILP32 is a long term alternative).
>
> Unless we are aware of performance impact with (a), that's my preferred
> option with some form of (b) next.

Ok, let's call that option

e) Use the existing aarch32 data structures with the asm-generic/unistd.h
system call numbers.

This would solve the main problem of the data structures just like option
d), and the main user-visible change would be that the syscall numbers
are shifted compared to aarch32, which is a very minor aspect. We could
also deal with the ucontext better this way than what I suggested.

> The above is mainly about syscall numbers and tables but the ABI goes
> beyond this. And the key point is whether we go for an AArch32-like ABI
> (32-bit time_t) or we try to define one close to LP64. If we go for an
> AArch32-like ABI, we'll have to use the compat layer for some of
> syscalls and assess how many of the asm/compat.h structures are
> different from the generic ones (I wouldn't expect many).

It would be wildly different from the generic data structures, since we
can only use the compat code if the implementation is the same as on
aarch32. Essentially we have to define the headers so that all native
data structures match what is in arch/arm64/include/asm/compat.h,
which in turn is largely the same as arch/arm/include/uapi/asm/*.h.

Exceptions to this are asm/ptrace.h and asm/ucontext.h, which cannot
be shared.

> > If we stick to the normal compat32 implementation for all data structures
> > and syscalls, we can support all drivers that work with aarch32 emulation
> > today, as well as any one that gains support later on a regular compat32
> > architecture (x86, powerpc, sparc, mips, arm, tile, parisc, s390), and
> > we don't have to watch all new ioctl interfaces that get added to the
> > kernel. Note that this does not just impact ioctl, but also things like
> > setsockopts and drivers that communicate with user space through a
> > mmapped data structure.
>
> I'm fine with this but I would limit this compat32 similarity to data
> structures rather than syscall numbers. Why do we need to support some
> old syscalls when we can easily use new variants (e.g. open vs openat)?

Fair enough.

> > Using that existing table would also make it much easier to add support
> > for additional C libraries, which then just have to implement the ELF
> > format, but could reuse the arm32 kernel interfaces.
>
> The existing compat32 ABI is a bit limiting on a 64-bit architecture. I
> think we should really take advantage of the 64-bit register width and
> avoid splitting 64-bit arguments in two registers. At which point, we
> need a separate table anyway.

As mentioned, this concerns only 8 system calls in total, but I agree
that if we use the asm-generic syscall list, this would be the natural
choice.

> > Finally, there is a certain set of security issues from each new syscall
> > we introduce. With the aarch32 syscall table, we have a higher degree
> > of reuse of existing code, so we won't introduce security bugs that
> > are only in one of the two ilp32 ABIs (aarch32 and aarch64).
>
> Note that the current aarch32 compat ABI assumes that the top 32-bit of
> every register is either zeroed or preserved by the architecture on
> exception entry. We know that an AArch32 application cannot access the
> top 32-bit of an AArch64 register. With native ILP32 however this is no
> longer the case (it is running in AArch64 mode). I can't immediately
> think of a problem (information leak) but it needs to be reviewed.

Hmm, interesting point. I'd have to think about this a bit more, but
I believe it is already solved:

- For input arguments, we have the COMPAT_SYSCALL_DEFINE wrappers that
are meant to deal with this problem.
- For output arguments, the kernel controls the register contents,
and I don't see a way that the function return value could leak
data in the upper bits. All syscall return 'long', so it should
be well-defined.

> > One notable downside of this is that all system calls have to pass 64-bit
> > arguments (i.e. loff_t) in two registers instead of one, to match the
> > aarch32 calling conventions, but that would be limited to a small part
> > of the libc implementation that already does the same thing for arm32.
>
> There is this downside but I'm still not convinced what the advantages
> of sharing the compat32 table are (not talking about the data structures
> though, I'm fine with sharing those).

Ok

Arnd

2015-04-14 16:55:10

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Tue, Apr 14, 2015 at 05:29:36PM +0200, Dr. Philipp Tomsich wrote:
> > On 14 Apr 2015, at 16:47, Catalin Marinas <[email protected]> wrote:
> >> I mainly want to avoid accidentally creating new ABIs for syscalls and ioctls:
> >> we have many drivers that today use ioctls with data structures derived from
> >> '__kernel_ulong_t' in some form, often by including a timespec or time_t in
> >> their own data structures. These are almost all broken today, because the
> >> data structures are a mix of the aarch32 and aarch64 variants, while the
> >> ioctl() system call in ilp32 always uses the aarch32 format by default.
> >>
> >> An example here would be
> >>
> >> struct cyclades_idle_stats {
> >> __kernel_time_t in_use; /* Time device has been in use (secs) */
> >> __kernel_time_t recv_idle; /* Time since last char received (secs) */
> >> __kernel_time_t xmit_idle; /* Time since last char transmitted (secs) */
> >> unsigned long recv_bytes; /* Bytes received */
> >> unsigned long xmit_bytes; /* Bytes transmitted */
> >> unsigned long overruns; /* Input overruns */
> >> unsigned long frame_errs; /* Input framing errors */
> >> unsigned long parity_errs; /* Input parity errors */
> >> };
> >>
> >> for a random ancient driver. Introducing a third set of data structures
> >> and syscalls for aarch64-ilp32 means that any driver doing something like
> >> this needs to be modified to support existing user space source code.
> >
> > That's indeed a problem as ILP32 doesn't look like any of the other
> > options (the siginfo structure is another case that doesn't fit in any
> > of the ABI as long as time_t is 64-bit).
>
> I believe we’ve already arrived at the conclusion that timespec needs to be
> changed from what Andrew and I had submitted.
>
> Let’s go back to the underlying definition of timespec:
> "The range and precision of times representable in clock_t and time_t are
> implementation-defined. The timespec structure shall contain at least the
> following members, in any order.
>
> time_t tv_sec; // whole seconds -- >= 0
> long tv_nsec; // nanoseconds -- [0, 999999999]”
>
> So tv_nsec needs to be 32bit on ILP32, as we would otherwise break the C
> language. Any program that assumes that tv_nsec is sizeof(long) would be
> correct and it would be unexpected and surprising behaviour [even though it
> would be consider a good programming style] if one would need to explicitly
> ask for the sizeof(ts.tv_nsec). Having the same problem on x32 doesn’t seem
> like a good justification to do the same.

>From a standards perspective, that's clear, and I'm fine with not making
the same choice as x32. I think on x32 it was a side-effect of glibc
defining tv_nsec as __syscall_slong_t and the kernel defining
__kernel_long_t to 64-bit.

> For time_t, I don’t see the need to have a 32bit type yet.
> As long as the the type is properly exposed through header files (and user
> programs can thus recreate the kernel’s data model), we should be safe.

The problem with a 64-bit time_t is that the timespec structure looks
like neither compat32 nor native 64-bit. If we make the AArch32 and
native ILP32 exclusive and build time, it makes it easier, otherwise we
need to support a third ABI in the kernel.

> The key to any design decision should be that we
> (a) don’t break C11, POSIX or the Single UNIX Specification
> (b) remain true to the definitions from the the AArch64 ILP32 ELF ABI
> (which defines 64bit values transferable in registers to callees)

I think these are fine.

> Can we thus agree on the following for the next revision of the patch-set:
> (1) We retain a 64bit time_t, but implement different sizes (between ILP32 and
> LP64) for ‘tv_nsec' in 'struct timespec’?
> (2) We use the 64bit system calls whereever possible (i.e. no register splitting).

As I mentioned above, timespec and possibly other structures no longer
like any of the existing ABIs. Do we know how many syscalls are
affected?

The alternative is 32-bit time_t which makes it easier to use the compat
syscall implementations (not numbers). It also depends on how we plan to
fix the 2038 problem. For new 32-bit only architectures, are we going to
require them to use a 64-bit time_t or we get alternative time64_t and
timespec64 specs?

--
Catalin

2015-04-14 22:28:56

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Tuesday 14 April 2015 16:00:34 Catalin Marinas wrote:
> On Tue, Apr 14, 2015 at 04:07:36PM +0200, Arnd Bergmann wrote:
> > For completeness, there is yet another option, which would be to use the
> > exact system call table from arm64 and do all the emulation in user space
> > rather than the kernel. This would however be the least compatible with
> > existing source code, so you probably don't want to do that.
>
> It would be great if this worked but I think we looked at it before and
> it seems nice until you hit the futex stuff and robust lists (I don't
> fully remember the details). Some of the structures (siginfo) would no
> longer be POSIX compliant and some of them aren't only accessed via libc
> to be able to create shadow copies.

Well, that may or may not be acceptable. Aarch64-ilp32 mode is a hack to
enable a very special class of applications, it's not like anyone would
want to run a full system for this and need POSIX compliance.

We could definitely be pragmatic and do whatever helps get the job
done. That said, it diverges further from what legacy 32-bit applications
expect to see, so this approach will likely make an application port harder,
not easier.

Arnd

2015-04-15 09:18:48

by Philipp Tomsich

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64


> On 15 Apr 2015, at 00:28, Arnd Bergmann <[email protected]> wrote:
>
> On Tuesday 14 April 2015 16:00:34 Catalin Marinas wrote:
>> On Tue, Apr 14, 2015 at 04:07:36PM +0200, Arnd Bergmann wrote:
>>> For completeness, there is yet another option, which would be to use the
>>> exact system call table from arm64 and do all the emulation in user space
>>> rather than the kernel. This would however be the least compatible with
>>> existing source code, so you probably don't want to do that.
>>
>> It would be great if this worked but I think we looked at it before and
>> it seems nice until you hit the futex stuff and robust lists (I don't
>> fully remember the details). Some of the structures (siginfo) would no
>> longer be POSIX compliant and some of them aren't only accessed via libc
>> to be able to create shadow copies.
>
> Well, that may or may not be acceptable. Aarch64-ilp32 mode is a hack to
> enable a very special class of applications, it's not like anyone would
> want to run a full system for this and need POSIX compliance.

I strongly disagree on this: ILP32 is a first-class citizen of the ARMv8
ecosystem as a “data-model” for AArch64. Having a corresponding Linux
syscall ABI is necessitated because not all data structures shared across
the syscall-boundary are describted/defined in data-model agnostic types.
ILP32 thus has the same importance as the LP64 ABI in ARMv8. It is thus
neither a hack nor likely/expected to go away anytime soon.

We’ve run full systems (built from buildroot) consisting of ILP32 binaries
only (ok… admittedly gdb was an exception, as we haven’t fixed the fact
that someone has assumed sizeof(long) == 8 in some data-structure of
the AArch64 backend there) in our verification runs. In fact, it will be very
special classes of applications that will need a 64bit address-space.

If anything, then backward-compatibility for ARMv7 binaries should be
considered a hack (although one that is performed in hardware).

> We could definitely be pragmatic and do whatever helps get the job
> done. That said, it diverges further from what legacy 32-bit applications
> expect to see, so this approach will likely make an application port harder,
> not easier.

The key question at this point seems to be whether we want to support
“legacy 32-bit applications” (i.e. ones that make assumption that are
not covered by the underlying type definitions or specifications) or whether
we aim for “well-formed 32-bit applications”.

To stay with the 'struct timespec’-example, the difference between the
former and the latter would (among others) be that the former might
assume sizeof(long) == sizeof(time_t), whereas the latter is allowed to
except that sizeof(long) == sizeof(ts.tv_nsec).

I don’t believe in keeping compatibility for the former type of applications.
Consequently, I don’t necessarily see the value in defining ILP32 for
AArch64 with a 32bit time_t (even though it would be simpler at this
moment), as I don’t see the benefit of adding a new ABI that propagates
a well known problem (even if one could argue that there’s plenty of time
to fix this by 2038).

Phil.-

2015-04-15 10:02:17

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Wed, Apr 15, 2015 at 11:18:06AM +0200, Dr. Philipp Tomsich wrote:
> On 15 Apr 2015, at 00:28, Arnd Bergmann <[email protected]> wrote:
> > On Tuesday 14 April 2015 16:00:34 Catalin Marinas wrote:
> >> On Tue, Apr 14, 2015 at 04:07:36PM +0200, Arnd Bergmann wrote:
> >>> For completeness, there is yet another option, which would be to use the
> >>> exact system call table from arm64 and do all the emulation in user space
> >>> rather than the kernel. This would however be the least compatible with
> >>> existing source code, so you probably don't want to do that.
> >>
> >> It would be great if this worked but I think we looked at it before and
> >> it seems nice until you hit the futex stuff and robust lists (I don't
> >> fully remember the details). Some of the structures (siginfo) would no
> >> longer be POSIX compliant and some of them aren't only accessed via libc
> >> to be able to create shadow copies.
> >
> > Well, that may or may not be acceptable. Aarch64-ilp32 mode is a hack to
> > enable a very special class of applications, it's not like anyone would
> > want to run a full system for this and need POSIX compliance.
>
> I strongly disagree on this: ILP32 is a first-class citizen of the ARMv8
> ecosystem as a “data-model” for AArch64. Having a corresponding Linux
> syscall ABI is necessitated because not all data structures shared across
> the syscall-boundary are describted/defined in data-model agnostic types.
> ILP32 thus has the same importance as the LP64 ABI in ARMv8. It is thus
> neither a hack nor likely/expected to go away anytime soon.

That's the kind of feedback I've been trying to get from the software
ecosystem - whether AArch64-ILP32 is a temporary hack for legacy 32-bit
applications or a solid long term solution for those not needing 64-bit.
The benchmarks I've seen so far didn't show any significant improvement
of AArch64-ILP32 over LP64. The comparison with AArch32 may not be
entirely fair at the moment due to the maturity of AArch64-ILP32
toolchains but I don't think we'll see a big jump.

The messages I get are mixed, even from companies initially stating the
need for ILP32. So I can't make an informed decision but I think we
should go for the safer option: a first class citizen, long term ABI. It
costs more in (kernel) maintenance initially but if it happens to catch
on, it will cost us later. The alternative is not to bother with
AArch64-ILP32 at all, especially if it's going to be used only as a
marketing exercise for CPUs not supporting AArch32.

(if anyone has more feedback on commercial needs for ILP32, please let
us know, even if it is in private)

> We’ve run full systems (built from buildroot) consisting of ILP32 binaries
> only (ok… admittedly gdb was an exception, as we haven’t fixed the fact
> that someone has assumed sizeof(long) == 8 in some data-structure of
> the AArch64 backend there) in our verification runs. In fact, it will be very
> special classes of applications that will need a 64bit address-space.

If we are to merge AArch64-ILP32, I'd like to see a full software stack,
maybe a distro like Debian. Otherwise the kernel code will bit-rot (just
like it regularly happens with big endian).

> > We could definitely be pragmatic and do whatever helps get the job
> > done. That said, it diverges further from what legacy 32-bit applications
> > expect to see, so this approach will likely make an application port harder,
> > not easier.
>
> The key question at this point seems to be whether we want to support
> “legacy 32-bit applications” (i.e. ones that make assumption that are
> not covered by the underlying type definitions or specifications) or whether
> we aim for “well-formed 32-bit applications”.
>
> To stay with the 'struct timespec’-example, the difference between the
> former and the latter would (among others) be that the former might
> assume sizeof(long) == sizeof(time_t), whereas the latter is allowed to
> except that sizeof(long) == sizeof(ts.tv_nsec).
>
> I don’t believe in keeping compatibility for the former type of applications.

That was one of the initial reasons I heard for AArch64-ILP32. So more
mixed messages.

> Consequently, I don’t necessarily see the value in defining ILP32 for
> AArch64 with a 32bit time_t (even though it would be simpler at this
> moment), as I don’t see the benefit of adding a new ABI that propagates
> a well known problem (even if one could argue that there’s plenty of time
> to fix this by 2038).

We could look at this in a different way: time_t should be the same size
as any *new* 32-bit architecture supported by Linux. So if the kernel
community decides that from now on time_t is 64-bit across new 32 and
64-bit architecture ports (note new, not existing), we do the same with
ILP32. Otherwise, we stick to 32-bit time_t and wait to see how the 2038
problem is solved, possibly with extensions to POSIX and additional
syscalls.

--
Catalin

2015-04-15 10:32:04

by Philipp Tomsich

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

Catalin,

even though this may now be moot, as we’ll out a 32bit time_t on ILP32 (making it
very similar to n32 on MIPS), here’s the the info on what would be affected by
changing timespec.

Below is a (hopefully) full list of system calls, helper functions and exposed data
structures (with some comments on what will need to be done to resolve this change)
that would be affected by introducing an other timespec (let’s call it ilp32_timespec
for the ease of discussion) consisting of a 64bit time_t and a 32bit integer.

> On 14 Apr 2015, at 18:55, Catalin Marinas <[email protected]> wrote:
>
> As I mentioned above, timespec and possibly other structures no longer
> like any of the existing ABIs. Do we know how many syscalls are
> affected?

Here’s everything that affected (details on how to resolve are below) in no particular
order:
> syscall: utimensat
> syscall: io_getevents
> syscall: select
> internal: poll_select_copy_remaining (via select) [+on stack: struct compat_timespec rts;]
> syscall: pselect6
> internal: do_compat_pselect (via pselect6) [+on stack: struct compat_timespec ts;]
> syscall: ppoll [+on stack: struct compat_timespec ts;]
> syscall: nanosleep
> internal: compat_nanosleep_restart (via nanosleep)
> syscall: clock_gettime
> syscall: clock_settime
> syscall: clock_getres
> syscall: clock_nanosleep
> syscall: rt_sigtimedwait
> syscall: sched_rr_get_interval
> internal: compat_get_timespec
> internal: compat_put_timespec
> syscall: futex
> syscall: recvmmsg
> file_operations: compat_sock_ioctl
> internal: do_siocgstampns (via compat_sock_ioctl_trans via compat_sock_ioctl)
> syscall: semtimedop
> syscall: mq_timedsend
> syscall: mq_timedreceive
> internal: compat_convert_timespec
> syscall: timer_settime
> syscall: timer_gettime
> syscall: timerfd_settime
> syscall: timerfd_gettime
> struct: itimerspec
> internal: get_compat_itimerspec
> internal: put_compat_itimerspec
> struct: snd_pcm_status32
> internal: snd_pcm_ioctl_sync_ptr_compat
> struct: snd_pcm_mmap_status32
> internal: snd_pcm_status_user_compat
> struct: v4l2_event32
> internal: put_v4l2_event32 (via do_video_ioctl)
> struct: restart_block [simple change: additional field; for nanosleep]
> internal: put_cmsg_compat [on stack: struct compat_timespec cts[3];]
> struct: snd_rawmidi_status32
> internal: snd_rawmidi_ioctl_status_compat (handles snd_rawmidi_status32)
> struct: snd_timer_status32
> internal: snd_timer_user_status_compat
> struct: struct snd_pcm_mmap_status32
> internal: snd_pcm_ioctl_sync_ptr_compat (handles snd_pcm_mmap_status32)
> struct: snd_pcm_status32
> internal: snd_pcm_status_user_compat (handles snd_pcm_status32)

For dealing with them, we can roughly use the following strategy (I may have lost
1. The timespec/compat_timespec/ilp32_timespec is ever only referenced through
its memory address and used for userspace/kernel-transfers. For these cases
we mere need to extend the compat_get_timespec and compat_put_timespec
functions to recognize the ILP32-case… same for compat_convert_timespec

For the affected syscalls, the ILP32 implementation should route through the
compat-layer. This can be done in the following cases (I’m leaving the compat
off for readability):
utimensat
io_getevents
nanosleep
clock_gettime
clock_settime
clock_getres
clock_nanosleep
rt_sigtimedwait
sched_rr_get_interval
recvmmsg
futex
semtimedop
mq_timedsend
mq_timedreceive

One helper called through an ioctl will also need to pick this us:
do_siocgstampns (through compat_sock_ioctl)

A special case is the nanosleep syscall and its restart-helper: even though less
apparent, this would be covered by the changes to compat_get_timespec and
compat_put_timespec also (as there’s only a pointer to a compat_timespec
involved).

2. An similar change will be required for anything that uses itimerspec (as that
structure contains two timespec elements):
timer_settime
timer_gettime
timerfd_settime
timerfd_gettime

3. A compat_timespec is currently created on the stack, even though it’s used
only for a get_user/put_user in a few cases; this can be resolved by changing
to use compat_get_timespec/compat_put_timespec. Once this has been
done, then the changes from step 1 should also extend to these case.

Instances include:
poll_select_copy_remaining (helper function called from ‘select’)
do_compat_pselect (helper function called from ‘pselect6’)
ppoll

The syscalls associated with these helper-functions need to be passed
through the compat-layer for ILP32 also (as functions in their call chain
are affected):
select
pselect6

4. There’s some limited expose in the v4l and snd subsystems, primarily in
ioctl data-structures. For these, there’s typically already a compat-layer
function and a compat-ioctl. So these will require a few (5 by my count) of
individual fixes.


Hope this answers the question,
Phil.-

2015-04-15 11:22:39

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Tue, Apr 14, 2015 at 05:44:07PM +0200, Arnd Bergmann wrote:
> On Tuesday 14 April 2015 15:47:02 Catalin Marinas wrote:
> > On Tue, Apr 14, 2015 at 12:08:11PM +0200, Arnd Bergmann wrote:
> > > d) don't use the asm-generic/unistd.h table for aarch64-ilp32 at all, but instead
> > > reuse the table from arch/arm64/include/asm/unistd32.h
> >
> > IMO, (d) only makes sense if we treat ILP32 as a temporary solution
> > (a.k.a. hack) hoping that such applications will be eventually built for
> > LP64. If we treat native ILP32 as a real long term alternative to LP64,
> > I would rather use the asm-generic/unistd.h for syscalls. For example,
> > use 'openat' instead of 'open' on the native ILP32 (based on the
> > assumption that ILP32 is a long term alternative).
> >
> > Unless we are aware of performance impact with (a), that's my preferred
> > option with some form of (b) next.
>
> Ok, let's call that option
>
> e) Use the existing aarch32 data structures with the asm-generic/unistd.h
> system call numbers.
>
> This would solve the main problem of the data structures just like option
> d), and the main user-visible change would be that the syscall numbers
> are shifted compared to aarch32, which is a very minor aspect. We could
> also deal with the ucontext better this way than what I suggested.

I think that's the easiest from a kernel perspective. But see the other
sub-thread on the long term view of ILP32 (beyond 2038).

> > The above is mainly about syscall numbers and tables but the ABI goes
> > beyond this. And the key point is whether we go for an AArch32-like ABI
> > (32-bit time_t) or we try to define one close to LP64. If we go for an
> > AArch32-like ABI, we'll have to use the compat layer for some of
> > syscalls and assess how many of the asm/compat.h structures are
> > different from the generic ones (I wouldn't expect many).
>
> It would be wildly different from the generic data structures, since we
> can only use the compat code if the implementation is the same as on
> aarch32. Essentially we have to define the headers so that all native
> data structures match what is in arch/arm64/include/asm/compat.h,
> which in turn is largely the same as arch/arm/include/uapi/asm/*.h.

What I meant by generic structures is those include/uapi/asm-generic/*.h
structures but compiled in an ILP32 context (exported headers not as
they are compiled in the LP64 kernel). Many of the asm/compat.h had to
be defined so that we can build them in the kernel context but many of
them are the same as the asm-generic ones (when compiled as ILP32).

BTW, we have to sort out the exported headers as well since we can't
rely on AArch32 for this. In the kernel, we'll have to re-use
asm/compat.h or some other asm/ilp32.h.

> > > Finally, there is a certain set of security issues from each new syscall
> > > we introduce. With the aarch32 syscall table, we have a higher degree
> > > of reuse of existing code, so we won't introduce security bugs that
> > > are only in one of the two ilp32 ABIs (aarch32 and aarch64).
> >
> > Note that the current aarch32 compat ABI assumes that the top 32-bit of
> > every register is either zeroed or preserved by the architecture on
> > exception entry. We know that an AArch32 application cannot access the
> > top 32-bit of an AArch64 register. With native ILP32 however this is no
> > longer the case (it is running in AArch64 mode). I can't immediately
> > think of a problem (information leak) but it needs to be reviewed.
>
> Hmm, interesting point. I'd have to think about this a bit more, but
> I believe it is already solved:
>
> - For input arguments, we have the COMPAT_SYSCALL_DEFINE wrappers that
> are meant to deal with this problem.
> - For output arguments, the kernel controls the register contents,
> and I don't see a way that the function return value could leak
> data in the upper bits. All syscall return 'long', so it should
> be well-defined.

I think you are right. I was more thinking of those routed directly to
the native (non-compat) syscalls. We would need to make sure the return
value (X0 being the only register not restored on return from exception)
has the top 32-bit part zeroed.

--
Catalin

2015-04-15 12:26:51

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Tuesday 14 April 2015 16:54:22 Dr. Philipp Tomsich wrote:
> On 14 Apr 2015, at 16:07, Arnd Bergmann <[email protected]> wrote:
> >
> > I don't understand what you mean here, please elaborate. Why would an ABI that works
> > on aarch32 be wrong on aarch64-ilp32 user space when you are using the same header
> > files?
> AArch32 and AArch64/ILP32 are entirely different instruction set architectures. They have
> differently sized register files (AArch64 has about twice as many registers and each one is
> 64bits in size) and different register usage conventions.
>
> This affects other “implementation details” such as the ucontext, too.
> For the sake of simplicity, I’ll refer to it just as “register file” below.
>
> This means that we would end up with very distinct code paths for the “dependent” in tools
> (such as strace), if option (d) was used:
> LP64: AArch64 context + 64bit syscall interface
> ILP32: AArch64 context + 32bit syscall interface
> AArch32: AArch32 context + 32bit syscall interface
>
> If we could agree on option (b), things would be much simpler:
> LP64: AArch64 context + 64bit syscall interface
> ILP32: AArch64 context + 64bit syscall interface + ILP32 compat-syscalls
> AArch32: AArch32 context + 32bit syscall interface
>
> I.e. for all tools involved (whether it’s strace, gdb, etc.), LP64 and ILP32 can and should
> look very similar. After all, they differ in their sizeof(ptr_t) and sizeof(long), only.
> AArch32, on the other hand, is very dissimilar to AArch64… it’s a different architecture.
>
> But this is talking from a tools-perspective...

Ok, I see.

>From the kernel perspective, this is very different: The compat syscall
handling in the kernel is fixed to the aarch32 behavior, and in particular
ioctl (but also a few others) in the current patch set need to share that
syscall between both IPL32 implementations (you can't use the LP64 version).

This means any data structure that can get passed into ioctl needs to
share the exact same layout between all ILP32 ABIs, or it would be a bug
in the kernel until someone fixes the driver to handle all three data
structure formats.

I thought until today that this would be limited to ioctl arguments derived
from the __kernel_ulong_t derived types I mentioned (__kernel_size_t,
__kernel_time_t, __kernel_ptrdiff_t, __kernel_off_t, __kernel_clock_t,
__kernel_ino_t, ...), but the problem is actually bigger than that and also
concerns types that are different between the traditional arm32 types and
the widened asm-generic types (__kernel_uid_t, __kernel_gid_t, __kernel_mode_t,
__kernel_off_t, __kernel_ipc_pid_t).

If we use the generic definitions for all those types, we cannot use the
existing compat_sys_ioctl() system call. If we use the aarch32 definitions,
we also have to use the other compat_sys_* calls that aarch32 uses in place
of the native ones (though a lot of syscalls are not needed any more in
general).

Arnd

2015-04-15 12:43:36

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Tuesday 14 April 2015 17:29:36 Dr. Philipp Tomsich wrote:
>
> > On 14 Apr 2015, at 16:47, Catalin Marinas <[email protected]> wrote:
> >
> >> I mainly want to avoid accidentally creating new ABIs for syscalls and ioctls:
> >> we have many drivers that today use ioctls with data structures derived from
> >> '__kernel_ulong_t' in some form, often by including a timespec or time_t in
> >> their own data structures. These are almost all broken today, because the
> >> data structures are a mix of the aarch32 and aarch64 variants, while the
> >> ioctl() system call in ilp32 always uses the aarch32 format by default.
> >>
> >> An example here would be
> >>
> >> struct cyclades_idle_stats {
> >> __kernel_time_t in_use; /* Time device has been in use (secs) */
> >> __kernel_time_t recv_idle; /* Time since last char received (secs) */
> >> __kernel_time_t xmit_idle; /* Time since last char transmitted (secs) */
> >> unsigned long recv_bytes; /* Bytes received */
> >> unsigned long xmit_bytes; /* Bytes transmitted */
> >> unsigned long overruns; /* Input overruns */
> >> unsigned long frame_errs; /* Input framing errors */
> >> unsigned long parity_errs; /* Input parity errors */
> >> };
> >>
> >> for a random ancient driver. Introducing a third set of data structures
> >> and syscalls for aarch64-ilp32 means that any driver doing something like
> >> this needs to be modified to support existing user space source code.
> >
> > That's indeed a problem as ILP32 doesn't look like any of the other
> > options (the siginfo structure is another case that doesn't fit in any
> > of the ABI as long as time_t is 64-bit).
>
> I believe we’ve already arrived at the conclusion that timespec needs to be
> changed from what Andrew and I had submitted.
>
> Let’s go back to the underlying definition of timespec:
> "The range and precision of times representable in clock_t and time_t are
> implementation-defined. The timespec structure shall contain at least the
> following members, in any order.
>
> time_t tv_sec; // whole seconds -- >= 0
> long tv_nsec; // nanoseconds -- [0, 999999999]”
>
> So tv_nsec needs to be 32bit on ILP32, as we would otherwise break the C
> language. Any program that assumes that tv_nsec is sizeof(long) would be
> correct and it would be unexpected and surprising behaviour [even though it
> would be consider a good programming style] if one would need to explicitly
> ask for the sizeof(ts.tv_nsec). Having the same problem on x32 doesn’t seem
> like a good justification to do the same.

I don't think assuming that people who don't write 64-bit safe code
write code that follows C11 is realistic ;-)

A lot more code is broken by having a 64-bit time_t than would be
broken by making tv_nsec 64-bit.

> For time_t, I don’t see the need to have a 32bit type yet.
> As long as the the type is properly exposed through header files (and user
> programs can thus recreate the kernel’s data model), we should be safe.
>
> Cases like the above data structure from an ioctl are clearly non-portable
> and would break today on any architecture that supports ABIs with different
> data models (say ILP32 and LP64)… so I would consider any attempt to
> support this as trying to remain “bug-compatible”.
>
> There are plenty of good examples in the uapi that will be nicely portable
> between ILP32 and LP64. Let’s take aio_abi.h (I’ve intentionally chosen this,
> as the userspace library libaio uses a broken redefinition instead of the
> kernel header file) as an example:
> > /*
> > ...

structures that done in modern times by competent developers should all
be the same across the three ABIs, no need to worry about that.
The only worrying part is drivers that are written in an incompatible
form for whatever reason. These have become rarer in the recent years,
but we still see new ones getting merged, e.g. the Android binder.

> The key to any design decision should be that we
> (a) don’t break C11, POSIX or the Single UNIX Specification
> (b) remain true to the definitions from the the AArch64 ILP32 ELF ABI
> (which defines 64bit values transferable in registers to callees)

These are nice goals, but I don't think they primary objectives.
Getting things to work is much more important, and the timespec
definition among other things may end up not being standards compliant
in order to get there.

> Can we thus agree on the following for the next revision of the patch-set:
> (1) We retain a 64bit time_t, but implement different sizes (between ILP32 and
> LP64) for ‘tv_nsec' in 'struct timespec’?

I have a plan for addressing that, but it will likely take another year
before we can get consensus on the timespec layout for 64-bit time_t.
At the moment, it looks like the 64/64 layout has more support than the
64/pad/32 layout you are describing. Let's not rush this for aarch64
when there is a chance that we end up with a different layout on
native 32-bit machines.

> (2) We use the 64bit system calls whereever possible (i.e. no register splitting).

I'm fine with using 64-bit registers for passing loff_t if we use the
asm-generic/unistd.h system call numbers.

Arnd

2015-04-15 12:47:51

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Tuesday 14 April 2015 17:55:00 Catalin Marinas wrote:
> On Tue, Apr 14, 2015 at 05:29:36PM +0200, Dr. Philipp Tomsich wrote:

> > So tv_nsec needs to be 32bit on ILP32, as we would otherwise break the C
> > language. Any program that assumes that tv_nsec is sizeof(long) would be
> > correct and it would be unexpected and surprising behaviour [even though it
> > would be consider a good programming style] if one would need to explicitly
> > ask for the sizeof(ts.tv_nsec). Having the same problem on x32 doesn’t seem
> > like a good justification to do the same.
>
> From a standards perspective, that's clear, and I'm fine with not making
> the same choice as x32. I think on x32 it was a side-effect of glibc
> defining tv_nsec as __syscall_slong_t and the kernel defining
> __kernel_long_t to 64-bit.

I'm pretty sure that this part of the x32 ABI was a deliberate choice
in full knowledge of the tradeoffs.

> > For time_t, I don’t see the need to have a 32bit type yet.
> > As long as the the type is properly exposed through header files (and user
> > programs can thus recreate the kernel’s data model), we should be safe.
>
> The problem with a 64-bit time_t is that the timespec structure looks
> like neither compat32 nor native 64-bit. If we make the AArch32 and
> native ILP32 exclusive and build time, it makes it easier, otherwise we
> need to support a third ABI in the kernel.

Exactly, which is why the layout was chosen to be the same as x86-64
for x32.

> > Can we thus agree on the following for the next revision of the patch-set:
> > (1) We retain a 64bit time_t, but implement different sizes (between ILP32 and
> > LP64) for ‘tv_nsec' in 'struct timespec’?
> > (2) We use the 64bit system calls whereever possible (i.e. no register splitting).
>
> As I mentioned above, timespec and possibly other structures no longer
> like any of the existing ABIs. Do we know how many syscalls are
> affected?
>
> The alternative is 32-bit time_t which makes it easier to use the compat
> syscall implementations (not numbers). It also depends on how we plan to
> fix the 2038 problem. For new 32-bit only architectures, are we going to
> require them to use a 64-bit time_t or we get alternative time64_t and
> timespec64 specs?

No, we had originally planned that a few years ago, but after deciding that
we are fixing this problem for all 32-bit machines, and also seeing the
magnitude of changes involved in that, I think we have a general consensus
that we do not want to add special cases for architectures that use 64-bit
time_t before everyone else does.

Arnd

2015-04-15 15:15:25

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Wednesday 15 April 2015 11:01:54 Catalin Marinas wrote:
> On Wed, Apr 15, 2015 at 11:18:06AM +0200, Dr. Philipp Tomsich wrote:
> > On 15 Apr 2015, at 00:28, Arnd Bergmann <[email protected]> wrote:
> > > On Tuesday 14 April 2015 16:00:34 Catalin Marinas wrote:
> > >> On Tue, Apr 14, 2015 at 04:07:36PM +0200, Arnd Bergmann wrote:
> > >>> For completeness, there is yet another option, which would be to use the
> > >>> exact system call table from arm64 and do all the emulation in user space
> > >>> rather than the kernel. This would however be the least compatible with
> > >>> existing source code, so you probably don't want to do that.
> > >>
> > >> It would be great if this worked but I think we looked at it before and
> > >> it seems nice until you hit the futex stuff and robust lists (I don't
> > >> fully remember the details). Some of the structures (siginfo) would no
> > >> longer be POSIX compliant and some of them aren't only accessed via libc
> > >> to be able to create shadow copies.
> > >
> > > Well, that may or may not be acceptable. Aarch64-ilp32 mode is a hack to
> > > enable a very special class of applications, it's not like anyone would
> > > want to run a full system for this and need POSIX compliance.
> >
> > I strongly disagree on this: ILP32 is a first-class citizen of the ARMv8
> > ecosystem as a “data-model” for AArch64. Having a corresponding Linux
> > syscall ABI is necessitated because not all data structures shared across
> > the syscall-boundary are describted/defined in data-model agnostic types.
> > ILP32 thus has the same importance as the LP64 ABI in ARMv8. It is thus
> > neither a hack nor likely/expected to go away anytime soon.
>
> That's the kind of feedback I've been trying to get from the software
> ecosystem - whether AArch64-ILP32 is a temporary hack for legacy 32-bit
> applications or a solid long term solution for those not needing 64-bit.
> The benchmarks I've seen so far didn't show any significant improvement
> of AArch64-ILP32 over LP64. The comparison with AArch32 may not be
> entirely fair at the moment due to the maturity of AArch64-ILP32
> toolchains but I don't think we'll see a big jump.
>
> The messages I get are mixed, even from companies initially stating the
> need for ILP32. So I can't make an informed decision but I think we
> should go for the safer option: a first class citizen, long term ABI. It
> costs more in (kernel) maintenance initially but if it happens to catch
> on, it will cost us later. The alternative is not to bother with
> AArch64-ILP32 at all, especially if it's going to be used only as a
> marketing exercise for CPUs not supporting AArch32.

Agreed on all this.

> (if anyone has more feedback on commercial needs for ILP32, please let
> us know, even if it is in private)
>
> > We’ve run full systems (built from buildroot) consisting of ILP32 binaries
> > only (ok… admittedly gdb was an exception, as we haven’t fixed the fact
> > that someone has assumed sizeof(long) == 8 in some data-structure of
> > the AArch64 backend there) in our verification runs. In fact, it will be very
> > special classes of applications that will need a 64bit address-space.
>
> If we are to merge AArch64-ILP32, I'd like to see a full software stack,
> maybe a distro like Debian. Otherwise the kernel code will bit-rot (just
> like it regularly happens with big endian).

I actually don't think this should be a prerequisite. We have too many
dependencies here, and as long as we are debating the exact ABI,
any work that gets put into a full distro support (other than openembedded
etc) would likely be wasted.

> > > We could definitely be pragmatic and do whatever helps get the job
> > > done. That said, it diverges further from what legacy 32-bit applications
> > > expect to see, so this approach will likely make an application port harder,
> > > not easier.
> >
> > The key question at this point seems to be whether we want to support
> > “legacy 32-bit applications” (i.e. ones that make assumption that are
> > not covered by the underlying type definitions or specifications) or whether
> > we aim for “well-formed 32-bit applications”.
> >
> > To stay with the 'struct timespec’-example, the difference between the
> > former and the latter would (among others) be that the former might
> > assume sizeof(long) == sizeof(time_t), whereas the latter is allowed to
> > except that sizeof(long) == sizeof(ts.tv_nsec).
> >
> > I don’t believe in keeping compatibility for the former type of applications.
>
> That was one of the initial reasons I heard for AArch64-ILP32. So more
> mixed messages.

Of course you hear different stories from different people, and some of
them might just be asking for things they don't fully understand.

As far as I'm concerned, supporting broken legacy applications in the
*only* reason we should be doing this for. If people are asking for
it "because x86 does it", "for performance" or "because it lines up
nicely with what the toolchain can do", I'm more than happy to ignore
them.

Arnd

2015-04-15 15:38:21

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Wed, Apr 15, 2015 at 05:15:16PM +0200, Arnd Bergmann wrote:
> On Wednesday 15 April 2015 11:01:54 Catalin Marinas wrote:
> > On Wed, Apr 15, 2015 at 11:18:06AM +0200, Dr. Philipp Tomsich wrote:
> > > We’ve run full systems (built from buildroot) consisting of ILP32 binaries
> > > only (ok… admittedly gdb was an exception, as we haven’t fixed the fact
> > > that someone has assumed sizeof(long) == 8 in some data-structure of
> > > the AArch64 backend there) in our verification runs. In fact, it will be very
> > > special classes of applications that will need a 64bit address-space.
> >
> > If we are to merge AArch64-ILP32, I'd like to see a full software stack,
> > maybe a distro like Debian. Otherwise the kernel code will bit-rot (just
> > like it regularly happens with big endian).
>
> I actually don't think this should be a prerequisite. We have too many
> dependencies here, and as long as we are debating the exact ABI,
> any work that gets put into a full distro support (other than openembedded
> etc) would likely be wasted.

I agree with this not being a prerequisite for merging ILP32 but at
least a long term plan to do something beyond openembedded, once we
agreed on the ABI and _upstreamed_ the kernel and glibc code. Those
legacy applications will probably need more than glibc to run and it's
likely that people will want to run them in a full AArch64 (LP64)
environment. A simpler approach (to me, I'm not a distro person) would
be to just provide additional ILP32 libs in a multi-lib arm64 distro
like Debian rather than all the packages. As for the compiler, AFAIK
aarch64-linux-gnu-* simply needs an option to build for ILP32.

> > > The key question at this point seems to be whether we want to support
> > > “legacy 32-bit applications” (i.e. ones that make assumption that are
> > > not covered by the underlying type definitions or specifications) or whether
> > > we aim for “well-formed 32-bit applications”.
> > >
> > > To stay with the 'struct timespec’-example, the difference between the
> > > former and the latter would (among others) be that the former might
> > > assume sizeof(long) == sizeof(time_t), whereas the latter is allowed to
> > > except that sizeof(long) == sizeof(ts.tv_nsec).
> > >
> > > I don’t believe in keeping compatibility for the former type of applications.
> >
> > That was one of the initial reasons I heard for AArch64-ILP32. So more
> > mixed messages.
>
> Of course you hear different stories from different people, and some of
> them might just be asking for things they don't fully understand.
>
> As far as I'm concerned, supporting broken legacy applications in the
> *only* reason we should be doing this for. If people are asking for
> it "because x86 does it", "for performance" or "because it lines up
> nicely with what the toolchain can do", I'm more than happy to ignore
> them.

I'm not even debating this for the lack of market feedback. So I tend to
agree with you.

--
Catalin

2015-04-15 15:49:51

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Wed, Apr 15, 2015 at 01:50:51PM +0200, Dr. Philipp Tomsich wrote:
> On 15 Apr 2015, at 13:22, Catalin Marinas <[email protected]> wrote:
> > I think you are right. I was more thinking of those routed directly to
> > the native (non-compat) syscalls. We would need to make sure the return
> > value (X0 being the only register not restored on return from exception)
> > has the top 32-bit part zeroed.
>
> As the kernel is LP64 and will thus attempt to return a 64bit return value, the
> high bits should be properly sign-extended in all cases.
>
> The problem (posed by procedure call standard) of information leakage could
> manifest itself only, if the kernel tried to return something smaller than 64 bits…
> in that case, we can the problem would already exhibit for the LP64 ABI.
>
> For the ILP32 implementation, I’ll thus assume that all LP64 ABI calls reused
> are clean in this regard.

Yes. All the compat_sys_* are defined to return a long, so even if ILP32
user space treats it as 32-bit, there is no information leak because of
the kernel's sign-extension. So just a false alarm, we can consider this
part sorted.

--
Catalin

2015-04-15 17:02:05

by Philipp Tomsich

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64


> On 15 Apr 2015, at 17:38, Catalin Marinas <[email protected]> wrote:
>
> On Wed, Apr 15, 2015 at 05:15:16PM +0200, Arnd Bergmann wrote:
>> On Wednesday 15 April 2015 11:01:54 Catalin Marinas wrote:
>>> On Wed, Apr 15, 2015 at 11:18:06AM +0200, Dr. Philipp Tomsich wrote:
>>>> We’ve run full systems (built from buildroot) consisting of ILP32 binaries
>>>> only (ok… admittedly gdb was an exception, as we haven’t fixed the fact
>>>> that someone has assumed sizeof(long) == 8 in some data-structure of
>>>> the AArch64 backend there) in our verification runs. In fact, it will be very
>>>> special classes of applications that will need a 64bit address-space.
>>>
>>> If we are to merge AArch64-ILP32, I'd like to see a full software stack,
>>> maybe a distro like Debian. Otherwise the kernel code will bit-rot (just
>>> like it regularly happens with big endian).
>>
>> I actually don't think this should be a prerequisite. We have too many
>> dependencies here, and as long as we are debating the exact ABI,
>> any work that gets put into a full distro support (other than openembedded
>> etc) would likely be wasted.
>
> I agree with this not being a prerequisite for merging ILP32 but at
> least a long term plan to do something beyond openembedded, once we
> agreed on the ABI and _upstreamed_ the kernel and glibc code. Those
> legacy applications will probably need more than glibc to run and it's
> likely that people will want to run them in a full AArch64 (LP64)
> environment. A simpler approach (to me, I'm not a distro person) would
> be to just provide additional ILP32 libs in a multi-lib arm64 distro
> like Debian rather than all the packages. As for the compiler, AFAIK
> aarch64-linux-gnu-* simply needs an option to build for ILP32.

We’ve had a PPA for Ubuntu 14.04 in the past that included glibc, ncurses,
termcap, zlib and a few others in a multiarch setup… this was used in the
field by customers and worked rather well.

One of the engineers in my team is currently working on carrying this forward
so we can use this for any Debian-based AArch64 distribution in the future.

Best,
Phil.

2015-04-15 17:22:33

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Wed, Apr 15, 2015 at 07:01:23PM +0200, Dr. Philipp Tomsich wrote:
> On 15 Apr 2015, at 17:38, Catalin Marinas <[email protected]> wrote:
> > On Wed, Apr 15, 2015 at 05:15:16PM +0200, Arnd Bergmann wrote:
> >> On Wednesday 15 April 2015 11:01:54 Catalin Marinas wrote:
> >>> On Wed, Apr 15, 2015 at 11:18:06AM +0200, Dr. Philipp Tomsich wrote:
> >>>> We’ve run full systems (built from buildroot) consisting of ILP32 binaries
> >>>> only (ok… admittedly gdb was an exception, as we haven’t fixed the fact
> >>>> that someone has assumed sizeof(long) == 8 in some data-structure of
> >>>> the AArch64 backend there) in our verification runs. In fact, it will be very
> >>>> special classes of applications that will need a 64bit address-space.
> >>>
> >>> If we are to merge AArch64-ILP32, I'd like to see a full software stack,
> >>> maybe a distro like Debian. Otherwise the kernel code will bit-rot (just
> >>> like it regularly happens with big endian).
> >>
> >> I actually don't think this should be a prerequisite. We have too many
> >> dependencies here, and as long as we are debating the exact ABI,
> >> any work that gets put into a full distro support (other than openembedded
> >> etc) would likely be wasted.
> >
> > I agree with this not being a prerequisite for merging ILP32 but at
> > least a long term plan to do something beyond openembedded, once we
> > agreed on the ABI and _upstreamed_ the kernel and glibc code. Those
> > legacy applications will probably need more than glibc to run and it's
> > likely that people will want to run them in a full AArch64 (LP64)
> > environment. A simpler approach (to me, I'm not a distro person) would
> > be to just provide additional ILP32 libs in a multi-lib arm64 distro
> > like Debian rather than all the packages. As for the compiler, AFAIK
> > aarch64-linux-gnu-* simply needs an option to build for ILP32.
>
> We’ve had a PPA for Ubuntu 14.04 in the past that included glibc, ncurses,
> termcap, zlib and a few others in a multiarch setup… this was used in the
> field by customers and worked rather well.
>
> One of the engineers in my team is currently working on carrying this forward
> so we can use this for any Debian-based AArch64 distribution in the future.

That sounds great. What I'm looking for is to be able to build something
like LTP to be able to reproduce the testing before merging the code. So
the PPA approach looks good.

--
Catalin

2015-04-15 22:25:48

by Alexander Graf

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On 15.04.15 19:22, Catalin Marinas wrote:
> On Wed, Apr 15, 2015 at 07:01:23PM +0200, Dr. Philipp Tomsich wrote:
>> On 15 Apr 2015, at 17:38, Catalin Marinas <[email protected]> wrote:
>>> On Wed, Apr 15, 2015 at 05:15:16PM +0200, Arnd Bergmann wrote:
>>>> On Wednesday 15 April 2015 11:01:54 Catalin Marinas wrote:
>>>>> On Wed, Apr 15, 2015 at 11:18:06AM +0200, Dr. Philipp Tomsich wrote:
>>>>>> We’ve run full systems (built from buildroot) consisting of ILP32 binaries
>>>>>> only (ok… admittedly gdb was an exception, as we haven’t fixed the fact
>>>>>> that someone has assumed sizeof(long) == 8 in some data-structure of
>>>>>> the AArch64 backend there) in our verification runs. In fact, it will be very
>>>>>> special classes of applications that will need a 64bit address-space.
>>>>>
>>>>> If we are to merge AArch64-ILP32, I'd like to see a full software stack,
>>>>> maybe a distro like Debian. Otherwise the kernel code will bit-rot (just
>>>>> like it regularly happens with big endian).
>>>>
>>>> I actually don't think this should be a prerequisite. We have too many
>>>> dependencies here, and as long as we are debating the exact ABI,
>>>> any work that gets put into a full distro support (other than openembedded
>>>> etc) would likely be wasted.
>>>
>>> I agree with this not being a prerequisite for merging ILP32 but at
>>> least a long term plan to do something beyond openembedded, once we
>>> agreed on the ABI and _upstreamed_ the kernel and glibc code. Those
>>> legacy applications will probably need more than glibc to run and it's
>>> likely that people will want to run them in a full AArch64 (LP64)
>>> environment. A simpler approach (to me, I'm not a distro person) would
>>> be to just provide additional ILP32 libs in a multi-lib arm64 distro
>>> like Debian rather than all the packages. As for the compiler, AFAIK
>>> aarch64-linux-gnu-* simply needs an option to build for ILP32.
>>
>> We’ve had a PPA for Ubuntu 14.04 in the past that included glibc, ncurses,
>> termcap, zlib and a few others in a multiarch setup… this was used in the
>> field by customers and worked rather well.
>>
>> One of the engineers in my team is currently working on carrying this forward
>> so we can use this for any Debian-based AArch64 distribution in the future.
>
> That sounds great. What I'm looking for is to be able to build something
> like LTP to be able to reproduce the testing before merging the code. So
> the PPA approach looks good.

We've just started to bootstrap openSUSE for ILP32 with the non-final
abi. However, keep in mind that at least for us bootstrapping is a
manual process. So changing syscall numbers means we'll need to go
through the manual process again.

So if you need any help on getting you an environment that allows you to
build LTP with whatever syscall abi people come up with, feel free to
poke Andreas or me.


Alex

PS: This mail does not include any commitment to maintain an ILP32
openSUSE distribution ;)

2015-04-16 11:03:39

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Thu, Apr 16, 2015 at 12:25:36AM +0200, Alexander Graf wrote:
> We've just started to bootstrap openSUSE for ILP32 with the non-final
> abi. However, keep in mind that at least for us bootstrapping is a
> manual process. So changing syscall numbers means we'll need to go
> through the manual process again.
>
> So if you need any help on getting you an environment that allows you to
> build LTP with whatever syscall abi people come up with, feel free to
> poke Andreas or me.

Thanks for the offer. It's great to see a full distro being built (even
though no commitment).

But I'm a bit worried that people started using these patches and we
haven't agreed on the ABI yet (well, for a while we thought that the x32
approach was fine until I've seen objections from others).

Maybe a quick poll on the options, ignoring syscall number details (we
go for the generic ones) or syscall tables sharing:

a) AArch32-like ILP32 ABI, 32-bit time_t, 32-bit __kernel_long_t
(POSIX-compliant)
b) Future-proof ILP32 ABI, 64-bit time_t, 32-bit __kernel_long_t (as
seen by the user) (POSIX-compliant)
c) LP64-like ILP32 ABI, 64-bit time_t, 64-bit __kernel_long_t
(non-POSIX-compliant)

Option (a) is the easiest from the kernel perspective and has the
highest chance of not breaking legacy AArch32 applications.

Option (b) is more future looking (beyond 2038) but it introduces a
third ABI in the kernel (incompatible with both compat and native).
There is also a risk that legacy applications assume a 32-bit time_t.

Option (c) is pretty much what we currently have in these patches. While
many syscalls are native LP64, it doesn't fully solve pointers in
structures shared between user and kernel (ioctl being one of the
affected areas)

I can't tell how bad the impact of non-POSIX compliance is. If this is
essential, between (a) and (b) I'm more in favour of (a) as the easiest
for both kernel and user. If we were to start a new ABI from scratch
without legacy applications, I would have definitely gone for (b) but
I'm worried about legacy applications still not fully working with this
option while adding more maintenance burden in the kernel.

--
Catalin

2015-04-16 11:19:34

by Philipp Tomsich

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

Just for the record (and to avoid anyone wasting their time on what’s available
today): we are migrating this over to option (a) now, even though we would
prefer to see option (b) implemented.

If we get a consensus on (b) in the next couple of days, we’ll redo things for
option (b). If not, we will have an implementation for option (a) available that
we can hopefully all agree on merging.

Best,
Phil.

> On 16 Apr 2015, at 13:03, Catalin Marinas <[email protected]> wrote:
>
> On Thu, Apr 16, 2015 at 12:25:36AM +0200, Alexander Graf wrote:
>> We've just started to bootstrap openSUSE for ILP32 with the non-final
>> abi. However, keep in mind that at least for us bootstrapping is a
>> manual process. So changing syscall numbers means we'll need to go
>> through the manual process again.
>>
>> So if you need any help on getting you an environment that allows you to
>> build LTP with whatever syscall abi people come up with, feel free to
>> poke Andreas or me.
>
> Thanks for the offer. It's great to see a full distro being built (even
> though no commitment).
>
> But I'm a bit worried that people started using these patches and we
> haven't agreed on the ABI yet (well, for a while we thought that the x32
> approach was fine until I've seen objections from others).
>
> Maybe a quick poll on the options, ignoring syscall number details (we
> go for the generic ones) or syscall tables sharing:
>
> a) AArch32-like ILP32 ABI, 32-bit time_t, 32-bit __kernel_long_t
> (POSIX-compliant)
> b) Future-proof ILP32 ABI, 64-bit time_t, 32-bit __kernel_long_t (as
> seen by the user) (POSIX-compliant)
> c) LP64-like ILP32 ABI, 64-bit time_t, 64-bit __kernel_long_t
> (non-POSIX-compliant)
>
> Option (a) is the easiest from the kernel perspective and has the
> highest chance of not breaking legacy AArch32 applications.
>
> Option (b) is more future looking (beyond 2038) but it introduces a
> third ABI in the kernel (incompatible with both compat and native).
> There is also a risk that legacy applications assume a 32-bit time_t.
>
> Option (c) is pretty much what we currently have in these patches. While
> many syscalls are native LP64, it doesn't fully solve pointers in
> structures shared between user and kernel (ioctl being one of the
> affected areas)
>
> I can't tell how bad the impact of non-POSIX compliance is. If this is
> essential, between (a) and (b) I'm more in favour of (a) as the easiest
> for both kernel and user. If we were to start a new ABI from scratch
> without legacy applications, I would have definitely gone for (b) but
> I'm worried about legacy applications still not fully working with this
> option while adding more maintenance burden in the kernel.
>
> --
> Catalin

2015-04-16 11:49:03

by Andrew Pinski

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64





> On Apr 16, 2015, at 4:19 AM, Dr. Philipp Tomsich <[email protected]> wrote:
>
> Just for the record (and to avoid anyone wasting their time on what?s available
> today): we are migrating this over to option (a) now, even though we would
> prefer to see option (b) implemented.
>
> If we get a consensus on (b) in the next couple of days, we?ll redo things for
> option (b). If not, we will have an implementation for option (a) available that
> we can hopefully all agree on merging.

I don't think either a or b are good in the long run. There are only a few places where long should be 32bit rather than 64bit. The non-time_t field of timespec is the only one I can think of. The rest are valid and good idea to stay as 64bit. Including the limits. I think this whole discussion should have happened over a year ago. And I thought c was decided back then. I had even implemented a originally and then asked to move over to c. So I am a bit upset now we are making this kind of huge changes to the abi a year after the original posting of the patch.

Also why does it takes over a year to accept patches into the linux kernel when it takes much less time to make huge changes into gcc (pointer plus is an example which took only a few months to accept and it was an infrastructure change and this is not even an infrastructure change).

Thanks,
Andrew


>
> Best,
> Phil.
>
>> On 16 Apr 2015, at 13:03, Catalin Marinas <[email protected]> wrote:
>>
>> On Thu, Apr 16, 2015 at 12:25:36AM +0200, Alexander Graf wrote:
>>> We've just started to bootstrap openSUSE for ILP32 with the non-final
>>> abi. However, keep in mind that at least for us bootstrapping is a
>>> manual process. So changing syscall numbers means we'll need to go
>>> through the manual process again.
>>>
>>> So if you need any help on getting you an environment that allows you to
>>> build LTP with whatever syscall abi people come up with, feel free to
>>> poke Andreas or me.
>>
>> Thanks for the offer. It's great to see a full distro being built (even
>> though no commitment).
>>
>> But I'm a bit worried that people started using these patches and we
>> haven't agreed on the ABI yet (well, for a while we thought that the x32
>> approach was fine until I've seen objections from others).
>>
>> Maybe a quick poll on the options, ignoring syscall number details (we
>> go for the generic ones) or syscall tables sharing:
>>
>> a) AArch32-like ILP32 ABI, 32-bit time_t, 32-bit __kernel_long_t
>> (POSIX-compliant)
>> b) Future-proof ILP32 ABI, 64-bit time_t, 32-bit __kernel_long_t (as
>> seen by the user) (POSIX-compliant)
>> c) LP64-like ILP32 ABI, 64-bit time_t, 64-bit __kernel_long_t
>> (non-POSIX-compliant)
>>
>> Option (a) is the easiest from the kernel perspective and has the
>> highest chance of not breaking legacy AArch32 applications.
>>
>> Option (b) is more future looking (beyond 2038) but it introduces a
>> third ABI in the kernel (incompatible with both compat and native).
>> There is also a risk that legacy applications assume a 32-bit time_t.
>>
>> Option (c) is pretty much what we currently have in these patches. While
>> many syscalls are native LP64, it doesn't fully solve pointers in
>> structures shared between user and kernel (ioctl being one of the
>> affected areas)
>>
>> I can't tell how bad the impact of non-POSIX compliance is. If this is
>> essential, between (a) and (b) I'm more in favour of (a) as the easiest
>> for both kernel and user. If we were to start a new ABI from scratch
>> without legacy applications, I would have definitely gone for (b) but
>> I'm worried about legacy applications still not fully working with this
>> option while adding more maintenance burden in the kernel.
>>
>> --
>> Catalin
>

2015-04-16 13:31:46

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Thu, Apr 16, 2015 at 11:33:49AM +0000, Pinski, Andrew wrote:
> On Apr 16, 2015, at 4:19 AM, Dr. Philipp Tomsich <[email protected]> wrote:
> > Just for the record (and to avoid anyone wasting their time on what’s available
> > today): we are migrating this over to option (a) now, even though we would
> > prefer to see option (b) implemented.
> >
> > If we get a consensus on (b) in the next couple of days, we’ll redo things for
> > option (b). If not, we will have an implementation for option (a) available that
> > we can hopefully all agree on merging.
>
> I don't think either a or b are good in the long run.

b would have been my preferred option if it wasn't for the legacy apps
support. We could also do it without much hassle in the kernel *if* we
disabled AArch32 compat support (basically use the compat layer for
ILP32). But I don't think choosing between AArch32 and AArch64 ILP32
should be a build time option.

> There are only a few places where long should be 32bit rather than
> 64bit. The non-time_t field of timespec is the only one I can think
> of.

It may be the only one but we could end up with a non-compliant
timespec. Unless we keep the tv_nsec as 32-bit long and add some
padding, we could work around it by getting the C library to sign-extend
such padding or we do it in a new "compat" layer in the kernel (but both
cases imply copying the structure).

However, timerspec is included in other structures, so we'd have to
intercept those as well. Philipp provided a list here:

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

> The rest are valid and good idea to stay as 64bit. Including the
> limits. I think this whole discussion should have happened over a year
> ago. And I thought c was decided back then. I had even implemented a
> originally and then asked to move over to c. So I am a bit upset now
> we are making this kind of huge changes to the abi a year after the
> original posting of the patch.

Well, I said it already, this ABI is *not* a kernel-only decision, so
without further feedback from the user space world I'm not merging any
patches. I thought I was pretty clear 6-7 months ago but there wasn't
any reply until February:

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

> Also why does it takes over a year to accept patches into the linux
> kernel when it takes much less time to make huge changes into gcc

Original developers being unresponsive could be a reason ;) (see the
above post unanswered for few months).

> (pointer plus is an example which took only a few months to accept and
> it was an infrastructure change and this is not even an infrastructure
> change).

ILP32 is an ABI that we have to leave with for many years. We have to
try hard to get it right rather than rush merging the patches (once
merged, we can't break the ABI later).

--
Catalin

2015-04-16 14:27:25

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Thu, Apr 16, 2015 at 01:19:14PM +0200, Dr. Philipp Tomsich wrote:
> Just for the record (and to avoid anyone wasting their time on what’s available
> today): we are migrating this over to option (a) now, even though we would
> prefer to see option (b) implemented.
>
> If we get a consensus on (b) in the next couple of days, we’ll redo things for
> option (b). If not, we will have an implementation for option (a) available that
> we can hopefully all agree on merging.

When you post, please include the libc-alpha list (I think they are fine
with cross-posting), maybe only for the cover letter as that's where the
useful discussion seems to happen.

It's interesting to re-read some older posts on x32 (it's not just
time_t affected, though probably that the most visible):

https://lwn.net/Articles/457089/
https://sourceware.org/ml/libc-alpha/2012-03/msg00487.html
https://sourceware.org/ml/libc-alpha/2012-03/msg00574.html

Basically for x32 POSIX compliance doesn't seem too critical. IIUC, the
x32 wasn't added to solve a 32-bit compatibility problem but as a
potential optimisation for specific cases.

On ARM OTOH, (one of?) the main goal for AArch64 ILP32 is to offer a
solution for 32-bit code when AArch32 is not present (and potentially
slightly more optimal than AArch32 but not necessarily when compared to
LP64).

--
Catalin

2015-04-16 15:22:29

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Thursday 16 April 2015 14:31:34 Catalin Marinas wrote:
> On Thu, Apr 16, 2015 at 11:33:49AM +0000, Pinski, Andrew wrote:
> > On Apr 16, 2015, at 4:19 AM, Dr. Philipp Tomsich <[email protected]> wrote:
> > > Just for the record (and to avoid anyone wasting their time on what’s available
> > > today): we are migrating this over to option (a) now, even though we would
> > > prefer to see option (b) implemented.
> > >
> > > If we get a consensus on (b) in the next couple of days, we’ll redo things for
> > > option (b). If not, we will have an implementation for option (a) available that
> > > we can hopefully all agree on merging.
> >
> > I don't think either a or b are good in the long run.
>
> b would have been my preferred option if it wasn't for the legacy apps
> support. We could also do it without much hassle in the kernel *if* we
> disabled AArch32 compat support (basically use the compat layer for
> ILP32). But I don't think choosing between AArch32 and AArch64 ILP32
> should be a build time option.

Right, that would be a clean way to support it, just one with
a significant downside of not being able to use both ILP32
ABIs concurrently on the same system.

> > There are only a few places where long should be 32bit rather than
> > 64bit. The non-time_t field of timespec is the only one I can think
> > of.
>
> It may be the only one but we could end up with a non-compliant
> timespec. Unless we keep the tv_nsec as 32-bit long and add some
> padding, we could work around it by getting the C library to sign-extend
> such padding or we do it in a new "compat" layer in the kernel (but both
> cases imply copying the structure).
>
> However, timerspec is included in other structures, so we'd have to
> intercept those as well. Philipp provided a list here:
>
> http://article.gmane.org/gmane.linux.kernel/1931497

We're basically in the same boat as x32 then, and should do the
same thing on both most importantly, whatever that ends up.

However, it would be nice to get agreement on the normal
32-bit ABI for time_t and timespec first, and then use the
same thing everywhere.

Arnd

2015-04-17 09:02:16

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Thu, Apr 16, 2015 at 05:21:30PM +0200, Arnd Bergmann wrote:
> On Thursday 16 April 2015 14:31:34 Catalin Marinas wrote:
> > On Thu, Apr 16, 2015 at 11:33:49AM +0000, Pinski, Andrew wrote:
> > > There are only a few places where long should be 32bit rather than
> > > 64bit. The non-time_t field of timespec is the only one I can think
> > > of.
> >
> > It may be the only one but we could end up with a non-compliant
> > timespec. Unless we keep the tv_nsec as 32-bit long and add some
> > padding, we could work around it by getting the C library to sign-extend
> > such padding or we do it in a new "compat" layer in the kernel (but both
> > cases imply copying the structure).
> >
> > However, timerspec is included in other structures, so we'd have to
> > intercept those as well. Philipp provided a list here:
> >
> > http://article.gmane.org/gmane.linux.kernel/1931497
>
> We're basically in the same boat as x32 then, and should do the same
> thing on both most importantly, whatever that ends up.

I'm getting confused ;). I thought you were pushing for a 32-bit time_t
on AArch64 ILP32.

I'm not sure we need to be in the same boat as x32. Their decision was
to primarily use the LP64 ABI and there are performance advantages, not
only the 2038 issue. The downside, few POSIX incompatibilities that I
think they are happy to live with. If we are happy to live with them as
well, we go ahead with the current patchset. We may try to patch some of
the POSIX incompatibilities (see Philipp's list above) by
padding/copying/sign-extending the affected structures.

> However, it would be nice to get agreement on the normal 32-bit ABI
> for time_t and timespec first, and then use the same thing everywhere.

Do you mean for native 32-bit architectures? I think OpenBSD uses a
64-bit time_t already on 32-bit arches, it's doable in Linux as well.

--
Catalin

2015-04-17 13:18:07

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Friday 17 April 2015 10:01:56 Catalin Marinas wrote:
> On Thu, Apr 16, 2015 at 05:21:30PM +0200, Arnd Bergmann wrote:
> > On Thursday 16 April 2015 14:31:34 Catalin Marinas wrote:
> > > On Thu, Apr 16, 2015 at 11:33:49AM +0000, Pinski, Andrew wrote:
> > > > There are only a few places where long should be 32bit rather than
> > > > 64bit. The non-time_t field of timespec is the only one I can think
> > > > of.
> > >
> > > It may be the only one but we could end up with a non-compliant
> > > timespec. Unless we keep the tv_nsec as 32-bit long and add some
> > > padding, we could work around it by getting the C library to sign-extend
> > > such padding or we do it in a new "compat" layer in the kernel (but both
> > > cases imply copying the structure).
> > >
> > > However, timerspec is included in other structures, so we'd have to
> > > intercept those as well. Philipp provided a list here:
> > >
> > > http://article.gmane.org/gmane.linux.kernel/1931497
> >
> > We're basically in the same boat as x32 then, and should do the same
> > thing on both most importantly, whatever that ends up.
>
> I'm getting confused ;). I thought you were pushing for a 32-bit time_t
> on AArch64 ILP32.
>
> I'm not sure we need to be in the same boat as x32. Their decision was
> to primarily use the LP64 ABI and there are performance advantages, not
> only the 2038 issue. The downside, few POSIX incompatibilities that I
> think they are happy to live with. If we are happy to live with them as
> well, we go ahead with the current patchset. We may try to patch some of
> the POSIX incompatibilities (see Philipp's list above) by
> padding/copying/sign-extending the affected structures.

Here is my current line of thinking:

- Using all the aarch32 data structures would be the easiest way, then
we could use the side of asm-generic/unistd.h and everything should
work to the same degree as it does today for aarch32 emulation.
This means 32-bit time_t of course, and it would give us the best
tradeoff between the amount of work needed and the results we get.
A few downsides have been mentioned, but I still think it's the
best approach. This would be the approach e) that you suggested
earlier.

- If we do not use the exact data structures that we have on aarch32,
then I think we should make aarch32 emulation and aarch64-ilp32
emulation mutually exclusive, and provide two separate asm/compat.h
header files that contain the differences. In this case, we should
try to come up with an ABI that makes the most sense for the majority
of the use cases that people are interested in. The two most likely
choices here would be

f) create a new ABI that follows exactly what x32 did. This is a
variation of the earlier b), c), or d), but with the change of
fixing ioctl support by using a matching asm/compat.h. This
would not be entirely POSIX compliant, but it would be a nice
hack to get the highest performance in microbenchmarks, as it
avoids most of the compat layer. Over time, it can get extended
to coexist with aarch32 emulation, but that may take a few years.

g) create a new ABI that does things in exactly the way that we
would use as the native syscall interface if we had an ilp32
kernel running on aarch64 with the asm-generic/unistd.h.
This would mean a 32-bit __kernel_long_t and time_t, but extending
time_t in the long run, together with aarch32 and i386.
This one is particularly interesting for people that are interested
in maximum posix compliance and in having a "nice" ABI, in particular
if there is a slight chance that within the next decade we have
reason to support building an arch/arm64 kernel itself in
aarch64-ilp32 mode.

Between e), f), and g), I'd lean towards e), but I'm fine with the other
two as well and still lack sufficient information on what people want
to do with it in the long run.

> > However, it would be nice to get agreement on the normal 32-bit ABI
> > for time_t and timespec first, and then use the same thing everywhere.
>
> Do you mean for native 32-bit architectures? I think OpenBSD uses a
> 64-bit time_t already on 32-bit arches, it's doable in Linux as well.

Yes, and I'm working on that for Linux. The first step involves fixing
the kernel, one file at a time, changing all users of time_t to use
some other type (ktime_t or time64_t in most cases) instead, and introducing
additional system calls to handle the boundary to user space without
breaking stuff. See my presentation at http://elinux.org/ELC_2015_Presentations
for more detail.

Arnd

2015-04-17 14:06:33

by Alexander Graf

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64



>>>> Am 17.04.2015 um 15:17 schrieb Arnd Bergmann <[email protected]>:
>>>>
>>>>> On Friday 17 April 2015 10:01:56 Catalin Marinas wrote:
>>>>> On Thu, Apr 16, 2015 at 05:21:30PM +0200, Arnd Bergmann wrote:
>>>>> On Thursday 16 April 2015 14:31:34 Catalin Marinas wrote:
>>>>> On Thu, Apr 16, 2015 at 11:33:49AM +0000, Pinski, Andrew wrote:
>>>>> There are only a few places where long should be 32bit rather than
>>>>> 64bit. The non-time_t field of timespec is the only one I can think
>>>>> of.
>>>>
>>>> It may be the only one but we could end up with a non-compliant
>>>> timespec. Unless we keep the tv_nsec as 32-bit long and add some
>>>> padding, we could work around it by getting the C library to sign-extend
>>>> such padding or we do it in a new "compat" layer in the kernel (but both
>>>> cases imply copying the structure).
>>>>
>>>> However, timerspec is included in other structures, so we'd have to
>>>> intercept those as well. Philipp provided a list here:
>>>>
>>>> http://article.gmane.org/gmane.linux.kernel/1931497
>>>
>>> We're basically in the same boat as x32 then, and should do the same
>>> thing on both most importantly, whatever that ends up.
>>
>> I'm getting confused ;). I thought you were pushing for a 32-bit time_t
>> on AArch64 ILP32.
>>
>> I'm not sure we need to be in the same boat as x32. Their decision was
>> to primarily use the LP64 ABI and there are performance advantages, not
>> only the 2038 issue. The downside, few POSIX incompatibilities that I
>> think they are happy to live with. If we are happy to live with them as
>> well, we go ahead with the current patchset. We may try to patch some of
>> the POSIX incompatibilities (see Philipp's list above) by
>> padding/copying/sign-extending the affected structures.
>
> Here is my current line of thinking:
>
> - Using all the aarch32 data structures would be the easiest way, then
> we could use the side of asm-generic/unistd.h and everything should
> work to the same degree as it does today for aarch32 emulation.
> This means 32-bit time_t of course, and it would give us the best
> tradeoff between the amount of work needed and the results we get.
> A few downsides have been mentioned, but I still think it's the
> best approach. This would be the approach e) that you suggested
> earlier.
>
> - If we do not use the exact data structures that we have on aarch32,
> then I think we should make aarch32 emulation and aarch64-ilp32
> emulation mutually exclusive, and provide two separate asm/compat.h
> header files that contain the differences. In this case, we should
> try to come up with an ABI that makes the most sense for the majority
> of the use cases that people are interested in. The two most likely
> choices here would be
>
> f) create a new ABI that follows exactly what x32 did. This is a
> variation of the earlier b), c), or d), but with the change of
> fixing ioctl support by using a matching asm/compat.h. This
> would not be entirely POSIX compliant, but it would be a nice
> hack to get the highest performance in microbenchmarks, as it
> avoids most of the compat layer. Over time, it can get extended
> to coexist with aarch32 emulation, but that may take a few years.
>
> g) create a new ABI that does things in exactly the way that we
> would use as the native syscall interface if we had an ilp32
> kernel running on aarch64 with the asm-generic/unistd.h.
> This would mean a 32-bit __kernel_long_t and time_t, but extending
> time_t in the long run, together with aarch32 and i386.
> This one is particularly interesting for people that are interested
> in maximum posix compliance and in having a "nice" ABI, in particular
> if there is a slight chance that within the next decade we have
> reason to support building an arch/arm64 kernel itself in
> aarch64-ilp32 mode.
>
> Between e), f), and g), I'd lean towards e), but I'm fine with the other
> two as well and still lack sufficient information on what people want
> to do with it in the long run.

I agree with you here. Let's create an interface that has the least possible maintenance overhead. I personally don't care about microbenchmark results - for me the only reason ilp32 exists on aarch64 is for broken non 64bit ready code.


Alex

(I had to drop Catalin from CC as otherwise my mail server wouldn't let me send the mail. Hrm)-

2015-04-17 14:47:06

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

Even more options below ;). I'll add mine.

On Fri, Apr 17, 2015 at 02:17:32PM +0100, Arnd Bergmann wrote:
> Here is my current line of thinking:
>
> - Using all the aarch32 data structures would be the easiest way, then
> we could use the side of asm-generic/unistd.h and everything should
> work to the same degree as it does today for aarch32 emulation.
> This means 32-bit time_t of course, and it would give us the best
> tradeoff between the amount of work needed and the results we get.
> A few downsides have been mentioned, but I still think it's the
> best approach. This would be the approach e) that you suggested
> earlier.

See my comment below on point g). I don't think there are lots of
similarities between the AArch32 structures and the generic ones (you
can look in arch/arm/include/uapi/asm/* rather than the arm64
asm/compat.h).

> - If we do not use the exact data structures that we have on aarch32,
> then I think we should make aarch32 emulation and aarch64-ilp32
> emulation mutually exclusive, and provide two separate asm/compat.h
> header files that contain the differences. In this case, we should
> try to come up with an ABI that makes the most sense for the majority
> of the use cases that people are interested in. The two most likely
> choices here would be
>
> f) create a new ABI that follows exactly what x32 did. This is a
> variation of the earlier b), c), or d), but with the change of
> fixing ioctl support by using a matching asm/compat.h. This
> would not be entirely POSIX compliant, but it would be a nice
> hack to get the highest performance in microbenchmarks, as it
> avoids most of the compat layer. Over time, it can get extended
> to coexist with aarch32 emulation, but that may take a few years.

Even in this case, we could enable AArch32 compat knowing that ioctls
wouldn't work. If this is important, we can add an option to enable
ioctl support for ILP32 and re-target the asm/compat.h definitions.

> g) create a new ABI that does things in exactly the way that we
> would use as the native syscall interface if we had an ilp32
> kernel running on aarch64 with the asm-generic/unistd.h.
> This would mean a 32-bit __kernel_long_t and time_t, but extending
> time_t in the long run, together with aarch32 and i386.
> This one is particularly interesting for people that are interested
> in maximum posix compliance and in having a "nice" ABI, in particular
> if there is a slight chance that within the next decade we have
> reason to support building an arch/arm64 kernel itself in
> aarch64-ilp32 mode.

I don't think there is a much difference between g) and e). The reason
we re-define many structures in asm/compat.h is because we don't have a
generic compat_* definition (e.g. compat_timespec, compat_timeval,
compat_flock, compat_flock64; anyway, I think some of these may not even
be needed with the canonical set of syscalls). The signal related
structures need to be handled differently for AArch32 and AArch64-ILP32
anyway because of the difference in the register set.

I would add a variation of g):

h) create a new ABI that uses asm-generic/unistd.h and generic types
with 32-bit __kernel_long_t and 64-bit time_t. This would be POSIX
compliant and we don't have to worry about extending time_t in the
future. We would have to duplicate some of the generic structures
in asm/compat.h so that we can use the compat layer. However, at
least in the short term, we don't have an easy way to enable both
AArch32 and AArch64 ILP32 in the same kernel (they would be
exclusive).

> Between e), f), and g), I'd lean towards e), but I'm fine with the other
> two as well and still lack sufficient information on what people want
> to do with it in the long run.

I guess we could wait to see a set of patches implementing e) or g) and
choose between afterwards.

> > > However, it would be nice to get agreement on the normal 32-bit ABI
> > > for time_t and timespec first, and then use the same thing everywhere.
> >
> > Do you mean for native 32-bit architectures? I think OpenBSD uses a
> > 64-bit time_t already on 32-bit arches, it's doable in Linux as well.
>
> Yes, and I'm working on that for Linux. The first step involves fixing
> the kernel, one file at a time, changing all users of time_t to use
> some other type (ktime_t or time64_t in most cases) instead, and introducing
> additional system calls to handle the boundary to user space without
> breaking stuff. See my presentation at http://elinux.org/ELC_2015_Presentations
> for more detail.

The approach here is primarily to fix the problem for existing 32-bit
architectures by adding a new syscall and that's fine. But what if we
enforce 64-bit time_t for all _new_ architectures?

--
Catalin

2015-04-17 15:16:23

by Philipp Tomsich

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

More comments below.

> On 17 Apr 2015, at 16:46, Catalin Marinas <[email protected]> wrote:
>
> Even in this case, we could enable AArch32 compat knowing that ioctls
> wouldn't work. If this is important, we can add an option to enable
> ioctl support for ILP32 and re-target the asm/compat.h definitions.
>
>> g) create a new ABI that does things in exactly the way that we
>> would use as the native syscall interface if we had an ilp32
>> kernel running on aarch64 with the asm-generic/unistd.h.
>> This would mean a 32-bit __kernel_long_t and time_t, but extending
>> time_t in the long run, together with aarch32 and i386.
>> This one is particularly interesting for people that are interested
>> in maximum posix compliance and in having a "nice" ABI, in particular
>> if there is a slight chance that within the next decade we have
>> reason to support building an arch/arm64 kernel itself in
>> aarch64-ilp32 mode.

I don’t believe that an ILP32 kernel wouldn’t use an uint64_t for time_t, as it
has full support for 64bit arithmetic anyway. I also believe that other kernel
internals (e.g. filesystems and inode-numbering) would use native 64bit types.

The differences on the kernel side would mainly rest in that only a 32bit address
space could reasonably be managed. So a native ILP32 ABI would differ from
the LP64 ABI mainly in how sizeof(long) is represented in the user-space.

In other works: a native ILP32 ABI on an ILP32 kernel would have a 64bit time_t.

>>>> However, it would be nice to get agreement on the normal 32-bit ABI
>>>> for time_t and timespec first, and then use the same thing everywhere.
>>>
>>> Do you mean for native 32-bit architectures? I think OpenBSD uses a
>>> 64-bit time_t already on 32-bit arches, it's doable in Linux as well.
>>
>> Yes, and I'm working on that for Linux. The first step involves fixing
>> the kernel, one file at a time, changing all users of time_t to use
>> some other type (ktime_t or time64_t in most cases) instead, and introducing
>> additional system calls to handle the boundary to user space without
>> breaking stuff. See my presentation at http://elinux.org/ELC_2015_Presentations
>> for more detail.
>
> The approach here is primarily to fix the problem for existing 32-bit
> architectures by adding a new syscall and that's fine. But what if we
> enforce 64-bit time_t for all _new_ architectures?

This boils down to whether we can define all the new syscalls _right now_ and
get the new (extended) compat-layer set up. In this case we could have a userspace
implementation that already conforms to this for ILP32.

Otherwise, we can just put a (MIPS64) N32-alike (AArch64) ILP32 in and migrate
with everyone else.

Although it feels wrong to add another ABI that has a known limitation, this may
in fact be the easiest way, as any fix to ILP32 would be done together with the
fixes to all other 32bit ABIs.

So, while I would like to have a 64bit time_t for ILP32 based on principle, I do see
the 32bit time_t path as the most pragmatic way forward… especially, as this unlinks
getting “some form of” ILP32 merged from resolving the 64bit time_t issue across
all architectures.

Phil.-

2015-04-17 15:50:00

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Friday 17 April 2015 15:46:57 Catalin Marinas wrote:
> On Fri, Apr 17, 2015 at 02:17:32PM +0100, Arnd Bergmann wrote:
> > - If we do not use the exact data structures that we have on aarch32,
> > then I think we should make aarch32 emulation and aarch64-ilp32
> > emulation mutually exclusive, and provide two separate asm/compat.h
> > header files that contain the differences. In this case, we should
> > try to come up with an ABI that makes the most sense for the majority
> > of the use cases that people are interested in. The two most likely
> > choices here would be
> >
> > f) create a new ABI that follows exactly what x32 did. This is a
> > variation of the earlier b), c), or d), but with the change of
> > fixing ioctl support by using a matching asm/compat.h. This
> > would not be entirely POSIX compliant, but it would be a nice
> > hack to get the highest performance in microbenchmarks, as it
> > avoids most of the compat layer. Over time, it can get extended
> > to coexist with aarch32 emulation, but that may take a few years.
>
> Even in this case, we could enable AArch32 compat knowing that ioctls
> wouldn't work. If this is important, we can add an option to enable
> ioctl support for ILP32 and re-target the asm/compat.h definitions.

We can allow them to coexist, but I'd only do that in mainline after
fixing all existing problems. Otherwise we can end up with user space
that tries to use the wrong ioctl API, and fixing the kernel breaks
the application, without a way for the kernel to detect which behavior
the user expects.

> > g) create a new ABI that does things in exactly the way that we
> > would use as the native syscall interface if we had an ilp32
> > kernel running on aarch64 with the asm-generic/unistd.h.
> > This would mean a 32-bit __kernel_long_t and time_t, but extending
> > time_t in the long run, together with aarch32 and i386.
> > This one is particularly interesting for people that are interested
> > in maximum posix compliance and in having a "nice" ABI, in particular
> > if there is a slight chance that within the next decade we have
> > reason to support building an arch/arm64 kernel itself in
> > aarch64-ilp32 mode.
>
> I don't think there is a much difference between g) and e). The reason
> we re-define many structures in asm/compat.h is because we don't have a
> generic compat_* definition (e.g. compat_timespec, compat_timeval,
> compat_flock, compat_flock64; anyway, I think some of these may not even
> be needed with the canonical set of syscalls). The signal related
> structures need to be handled differently for AArch32 and AArch64-ILP32
> anyway because of the difference in the register set.

Interesting observation, I had not guessed this.

Let's list the differences, this is what I could find:

| #define FIOQSIZE 0x545E

probably broken on arm64 already, should be investigated

| typedef unsigned short __kernel_mode_t;
| typedef unsigned short __kernel_ipc_pid_t;

Both of these affect all sysvipc, but very little else

| typedef unsigned short __kernel_uid_t;
| typedef unsigned short __kernel_gid_t;

sysvipc, ncpfs, and core dumps (probably fine since they are separate
anyway),

| typedef unsigned short __kernel_old_dev_t; /* compat gets this wrong */

old-style loopdev ioctl

| struct stat { ... } /* possibly not needed */

- lustre ioctls (needs to be fixed anyway)
- old stat syscalls (won't be used with asm-generic/unistd.h)

| struct stat64 { ... }

- lustre ioctls
- new style stat syscalls

So, in essence the difference comes down to the syscalls for stat
and ipc. If we use the aarch32 data types, we can share the
fstatat64, fstat64, semctl, msgsnd, msgrcv, msgctl, shmat,
and shmctl compat system calls between aarch32-compat and
aarch64-ilp32-compat. Otherwise we have to duplicate or extend
them to cover both cases at runtime. That would be rather ugly
but entirely doable. The ioctls are hardly affected, the few
ones that differ once __kernel_long_t matches could easily be
fixed up as you say.

> I would add a variation of g):
>
> h) create a new ABI that uses asm-generic/unistd.h and generic types
> with 32-bit __kernel_long_t and 64-bit time_t. This would be POSIX
> compliant and we don't have to worry about extending time_t in the
> future. We would have to duplicate some of the generic structures
> in asm/compat.h so that we can use the compat layer. However, at
> least in the short term, we don't have an easy way to enable both
> AArch32 and AArch64 ILP32 in the same kernel (they would be
> exclusive).

I'd particularly like to avoid this case, out of pure self-interest:

> > > > However, it would be nice to get agreement on the normal 32-bit ABI
> > > > for time_t and timespec first, and then use the same thing everywhere.
> > >
> > > Do you mean for native 32-bit architectures? I think OpenBSD uses a
> > > 64-bit time_t already on 32-bit arches, it's doable in Linux as well.
> >
> > Yes, and I'm working on that for Linux. The first step involves fixing
> > the kernel, one file at a time, changing all users of time_t to use
> > some other type (ktime_t or time64_t in most cases) instead, and introducing
> > additional system calls to handle the boundary to user space without
> > breaking stuff. See my presentation at http://elinux.org/ELC_2015_Presentations
> > for more detail.
>
> The approach here is primarily to fix the problem for existing 32-bit
> architectures by adding a new syscall and that's fine. But what if we
> enforce 64-bit time_t for all _new_ architectures?

I think that makes the job of fixing the existing architectures harder,
because it adds more special cases. It's already incredibly hard to
do this without breaking user space or missing some corner cases that
needs to be fixed. So far, the easy assumption is that 64-bit architectures
use 64-bit time_t, 32-bit architectures use 32-bit time_t, and x32
is somewhat broken regarding ioctl and would be fixed in the process.
I don't want to have to deal with more combinations in the kernel for now.
Once we have established a syscall API and found a large-enough subset
of drivers that have a working ioctl (and the other ones marked
'depends on COMPAT_TIME_T'), we would stop taking new architecture
ports that provide both APIs and mandate that new ones only implement
the 64-bit time_t one.

Arnd

2015-04-18 19:24:57

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Friday 17 April 2015 17:15:46 Dr. Philipp Tomsich wrote:
> More comments below.
>
> > On 17 Apr 2015, at 16:46, Catalin Marinas <[email protected]> wrote:
> >
> > Even in this case, we could enable AArch32 compat knowing that ioctls
> > wouldn't work. If this is important, we can add an option to enable
> > ioctl support for ILP32 and re-target the asm/compat.h definitions.
> >
> >> g) create a new ABI that does things in exactly the way that we
> >> would use as the native syscall interface if we had an ilp32
> >> kernel running on aarch64 with the asm-generic/unistd.h.
> >> This would mean a 32-bit __kernel_long_t and time_t, but extending
> >> time_t in the long run, together with aarch32 and i386.
> >> This one is particularly interesting for people that are interested
> >> in maximum posix compliance and in having a "nice" ABI, in particular
> >> if there is a slight chance that within the next decade we have
> >> reason to support building an arch/arm64 kernel itself in
> >> aarch64-ilp32 mode.
>
> I don’t believe that an ILP32 kernel wouldn’t use an uint64_t for time_t, as it
> has full support for 64bit arithmetic anyway. I also believe that other kernel
> internals (e.g. filesystems and inode-numbering) would use native 64bit types.
>
> The differences on the kernel side would mainly rest in that only a 32bit address
> space could reasonably be managed. So a native ILP32 ABI would differ from
> the LP64 ABI mainly in how sizeof(long) is represented in the user-space.
>
> In other works: a native ILP32 ABI on an ILP32 kernel would have a 64bit time_t.

We normally like to all newly architectures to have an identical ABI though,
which I think would be more important here. 64-bit time_t of course is what
we want all architectures to have in principle, but we didn't do it for nios2
because of the added complexity. I think it's more likely to have no
__kernel_time_t to defined at some point and only provide __kernel_time64_t
in the future for new architectures, but we have not even introduced that.

> >>>> However, it would be nice to get agreement on the normal 32-bit ABI
> >>>> for time_t and timespec first, and then use the same thing everywhere.
> >>>
> >>> Do you mean for native 32-bit architectures? I think OpenBSD uses a
> >>> 64-bit time_t already on 32-bit arches, it's doable in Linux as well.
> >>
> >> Yes, and I'm working on that for Linux. The first step involves fixing
> >> the kernel, one file at a time, changing all users of time_t to use
> >> some other type (ktime_t or time64_t in most cases) instead, and introducing
> >> additional system calls to handle the boundary to user space without
> >> breaking stuff. See my presentation at http://elinux.org/ELC_2015_Presentations
> >> for more detail.
> >
> > The approach here is primarily to fix the problem for existing 32-bit
> > architectures by adding a new syscall and that's fine. But what if we
> > enforce 64-bit time_t for all _new_ architectures?
>
> This boils down to whether we can define all the new syscalls _right now_ and
> get the new (extended) compat-layer set up. In this case we could have a userspace
> implementation that already conforms to this for ILP32.
>
> Otherwise, we can just put a (MIPS64) N32-alike (AArch64) ILP32 in and migrate
> with everyone else.
>
> Although it feels wrong to add another ABI that has a known limitation, this may
> in fact be the easiest way, as any fix to ILP32 would be done together with the
> fixes to all other 32bit ABIs.
>
> So, while I would like to have a 64bit time_t for ILP32 based on principle, I do see
> the 32bit time_t path as the most pragmatic way forward… especially, as this unlinks
> getting “some form of” ILP32 merged from resolving the 64bit time_t issue across
> all architectures.

Given Catalin's comments from yesterday, I think we can just fix the
definitions of 'struct stat64' for asm-generic to make it have the same
layout as the 64-bit version of 'struct stat', and use that for aarch64-ilp32.

Similarly for the four sysvipc headers, we can have a modified version of
the asm-generic ones in arch/arm64/uapi/asm, which will use the same layout
for ilp32 and lp64 without having to set __kernel_ulong_t to 64-bit.

Arnd

2015-04-20 14:42:27

by Zhangjian (Bamvor)

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64



On 2015/4/17 21:17, Arnd Bergmann wrote:
> On Friday 17 April 2015 10:01:56 Catalin Marinas wrote:
>> On Thu, Apr 16, 2015 at 05:21:30PM +0200, Arnd Bergmann wrote:
>>> On Thursday 16 April 2015 14:31:34 Catalin Marinas wrote:
>>>> On Thu, Apr 16, 2015 at 11:33:49AM +0000, Pinski, Andrew wrote:
>>>>> There are only a few places where long should be 32bit rather than
>>>>> 64bit. The non-time_t field of timespec is the only one I can think
>>>>> of.
>>>>
>>>> It may be the only one but we could end up with a non-compliant
>>>> timespec. Unless we keep the tv_nsec as 32-bit long and add some
>>>> padding, we could work around it by getting the C library to sign-extend
>>>> such padding or we do it in a new "compat" layer in the kernel (but both
>>>> cases imply copying the structure).
>>>>
>>>> However, timerspec is included in other structures, so we'd have to
>>>> intercept those as well. Philipp provided a list here:
>>>>
>>>> http://article.gmane.org/gmane.linux.kernel/1931497
>>>
>>> We're basically in the same boat as x32 then, and should do the same
>>> thing on both most importantly, whatever that ends up.
>>
>> I'm getting confused ;). I thought you were pushing for a 32-bit time_t
>> on AArch64 ILP32.
>>
>> I'm not sure we need to be in the same boat as x32. Their decision was
>> to primarily use the LP64 ABI and there are performance advantages, not
>> only the 2038 issue. The downside, few POSIX incompatibilities that I
>> think they are happy to live with. If we are happy to live with them as
>> well, we go ahead with the current patchset. We may try to patch some of
>> the POSIX incompatibilities (see Philipp's list above) by
>> padding/copying/sign-extending the affected structures.
>
> Here is my current line of thinking:
>
> - Using all the aarch32 data structures would be the easiest way, then
> we could use the side of asm-generic/unistd.h and everything should
> work to the same degree as it does today for aarch32 emulation.
> This means 32-bit time_t of course, and it would give us the best
> tradeoff between the amount of work needed and the results we get.
> A few downsides have been mentioned, but I still think it's the
> best approach. This would be the approach e) that you suggested
> earlier.
>
> - If we do not use the exact data structures that we have on aarch32,
> then I think we should make aarch32 emulation and aarch64-ilp32
> emulation mutually exclusive, and provide two separate asm/compat.h
> header files that contain the differences. In this case, we should
> try to come up with an ABI that makes the most sense for the majority
> of the use cases that people are interested in. The two most likely
> choices here would be
From my point of view, Aarch32 and Aarch64 ILP32 should be not exclusive,
otherwise, it would be a little bit hard to maintenance.
IIUC, ILP32 address an optional road for the application migrating from
arm 32bit SOC to arm64 SOC. There are lots of application in huawei we
need to support in the same product. And different subsystem of the product may
choose the different road to migrate. E.g. Aarch32 -> Aarch64 LP64, arm 32bit
-> Aarch64 ILP32, arm 32bit -> Aarch64, ... (Those application running on one
kernel of course).

regards

bamvor

> f) create a new ABI that follows exactly what x32 did. This is a
> variation of the earlier b), c), or d), but with the change of
> fixing ioctl support by using a matching asm/compat.h. This
> would not be entirely POSIX compliant, but it would be a nice
> hack to get the highest performance in microbenchmarks, as it
> avoids most of the compat layer. Over time, it can get extended
> to coexist with aarch32 emulation, but that may take a few years.
>
> g) create a new ABI that does things in exactly the way that we
> would use as the native syscall interface if we had an ilp32
> kernel running on aarch64 with the asm-generic/unistd.h.
> This would mean a 32-bit __kernel_long_t and time_t, but extending
> time_t in the long run, together with aarch32 and i386.
> This one is particularly interesting for people that are interested
> in maximum posix compliance and in having a "nice" ABI, in particular
> if there is a slight chance that within the next decade we have
> reason to support building an arch/arm64 kernel itself in
> aarch64-ilp32 mode.
>
> Between e), f), and g), I'd lean towards e), but I'm fine with the other
> two as well and still lack sufficient information on what people want
> to do with it in the long run.
>
>>> However, it would be nice to get agreement on the normal 32-bit ABI
>>> for time_t and timespec first, and then use the same thing everywhere.
>>
>> Do you mean for native 32-bit architectures? I think OpenBSD uses a
>> 64-bit time_t already on 32-bit arches, it's doable in Linux as well.
>
> Yes, and I'm working on that for Linux. The first step involves fixing
> the kernel, one file at a time, changing all users of time_t to use
> some other type (ktime_t or time64_t in most cases) instead, and introducing
> additional system calls to handle the boundary to user space without
> breaking stuff. See my presentation at http://elinux.org/ELC_2015_Presentations
> for more detail.
>
> Arnd
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>

2015-04-20 15:56:07

by Catalin Marinas

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Fri, Apr 17, 2015 at 05:49:44PM +0200, Arnd Bergmann wrote:
> On Friday 17 April 2015 15:46:57 Catalin Marinas wrote:
> > On Fri, Apr 17, 2015 at 02:17:32PM +0100, Arnd Bergmann wrote:
> > > g) create a new ABI that does things in exactly the way that we
> > > would use as the native syscall interface if we had an ilp32
> > > kernel running on aarch64 with the asm-generic/unistd.h.
> > > This would mean a 32-bit __kernel_long_t and time_t, but extending
> > > time_t in the long run, together with aarch32 and i386.
> > > This one is particularly interesting for people that are interested
> > > in maximum posix compliance and in having a "nice" ABI, in particular
> > > if there is a slight chance that within the next decade we have
> > > reason to support building an arch/arm64 kernel itself in
> > > aarch64-ilp32 mode.
> >
> > I don't think there is a much difference between g) and e). The reason
> > we re-define many structures in asm/compat.h is because we don't have a
> > generic compat_* definition (e.g. compat_timespec, compat_timeval,
> > compat_flock, compat_flock64; anyway, I think some of these may not even
> > be needed with the canonical set of syscalls). The signal related
> > structures need to be handled differently for AArch32 and AArch64-ILP32
> > anyway because of the difference in the register set.
>
> Interesting observation, I had not guessed this.
>
> Let's list the differences, this is what I could find:
>
> | #define FIOQSIZE 0x545E
>
> probably broken on arm64 already, should be investigated

Yes, it seems broken. arm64 uses the generic FIOQSIZE which doesn't
match the compat one.

> | typedef unsigned short __kernel_mode_t;
> | typedef unsigned short __kernel_ipc_pid_t;
>
> Both of these affect all sysvipc, but very little else
>
> | typedef unsigned short __kernel_uid_t;
> | typedef unsigned short __kernel_gid_t;
>
> sysvipc, ncpfs, and core dumps (probably fine since they are separate
> anyway),

Not all ipc functions are affected AFAICT. msgsnd, msgrcv, msgctl look
to me like we can just use the compat variants with the generic
definitions for the types above (unless I missed something). Similarly
for shmat, compat_sys_shmat just does some compat_ptr casting.

> | typedef unsigned short __kernel_old_dev_t; /* compat gets this wrong */
>
> old-style loopdev ioctl
>
> | struct stat { ... } /* possibly not needed */
>
> - lustre ioctls (needs to be fixed anyway)
> - old stat syscalls (won't be used with asm-generic/unistd.h)
>
> | struct stat64 { ... }
>
> - lustre ioctls
> - new style stat syscalls

For stat64 the wrappers don't look complicated, so we could add arm64
ILP32-specific ones.

I'm not sure about the ioctls affected, I haven't checked.

> So, in essence the difference comes down to the syscalls for stat
> and ipc. If we use the aarch32 data types, we can share the
> fstatat64, fstat64, semctl, msgsnd, msgrcv, msgctl, shmat,
> and shmctl compat system calls between aarch32-compat and
> aarch64-ilp32-compat. Otherwise we have to duplicate or extend
> them to cover both cases at runtime. That would be rather ugly
> but entirely doable. The ioctls are hardly affected, the few
> ones that differ once __kernel_long_t matches could easily be
> fixed up as you say.

I'd prefer a cleaner ABI even if we are to write some specific wrappers.

--
Catalin

2015-04-20 17:40:55

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Monday 20 April 2015 16:56:00 Catalin Marinas wrote:
> On Fri, Apr 17, 2015 at 05:49:44PM +0200, Arnd Bergmann wrote:
> > On Friday 17 April 2015 15:46:57 Catalin Marinas wrote:
> > > On Fri, Apr 17, 2015 at 02:17:32PM +0100, Arnd Bergmann wrote:
> > | typedef unsigned short __kernel_mode_t;
> > | typedef unsigned short __kernel_ipc_pid_t;
> >
> > Both of these affect all sysvipc, but very little else
> >
> > | typedef unsigned short __kernel_uid_t;
> > | typedef unsigned short __kernel_gid_t;
> >
> > sysvipc, ncpfs, and core dumps (probably fine since they are separate
> > anyway),
>
> Not all ipc functions are affected AFAICT. msgsnd, msgrcv, msgctl look
> to me like we can just use the compat variants with the generic
> definitions for the types above (unless I missed something). Similarly
> for shmat, compat_sys_shmat just does some compat_ptr casting.

Right.

> > | typedef unsigned short __kernel_old_dev_t; /* compat gets this wrong */
> >
> > old-style loopdev ioctl
> >
> > | struct stat { ... } /* possibly not needed */
> >
> > - lustre ioctls (needs to be fixed anyway)
> > - old stat syscalls (won't be used with asm-generic/unistd.h)
> >
> > | struct stat64 { ... }
> >
> > - lustre ioctls
> > - new style stat syscalls
>
> For stat64 the wrappers don't look complicated, so we could add arm64
> ILP32-specific ones.

stat is never easy ;-)

Note that for new architectures, we use 'struct stat64' on 32-bit systems
but 'struct stat' on 64-bit systems. Old architectures like arch/arm has
both, and neither of them matches the on from arch/arm64.

Also, the asm-generic definition of 'struct stat64' is wrong and really
needs to be fixed to have the same layout that 'struct stat' has on
a 64-bit architecture. The only difference between the two is the size
of the time related 'st_atime' etc members, and having them defined
this way was my biggest mistake when I created the uapi/asm-generic
headers.

> > So, in essence the difference comes down to the syscalls for stat
> > and ipc. If we use the aarch32 data types, we can share the
> > fstatat64, fstat64, semctl, msgsnd, msgrcv, msgctl, shmat,
> > and shmctl compat system calls between aarch32-compat and
> > aarch64-ilp32-compat. Otherwise we have to duplicate or extend
> > them to cover both cases at runtime. That would be rather ugly
> > but entirely doable. The ioctls are hardly affected, the few
> > ones that differ once __kernel_long_t matches could easily be
> > fixed up as you say.
>
> I'd prefer a cleaner ABI even if we are to write some specific wrappers.

Ok, makes sense. As I replied to Philipp later, even with the
cleaner definition of 'stat64' and the sysipc syscalls, we should
be able to trivially reuse the native 64-bit version in the way that
the current patch set does for a lot of other syscalls, but keep all
the other syscalls using the normal 32-bit __kernel_long_t variants
that we already have.

Arnd

2015-05-04 10:30:47

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Saturday 18 April 2015 21:24:19 Arnd Bergmann wrote:
> Given Catalin's comments from yesterday, I think we can just fix the
> definitions of 'struct stat64' for asm-generic to make it have the same
> layout as the 64-bit version of 'struct stat', and use that for aarch64-ilp32.
>
> Similarly for the four sysvipc headers, we can have a modified version of
> the asm-generic ones in arch/arm64/uapi/asm, which will use the same layout
> for ilp32 and lp64 without having to set __kernel_ulong_t to 64-bit.

To pick up that earlier thread, I now have a prototype implementation for
converting all 32-bit architectures to use 64-bit time_t.

For 'struct stat', I ended up introducing a new structure on arm32 that
matches the layout of arm64 (and I did the same for all other 32-bit
architectures that have a 64-bit counterpart). This means we can share
the same system calls between arm64-lp64, arm64-ilp32 and arm32 with
64-bit time_t and arm64-aarch32 emulation for 32-bit time_t, while
using the existing compat handling for the original 'struct stat'
emulation in both arm32 and arm64-aarch32.

However, for ipc, the situation is different: I found a way to use
extra padding fields in semid64_ds/shmid64_ds/msqid64_ds, so the
ipc system calls will still use normal 32-bit data structures
on arm32 and arm64-aarch64, but you cannot use them arm64-ilp32,
and will have to #ifdef the three header files there to choose between
the two implementations.

Arnd

2015-05-04 10:33:02

by Philipp Tomsich

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

Arnd,

Where can I pull this prototype implementation from?
As we are working on getting a final ILP32 change-set ready, I’d like to make
sure that we base this on the latest consensus for new ILP32 ABIs on 64bit
machines.

Thanks,
Philipp.

> On 04 May 2015, at 12:29, Arnd Bergmann <[email protected]> wrote:
>
> On Saturday 18 April 2015 21:24:19 Arnd Bergmann wrote:
>> Given Catalin's comments from yesterday, I think we can just fix the
>> definitions of 'struct stat64' for asm-generic to make it have the same
>> layout as the 64-bit version of 'struct stat', and use that for aarch64-ilp32.
>>
>> Similarly for the four sysvipc headers, we can have a modified version of
>> the asm-generic ones in arch/arm64/uapi/asm, which will use the same layout
>> for ilp32 and lp64 without having to set __kernel_ulong_t to 64-bit.
>
> To pick up that earlier thread, I now have a prototype implementation for
> converting all 32-bit architectures to use 64-bit time_t.
>
> For 'struct stat', I ended up introducing a new structure on arm32 that
> matches the layout of arm64 (and I did the same for all other 32-bit
> architectures that have a 64-bit counterpart). This means we can share
> the same system calls between arm64-lp64, arm64-ilp32 and arm32 with
> 64-bit time_t and arm64-aarch32 emulation for 32-bit time_t, while
> using the existing compat handling for the original 'struct stat'
> emulation in both arm32 and arm64-aarch32.
>
> However, for ipc, the situation is different: I found a way to use
> extra padding fields in semid64_ds/shmid64_ds/msqid64_ds, so the
> ipc system calls will still use normal 32-bit data structures
> on arm32 and arm64-aarch64, but you cannot use them arm64-ilp32,
> and will have to #ifdef the three header files there to choose between
> the two implementations.
>
> Arnd

2015-05-04 14:45:00

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Monday 04 May 2015 12:32:30 Dr. Philipp Tomsich wrote:
> Arnd,
>
> Where can I pull this prototype implementation from?
> As we are working on getting a final ILP32 change-set ready, I’d like to make
> sure that we base this on the latest consensus for new ILP32 ABIs on 64bit
> machines.
>

I currently have an early prototype that I have done on top of another
working branch. You can find it at

git://git.kernel.org/pub/scm/linux/kernel/git/arnd/playground.git y2038-syscalls

to see the current state, but as this has so far not been posted for review
to a wider group of people, I expect that a lot of details will change, possibly
even the overall approach I've taken. See also my introduction at
https://lists.linaro.org/pipermail/y2038/2015-May/000178.html

Arnd

2015-05-05 00:36:39

by Andrew Pinski

[permalink] [raw]
Subject: Re: [PATCH v4 22/24] arm64:ilp32: use compat for stack_t


> On Apr 13, 2015, at 1:18 PM, Philipp Tomsich <[email protected]> wrote:
>
> We use a 'natively sized' stack_t in glibc (i.e. having a 32bit pointer for
> ss_sp), which requires the invocation of the compat layer for the following
> functionality:
> * sigaltstack
> * saving and restoring uc_stack during signal setup and returns

Can you explain why you want to use a natively sized stack_t? My patches for glibc included changing stack_t too. I would rather keep the same size stack_t between lp64 and ilp32 due easier gdb support.

Thanks,
Andrew


>
> As the userspace stack_t is natively sized, we avoid code duplication in the
> syscall table and can use the compat-functions to zero-extend the pointers
> involved.
>
> Signed-off-by: Philipp Tomsich <[email protected]>
> Signed-off-by: Christoph Muellner <[email protected]>
> ---
> arch/arm64/kernel/signal.c | 19 +++++++++++++++++++
> arch/arm64/kernel/sys_ilp32.c | 44 +------------------------------------------
> 2 files changed, 20 insertions(+), 43 deletions(-)
>
> diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
> index 99e36be..b3f6e52 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/vdso.h>
> +#include <asm/syscalls.h>
>
> /*
> * Do a signal return; undo the signal stack. These are aligned to 128-bit.
> @@ -148,9 +149,22 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
> if (restore_sigframe(regs, frame))
> goto badframe;
>
> +
> +#if defined(CONFIG_ARM64_ILP32)
> + if (is_ilp32_compat_task()) {
> + /* For ILP32, we have a different stack_t (the ss_sp
> + field will be only 32bit sized), which fits into
> + the memory area reserved for the (larger) LP64
> + stack_t and which we place into uc_stack: this
> + implies padding after the ILP32 stack_t. */
> + if (compat_restore_altstack((compat_stack_t*)&frame->uc.uc_stack))
> + goto badframe;
> + } else
> +#endif
> if (restore_altstack(&frame->uc.uc_stack))
> goto badframe;
>
> +
> return regs->regs[0];
>
> badframe:
> @@ -264,6 +278,11 @@ static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
> __put_user_error(0, &frame->uc.uc_flags, err);
> __put_user_error(NULL, &frame->uc.uc_link, err);
>
> +#if defined(CONFIG_ARM64_ILP32)
> + if (is_ilp32_compat_task())
> + err |= __compat_save_altstack((compat_stack_t*)&frame->uc.uc_stack, regs->sp);
> + else
> +#endif
> err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
> err |= setup_sigframe(frame, regs, set);
> if (err == 0) {
> diff --git a/arch/arm64/kernel/sys_ilp32.c b/arch/arm64/kernel/sys_ilp32.c
> index 3471f27..31f82ca 100644
> --- a/arch/arm64/kernel/sys_ilp32.c
> +++ b/arch/arm64/kernel/sys_ilp32.c
> @@ -77,6 +77,7 @@
>
> /* Pointer in struct */
> #define sys_mount compat_sys_mount
> +#define sys_sigaltstack compat_sys_sigaltstack
>
> /* NUMA */
> /* unsigned long bitmaps */
> @@ -122,49 +123,6 @@ asmlinkage long ilp32_sys_mq_notify(mqd_t mqdes, const struct sigevent __user *u
> but need special handling due to padding for SIGEV_THREAD. */
> #define sys_mq_notify ilp32_sys_mq_notify
>
> -
> -/* sigaltstack needs some special handling as the
> - padding for stack_t might not be non-zero. */
> -long ilp32_sys_sigaltstack(const stack_t __user *uss_ptr,
> - stack_t __user *uoss_ptr)
> -{
> - stack_t uss, uoss;
> - int ret;
> - mm_segment_t seg;
> -
> - if (uss_ptr) {
> - if (!access_ok(VERIFY_READ, uss_ptr, sizeof(*uss_ptr)))
> - return -EFAULT;
> - if (__get_user(uss.ss_sp, &uss_ptr->ss_sp) |
> - __get_user(uss.ss_flags, &uss_ptr->ss_flags) |
> - __get_user(uss.ss_size, &uss_ptr->ss_size))
> - return -EFAULT;
> - /* Zero extend the sp address and the size. */
> - uss.ss_sp = (void *)(uintptr_t)(unsigned int)(uintptr_t)uss.ss_sp;
> - uss.ss_size = (size_t)(unsigned int)uss.ss_size;
> - }
> - seg = get_fs();
> - set_fs(KERNEL_DS);
> - /* Note we need to use uoss as we have changed the segment to the
> - kernel one so passing an user one around is wrong. */
> - ret = sys_sigaltstack((stack_t __force __user *) (uss_ptr ? &uss : NULL),
> - (stack_t __force __user *) &uoss);
> - set_fs(seg);
> - if (ret >= 0 && uoss_ptr) {
> - if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_t)) ||
> - __put_user(uoss.ss_sp, &uoss_ptr->ss_sp) ||
> - __put_user(uoss.ss_flags, &uoss_ptr->ss_flags) ||
> - __put_user(uoss.ss_size, &uoss_ptr->ss_size))
> - ret = -EFAULT;
> - }
> - return ret;
> -}
> -
> -/* sigaltstack needs some special handling as the padding
> - for stack_t might not be non-zero. */
> -#define sys_sigaltstack ilp32_sys_sigaltstack
> -
> -
> #include <asm/syscalls.h>
>
> #undef __SYSCALL
> --
> 1.9.1
>

2015-05-05 13:11:28

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v4 00/24] ILP32 for ARM64

On Monday 04 May 2015 12:29:52 Arnd Bergmann wrote:
>
> For 'struct stat', I ended up introducing a new structure on arm32 that
> matches the layout of arm64 (and I did the same for all other 32-bit
> architectures that have a 64-bit counterpart). This means we can share
> the same system calls between arm64-lp64, arm64-ilp32 and arm32 with
> 64-bit time_t and arm64-aarch32 emulation for 32-bit time_t, while
> using the existing compat handling for the original 'struct stat'
> emulation in both arm32 and arm64-aarch32.
>
> However, for ipc, the situation is different: I found a way to use
> extra padding fields in semid64_ds/shmid64_ds/msqid64_ds, so the
> ipc system calls will still use normal 32-bit data structures
> on arm32 and arm64-aarch64, but you cannot use them arm64-ilp32,
> and will have to #ifdef the three header files there to choose between
> the two implementations.

I realized that this may need some more clarification. What I meant is
that we can extend the current 32-bit version of struct semid64_ds
and the others on arm32, and in the same way extend compat_semid64_ds
on arm64, but you cannot use that on arm64-ilp32 for other reasons.


The solution here is to redefine the normal arm64 semid64_ds so ilp32
see a structure with the same layout as lp64, and then use sys_semctl()
for arm64-ilp32 but use compat_sys_semctl() for aarch32-compat.

The definition would be something like

#ifdef __LP64__
#include <asm-generic/sembuf.h>
#else
struct semid64_ds {
struct ipc64_perm sem_perm; /* permissions .. see ipc.h */
__kernel_time_t sem_otime; /* last semop time */
__kernel_time_t sem_ctime; /* last change time */
__u64 sem_nsems; /* no. of semaphores in array */
__u64 __unused3;
__u64 __unused4;
};
#endif

Alternatively, we could use the same definition for both lp64 and ilp32,
which would change the type mangling but not the binary structure.

Arnd