tile: add basic support for tilegx
[uclibc-ng.git] / libc / sysdeps / linux / tile / clone.S
blob17b9ab1cdceac508b9693f7ed6986ef178f1a633
1 /* Copyright (C) 2011-2018 Free Software Foundation, Inc.
3    The GNU C Library is free software; you can redistribute it and/or
4    modify it under the terms of the GNU Lesser General Public
5    License as published by the Free Software Foundation; either
6    version 2.1 of the License, or (at your option) any later version.
8    The GNU C Library is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11    Lesser General Public License for more details.
13    You should have received a copy of the GNU Lesser General Public
14    License along with the GNU C Library.  If not, see
15    <http://www.gnu.org/licenses/>.  */
17 /* clone() is even more special than fork() as it mucks with stacks
18    and invokes a function in the right context after it's all over.  */
20 #include <sysdep.h>
21 #define _ERRNO_H 1
22 #include <bits/errno.h>
24 #include <asm/unistd.h>
25 #include <arch/abi.h>
26 #include <linux/sched.h>
28 /* What we save where in the stack frame; must include all callee-saves. */
29 #define FRAME_NEXT_LR   (0 * REGSIZE)  /* reserved by ABI; not used here */
30 #define FRAME_SP        (1 * REGSIZE)
31 #define FRAME_R30       (2 * REGSIZE)
32 #define FRAME_R31       (3 * REGSIZE)
33 #define FRAME_R32       (4 * REGSIZE)
34 #define FRAME_SIZE      (5 * REGSIZE)
36 /* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
37              pid_t *ptid, struct user_desc *tls, pid_t *ctid); */
39         .text
40 ENTRY (__clone)
41         /* Create a stack frame so we can pass callee-saves to new task. */
42         {
43          move r10, sp
44          st sp, lr
45          ADDI_PTR sp, sp, -FRAME_SIZE
46         }
47         cfi_offset (lr, 0)
48         cfi_def_cfa_offset (FRAME_SIZE)
49         ADDI_PTR r11, sp, FRAME_SP
50         {
51          st r11, r10
52          ADDI_PTR r11, sp, FRAME_R30
53         }
54         {
55          st r11, r30
56          ADDI_PTR r11, sp, FRAME_R31
57         }
58         cfi_offset (r30, FRAME_R30 - FRAME_SIZE)
59         {
60          st r11, r31
61          ADDI_PTR r11, sp, FRAME_R32
62         }
63         cfi_offset (r31, FRAME_R31 - FRAME_SIZE)
64         st r11, r32
65         cfi_offset (r32, FRAME_R32 - FRAME_SIZE)
67         /* sanity check arguments */
68         beqz r0, .Linvalid
69         beqz r1, .Linvalid
71         /* Make sure child stack is properly aligned, and set up the
72            top frame so that we can call out of it immediately in the
73            child.  Setting it up here means we fault in the parent if
74            it's bogus, which is probably cleaner than faulting first
75            thing in the child. */
76         ADDI_PTR r1, r1, -C_ABI_SAVE_AREA_SIZE
77         andi r1, r1, -C_ABI_SAVE_AREA_SIZE
78         ADDI_PTR r9, r1, REGSIZE /* sp of this frame on entry, i.e. zero */
79         st r9, zero
81         /* We need to switch the argument convention around from
82            libc to kernel:
84            libc:
85             r0 fn
86             r1 child_stack
87             r2 flags
88             r3 arg
89             r4 ptid
90             r5 tls
91             r6 ctid
93            kernel:
94             r0 flags
95             r1 child_stack [same as libc]
96             r2 ptid
97             r3 ctid
98             r4 tls
100            Plus the callee-saves as described at .Lthread_start, below.  */
101         {
102          move r32, r0
103          move r0, r2
104         }
105         {
106          move r31, r3
107          move r3, r6
108         }
109         {
110          move r30, r2
111          move r2, r4
112         }
113         {
114          move r4, r5
115          moveli TREG_SYSCALL_NR_NAME, __NR_clone
116         }
117         swint1
118         beqz r0, .Lthread_start  /* If in child task.  */
120 .Ldone:
121         /* Restore the callee-saved registers and return. */
122         ADDLI_PTR lr, sp, FRAME_SIZE
123         {
124          ld lr, lr
125          ADDLI_PTR r30, sp, FRAME_R30
126         }
127         {
128          ld r30, r30
129          ADDLI_PTR r31, sp, FRAME_R31
130         }
131         {
132          ld r31, r31
133          ADDLI_PTR r32, sp, FRAME_R32
134         }
135         {
136          ld r32, r32
137          ADDI_PTR sp, sp, FRAME_SIZE
138         }
139         cfi_def_cfa_offset (0)
141         bnez r1, .Lerror
142         jrp lr
144 .Lerror:
145         j SYSCALL_ERROR_NAME
147 .Linvalid:
148         {
149          movei r1, EINVAL
150          j .Ldone
151         }
153 /* This function expects to receive:
155    sp: the top of a valid stack area
156    r30: clone() flags
157    r31: the argument to pass to the user function
158    r32: the user function pointer  */
160 .Lthread_start:
161         cfi_def_cfa_offset (FRAME_SIZE)
162         cfi_undefined (lr)
163         {
164          /* Invoke user function with specified argument. */
165          move r0, r31
166          jalr r32
167         }
168         moveli TREG_SYSCALL_NR_NAME, __NR_exit
169         swint1
170 PSEUDO_END (__clone)
172 libc_hidden_def (clone)
173 weak_alias (__clone, clone)