diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
index cf7a43521c67d318396e185bb7a126460ba1221a..7ffed9d85f0aec8436e2b9d0a212f7c4bc88229f 100644
--- a/arch/arm64/include/asm/syscall.h
+++ b/arch/arm64/include/asm/syscall.h
@@ -28,6 +28,10 @@ extern const syscall_fn_t sys_call_table[];
extern const syscall_fn_t a32_sys_call_table[];
#endif
+#ifdef CONFIG_ARM64_ILP32
+extern const syscall_fn_t ilp32_sys_call_table[];
+#endif
+
static inline int syscall_get_nr(struct task_struct *task,
struct pt_regs *regs)
{
diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h
index c17ae448c3574eb799717ef978675efb3bd50215..f3401de12dc9db49da3eec4d086bdbf70ebe0889 100644
--- a/arch/arm64/include/asm/unistd.h
+++ b/arch/arm64/include/asm/unistd.h
@@ -13,12 +13,16 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-#ifdef CONFIG_AARCH32_EL0
+
+#ifdef CONFIG_COMPAT
#define __ARCH_WANT_COMPAT_STAT64
+#define __ARCH_WANT_SYS_LLSEEK
+#endif
+
+#ifdef CONFIG_AARCH32_EL0
#define __ARCH_WANT_SYS_GETHOSTNAME
#define __ARCH_WANT_SYS_PAUSE
#define __ARCH_WANT_SYS_GETPGRP
-#define __ARCH_WANT_SYS_LLSEEK
#define __ARCH_WANT_SYS_NICE
#define __ARCH_WANT_SYS_SIGPENDING
#define __ARCH_WANT_SYS_SIGPROCMASK
diff --git a/arch/arm64/include/uapi/asm/unistd.h b/arch/arm64/include/uapi/asm/unistd.h
index 439b1c55c827b7fbe4fbfc55ac098d36a6cbbe02..80f1cb4ae2e13c42d17f36b46bf219524bcb7d34 100644
--- a/arch/arm64/include/uapi/asm/unistd.h
+++ b/arch/arm64/include/uapi/asm/unistd.h
@@ -15,7 +15,19 @@
* along with this program. If not, see .
*/
+/*
+ * Use AARCH32 interface for sys_sync_file_range() as it passes 64-bit arguments.
+ */
+#if defined(__ILP32__) || defined(__SYSCALL_COMPAT)
+#define __ARCH_WANT_SYNC_FILE_RANGE2
+#endif
+
+/*
+ * AARCH64/ILP32 is introduced after next syscalls were deprecated.
+ */
+#if !(defined(__ILP32__) || defined(__SYSCALL_COMPAT))
#define __ARCH_WANT_RENAMEAT
#define __ARCH_WANT_SET_GET_RLIMIT
+#endif
#include
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index f6157900a395c102f198622dc324d622a851dc5b..47093d4cb2078b33f25c344a94859c78f0e711e8 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -29,7 +29,7 @@ $(obj)/%.stub.o: $(obj)/%.o FORCE
arm64-obj-$(CONFIG_AARCH32_EL0) += sys32.o kuser32.o signal32.o \
sys_compat.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_COMPAT) += sys32_common.o
arm64-obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o
arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o
diff --git a/arch/arm64/kernel/sys_ilp32.c b/arch/arm64/kernel/sys_ilp32.c
new file mode 100644
index 0000000000000000000000000000000000000000..169a3813631102202a7bff09146c9ce39a789b3d
--- /dev/null
+++ b/arch/arm64/kernel/sys_ilp32.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/*
+ * AArch64- ILP32 specific system calls implementation
+ * Copyright (C) 2018 Marvell.
+ */
+
+#define __SYSCALL_COMPAT
+
+#include
+#include
+#include
+
+#include
+
+/*
+ * AARCH32 requires 4-page alignment for shared memory,
+ * but AARCH64 - only 1 page. This is the only difference
+ * between compat and native sys_shmat(). So ILP32 just pick
+ * AARCH64 version.
+ */
+#define __arm64_compat_sys_shmat __arm64_sys_shmat
+
+/*
+ * ILP32 needs special handling for some ptrace requests.
+ */
+#define __arm64_sys_ptrace __arm64_compat_sys_ptrace
+
+/*
+ * Using AARCH32 interface for syscalls that take 64-bit
+ * parameters in registers.
+ */
+#define __arm64_compat_sys_fadvise64_64 __arm64_compat_sys_aarch32_fadvise64_64
+#define __arm64_compat_sys_fallocate __arm64_compat_sys_aarch32_fallocate
+#define __arm64_compat_sys_ftruncate64 __arm64_compat_sys_aarch32_ftruncate64
+#define __arm64_compat_sys_pread64 __arm64_compat_sys_aarch32_pread64
+#define __arm64_compat_sys_pwrite64 __arm64_compat_sys_aarch32_pwrite64
+#define __arm64_compat_sys_readahead __arm64_compat_sys_aarch32_readahead
+#define __arm64_compat_sys_sync_file_range2 __arm64_compat_sys_aarch32_sync_file_range2
+#define __arm64_compat_sys_truncate64 __arm64_compat_sys_aarch32_truncate64
+#define __arm64_sys_mmap2 __arm64_compat_sys_aarch32_mmap2
+
+/*
+ * Using AARCH32 interface for syscalls that take the size of
+ * struct statfs as an argument, as it's calculated differently
+ * in kernel and user spaces.
+ */
+#define __arm64_compat_sys_fstatfs64 __arm64_compat_sys_aarch32_fstatfs64
+#define __arm64_compat_sys_statfs64 __arm64_compat_sys_aarch32_statfs64
+
+/*
+ * Wrappers to pass the pt_regs argument.
+ */
+#define sys_personality sys_arm64_personality
+
+asmlinkage long sys_ni_syscall(const struct pt_regs *);
+#define __arm64_sys_ni_syscall sys_ni_syscall
+
+#undef __SYSCALL
+#define __SYSCALL(nr, sym) asmlinkage long __arm64_##sym(const struct pt_regs *);
+#include
+
+#undef __SYSCALL
+#define __SYSCALL(nr, sym) [nr] = (syscall_fn_t)__arm64_##sym,
+
+const syscall_fn_t ilp32_sys_call_table[__NR_syscalls] = {
+ [0 ... __NR_syscalls - 1] = (syscall_fn_t)sys_ni_syscall,
+#include
+};
diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index 67021e7d7986bd8392ba3f730a2353ed534d4fdc..20b6ebbd79d67b723d31b036195e6ff69d2507ed 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c
@@ -157,10 +157,33 @@ static inline void sve_user_discard(void)
sve_user_disable();
}
+#ifdef CONFIG_ARM64_ILP32
+static inline void delouse_pt_regs(struct pt_regs *regs)
+{
+ regs->regs[0] &= UINT_MAX;
+ regs->regs[1] &= UINT_MAX;
+ regs->regs[2] &= UINT_MAX;
+ regs->regs[3] &= UINT_MAX;
+ regs->regs[4] &= UINT_MAX;
+ regs->regs[5] &= UINT_MAX;
+ regs->regs[6] &= UINT_MAX;
+ regs->regs[7] &= UINT_MAX;
+}
+#endif
+
asmlinkage void el0_svc_handler(struct pt_regs *regs)
{
+ const syscall_fn_t *t = sys_call_table;
+
+#ifdef CONFIG_ARM64_ILP32
+ if (is_ilp32_compat_task()) {
+ t = ilp32_sys_call_table;
+ delouse_pt_regs(regs);
+ }
+#endif
+
sve_user_discard();
- el0_svc_common(regs, regs->regs[8], __NR_syscalls, sys_call_table);
+ el0_svc_common(regs, regs->regs[8], __NR_syscalls, t);
}
#ifdef CONFIG_AARCH32_EL0