5 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
8 Desc: Macros to handle unix signals
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
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++)
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.
54 +--------------------------+
55 | last entry before signal |
56 +--------------------------+
58 +--------------------------+
60 +--------------------------+
62 +--------------------------+
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); \
71 static void SIGHANDLER (int sig, siginfo_t *blub, struct ucontext *u) \
73 sighandler(sig, (sigcontext_t *)&u->uc_mcontext); \
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
81 /* How many general purpose registers are to be saved on the stack
82 when a task switch happens */
85 /* Use this structure to save/restore registers if the stack is too
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;
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
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) \
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); \
168 #define RESTORE_CPU(cc,sc) \
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]; \
190 #define SAVE_ERRNO(cc) \
193 (cc)->errno_backup = errno; \
196 #define RESTORE_ERRNO(cc) \
199 errno = (cc)->errno_backup; \
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:
209 +--------------------------+
210 | last entry before signal |
211 +--------------------------+
212 | empty space | <--- SP
213 +--------------------------+
215 +--------------------------+
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
231 This macro returns 1 if an FPU is available.
234 # define HAS_FPU(sc) (sc->fpstate)
236 # define HAS_FPU(sc) 0
239 #define SAVE_FPU(cc,sc) \
243 (cc)->fpstate = *(sc)->fpstate; \
246 #define RESTORE_FPU(cc,sc) \
250 *(sc)->fpstate = (cc)->fpstate; \
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:
261 +------------------------+
263 +------------------------+
265 +------------------------+
266 | old frame pointer |
267 +------------------------+
269 +------------------------+
271 +------------------------+
274 stack grows from high to
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:
284 then you must prepare the stack like this:
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
298 # define PREPARE_INITIAL_FRAME(sp,pc) \
301 GetCpuContext(task)->regs[15] = 0; \
302 GetCpuContext(task)->regs[16] = (UQUAD)pc; \
305 /* Here we have to setup a complete stack frame
306 so Exec_Exception thinks it was called as a
308 #define SETUP_EXCEPTION(sc,arg)\
311 _PUSH(GetSP(SysBase->ThisTask), arg); \
312 _PUSH(GetSP(SysBase->ThisTask), arg); \
316 Prepare the cpu context
321 #define PREPARE_INITIAL_CONTEXT(task,startpc) \
322 asm volatile("fninit\n\t" \
324 "fwait" : "=m" (GetCpuContext(task)->fpstate))
328 #define PREPARE_INITIAL_CONTEXT(task,startpc)
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) \
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) \
371 struct AROS_cpu_context *cc = GetCpuContext(task); \
372 GetSP(task) = (SP_TYPE *)SP(sc); \
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) \
388 struct AROS_cpu_context *cc = GetCpuContext(task); \
390 RESTORE_FPU(cc,sc); \
391 RESTORE_CPU(cc,sc); \
392 SP(sc) = (typeof(SP(sc)))GetSP(task); \
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) \
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] \
435 #endif /* _SIGCORE_H */