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