diff options
Diffstat (limited to 'arch/parisc/kernel/process.c')
-rw-r--r-- | arch/parisc/kernel/process.c | 142 |
1 files changed, 23 insertions, 119 deletions
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index cbc37216bf90..d13507246c5d 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c | |||
@@ -52,6 +52,7 @@ | |||
52 | 52 | ||
53 | #include <asm/io.h> | 53 | #include <asm/io.h> |
54 | #include <asm/asm-offsets.h> | 54 | #include <asm/asm-offsets.h> |
55 | #include <asm/assembly.h> | ||
55 | #include <asm/pdc.h> | 56 | #include <asm/pdc.h> |
56 | #include <asm/pdc_chassis.h> | 57 | #include <asm/pdc_chassis.h> |
57 | #include <asm/pgalloc.h> | 58 | #include <asm/pgalloc.h> |
@@ -165,23 +166,6 @@ void (*pm_power_off)(void) = machine_power_off; | |||
165 | EXPORT_SYMBOL(pm_power_off); | 166 | EXPORT_SYMBOL(pm_power_off); |
166 | 167 | ||
167 | /* | 168 | /* |
168 | * Create a kernel thread | ||
169 | */ | ||
170 | |||
171 | extern pid_t __kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); | ||
172 | pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | ||
173 | { | ||
174 | |||
175 | /* | ||
176 | * FIXME: Once we are sure we don't need any debug here, | ||
177 | * kernel_thread can become a #define. | ||
178 | */ | ||
179 | |||
180 | return __kernel_thread(fn, arg, flags); | ||
181 | } | ||
182 | EXPORT_SYMBOL(kernel_thread); | ||
183 | |||
184 | /* | ||
185 | * Free current thread data structures etc.. | 169 | * Free current thread data structures etc.. |
186 | */ | 170 | */ |
187 | void exit_thread(void) | 171 | void exit_thread(void) |
@@ -218,48 +202,11 @@ int dump_task_fpu (struct task_struct *tsk, elf_fpregset_t *r) | |||
218 | return 1; | 202 | return 1; |
219 | } | 203 | } |
220 | 204 | ||
221 | /* Note that "fork()" is implemented in terms of clone, with | ||
222 | parameters (SIGCHLD, regs->gr[30], regs). */ | ||
223 | int | ||
224 | sys_clone(unsigned long clone_flags, unsigned long usp, | ||
225 | struct pt_regs *regs) | ||
226 | { | ||
227 | /* Arugments from userspace are: | ||
228 | r26 = Clone flags. | ||
229 | r25 = Child stack. | ||
230 | r24 = parent_tidptr. | ||
231 | r23 = Is the TLS storage descriptor | ||
232 | r22 = child_tidptr | ||
233 | |||
234 | However, these last 3 args are only examined | ||
235 | if the proper flags are set. */ | ||
236 | int __user *parent_tidptr = (int __user *)regs->gr[24]; | ||
237 | int __user *child_tidptr = (int __user *)regs->gr[22]; | ||
238 | |||
239 | /* usp must be word aligned. This also prevents users from | ||
240 | * passing in the value 1 (which is the signal for a special | ||
241 | * return for a kernel thread) */ | ||
242 | usp = ALIGN(usp, 4); | ||
243 | |||
244 | /* A zero value for usp means use the current stack */ | ||
245 | if (usp == 0) | ||
246 | usp = regs->gr[30]; | ||
247 | |||
248 | return do_fork(clone_flags, usp, regs, 0, parent_tidptr, child_tidptr); | ||
249 | } | ||
250 | |||
251 | int | ||
252 | sys_vfork(struct pt_regs *regs) | ||
253 | { | ||
254 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gr[30], regs, 0, NULL, NULL); | ||
255 | } | ||
256 | |||
257 | int | 205 | int |
258 | copy_thread(unsigned long clone_flags, unsigned long usp, | 206 | copy_thread(unsigned long clone_flags, unsigned long usp, |
259 | unsigned long unused, /* in ia64 this is "user_stack_size" */ | 207 | unsigned long arg, struct task_struct *p) |
260 | struct task_struct * p, struct pt_regs * pregs) | ||
261 | { | 208 | { |
262 | struct pt_regs * cregs = &(p->thread.regs); | 209 | struct pt_regs *cregs = &(p->thread.regs); |
263 | void *stack = task_stack_page(p); | 210 | void *stack = task_stack_page(p); |
264 | 211 | ||
265 | /* We have to use void * instead of a function pointer, because | 212 | /* We have to use void * instead of a function pointer, because |
@@ -270,48 +217,39 @@ copy_thread(unsigned long clone_flags, unsigned long usp, | |||
270 | #ifdef CONFIG_HPUX | 217 | #ifdef CONFIG_HPUX |
271 | extern void * const hpux_child_return; | 218 | extern void * const hpux_child_return; |
272 | #endif | 219 | #endif |
220 | if (unlikely(p->flags & PF_KTHREAD)) { | ||
221 | memset(cregs, 0, sizeof(struct pt_regs)); | ||
222 | if (!usp) /* idle thread */ | ||
223 | return 0; | ||
273 | 224 | ||
274 | *cregs = *pregs; | ||
275 | |||
276 | /* Set the return value for the child. Note that this is not | ||
277 | actually restored by the syscall exit path, but we put it | ||
278 | here for consistency in case of signals. */ | ||
279 | cregs->gr[28] = 0; /* child */ | ||
280 | |||
281 | /* | ||
282 | * We need to differentiate between a user fork and a | ||
283 | * kernel fork. We can't use user_mode, because the | ||
284 | * the syscall path doesn't save iaoq. Right now | ||
285 | * We rely on the fact that kernel_thread passes | ||
286 | * in zero for usp. | ||
287 | */ | ||
288 | if (usp == 1) { | ||
289 | /* kernel thread */ | 225 | /* kernel thread */ |
290 | cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN; | ||
291 | /* Must exit via ret_from_kernel_thread in order | 226 | /* Must exit via ret_from_kernel_thread in order |
292 | * to call schedule_tail() | 227 | * to call schedule_tail() |
293 | */ | 228 | */ |
229 | cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN + FRAME_SIZE; | ||
294 | cregs->kpc = (unsigned long) &ret_from_kernel_thread; | 230 | cregs->kpc = (unsigned long) &ret_from_kernel_thread; |
295 | /* | 231 | /* |
296 | * Copy function and argument to be called from | 232 | * Copy function and argument to be called from |
297 | * ret_from_kernel_thread. | 233 | * ret_from_kernel_thread. |
298 | */ | 234 | */ |
299 | #ifdef CONFIG_64BIT | 235 | #ifdef CONFIG_64BIT |
300 | cregs->gr[27] = pregs->gr[27]; | 236 | cregs->gr[27] = ((unsigned long *)usp)[3]; |
237 | cregs->gr[26] = ((unsigned long *)usp)[2]; | ||
238 | #else | ||
239 | cregs->gr[26] = usp; | ||
301 | #endif | 240 | #endif |
302 | cregs->gr[26] = pregs->gr[26]; | 241 | cregs->gr[25] = arg; |
303 | cregs->gr[25] = pregs->gr[25]; | ||
304 | } else { | 242 | } else { |
305 | /* user thread */ | 243 | /* user thread */ |
306 | /* | 244 | /* usp must be word aligned. This also prevents users from |
307 | * Note that the fork wrappers are responsible | 245 | * passing in the value 1 (which is the signal for a special |
308 | * for setting gr[21]. | 246 | * return for a kernel thread) */ |
309 | */ | 247 | if (usp) { |
310 | 248 | usp = ALIGN(usp, 4); | |
311 | /* Use same stack depth as parent */ | 249 | if (likely(usp)) |
312 | cregs->ksp = (unsigned long)stack | 250 | cregs->gr[30] = usp; |
313 | + (pregs->gr[21] & (THREAD_SIZE - 1)); | 251 | } |
314 | cregs->gr[30] = usp; | 252 | cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN + FRAME_SIZE; |
315 | if (personality(p->personality) == PER_HPUX) { | 253 | if (personality(p->personality) == PER_HPUX) { |
316 | #ifdef CONFIG_HPUX | 254 | #ifdef CONFIG_HPUX |
317 | cregs->kpc = (unsigned long) &hpux_child_return; | 255 | cregs->kpc = (unsigned long) &hpux_child_return; |
@@ -323,8 +261,7 @@ copy_thread(unsigned long clone_flags, unsigned long usp, | |||
323 | } | 261 | } |
324 | /* Setup thread TLS area from the 4th parameter in clone */ | 262 | /* Setup thread TLS area from the 4th parameter in clone */ |
325 | if (clone_flags & CLONE_SETTLS) | 263 | if (clone_flags & CLONE_SETTLS) |
326 | cregs->cr27 = pregs->gr[23]; | 264 | cregs->cr27 = cregs->gr[23]; |
327 | |||
328 | } | 265 | } |
329 | 266 | ||
330 | return 0; | 267 | return 0; |
@@ -335,39 +272,6 @@ unsigned long thread_saved_pc(struct task_struct *t) | |||
335 | return t->thread.regs.kpc; | 272 | return t->thread.regs.kpc; |
336 | } | 273 | } |
337 | 274 | ||
338 | /* | ||
339 | * sys_execve() executes a new program. | ||
340 | */ | ||
341 | |||
342 | asmlinkage int sys_execve(struct pt_regs *regs) | ||
343 | { | ||
344 | int error; | ||
345 | struct filename *filename; | ||
346 | |||
347 | filename = getname((const char __user *) regs->gr[26]); | ||
348 | error = PTR_ERR(filename); | ||
349 | if (IS_ERR(filename)) | ||
350 | goto out; | ||
351 | error = do_execve(filename->name, | ||
352 | (const char __user *const __user *) regs->gr[25], | ||
353 | (const char __user *const __user *) regs->gr[24], | ||
354 | regs); | ||
355 | putname(filename); | ||
356 | out: | ||
357 | |||
358 | return error; | ||
359 | } | ||
360 | |||
361 | extern int __execve(const char *filename, | ||
362 | const char *const argv[], | ||
363 | const char *const envp[], struct task_struct *task); | ||
364 | int kernel_execve(const char *filename, | ||
365 | const char *const argv[], | ||
366 | const char *const envp[]) | ||
367 | { | ||
368 | return __execve(filename, argv, envp, current); | ||
369 | } | ||
370 | |||
371 | unsigned long | 275 | unsigned long |
372 | get_wchan(struct task_struct *p) | 276 | get_wchan(struct task_struct *p) |
373 | { | 277 | { |