Update tc_SPReg (as well as the stack pointer register) before and after
[AROS.git] / arch / i386-all / exec / newstackswap.c
blobcfdcd3ee3fab811a1ac08e2d83c80d031d7e4d7f
1 /*
2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: NewStackSwap() - Call a function with swapped stack.
6 Lang: english
7 */
9 #include <aros/config.h>
10 #include <aros/debug.h>
11 #include <exec/tasks.h>
12 #include <proto/exec.h>
14 #define _PUSH(sp, val) *--sp = (IPTR)val
16 AROS_LH3(IPTR, NewStackSwap,
17 AROS_LHA(struct StackSwapStruct *, sss, A0),
18 AROS_LHA(LONG_FUNC, entry, A1),
19 AROS_LHA(struct StackSwapArgs *, args, A2),
20 struct ExecBase *, SysBase, 134, Exec)
22 AROS_LIBFUNC_INIT
24 volatile struct Task *t = FindTask(NULL);
25 volatile IPTR *sp = sss->stk_Pointer;
26 volatile APTR spreg = t->tc_SPReg;
27 volatile APTR splower = t->tc_SPLower;
28 volatile APTR spupper = t->tc_SPUpper;
29 IPTR ret;
30 BYTE i;
32 /* Put arguments on stack in appropriate order */
33 for (i = 7; i >= 0; i--)
35 D(bug("[NewStackSwap] Argument %d value 0x%08lX\n", i, args->Args[i]));
36 _PUSH(sp, args->Args[i]);
39 if (t->tc_Flags & TF_STACKCHK)
41 volatile UBYTE* startfill = sss->stk_Lower;
43 while (startfill < (UBYTE *)sp)
44 *startfill++ = 0xE1;
48 * We need to Disable() before changing limits and SP, otherwise
49 * stack check will fail if we get interrupted in the middle of this
51 D(bug("[NewStackSwap] SP 0x%p, entry point 0x%p\n", sp, entry));
52 Disable();
54 /* Change limits. The rest is done in asm below */
55 t->tc_SPReg = (APTR)sp;
56 t->tc_SPLower = sss->stk_Lower;
57 t->tc_SPUpper = sss->stk_Upper;
59 asm volatile
61 /* Save original ESP by setting up a new stack frame */
62 " push %%ebp\n"
63 " movl %%esp, %%ebp\n"
64 /* Actually change the stack */
65 " movl %2, %%esp\n\t"
67 /* Enable(). Pass SysBase in %eax, We don't need %eax afterwards */
68 " call *-84(%0)\n"
70 /* Call our function */
71 " call *%1\n"
74 * Disable().
75 * Remember %eax (e.g. %0) and put local SysBase of this function in it.
76 * %3 was clobbered by the called function.
77 */
78 " push %0\n"
79 " movl SysBase, %0\n"
80 " call *-80(%0)\n"
81 " pop %0\n"
83 /* Restore original ESP. Function's return value is in EAX. */
84 " movl %%ebp, %%esp\n"
85 " pop %%ebp\n"
86 : "=a"(ret)
87 : "r"(entry), "r"(sp), "a"(SysBase)
88 : "ecx", "edx", "cc");
90 /* Change limits back and return */
91 t->tc_SPReg = spreg;
92 t->tc_SPLower = splower;
93 t->tc_SPUpper = spupper;
94 Enable();
96 D(bug("[NewStackSwap] Returning 0x%08lX\n", ret));
97 return ret;
99 AROS_LIBFUNC_EXIT
100 } /* NewStackSwap() */