2 Copyright © 1995-2017, The AROS Development Team. All rights reserved.
5 Desc: PrepareContext() - Prepare a task context for dispatch, x86-64 version
9 #include <exec/execbase.h>
10 #include <exec/memory.h>
11 #include <utility/tagitem.h>
12 #include <aros/x86_64/cpucontext.h>
14 #include "exec_intern.h"
15 #include "exec_util.h"
16 #if defined(__AROSEXEC_SMP__)
20 extern void TaskExitStub(void);
22 #define _PUSH(sp, val) *--sp = (IPTR)val
24 BOOL
PrepareContext(struct Task
*task
, APTR entryPoint
, APTR fallBack
,
25 const struct TagItem
*tagList
, struct ExecBase
*SysBase
)
28 IPTR
*sp
= task
->tc_SPReg
;
29 struct TagItem
*t
, *tstate
= (struct TagItem
*)tagList
;
30 struct ExceptionContext
*ctx
;
32 if (!(task
->tc_Flags
& TF_ETASK
))
35 ctx
= KrnCreateContext();
36 task
->tc_UnionETask
.tc_ETask
->et_RegFrame
= ctx
;
40 while ((t
= LibNextTagItem(&tstate
)))
44 #if defined(__AROSEXEC_SMP__)
45 case TASKTAG_AFFINITY
:
46 if ((IntETask(task
->tc_UnionETask
.tc_ETask
)->iet_CpuAffinity
) && ((IPTR
)IntETask(task
->tc_UnionETask
.tc_ETask
)->iet_CpuAffinity
!= TASKAFFINITY_ANY
))
47 KrnFreeCPUMask(IntETask(task
->tc_UnionETask
.tc_ETask
)->iet_CpuAffinity
);
48 IntETask(task
->tc_UnionETask
.tc_ETask
)->iet_CpuAffinity
= (void *)t
->ti_Data
;
51 #define REGARG(x, reg) \
52 case TASKTAG_ARG ## x: \
53 ctx->reg = t->ti_Data; \
57 case TASKTAG_ARG ## x: \
58 args[x - 7] = t->ti_Data; \
73 * 64-bit ABI says that the stack must be 16-byte aligned *BEFORE*
74 * calling a function. When a return address is pushed by call instruction,
75 * the stack loses alignment, the callee knows about it and fixes it up.
76 * Commonly it's fixed automatically by pushing old frame pointer.
77 * A little of magic below ensures proper stack alignment for both entryPoint
78 * and fallBack routines.
80 _PUSH(sp
, 0); /* De-align the stack (this will be RSP value when fallBack is called) */
81 _PUSH(sp
, fallBack
); /* Push real exit code address for TaskExitStub */
84 * Now stacked arguments for entry point. On x86-64 C function gets on stack only
85 * last two arguments, and we always push them both even if they are empty.
86 * This is needed for two reasons:
87 * 1. Keep stack 16-byte-aligned (we can't push only one, for example).
88 * 2. Simplify TaskExitStub, so that it always knows there are two arguments pushed.
94 * Now push the return address. Stack becomes de-aligned here, this will be RSP
95 * value upon entering entryPoint.
96 * TaskExitStub will remove two arguments pushed above and execute 'ret' instruction.
97 * This way fallBack will be called with proper RSP value.
99 _PUSH(sp
, TaskExitStub
);
101 /* Then set up the frame to be used by Dispatch() */
103 ctx
->rip
= (UQUAD
)entryPoint
;
104 ctx
->rsp
= (UQUAD
)sp
;
106 /* We return the new stack pointer back to the caller. */
110 } /* PrepareContext() */