aboutsummaryrefslogtreecommitdiffstats
path: root/arch/m32r/kernel/process.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/m32r/kernel/process.c')
-rw-r--r--arch/m32r/kernel/process.c133
1 files changed, 112 insertions, 21 deletions
diff --git a/arch/m32r/kernel/process.c b/arch/m32r/kernel/process.c
index 765d0f57c78..422bea9f1db 100644
--- a/arch/m32r/kernel/process.c
+++ b/arch/m32r/kernel/process.c
@@ -26,7 +26,6 @@
26#include <linux/ptrace.h> 26#include <linux/ptrace.h>
27#include <linux/unistd.h> 27#include <linux/unistd.h>
28#include <linux/hardirq.h> 28#include <linux/hardirq.h>
29#include <linux/rcupdate.h>
30 29
31#include <asm/io.h> 30#include <asm/io.h>
32#include <asm/uaccess.h> 31#include <asm/uaccess.h>
@@ -83,7 +82,6 @@ void cpu_idle (void)
83{ 82{
84 /* endless idle loop with no priority at all */ 83 /* endless idle loop with no priority at all */
85 while (1) { 84 while (1) {
86 rcu_idle_enter();
87 while (!need_resched()) { 85 while (!need_resched()) {
88 void (*idle)(void) = pm_idle; 86 void (*idle)(void) = pm_idle;
89 87
@@ -92,8 +90,9 @@ void cpu_idle (void)
92 90
93 idle(); 91 idle();
94 } 92 }
95 rcu_idle_exit(); 93 preempt_enable_no_resched();
96 schedule_preempt_disabled(); 94 schedule();
95 preempt_disable();
97 } 96 }
98} 97}
99 98
@@ -165,6 +164,41 @@ void show_regs(struct pt_regs * regs)
165} 164}
166 165
167/* 166/*
167 * Create a kernel thread
168 */
169
170/*
171 * This is the mechanism for creating a new kernel thread.
172 *
173 * NOTE! Only a kernel-only process(ie the swapper or direct descendants
174 * who haven't done an "execve()") should use this: it will work within
175 * a system call from a "real" process, but the process memory space will
176 * not be free'd until both the parent and the child have exited.
177 */
178static void kernel_thread_helper(void *nouse, int (*fn)(void *), void *arg)
179{
180 fn(arg);
181 do_exit(-1);
182}
183
184int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
185{
186 struct pt_regs regs;
187
188 memset(&regs, 0, sizeof (regs));
189 regs.r1 = (unsigned long)fn;
190 regs.r2 = (unsigned long)arg;
191
192 regs.bpc = (unsigned long)kernel_thread_helper;
193
194 regs.psw = M32R_PSW_BIE;
195
196 /* Ok, create the new process. */
197 return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL,
198 NULL);
199}
200
201/*
168 * Free current thread data structures etc.. 202 * Free current thread data structures etc..
169 */ 203 */
170void exit_thread(void) 204void exit_thread(void)
@@ -192,31 +226,88 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
192} 226}
193 227
194int copy_thread(unsigned long clone_flags, unsigned long spu, 228int copy_thread(unsigned long clone_flags, unsigned long spu,
195 unsigned long arg, struct task_struct *tsk) 229 unsigned long unused, struct task_struct *tsk, struct pt_regs *regs)
196{ 230{
197 struct pt_regs *childregs = task_pt_regs(tsk); 231 struct pt_regs *childregs = task_pt_regs(tsk);
198 extern void ret_from_fork(void); 232 extern void ret_from_fork(void);
199 extern void ret_from_kernel_thread(void); 233
200 234 /* Copy registers */
201 if (unlikely(tsk->flags & PF_KTHREAD)) { 235 *childregs = *regs;
202 memset(childregs, 0, sizeof(struct pt_regs)); 236
203 childregs->psw = M32R_PSW_BIE; 237 childregs->spu = spu;
204 childregs->r1 = spu; /* fn */ 238 childregs->r0 = 0; /* Child gets zero as return value */
205 childregs->r0 = arg; 239 regs->r0 = tsk->pid;
206 tsk->thread.lr = (unsigned long)ret_from_kernel_thread;
207 } else {
208 /* Copy registers */
209 *childregs = *current_pt_regs();
210 if (spu)
211 childregs->spu = spu;
212 childregs->r0 = 0; /* Child gets zero as return value */
213 tsk->thread.lr = (unsigned long)ret_from_fork;
214 }
215 tsk->thread.sp = (unsigned long)childregs; 240 tsk->thread.sp = (unsigned long)childregs;
241 tsk->thread.lr = (unsigned long)ret_from_fork;
216 242
217 return 0; 243 return 0;
218} 244}
219 245
246asmlinkage int sys_fork(unsigned long r0, unsigned long r1, unsigned long r2,
247 unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6,
248 struct pt_regs regs)
249{
250#ifdef CONFIG_MMU
251 return do_fork(SIGCHLD, regs.spu, &regs, 0, NULL, NULL);
252#else
253 return -EINVAL;
254#endif /* CONFIG_MMU */
255}
256
257asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
258 unsigned long parent_tidptr,
259 unsigned long child_tidptr,
260 unsigned long r4, unsigned long r5, unsigned long r6,
261 struct pt_regs regs)
262{
263 if (!newsp)
264 newsp = regs.spu;
265
266 return do_fork(clone_flags, newsp, &regs, 0,
267 (int __user *)parent_tidptr, (int __user *)child_tidptr);
268}
269
270/*
271 * This is trivial, and on the face of it looks like it
272 * could equally well be done in user mode.
273 *
274 * Not so, for quite unobvious reasons - register pressure.
275 * In user mode vfork() cannot have a stack frame, and if
276 * done by calling the "clone()" system call directly, you
277 * do not have enough call-clobbered registers to hold all
278 * the information you need.
279 */
280asmlinkage int sys_vfork(unsigned long r0, unsigned long r1, unsigned long r2,
281 unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6,
282 struct pt_regs regs)
283{
284 return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.spu, &regs, 0,
285 NULL, NULL);
286}
287
288/*
289 * sys_execve() executes a new program.
290 */
291asmlinkage int sys_execve(const char __user *ufilename,
292 const char __user *const __user *uargv,
293 const char __user *const __user *uenvp,
294 unsigned long r3, unsigned long r4, unsigned long r5,
295 unsigned long r6, struct pt_regs regs)
296{
297 int error;
298 char *filename;
299
300 filename = getname(ufilename);
301 error = PTR_ERR(filename);
302 if (IS_ERR(filename))
303 goto out;
304
305 error = do_execve(filename, uargv, uenvp, &regs);
306 putname(filename);
307out:
308 return error;
309}
310
220/* 311/*
221 * These bracket the sleeping functions.. 312 * These bracket the sleeping functions..
222 */ 313 */