Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 334582
b: refs/heads/master
c: 84ed305
h: refs/heads/master
v: v3
  • Loading branch information
Marc Gauthier authored and Chris Zankel committed Oct 16, 2012
1 parent b2d541c commit 7dc89a4
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 5 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: eae8a416afe140df4b054c448476654db0d46bde
refs/heads/master: 84ed30538b5d9a29a9612b93dd0a45d561624f82
24 changes: 20 additions & 4 deletions trunk/arch/xtensa/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,16 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
*
* Note: This is a pristine frame, so we don't need any spill region on top of
* childregs.
*
* The fun part: if we're keeping the same VM (i.e. cloning a thread,
* not an entire process), we're normally given a new usp, and we CANNOT share
* any live address register windows. If we just copy those live frames over,
* the two threads (parent and child) will overflow the same frames onto the
* parent stack at different times, likely corrupting the parent stack (esp.
* if the parent returns from functions that called clone() and calls new
* ones, before the child overflows its now old copies of its parent windows).
* One solution is to spill windows to the parent stack, but that's fairly
* involved. Much simpler to just not copy those live frames across.
*/

int copy_thread(unsigned long clone_flags, unsigned long usp,
Expand All @@ -191,31 +201,37 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
else
childregs = (struct pt_regs*)tos - 1;

/* This does not copy all the regs. In a bout of brilliance or madness,
ARs beyond a0-a15 exist past the end of the struct. */
*childregs = *regs;

/* Create a call4 dummy-frame: a0 = 0, a1 = childregs. */
*((int*)childregs - 3) = (unsigned long)childregs;
*((int*)childregs - 4) = 0;

childregs->areg[1] = tos;
childregs->areg[2] = 0;
p->set_child_tid = p->clear_child_tid = NULL;
p->thread.ra = MAKE_RA_FOR_CALL((unsigned long)ret_from_fork, 0x1);
p->thread.sp = (unsigned long)childregs;

if (user_mode(regs)) {

int len = childregs->wmask & ~0xf;
childregs->areg[1] = usp;
memcpy(&childregs->areg[XCHAL_NUM_AREGS - len/4],
&regs->areg[XCHAL_NUM_AREGS - len/4], len);
if (clone_flags & CLONE_VM) {
childregs->wmask = 1; /* can't share live windows */
} else {
int len = childregs->wmask & ~0xf;
memcpy(&childregs->areg[XCHAL_NUM_AREGS - len/4],
&regs->areg[XCHAL_NUM_AREGS - len/4], len);
}
// FIXME: we need to set THREADPTR in thread_info...
if (clone_flags & CLONE_SETTLS)
childregs->areg[2] = childregs->areg[6];

} else {
/* In kernel space, we start a new thread with a new stack. */
childregs->wmask = 1;
childregs->areg[1] = tos;
}

#if (XTENSA_HAVE_COPROCESSORS || XTENSA_HAVE_IO_PORTS)
Expand Down

0 comments on commit 7dc89a4

Please sign in to comment.