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

From: Zhangjian (Bamvor)
Date: Fri May 06 2016 - 08:20:42 EST


Hi,

On 2016/4/6 6:08, Yury Norov wrote:
From: Andrew Pinski <apinski@xxxxxxxxxx>

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

Signed-off-by: Andrew Pinski <Andrew.Pinski@xxxxxxxxxxxxxxxxxx>
Signed-off-by: Yury Norov <ynorov@xxxxxxxxxxxxxxxxxx>
---
arch/arm64/include/asm/unistd.h | 11 ++++++-
arch/arm64/kernel/Makefile | 2 +-
arch/arm64/kernel/entry.S | 12 +++++++-
arch/arm64/kernel/sys_ilp32.c | 65 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 87 insertions(+), 3 deletions(-)
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 2971dea..5ea18ef 100644
--- a/arch/arm64/include/asm/unistd.h
+++ b/arch/arm64/include/asm/unistd.h
@@ -13,9 +13,18 @@
* 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
+#define __ARCH_WANT_COMPAT_STAT64
+#endif
+
+#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
#define __ARCH_WANT_SYS_GETHOSTNAME
#define __ARCH_WANT_SYS_PAUSE
#define __ARCH_WANT_SYS_GETPGRP
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 9dfdf86..7aa65ea 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -28,7 +28,7 @@ $(obj)/%.stub.o: $(obj)/%.o FORCE
arm64-obj-$(CONFIG_AARCH32_EL0) += sys32.o kuser32.o signal32.o \
sys_compat.o entry32.o \
../../arm/kernel/opcodes.o binfmt_elf32.o
-arm64-obj-$(CONFIG_ARM64_ILP32) += binfmt_ilp32.o
+arm64-obj-$(CONFIG_ARM64_ILP32) += binfmt_ilp32.o sys_ilp32.o
arm64-obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o
arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o
arm64-obj-$(CONFIG_ARM64_MODULE_PLTS) += module-plts.o
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index cf4d1ae..1f7a145 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -715,9 +715,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
@@ -737,6 +741,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..0996d8e
--- /dev/null
+++ b/arch/arm64/kernel/sys_ilp32.c
@@ -0,0 +1,65 @@
+/*
+ * AArch64- ILP32 specific system calls implementation
+ *
+ * Copyright (C) 2016 Cavium Inc.
+ * Author: Andrew Pinski <apinski@xxxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/compiler.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/msg.h>
+#include <linux/export.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/syscalls.h>
+#include <linux/compat.h>
+#include <asm-generic/syscalls.h>
+
+/* Using non-compat syscalls where necessary */
+#define compat_sys_fadvise64_64 sys_fadvise64_64
+#define compat_sys_fallocate sys_fallocate
+#define compat_sys_ftruncate64 sys_ftruncate
+#define compat_sys_lookup_dcookie sys_lookup_dcookie
+#define compat_sys_pread64 sys_pread64
+#define compat_sys_pwrite64 sys_pwrite64
+#define compat_sys_readahead sys_readahead
+#define compat_sys_shmat sys_shmat
+#define compat_sys_sync_file_range sys_sync_file_range
+#define compat_sys_truncate64 sys_truncate
+#define sys_llseek sys_lseek
+#define sys_mmap2 sys_mmap
I am a little bit confused here. We wrap the mmap to mmap2 in glibc
without shift the 4096 and We map mmap2 to mmap in kernel which
means we shift with the real page size. It works unless the
application want to mmap the offset bigger then 2G. In ILP32 app,
if the offset is bigger than 2G(e.g. 0xfb000000), it is a negative
number and extend to 64bit nagetive number in kernel
(0xfffffff fb000000). I add the "COMPAT_SYSCALL_WRAP6(mmap, ...)" in
kernel/compat_wrapper.c. But it is not works. I am not sure if it is
already sign extended in userspace.

On the other hand, I read the code of mmap in arm and other
architecture. Usually, they will shift 4096 in userspace and shift
others in kernel if needed. Should we follow the similar ways or we
could call mmap_pgoff in glibc and do the shift according the real
page shift(getpages())?

Thanks

Bamvor