diff options
Diffstat (limited to 'arch/m32r/kernel/process.c')
-rw-r--r-- | arch/m32r/kernel/process.c | 133 |
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 | */ | ||
178 | static void kernel_thread_helper(void *nouse, int (*fn)(void *), void *arg) | ||
179 | { | ||
180 | fn(arg); | ||
181 | do_exit(-1); | ||
182 | } | ||
183 | |||
184 | int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | ||
185 | { | ||
186 | struct pt_regs regs; | ||
187 | |||
188 | memset(®s, 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, ®s, 0, NULL, | ||
198 | NULL); | ||
199 | } | ||
200 | |||
201 | /* | ||
168 | * Free current thread data structures etc.. | 202 | * Free current thread data structures etc.. |
169 | */ | 203 | */ |
170 | void exit_thread(void) | 204 | void exit_thread(void) |
@@ -192,31 +226,88 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) | |||
192 | } | 226 | } |
193 | 227 | ||
194 | int copy_thread(unsigned long clone_flags, unsigned long spu, | 228 | int 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 | ||
246 | asmlinkage 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, ®s, 0, NULL, NULL); | ||
252 | #else | ||
253 | return -EINVAL; | ||
254 | #endif /* CONFIG_MMU */ | ||
255 | } | ||
256 | |||
257 | asmlinkage 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, ®s, 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 | */ | ||
280 | asmlinkage 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, ®s, 0, | ||
285 | NULL, NULL); | ||
286 | } | ||
287 | |||
288 | /* | ||
289 | * sys_execve() executes a new program. | ||
290 | */ | ||
291 | asmlinkage 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, ®s); | ||
306 | putname(filename); | ||
307 | out: | ||
308 | return error; | ||
309 | } | ||
310 | |||
220 | /* | 311 | /* |
221 | * These bracket the sleeping functions.. | 312 | * These bracket the sleeping functions.. |
222 | */ | 313 | */ |