blob: 39cf247cdae4ef4dcbe4d4fa3563432a520f1531 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * arch/v850/kernel/process.c -- Arch-dependent process handling
3 *
4 * Copyright (C) 2001,02,03 NEC Electronics Corporation
5 * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
6 *
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.
10 *
11 * Written by Miles Bader <miles@gnu.org>
12 */
13
14#include <linux/config.h>
15#include <linux/errno.h>
16#include <linux/sched.h>
17#include <linux/kernel.h>
18#include <linux/mm.h>
19#include <linux/smp.h>
20#include <linux/smp_lock.h>
21#include <linux/stddef.h>
22#include <linux/unistd.h>
23#include <linux/ptrace.h>
24#include <linux/slab.h>
25#include <linux/user.h>
26#include <linux/a.out.h>
27#include <linux/reboot.h>
28
29#include <asm/uaccess.h>
30#include <asm/system.h>
31#include <asm/pgtable.h>
32
33extern void ret_from_fork (void);
34
35
36/* The idle loop. */
37void default_idle (void)
38{
Nick Piggin5bfb5d62005-11-08 21:39:01 -080039 while (! need_resched ())
40 asm ("halt; nop; nop; nop; nop; nop" ::: "cc");
Linus Torvalds1da177e2005-04-16 15:20:36 -070041}
42
43void (*idle)(void) = default_idle;
44
45/*
46 * The idle thread. There's no useful work to be
47 * done, so just try to conserve power and have a
48 * low exit latency (ie sit in a loop waiting for
49 * somebody to say that they'd like to reschedule)
50 */
51void cpu_idle (void)
52{
53 /* endless idle loop with no priority at all */
Nick Piggin5bfb5d62005-11-08 21:39:01 -080054 while (1) {
55 while (!need_resched())
56 (*idle) ();
57
58 preempt_enable_no_resched();
59 schedule();
60 preempt_disable();
61 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070062}
63
64/*
65 * This is the mechanism for creating a new kernel thread.
66 *
67 * NOTE! Only a kernel-only process (ie the swapper or direct descendants who
68 * haven't done an "execve()") should use this: it will work within a system
69 * call from a "real" process, but the process memory space will not be free'd
70 * until both the parent and the child have exited.
71 */
72int kernel_thread (int (*fn)(void *), void *arg, unsigned long flags)
73{
74 register mm_segment_t fs = get_fs ();
75 register unsigned long syscall asm (SYSCALL_NUM);
76 register unsigned long arg0 asm (SYSCALL_ARG0);
77 register unsigned long ret asm (SYSCALL_RET);
78
79 set_fs (KERNEL_DS);
80
81 /* Clone this thread. Note that we don't pass the clone syscall's
82 second argument -- it's ignored for calls from kernel mode (the
83 child's SP is always set to the top of the kernel stack). */
84 arg0 = flags | CLONE_VM;
85 syscall = __NR_clone;
86 asm volatile ("trap " SYSCALL_SHORT_TRAP
87 : "=r" (ret), "=r" (syscall)
88 : "1" (syscall), "r" (arg0)
89 : SYSCALL_SHORT_CLOBBERS);
90
91 if (ret == 0) {
92 /* In child thread, call FN and exit. */
93 arg0 = (*fn) (arg);
94 syscall = __NR_exit;
95 asm volatile ("trap " SYSCALL_SHORT_TRAP
96 : "=r" (ret), "=r" (syscall)
97 : "1" (syscall), "r" (arg0)
98 : SYSCALL_SHORT_CLOBBERS);
99 }
100
101 /* In parent. */
102 set_fs (fs);
103
104 return ret;
105}
106
107void flush_thread (void)
108{
109 set_fs (USER_DS);
110}
111
112int copy_thread (int nr, unsigned long clone_flags,
113 unsigned long stack_start, unsigned long stack_size,
114 struct task_struct *p, struct pt_regs *regs)
115{
116 /* Start pushing stuff from the top of the child's kernel stack. */
117 unsigned long orig_ksp = (unsigned long)p->thread_info + THREAD_SIZE;
118 unsigned long ksp = orig_ksp;
119 /* We push two `state save' stack fames (see entry.S) on the new
120 kernel stack:
121 1) The innermost one is what switch_thread would have
122 pushed, and is used when we context switch to the child
123 thread for the first time. It's set up to return to
124 ret_from_fork in entry.S.
125 2) The outermost one (nearest the top) is what a syscall
126 trap would have pushed, and is set up to return to the
127 same location as the parent thread, but with a return
128 value of 0. */
129 struct pt_regs *child_switch_regs, *child_trap_regs;
130
131 /* Trap frame. */
132 ksp -= STATE_SAVE_SIZE;
133 child_trap_regs = (struct pt_regs *)(ksp + STATE_SAVE_PT_OFFSET);
134 /* Switch frame. */
135 ksp -= STATE_SAVE_SIZE;
136 child_switch_regs = (struct pt_regs *)(ksp + STATE_SAVE_PT_OFFSET);
137
138 /* First copy parent's register state to child. */
139 *child_switch_regs = *regs;
140 *child_trap_regs = *regs;
141
142 /* switch_thread returns to the restored value of the lp
143 register (r31), so we make that the place where we want to
144 jump when the child thread begins running. */
145 child_switch_regs->gpr[GPR_LP] = (v850_reg_t)ret_from_fork;
146
147 if (regs->kernel_mode)
148 /* Since we're returning to kernel-mode, make sure the child's
149 stored kernel stack pointer agrees with what the actual
150 stack pointer will be at that point (the trap return code
151 always restores the SP, even when returning to
152 kernel-mode). */
153 child_trap_regs->gpr[GPR_SP] = orig_ksp;
154 else
155 /* Set the child's user-mode stack-pointer (the name
156 `stack_start' is a misnomer, it's just the initial SP
157 value). */
158 child_trap_regs->gpr[GPR_SP] = stack_start;
159
160 /* Thread state for the child (everything else is on the stack). */
161 p->thread.ksp = ksp;
162
163 return 0;
164}
165
166/*
167 * fill in the user structure for a core dump..
168 */
169void dump_thread (struct pt_regs *regs, struct user *dump)
170{
171#if 0 /* Later. XXX */
172 dump->magic = CMAGIC;
173 dump->start_code = 0;
174 dump->start_stack = regs->gpr[GPR_SP];
175 dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT;
176 dump->u_dsize = ((unsigned long) (current->mm->brk +
177 (PAGE_SIZE-1))) >> PAGE_SHIFT;
178 dump->u_dsize -= dump->u_tsize;
179 dump->u_ssize = 0;
180
181 if (dump->start_stack < TASK_SIZE)
182 dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT;
183
184 dump->u_ar0 = (struct user_regs_struct *)((int)&dump->regs - (int)dump);
185 dump->regs = *regs;
186 dump->u_fpvalid = 0;
187#endif
188}
189
190/*
191 * sys_execve() executes a new program.
192 */
193int sys_execve (char *name, char **argv, char **envp, struct pt_regs *regs)
194{
195 char *filename = getname (name);
196 int error = PTR_ERR (filename);
197
198 if (! IS_ERR (filename)) {
199 error = do_execve (filename, argv, envp, regs);
200 putname (filename);
201 }
202
203 return error;
204}
205
206
207/*
208 * These bracket the sleeping functions..
209 */
210#define first_sched ((unsigned long)__sched_text_start)
211#define last_sched ((unsigned long)__sched_text_end)
212
213unsigned long get_wchan (struct task_struct *p)
214{
215#if 0 /* Barf. Figure out the stack-layout later. XXX */
216 unsigned long fp, pc;
217 int count = 0;
218
219 if (!p || p == current || p->state == TASK_RUNNING)
220 return 0;
221
222 pc = thread_saved_pc (p);
223
224 /* This quite disgusting function walks up the stack, following
225 saved return address, until it something that's out of bounds
226 (as defined by `first_sched' and `last_sched'). It then
227 returns the last PC that was in-bounds. */
228 do {
229 if (fp < stack_page + sizeof (struct task_struct) ||
230 fp >= 8184+stack_page)
231 return 0;
232 pc = ((unsigned long *)fp)[1];
233 if (pc < first_sched || pc >= last_sched)
234 return pc;
235 fp = *(unsigned long *) fp;
236 } while (count++ < 16);
237#endif
238
239 return 0;
240}