make the linux-ppc packags be in synch with other platforms
[tangerine.git] / arch / all-linux / x86_64 / sigcore.h.src
blobbdf5e5a6bad0e4e1be6a24b695516bac49ca2159
1 #ifndef _SIGCORE_H
2 #define _SIGCORE_H
4 /*
5     Copyright © 1995-2001, The AROS Development Team. All rights reserved.
6     $Id$
8     Desc: Macros to handle unix signals
9     Lang: english
12 /* There's no need for USE_SA_SIGINFO, as we always use SA_SIGINFO
13    on x86_64 - there's no other sane way to get ucontext. */ 
14 #define SIGCORE_NEED_SA_SIGINFO 1
15 #include <ucontext.h>
17 #include <signal.h>
18 #include <errno.h>
19 #include "etask.h"
21 /* Put a value of type SP_TYPE on the stack or get it off the stack. */
22 #define _PUSH(sp,val)       (*--sp = (SP_TYPE)(val))
23 #define _POP(sp)            (*sp++)
25 #ifndef _SIGNAL_H
26 #define _SIGNAL_H
27 #endif
28 #include <bits/sigcontext.h>
29 /* sigcontext_t is the type of the signals' context. Linux offers no way
30    to get this context in a legal way, so I have to use tricks. */
31 typedef @sigcontext@ sigcontext_t;
32 typedef @sighandler@ SignalHandler;
34 /* name and type of the signal handler */
35 #define SIGHANDLER      linux_sighandler
36 #define SIGHANDLER_T    SignalHandler
39     This macro contains some magic necessary to make it work.
40     The problem is that Linux offers no official way to obtain the
41     signals' context. Linux stores the signals' context on the
42     process' stack. It looks like this:
43     Attention: As of version 2.2 of the Linux kernel there is
44                not enough room on the stack anymore to save
45                any registers on it. So everything has to go into
46                the context structure. Previously PC and FP used 
47                to be saved on the stack but now this would over-
48                write some return address.
49                The stack you see below is the stack of the last 
50                active task within AROS. The linux kernel puts
51                all kinds of other junk on it.
53                     |                          |
54                     +--------------------------+
55                     | last entry before signal |
56                     +--------------------------+
57                     |      signal context      |
58                     +--------------------------+
59                     |      signal number       |
60                     +--------------------------+
61                     |      return address      | 
62                     +--------------------------+
63                     |                          |
65     so the address of the signal context is &sig+1.
68 #define GLOBAL_SIGNAL_INIT \
69         static void sighandler (int sig, sigcontext_t * sc);                    \
70                                                                                 \
71         static void SIGHANDLER (int sig, siginfo_t *blub, struct ucontext *u)   \
72         {                                                                       \
73             sighandler(sig, (sigcontext_t *)&u->uc_mcontext);                   \
74         }
76 /* Type of the values which can be stored on the stack. A variable
77    which is to be used as a stack pointer must be declared as
78    "SP_TYPE *". */
79 #define SP_TYPE     long
81 /* How many general purpose registers are to be saved on the stack
82    when a task switch happens */
83 #define CPU_NUMREGS             0
85 /* Use this structure to save/restore registers if the stack is too
86    small */
88 struct AROS_cpu_context
90     UQUAD regs[17];          /* rip (PC), rbp (FP), rax, rbx, rcx,
91                              rdx, rdi, rsi, r8, r9, r10, r11, r12,
92                              r13, r14, r15, eflags */
93     struct _fpstate fpstate __attribute__ ((aligned (16))); /* FPU state */
94     struct AROS_cpu_context * sc;
95     int errno_backup;
98 #define SIZEOF_ALL_REGISTERS    (sizeof (struct AROS_cpu_context))
99 #define GetCpuContext(task)     ((struct AROS_cpu_context *)\
100                                 (GetIntETask(task)->iet_Context))
101 #define GetSP(task)             (*(SP_TYPE **)&task->tc_SPReg)
104     Macros to access the stack pointer, frame pointer and program
105     counter. The FP is the base address for accesses to arguments
106     and local variables of a function and PC is the current address
107     in the program code.
109 #define SP(sc)           ((sc)->rsp)
110 #define FP(sc)           ((sc)->rbp)
111 #define PC(sc)           ((sc)->rip)
114     Macros to enable or disable all signals after the signal handler
115     has returned and the normal execution commences.
117 #define SC_DISABLE(sc)   ((sc)->oldmask = ~0L)
118 #define SC_ENABLE(sc)    ((sc)->oldmask = 0L)
121     The names of the general purpose registers which are to be saved.
122     Use R and a number as name, no matter what the real name is.
123     General purpose registers (GPRs) are registers which can be
124     modified by the task (ie. data and address registers) and which are
125     not saved by the CPU when an interrupt happens.
127 #define R0(sc)           ((sc)->rax)
128 #define R1(sc)           ((sc)->rbx)
129 #define R2(sc)           ((sc)->rcx)
130 #define R3(sc)           ((sc)->rdx)
131 #define R4(sc)           ((sc)->rdi)
132 #define R5(sc)           ((sc)->rsi)
133 #define R6(sc)           ((sc)->r8)
134 #define R7(sc)           ((sc)->r9)
135 #define R8(sc)           ((sc)->r10)
136 #define R9(sc)           ((sc)->r11)
137 #define R10(sc)           ((sc)->r12)
138 #define R11(sc)           ((sc)->r13)
139 #define R12(sc)           ((sc)->r14)
140 #define R13(sc)           ((sc)->r15)
141 #define R14(sc)           ((sc)->eflags)
144     Save and restore the CPU GPRs in the CPU context
146 #define SAVE_CPU(cc,sc)          \
147     do                           \
148     {                            \
149          (cc)->regs[0] = R0(sc); \
150          (cc)->regs[1] = R1(sc); \
151          (cc)->regs[2] = R2(sc); \
152          (cc)->regs[3] = R3(sc); \
153          (cc)->regs[4] = R4(sc); \
154          (cc)->regs[5] = R5(sc); \
155          (cc)->regs[6] = R6(sc); \
156          (cc)->regs[7] = R7(sc); \
157          (cc)->regs[8] = R8(sc); \
158          (cc)->regs[9] = R9(sc); \
159          (cc)->regs[10] = R10(sc); \
160          (cc)->regs[11] = R11(sc); \
161          (cc)->regs[12] = R12(sc); \
162          (cc)->regs[13] = R13(sc); \
163          (cc)->regs[14] = R14(sc); \
164          (cc)->regs[15] = FP(sc); \
165          (cc)->regs[16] = PC(sc); \
166     } while (0)
167          
168 #define RESTORE_CPU(cc,sc)       \
169     do                           \
170     {                            \
171          R0(sc) = (cc)->regs[0]; \
172          R1(sc) = (cc)->regs[1]; \
173          R2(sc) = (cc)->regs[2]; \
174          R3(sc) = (cc)->regs[3]; \
175          R4(sc) = (cc)->regs[4]; \
176          R5(sc) = (cc)->regs[5]; \
177          R6(sc) = (cc)->regs[6]; \
178          R7(sc) = (cc)->regs[7]; \
179          R8(sc) = (cc)->regs[8]; \
180          R9(sc) = (cc)->regs[9]; \
181          R10(sc) = (cc)->regs[10]; \
182          R11(sc) = (cc)->regs[11]; \
183          R12(sc) = (cc)->regs[12]; \
184          R13(sc) = (cc)->regs[13]; \
185          R14(sc) = (cc)->regs[14]; \
186          FP(sc) = (cc)->regs[15]; \
187          PC(sc) = (cc)->regs[16]; \
188     } while (0)
190 #define SAVE_ERRNO(cc) \
191     do                 \
192     {                  \
193         (cc)->errno_backup = errno; \
194     } while (0) 
195         
196 #define RESTORE_ERRNO(cc) \
197     do                    \
198     {                     \
199         errno = (cc)->errno_backup; \
200     } while (0)
203     It's not possible to save the FPU under linux because linux
204     uses the tasks stack to save the signal context. The signal
205     context conatins the SP *before* the sigcontext was pushed on
206     this stack, so it looks like this:
208                     |                          |
209                     +--------------------------+
210                     | last entry before signal |
211                     +--------------------------+
212                     |       empty space        | <--- SP
213                     +--------------------------+
214                     |      signal context      |
215                     +--------------------------+
216                     |                          |
219     As you can see, SP points to the empty space. Now this empty space
220     is not very big. It's big enough that one can save the CPU
221     registers but not big enough for the FPU. *sigh*.
223     Attention: The above WAS TRUE for 2.0.x kernels but now the stack layout
224                looks different. See above!
226     Update: We store the registers in our own structure now
229 /*  define NO_FPU */
231     This macro returns 1 if an FPU is available.
233 #ifndef NO_FPU
234 #   define HAS_FPU(sc)      (sc->fpstate)
235 #else
236 #   define HAS_FPU(sc)      0
237 #endif
239 #define SAVE_FPU(cc,sc)                         \
240         do                                      \
241         {                                       \
242             if (HAS_FPU(sc))                    \
243                 (cc)->fpstate = *(sc)->fpstate; \
244         } while (0)
246 #define RESTORE_FPU(cc,sc)                      \
247         do                                      \
248         {                                       \
249             if (HAS_FPU(sc))                    \
250                 *(sc)->fpstate = (cc)->fpstate; \
251         } while (0)
254     Prepare the stack. This macro is used on the stack before a new
255     task is run for the first time. To create such a macro, you must
256     know how the system uses the stack. On Linux/i386, every stack
257     frame looks like this:
259                                                  high adresses
260                     |          ...           |
261                     +------------------------+
262                     |       arguments        |
263                     +------------------------+
264                     |     return address     |
265                     +------------------------+
266                     |   old frame pointer    |
267                     +------------------------+
268                     |    local variables     |
269                     +------------------------+
270                     |    saved registers     |
271                     +------------------------+
272                     |          ...           |
273                                                 low addresses
274                                                 stack grows from high to
275                                                 low addresses.
277     The first routine gets no arguments, but if you want to pass
278     some to it, then you must push them on the stack before you
279     call this macro. Note that the arguments must be pushed in
280     reverse order, ie. if you want to call a function like this:
282             func (a,b,c);
284     then you must prepare the stack like this:
286             _PUSH(sp,c);
287             _PUSH(sp,b);
288             _PUSH(sp,a);
289             PREPARE_INITIAL_FRAME(sp,func);
291     This is because the arguments are fetched relative to the FP
292     (ie. FP[0] is the old frame pointer, FP[1] is the return
293     address, FP[2] is the first argument, FP[3] is the second
294     and so on).
298 #   define PREPARE_INITIAL_FRAME(sp,pc)       \
299         do                                    \
300         {                                     \
301             GetCpuContext(task)->regs[15] = 0; \
302             GetCpuContext(task)->regs[16] = (UQUAD)pc; \
303         } while (0)
305 /* Here we have to setup a complete stack frame
306     so Exec_Exception thinks it was called as a
307     normal function. */
308 #define SETUP_EXCEPTION(sc,arg)\
309         do                                        \
310         {                                         \
311             _PUSH(GetSP(SysBase->ThisTask), arg); \
312             _PUSH(GetSP(SysBase->ThisTask), arg); \
313         } while (0)
316     Prepare the cpu context
319 #ifndef NO_FPU
321 #define PREPARE_INITIAL_CONTEXT(task,startpc) \
322    asm volatile("fninit\n\t" \
323                 "fxsave %0\n\t" \
324                 "fwait" : "=m" (GetCpuContext(task)->fpstate))
326 #else
328 #define PREPARE_INITIAL_CONTEXT(task,startpc)
330 #endif
333     Store first six arguments in registers, the rest on stack
336 #define PREPARE_INITIAL_ARGS(task, args, numargs) \
337     UQUAD* regs = GetIntETask (task)->iet_Context;\
338     int argcounter = numargs;                     \
339     while (argcounter > 6)                        \
340         _PUSH(GetSP(task), args[--argcounter]);   \
341     switch (argcounter)                           \
342     {                                             \
343         case 6:                                   \
344             regs[7] = args[5];                    \
345         case 5:                                   \
346             regs[6] = args[4];                    \
347         case 4:                                   \
348             regs[2] = args[3];                    \
349         case 3:                                   \
350             regs[3] = args[2];                    \
351         case 2:                                   \
352             regs[5] = args[1];                    \
353         case 1:                                   \
354             regs[4] = args[0];                    \
355             break;                                \
356     }
359     This macro is similar to PREPARE_INITIAL_FRAME() but also saves
360     all general purpose registers. Use this macro when you want to
361     leave the current tasks' context to save the registers. Note that
362     the argument "sp" of the macro is just the name of the stack
363     pointer. The macro will load it from the sigcontext "sc". You
364     must store the value of "sp" after the macro and hand it to
365     RESTOREREGS() below to restore this context.
368 #define SAVEREGS(task,sc)                                  \
369     do                                                     \
370     {                                                      \
371         struct AROS_cpu_context *cc = GetCpuContext(task); \
372         GetSP(task) = (SP_TYPE *)SP(sc); \
373         SAVE_FPU(cc,sc);                 \
374         SAVE_CPU(cc,sc);                 \
375         SAVE_ERRNO(cc);                  \
376     } while (0)
379     This macro does the opposite to SAVEREGS(). It restores all
380     general purpose registers. After that, you can enter the new
381     tasks' context. Both "sp" and "sc" must be initialized.
382     The macro will save the new SP into the sigcontext "sc".
385 #   define RESTOREREGS(task,sc) \
386     do                                                     \
387     {                                                      \
388         struct AROS_cpu_context *cc = GetCpuContext(task); \
389         RESTORE_ERRNO(cc);    \
390         RESTORE_FPU(cc,sc);   \
391         RESTORE_CPU(cc,sc);   \
392         SP(sc) = (typeof(SP(sc)))GetSP(task); \
393     } while (0)
396     /* This macro prints the current signals' context */
397 #define PRINT_SC(sc) \
398         printf ("    SP=%08lx  FP=%08lx  PC=%08lx  FPU=%s\n" \
399                 "    R0=%08lx  R1=%08lx  R2=%08lx  R3=%08lx\n" \
400                 "    R4=%08lx  R5=%08lx  R6=%08lx  R7=%08lx\n" \
401                 "    R8=%08lx  R9=%08lx  R10=%08lx  R11=%08lx\n" \
402                 "    R12=%08lx  R13=%08lx R14=%08lx\n" \
403             , SP(sc), FP(sc), PC(sc) \
404             , HAS_FPU(sc) ? "yes" : "no" \
405             , R0(sc), R1(sc), R2(sc), R3(sc) \
406             , R4(sc), R5(sc), R6(sc), R7(sc), R8(sc), R9(sc) \
407             , R10(sc), R11(sc), R12(sc), R13(sc), R14(sc) \
408         )
410     /* This macro prints the current stack (after SAVEREGS()) */
411 #define PRINT_CPUCONTEXT(task) \
412         printf ("    SP=%08lx  FP=%08lx  PC=%08lx\n" \
413                 "    R0=%08lx  R1=%08lx  R2=%08lx  R3=%08lx\n" \
414                 "    R4=%08lx  R5=%08lx\n" \
415             , (ULONG)(GetSP(task)) \
416             , GetCpuContext(task)->regs[15] \
417             , GetCpuContext(task)->regs[16] \
418             , GetCpuContext(task)->regs[0] \
419             , GetCpuContext(task)->regs[1] \
420             , GetCpuContext(task)->regs[2] \
421             , GetCpuContext(task)->regs[3] \
422             , GetCpuContext(task)->regs[4] \
423             , GetCpuContext(task)->regs[5] \
424             , GetCpuContext(task)->regs[6] \
425             , GetCpuContext(task)->regs[7] \
426             , GetCpuContext(task)->regs[8] \
427             , GetCpuContext(task)->regs[9] \
428             , GetCpuContext(task)->regs[10] \
429             , GetCpuContext(task)->regs[11] \
430             , GetCpuContext(task)->regs[12] \
431             , GetCpuContext(task)->regs[13] \
432             , GetCpuContext(task)->regs[14] \
433         )
435 #endif /* _SIGCORE_H */