aboutsummaryrefslogtreecommitdiffstats
path: root/arch/xtensa/kernel/process.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/xtensa/kernel/process.c')
-rw-r--r--arch/xtensa/kernel/process.c147
1 files changed, 90 insertions, 57 deletions
diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c
index bc020825cce5..09ae7bfab9a7 100644
--- a/arch/xtensa/kernel/process.c
+++ b/arch/xtensa/kernel/process.c
@@ -45,6 +45,7 @@
45#include <asm/regs.h> 45#include <asm/regs.h>
46 46
47extern void ret_from_fork(void); 47extern void ret_from_fork(void);
48extern void ret_from_kernel_thread(void);
48 49
49struct task_struct *current_set[NR_CPUS] = {&init_task, }; 50struct task_struct *current_set[NR_CPUS] = {&init_task, };
50 51
@@ -158,64 +159,123 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
158/* 159/*
159 * Copy thread. 160 * Copy thread.
160 * 161 *
162 * There are two modes in which this function is called:
163 * 1) Userspace thread creation,
164 * regs != NULL, usp_thread_fn is userspace stack pointer.
165 * It is expected to copy parent regs (in case CLONE_VM is not set
166 * in the clone_flags) and set up passed usp in the childregs.
167 * 2) Kernel thread creation,
168 * regs == NULL, usp_thread_fn is the function to run in the new thread
169 * and thread_fn_arg is its parameter.
170 * childregs are not used for the kernel threads.
171 *
161 * The stack layout for the new thread looks like this: 172 * The stack layout for the new thread looks like this:
162 * 173 *
163 * +------------------------+ <- sp in childregs (= tos) 174 * +------------------------+
164 * | childregs | 175 * | childregs |
165 * +------------------------+ <- thread.sp = sp in dummy-frame 176 * +------------------------+ <- thread.sp = sp in dummy-frame
166 * | dummy-frame | (saved in dummy-frame spill-area) 177 * | dummy-frame | (saved in dummy-frame spill-area)
167 * +------------------------+ 178 * +------------------------+
168 * 179 *
169 * We create a dummy frame to return to ret_from_fork: 180 * We create a dummy frame to return to either ret_from_fork or
170 * a0 points to ret_from_fork (simulating a call4) 181 * ret_from_kernel_thread:
182 * a0 points to ret_from_fork/ret_from_kernel_thread (simulating a call4)
171 * sp points to itself (thread.sp) 183 * sp points to itself (thread.sp)
172 * a2, a3 are unused. 184 * a2, a3 are unused for userspace threads,
185 * a2 points to thread_fn, a3 holds thread_fn arg for kernel threads.
173 * 186 *
174 * Note: This is a pristine frame, so we don't need any spill region on top of 187 * Note: This is a pristine frame, so we don't need any spill region on top of
175 * childregs. 188 * childregs.
189 *
190 * The fun part: if we're keeping the same VM (i.e. cloning a thread,
191 * not an entire process), we're normally given a new usp, and we CANNOT share
192 * any live address register windows. If we just copy those live frames over,
193 * the two threads (parent and child) will overflow the same frames onto the
194 * parent stack at different times, likely corrupting the parent stack (esp.
195 * if the parent returns from functions that called clone() and calls new
196 * ones, before the child overflows its now old copies of its parent windows).
197 * One solution is to spill windows to the parent stack, but that's fairly
198 * involved. Much simpler to just not copy those live frames across.
176 */ 199 */
177 200
178int copy_thread(unsigned long clone_flags, unsigned long usp, 201int copy_thread(unsigned long clone_flags, unsigned long usp_thread_fn,
179 unsigned long unused, 202 unsigned long thread_fn_arg,
180 struct task_struct * p, struct pt_regs * regs) 203 struct task_struct *p, struct pt_regs *unused)
181{ 204{
182 struct pt_regs *childregs; 205 struct pt_regs *childregs = task_pt_regs(p);
183 struct thread_info *ti;
184 unsigned long tos;
185 int user_mode = user_mode(regs);
186
187 /* Set up new TSS. */
188 tos = (unsigned long)task_stack_page(p) + THREAD_SIZE;
189 if (user_mode)
190 childregs = (struct pt_regs*)(tos - PT_USER_SIZE);
191 else
192 childregs = (struct pt_regs*)tos - 1;
193 206
194 *childregs = *regs; 207#if (XTENSA_HAVE_COPROCESSORS || XTENSA_HAVE_IO_PORTS)
208 struct thread_info *ti;
209#endif
195 210
196 /* Create a call4 dummy-frame: a0 = 0, a1 = childregs. */ 211 /* Create a call4 dummy-frame: a0 = 0, a1 = childregs. */
197 *((int*)childregs - 3) = (unsigned long)childregs; 212 *((int*)childregs - 3) = (unsigned long)childregs;
198 *((int*)childregs - 4) = 0; 213 *((int*)childregs - 4) = 0;
199 214
200 childregs->areg[1] = tos;
201 childregs->areg[2] = 0;
202 p->set_child_tid = p->clear_child_tid = NULL;
203 p->thread.ra = MAKE_RA_FOR_CALL((unsigned long)ret_from_fork, 0x1);
204 p->thread.sp = (unsigned long)childregs; 215 p->thread.sp = (unsigned long)childregs;
205 216
206 if (user_mode(regs)) { 217 if (!(p->flags & PF_KTHREAD)) {
218 struct pt_regs *regs = current_pt_regs();
219 unsigned long usp = usp_thread_fn ?
220 usp_thread_fn : regs->areg[1];
207 221
208 int len = childregs->wmask & ~0xf; 222 p->thread.ra = MAKE_RA_FOR_CALL(
223 (unsigned long)ret_from_fork, 0x1);
224
225 /* This does not copy all the regs.
226 * In a bout of brilliance or madness,
227 * ARs beyond a0-a15 exist past the end of the struct.
228 */
229 *childregs = *regs;
209 childregs->areg[1] = usp; 230 childregs->areg[1] = usp;
210 memcpy(&childregs->areg[XCHAL_NUM_AREGS - len/4], 231 childregs->areg[2] = 0;
211 &regs->areg[XCHAL_NUM_AREGS - len/4], len); 232
233 /* When sharing memory with the parent thread, the child
234 usually starts on a pristine stack, so we have to reset
235 windowbase, windowstart and wmask.
236 (Note that such a new thread is required to always create
237 an initial call4 frame)
238 The exception is vfork, where the new thread continues to
239 run on the parent's stack until it calls execve. This could
240 be a call8 or call12, which requires a legal stack frame
241 of the previous caller for the overflow handlers to work.
242 (Note that it's always legal to overflow live registers).
243 In this case, ensure to spill at least the stack pointer
244 of that frame. */
245
246 if (clone_flags & CLONE_VM) {
247 /* check that caller window is live and same stack */
248 int len = childregs->wmask & ~0xf;
249 if (regs->areg[1] == usp && len != 0) {
250 int callinc = (regs->areg[0] >> 30) & 3;
251 int caller_ars = XCHAL_NUM_AREGS - callinc * 4;
252 put_user(regs->areg[caller_ars+1],
253 (unsigned __user*)(usp - 12));
254 }
255 childregs->wmask = 1;
256 childregs->windowstart = 1;
257 childregs->windowbase = 0;
258 } else {
259 int len = childregs->wmask & ~0xf;
260 memcpy(&childregs->areg[XCHAL_NUM_AREGS - len/4],
261 &regs->areg[XCHAL_NUM_AREGS - len/4], len);
262 }
212// FIXME: we need to set THREADPTR in thread_info... 263// FIXME: we need to set THREADPTR in thread_info...
213 if (clone_flags & CLONE_SETTLS) 264 if (clone_flags & CLONE_SETTLS)
214 childregs->areg[2] = childregs->areg[6]; 265 childregs->areg[2] = childregs->areg[6];
215
216 } else { 266 } else {
217 /* In kernel space, we start a new thread with a new stack. */ 267 p->thread.ra = MAKE_RA_FOR_CALL(
218 childregs->wmask = 1; 268 (unsigned long)ret_from_kernel_thread, 1);
269
270 /* pass parameters to ret_from_kernel_thread:
271 * a2 = thread_fn, a3 = thread_fn arg
272 */
273 *((int *)childregs - 1) = thread_fn_arg;
274 *((int *)childregs - 2) = usp_thread_fn;
275
276 /* Childregs are only used when we're going to userspace
277 * in which case start_thread will set them up.
278 */
219 } 279 }
220 280
221#if (XTENSA_HAVE_COPROCESSORS || XTENSA_HAVE_IO_PORTS) 281#if (XTENSA_HAVE_COPROCESSORS || XTENSA_HAVE_IO_PORTS)
@@ -311,32 +371,5 @@ long xtensa_clone(unsigned long clone_flags, unsigned long newsp,
311 void __user *child_tid, long a5, 371 void __user *child_tid, long a5,
312 struct pt_regs *regs) 372 struct pt_regs *regs)
313{ 373{
314 if (!newsp)
315 newsp = regs->areg[1];
316 return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid); 374 return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid);
317} 375}
318
319/*
320 * xtensa_execve() executes a new program.
321 */
322
323asmlinkage
324long xtensa_execve(const char __user *name,
325 const char __user *const __user *argv,
326 const char __user *const __user *envp,
327 long a3, long a4, long a5,
328 struct pt_regs *regs)
329{
330 long error;
331 struct filename *filename;
332
333 filename = getname(name);
334 error = PTR_ERR(filename);
335 if (IS_ERR(filename))
336 goto out;
337 error = do_execve(filename->name, argv, envp, regs);
338 putname(filename);
339out:
340 return error;
341}
342