aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/xtensa/kernel/process.c26
1 files changed, 25 insertions, 1 deletions
diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c
index 1908f6642d31..341c151af919 100644
--- a/arch/xtensa/kernel/process.c
+++ b/arch/xtensa/kernel/process.c
@@ -220,8 +220,32 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
220 if (user_mode(regs)) { 220 if (user_mode(regs)) {
221 221
222 childregs->areg[1] = usp; 222 childregs->areg[1] = usp;
223
224 /* When sharing memory with the parent thread, the child
225 usually starts on a pristine stack, so we have to reset
226 windowbase, windowstart and wmask.
227 (Note that such a new thread is required to always create
228 an initial call4 frame)
229 The exception is vfork, where the new thread continues to
230 run on the parent's stack until it calls execve. This could
231 be a call8 or call12, which requires a legal stack frame
232 of the previous caller for the overflow handlers to work.
233 (Note that it's always legal to overflow live registers).
234 In this case, ensure to spill at least the stack pointer
235 of that frame. */
236
223 if (clone_flags & CLONE_VM) { 237 if (clone_flags & CLONE_VM) {
224 childregs->wmask = 1; /* can't share live windows */ 238 /* check that caller window is live and same stack */
239 int len = childregs->wmask & ~0xf;
240 if (regs->areg[1] == usp && len != 0) {
241 int callinc = (regs->areg[0] >> 30) & 3;
242 int caller_ars = XCHAL_NUM_AREGS - callinc * 4;
243 put_user(regs->areg[caller_ars+1],
244 (unsigned __user*)(usp - 12));
245 }
246 childregs->wmask = 1;
247 childregs->windowstart = 1;
248 childregs->windowbase = 0;
225 } else { 249 } else {
226 int len = childregs->wmask & ~0xf; 250 int len = childregs->wmask & ~0xf;
227 memcpy(&childregs->areg[XCHAL_NUM_AREGS - len/4], 251 memcpy(&childregs->areg[XCHAL_NUM_AREGS - len/4],