diff options
Diffstat (limited to 'arch/cris/arch-v10/kernel/process.c')
-rw-r--r-- | arch/cris/arch-v10/kernel/process.c | 121 |
1 files changed, 19 insertions, 102 deletions
diff --git a/arch/cris/arch-v10/kernel/process.c b/arch/cris/arch-v10/kernel/process.c index 15ac7150371f..b1018750cffb 100644 --- a/arch/cris/arch-v10/kernel/process.c +++ b/arch/cris/arch-v10/kernel/process.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <arch/svinto.h> | 17 | #include <arch/svinto.h> |
18 | #include <linux/init.h> | 18 | #include <linux/init.h> |
19 | #include <arch/system.h> | 19 | #include <arch/system.h> |
20 | #include <linux/ptrace.h> | ||
20 | 21 | ||
21 | #ifdef CONFIG_ETRAX_GPIO | 22 | #ifdef CONFIG_ETRAX_GPIO |
22 | void etrax_gpio_wake_up_check(void); /* drivers/gpio.c */ | 23 | void etrax_gpio_wake_up_check(void); /* drivers/gpio.c */ |
@@ -81,31 +82,6 @@ unsigned long thread_saved_pc(struct task_struct *t) | |||
81 | return task_pt_regs(t)->irp; | 82 | return task_pt_regs(t)->irp; |
82 | } | 83 | } |
83 | 84 | ||
84 | static void kernel_thread_helper(void* dummy, int (*fn)(void *), void * arg) | ||
85 | { | ||
86 | fn(arg); | ||
87 | do_exit(-1); /* Should never be called, return bad exit value */ | ||
88 | } | ||
89 | |||
90 | /* | ||
91 | * Create a kernel thread | ||
92 | */ | ||
93 | int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | ||
94 | { | ||
95 | struct pt_regs regs; | ||
96 | |||
97 | memset(®s, 0, sizeof(regs)); | ||
98 | |||
99 | /* Don't use r10 since that is set to 0 in copy_thread */ | ||
100 | regs.r11 = (unsigned long)fn; | ||
101 | regs.r12 = (unsigned long)arg; | ||
102 | regs.irp = (unsigned long)kernel_thread_helper; | ||
103 | regs.dccr = 1 << I_DCCR_BITNR; | ||
104 | |||
105 | /* Ok, create the new process.. */ | ||
106 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); | ||
107 | } | ||
108 | |||
109 | /* setup the child's kernel stack with a pt_regs and switch_stack on it. | 85 | /* setup the child's kernel stack with a pt_regs and switch_stack on it. |
110 | * it will be un-nested during _resume and _ret_from_sys_call when the | 86 | * it will be un-nested during _resume and _ret_from_sys_call when the |
111 | * new thread is scheduled. | 87 | * new thread is scheduled. |
@@ -115,29 +91,34 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | |||
115 | * | 91 | * |
116 | */ | 92 | */ |
117 | asmlinkage void ret_from_fork(void); | 93 | asmlinkage void ret_from_fork(void); |
94 | asmlinkage void ret_from_kernel_thread(void); | ||
118 | 95 | ||
119 | int copy_thread(unsigned long clone_flags, unsigned long usp, | 96 | int copy_thread(unsigned long clone_flags, unsigned long usp, |
120 | unsigned long unused, | 97 | unsigned long arg, struct task_struct *p) |
121 | struct task_struct *p, struct pt_regs *regs) | ||
122 | { | 98 | { |
123 | struct pt_regs * childregs; | 99 | struct pt_regs *childregs = task_pt_regs(p); |
124 | struct switch_stack *swstack; | 100 | struct switch_stack *swstack = ((struct switch_stack *)childregs) - 1; |
125 | 101 | ||
126 | /* put the pt_regs structure at the end of the new kernel stack page and fix it up | 102 | /* put the pt_regs structure at the end of the new kernel stack page and fix it up |
127 | * remember that the task_struct doubles as the kernel stack for the task | 103 | * remember that the task_struct doubles as the kernel stack for the task |
128 | */ | 104 | */ |
129 | 105 | ||
130 | childregs = task_pt_regs(p); | 106 | if (unlikely(p->flags & PF_KTHREAD)) { |
131 | 107 | memset(swstack, 0, | |
132 | *childregs = *regs; /* struct copy of pt_regs */ | 108 | sizeof(struct switch_stack) + sizeof(struct pt_regs)); |
133 | 109 | swstack->r1 = usp; | |
134 | p->set_child_tid = p->clear_child_tid = NULL; | 110 | swstack->r2 = arg; |
111 | childregs->dccr = 1 << I_DCCR_BITNR; | ||
112 | swstack->return_ip = (unsigned long) ret_from_kernel_thread; | ||
113 | p->thread.ksp = (unsigned long) swstack; | ||
114 | p->thread.usp = 0; | ||
115 | return 0; | ||
116 | } | ||
117 | *childregs = *current_pt_regs(); /* struct copy of pt_regs */ | ||
135 | 118 | ||
136 | childregs->r10 = 0; /* child returns 0 after a fork/clone */ | 119 | childregs->r10 = 0; /* child returns 0 after a fork/clone */ |
137 | |||
138 | /* put the switch stack right below the pt_regs */ | ||
139 | 120 | ||
140 | swstack = ((struct switch_stack *)childregs) - 1; | 121 | /* put the switch stack right below the pt_regs */ |
141 | 122 | ||
142 | swstack->r9 = 0; /* parameter to ret_from_sys_call, 0 == dont restart the syscall */ | 123 | swstack->r9 = 0; /* parameter to ret_from_sys_call, 0 == dont restart the syscall */ |
143 | 124 | ||
@@ -147,7 +128,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
147 | 128 | ||
148 | /* fix the user-mode stackpointer */ | 129 | /* fix the user-mode stackpointer */ |
149 | 130 | ||
150 | p->thread.usp = usp; | 131 | p->thread.usp = usp ?: rdusp(); |
151 | 132 | ||
152 | /* and the kernel-mode one */ | 133 | /* and the kernel-mode one */ |
153 | 134 | ||
@@ -161,70 +142,6 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
161 | return 0; | 142 | return 0; |
162 | } | 143 | } |
163 | 144 | ||
164 | /* | ||
165 | * Be aware of the "magic" 7th argument in the four system-calls below. | ||
166 | * They need the latest stackframe, which is put as the 7th argument by | ||
167 | * entry.S. The previous arguments are dummies or actually used, but need | ||
168 | * to be defined to reach the 7th argument. | ||
169 | * | ||
170 | * N.B.: Another method to get the stackframe is to use current_regs(). But | ||
171 | * it returns the latest stack-frame stacked when going from _user mode_ and | ||
172 | * some of these (at least sys_clone) are called from kernel-mode sometimes | ||
173 | * (for example during kernel_thread, above) and thus cannot use it. Thus, | ||
174 | * to be sure not to get any surprises, we use the method for the other calls | ||
175 | * as well. | ||
176 | */ | ||
177 | |||
178 | asmlinkage int sys_fork(long r10, long r11, long r12, long r13, long mof, long srp, | ||
179 | struct pt_regs *regs) | ||
180 | { | ||
181 | return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL); | ||
182 | } | ||
183 | |||
184 | /* if newusp is 0, we just grab the old usp */ | ||
185 | /* FIXME: Is parent_tid/child_tid really third/fourth argument? Update lib? */ | ||
186 | asmlinkage int sys_clone(unsigned long newusp, unsigned long flags, | ||
187 | int* parent_tid, int* child_tid, long mof, long srp, | ||
188 | struct pt_regs *regs) | ||
189 | { | ||
190 | if (!newusp) | ||
191 | newusp = rdusp(); | ||
192 | return do_fork(flags, newusp, regs, 0, parent_tid, child_tid); | ||
193 | } | ||
194 | |||
195 | /* vfork is a system call in i386 because of register-pressure - maybe | ||
196 | * we can remove it and handle it in libc but we put it here until then. | ||
197 | */ | ||
198 | |||
199 | asmlinkage int sys_vfork(long r10, long r11, long r12, long r13, long mof, long srp, | ||
200 | struct pt_regs *regs) | ||
201 | { | ||
202 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL); | ||
203 | } | ||
204 | |||
205 | /* | ||
206 | * sys_execve() executes a new program. | ||
207 | */ | ||
208 | asmlinkage int sys_execve(const char *fname, | ||
209 | const char *const *argv, | ||
210 | const char *const *envp, | ||
211 | long r13, long mof, long srp, | ||
212 | struct pt_regs *regs) | ||
213 | { | ||
214 | int error; | ||
215 | struct filename *filename; | ||
216 | |||
217 | filename = getname(fname); | ||
218 | error = PTR_ERR(filename); | ||
219 | |||
220 | if (IS_ERR(filename)) | ||
221 | goto out; | ||
222 | error = do_execve(filename->name, argv, envp, regs); | ||
223 | putname(filename); | ||
224 | out: | ||
225 | return error; | ||
226 | } | ||
227 | |||
228 | unsigned long get_wchan(struct task_struct *p) | 145 | unsigned long get_wchan(struct task_struct *p) |
229 | { | 146 | { |
230 | #if 0 | 147 | #if 0 |