adapt to cpu affinity mask changes
[AROS.git] / arch / x86_64-all / exec / preparecontext.c
blob5ee62e3d782a307f22e6292c096e514c2f0bfc72
1 /*
2 Copyright © 1995-2017, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: PrepareContext() - Prepare a task context for dispatch, x86-64 version
6 Lang: english
7 */
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__)
17 #include "etask.h"
18 #endif
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)
27 IPTR args[2] = {0};
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))
33 return FALSE;
35 ctx = KrnCreateContext();
36 task->tc_UnionETask.tc_ETask->et_RegFrame = ctx;
37 if (!ctx)
38 return FALSE;
40 while ((t = LibNextTagItem(&tstate)))
42 switch(t->ti_Tag)
44 #if defined(__AROSEXEC_SMP__)
45 case TASKTAG_AFFINITY:
46 if (IntETask(task->tc_UnionETask.tc_ETask)->iet_CpuAffinity)
47 KrnFreeCPUMask(IntETask(task->tc_UnionETask.tc_ETask)->iet_CpuAffinity);
48 IntETask(task->tc_UnionETask.tc_ETask)->iet_CpuAffinity = (void *)t->ti_Data;
49 break;
50 #endif
51 #define REGARG(x, reg) \
52 case TASKTAG_ARG ## x: \
53 ctx->reg = t->ti_Data; \
54 break;
56 #define STACKARG(x) \
57 case TASKTAG_ARG ## x: \
58 args[x - 7] = t->ti_Data; \
59 break;
61 REGARG(1, rdi)
62 REGARG(2, rsi)
63 REGARG(3, rdx)
64 REGARG(4, rcx)
65 REGARG(5, r8)
66 REGARG(6, r9)
67 STACKARG(7)
68 STACKARG(8)
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.
90 _PUSH(sp, args[1]);
91 _PUSH(sp, args[0]);
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() */
102 ctx->rbp = 0;
103 ctx->rip = (UQUAD)entryPoint;
104 ctx->rsp = (UQUAD)sp;
106 /* We return the new stack pointer back to the caller. */
107 task->tc_SPReg = sp;
109 return TRUE;
110 } /* PrepareContext() */