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