5 Copyright © 1995-2013, The AROS Development Team. All rights reserved.
8 Desc: Macros to handle i386 Linux signals
12 #include <aros/i386/cpucontext.h>
14 /* Allocate legacy 80087 frame together with SSE frame */
15 #define USE_LEGACY_8087
17 /* Allocate 112 bytes for 8087 frame. It contains host_specific portion (status and magic). */
18 #define SIZEOF_8087_FRAME 112
20 #ifdef __AROS_EXEC_LIBRARY__
23 typedef struct sigcontext regs_t
;
27 #define USE_SA_SIGINFO 0
30 #define SIGCORE_NEED_SA_SIGINFO 1
36 /* Include generated fragment */
39 /* name and type of the signal handler */
40 #define SIGHANDLER linux_sighandler
41 #define SIGHANDLER_T SignalHandler
44 This macro contains some magic necessary to make it work.
45 The problem is that Linux offers no official way to obtain the
46 signals' context. Linux stores the signals' context on the
47 process' stack. It looks like this:
48 Attention: As of version 2.2 of the Linux kernel there is
49 not enough room on the stack anymore to save
50 any registers on it. So everything has to go into
51 the context structure. Previously PC and FP used
52 to be saved on the stack but now this would over-
53 write some return address.
54 The stack you see below is the stack of the last
55 active task within AROS. The linux kernel puts
56 all kinds of other junk on it.
59 +--------------------------+
60 | last entry before signal |
61 +--------------------------+
63 +--------------------------+
65 +--------------------------+
67 +--------------------------+
70 so the address of the signal context is &sig+1.
74 #define GLOBAL_SIGNAL_INIT(sighandler) \
75 static void sighandler ## _gate (int sig, siginfo_t *blub, struct ucontext *u) \
77 sighandler(sig, (regs_t *)&u->uc_mcontext); \
82 #define GLOBAL_SIGNAL_INIT(sighandler) \
83 static void sighandler ## _gate (int sig) \
85 sighandler (sig, (regs_t *)(&sig+1)); \
90 Macros to access the stack pointer, frame pointer and program
91 counter. The FP is the base address for accesses to arguments
92 and local variables of a function and PC is the current address
96 #define SP(sc) ((sc)->esp)
97 #define FP(sc) ((sc)->ebp)
98 #define PC(sc) ((sc)->eip)
101 Macros to enable or disable all signals after the signal handler
102 has returned and the normal execution commences.
104 WARNING!!! If you change #define USE_SA_SIGINFO to 1, this will
105 stop working! In this case Linux will use ucontext->uc_sigmask
106 to store original signal mask. See x86-64 and PPC implementation
107 of these macros for examples.
109 #ifdef HOST_OS_android
110 /* In Android's Bionic sigset_t is simply unsigned long */
111 #define SC_DISABLE(sc) ((sc)->oldmask = KernelBase->kb_PlatformData->sig_int_mask)
113 #define SC_DISABLE(sc) ((sc)->oldmask = KernelBase->kb_PlatformData->sig_int_mask.__val[0])
115 #define SC_ENABLE(sc) ((sc)->oldmask = 0L)
118 The names of the general purpose registers which are to be saved.
119 Use R and a number as name, no matter what the real name is.
120 General purpose registers (GPRs) are registers which can be
121 modified by the task (ie. data and address registers) and which are
122 not saved by the CPU when an interrupt happens.
124 #define R0(sc) ((sc)->eax)
125 #define R1(sc) ((sc)->ebx)
126 #define R2(sc) ((sc)->ecx)
127 #define R3(sc) ((sc)->edx)
128 #define R4(sc) ((sc)->edi)
129 #define R5(sc) ((sc)->esi)
130 #define R6(sc) ((sc)->eflags)
132 /* Save and restore the CPU GPRs in the CPU context */
133 #define SAVE_CPU(cc, sc) \
140 cc.eflags = R6(sc); \
145 #define RESTORE_CPU(cc, sc) \
152 R6(sc) = cc.eflags; \
159 It's not possible to save the FPU under linux because linux
160 uses the tasks stack to save the signal context. The signal
161 context conatins the SP *before* the sigcontext was pushed on
162 this stack, so it looks like this:
165 +--------------------------+
166 | last entry before signal |
167 +--------------------------+
168 | empty space | <--- SP
169 +--------------------------+
171 +--------------------------+
175 As you can see, SP points to the empty space. Now this empty space
176 is not very big. It's big enough that one can save the CPU
177 registers but not big enough for the FPU. *sigh*.
179 Attention: The above WAS TRUE for 2.0.x kernels but now the stack layout
180 looks different. See above!
182 Update: We store the registers in our own structure now
186 * This macro saves all registers. Use this macro when you
187 * want to leave the current task's context.
188 * If will also save FPU and SSE areas (if possible) and
189 * set appropriate context flags to indicate this.
191 #define SAVEREGS(cc, sc) \
192 SAVE_CPU((cc)->regs, sc); \
193 if ((cc)->regs.FPData && sc->fpstate) \
195 (cc)->regs.Flags |= ECF_FPU; \
196 CopyMemQuick(sc->fpstate, (cc)->regs.FPData, SIZEOF_8087_FRAME); \
197 if ((cc)->regs.FXData && (sc->fpstate->magic != 0xFFFF)) \
199 (cc)->regs.Flags |= ECF_FPX; \
200 CopyMemQuick(sc->fpstate->_fxsr_env, (cc)->regs.FXData, sizeof(struct FPXContext)); \
205 * This macro does the opposite to SAVEREGS(). It restores all registers.
206 * After that, you can enter the new task's context.
207 * FPU and SSE areas will be restored only if they were present in the
208 * saved context. This should be indicated by context's flags.
210 #define RESTOREREGS(cc, sc) \
211 RESTORE_CPU((cc)->regs, sc); \
214 if ((cc)->regs.Flags & ECF_FPU) \
215 CopyMemQuick((cc)->regs.FPData, sc->fpstate, SIZEOF_8087_FRAME); \
216 if ((cc)->regs.Flags & ECF_FPX) \
217 CopyMemQuick((cc)->regs.FXData, sc->fpstate->_fxsr_env, sizeof(struct FPXContext)); \
220 /* This macro prints the current signals' context */
221 #define PRINT_SC(sc) \
222 bug (" SP=%08lx FP=%08lx PC=%08lx\n" \
223 " R0=%08lx R1=%08lx R2=%08lx R3=%08lx\n" \
224 " R4=%08lx R5=%08lx\n" \
225 , SP(sc), FP(sc), PC(sc) \
226 , R0(sc), R1(sc), R2(sc), R3(sc) \
230 #endif /* __AROS_EXEC_LIBRARY__ */
232 #define EXCEPTIONS_COUNT 17
234 /* Use this structure to save/restore registers */
235 struct AROSCPUContext
237 struct ExceptionContext regs
; /* Public portion */
238 int errno_backup
; /* Host-specific stuff, private */
241 #endif /* _SIGCORE_H */