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