Allow 'args' to be NULL: added convenience for programmers, and better
[AROS.git] / arch / x86_64-all / exec / newstackswap.c
blobdc8b570e759dc4eca2d730d379556dec0d763107
1 /*
2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: NewStackSwap() - Call a function with swapped stack, x86-64 version
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;
31 if (args != NULL)
33 /* Only last two arguments are put to stack in x86-64 */
34 _PUSH(sp, args->Args[7]);
35 _PUSH(sp, args->Args[6]);
37 else
39 /* Dummy args to be put in registers below */
40 args = splower;
43 if (t->tc_Flags & TF_STACKCHK)
45 UBYTE* startfill = sss->stk_Lower;
47 while (startfill < (UBYTE *)sp)
48 *startfill++ = 0xE1;
52 * We need to Disable() before changing limits and SP, otherwise
53 * stack check will fail if we get interrupted in the middle of this
55 D(bug("[NewStackSwap] SP 0x%p, entry point 0x%p\n", sp, entry));
56 Disable();
58 /* Change limits. The rest is done in asm below */
59 t->tc_SPReg = (APTR)sp;
60 t->tc_SPLower = sss->stk_Lower;
61 t->tc_SPUpper = sss->stk_Upper;
63 asm volatile(
64 /* Save original RSP */
65 "push %%rbp\n\t"
66 "movq %%rsp, %%rbp\n\t"
67 /* Actually change the stack */
68 "movq %2, %%rsp\n\t"
70 /* Enable(). It preserves all registers by convention. */
71 "call *-168(%%rdi)\n\t"
73 /* Call our function with its arguments */
74 "movq 0(%3), %%rdi\n\t"
75 "movq 8(%3), %%rsi\n\t"
76 "movq 16(%3), %%rdx\n\t"
77 "movq 24(%3), %%rcx\n\t"
78 "movq 32(%3), %%r8\n\t"
79 "movq 40(%3), %%r9\n\t"
80 "call *%1\n\t"
82 /* Disable(). Also preserves registers. */
83 "movabsq $SysBase, %%rdi\n\t"
84 "movq (%%rdi), %%rdi\n\t"
85 "call *-160(%%rdi)\n\t"
87 /* Restore original RSP. Function's return value is in RAX. */
88 "movq %%rbp, %%rsp\n\t"
89 "popq %%rbp\n"
90 : "=a"(ret)
91 : "r"(entry), "r"(sp), "r"(args), "D"(SysBase)
92 : "rsi", "rdx", "rcx", "r8", "r9", "cc");
94 /* Change limits back and return */
95 t->tc_SPReg = spreg;
96 t->tc_SPLower = splower;
97 t->tc_SPUpper = spupper;
98 Enable();
100 D(bug("[NewStackSwap] Returning 0x%p\n", ret));
101 return ret;
103 AROS_LIBFUNC_EXIT
104 } /* NewStackSwap() */