Updated PCI IDs to latest snapshot.
[tangerine.git] / arch / all-linux / i386 / sigcore.h.src
blob4be80a67b55a9d815184ce017f1e99bc027f8c4f
1 #ifndef _SIGCORE_H
2 #define _SIGCORE_H
4 /*
5     Copyright © 1995-2009, The AROS Development Team. All rights reserved.
6     $Id$
8     Desc: Macros to handle unix signals
9     Lang: english
12 #define USE_SA_SIGINFO 0
14 #if USE_SA_SIGINFO
15 #define SIGCORE_NEED_SA_SIGINFO 1
16 #include <ucontext.h>
17 #endif
19 #include <signal.h>
20 #include <errno.h>
21 #include "etask.h"
23 /* Put a value of type SP_TYPE on the stack or get it off the stack. */
24 #define _PUSH(sp,val)              \
25     do                             \
26     {                              \
27        SP_TYPE **stackp = (sp);    \
28        --*stackp;                  \
29        **stackp = (SP_TYPE) (val); \
30     } while (0)
31 #define _POP(sp)            (*sp++)
33 #ifndef _SIGNAL_H
34 #define _SIGNAL_H
35 #endif
36 #include <bits/sigcontext.h>
37 /* sigcontext_t is the type of the signals' context. Linux offers no way
38    to get this context in a legal way, so I have to use tricks. */
39 typedef @sigcontext@ sigcontext_t;
40 typedef @sighandler@ SignalHandler;
42 /* name and type of the signal handler */
43 #define SIGHANDLER      linux_sighandler
44 #define SIGHANDLER_T    SignalHandler
47     This macro contains some magic necessary to make it work.
48     The problem is that Linux offers no official way to obtain the
49     signals' context. Linux stores the signals' context on the
50     process' stack. It looks like this:
51     Attention: As of version 2.2 of the Linux kernel there is
52                not enough room on the stack anymore to save
53                any registers on it. So everything has to go into
54                the context structure. Previously PC and FP used 
55                to be saved on the stack but now this would over-
56                write some return address.
57                The stack you see below is the stack of the last 
58                active task within AROS. The linux kernel puts
59                all kinds of other junk on it.
61                     |                          |
62                     +--------------------------+
63                     | last entry before signal |
64                     +--------------------------+
65                     |      signal context      |
66                     +--------------------------+
67                     |      signal number       |
68                     +--------------------------+
69                     |      return address      | 
70                     +--------------------------+
71                     |                          |
73     so the address of the signal context is &sig+1.
76 #if USE_SA_SIGINFO
77 #define GLOBAL_SIGNAL_INIT \
78         static void sighandler (int sig, sigcontext_t * sc);                    \
79                                                                                 \
80         static void SIGHANDLER (int sig, siginfo_t *blub, struct ucontext *u)   \
81         {                                                                       \
82             sighandler(sig, (sigcontext_t *)&u->uc_mcontext);                   \
83         }
85 #else
87 #define GLOBAL_SIGNAL_INIT \
88         static void sighandler (int sig, sigcontext_t * sc);    \
89                                                                 \
90         static void SIGHANDLER (int sig)                        \
91         {                                                       \
92             sighandler (sig, (sigcontext_t *)(&sig+1));         \
93         }
94 #endif
96 /* Type of the values which can be stored on the stack. A variable
97    which is to be used as a stack pointer must be declared as
98    "SP_TYPE *". */
99 #define SP_TYPE     long
101 /* How many general purpose registers are to be saved on the stack
102    when a task switch happens */
103 #define CPU_NUMREGS             0
105 /* Use this structure to save/restore registers if the stack is too
106    small */
108 struct AROS_cpu_context
110     ULONG                     regs[9]; /* eip (PC), ebp (FP), eax, ebx, ecx, edx, edi, esi, eflags */
111     struct _fpstate           fpstate; /* FPU state */
112     int                       errno_backup;
113     struct AROS_cpu_context * sc;
116 #undef SIZEOF_ALL_REGISTERS
117 #define SIZEOF_ALL_REGISTERS    (sizeof (struct AROS_cpu_context))
118 #define GetCpuContext(task)     ((struct AROS_cpu_context *)\
119                                 (GetIntETask(task)->iet_Context))
120 #define GetSP(task)             ((SP_TYPE **)&task->tc_SPReg)
123     Macros to access the stack pointer, frame pointer and program
124     counter. The FP is the base address for accesses to arguments
125     and local variables of a function and PC is the current address
126     in the program code.
128 #define SP(sc)           ((sc)->esp)
129 #define FP(sc)           ((sc)->ebp)
130 #define PC(sc)           ((sc)->eip)
133     Macros to enable or disable all signals after the signal handler
134     has returned and the normal execution commences.
136 #define SC_DISABLE(sc)   ((sc)->oldmask = ~0L)
137 #define SC_ENABLE(sc)    ((sc)->oldmask = 0L)
140     The names of the general purpose registers which are to be saved.
141     Use R and a number as name, no matter what the real name is.
142     General purpose registers (GPRs) are registers which can be
143     modified by the task (ie. data and address registers) and which are
144     not saved by the CPU when an interrupt happens.
146 #define R0(sc)           ((sc)->eax)
147 #define R1(sc)           ((sc)->ebx)
148 #define R2(sc)           ((sc)->ecx)
149 #define R3(sc)           ((sc)->edx)
150 #define R4(sc)           ((sc)->edi)
151 #define R5(sc)           ((sc)->esi)
152 #define R6(sc)           ((sc)->eflags)
155     Save and restore the CPU GPRs in the CPU context
157 #define SAVE_CPU(cc,sc)          \
158     do                           \
159     {                            \
160          (cc)->regs[0] = R0(sc); \
161          (cc)->regs[1] = R1(sc); \
162          (cc)->regs[2] = R2(sc); \
163          (cc)->regs[3] = R3(sc); \
164          (cc)->regs[4] = R4(sc); \
165          (cc)->regs[5] = R5(sc); \
166          (cc)->regs[6] = R6(sc); \
167          (cc)->regs[7] = FP(sc); \
168          (cc)->regs[8] = PC(sc); \
169     } while (0)
170          
171 #define RESTORE_CPU(cc,sc)       \
172     do                           \
173     {                            \
174          R0(sc) = (cc)->regs[0]; \
175          R1(sc) = (cc)->regs[1]; \
176          R2(sc) = (cc)->regs[2]; \
177          R3(sc) = (cc)->regs[3]; \
178          R4(sc) = (cc)->regs[4]; \
179          R5(sc) = (cc)->regs[5]; \
180          R6(sc) = (cc)->regs[6]; \
181          FP(sc) = (cc)->regs[7]; \
182          PC(sc) = (cc)->regs[8]; \
183     } while (0)
185 #define SAVE_ERRNO(cc) \
186     do                 \
187     {                  \
188         (cc)->errno_backup = errno; \
189     } while (0) 
190         
191 #define RESTORE_ERRNO(cc) \
192     do                    \
193     {                     \
194         errno = (cc)->errno_backup; \
195     } while (0)
198     It's not possible to save the FPU under linux because linux
199     uses the tasks stack to save the signal context. The signal
200     context conatins the SP *before* the sigcontext was pushed on
201     this stack, so it looks like this:
203                     |                          |
204                     +--------------------------+
205                     | last entry before signal |
206                     +--------------------------+
207                     |       empty space        | <--- SP
208                     +--------------------------+
209                     |      signal context      |
210                     +--------------------------+
211                     |                          |
214     As you can see, SP points to the empty space. Now this empty space
215     is not very big. It's big enough that one can save the CPU
216     registers but not big enough for the FPU. *sigh*.
218     Attention: The above WAS TRUE for 2.0.x kernels but now the stack layout
219                looks different. See above!
221     Update: We store the registers in our own structure now
224 //#   define NO_FPU
227     This macro returns 1 if an FPU is available.
229 #ifndef NO_FPU
230 #   define HAS_FPU(sc)      (sc->fpstate)
231 #else
232 #   define HAS_FPU(sc)      0
233 #endif
235 #define SAVE_FPU(cc,sc)                         \
236         do                                      \
237         {                                       \
238             if (HAS_FPU(sc))                    \
239                 (cc)->fpstate = *(sc)->fpstate; \
240         } while (0)
242 #define RESTORE_FPU(cc,sc)                      \
243         do                                      \
244         {                                       \
245             if (HAS_FPU(sc))                    \
246                 *(sc)->fpstate = (cc)->fpstate; \
247         } while (0)
250     Prepare the stack. This macro is used on the stack before a new
251     task is run for the first time. To create such a macro, you must
252     know how the system uses the stack. On Linux/i386, every stack
253     frame looks like this:
255                                                  high adresses
256                     |          ...           |
257                     +------------------------+
258                     |       arguments        |
259                     +------------------------+
260                     |     return address     |
261                     +------------------------+
262                     |   old frame pointer    |
263                     +------------------------+
264                     |    local variables     |
265                     +------------------------+
266                     |    saved registers     |
267                     +------------------------+
268                     |          ...           |
269                                                 low addresses
270                                                 stack grows from high to
271                                                 low addresses.
273     The first routine gets no arguments, but if you want to pass
274     some to it, then you must push them on the stack before you
275     call this macro. Note that the arguments must be pushed in
276     reverse order, ie. if you want to call a function like this:
278             func (a,b,c);
280     then you must prepare the stack like this:
282             _PUSH(sp,c);
283             _PUSH(sp,b);
284             _PUSH(sp,a);
285             PREPARE_INITIAL_FRAME(sp,func);
287     This is because the arguments are fetched relative to the FP
288     (ie. FP[0] is the old frame pointer, FP[1] is the return
289     address, FP[2] is the first argument, FP[3] is the second
290     and so on).
294 #   define PREPARE_INITIAL_FRAME(sp,pc)       \
295         do                                    \
296         {                                     \
297             GetCpuContext(task)->regs[7] = 0; \
298             GetCpuContext(task)->regs[8] = (ULONG)pc; \
299         } while (0)
301 /* Here we have to setup a complete stack frame
302     so Exec_Exception thinks it was called as a
303     normal function. */
304 #define SETUP_EXCEPTION(sc,arg)\
305         do                                        \
306         {                                         \
307             _PUSH(GetSP(SysBase->ThisTask), arg); \
308             _PUSH(GetSP(SysBase->ThisTask), arg); \
309         } while (0)
312     Prepare the cpu context
315 #ifndef NO_FPU
317 #define PREPARE_INITIAL_CONTEXT(task,startpc) \
318    asm volatile("fninit\n\t" \
319                 "fnsave %0\n\t" \
320                 "fwait" : "=m" (GetCpuContext(task)->fpstate))
322 #else
324 #define PREPARE_INITIAL_CONTEXT(task,startpc)
326 #endif
329     This macro is similar to PREPARE_INITIAL_FRAME() but also saves
330     all general purpose registers. Use this macro when you want to
331     leave the current tasks' context to save the registers. Note that
332     the argument "sp" of the macro is just the name of the stack
333     pointer. The macro will load it from the sigcontext "sc". You
334     must store the value of "sp" after the macro and hand it to
335     RESTOREREGS() below to restore this context.
338 #define SAVEREGS(task,sc)                                  \
339     do                                                     \
340     {                                                      \
341         struct AROS_cpu_context *cc = GetCpuContext(task); \
342         SP_TYPE **sp = GetSP(task);      \
343         *sp = (SP_TYPE *)SP(sc);         \
344         SAVE_FPU(cc,sc);                 \
345         SAVE_CPU(cc,sc);                 \
346         SAVE_ERRNO(cc);                  \
347     } while (0)
350     This macro does the opposite to SAVEREGS(). It restores all
351     general purpose registers. After that, you can enter the new
352     tasks' context. Both "sp" and "sc" must be initialized.
353     The macro will save the new SP into the sigcontext "sc".
356 #   define RESTOREREGS(task,sc) \
357     do                                                     \
358     {                                                      \
359         struct AROS_cpu_context *cc = GetCpuContext(task); \
360         RESTORE_ERRNO(cc);    \
361         RESTORE_FPU(cc,sc);   \
362         RESTORE_CPU(cc,sc);   \
363         SP_TYPE** sp = GetSP(task);    \
364         SP(sc) = (typeof(SP(sc))) *sp; \
365     } while (0)
368     /* This macro prints the current signals' context */
369 #define PRINT_SC(sc) \
370         printf ("    SP=%08lx  FP=%08lx  PC=%08lx  FPU=%s\n" \
371                 "    R0=%08lx  R1=%08lx  R2=%08lx  R3=%08lx\n" \
372                 "    R4=%08lx  R5=%08lx\n" \
373             , SP(sc), FP(sc), PC(sc) \
374             , HAS_FPU(sc) ? "yes" : "no" \
375             , R0(sc), R1(sc), R2(sc), R3(sc) \
376             , R4(sc), R5(sc) \
377         )
379     /* This macro prints the current stack (after SAVEREGS()) */
380 #define PRINT_CPUCONTEXT(task) \
381         printf ("    SP=%08lx  FP=%08lx  PC=%08lx\n" \
382                 "    R0=%08x  R1=%08x  R2=%08x  R3=%08x\n" \
383                 "    R4=%08x  R5=%08x\n" \
384             , (*GetSP(task))[ 0] \
385             , (*GetSP(task))[-1] \
386             , (*GetSP(task))[-2] \
387             , GetCpuContext(task)->regs[0] \
388             , GetCpuContext(task)->regs[1] \
389             , GetCpuContext(task)->regs[2] \
390             , GetCpuContext(task)->regs[3] \
391             , GetCpuContext(task)->regs[4] \
392             , GetCpuContext(task)->regs[5] \
393         )
395 #endif /* _SIGCORE_H */