mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-30 15:44:13 +08:00
dcad2a62bc
This is part of a larger series that aims at getting rid of the copy_thread()/copy_thread_tls() split that makes the process creation codepaths in the kernel more convoluted and error-prone than they need to be. It also unblocks implementing clone3() on architectures not support copy_thread_tls(). Any architecture that wants to implement clone3() will need to select HAVE_COPY_THREAD_TLS and thus need to implement copy_thread_tls(). So both goals are connected but independently beneficial. HAVE_COPY_THREAD_TLS means that a given architecture supports CLONE_SETTLS and not setting it should usually mean that the architectures doesn't implement it but that's not how things are. In fact all architectures support CLONE_TLS it's just that they don't follow the calling convention that HAVE_COPY_THREAD_TLS implies. That means all architectures can be switched over to select HAVE_COPY_THREAD_TLS. Once that is done we can remove that macro (yay, less code), the unnecessary do_fork() export in kernel/fork.c, and also rename copy_thread_tls() back to copy_thread(). At this point copy_thread() becomes the main architecture specific part of process creation but it will be the same layout and calling convention for all architectures. (Once that is done we can probably cleanup each copy_thread() function even more but that's for the future.) Since sparc does support CLONE_SETTLS there's no reason to not select HAVE_COPY_THREAD_TLS. This brings us one step closer to getting rid of the copy_thread()/copy_thread_tls() split we still have and ultimately the HAVE_COPY_THREAD_TLS define in general. A lot of architectures have already converted and sparc is one of the few hat haven't yet. This also unblocks implementing the clone3() syscall on sparc which I will follow up later (if no one gets there before me). Once that is done we can get of another ARCH_WANTS_* macro. This patch just switches sparc64 over to HAVE_COPY_THREAD_TLS but not sparc32 which will be done in the next patch. Once Any architecture that supports HAVE_COPY_THREAD_TLS cannot call the do_fork() helper anymore. This is fine and intended since it should be removed in favor of the new, cleaner _do_fork() calling convention based on struct kernel_clone_args. In fact, most architectures have already switched. With this patch, sparc joins the other arches which can't use the fork(), vfork(), clone(), clone3() syscalls directly and who follow the new process creation calling convention that is based on struct kernel_clone_args which we introduced a while back. This means less custom assembly in the architectures entry path to set up the registers before calling into the process creation helper and it is easier to to support new features without having to adapt calling conventions. It also unifies all process creation paths between fork(), vfork(), clone(), and clone3(). (We can't fix the ABI nightmare that legacy clone() is but we can prevent stuff like this happening in the future.) Note that sparc can't easily call into the syscalls directly because of its return value conventions when a new process is created which needs to clobber the UREG_I1 register in copy_thread{_tls()} and it needs to restore it if process creation fails. That's not a big deal since the new process creation calling convention makes things simpler. This removes sparc_do_fork() and replaces it with 3 clean helpers, sparc_fork(), sparc_vfork(), and sparc_clone(). That means a little more C code until the next patch unifies sparc 32bit and sparc64. It has the advantage that we can remove quite a bit of assembler and it makes the whole syscall.S process creation bits easier to read. The follow-up patch will remove the custom sparc_do_fork() helper for 32bi sparc and move sparc_fork(), sparc_vfork(), and sparc_clone() into a common process.c file. This allows us to remove quite a bit of custom assembly form 32bit sparc's entry.S file too and allows to remove even more code because now all helpers are shared between 32bit sparc and sparc64 instead of having to maintain two separate sparc_do_fork() implementations. For some more context, please see: commit606e9ad200
Merge:ac61145a72
457677c70c
Author: Linus Torvalds <torvalds@linux-foundation.org> Date: Sat Jan 11 15:33:48 2020 -0800 Merge tag 'clone3-tls-v5.5-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux Pull thread fixes from Christian Brauner: "This contains a series of patches to fix CLONE_SETTLS when used with clone3(). The clone3() syscall passes the tls argument through struct clone_args instead of a register. This means, all architectures that do not implement copy_thread_tls() but still support CLONE_SETTLS via copy_thread() expecting the tls to be located in a register argument based on clone() are currently unfortunately broken. Their tls value will be garbage. The patch series fixes this on all architectures that currently define __ARCH_WANT_SYS_CLONE3. It also adds a compile-time check to ensure that any architecture that enables clone3() in the future is forced to also implement copy_thread_tls(). My ultimate goal is to get rid of the copy_thread()/copy_thread_tls() split and just have copy_thread_tls() at some point in the not too distant future (Maybe even renaming copy_thread_tls() back to simply copy_thread() once the old function is ripped from all arches). This is dependent now on all arches supporting clone3(). While all relevant arches do that now there are still four missing: ia64, m68k, sh and sparc. They have the system call reserved, but not implemented. Once they all implement clone3() we can get rid of ARCH_WANT_SYS_CLONE3 and HAVE_COPY_THREAD_TLS. Note that in the meantime, m68k has already switched to the new calling convention. Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com> Acked-by: David S. Miller <davem@davemloft.net> Cc: Arnd Bergmann <arnd@arndb.de> Cc: "David S. Miller" <davem@davemloft.net> Cc: Guo Ren <guoren@kernel.org> Cc: linux-csky@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: sparclinux@vger.kernel.org See:d95b56c77e
("openrisc: Cleanup copy_thread_tls docs and comments") See:0b9f386c4b
("csky: Implement copy_thread_tls") Link: https://lore.kernel.org/r/20200512171527.570109-2-christian.brauner@ubuntu.com
302 lines
7.5 KiB
ArmAsm
302 lines
7.5 KiB
ArmAsm
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/* SunOS's execv() call only specifies the argv argument, the
|
|
* environment settings are the same as the calling processes.
|
|
*/
|
|
sys64_execve:
|
|
set sys_execve, %g1
|
|
jmpl %g1, %g0
|
|
flushw
|
|
|
|
sys64_execveat:
|
|
set sys_execveat, %g1
|
|
jmpl %g1, %g0
|
|
flushw
|
|
|
|
#ifdef CONFIG_COMPAT
|
|
sunos_execv:
|
|
mov %g0, %o2
|
|
sys32_execve:
|
|
set compat_sys_execve, %g1
|
|
jmpl %g1, %g0
|
|
flushw
|
|
|
|
sys32_execveat:
|
|
set compat_sys_execveat, %g1
|
|
jmpl %g1, %g0
|
|
flushw
|
|
#endif
|
|
|
|
.align 32
|
|
#ifdef CONFIG_COMPAT
|
|
sys32_sigstack:
|
|
ba,pt %xcc, do_sys32_sigstack
|
|
mov %i6, %o2
|
|
#endif
|
|
.align 32
|
|
#ifdef CONFIG_COMPAT
|
|
sys32_sigreturn:
|
|
add %sp, PTREGS_OFF, %o0
|
|
call do_sigreturn32
|
|
add %o7, 1f-.-4, %o7
|
|
nop
|
|
#endif
|
|
sys_rt_sigreturn:
|
|
add %sp, PTREGS_OFF, %o0
|
|
call do_rt_sigreturn
|
|
add %o7, 1f-.-4, %o7
|
|
nop
|
|
#ifdef CONFIG_COMPAT
|
|
sys32_rt_sigreturn:
|
|
add %sp, PTREGS_OFF, %o0
|
|
call do_rt_sigreturn32
|
|
add %o7, 1f-.-4, %o7
|
|
nop
|
|
#endif
|
|
.align 32
|
|
1: ldx [%g6 + TI_FLAGS], %l5
|
|
andcc %l5, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT|_TIF_SYSCALL_TRACEPOINT|_TIF_NOHZ), %g0
|
|
be,pt %icc, rtrap
|
|
nop
|
|
call syscall_trace_leave
|
|
add %sp, PTREGS_OFF, %o0
|
|
ba,pt %xcc, rtrap
|
|
nop
|
|
|
|
/* This is how fork() was meant to be done, 8 instruction entry.
|
|
*
|
|
* I questioned the following code briefly, let me clear things
|
|
* up so you must not reason on it like I did.
|
|
*
|
|
* Know the fork_kpsr etc. we use in the sparc32 port? We don't
|
|
* need it here because the only piece of window state we copy to
|
|
* the child is the CWP register. Even if the parent sleeps,
|
|
* we are safe because we stuck it into pt_regs of the parent
|
|
* so it will not change.
|
|
*
|
|
* XXX This raises the question, whether we can do the same on
|
|
* XXX sparc32 to get rid of fork_kpsr _and_ fork_kwim. The
|
|
* XXX answer is yes. We stick fork_kpsr in UREG_G0 and
|
|
* XXX fork_kwim in UREG_G1 (global registers are considered
|
|
* XXX volatile across a system call in the sparc ABI I think
|
|
* XXX if it isn't we can use regs->y instead, anyone who depends
|
|
* XXX upon the Y register being preserved across a fork deserves
|
|
* XXX to lose).
|
|
*
|
|
* In fact we should take advantage of that fact for other things
|
|
* during system calls...
|
|
*/
|
|
.align 32
|
|
sys_vfork:
|
|
flushw
|
|
ba,pt %xcc, sparc_vfork
|
|
add %sp, PTREGS_OFF, %o0
|
|
|
|
.align 32
|
|
sys_fork:
|
|
flushw
|
|
ba,pt %xcc, sparc_fork
|
|
add %sp, PTREGS_OFF, %o0
|
|
|
|
.align 32
|
|
sys_clone:
|
|
flushw
|
|
ba,pt %xcc, sparc_clone
|
|
add %sp, PTREGS_OFF, %o0
|
|
|
|
.globl ret_from_fork
|
|
ret_from_fork:
|
|
/* Clear current_thread_info()->new_child. */
|
|
stb %g0, [%g6 + TI_NEW_CHILD]
|
|
call schedule_tail
|
|
mov %g7, %o0
|
|
ldx [%sp + PTREGS_OFF + PT_V9_I0], %o0
|
|
brnz,pt %o0, ret_sys_call
|
|
ldx [%g6 + TI_FLAGS], %l0
|
|
ldx [%sp + PTREGS_OFF + PT_V9_G1], %l1
|
|
call %l1
|
|
ldx [%sp + PTREGS_OFF + PT_V9_G2], %o0
|
|
ba,pt %xcc, ret_sys_call
|
|
mov 0, %o0
|
|
|
|
.globl sparc_exit_group
|
|
.type sparc_exit_group,#function
|
|
sparc_exit_group:
|
|
sethi %hi(sys_exit_group), %g7
|
|
ba,pt %xcc, 1f
|
|
or %g7, %lo(sys_exit_group), %g7
|
|
.size sparc_exit_group,.-sparc_exit_group
|
|
|
|
.globl sparc_exit
|
|
.type sparc_exit,#function
|
|
sparc_exit:
|
|
sethi %hi(sys_exit), %g7
|
|
or %g7, %lo(sys_exit), %g7
|
|
1: rdpr %pstate, %g2
|
|
wrpr %g2, PSTATE_IE, %pstate
|
|
rdpr %otherwin, %g1
|
|
rdpr %cansave, %g3
|
|
add %g3, %g1, %g3
|
|
wrpr %g3, 0x0, %cansave
|
|
wrpr %g0, 0x0, %otherwin
|
|
wrpr %g2, 0x0, %pstate
|
|
jmpl %g7, %g0
|
|
stb %g0, [%g6 + TI_WSAVED]
|
|
.size sparc_exit,.-sparc_exit
|
|
|
|
linux_sparc_ni_syscall:
|
|
sethi %hi(sys_ni_syscall), %l7
|
|
ba,pt %xcc, 4f
|
|
or %l7, %lo(sys_ni_syscall), %l7
|
|
|
|
linux_syscall_trace32:
|
|
call syscall_trace_enter
|
|
add %sp, PTREGS_OFF, %o0
|
|
brnz,pn %o0, 3f
|
|
mov -ENOSYS, %o0
|
|
|
|
/* Syscall tracing can modify the registers. */
|
|
ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1
|
|
sethi %hi(sys_call_table32), %l7
|
|
ldx [%sp + PTREGS_OFF + PT_V9_I0], %i0
|
|
or %l7, %lo(sys_call_table32), %l7
|
|
ldx [%sp + PTREGS_OFF + PT_V9_I1], %i1
|
|
ldx [%sp + PTREGS_OFF + PT_V9_I2], %i2
|
|
ldx [%sp + PTREGS_OFF + PT_V9_I3], %i3
|
|
ldx [%sp + PTREGS_OFF + PT_V9_I4], %i4
|
|
ldx [%sp + PTREGS_OFF + PT_V9_I5], %i5
|
|
|
|
cmp %g1, NR_syscalls
|
|
bgeu,pn %xcc, 3f
|
|
mov -ENOSYS, %o0
|
|
|
|
sll %g1, 2, %l4
|
|
srl %i0, 0, %o0
|
|
lduw [%l7 + %l4], %l7
|
|
srl %i4, 0, %o4
|
|
srl %i1, 0, %o1
|
|
srl %i2, 0, %o2
|
|
ba,pt %xcc, 5f
|
|
srl %i3, 0, %o3
|
|
|
|
linux_syscall_trace:
|
|
call syscall_trace_enter
|
|
add %sp, PTREGS_OFF, %o0
|
|
brnz,pn %o0, 3f
|
|
mov -ENOSYS, %o0
|
|
|
|
/* Syscall tracing can modify the registers. */
|
|
ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1
|
|
sethi %hi(sys_call_table64), %l7
|
|
ldx [%sp + PTREGS_OFF + PT_V9_I0], %i0
|
|
or %l7, %lo(sys_call_table64), %l7
|
|
ldx [%sp + PTREGS_OFF + PT_V9_I1], %i1
|
|
ldx [%sp + PTREGS_OFF + PT_V9_I2], %i2
|
|
ldx [%sp + PTREGS_OFF + PT_V9_I3], %i3
|
|
ldx [%sp + PTREGS_OFF + PT_V9_I4], %i4
|
|
ldx [%sp + PTREGS_OFF + PT_V9_I5], %i5
|
|
|
|
cmp %g1, NR_syscalls
|
|
bgeu,pn %xcc, 3f
|
|
mov -ENOSYS, %o0
|
|
|
|
sll %g1, 2, %l4
|
|
mov %i0, %o0
|
|
lduw [%l7 + %l4], %l7
|
|
mov %i1, %o1
|
|
mov %i2, %o2
|
|
mov %i3, %o3
|
|
b,pt %xcc, 2f
|
|
mov %i4, %o4
|
|
|
|
|
|
/* Linux 32-bit system calls enter here... */
|
|
.align 32
|
|
.globl linux_sparc_syscall32
|
|
linux_sparc_syscall32:
|
|
/* Direct access to user regs, much faster. */
|
|
cmp %g1, NR_syscalls ! IEU1 Group
|
|
bgeu,pn %xcc, linux_sparc_ni_syscall ! CTI
|
|
srl %i0, 0, %o0 ! IEU0
|
|
sll %g1, 2, %l4 ! IEU0 Group
|
|
srl %i4, 0, %o4 ! IEU1
|
|
lduw [%l7 + %l4], %l7 ! Load
|
|
srl %i1, 0, %o1 ! IEU0 Group
|
|
ldx [%g6 + TI_FLAGS], %l0 ! Load
|
|
|
|
srl %i3, 0, %o3 ! IEU0
|
|
srl %i2, 0, %o2 ! IEU0 Group
|
|
andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT|_TIF_SYSCALL_TRACEPOINT|_TIF_NOHZ), %g0
|
|
bne,pn %icc, linux_syscall_trace32 ! CTI
|
|
mov %i0, %l5 ! IEU1
|
|
5: call %l7 ! CTI Group brk forced
|
|
srl %i5, 0, %o5 ! IEU1
|
|
ba,pt %xcc, 3f
|
|
sra %o0, 0, %o0
|
|
|
|
/* Linux native system calls enter here... */
|
|
.align 32
|
|
.globl linux_sparc_syscall
|
|
linux_sparc_syscall:
|
|
/* Direct access to user regs, much faster. */
|
|
cmp %g1, NR_syscalls ! IEU1 Group
|
|
bgeu,pn %xcc, linux_sparc_ni_syscall ! CTI
|
|
mov %i0, %o0 ! IEU0
|
|
sll %g1, 2, %l4 ! IEU0 Group
|
|
mov %i1, %o1 ! IEU1
|
|
lduw [%l7 + %l4], %l7 ! Load
|
|
4: mov %i2, %o2 ! IEU0 Group
|
|
ldx [%g6 + TI_FLAGS], %l0 ! Load
|
|
|
|
mov %i3, %o3 ! IEU1
|
|
mov %i4, %o4 ! IEU0 Group
|
|
andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT|_TIF_SYSCALL_TRACEPOINT|_TIF_NOHZ), %g0
|
|
bne,pn %icc, linux_syscall_trace ! CTI Group
|
|
mov %i0, %l5 ! IEU0
|
|
2: call %l7 ! CTI Group brk forced
|
|
mov %i5, %o5 ! IEU0
|
|
nop
|
|
|
|
3: stx %o0, [%sp + PTREGS_OFF + PT_V9_I0]
|
|
ret_sys_call:
|
|
ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %g3
|
|
mov %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
|
|
sllx %g2, 32, %g2
|
|
|
|
cmp %o0, -ERESTART_RESTARTBLOCK
|
|
bgeu,pn %xcc, 1f
|
|
andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT|_TIF_SYSCALL_TRACEPOINT|_TIF_NOHZ), %g0
|
|
ldx [%sp + PTREGS_OFF + PT_V9_TNPC], %l1 ! pc = npc
|
|
|
|
2:
|
|
/* System call success, clear Carry condition code. */
|
|
andn %g3, %g2, %g3
|
|
3:
|
|
stx %g3, [%sp + PTREGS_OFF + PT_V9_TSTATE]
|
|
bne,pn %icc, linux_syscall_trace2
|
|
add %l1, 0x4, %l2 ! npc = npc+4
|
|
stx %l1, [%sp + PTREGS_OFF + PT_V9_TPC]
|
|
ba,pt %xcc, rtrap
|
|
stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
|
|
|
|
1:
|
|
/* Check if force_successful_syscall_return()
|
|
* was invoked.
|
|
*/
|
|
ldub [%g6 + TI_SYS_NOERROR], %l2
|
|
brnz,pn %l2, 2b
|
|
ldx [%sp + PTREGS_OFF + PT_V9_TNPC], %l1 ! pc = npc
|
|
/* System call failure, set Carry condition code.
|
|
* Also, get abs(errno) to return to the process.
|
|
*/
|
|
sub %g0, %o0, %o0
|
|
stx %o0, [%sp + PTREGS_OFF + PT_V9_I0]
|
|
ba,pt %xcc, 3b
|
|
or %g3, %g2, %g3
|
|
|
|
linux_syscall_trace2:
|
|
call syscall_trace_leave
|
|
add %sp, PTREGS_OFF, %o0
|
|
stx %l1, [%sp + PTREGS_OFF + PT_V9_TPC]
|
|
ba,pt %xcc, rtrap
|
|
stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
|