aboutsummaryrefslogtreecommitdiffstats
path: root/arch/xtensa/kernel/process.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2012-11-25 17:23:57 -0500
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2012-11-25 17:23:57 -0500
commit2a859ab07b6ab66f4134c4fffc341398bd3d328c (patch)
treec5e7eaf3bffbc18feb326940e39794328d98dc07 /arch/xtensa/kernel/process.c
parentcedddd812a79a4fda3885a15711aee3de78c4a24 (diff)
parente716e014384688d1a50d1aa5213ee74748c6d4e0 (diff)
Merge branch 'merge' into next
Merge my own merge branch to get various fixes from there and upstream, especially the hvc console tty refcouting fixes which which testing is quite a bit harder...
Diffstat (limited to 'arch/xtensa/kernel/process.c')
-rw-r--r--arch/xtensa/kernel/process.c29
1 files changed, 24 insertions, 5 deletions
diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c
index bc020825cce5..1908f6642d31 100644
--- a/arch/xtensa/kernel/process.c
+++ b/arch/xtensa/kernel/process.c
@@ -173,6 +173,16 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
173 * 173 *
174 * Note: This is a pristine frame, so we don't need any spill region on top of 174 * Note: This is a pristine frame, so we don't need any spill region on top of
175 * childregs. 175 * childregs.
176 *
177 * The fun part: if we're keeping the same VM (i.e. cloning a thread,
178 * not an entire process), we're normally given a new usp, and we CANNOT share
179 * any live address register windows. If we just copy those live frames over,
180 * the two threads (parent and child) will overflow the same frames onto the
181 * parent stack at different times, likely corrupting the parent stack (esp.
182 * if the parent returns from functions that called clone() and calls new
183 * ones, before the child overflows its now old copies of its parent windows).
184 * One solution is to spill windows to the parent stack, but that's fairly
185 * involved. Much simpler to just not copy those live frames across.
176 */ 186 */
177 187
178int copy_thread(unsigned long clone_flags, unsigned long usp, 188int copy_thread(unsigned long clone_flags, unsigned long usp,
@@ -180,10 +190,13 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
180 struct task_struct * p, struct pt_regs * regs) 190 struct task_struct * p, struct pt_regs * regs)
181{ 191{
182 struct pt_regs *childregs; 192 struct pt_regs *childregs;
183 struct thread_info *ti;
184 unsigned long tos; 193 unsigned long tos;
185 int user_mode = user_mode(regs); 194 int user_mode = user_mode(regs);
186 195
196#if (XTENSA_HAVE_COPROCESSORS || XTENSA_HAVE_IO_PORTS)
197 struct thread_info *ti;
198#endif
199
187 /* Set up new TSS. */ 200 /* Set up new TSS. */
188 tos = (unsigned long)task_stack_page(p) + THREAD_SIZE; 201 tos = (unsigned long)task_stack_page(p) + THREAD_SIZE;
189 if (user_mode) 202 if (user_mode)
@@ -191,13 +204,14 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
191 else 204 else
192 childregs = (struct pt_regs*)tos - 1; 205 childregs = (struct pt_regs*)tos - 1;
193 206
207 /* This does not copy all the regs. In a bout of brilliance or madness,
208 ARs beyond a0-a15 exist past the end of the struct. */
194 *childregs = *regs; 209 *childregs = *regs;
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; 215 childregs->areg[2] = 0;
202 p->set_child_tid = p->clear_child_tid = NULL; 216 p->set_child_tid = p->clear_child_tid = NULL;
203 p->thread.ra = MAKE_RA_FOR_CALL((unsigned long)ret_from_fork, 0x1); 217 p->thread.ra = MAKE_RA_FOR_CALL((unsigned long)ret_from_fork, 0x1);
@@ -205,10 +219,14 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
205 219
206 if (user_mode(regs)) { 220 if (user_mode(regs)) {
207 221
208 int len = childregs->wmask & ~0xf;
209 childregs->areg[1] = usp; 222 childregs->areg[1] = usp;
210 memcpy(&childregs->areg[XCHAL_NUM_AREGS - len/4], 223 if (clone_flags & CLONE_VM) {
211 &regs->areg[XCHAL_NUM_AREGS - len/4], len); 224 childregs->wmask = 1; /* can't share live windows */
225 } else {
226 int len = childregs->wmask & ~0xf;
227 memcpy(&childregs->areg[XCHAL_NUM_AREGS - len/4],
228 &regs->areg[XCHAL_NUM_AREGS - len/4], len);
229 }
212// FIXME: we need to set THREADPTR in thread_info... 230// FIXME: we need to set THREADPTR in thread_info...
213 if (clone_flags & CLONE_SETTLS) 231 if (clone_flags & CLONE_SETTLS)
214 childregs->areg[2] = childregs->areg[6]; 232 childregs->areg[2] = childregs->areg[6];
@@ -216,6 +234,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
216 } else { 234 } else {
217 /* In kernel space, we start a new thread with a new stack. */ 235 /* In kernel space, we start a new thread with a new stack. */
218 childregs->wmask = 1; 236 childregs->wmask = 1;
237 childregs->areg[1] = tos;
219 } 238 }
220 239
221#if (XTENSA_HAVE_COPROCESSORS || XTENSA_HAVE_IO_PORTS) 240#if (XTENSA_HAVE_COPROCESSORS || XTENSA_HAVE_IO_PORTS)