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
22 /* Put a value of type SP_TYPE on the stack or get it off the stack. */
23 #define _PUSH(sp,val) (*--sp = (SP_TYPE)(val))
24 #define _POP(sp) (*sp++)
29 #include <bits/sigcontext.h>
30 /* sigcontext_t is the type of the signals' context. Linux offers no way
31 to get this context in a legal way, so I have to use tricks. */
32 typedef @sigcontext@ sigcontext_t;
33 typedef @sighandler@ SignalHandler;
35 /* name and type of the signal handler */
36 #define SIGHANDLER linux_sighandler
37 #define SIGHANDLER_T SignalHandler
40 This macro contains some magic necessary to make it work.
41 The problem is that Linux offers no official way to obtain the
42 signals' context. Linux stores the signals' context on the
43 process' stack. It looks like this:
44 Attention: As of version 2.2 of the Linux kernel there is
45 not enough room on the stack anymore to save
46 any registers on it. So everything has to go into
47 the context structure. Previously PC and FP used
48 to be saved on the stack but now this would over-
49 write some return address.
50 The stack you see below is the stack of the last
51 active task within AROS. The linux kernel puts
52 all kinds of other junk on it.
55 +--------------------------+
56 | last entry before signal |
57 +--------------------------+
59 +--------------------------+
61 +--------------------------+
63 +--------------------------+
66 so the address of the signal context is &sig+1.
69 #define GLOBAL_SIGNAL_INIT \
70 static void sighandler (int sig, sigcontext_t * sc); \
72 static void SIGHANDLER (int sig, siginfo_t *blub, struct ucontext *u) \
74 sighandler(sig, (sigcontext_t *)&u->uc_mcontext); \
77 /* Type of the values which can be stored on the stack. A variable
78 which is to be used as a stack pointer must be declared as
82 /* How many general purpose registers are to be saved on the stack
83 when a task switch happens */
86 /* Use this structure to save/restore registers if the stack is too
89 struct AROS_cpu_context
91 UQUAD regs[17]; /* rip (PC), rbp (FP), rax, rbx, rcx,
92 rdx, rdi, rsi, r8, r9, r10, r11, r12,
93 r13, r14, r15, eflags */
94 struct _fpstate fpstate __attribute__ ((aligned (16))); /* FPU state */
95 struct AROS_cpu_context * sc;
99 #define SIZEOF_ALL_REGISTERS (sizeof (struct AROS_cpu_context))
100 #define GetCpuContext(task) ((struct AROS_cpu_context *)\
101 (GetIntETask(task)->iet_Context))
102 #define GetSP(task) (*(SP_TYPE **)&task->tc_SPReg)
105 Macros to access the stack pointer, frame pointer and program
106 counter. The FP is the base address for accesses to arguments
107 and local variables of a function and PC is the current address
110 #define SP(sc) ((sc)->rsp)
111 #define FP(sc) ((sc)->rbp)
112 #define PC(sc) ((sc)->rip)
115 Macros to enable or disable all signals after the signal handler
116 has returned and the normal execution commences.
118 On Linux x86-64 signal mask is restored from uc_sigmask field of ucontext
119 structure. We are computing address of uc_sigmask field from address of
120 uc_mcontext field given as sc parameter.
122 #define SC_DISABLE(sc) \
123 sigfillset((sigset_t*)((char*) sc + \
124 offsetof(struct ucontext, uc_sigmask) - \
125 offsetof(struct ucontext, uc_mcontext)) \
128 #define SC_ENABLE(sc) \
129 sigemptyset((sigset_t*)((char*) sc + \
130 offsetof(struct ucontext, uc_sigmask) - \
131 offsetof(struct ucontext, uc_mcontext)) \
135 The names of the general purpose registers which are to be saved.
136 Use R and a number as name, no matter what the real name is.
137 General purpose registers (GPRs) are registers which can be
138 modified by the task (ie. data and address registers) and which are
139 not saved by the CPU when an interrupt happens.
141 #define R0(sc) ((sc)->rax)
142 #define R1(sc) ((sc)->rbx)
143 #define R2(sc) ((sc)->rcx)
144 #define R3(sc) ((sc)->rdx)
145 #define R4(sc) ((sc)->rdi)
146 #define R5(sc) ((sc)->rsi)
147 #define R6(sc) ((sc)->r8)
148 #define R7(sc) ((sc)->r9)
149 #define R8(sc) ((sc)->r10)
150 #define R9(sc) ((sc)->r11)
151 #define R10(sc) ((sc)->r12)
152 #define R11(sc) ((sc)->r13)
153 #define R12(sc) ((sc)->r14)
154 #define R13(sc) ((sc)->r15)
155 #define R14(sc) ((sc)->eflags)
158 Save and restore the CPU GPRs in the CPU context
160 #define SAVE_CPU(cc,sc) \
163 (cc)->regs[0] = R0(sc); \
164 (cc)->regs[1] = R1(sc); \
165 (cc)->regs[2] = R2(sc); \
166 (cc)->regs[3] = R3(sc); \
167 (cc)->regs[4] = R4(sc); \
168 (cc)->regs[5] = R5(sc); \
169 (cc)->regs[6] = R6(sc); \
170 (cc)->regs[7] = R7(sc); \
171 (cc)->regs[8] = R8(sc); \
172 (cc)->regs[9] = R9(sc); \
173 (cc)->regs[10] = R10(sc); \
174 (cc)->regs[11] = R11(sc); \
175 (cc)->regs[12] = R12(sc); \
176 (cc)->regs[13] = R13(sc); \
177 (cc)->regs[14] = R14(sc); \
178 (cc)->regs[15] = FP(sc); \
179 (cc)->regs[16] = PC(sc); \
182 #define RESTORE_CPU(cc,sc) \
185 R0(sc) = (cc)->regs[0]; \
186 R1(sc) = (cc)->regs[1]; \
187 R2(sc) = (cc)->regs[2]; \
188 R3(sc) = (cc)->regs[3]; \
189 R4(sc) = (cc)->regs[4]; \
190 R5(sc) = (cc)->regs[5]; \
191 R6(sc) = (cc)->regs[6]; \
192 R7(sc) = (cc)->regs[7]; \
193 R8(sc) = (cc)->regs[8]; \
194 R9(sc) = (cc)->regs[9]; \
195 R10(sc) = (cc)->regs[10]; \
196 R11(sc) = (cc)->regs[11]; \
197 R12(sc) = (cc)->regs[12]; \
198 R13(sc) = (cc)->regs[13]; \
199 R14(sc) = (cc)->regs[14]; \
200 FP(sc) = (cc)->regs[15]; \
201 PC(sc) = (cc)->regs[16]; \
204 #define SAVE_ERRNO(cc) \
207 (cc)->errno_backup = errno; \
210 #define RESTORE_ERRNO(cc) \
213 errno = (cc)->errno_backup; \
217 It's not possible to save the FPU under linux because linux
218 uses the tasks stack to save the signal context. The signal
219 context conatins the SP *before* the sigcontext was pushed on
220 this stack, so it looks like this:
223 +--------------------------+
224 | last entry before signal |
225 +--------------------------+
226 | empty space | <--- SP
227 +--------------------------+
229 +--------------------------+
233 As you can see, SP points to the empty space. Now this empty space
234 is not very big. It's big enough that one can save the CPU
235 registers but not big enough for the FPU. *sigh*.
237 Attention: The above WAS TRUE for 2.0.x kernels but now the stack layout
238 looks different. See above!
240 Update: We store the registers in our own structure now
245 This macro returns 1 if an FPU is available.
248 # define HAS_FPU(sc) (sc->fpstate)
250 # define HAS_FPU(sc) 0
253 #define SAVE_FPU(cc,sc) \
257 (cc)->fpstate = *(sc)->fpstate; \
260 #define RESTORE_FPU(cc,sc) \
264 *(sc)->fpstate = (cc)->fpstate; \
268 Prepare the stack. This macro is used on the stack before a new
269 task is run for the first time. To create such a macro, you must
270 know how the system uses the stack. On Linux/i386, every stack
271 frame looks like this:
275 +------------------------+
277 +------------------------+
279 +------------------------+
280 | old frame pointer |
281 +------------------------+
283 +------------------------+
285 +------------------------+
288 stack grows from high to
291 The first routine gets no arguments, but if you want to pass
292 some to it, then you must push them on the stack before you
293 call this macro. Note that the arguments must be pushed in
294 reverse order, ie. if you want to call a function like this:
298 then you must prepare the stack like this:
303 PREPARE_INITIAL_FRAME(sp,func);
305 This is because the arguments are fetched relative to the FP
306 (ie. FP[0] is the old frame pointer, FP[1] is the return
307 address, FP[2] is the first argument, FP[3] is the second
312 # define PREPARE_INITIAL_FRAME(sp,pc) \
315 GetCpuContext(task)->regs[15] = 0; \
316 GetCpuContext(task)->regs[16] = (UQUAD)pc; \
319 /* Here we have to setup a complete stack frame
320 so Exec_Exception thinks it was called as a
322 #define SETUP_EXCEPTION(sc,arg)\
325 _PUSH(GetSP(SysBase->ThisTask), arg); \
326 _PUSH(GetSP(SysBase->ThisTask), arg); \
330 Prepare the cpu context
335 #define PREPARE_INITIAL_CONTEXT(task,startpc) \
336 asm volatile("fninit\n\t" \
338 "fwait" : "=m" (GetCpuContext(task)->fpstate))
342 #define PREPARE_INITIAL_CONTEXT(task,startpc)
347 Store first six arguments in registers, the rest on stack
350 #define PREPARE_INITIAL_ARGS(task, args, numargs) \
351 UQUAD* regs = GetIntETask (task)->iet_Context;\
352 int argcounter = numargs; \
353 while (argcounter > 6) \
354 _PUSH(GetSP(task), args[--argcounter]); \
355 switch (argcounter) \
373 This macro is similar to PREPARE_INITIAL_FRAME() but also saves
374 all general purpose registers. Use this macro when you want to
375 leave the current tasks' context to save the registers. Note that
376 the argument "sp" of the macro is just the name of the stack
377 pointer. The macro will load it from the sigcontext "sc". You
378 must store the value of "sp" after the macro and hand it to
379 RESTOREREGS() below to restore this context.
382 #define SAVEREGS(task,sc) \
385 struct AROS_cpu_context *cc = GetCpuContext(task); \
386 GetSP(task) = (SP_TYPE *)SP(sc); \
393 This macro does the opposite to SAVEREGS(). It restores all
394 general purpose registers. After that, you can enter the new
395 tasks' context. Both "sp" and "sc" must be initialized.
396 The macro will save the new SP into the sigcontext "sc".
399 # define RESTOREREGS(task,sc) \
402 struct AROS_cpu_context *cc = GetCpuContext(task); \
404 RESTORE_FPU(cc,sc); \
405 RESTORE_CPU(cc,sc); \
406 SP(sc) = (typeof(SP(sc)))GetSP(task); \
410 /* This macro prints the current signals' context */
411 #define PRINT_SC(sc) \
412 printf (" SP=%08lx FP=%08lx PC=%08lx FPU=%s\n" \
413 " R0=%08lx R1=%08lx R2=%08lx R3=%08lx\n" \
414 " R4=%08lx R5=%08lx R6=%08lx R7=%08lx\n" \
415 " R8=%08lx R9=%08lx R10=%08lx R11=%08lx\n" \
416 " R12=%08lx R13=%08lx R14=%08lx\n" \
417 , SP(sc), FP(sc), PC(sc) \
418 , HAS_FPU(sc) ? "yes" : "no" \
419 , R0(sc), R1(sc), R2(sc), R3(sc) \
420 , R4(sc), R5(sc), R6(sc), R7(sc), R8(sc), R9(sc) \
421 , R10(sc), R11(sc), R12(sc), R13(sc), R14(sc) \
424 /* This macro prints the current stack (after SAVEREGS()) */
425 #define PRINT_CPUCONTEXT(task) \
426 printf (" SP=%08lx FP=%08lx PC=%08lx\n" \
427 " R0=%08lx R1=%08lx R2=%08lx R3=%08lx\n" \
428 " R4=%08lx R5=%08lx\n" \
429 , (ULONG)(GetSP(task)) \
430 , GetCpuContext(task)->regs[15] \
431 , GetCpuContext(task)->regs[16] \
432 , GetCpuContext(task)->regs[0] \
433 , GetCpuContext(task)->regs[1] \
434 , GetCpuContext(task)->regs[2] \
435 , GetCpuContext(task)->regs[3] \
436 , GetCpuContext(task)->regs[4] \
437 , GetCpuContext(task)->regs[5] \
438 , GetCpuContext(task)->regs[6] \
439 , GetCpuContext(task)->regs[7] \
440 , GetCpuContext(task)->regs[8] \
441 , GetCpuContext(task)->regs[9] \
442 , GetCpuContext(task)->regs[10] \
443 , GetCpuContext(task)->regs[11] \
444 , GetCpuContext(task)->regs[12] \
445 , GetCpuContext(task)->regs[13] \
446 , GetCpuContext(task)->regs[14] \
449 #endif /* _SIGCORE_H */