xref: /openbmc/linux/arch/parisc/kernel/process.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1*1da177e4SLinus Torvalds /*
2*1da177e4SLinus Torvalds  *    PARISC Architecture-dependent parts of process handling
3*1da177e4SLinus Torvalds  *    based on the work for i386
4*1da177e4SLinus Torvalds  *
5*1da177e4SLinus Torvalds  *    Copyright (C) 1999-2003 Matthew Wilcox <willy at parisc-linux.org>
6*1da177e4SLinus Torvalds  *    Copyright (C) 2000 Martin K Petersen <mkp at mkp.net>
7*1da177e4SLinus Torvalds  *    Copyright (C) 2000 John Marvin <jsm at parisc-linux.org>
8*1da177e4SLinus Torvalds  *    Copyright (C) 2000 David Huggins-Daines <dhd with pobox.org>
9*1da177e4SLinus Torvalds  *    Copyright (C) 2000-2003 Paul Bame <bame at parisc-linux.org>
10*1da177e4SLinus Torvalds  *    Copyright (C) 2000 Philipp Rumpf <prumpf with tux.org>
11*1da177e4SLinus Torvalds  *    Copyright (C) 2000 David Kennedy <dkennedy with linuxcare.com>
12*1da177e4SLinus Torvalds  *    Copyright (C) 2000 Richard Hirst <rhirst with parisc-lixux.org>
13*1da177e4SLinus Torvalds  *    Copyright (C) 2000 Grant Grundler <grundler with parisc-linux.org>
14*1da177e4SLinus Torvalds  *    Copyright (C) 2001 Alan Modra <amodra at parisc-linux.org>
15*1da177e4SLinus Torvalds  *    Copyright (C) 2001-2002 Ryan Bradetich <rbrad at parisc-linux.org>
16*1da177e4SLinus Torvalds  *    Copyright (C) 2001-2002 Helge Deller <deller at parisc-linux.org>
17*1da177e4SLinus Torvalds  *    Copyright (C) 2002 Randolph Chung <tausq with parisc-linux.org>
18*1da177e4SLinus Torvalds  *
19*1da177e4SLinus Torvalds  *
20*1da177e4SLinus Torvalds  *    This program is free software; you can redistribute it and/or modify
21*1da177e4SLinus Torvalds  *    it under the terms of the GNU General Public License as published by
22*1da177e4SLinus Torvalds  *    the Free Software Foundation; either version 2 of the License, or
23*1da177e4SLinus Torvalds  *    (at your option) any later version.
24*1da177e4SLinus Torvalds  *
25*1da177e4SLinus Torvalds  *    This program is distributed in the hope that it will be useful,
26*1da177e4SLinus Torvalds  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
27*1da177e4SLinus Torvalds  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28*1da177e4SLinus Torvalds  *    GNU General Public License for more details.
29*1da177e4SLinus Torvalds  *
30*1da177e4SLinus Torvalds  *    You should have received a copy of the GNU General Public License
31*1da177e4SLinus Torvalds  *    along with this program; if not, write to the Free Software
32*1da177e4SLinus Torvalds  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
33*1da177e4SLinus Torvalds  */
34*1da177e4SLinus Torvalds 
35*1da177e4SLinus Torvalds #include <stdarg.h>
36*1da177e4SLinus Torvalds 
37*1da177e4SLinus Torvalds #include <linux/elf.h>
38*1da177e4SLinus Torvalds #include <linux/errno.h>
39*1da177e4SLinus Torvalds #include <linux/kernel.h>
40*1da177e4SLinus Torvalds #include <linux/mm.h>
41*1da177e4SLinus Torvalds #include <linux/module.h>
42*1da177e4SLinus Torvalds #include <linux/personality.h>
43*1da177e4SLinus Torvalds #include <linux/ptrace.h>
44*1da177e4SLinus Torvalds #include <linux/sched.h>
45*1da177e4SLinus Torvalds #include <linux/stddef.h>
46*1da177e4SLinus Torvalds #include <linux/unistd.h>
47*1da177e4SLinus Torvalds #include <linux/kallsyms.h>
48*1da177e4SLinus Torvalds 
49*1da177e4SLinus Torvalds #include <asm/io.h>
50*1da177e4SLinus Torvalds #include <asm/offsets.h>
51*1da177e4SLinus Torvalds #include <asm/pdc.h>
52*1da177e4SLinus Torvalds #include <asm/pdc_chassis.h>
53*1da177e4SLinus Torvalds #include <asm/pgalloc.h>
54*1da177e4SLinus Torvalds #include <asm/uaccess.h>
55*1da177e4SLinus Torvalds #include <asm/unwind.h>
56*1da177e4SLinus Torvalds 
57*1da177e4SLinus Torvalds static int hlt_counter;
58*1da177e4SLinus Torvalds 
59*1da177e4SLinus Torvalds /*
60*1da177e4SLinus Torvalds  * Power off function, if any
61*1da177e4SLinus Torvalds  */
62*1da177e4SLinus Torvalds void (*pm_power_off)(void);
63*1da177e4SLinus Torvalds 
64*1da177e4SLinus Torvalds void disable_hlt(void)
65*1da177e4SLinus Torvalds {
66*1da177e4SLinus Torvalds 	hlt_counter++;
67*1da177e4SLinus Torvalds }
68*1da177e4SLinus Torvalds 
69*1da177e4SLinus Torvalds EXPORT_SYMBOL(disable_hlt);
70*1da177e4SLinus Torvalds 
71*1da177e4SLinus Torvalds void enable_hlt(void)
72*1da177e4SLinus Torvalds {
73*1da177e4SLinus Torvalds 	hlt_counter--;
74*1da177e4SLinus Torvalds }
75*1da177e4SLinus Torvalds 
76*1da177e4SLinus Torvalds EXPORT_SYMBOL(enable_hlt);
77*1da177e4SLinus Torvalds 
78*1da177e4SLinus Torvalds void default_idle(void)
79*1da177e4SLinus Torvalds {
80*1da177e4SLinus Torvalds 	barrier();
81*1da177e4SLinus Torvalds }
82*1da177e4SLinus Torvalds 
83*1da177e4SLinus Torvalds /*
84*1da177e4SLinus Torvalds  * The idle thread. There's no useful work to be
85*1da177e4SLinus Torvalds  * done, so just try to conserve power and have a
86*1da177e4SLinus Torvalds  * low exit latency (ie sit in a loop waiting for
87*1da177e4SLinus Torvalds  * somebody to say that they'd like to reschedule)
88*1da177e4SLinus Torvalds  */
89*1da177e4SLinus Torvalds void cpu_idle(void)
90*1da177e4SLinus Torvalds {
91*1da177e4SLinus Torvalds 	/* endless idle loop with no priority at all */
92*1da177e4SLinus Torvalds 	while (1) {
93*1da177e4SLinus Torvalds 		while (!need_resched())
94*1da177e4SLinus Torvalds 			barrier();
95*1da177e4SLinus Torvalds 		schedule();
96*1da177e4SLinus Torvalds 		check_pgt_cache();
97*1da177e4SLinus Torvalds 	}
98*1da177e4SLinus Torvalds }
99*1da177e4SLinus Torvalds 
100*1da177e4SLinus Torvalds 
101*1da177e4SLinus Torvalds #ifdef __LP64__
102*1da177e4SLinus Torvalds #define COMMAND_GLOBAL  0xfffffffffffe0030UL
103*1da177e4SLinus Torvalds #else
104*1da177e4SLinus Torvalds #define COMMAND_GLOBAL  0xfffe0030
105*1da177e4SLinus Torvalds #endif
106*1da177e4SLinus Torvalds 
107*1da177e4SLinus Torvalds #define CMD_RESET       5       /* reset any module */
108*1da177e4SLinus Torvalds 
109*1da177e4SLinus Torvalds /*
110*1da177e4SLinus Torvalds ** The Wright Brothers and Gecko systems have a H/W problem
111*1da177e4SLinus Torvalds ** (Lasi...'nuf said) may cause a broadcast reset to lockup
112*1da177e4SLinus Torvalds ** the system. An HVERSION dependent PDC call was developed
113*1da177e4SLinus Torvalds ** to perform a "safe", platform specific broadcast reset instead
114*1da177e4SLinus Torvalds ** of kludging up all the code.
115*1da177e4SLinus Torvalds **
116*1da177e4SLinus Torvalds ** Older machines which do not implement PDC_BROADCAST_RESET will
117*1da177e4SLinus Torvalds ** return (with an error) and the regular broadcast reset can be
118*1da177e4SLinus Torvalds ** issued. Obviously, if the PDC does implement PDC_BROADCAST_RESET
119*1da177e4SLinus Torvalds ** the PDC call will not return (the system will be reset).
120*1da177e4SLinus Torvalds */
121*1da177e4SLinus Torvalds void machine_restart(char *cmd)
122*1da177e4SLinus Torvalds {
123*1da177e4SLinus Torvalds #ifdef FASTBOOT_SELFTEST_SUPPORT
124*1da177e4SLinus Torvalds 	/*
125*1da177e4SLinus Torvalds 	 ** If user has modified the Firmware Selftest Bitmap,
126*1da177e4SLinus Torvalds 	 ** run the tests specified in the bitmap after the
127*1da177e4SLinus Torvalds 	 ** system is rebooted w/PDC_DO_RESET.
128*1da177e4SLinus Torvalds 	 **
129*1da177e4SLinus Torvalds 	 ** ftc_bitmap = 0x1AUL "Skip destructive memory tests"
130*1da177e4SLinus Torvalds 	 **
131*1da177e4SLinus Torvalds 	 ** Using "directed resets" at each processor with the MEM_TOC
132*1da177e4SLinus Torvalds 	 ** vector cleared will also avoid running destructive
133*1da177e4SLinus Torvalds 	 ** memory self tests. (Not implemented yet)
134*1da177e4SLinus Torvalds 	 */
135*1da177e4SLinus Torvalds 	if (ftc_bitmap) {
136*1da177e4SLinus Torvalds 		pdc_do_firm_test_reset(ftc_bitmap);
137*1da177e4SLinus Torvalds 	}
138*1da177e4SLinus Torvalds #endif
139*1da177e4SLinus Torvalds 	/* set up a new led state on systems shipped with a LED State panel */
140*1da177e4SLinus Torvalds 	pdc_chassis_send_status(PDC_CHASSIS_DIRECT_SHUTDOWN);
141*1da177e4SLinus Torvalds 
142*1da177e4SLinus Torvalds 	/* "Normal" system reset */
143*1da177e4SLinus Torvalds 	pdc_do_reset();
144*1da177e4SLinus Torvalds 
145*1da177e4SLinus Torvalds 	/* Nope...box should reset with just CMD_RESET now */
146*1da177e4SLinus Torvalds 	gsc_writel(CMD_RESET, COMMAND_GLOBAL);
147*1da177e4SLinus Torvalds 
148*1da177e4SLinus Torvalds 	/* Wait for RESET to lay us to rest. */
149*1da177e4SLinus Torvalds 	while (1) ;
150*1da177e4SLinus Torvalds 
151*1da177e4SLinus Torvalds }
152*1da177e4SLinus Torvalds 
153*1da177e4SLinus Torvalds EXPORT_SYMBOL(machine_restart);
154*1da177e4SLinus Torvalds 
155*1da177e4SLinus Torvalds void machine_halt(void)
156*1da177e4SLinus Torvalds {
157*1da177e4SLinus Torvalds 	/*
158*1da177e4SLinus Torvalds 	** The LED/ChassisCodes are updated by the led_halt()
159*1da177e4SLinus Torvalds 	** function, called by the reboot notifier chain.
160*1da177e4SLinus Torvalds 	*/
161*1da177e4SLinus Torvalds }
162*1da177e4SLinus Torvalds 
163*1da177e4SLinus Torvalds EXPORT_SYMBOL(machine_halt);
164*1da177e4SLinus Torvalds 
165*1da177e4SLinus Torvalds 
166*1da177e4SLinus Torvalds /*
167*1da177e4SLinus Torvalds  * This routine is called from sys_reboot to actually turn off the
168*1da177e4SLinus Torvalds  * machine
169*1da177e4SLinus Torvalds  */
170*1da177e4SLinus Torvalds void machine_power_off(void)
171*1da177e4SLinus Torvalds {
172*1da177e4SLinus Torvalds 	/* If there is a registered power off handler, call it. */
173*1da177e4SLinus Torvalds 	if(pm_power_off)
174*1da177e4SLinus Torvalds 		pm_power_off();
175*1da177e4SLinus Torvalds 
176*1da177e4SLinus Torvalds 	/* Put the soft power button back under hardware control.
177*1da177e4SLinus Torvalds 	 * If the user had already pressed the power button, the
178*1da177e4SLinus Torvalds 	 * following call will immediately power off. */
179*1da177e4SLinus Torvalds 	pdc_soft_power_button(0);
180*1da177e4SLinus Torvalds 
181*1da177e4SLinus Torvalds 	pdc_chassis_send_status(PDC_CHASSIS_DIRECT_SHUTDOWN);
182*1da177e4SLinus Torvalds 
183*1da177e4SLinus Torvalds 	/* It seems we have no way to power the system off via
184*1da177e4SLinus Torvalds 	 * software. The user has to press the button himself. */
185*1da177e4SLinus Torvalds 
186*1da177e4SLinus Torvalds 	printk(KERN_EMERG "System shut down completed.\n"
187*1da177e4SLinus Torvalds 	       KERN_EMERG "Please power this system off now.");
188*1da177e4SLinus Torvalds }
189*1da177e4SLinus Torvalds 
190*1da177e4SLinus Torvalds EXPORT_SYMBOL(machine_power_off);
191*1da177e4SLinus Torvalds 
192*1da177e4SLinus Torvalds 
193*1da177e4SLinus Torvalds /*
194*1da177e4SLinus Torvalds  * Create a kernel thread
195*1da177e4SLinus Torvalds  */
196*1da177e4SLinus Torvalds 
197*1da177e4SLinus Torvalds extern pid_t __kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
198*1da177e4SLinus Torvalds pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
199*1da177e4SLinus Torvalds {
200*1da177e4SLinus Torvalds 
201*1da177e4SLinus Torvalds 	/*
202*1da177e4SLinus Torvalds 	 * FIXME: Once we are sure we don't need any debug here,
203*1da177e4SLinus Torvalds 	 *	  kernel_thread can become a #define.
204*1da177e4SLinus Torvalds 	 */
205*1da177e4SLinus Torvalds 
206*1da177e4SLinus Torvalds 	return __kernel_thread(fn, arg, flags);
207*1da177e4SLinus Torvalds }
208*1da177e4SLinus Torvalds EXPORT_SYMBOL(kernel_thread);
209*1da177e4SLinus Torvalds 
210*1da177e4SLinus Torvalds /*
211*1da177e4SLinus Torvalds  * Free current thread data structures etc..
212*1da177e4SLinus Torvalds  */
213*1da177e4SLinus Torvalds void exit_thread(void)
214*1da177e4SLinus Torvalds {
215*1da177e4SLinus Torvalds }
216*1da177e4SLinus Torvalds 
217*1da177e4SLinus Torvalds void flush_thread(void)
218*1da177e4SLinus Torvalds {
219*1da177e4SLinus Torvalds 	/* Only needs to handle fpu stuff or perf monitors.
220*1da177e4SLinus Torvalds 	** REVISIT: several arches implement a "lazy fpu state".
221*1da177e4SLinus Torvalds 	*/
222*1da177e4SLinus Torvalds 	set_fs(USER_DS);
223*1da177e4SLinus Torvalds }
224*1da177e4SLinus Torvalds 
225*1da177e4SLinus Torvalds void release_thread(struct task_struct *dead_task)
226*1da177e4SLinus Torvalds {
227*1da177e4SLinus Torvalds }
228*1da177e4SLinus Torvalds 
229*1da177e4SLinus Torvalds /*
230*1da177e4SLinus Torvalds  * Fill in the FPU structure for a core dump.
231*1da177e4SLinus Torvalds  */
232*1da177e4SLinus Torvalds 
233*1da177e4SLinus Torvalds int dump_fpu (struct pt_regs * regs, elf_fpregset_t *r)
234*1da177e4SLinus Torvalds {
235*1da177e4SLinus Torvalds 	if (regs == NULL)
236*1da177e4SLinus Torvalds 		return 0;
237*1da177e4SLinus Torvalds 
238*1da177e4SLinus Torvalds 	memcpy(r, regs->fr, sizeof *r);
239*1da177e4SLinus Torvalds 	return 1;
240*1da177e4SLinus Torvalds }
241*1da177e4SLinus Torvalds 
242*1da177e4SLinus Torvalds int dump_task_fpu (struct task_struct *tsk, elf_fpregset_t *r)
243*1da177e4SLinus Torvalds {
244*1da177e4SLinus Torvalds 	memcpy(r, tsk->thread.regs.fr, sizeof(*r));
245*1da177e4SLinus Torvalds 	return 1;
246*1da177e4SLinus Torvalds }
247*1da177e4SLinus Torvalds 
248*1da177e4SLinus Torvalds /* Note that "fork()" is implemented in terms of clone, with
249*1da177e4SLinus Torvalds    parameters (SIGCHLD, regs->gr[30], regs). */
250*1da177e4SLinus Torvalds int
251*1da177e4SLinus Torvalds sys_clone(unsigned long clone_flags, unsigned long usp,
252*1da177e4SLinus Torvalds 	  struct pt_regs *regs)
253*1da177e4SLinus Torvalds {
254*1da177e4SLinus Torvalds 	int __user *user_tid = (int __user *)regs->gr[26];
255*1da177e4SLinus Torvalds 
256*1da177e4SLinus Torvalds 	/* usp must be word aligned.  This also prevents users from
257*1da177e4SLinus Torvalds 	 * passing in the value 1 (which is the signal for a special
258*1da177e4SLinus Torvalds 	 * return for a kernel thread) */
259*1da177e4SLinus Torvalds 	usp = ALIGN(usp, 4);
260*1da177e4SLinus Torvalds 
261*1da177e4SLinus Torvalds 	/* A zero value for usp means use the current stack */
262*1da177e4SLinus Torvalds 	if(usp == 0)
263*1da177e4SLinus Torvalds 		usp = regs->gr[30];
264*1da177e4SLinus Torvalds 
265*1da177e4SLinus Torvalds 	return do_fork(clone_flags, usp, regs, 0, user_tid, NULL);
266*1da177e4SLinus Torvalds }
267*1da177e4SLinus Torvalds 
268*1da177e4SLinus Torvalds int
269*1da177e4SLinus Torvalds sys_vfork(struct pt_regs *regs)
270*1da177e4SLinus Torvalds {
271*1da177e4SLinus Torvalds 	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gr[30], regs, 0, NULL, NULL);
272*1da177e4SLinus Torvalds }
273*1da177e4SLinus Torvalds 
274*1da177e4SLinus Torvalds int
275*1da177e4SLinus Torvalds copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
276*1da177e4SLinus Torvalds 	    unsigned long unused,	/* in ia64 this is "user_stack_size" */
277*1da177e4SLinus Torvalds 	    struct task_struct * p, struct pt_regs * pregs)
278*1da177e4SLinus Torvalds {
279*1da177e4SLinus Torvalds 	struct pt_regs * cregs = &(p->thread.regs);
280*1da177e4SLinus Torvalds 	struct thread_info *ti = p->thread_info;
281*1da177e4SLinus Torvalds 
282*1da177e4SLinus Torvalds 	/* We have to use void * instead of a function pointer, because
283*1da177e4SLinus Torvalds 	 * function pointers aren't a pointer to the function on 64-bit.
284*1da177e4SLinus Torvalds 	 * Make them const so the compiler knows they live in .text */
285*1da177e4SLinus Torvalds 	extern void * const ret_from_kernel_thread;
286*1da177e4SLinus Torvalds 	extern void * const child_return;
287*1da177e4SLinus Torvalds #ifdef CONFIG_HPUX
288*1da177e4SLinus Torvalds 	extern void * const hpux_child_return;
289*1da177e4SLinus Torvalds #endif
290*1da177e4SLinus Torvalds 
291*1da177e4SLinus Torvalds 	*cregs = *pregs;
292*1da177e4SLinus Torvalds 
293*1da177e4SLinus Torvalds 	/* Set the return value for the child.  Note that this is not
294*1da177e4SLinus Torvalds            actually restored by the syscall exit path, but we put it
295*1da177e4SLinus Torvalds            here for consistency in case of signals. */
296*1da177e4SLinus Torvalds 	cregs->gr[28] = 0; /* child */
297*1da177e4SLinus Torvalds 
298*1da177e4SLinus Torvalds 	/*
299*1da177e4SLinus Torvalds 	 * We need to differentiate between a user fork and a
300*1da177e4SLinus Torvalds 	 * kernel fork. We can't use user_mode, because the
301*1da177e4SLinus Torvalds 	 * the syscall path doesn't save iaoq. Right now
302*1da177e4SLinus Torvalds 	 * We rely on the fact that kernel_thread passes
303*1da177e4SLinus Torvalds 	 * in zero for usp.
304*1da177e4SLinus Torvalds 	 */
305*1da177e4SLinus Torvalds 	if (usp == 1) {
306*1da177e4SLinus Torvalds 		/* kernel thread */
307*1da177e4SLinus Torvalds 		cregs->ksp = (((unsigned long)(ti)) + THREAD_SZ_ALGN);
308*1da177e4SLinus Torvalds 		/* Must exit via ret_from_kernel_thread in order
309*1da177e4SLinus Torvalds 		 * to call schedule_tail()
310*1da177e4SLinus Torvalds 		 */
311*1da177e4SLinus Torvalds 		cregs->kpc = (unsigned long) &ret_from_kernel_thread;
312*1da177e4SLinus Torvalds 		/*
313*1da177e4SLinus Torvalds 		 * Copy function and argument to be called from
314*1da177e4SLinus Torvalds 		 * ret_from_kernel_thread.
315*1da177e4SLinus Torvalds 		 */
316*1da177e4SLinus Torvalds #ifdef __LP64__
317*1da177e4SLinus Torvalds 		cregs->gr[27] = pregs->gr[27];
318*1da177e4SLinus Torvalds #endif
319*1da177e4SLinus Torvalds 		cregs->gr[26] = pregs->gr[26];
320*1da177e4SLinus Torvalds 		cregs->gr[25] = pregs->gr[25];
321*1da177e4SLinus Torvalds 	} else {
322*1da177e4SLinus Torvalds 		/* user thread */
323*1da177e4SLinus Torvalds 		/*
324*1da177e4SLinus Torvalds 		 * Note that the fork wrappers are responsible
325*1da177e4SLinus Torvalds 		 * for setting gr[21].
326*1da177e4SLinus Torvalds 		 */
327*1da177e4SLinus Torvalds 
328*1da177e4SLinus Torvalds 		/* Use same stack depth as parent */
329*1da177e4SLinus Torvalds 		cregs->ksp = ((unsigned long)(ti))
330*1da177e4SLinus Torvalds 			+ (pregs->gr[21] & (THREAD_SIZE - 1));
331*1da177e4SLinus Torvalds 		cregs->gr[30] = usp;
332*1da177e4SLinus Torvalds 		if (p->personality == PER_HPUX) {
333*1da177e4SLinus Torvalds #ifdef CONFIG_HPUX
334*1da177e4SLinus Torvalds 			cregs->kpc = (unsigned long) &hpux_child_return;
335*1da177e4SLinus Torvalds #else
336*1da177e4SLinus Torvalds 			BUG();
337*1da177e4SLinus Torvalds #endif
338*1da177e4SLinus Torvalds 		} else {
339*1da177e4SLinus Torvalds 			cregs->kpc = (unsigned long) &child_return;
340*1da177e4SLinus Torvalds 		}
341*1da177e4SLinus Torvalds 	}
342*1da177e4SLinus Torvalds 
343*1da177e4SLinus Torvalds 	return 0;
344*1da177e4SLinus Torvalds }
345*1da177e4SLinus Torvalds 
346*1da177e4SLinus Torvalds unsigned long thread_saved_pc(struct task_struct *t)
347*1da177e4SLinus Torvalds {
348*1da177e4SLinus Torvalds 	return t->thread.regs.kpc;
349*1da177e4SLinus Torvalds }
350*1da177e4SLinus Torvalds 
351*1da177e4SLinus Torvalds /*
352*1da177e4SLinus Torvalds  * sys_execve() executes a new program.
353*1da177e4SLinus Torvalds  */
354*1da177e4SLinus Torvalds 
355*1da177e4SLinus Torvalds asmlinkage int sys_execve(struct pt_regs *regs)
356*1da177e4SLinus Torvalds {
357*1da177e4SLinus Torvalds 	int error;
358*1da177e4SLinus Torvalds 	char *filename;
359*1da177e4SLinus Torvalds 
360*1da177e4SLinus Torvalds 	filename = getname((const char __user *) regs->gr[26]);
361*1da177e4SLinus Torvalds 	error = PTR_ERR(filename);
362*1da177e4SLinus Torvalds 	if (IS_ERR(filename))
363*1da177e4SLinus Torvalds 		goto out;
364*1da177e4SLinus Torvalds 	error = do_execve(filename, (char __user **) regs->gr[25],
365*1da177e4SLinus Torvalds 		(char __user **) regs->gr[24], regs);
366*1da177e4SLinus Torvalds 	if (error == 0) {
367*1da177e4SLinus Torvalds 		task_lock(current);
368*1da177e4SLinus Torvalds 		current->ptrace &= ~PT_DTRACE;
369*1da177e4SLinus Torvalds 		task_unlock(current);
370*1da177e4SLinus Torvalds 	}
371*1da177e4SLinus Torvalds 	putname(filename);
372*1da177e4SLinus Torvalds out:
373*1da177e4SLinus Torvalds 
374*1da177e4SLinus Torvalds 	return error;
375*1da177e4SLinus Torvalds }
376*1da177e4SLinus Torvalds 
377*1da177e4SLinus Torvalds unsigned long
378*1da177e4SLinus Torvalds get_wchan(struct task_struct *p)
379*1da177e4SLinus Torvalds {
380*1da177e4SLinus Torvalds 	struct unwind_frame_info info;
381*1da177e4SLinus Torvalds 	unsigned long ip;
382*1da177e4SLinus Torvalds 	int count = 0;
383*1da177e4SLinus Torvalds 	/*
384*1da177e4SLinus Torvalds 	 * These bracket the sleeping functions..
385*1da177e4SLinus Torvalds 	 */
386*1da177e4SLinus Torvalds 
387*1da177e4SLinus Torvalds 	unwind_frame_init_from_blocked_task(&info, p);
388*1da177e4SLinus Torvalds 	do {
389*1da177e4SLinus Torvalds 		if (unwind_once(&info) < 0)
390*1da177e4SLinus Torvalds 			return 0;
391*1da177e4SLinus Torvalds 		ip = info.ip;
392*1da177e4SLinus Torvalds 		if (!in_sched_functions(ip))
393*1da177e4SLinus Torvalds 			return ip;
394*1da177e4SLinus Torvalds 	} while (count++ < 16);
395*1da177e4SLinus Torvalds 	return 0;
396*1da177e4SLinus Torvalds }
397