Forward compatibility: build relative-base link libraries where needed
[AROS.git] / arch / x86_64-all / exec / preparecontext.c
blobdd3f2c04222d037c6a1e964337cdd32219c3a99b
1 /*
2 Copyright © 1995-2011, 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 <proto/kernel.h>
13 #include <aros/x86_64/cpucontext.h>
15 #include "exec_intern.h"
16 #include "exec_util.h"
18 extern void TaskExitStub(void);
20 #define _PUSH(sp, val) *--sp = (IPTR)val
22 BOOL PrepareContext(struct Task *task, APTR entryPoint, APTR fallBack,
23 const struct TagItem *tagList, struct ExecBase *SysBase)
25 IPTR args[2] = {0};
26 IPTR *sp = task->tc_SPReg;
27 struct TagItem *t, *tstate = (struct TagItem *)tagList;
28 struct ExceptionContext *ctx;
30 if (!(task->tc_Flags & TF_ETASK))
31 return FALSE;
33 ctx = KrnCreateContext();
34 task->tc_UnionETask.tc_ETask->et_RegFrame = ctx;
35 if (!ctx)
36 return FALSE;
38 while ((t = LibNextTagItem(&tstate)))
40 switch(t->ti_Tag)
43 #define REGARG(x, reg) \
44 case TASKTAG_ARG ## x: \
45 ctx->reg = t->ti_Data; \
46 break;
48 #define STACKARG(x) \
49 case TASKTAG_ARG ## x: \
50 args[x - 7] = t->ti_Data; \
51 break;
53 REGARG(1, rdi)
54 REGARG(2, rsi)
55 REGARG(3, rdx)
56 REGARG(4, rcx)
57 REGARG(5, r8)
58 REGARG(6, r9)
59 STACKARG(7)
60 STACKARG(8)
65 * 64-bit ABI says that the stack must be 16-byte aligned *BEFORE*
66 * calling a function. When a return address is pushed by call instruction,
67 * the stack loses alignment, the callee knows about it and fixes it up.
68 * Commonly it's fixed automatically by pushing old frame pointer.
69 * A little of magic below ensures proper stack alignment for both entryPoint
70 * and fallBack routines.
72 _PUSH(sp, 0); /* De-align the stack (this will be RSP value when fallBack is called) */
73 _PUSH(sp, fallBack); /* Push real exit code address for TaskExitStub */
76 * Now stacked arguments for entry point. On x86-64 C function gets on stack only
77 * last two arguments, and we always push them both even if they are empty.
78 * This is needed for two reasons:
79 * 1. Keep stack 16-byte-aligned (we can't push only one, for example).
80 * 2. Simplify TaskExitStub, so that it always knows there are two arguments pushed.
82 _PUSH(sp, args[1]);
83 _PUSH(sp, args[0]);
86 * Now push the return address. Stack becomes de-aligned here, this will be RSP
87 * value upon entering entryPoint.
88 * TaskExitStub will remove two arguments pushed above and execute 'ret' instruction.
89 * This way fallBack will be called with proper RSP value.
91 _PUSH(sp, TaskExitStub);
93 /* Then set up the frame to be used by Dispatch() */
94 ctx->rbp = 0;
95 ctx->rip = (UQUAD)entryPoint;
96 ctx->rsp = (UQUAD)sp;
98 /* We return the new stack pointer back to the caller. */
99 task->tc_SPReg = sp;
101 return TRUE;
102 } /* PrepareContext() */