18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
38c2ecf20Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
48c2ecf20Sopenharmony_ci * for more details.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 1995-99, 2000- 02, 06 Ralf Baechle <ralf@linux-mips.org>
78c2ecf20Sopenharmony_ci * Copyright (C) 2001 MIPS Technologies, Inc.
88c2ecf20Sopenharmony_ci * Copyright (C) 2004 Thiemo Seufer
98c2ecf20Sopenharmony_ci * Copyright (C) 2014 Imagination Technologies Ltd.
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci#include <linux/errno.h>
128c2ecf20Sopenharmony_ci#include <asm/asm.h>
138c2ecf20Sopenharmony_ci#include <asm/asmmacro.h>
148c2ecf20Sopenharmony_ci#include <asm/irqflags.h>
158c2ecf20Sopenharmony_ci#include <asm/mipsregs.h>
168c2ecf20Sopenharmony_ci#include <asm/regdef.h>
178c2ecf20Sopenharmony_ci#include <asm/stackframe.h>
188c2ecf20Sopenharmony_ci#include <asm/isadep.h>
198c2ecf20Sopenharmony_ci#include <asm/sysmips.h>
208c2ecf20Sopenharmony_ci#include <asm/thread_info.h>
218c2ecf20Sopenharmony_ci#include <asm/unistd.h>
228c2ecf20Sopenharmony_ci#include <asm/war.h>
238c2ecf20Sopenharmony_ci#include <asm/asm-offsets.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	.align	5
268c2ecf20Sopenharmony_ciNESTED(handle_sys, PT_SIZE, sp)
278c2ecf20Sopenharmony_ci	.set	noat
288c2ecf20Sopenharmony_ci	SAVE_SOME
298c2ecf20Sopenharmony_ci	TRACE_IRQS_ON_RELOAD
308c2ecf20Sopenharmony_ci	STI
318c2ecf20Sopenharmony_ci	.set	at
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	lw	t1, PT_EPC(sp)		# skip syscall on return
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	addiu	t1, 4			# skip to next instruction
368c2ecf20Sopenharmony_ci	sw	t1, PT_EPC(sp)
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	sw	a3, PT_R26(sp)		# save a3 for syscall restarting
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	/*
418c2ecf20Sopenharmony_ci	 * More than four arguments.  Try to deal with it by copying the
428c2ecf20Sopenharmony_ci	 * stack arguments from the user stack to the kernel stack.
438c2ecf20Sopenharmony_ci	 * This Sucks (TM).
448c2ecf20Sopenharmony_ci	 */
458c2ecf20Sopenharmony_ci	lw	t0, PT_R29(sp)		# get old user stack pointer
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	/*
488c2ecf20Sopenharmony_ci	 * We intentionally keep the kernel stack a little below the top of
498c2ecf20Sopenharmony_ci	 * userspace so we don't have to do a slower byte accurate check here.
508c2ecf20Sopenharmony_ci	 */
518c2ecf20Sopenharmony_ci	lw	t5, TI_ADDR_LIMIT($28)
528c2ecf20Sopenharmony_ci	addu	t4, t0, 32
538c2ecf20Sopenharmony_ci	and	t5, t4
548c2ecf20Sopenharmony_ci	bltz	t5, bad_stack		# -> sp is bad
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	/*
578c2ecf20Sopenharmony_ci	 * Ok, copy the args from the luser stack to the kernel stack.
588c2ecf20Sopenharmony_ci	 */
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	.set    push
618c2ecf20Sopenharmony_ci	.set    noreorder
628c2ecf20Sopenharmony_ci	.set	nomacro
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ciload_a4: user_lw(t5, 16(t0))		# argument #5 from usp
658c2ecf20Sopenharmony_ciload_a5: user_lw(t6, 20(t0))		# argument #6 from usp
668c2ecf20Sopenharmony_ciload_a6: user_lw(t7, 24(t0))		# argument #7 from usp
678c2ecf20Sopenharmony_ciload_a7: user_lw(t8, 28(t0))		# argument #8 from usp
688c2ecf20Sopenharmony_ciloads_done:
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	sw	t5, 16(sp)		# argument #5 to ksp
718c2ecf20Sopenharmony_ci	sw	t6, 20(sp)		# argument #6 to ksp
728c2ecf20Sopenharmony_ci	sw	t7, 24(sp)		# argument #7 to ksp
738c2ecf20Sopenharmony_ci	sw	t8, 28(sp)		# argument #8 to ksp
748c2ecf20Sopenharmony_ci	.set	pop
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	.section __ex_table,"a"
778c2ecf20Sopenharmony_ci	PTR	load_a4, bad_stack_a4
788c2ecf20Sopenharmony_ci	PTR	load_a5, bad_stack_a5
798c2ecf20Sopenharmony_ci	PTR	load_a6, bad_stack_a6
808c2ecf20Sopenharmony_ci	PTR	load_a7, bad_stack_a7
818c2ecf20Sopenharmony_ci	.previous
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	lw	t0, TI_FLAGS($28)	# syscall tracing enabled?
848c2ecf20Sopenharmony_ci	li	t1, _TIF_WORK_SYSCALL_ENTRY
858c2ecf20Sopenharmony_ci	and	t0, t1
868c2ecf20Sopenharmony_ci	bnez	t0, syscall_trace_entry # -> yes
878c2ecf20Sopenharmony_cisyscall_common:
888c2ecf20Sopenharmony_ci	subu	v0, v0, __NR_O32_Linux	# check syscall number
898c2ecf20Sopenharmony_ci	sltiu	t0, v0, __NR_O32_Linux_syscalls
908c2ecf20Sopenharmony_ci	beqz	t0, illegal_syscall
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	sll	t0, v0, 2
938c2ecf20Sopenharmony_ci	la	t1, sys_call_table
948c2ecf20Sopenharmony_ci	addu	t1, t0
958c2ecf20Sopenharmony_ci	lw	t2, (t1)		# syscall routine
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	beqz	t2, illegal_syscall
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	jalr	t2			# Do The Real Thing (TM)
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	li	t0, -EMAXERRNO - 1	# error?
1028c2ecf20Sopenharmony_ci	sltu	t0, t0, v0
1038c2ecf20Sopenharmony_ci	sw	t0, PT_R7(sp)		# set error flag
1048c2ecf20Sopenharmony_ci	beqz	t0, 1f
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	lw	t1, PT_R2(sp)		# syscall number
1078c2ecf20Sopenharmony_ci	negu	v0			# error
1088c2ecf20Sopenharmony_ci	sw	t1, PT_R0(sp)		# save it for syscall restarting
1098c2ecf20Sopenharmony_ci1:	sw	v0, PT_R2(sp)		# result
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cio32_syscall_exit:
1128c2ecf20Sopenharmony_ci	j	syscall_exit_partial
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------------ */
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cisyscall_trace_entry:
1178c2ecf20Sopenharmony_ci	SAVE_STATIC
1188c2ecf20Sopenharmony_ci	move	a0, sp
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	/*
1218c2ecf20Sopenharmony_ci	 * syscall number is in v0 unless we called syscall(__NR_###)
1228c2ecf20Sopenharmony_ci	 * where the real syscall number is in a0
1238c2ecf20Sopenharmony_ci	 */
1248c2ecf20Sopenharmony_ci	move	a1, v0
1258c2ecf20Sopenharmony_ci	subu	t2, v0,  __NR_O32_Linux
1268c2ecf20Sopenharmony_ci	bnez	t2, 1f /* __NR_syscall at offset 0 */
1278c2ecf20Sopenharmony_ci	lw	a1, PT_R4(sp)
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci1:	jal	syscall_trace_enter
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	bltz	v0, 1f			# seccomp failed? Skip syscall
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	RESTORE_STATIC
1348c2ecf20Sopenharmony_ci	lw	v0, PT_R2(sp)		# Restore syscall (maybe modified)
1358c2ecf20Sopenharmony_ci	lw	a0, PT_R4(sp)		# Restore argument registers
1368c2ecf20Sopenharmony_ci	lw	a1, PT_R5(sp)
1378c2ecf20Sopenharmony_ci	lw	a2, PT_R6(sp)
1388c2ecf20Sopenharmony_ci	lw	a3, PT_R7(sp)
1398c2ecf20Sopenharmony_ci	j	syscall_common
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci1:	j	syscall_exit
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------------ */
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	/*
1468c2ecf20Sopenharmony_ci	 * Our open-coded access area sanity test for the stack pointer
1478c2ecf20Sopenharmony_ci	 * failed. We probably should handle this case a bit more drastic.
1488c2ecf20Sopenharmony_ci	 */
1498c2ecf20Sopenharmony_cibad_stack:
1508c2ecf20Sopenharmony_ci	li	v0, EFAULT
1518c2ecf20Sopenharmony_ci	sw	v0, PT_R2(sp)
1528c2ecf20Sopenharmony_ci	li	t0, 1				# set error flag
1538c2ecf20Sopenharmony_ci	sw	t0, PT_R7(sp)
1548c2ecf20Sopenharmony_ci	j	o32_syscall_exit
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cibad_stack_a4:
1578c2ecf20Sopenharmony_ci	li	t5, 0
1588c2ecf20Sopenharmony_ci	b	load_a5
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_cibad_stack_a5:
1618c2ecf20Sopenharmony_ci	li	t6, 0
1628c2ecf20Sopenharmony_ci	b	load_a6
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cibad_stack_a6:
1658c2ecf20Sopenharmony_ci	li	t7, 0
1668c2ecf20Sopenharmony_ci	b	load_a7
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cibad_stack_a7:
1698c2ecf20Sopenharmony_ci	li	t8, 0
1708c2ecf20Sopenharmony_ci	b	loads_done
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	/*
1738c2ecf20Sopenharmony_ci	 * The system call does not exist in this kernel
1748c2ecf20Sopenharmony_ci	 */
1758c2ecf20Sopenharmony_ciillegal_syscall:
1768c2ecf20Sopenharmony_ci	li	v0, ENOSYS			# error
1778c2ecf20Sopenharmony_ci	sw	v0, PT_R2(sp)
1788c2ecf20Sopenharmony_ci	li	t0, 1				# set error flag
1798c2ecf20Sopenharmony_ci	sw	t0, PT_R7(sp)
1808c2ecf20Sopenharmony_ci	j	o32_syscall_exit
1818c2ecf20Sopenharmony_ci	END(handle_sys)
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	LEAF(sys_syscall)
1848c2ecf20Sopenharmony_ci	subu	t0, a0, __NR_O32_Linux	# check syscall number
1858c2ecf20Sopenharmony_ci	sltiu	v0, t0, __NR_O32_Linux_syscalls
1868c2ecf20Sopenharmony_ci	beqz	t0, einval		# do not recurse
1878c2ecf20Sopenharmony_ci	sll	t1, t0, 2
1888c2ecf20Sopenharmony_ci	beqz	v0, einval
1898c2ecf20Sopenharmony_ci	lw	t2, sys_call_table(t1)		# syscall routine
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	move	a0, a1				# shift argument registers
1928c2ecf20Sopenharmony_ci	move	a1, a2
1938c2ecf20Sopenharmony_ci	move	a2, a3
1948c2ecf20Sopenharmony_ci	lw	a3, 16(sp)
1958c2ecf20Sopenharmony_ci	lw	t4, 20(sp)
1968c2ecf20Sopenharmony_ci	lw	t5, 24(sp)
1978c2ecf20Sopenharmony_ci	lw	t6, 28(sp)
1988c2ecf20Sopenharmony_ci	sw	t4, 16(sp)
1998c2ecf20Sopenharmony_ci	sw	t5, 20(sp)
2008c2ecf20Sopenharmony_ci	sw	t6, 24(sp)
2018c2ecf20Sopenharmony_ci	jr	t2
2028c2ecf20Sopenharmony_ci	/* Unreached */
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cieinval: li	v0, -ENOSYS
2058c2ecf20Sopenharmony_ci	jr	ra
2068c2ecf20Sopenharmony_ci	END(sys_syscall)
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci#ifdef CONFIG_MIPS_MT_FPAFF
2098c2ecf20Sopenharmony_ci	/*
2108c2ecf20Sopenharmony_ci	 * For FPU affinity scheduling on MIPS MT processors, we need to
2118c2ecf20Sopenharmony_ci	 * intercept sys_sched_xxxaffinity() calls until we get a proper hook
2128c2ecf20Sopenharmony_ci	 * in kernel/sched/core.c.  Considered only temporary we only support
2138c2ecf20Sopenharmony_ci	 * these hooks for the 32-bit kernel - there is no MIPS64 MT processor
2148c2ecf20Sopenharmony_ci	 * atm.
2158c2ecf20Sopenharmony_ci	 */
2168c2ecf20Sopenharmony_ci#define sys_sched_setaffinity	mipsmt_sys_sched_setaffinity
2178c2ecf20Sopenharmony_ci#define sys_sched_getaffinity	mipsmt_sys_sched_getaffinity
2188c2ecf20Sopenharmony_ci#endif /* CONFIG_MIPS_MT_FPAFF */
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci#define __SYSCALL(nr, entry) 	PTR entry
2218c2ecf20Sopenharmony_ci	.align	2
2228c2ecf20Sopenharmony_ci	.type	sys_call_table, @object
2238c2ecf20Sopenharmony_ciEXPORT(sys_call_table)
2248c2ecf20Sopenharmony_ci#include <asm/syscall_table_32_o32.h>
2258c2ecf20Sopenharmony_ci#undef __SYSCALL
226