allow coexistance of N build and AC build.
[tomato.git] / release / src-rt-6.x / linux / linux-2.6 / arch / v850 / kernel / process.c
blobe4a4b8e7d5a3e3b664e99f9b4034c22b09c6204a
1 /*
2 * arch/v850/kernel/process.c -- Arch-dependent process handling
4 * Copyright (C) 2001,02,03 NEC Electronics Corporation
5 * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
7 * This file is subject to the terms and conditions of the GNU General
8 * Public License. See the file COPYING in the main directory of this
9 * archive for more details.
11 * Written by Miles Bader <miles@gnu.org>
14 #include <linux/errno.h>
15 #include <linux/sched.h>
16 #include <linux/kernel.h>
17 #include <linux/mm.h>
18 #include <linux/smp.h>
19 #include <linux/stddef.h>
20 #include <linux/unistd.h>
21 #include <linux/ptrace.h>
22 #include <linux/slab.h>
23 #include <linux/user.h>
24 #include <linux/a.out.h>
25 #include <linux/reboot.h>
27 #include <asm/uaccess.h>
28 #include <asm/system.h>
29 #include <asm/pgtable.h>
31 void (*pm_power_off)(void) = NULL;
32 EXPORT_SYMBOL(pm_power_off);
34 extern void ret_from_fork (void);
37 /* The idle loop. */
38 static void default_idle (void)
40 while (! need_resched ())
41 asm ("halt; nop; nop; nop; nop; nop" ::: "cc");
44 void (*idle)(void) = default_idle;
47 * The idle thread. There's no useful work to be
48 * done, so just try to conserve power and have a
49 * low exit latency (ie sit in a loop waiting for
50 * somebody to say that they'd like to reschedule)
52 void cpu_idle (void)
54 /* endless idle loop with no priority at all */
55 while (1) {
56 while (!need_resched())
57 (*idle) ();
59 preempt_enable_no_resched();
60 schedule();
61 preempt_disable();
66 * This is the mechanism for creating a new kernel thread.
68 * NOTE! Only a kernel-only process (ie the swapper or direct descendants who
69 * haven't done an "execve()") should use this: it will work within a system
70 * call from a "real" process, but the process memory space will not be free'd
71 * until both the parent and the child have exited.
73 int kernel_thread (int (*fn)(void *), void *arg, unsigned long flags)
75 register mm_segment_t fs = get_fs ();
76 register unsigned long syscall asm (SYSCALL_NUM);
77 register unsigned long arg0 asm (SYSCALL_ARG0);
78 register unsigned long ret asm (SYSCALL_RET);
80 set_fs (KERNEL_DS);
82 /* Clone this thread. Note that we don't pass the clone syscall's
83 second argument -- it's ignored for calls from kernel mode (the
84 child's SP is always set to the top of the kernel stack). */
85 arg0 = flags | CLONE_VM;
86 syscall = __NR_clone;
87 asm volatile ("trap " SYSCALL_SHORT_TRAP
88 : "=r" (ret), "=r" (syscall)
89 : "1" (syscall), "r" (arg0)
90 : SYSCALL_SHORT_CLOBBERS);
92 if (ret == 0) {
93 /* In child thread, call FN and exit. */
94 arg0 = (*fn) (arg);
95 syscall = __NR_exit;
96 asm volatile ("trap " SYSCALL_SHORT_TRAP
97 : "=r" (ret), "=r" (syscall)
98 : "1" (syscall), "r" (arg0)
99 : SYSCALL_SHORT_CLOBBERS);
102 /* In parent. */
103 set_fs (fs);
105 return ret;
108 void flush_thread (void)
110 set_fs (USER_DS);
113 int copy_thread (int nr, unsigned long clone_flags,
114 unsigned long stack_start, unsigned long stack_size,
115 struct task_struct *p, struct pt_regs *regs)
117 /* Start pushing stuff from the top of the child's kernel stack. */
118 unsigned long orig_ksp = task_tos(p);
119 unsigned long ksp = orig_ksp;
120 /* We push two `state save' stack fames (see entry.S) on the new
121 kernel stack:
122 1) The innermost one is what switch_thread would have
123 pushed, and is used when we context switch to the child
124 thread for the first time. It's set up to return to
125 ret_from_fork in entry.S.
126 2) The outermost one (nearest the top) is what a syscall
127 trap would have pushed, and is set up to return to the
128 same location as the parent thread, but with a return
129 value of 0. */
130 struct pt_regs *child_switch_regs, *child_trap_regs;
132 /* Trap frame. */
133 ksp -= STATE_SAVE_SIZE;
134 child_trap_regs = (struct pt_regs *)(ksp + STATE_SAVE_PT_OFFSET);
135 /* Switch frame. */
136 ksp -= STATE_SAVE_SIZE;
137 child_switch_regs = (struct pt_regs *)(ksp + STATE_SAVE_PT_OFFSET);
139 /* First copy parent's register state to child. */
140 *child_switch_regs = *regs;
141 *child_trap_regs = *regs;
143 /* switch_thread returns to the restored value of the lp
144 register (r31), so we make that the place where we want to
145 jump when the child thread begins running. */
146 child_switch_regs->gpr[GPR_LP] = (v850_reg_t)ret_from_fork;
148 if (regs->kernel_mode)
149 /* Since we're returning to kernel-mode, make sure the child's
150 stored kernel stack pointer agrees with what the actual
151 stack pointer will be at that point (the trap return code
152 always restores the SP, even when returning to
153 kernel-mode). */
154 child_trap_regs->gpr[GPR_SP] = orig_ksp;
155 else
156 /* Set the child's user-mode stack-pointer (the name
157 `stack_start' is a misnomer, it's just the initial SP
158 value). */
159 child_trap_regs->gpr[GPR_SP] = stack_start;
161 /* Thread state for the child (everything else is on the stack). */
162 p->thread.ksp = ksp;
164 return 0;
168 * sys_execve() executes a new program.
170 int sys_execve (char *name, char **argv, char **envp, struct pt_regs *regs)
172 char *filename = getname (name);
173 int error = PTR_ERR (filename);
175 if (! IS_ERR (filename)) {
176 error = do_execve (filename, argv, envp, regs);
177 putname (filename);
180 return error;
185 * These bracket the sleeping functions..
187 #define first_sched ((unsigned long)__sched_text_start)
188 #define last_sched ((unsigned long)__sched_text_end)
190 unsigned long get_wchan (struct task_struct *p)
192 #if 0 /* Barf. Figure out the stack-layout later. XXX */
193 unsigned long fp, pc;
194 int count = 0;
196 if (!p || p == current || p->state == TASK_RUNNING)
197 return 0;
199 pc = thread_saved_pc (p);
201 /* This quite disgusting function walks up the stack, following
202 saved return address, until it something that's out of bounds
203 (as defined by `first_sched' and `last_sched'). It then
204 returns the last PC that was in-bounds. */
205 do {
206 if (fp < stack_page + sizeof (struct task_struct) ||
207 fp >= 8184+stack_page)
208 return 0;
209 pc = ((unsigned long *)fp)[1];
210 if (pc < first_sched || pc >= last_sched)
211 return pc;
212 fp = *(unsigned long *) fp;
213 } while (count++ < 16);
214 #endif
216 return 0;