[ARM] 3110/5: old ABI compat: multi-ABI syscall entry support

Patch from Nicolas Pitre

This patch adds the required code to support both user space ABIs at
the same time. A second syscall table is created to include legacy ABI
syscalls that need an ABI compat wrapper.

Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
index 8c0bf04..75e6f9a 100644
--- a/arch/arm/kernel/calls.S
+++ b/arch/arm/kernel/calls.S
@@ -13,7 +13,7 @@
 #define NR_syscalls 328
 #else
 
-__syscall_start:
+100:
 /* 0 */		.long	sys_restart_syscall
 		.long	sys_exit
 		.long	sys_fork_wrapper
@@ -27,7 +27,7 @@
 /* 10 */	.long	sys_unlink
 		.long	sys_execve_wrapper
 		.long	sys_chdir
-		.long	sys_time		/* used by libc4 */
+		.long	OBSOLETE(sys_time)	/* used by libc4 */
 		.long	sys_mknod
 /* 15 */	.long	sys_chmod
 		.long	sys_lchown16
@@ -36,15 +36,15 @@
 		.long	sys_lseek
 /* 20 */	.long	sys_getpid
 		.long	sys_mount
-		.long	sys_oldumount		/* used by libc4 */
+		.long	OBSOLETE(sys_oldumount)	/* used by libc4 */
 		.long	sys_setuid16
 		.long	sys_getuid16
-/* 25 */	.long	sys_stime
+/* 25 */	.long	OBSOLETE(sys_stime)
 		.long	sys_ptrace
-		.long	sys_alarm		/* used by libc4 */
+		.long	OBSOLETE(sys_alarm)	/* used by libc4 */
 		.long	sys_ni_syscall		/* was sys_fstat */
 		.long	sys_pause
-/* 30 */	.long	sys_utime		/* used by libc4 */
+/* 30 */	.long	OBSOLETE(sys_utime)	/* used by libc4 */
 		.long	sys_ni_syscall		/* was sys_stty */
 		.long	sys_ni_syscall		/* was sys_getty */
 		.long	sys_access
@@ -90,21 +90,21 @@
 		.long	sys_sigpending
 		.long	sys_sethostname
 /* 75 */	.long	sys_setrlimit
-		.long	sys_old_getrlimit	/* used by libc4 */
+		.long	OBSOLETE(sys_old_getrlimit) /* used by libc4 */
 		.long	sys_getrusage
 		.long	sys_gettimeofday
 		.long	sys_settimeofday
 /* 80 */	.long	sys_getgroups16
 		.long	sys_setgroups16
-		.long	old_select		/* used by libc4 */
+		.long	OBSOLETE(old_select)	/* used by libc4 */
 		.long	sys_symlink
 		.long	sys_ni_syscall		/* was sys_lstat */
 /* 85 */	.long	sys_readlink
 		.long	sys_uselib
 		.long	sys_swapon
 		.long	sys_reboot
-		.long	old_readdir		/* used by libc4 */
-/* 90 */	.long	old_mmap		/* used by libc4 */
+		.long	OBSOLETE(old_readdir)	/* used by libc4 */
+/* 90 */	.long	OBSOLETE(old_mmap)	/* used by libc4 */
 		.long	sys_munmap
 		.long	sys_truncate
 		.long	sys_ftruncate
@@ -116,7 +116,7 @@
 		.long	sys_statfs
 /* 100 */	.long	sys_fstatfs
 		.long	sys_ni_syscall
-		.long	sys_socketcall
+		.long	OBSOLETE(sys_socketcall)
 		.long	sys_syslog
 		.long	sys_setitimer
 /* 105 */	.long	sys_getitimer
@@ -127,11 +127,11 @@
 /* 110 */	.long	sys_ni_syscall		/* was sys_iopl */
 		.long	sys_vhangup
 		.long	sys_ni_syscall
-		.long	sys_syscall		/* call a syscall */
+		.long	OBSOLETE(sys_syscall)	/* call a syscall */
 		.long	sys_wait4
 /* 115 */	.long	sys_swapoff
 		.long	sys_sysinfo
-		.long	sys_ipc
+		.long	OBSOLETE(ABI(sys_ipc, sys_oabi_ipc))
 		.long	sys_fsync
 		.long	sys_sigreturn_wrapper
 /* 120 */	.long	sys_clone_wrapper
@@ -194,8 +194,8 @@
 		.long	sys_rt_sigtimedwait
 		.long	sys_rt_sigqueueinfo
 		.long	sys_rt_sigsuspend_wrapper
-/* 180 */	.long	sys_pread64
-		.long	sys_pwrite64
+/* 180 */	.long	ABI(sys_pread64, sys_oabi_pread64)
+		.long	ABI(sys_pwrite64, sys_oabi_pwrite64)
 		.long	sys_chown16
 		.long	sys_getcwd
 		.long	sys_capget
@@ -207,11 +207,11 @@
 /* 190 */	.long	sys_vfork_wrapper
 		.long	sys_getrlimit
 		.long	sys_mmap2
-		.long	sys_truncate64
-		.long	sys_ftruncate64
-/* 195 */	.long	sys_stat64
-		.long	sys_lstat64
-		.long	sys_fstat64
+		.long	ABI(sys_truncate64, sys_oabi_truncate64)
+		.long	ABI(sys_ftruncate64, sys_oabi_ftruncate64)
+/* 195 */	.long	ABI(sys_stat64, sys_oabi_stat64)
+		.long	ABI(sys_lstat64, sys_oabi_lstat64)
+		.long	ABI(sys_fstat64, sys_oabi_fstat64)
 		.long	sys_lchown
 		.long	sys_getuid
 /* 200 */	.long	sys_getgid
@@ -235,11 +235,11 @@
 		.long	sys_pivot_root
 		.long	sys_mincore
 /* 220 */	.long	sys_madvise
-		.long	sys_fcntl64
+		.long	ABI(sys_fcntl64, sys_oabi_fcntl64)
 		.long	sys_ni_syscall /* TUX */
 		.long	sys_ni_syscall
 		.long	sys_gettid
-/* 225 */	.long	sys_readahead
+/* 225 */	.long	ABI(sys_readahead, sys_oabi_readahead)
 		.long	sys_setxattr
 		.long	sys_lsetxattr
 		.long	sys_fsetxattr
@@ -265,8 +265,8 @@
 		.long	sys_exit_group
 		.long	sys_lookup_dcookie
 /* 250 */	.long	sys_epoll_create
-		.long	sys_epoll_ctl
-		.long	sys_epoll_wait
+		.long	ABI(sys_epoll_ctl, sys_oabi_epoll_ctl)
+		.long	ABI(sys_epoll_wait, sys_oabi_epoll_wait)
 	 	.long	sys_remap_file_pages
 		.long	sys_ni_syscall	/* sys_set_thread_area */
 /* 255 */	.long	sys_ni_syscall	/* sys_get_thread_area */
@@ -312,7 +312,7 @@
 /* 295 */	.long	sys_getsockopt
 		.long	sys_sendmsg
 		.long	sys_recvmsg
-		.long	sys_semop
+		.long	ABI(sys_semop, sys_oabi_semop)
 		.long	sys_semget
 /* 300 */	.long	sys_semctl
 		.long	sys_msgsnd
@@ -326,7 +326,7 @@
 		.long	sys_add_key
 /* 310 */	.long	sys_request_key
 		.long	sys_keyctl
-		.long	sys_semtimedop
+		.long	ABI(sys_semtimedop, sys_oabi_semtimedop)
 /* vserver */	.long	sys_ni_syscall
 		.long	sys_ioprio_set
 /* 315 */	.long	sys_ioprio_get
@@ -336,9 +336,8 @@
 		.long	sys_mbind
 /* 320 */	.long	sys_get_mempolicy
 		.long	sys_set_mempolicy
-__syscall_end:
 
-		.rept	NR_syscalls - (__syscall_end - __syscall_start) / 4
+		.rept	NR_syscalls - (. - 100b) / 4
 			.long	sys_ni_syscall
 		.endr
 #endif
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 59ce1bc..8826d98 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -123,23 +123,49 @@
 	/*
 	 * Get the system call number.
 	 */
-#if defined(CONFIG_AEABI)
 
-	@ syscall number is in scno (r7) already.
+#if defined(CONFIG_OABI_COMPAT)
 
+	/*
+	 * If we have CONFIG_OABI_COMPAT then we need to look at the swi
+	 * value to determine if it is an EABI or an old ABI call.
+	 */
+#ifdef CONFIG_ARM_THUMB
+	tst	r8, #PSR_T_BIT
+	movne	r10, #0				@ no thumb OABI emulation
+	ldreq	r10, [lr, #-4]			@ get SWI instruction
+#else
+	ldr	r10, [lr, #-4]			@ get SWI instruction
+  A710(	and	ip, r10, #0x0f000000		@ check for SWI		)
+  A710(	teq	ip, #0x0f000000						)
+  A710(	bne	.Larm710bug						)
+#endif
+
+#elif defined(CONFIG_AEABI)
+
+	/*
+	 * Pure EABI user space always put syscall number into scno (r7).
+	 */
   A710(	ldr	ip, [lr, #-4]			@ get SWI instruction	)
   A710(	and	ip, ip, #0x0f000000		@ check for SWI		)
   A710(	teq	ip, #0x0f000000						)
   A710(	bne	.Larm710bug						)
+
 #elif defined(CONFIG_ARM_THUMB)
+
+	/* Legacy ABI only, possibly thumb mode. */
 	tst	r8, #PSR_T_BIT			@ this is SPSR from save_user_regs
 	addne	scno, r7, #__NR_SYSCALL_BASE	@ put OS number in
 	ldreq	scno, [lr, #-4]
+
 #else
+
+	/* Legacy ABI only. */
 	ldr	scno, [lr, #-4]			@ get SWI instruction
   A710(	and	ip, scno, #0x0f000000		@ check for SWI		)
   A710(	teq	ip, #0x0f000000						)
   A710(	bne	.Larm710bug						)
+
 #endif
 
 #ifdef CONFIG_ALIGNMENT_TRAP
@@ -150,12 +176,24 @@
 	enable_irq
 
 	get_thread_info tsk
+	adr	tbl, sys_call_table		@ load syscall table pointer
 	ldr	ip, [tsk, #TI_FLAGS]		@ check for syscall tracing
-#ifndef CONFIG_AEABI
+
+#if defined(CONFIG_OABI_COMPAT)
+	/*
+	 * If the swi argument is zero, this is an EABI call and we do nothing.
+	 *
+	 * If this is an old ABI call, get the syscall number into scno and
+	 * get the old ABI syscall table address.
+	 */
+	bics	r10, r10, #0xff000000
+	eorne	scno, r10, #__NR_OABI_SYSCALL_BASE
+	ldrne	tbl, =sys_oabi_call_table
+#elif !defined(CONFIG_AEABI)
 	bic	scno, scno, #0xff000000		@ mask off SWI op-code
 	eor	scno, scno, #__NR_SYSCALL_BASE	@ check OS number
 #endif
-	adr	tbl, sys_call_table		@ load syscall table pointer
+
 	stmdb	sp!, {r4, r5}			@ push fifth and sixth args
 	tst	ip, #_TIF_SYSCALL_TRACE		@ are we tracing syscalls?
 	bne	__sys_trace
@@ -200,10 +238,24 @@
 __cr_alignment:
 	.word	cr_alignment
 #endif
+	.ltorg
+
+/*
+ * This is the syscall table declaration for native ABI syscalls.
+ * With EABI a couple syscalls are obsolete and defined as sys_ni_syscall.
+ */
+#define ABI(native, compat) native
+#ifdef CONFIG_AEABI
+#define OBSOLETE(syscall) sys_ni_syscall
+#else
+#define OBSOLETE(syscall) syscall
+#endif
 
 	.type	sys_call_table, #object
 ENTRY(sys_call_table)
 #include "calls.S"
+#undef ABI
+#undef OBSOLETE
 
 /*============================================================================
  * Special system call wrappers
@@ -212,8 +264,7 @@
 @ r8 = syscall table
 		.type	sys_syscall, #function
 sys_syscall:
-#ifndef CONFIG_AEABI
-		eor	scno, r0, #__NR_SYSCALL_BASE
+		eor	scno, r0, #__NR_OABI_SYSCALL_BASE
 		cmp	scno, #__NR_syscall - __NR_SYSCALL_BASE
 		cmpne	scno, #NR_syscalls	@ check range
 		stmloia	sp, {r5, r6}		@ shuffle args
@@ -222,7 +273,6 @@
 		movlo	r2, r3
 		movlo	r3, r4
 		ldrlo	pc, [tbl, scno, lsl #2]
-#endif
 		b	sys_ni_syscall
 
 sys_fork_wrapper:
@@ -290,6 +340,7 @@
 #endif
 
 #ifdef CONFIG_OABI_COMPAT
+
 /*
  * These are syscalls with argument register differences
  */
@@ -318,5 +369,18 @@
 		mov	r2, r1
 		b	sys_readahead
 
+/*
+ * Let's declare a second syscall table for old ABI binaries
+ * using the compatibility syscall entries.
+ */
+#define ABI(native, compat) compat
+#define OBSOLETE(syscall) syscall
+
+	.type	sys_oabi_call_table, #object
+ENTRY(sys_oabi_call_table)
+#include "calls.S"
+#undef ABI
+#undef OBSOLETE
+
 #endif
 
diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c
index ea569ba..a491de2 100644
--- a/arch/arm/kernel/sys_arm.c
+++ b/arch/arm/kernel/sys_arm.c
@@ -147,6 +147,7 @@
 	return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
 }
 
+#if !defined(CONFIG_AEABI) || defined(CONFIG_OABI_COMPAT)
 /*
  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
  *
@@ -226,6 +227,7 @@
 		return -ENOSYS;
 	}
 }
+#endif
 
 /* Fork a new task - this creates a new program thread.
  * This is called indirectly via a small wrapper
diff --git a/include/asm-arm/unistd.h b/include/asm-arm/unistd.h
index c9e087f..77430d6 100644
--- a/include/asm-arm/unistd.h
+++ b/include/asm-arm/unistd.h
@@ -514,22 +514,25 @@
 
 #ifdef __KERNEL__
 #define __ARCH_WANT_IPC_PARSE_VERSION
-#define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_STAT64
-#define __ARCH_WANT_SYS_ALARM
 #define __ARCH_WANT_SYS_GETHOSTNAME
 #define __ARCH_WANT_SYS_PAUSE
-#define __ARCH_WANT_SYS_TIME
-#define __ARCH_WANT_SYS_UTIME
-#define __ARCH_WANT_SYS_SOCKETCALL
 #define __ARCH_WANT_SYS_GETPGRP
 #define __ARCH_WANT_SYS_LLSEEK
 #define __ARCH_WANT_SYS_NICE
-#define __ARCH_WANT_SYS_OLD_GETRLIMIT
-#define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGACTION
+
+#if !defined(CONFIG_AEABI) || defined(CONFIG_OABI_COMPAT)
+#define __ARCH_WANT_SYS_TIME
+#define __ARCH_WANT_SYS_OLDUMOUNT
+#define __ARCH_WANT_SYS_ALARM
+#define __ARCH_WANT_SYS_UTIME
+#define __ARCH_WANT_SYS_OLD_GETRLIMIT
+#define __ARCH_WANT_OLD_READDIR
+#define __ARCH_WANT_SYS_SOCKETCALL
+#endif
 #endif
 
 #ifdef __KERNEL_SYSCALLS__