xref: /qemu/linux-user/i386/signal.c (revision a7365e984d27b961f381cf3be46682e4da5ab6f7)
1befb7447SLaurent Vivier /*
2befb7447SLaurent Vivier  *  Emulation of Linux signals
3befb7447SLaurent Vivier  *
4befb7447SLaurent Vivier  *  Copyright (c) 2003 Fabrice Bellard
5befb7447SLaurent Vivier  *
6befb7447SLaurent Vivier  *  This program is free software; you can redistribute it and/or modify
7befb7447SLaurent Vivier  *  it under the terms of the GNU General Public License as published by
8befb7447SLaurent Vivier  *  the Free Software Foundation; either version 2 of the License, or
9befb7447SLaurent Vivier  *  (at your option) any later version.
10befb7447SLaurent Vivier  *
11befb7447SLaurent Vivier  *  This program is distributed in the hope that it will be useful,
12befb7447SLaurent Vivier  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13befb7447SLaurent Vivier  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14befb7447SLaurent Vivier  *  GNU General Public License for more details.
15befb7447SLaurent Vivier  *
16befb7447SLaurent Vivier  *  You should have received a copy of the GNU General Public License
17befb7447SLaurent Vivier  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18befb7447SLaurent Vivier  */
19a075f313SLaurent Vivier #include "qemu/osdep.h"
20a075f313SLaurent Vivier #include "qemu.h"
213b249d26SPeter Maydell #include "user-internals.h"
22a075f313SLaurent Vivier #include "signal-common.h"
23a075f313SLaurent Vivier #include "linux-user/trace.h"
2482723866SPhilippe Mathieu-Daudé #include "user/tswap-target.h"
25a075f313SLaurent Vivier 
26a075f313SLaurent Vivier /* from the Linux kernel - /arch/x86/include/uapi/asm/sigcontext.h */
27a075f313SLaurent Vivier 
285d245678SPaolo Bonzini #define TARGET_FP_XSTATE_MAGIC1         0x46505853U /* FPXS */
295d245678SPaolo Bonzini #define TARGET_FP_XSTATE_MAGIC2         0x46505845U /* FPXE */
305d245678SPaolo Bonzini #define TARGET_FP_XSTATE_MAGIC2_SIZE    4
315d245678SPaolo Bonzini 
32a075f313SLaurent Vivier struct target_fpreg {
33a075f313SLaurent Vivier     uint16_t significand[4];
34a075f313SLaurent Vivier     uint16_t exponent;
35a075f313SLaurent Vivier };
36a075f313SLaurent Vivier 
375cc77ebeSRichard Henderson /* Legacy x87 fpu state format for FSAVE/FRESTOR. */
385cc77ebeSRichard Henderson struct target_fregs_state {
395cc77ebeSRichard Henderson     uint32_t cwd;
405cc77ebeSRichard Henderson     uint32_t swd;
415cc77ebeSRichard Henderson     uint32_t twd;
425cc77ebeSRichard Henderson     uint32_t fip;
435cc77ebeSRichard Henderson     uint32_t fcs;
445cc77ebeSRichard Henderson     uint32_t foo;
455cc77ebeSRichard Henderson     uint32_t fos;
465cc77ebeSRichard Henderson     struct target_fpreg st[8];
475cc77ebeSRichard Henderson 
485cc77ebeSRichard Henderson     /* Software status information [not touched by FSAVE]. */
495cc77ebeSRichard Henderson     uint16_t status;
505cc77ebeSRichard Henderson     uint16_t magic;   /* 0xffff: FPU data only, 0x0000: FXSR FPU data */
515cc77ebeSRichard Henderson };
525cc77ebeSRichard Henderson QEMU_BUILD_BUG_ON(sizeof(struct target_fregs_state) != 32 + 80);
535cc77ebeSRichard Henderson 
545d245678SPaolo Bonzini struct target_fpx_sw_bytes {
555d245678SPaolo Bonzini     uint32_t magic1;
565d245678SPaolo Bonzini     uint32_t extended_size;
575d245678SPaolo Bonzini     uint64_t xfeatures;
585d245678SPaolo Bonzini     uint32_t xstate_size;
595d245678SPaolo Bonzini     uint32_t reserved[7];
605d245678SPaolo Bonzini };
615d245678SPaolo Bonzini QEMU_BUILD_BUG_ON(sizeof(struct target_fpx_sw_bytes) != 12*4);
625d245678SPaolo Bonzini 
632796f290SPaolo Bonzini struct target_fpstate_32 {
645cc77ebeSRichard Henderson     struct target_fregs_state fpstate;
655cc77ebeSRichard Henderson     X86LegacyXSaveArea fxstate;
662796f290SPaolo Bonzini };
672796f290SPaolo Bonzini 
68a075f313SLaurent Vivier struct target_sigcontext_32 {
69a075f313SLaurent Vivier     uint16_t gs, __gsh;
70a075f313SLaurent Vivier     uint16_t fs, __fsh;
71a075f313SLaurent Vivier     uint16_t es, __esh;
72a075f313SLaurent Vivier     uint16_t ds, __dsh;
73a075f313SLaurent Vivier     uint32_t edi;
74a075f313SLaurent Vivier     uint32_t esi;
75a075f313SLaurent Vivier     uint32_t ebp;
76a075f313SLaurent Vivier     uint32_t esp;
77a075f313SLaurent Vivier     uint32_t ebx;
78a075f313SLaurent Vivier     uint32_t edx;
79a075f313SLaurent Vivier     uint32_t ecx;
80a075f313SLaurent Vivier     uint32_t eax;
81a075f313SLaurent Vivier     uint32_t trapno;
82a075f313SLaurent Vivier     uint32_t err;
83a075f313SLaurent Vivier     uint32_t eip;
84a075f313SLaurent Vivier     uint16_t cs, __csh;
85a075f313SLaurent Vivier     uint32_t eflags;
86a075f313SLaurent Vivier     uint32_t esp_at_signal;
87a075f313SLaurent Vivier     uint16_t ss, __ssh;
88a075f313SLaurent Vivier     uint32_t fpstate; /* pointer */
89a075f313SLaurent Vivier     uint32_t oldmask;
90a075f313SLaurent Vivier     uint32_t cr2;
91a075f313SLaurent Vivier };
92a075f313SLaurent Vivier 
93a075f313SLaurent Vivier struct target_sigcontext_64 {
94a075f313SLaurent Vivier     uint64_t r8;
95a075f313SLaurent Vivier     uint64_t r9;
96a075f313SLaurent Vivier     uint64_t r10;
97a075f313SLaurent Vivier     uint64_t r11;
98a075f313SLaurent Vivier     uint64_t r12;
99a075f313SLaurent Vivier     uint64_t r13;
100a075f313SLaurent Vivier     uint64_t r14;
101a075f313SLaurent Vivier     uint64_t r15;
102a075f313SLaurent Vivier 
103a075f313SLaurent Vivier     uint64_t rdi;
104a075f313SLaurent Vivier     uint64_t rsi;
105a075f313SLaurent Vivier     uint64_t rbp;
106a075f313SLaurent Vivier     uint64_t rbx;
107a075f313SLaurent Vivier     uint64_t rdx;
108a075f313SLaurent Vivier     uint64_t rax;
109a075f313SLaurent Vivier     uint64_t rcx;
110a075f313SLaurent Vivier     uint64_t rsp;
111a075f313SLaurent Vivier     uint64_t rip;
112a075f313SLaurent Vivier 
113a075f313SLaurent Vivier     uint64_t eflags;
114a075f313SLaurent Vivier 
115a075f313SLaurent Vivier     uint16_t cs;
116a075f313SLaurent Vivier     uint16_t gs;
117a075f313SLaurent Vivier     uint16_t fs;
118a075f313SLaurent Vivier     uint16_t ss;
119a075f313SLaurent Vivier 
120a075f313SLaurent Vivier     uint64_t err;
121a075f313SLaurent Vivier     uint64_t trapno;
122a075f313SLaurent Vivier     uint64_t oldmask;
123a075f313SLaurent Vivier     uint64_t cr2;
124a075f313SLaurent Vivier 
125a075f313SLaurent Vivier     uint64_t fpstate; /* pointer */
126a075f313SLaurent Vivier     uint64_t padding[8];
127a075f313SLaurent Vivier };
128a075f313SLaurent Vivier 
129a075f313SLaurent Vivier #ifndef TARGET_X86_64
130a075f313SLaurent Vivier # define target_sigcontext target_sigcontext_32
131a075f313SLaurent Vivier #else
132a075f313SLaurent Vivier # define target_sigcontext target_sigcontext_64
133a075f313SLaurent Vivier #endif
134a075f313SLaurent Vivier 
135a075f313SLaurent Vivier /* see Linux/include/uapi/asm-generic/ucontext.h */
136a075f313SLaurent Vivier struct target_ucontext {
137a075f313SLaurent Vivier     abi_ulong         tuc_flags;
138a075f313SLaurent Vivier     abi_ulong         tuc_link;
139a075f313SLaurent Vivier     target_stack_t    tuc_stack;
140a075f313SLaurent Vivier     struct target_sigcontext tuc_mcontext;
141a075f313SLaurent Vivier     target_sigset_t   tuc_sigmask;  /* mask last for extensibility */
142a075f313SLaurent Vivier };
143a075f313SLaurent Vivier 
144a075f313SLaurent Vivier #ifndef TARGET_X86_64
145a075f313SLaurent Vivier struct sigframe {
146a075f313SLaurent Vivier     abi_ulong pretcode;
147a075f313SLaurent Vivier     int sig;
148a075f313SLaurent Vivier     struct target_sigcontext sc;
1495154d35bSPaolo Bonzini     /*
150*a7365e98SRichard Henderson      * The actual fpstate is placed after retcode[] below, to make room
151*a7365e98SRichard Henderson      * for the variable-sized xsave data.  The older unused fpstate has
152*a7365e98SRichard Henderson      * to be kept to avoid changing the offset of extramask[], which
1535154d35bSPaolo Bonzini      * is part of the ABI.
1545154d35bSPaolo Bonzini      */
155*a7365e98SRichard Henderson     struct target_fpstate_32 fpstate_unused;
156a075f313SLaurent Vivier     abi_ulong extramask[TARGET_NSIG_WORDS-1];
157a075f313SLaurent Vivier     char retcode[8];
158*a7365e98SRichard Henderson     /* fp state follows here */
159a075f313SLaurent Vivier };
160a075f313SLaurent Vivier 
161a075f313SLaurent Vivier struct rt_sigframe {
162a075f313SLaurent Vivier     abi_ulong pretcode;
163a075f313SLaurent Vivier     int sig;
164a075f313SLaurent Vivier     abi_ulong pinfo;
165a075f313SLaurent Vivier     abi_ulong puc;
166a075f313SLaurent Vivier     struct target_siginfo info;
167a075f313SLaurent Vivier     struct target_ucontext uc;
168a075f313SLaurent Vivier     char retcode[8];
169*a7365e98SRichard Henderson     /* fp state follows here */
170a075f313SLaurent Vivier };
171a1367443SRichard Henderson 
172a1367443SRichard Henderson /*
173a1367443SRichard Henderson  * Verify that vdso-asmoffset.h constants match.
174a1367443SRichard Henderson  */
175a1367443SRichard Henderson #include "i386/vdso-asmoffset.h"
176a1367443SRichard Henderson 
177a1367443SRichard Henderson QEMU_BUILD_BUG_ON(offsetof(struct sigframe, sc.eip)
178a1367443SRichard Henderson                   != SIGFRAME_SIGCONTEXT_eip);
179a1367443SRichard Henderson QEMU_BUILD_BUG_ON(offsetof(struct rt_sigframe, uc.tuc_mcontext.eip)
180a1367443SRichard Henderson                   != RT_SIGFRAME_SIGCONTEXT_eip);
181a1367443SRichard Henderson 
182a075f313SLaurent Vivier #else
183a075f313SLaurent Vivier 
184a075f313SLaurent Vivier struct rt_sigframe {
185a075f313SLaurent Vivier     abi_ulong pretcode;
186a075f313SLaurent Vivier     struct target_ucontext uc;
187a075f313SLaurent Vivier     struct target_siginfo info;
188*a7365e98SRichard Henderson     /* fp state follows here */
189a075f313SLaurent Vivier };
190a075f313SLaurent Vivier #endif
191a075f313SLaurent Vivier 
192*a7365e98SRichard Henderson typedef enum {
193*a7365e98SRichard Henderson #ifndef TARGET_X86_64
194*a7365e98SRichard Henderson     FPSTATE_FSAVE,
195*a7365e98SRichard Henderson #endif
196*a7365e98SRichard Henderson     FPSTATE_FXSAVE,
197*a7365e98SRichard Henderson     FPSTATE_XSAVE
198*a7365e98SRichard Henderson } FPStateKind;
199*a7365e98SRichard Henderson 
200*a7365e98SRichard Henderson static FPStateKind get_fpstate_kind(CPUX86State *env)
201*a7365e98SRichard Henderson {
202*a7365e98SRichard Henderson     if (env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE) {
203*a7365e98SRichard Henderson         return FPSTATE_XSAVE;
204*a7365e98SRichard Henderson     }
205*a7365e98SRichard Henderson #ifdef TARGET_X86_64
206*a7365e98SRichard Henderson     return FPSTATE_FXSAVE;
207*a7365e98SRichard Henderson #else
208*a7365e98SRichard Henderson     if (env->features[FEAT_1_EDX] & CPUID_FXSR) {
209*a7365e98SRichard Henderson         return FPSTATE_FXSAVE;
210*a7365e98SRichard Henderson     }
211*a7365e98SRichard Henderson     return FPSTATE_FSAVE;
212*a7365e98SRichard Henderson #endif
213*a7365e98SRichard Henderson }
214*a7365e98SRichard Henderson 
215*a7365e98SRichard Henderson static unsigned get_fpstate_size(CPUX86State *env, FPStateKind fpkind)
216*a7365e98SRichard Henderson {
217*a7365e98SRichard Henderson     /*
218*a7365e98SRichard Henderson      * Kernel:
219*a7365e98SRichard Henderson      *   fpu__alloc_mathframe
220*a7365e98SRichard Henderson      *     xstate_sigframe_size(current->thread.fpu.fpstate);
221*a7365e98SRichard Henderson      *       size = fpstate->user_size
222*a7365e98SRichard Henderson      *       use_xsave() ? size + FP_XSTATE_MAGIC2_SIZE : size
223*a7365e98SRichard Henderson      *   where fpstate->user_size is computed at init in
224*a7365e98SRichard Henderson      *   fpu__init_system_xstate_size_legacy and
225*a7365e98SRichard Henderson      *   fpu__init_system_xstate.
226*a7365e98SRichard Henderson      *
227*a7365e98SRichard Henderson      * Here we have no place to pre-compute, so inline it all.
228*a7365e98SRichard Henderson      */
229*a7365e98SRichard Henderson     switch (fpkind) {
230*a7365e98SRichard Henderson     case FPSTATE_XSAVE:
231*a7365e98SRichard Henderson         return (xsave_area_size(env->xcr0, false)
232*a7365e98SRichard Henderson                 + TARGET_FP_XSTATE_MAGIC2_SIZE);
233*a7365e98SRichard Henderson     case FPSTATE_FXSAVE:
234*a7365e98SRichard Henderson         return sizeof(X86LegacyXSaveArea);
235*a7365e98SRichard Henderson #ifndef TARGET_X86_64
236*a7365e98SRichard Henderson     case FPSTATE_FSAVE:
237*a7365e98SRichard Henderson         return sizeof(struct target_fregs_state);
238*a7365e98SRichard Henderson #endif
239*a7365e98SRichard Henderson     }
240*a7365e98SRichard Henderson     g_assert_not_reached();
241*a7365e98SRichard Henderson }
242*a7365e98SRichard Henderson 
243*a7365e98SRichard Henderson static abi_ptr get_sigframe(struct target_sigaction *ka, CPUX86State *env,
244*a7365e98SRichard Henderson                             unsigned frame_size, FPStateKind fpkind,
245*a7365e98SRichard Henderson                             abi_ptr *fpstate, abi_ptr *fxstate, abi_ptr *fpend)
246*a7365e98SRichard Henderson {
247*a7365e98SRichard Henderson     abi_ptr sp;
248*a7365e98SRichard Henderson     unsigned math_size;
249*a7365e98SRichard Henderson 
250*a7365e98SRichard Henderson     /* Default to using normal stack */
251*a7365e98SRichard Henderson     sp = get_sp_from_cpustate(env);
252*a7365e98SRichard Henderson #ifdef TARGET_X86_64
253*a7365e98SRichard Henderson     sp -= 128; /* this is the redzone */
254*a7365e98SRichard Henderson #endif
255*a7365e98SRichard Henderson 
256*a7365e98SRichard Henderson     /* This is the X/Open sanctioned signal stack switching.  */
257*a7365e98SRichard Henderson     if (ka->sa_flags & TARGET_SA_ONSTACK) {
258*a7365e98SRichard Henderson         sp = target_sigsp(sp, ka);
259*a7365e98SRichard Henderson     } else {
260*a7365e98SRichard Henderson #ifndef TARGET_X86_64
261*a7365e98SRichard Henderson         /* This is the legacy signal stack switching. */
262*a7365e98SRichard Henderson         if ((env->segs[R_SS].selector & 0xffff) != __USER_DS
263*a7365e98SRichard Henderson             && !(ka->sa_flags & TARGET_SA_RESTORER)
264*a7365e98SRichard Henderson             && ka->sa_restorer) {
265*a7365e98SRichard Henderson             sp = ka->sa_restorer;
266*a7365e98SRichard Henderson         }
267*a7365e98SRichard Henderson #endif
268*a7365e98SRichard Henderson     }
269*a7365e98SRichard Henderson 
270*a7365e98SRichard Henderson     math_size = get_fpstate_size(env, fpkind);
271*a7365e98SRichard Henderson     sp = ROUND_DOWN(sp - math_size, 64);
272*a7365e98SRichard Henderson     *fpend = sp + math_size;
273*a7365e98SRichard Henderson     *fxstate = sp;
274*a7365e98SRichard Henderson #ifndef TARGET_X86_64
275*a7365e98SRichard Henderson     if (fpkind != FPSTATE_FSAVE) {
276*a7365e98SRichard Henderson         sp -= sizeof(struct target_fregs_state);
277*a7365e98SRichard Henderson     }
278*a7365e98SRichard Henderson #endif
279*a7365e98SRichard Henderson     *fpstate = sp;
280*a7365e98SRichard Henderson 
281*a7365e98SRichard Henderson     sp -= frame_size;
282*a7365e98SRichard Henderson     /*
283*a7365e98SRichard Henderson      * Align the stack pointer according to the ABI, i.e. so that on
284*a7365e98SRichard Henderson      * function entry ((sp + sizeof(return_addr)) & 15) == 0.
285*a7365e98SRichard Henderson      */
286*a7365e98SRichard Henderson     sp += sizeof(target_ulong);
287*a7365e98SRichard Henderson     sp = ROUND_DOWN(sp, 16);
288*a7365e98SRichard Henderson     sp -= sizeof(target_ulong);
289*a7365e98SRichard Henderson 
290*a7365e98SRichard Henderson     return sp;
291*a7365e98SRichard Henderson }
292*a7365e98SRichard Henderson 
293a075f313SLaurent Vivier /*
294a075f313SLaurent Vivier  * Set up a signal frame.
295a075f313SLaurent Vivier  */
296a075f313SLaurent Vivier 
297*a7365e98SRichard Henderson static void fxsave_sigcontext(CPUX86State *env, X86LegacyXSaveArea *fxstate,
298*a7365e98SRichard Henderson                               abi_ptr fxstate_addr)
2992796f290SPaolo Bonzini {
300*a7365e98SRichard Henderson     struct target_fpx_sw_bytes *sw = (void *)&fxstate->sw_reserved;
3013b6e9491SRichard Henderson 
302*a7365e98SRichard Henderson     /* fxstate_addr must be 16 byte aligned for fxsave */
303*a7365e98SRichard Henderson     assert(!(fxstate_addr & 0xf));
304*a7365e98SRichard Henderson     cpu_x86_fxsave(env, fxstate_addr);
3053b6e9491SRichard Henderson     __put_user(0, &sw->magic1);
306*a7365e98SRichard Henderson }
3075d245678SPaolo Bonzini 
308*a7365e98SRichard Henderson static void xsave_sigcontext(CPUX86State *env,
309*a7365e98SRichard Henderson                              X86LegacyXSaveArea *fxstate,
310*a7365e98SRichard Henderson                              abi_ptr fpstate_addr,
311*a7365e98SRichard Henderson                              abi_ptr xstate_addr,
312*a7365e98SRichard Henderson                              abi_ptr fpend_addr)
313*a7365e98SRichard Henderson {
314*a7365e98SRichard Henderson     struct target_fpx_sw_bytes *sw = (void *)&fxstate->sw_reserved;
3155d245678SPaolo Bonzini     /*
316*a7365e98SRichard Henderson      * extended_size is the offset from fpstate_addr to right after
317*a7365e98SRichard Henderson      * the end of the extended save states.  On 32-bit that includes
318*a7365e98SRichard Henderson      * the legacy FSAVE area.
3195d245678SPaolo Bonzini      */
320*a7365e98SRichard Henderson     uint32_t extended_size = fpend_addr - fpstate_addr;
321*a7365e98SRichard Henderson     /* Recover xstate_size by removing magic2. */
322*a7365e98SRichard Henderson     uint32_t xstate_size = (fpend_addr - xstate_addr
323*a7365e98SRichard Henderson                             - TARGET_FP_XSTATE_MAGIC2_SIZE);
324*a7365e98SRichard Henderson     /* magic2 goes just after xstate. */
325*a7365e98SRichard Henderson     uint32_t *magic2 = (void *)fxstate + xstate_size;
3265d245678SPaolo Bonzini 
327*a7365e98SRichard Henderson     /* xstate_addr must be 64 byte aligned for xsave */
328*a7365e98SRichard Henderson     assert(!(xstate_addr & 0x3f));
3295d245678SPaolo Bonzini 
3305d245678SPaolo Bonzini     /* Zero the header, XSAVE *adds* features to an existing save state.  */
331*a7365e98SRichard Henderson     memset(fxstate + 1, 0, sizeof(X86XSaveHeader));
332*a7365e98SRichard Henderson     cpu_x86_xsave(env, xstate_addr, -1);
333*a7365e98SRichard Henderson 
3343b6e9491SRichard Henderson     __put_user(TARGET_FP_XSTATE_MAGIC1, &sw->magic1);
3353b6e9491SRichard Henderson     __put_user(extended_size, &sw->extended_size);
3363b6e9491SRichard Henderson     __put_user(env->xcr0, &sw->xfeatures);
3373b6e9491SRichard Henderson     __put_user(xstate_size, &sw->xstate_size);
338*a7365e98SRichard Henderson     __put_user(TARGET_FP_XSTATE_MAGIC2, magic2);
3392796f290SPaolo Bonzini }
3402796f290SPaolo Bonzini 
341*a7365e98SRichard Henderson static void setup_sigcontext(CPUX86State *env,
342*a7365e98SRichard Henderson                              struct target_sigcontext *sc,
343*a7365e98SRichard Henderson                              abi_ulong mask, FPStateKind fpkind,
344*a7365e98SRichard Henderson                              struct target_fregs_state *fpstate,
345*a7365e98SRichard Henderson                              abi_ptr fpstate_addr,
346*a7365e98SRichard Henderson                              X86LegacyXSaveArea *fxstate,
347*a7365e98SRichard Henderson                              abi_ptr fxstate_addr,
348*a7365e98SRichard Henderson                              abi_ptr fpend_addr)
349a075f313SLaurent Vivier {
3506aa9e42fSRichard Henderson     CPUState *cs = env_cpu(env);
351*a7365e98SRichard Henderson 
352a075f313SLaurent Vivier #ifndef TARGET_X86_64
353a075f313SLaurent Vivier     uint16_t magic;
354a075f313SLaurent Vivier 
355a075f313SLaurent Vivier     /* already locked in setup_frame() */
356*a7365e98SRichard Henderson     __put_user(env->segs[R_GS].selector, (uint32_t *)&sc->gs);
357*a7365e98SRichard Henderson     __put_user(env->segs[R_FS].selector, (uint32_t *)&sc->fs);
358*a7365e98SRichard Henderson     __put_user(env->segs[R_ES].selector, (uint32_t *)&sc->es);
359*a7365e98SRichard Henderson     __put_user(env->segs[R_DS].selector, (uint32_t *)&sc->ds);
360a075f313SLaurent Vivier     __put_user(env->regs[R_EDI], &sc->edi);
361a075f313SLaurent Vivier     __put_user(env->regs[R_ESI], &sc->esi);
362a075f313SLaurent Vivier     __put_user(env->regs[R_EBP], &sc->ebp);
363a075f313SLaurent Vivier     __put_user(env->regs[R_ESP], &sc->esp);
364a075f313SLaurent Vivier     __put_user(env->regs[R_EBX], &sc->ebx);
365a075f313SLaurent Vivier     __put_user(env->regs[R_EDX], &sc->edx);
366a075f313SLaurent Vivier     __put_user(env->regs[R_ECX], &sc->ecx);
367a075f313SLaurent Vivier     __put_user(env->regs[R_EAX], &sc->eax);
368a075f313SLaurent Vivier     __put_user(cs->exception_index, &sc->trapno);
369a075f313SLaurent Vivier     __put_user(env->error_code, &sc->err);
370a075f313SLaurent Vivier     __put_user(env->eip, &sc->eip);
371*a7365e98SRichard Henderson     __put_user(env->segs[R_CS].selector, (uint32_t *)&sc->cs);
372a075f313SLaurent Vivier     __put_user(env->eflags, &sc->eflags);
373a075f313SLaurent Vivier     __put_user(env->regs[R_ESP], &sc->esp_at_signal);
374*a7365e98SRichard Henderson     __put_user(env->segs[R_SS].selector, (uint32_t *)&sc->ss);
375a075f313SLaurent Vivier 
376a075f313SLaurent Vivier     cpu_x86_fsave(env, fpstate_addr, 1);
377*a7365e98SRichard Henderson     fpstate->status = fpstate->swd;
378*a7365e98SRichard Henderson     magic = (fpkind == FPSTATE_FSAVE ? 0 : 0xffff);
379*a7365e98SRichard Henderson     __put_user(magic, &fpstate->magic);
380a075f313SLaurent Vivier #else
381a075f313SLaurent Vivier     __put_user(env->regs[R_EDI], &sc->rdi);
382a075f313SLaurent Vivier     __put_user(env->regs[R_ESI], &sc->rsi);
383a075f313SLaurent Vivier     __put_user(env->regs[R_EBP], &sc->rbp);
384a075f313SLaurent Vivier     __put_user(env->regs[R_ESP], &sc->rsp);
385a075f313SLaurent Vivier     __put_user(env->regs[R_EBX], &sc->rbx);
386a075f313SLaurent Vivier     __put_user(env->regs[R_EDX], &sc->rdx);
387a075f313SLaurent Vivier     __put_user(env->regs[R_ECX], &sc->rcx);
388a075f313SLaurent Vivier     __put_user(env->regs[R_EAX], &sc->rax);
389a075f313SLaurent Vivier 
390a075f313SLaurent Vivier     __put_user(env->regs[8], &sc->r8);
391a075f313SLaurent Vivier     __put_user(env->regs[9], &sc->r9);
392a075f313SLaurent Vivier     __put_user(env->regs[10], &sc->r10);
393a075f313SLaurent Vivier     __put_user(env->regs[11], &sc->r11);
394a075f313SLaurent Vivier     __put_user(env->regs[12], &sc->r12);
395a075f313SLaurent Vivier     __put_user(env->regs[13], &sc->r13);
396a075f313SLaurent Vivier     __put_user(env->regs[14], &sc->r14);
397a075f313SLaurent Vivier     __put_user(env->regs[15], &sc->r15);
398a075f313SLaurent Vivier 
399a075f313SLaurent Vivier     __put_user(cs->exception_index, &sc->trapno);
400a075f313SLaurent Vivier     __put_user(env->error_code, &sc->err);
401a075f313SLaurent Vivier     __put_user(env->eip, &sc->rip);
402a075f313SLaurent Vivier 
403a075f313SLaurent Vivier     __put_user(env->eflags, &sc->eflags);
404a075f313SLaurent Vivier     __put_user(env->segs[R_CS].selector, &sc->cs);
405a075f313SLaurent Vivier     __put_user((uint16_t)0, &sc->gs);
406a075f313SLaurent Vivier     __put_user((uint16_t)0, &sc->fs);
407a075f313SLaurent Vivier     __put_user(env->segs[R_SS].selector, &sc->ss);
4082796f290SPaolo Bonzini #endif
4092796f290SPaolo Bonzini 
410*a7365e98SRichard Henderson     switch (fpkind) {
411*a7365e98SRichard Henderson     case FPSTATE_XSAVE:
412*a7365e98SRichard Henderson         xsave_sigcontext(env, fxstate, fpstate_addr, fxstate_addr, fpend_addr);
413*a7365e98SRichard Henderson         break;
414*a7365e98SRichard Henderson     case FPSTATE_FXSAVE:
415*a7365e98SRichard Henderson         fxsave_sigcontext(env, fxstate, fxstate_addr);
416*a7365e98SRichard Henderson         break;
417*a7365e98SRichard Henderson     default:
418*a7365e98SRichard Henderson         break;
419*a7365e98SRichard Henderson     }
4202796f290SPaolo Bonzini 
421*a7365e98SRichard Henderson     __put_user(fpstate_addr, &sc->fpstate);
4222796f290SPaolo Bonzini     /* non-iBCS2 extensions.. */
423a075f313SLaurent Vivier     __put_user(mask, &sc->oldmask);
424a075f313SLaurent Vivier     __put_user(env->cr[2], &sc->cr2);
425a075f313SLaurent Vivier }
426a075f313SLaurent Vivier 
427a075f313SLaurent Vivier #ifndef TARGET_X86_64
4288ee8a104SRichard Henderson static void install_sigtramp(void *tramp)
4298ee8a104SRichard Henderson {
4308ee8a104SRichard Henderson     /* This is popl %eax ; movl $syscall,%eax ; int $0x80 */
4318ee8a104SRichard Henderson     __put_user(0xb858, (uint16_t *)(tramp + 0));
4328ee8a104SRichard Henderson     __put_user(TARGET_NR_sigreturn, (int32_t *)(tramp + 2));
4338ee8a104SRichard Henderson     __put_user(0x80cd, (uint16_t *)(tramp + 6));
4348ee8a104SRichard Henderson }
4358ee8a104SRichard Henderson 
4368ee8a104SRichard Henderson static void install_rt_sigtramp(void *tramp)
4378ee8a104SRichard Henderson {
4388ee8a104SRichard Henderson     /* This is movl $syscall,%eax ; int $0x80 */
4398ee8a104SRichard Henderson     __put_user(0xb8, (uint8_t *)(tramp + 0));
4408ee8a104SRichard Henderson     __put_user(TARGET_NR_rt_sigreturn, (int32_t *)(tramp + 1));
4418ee8a104SRichard Henderson     __put_user(0x80cd, (uint16_t *)(tramp + 5));
4428ee8a104SRichard Henderson }
4438ee8a104SRichard Henderson 
444a075f313SLaurent Vivier /* compare linux/arch/i386/kernel/signal.c:setup_frame() */
445a075f313SLaurent Vivier void setup_frame(int sig, struct target_sigaction *ka,
446a075f313SLaurent Vivier                  target_sigset_t *set, CPUX86State *env)
447a075f313SLaurent Vivier {
448*a7365e98SRichard Henderson     abi_ptr frame_addr, fpstate_addr, fxstate_addr, fpend_addr;
449a075f313SLaurent Vivier     struct sigframe *frame;
450*a7365e98SRichard Henderson     struct target_fregs_state *fpstate;
451*a7365e98SRichard Henderson     X86LegacyXSaveArea *fxstate;
452*a7365e98SRichard Henderson     unsigned total_size;
453*a7365e98SRichard Henderson     FPStateKind fpkind;
454a075f313SLaurent Vivier 
455*a7365e98SRichard Henderson     fpkind = get_fpstate_kind(env);
456*a7365e98SRichard Henderson     frame_addr = get_sigframe(ka, env, sizeof(struct sigframe), fpkind,
457*a7365e98SRichard Henderson                               &fpstate_addr, &fxstate_addr, &fpend_addr);
458a075f313SLaurent Vivier     trace_user_setup_frame(env, frame_addr);
459a075f313SLaurent Vivier 
460*a7365e98SRichard Henderson     total_size = fpend_addr - frame_addr;
461*a7365e98SRichard Henderson     frame = lock_user(VERIFY_WRITE, frame_addr, total_size, 0);
462*a7365e98SRichard Henderson     if (!frame) {
463*a7365e98SRichard Henderson         force_sigsegv(sig);
464*a7365e98SRichard Henderson         return;
465*a7365e98SRichard Henderson     }
466a075f313SLaurent Vivier 
467*a7365e98SRichard Henderson     fxstate = (void *)frame + (fxstate_addr - frame_addr);
468*a7365e98SRichard Henderson #ifdef TARGET_X86_64
469*a7365e98SRichard Henderson     fpstate = NULL;
470*a7365e98SRichard Henderson #else
471*a7365e98SRichard Henderson     fpstate = (void *)frame + (fpstate_addr - frame_addr);
472*a7365e98SRichard Henderson #endif
473a075f313SLaurent Vivier 
474*a7365e98SRichard Henderson     setup_sigcontext(env, &frame->sc, set->sig[0], fpkind,
475*a7365e98SRichard Henderson                      fpstate, fpstate_addr, fxstate, fxstate_addr, fpend_addr);
476*a7365e98SRichard Henderson 
477*a7365e98SRichard Henderson     for (int i = 1; i < TARGET_NSIG_WORDS; i++) {
478a075f313SLaurent Vivier         __put_user(set->sig[i], &frame->extramask[i - 1]);
479a075f313SLaurent Vivier     }
480a075f313SLaurent Vivier 
481a075f313SLaurent Vivier     /* Set up to return from userspace.  If provided, use a stub
482a075f313SLaurent Vivier        already in userspace.  */
483a075f313SLaurent Vivier     if (ka->sa_flags & TARGET_SA_RESTORER) {
484a075f313SLaurent Vivier         __put_user(ka->sa_restorer, &frame->pretcode);
485a075f313SLaurent Vivier     } else {
4868ee8a104SRichard Henderson         /* This is no longer used, but is retained for ABI compatibility. */
4878ee8a104SRichard Henderson         install_sigtramp(frame->retcode);
4888ee8a104SRichard Henderson         __put_user(default_sigreturn, &frame->pretcode);
489a075f313SLaurent Vivier     }
490*a7365e98SRichard Henderson     unlock_user(frame, frame_addr, total_size);
491a075f313SLaurent Vivier 
492a075f313SLaurent Vivier     /* Set up registers for signal handler */
493a075f313SLaurent Vivier     env->regs[R_ESP] = frame_addr;
494a075f313SLaurent Vivier     env->eip = ka->_sa_handler;
495a075f313SLaurent Vivier 
496bae0455cSRichard Henderson     /* Store argument for both -mregparm=3 and standard. */
497bae0455cSRichard Henderson     env->regs[R_EAX] = sig;
498bae0455cSRichard Henderson     __put_user(sig, &frame->sig);
499bae0455cSRichard Henderson     /* The kernel clears EDX and ECX even though there is only one arg. */
500bae0455cSRichard Henderson     env->regs[R_EDX] = 0;
501bae0455cSRichard Henderson     env->regs[R_ECX] = 0;
502bae0455cSRichard Henderson 
503a075f313SLaurent Vivier     cpu_x86_load_seg(env, R_DS, __USER_DS);
504a075f313SLaurent Vivier     cpu_x86_load_seg(env, R_ES, __USER_DS);
505a075f313SLaurent Vivier     cpu_x86_load_seg(env, R_SS, __USER_DS);
506a075f313SLaurent Vivier     cpu_x86_load_seg(env, R_CS, __USER_CS);
507a075f313SLaurent Vivier     env->eflags &= ~TF_MASK;
508a075f313SLaurent Vivier }
509a075f313SLaurent Vivier #endif
510a075f313SLaurent Vivier 
511a075f313SLaurent Vivier /* compare linux/arch/x86/kernel/signal.c:setup_rt_frame() */
512a075f313SLaurent Vivier void setup_rt_frame(int sig, struct target_sigaction *ka,
513a075f313SLaurent Vivier                     target_siginfo_t *info,
514a075f313SLaurent Vivier                     target_sigset_t *set, CPUX86State *env)
515a075f313SLaurent Vivier {
516*a7365e98SRichard Henderson     abi_ptr frame_addr, fpstate_addr, fxstate_addr, fpend_addr;
517a075f313SLaurent Vivier     struct rt_sigframe *frame;
518*a7365e98SRichard Henderson     X86LegacyXSaveArea *fxstate;
519*a7365e98SRichard Henderson     struct target_fregs_state *fpstate;
520*a7365e98SRichard Henderson     unsigned total_size;
521*a7365e98SRichard Henderson     FPStateKind fpkind;
522a075f313SLaurent Vivier 
523*a7365e98SRichard Henderson     fpkind = get_fpstate_kind(env);
524*a7365e98SRichard Henderson     frame_addr = get_sigframe(ka, env, sizeof(struct rt_sigframe), fpkind,
525*a7365e98SRichard Henderson                               &fpstate_addr, &fxstate_addr, &fpend_addr);
526a075f313SLaurent Vivier     trace_user_setup_rt_frame(env, frame_addr);
527a075f313SLaurent Vivier 
528*a7365e98SRichard Henderson     total_size = fpend_addr - frame_addr;
529*a7365e98SRichard Henderson     frame = lock_user(VERIFY_WRITE, frame_addr, total_size, 0);
530*a7365e98SRichard Henderson     if (!frame) {
531a075f313SLaurent Vivier         goto give_sigsegv;
532*a7365e98SRichard Henderson     }
533a075f313SLaurent Vivier 
534a075f313SLaurent Vivier     if (ka->sa_flags & TARGET_SA_SIGINFO) {
5354d6d8a05SGustavo Romero         frame->info = *info;
536a075f313SLaurent Vivier     }
537a075f313SLaurent Vivier 
538a075f313SLaurent Vivier     /* Create the ucontext.  */
539*a7365e98SRichard Henderson     __put_user(fpkind == FPSTATE_XSAVE, &frame->uc.tuc_flags);
540a075f313SLaurent Vivier     __put_user(0, &frame->uc.tuc_link);
541465e237bSLaurent Vivier     target_save_altstack(&frame->uc.tuc_stack, env);
542a075f313SLaurent Vivier 
543*a7365e98SRichard Henderson     fxstate = (void *)frame + (fxstate_addr - frame_addr);
544*a7365e98SRichard Henderson #ifdef TARGET_X86_64
545*a7365e98SRichard Henderson     fpstate = NULL;
546*a7365e98SRichard Henderson #else
547*a7365e98SRichard Henderson     fpstate = (void *)frame + (fpstate_addr - frame_addr);
548*a7365e98SRichard Henderson #endif
549*a7365e98SRichard Henderson 
550*a7365e98SRichard Henderson     setup_sigcontext(env, &frame->uc.tuc_mcontext, set->sig[0], fpkind,
551*a7365e98SRichard Henderson                      fpstate, fpstate_addr, fxstate, fxstate_addr, fpend_addr);
552*a7365e98SRichard Henderson 
553*a7365e98SRichard Henderson     for (int i = 0; i < TARGET_NSIG_WORDS; i++) {
554a075f313SLaurent Vivier         __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
555a075f313SLaurent Vivier     }
556a075f313SLaurent Vivier 
557*a7365e98SRichard Henderson     /*
558*a7365e98SRichard Henderson      * Set up to return from userspace.  If provided, use a stub
559*a7365e98SRichard Henderson      * already in userspace.
560*a7365e98SRichard Henderson      */
561a075f313SLaurent Vivier     if (ka->sa_flags & TARGET_SA_RESTORER) {
562a075f313SLaurent Vivier         __put_user(ka->sa_restorer, &frame->pretcode);
563a075f313SLaurent Vivier     } else {
564db205541SRichard Henderson #ifdef TARGET_X86_64
565db205541SRichard Henderson         /* For x86_64, SA_RESTORER is required ABI.  */
566db205541SRichard Henderson         goto give_sigsegv;
567db205541SRichard Henderson #else
5688ee8a104SRichard Henderson         /* This is no longer used, but is retained for ABI compatibility. */
5698ee8a104SRichard Henderson         install_rt_sigtramp(frame->retcode);
5708ee8a104SRichard Henderson         __put_user(default_rt_sigreturn, &frame->pretcode);
571a075f313SLaurent Vivier #endif
572db205541SRichard Henderson     }
573a075f313SLaurent Vivier 
574a075f313SLaurent Vivier     /* Set up registers for signal handler */
575a075f313SLaurent Vivier     env->regs[R_ESP] = frame_addr;
576a075f313SLaurent Vivier     env->eip = ka->_sa_handler;
577a075f313SLaurent Vivier 
578a075f313SLaurent Vivier #ifndef TARGET_X86_64
579bae0455cSRichard Henderson     /* Store arguments for both -mregparm=3 and standard. */
580a075f313SLaurent Vivier     env->regs[R_EAX] = sig;
581bae0455cSRichard Henderson     __put_user(sig, &frame->sig);
5820c40c18eSIlya Leoshkevich     env->regs[R_EDX] = frame_addr + offsetof(struct rt_sigframe, info);
583bae0455cSRichard Henderson     __put_user(env->regs[R_EDX], &frame->pinfo);
5840c40c18eSIlya Leoshkevich     env->regs[R_ECX] = frame_addr + offsetof(struct rt_sigframe, uc);
585bae0455cSRichard Henderson     __put_user(env->regs[R_ECX], &frame->puc);
586a075f313SLaurent Vivier #else
587a075f313SLaurent Vivier     env->regs[R_EAX] = 0;
588a075f313SLaurent Vivier     env->regs[R_EDI] = sig;
5890c40c18eSIlya Leoshkevich     env->regs[R_ESI] = frame_addr + offsetof(struct rt_sigframe, info);
5900c40c18eSIlya Leoshkevich     env->regs[R_EDX] = frame_addr + offsetof(struct rt_sigframe, uc);
591a075f313SLaurent Vivier #endif
592*a7365e98SRichard Henderson     unlock_user(frame, frame_addr, total_size);
593a075f313SLaurent Vivier 
594a075f313SLaurent Vivier     cpu_x86_load_seg(env, R_DS, __USER_DS);
595a075f313SLaurent Vivier     cpu_x86_load_seg(env, R_ES, __USER_DS);
596a075f313SLaurent Vivier     cpu_x86_load_seg(env, R_CS, __USER_CS);
597a075f313SLaurent Vivier     cpu_x86_load_seg(env, R_SS, __USER_DS);
598a075f313SLaurent Vivier     env->eflags &= ~TF_MASK;
599a075f313SLaurent Vivier     return;
600a075f313SLaurent Vivier 
601a075f313SLaurent Vivier give_sigsegv:
602a075f313SLaurent Vivier     force_sigsegv(sig);
603a075f313SLaurent Vivier }
604a075f313SLaurent Vivier 
605*a7365e98SRichard Henderson /*
606*a7365e98SRichard Henderson  * Restore a signal frame.
607*a7365e98SRichard Henderson  */
608*a7365e98SRichard Henderson 
609*a7365e98SRichard Henderson static bool xrstor_sigcontext(CPUX86State *env, FPStateKind fpkind,
610*a7365e98SRichard Henderson                               X86LegacyXSaveArea *fxstate,
611*a7365e98SRichard Henderson                               abi_ptr fxstate_addr)
6125d245678SPaolo Bonzini {
613*a7365e98SRichard Henderson     struct target_fpx_sw_bytes *sw = (void *)&fxstate->sw_reserved;
614*a7365e98SRichard Henderson     uint32_t magic1, magic2;
615*a7365e98SRichard Henderson     uint32_t extended_size, xstate_size, min_size, max_size;
6163b6e9491SRichard Henderson 
617*a7365e98SRichard Henderson     switch (fpkind) {
618*a7365e98SRichard Henderson     case FPSTATE_XSAVE:
619*a7365e98SRichard Henderson         magic1 = tswap32(sw->magic1);
620*a7365e98SRichard Henderson         extended_size = tswap32(sw->extended_size);
621*a7365e98SRichard Henderson         xstate_size = tswap32(sw->xstate_size);
622*a7365e98SRichard Henderson         min_size = sizeof(X86LegacyXSaveArea) + sizeof(X86XSaveHeader);
623*a7365e98SRichard Henderson         max_size = xsave_area_size(env->xcr0, false);
6245d245678SPaolo Bonzini 
625*a7365e98SRichard Henderson         /* Check for the first magic field and other error scenarios. */
626*a7365e98SRichard Henderson         if (magic1 != TARGET_FP_XSTATE_MAGIC1 ||
627*a7365e98SRichard Henderson             xstate_size < min_size ||
628*a7365e98SRichard Henderson             xstate_size > max_size ||
629*a7365e98SRichard Henderson             xstate_size > extended_size) {
630*a7365e98SRichard Henderson             break;
631*a7365e98SRichard Henderson         }
632*a7365e98SRichard Henderson         if (!access_ok(env_cpu(env), VERIFY_READ, fxstate_addr,
633*a7365e98SRichard Henderson                        xstate_size + TARGET_FP_XSTATE_MAGIC2_SIZE)) {
6349e9b7d4cSRichard Henderson             return false;
6355d245678SPaolo Bonzini         }
636*a7365e98SRichard Henderson         /*
637*a7365e98SRichard Henderson          * Check for the presence of second magic word at the end of memory
638*a7365e98SRichard Henderson          * layout. This detects the case where the user just copied the legacy
639*a7365e98SRichard Henderson          * fpstate layout with out copying the extended state information
640*a7365e98SRichard Henderson          * in the memory layout.
641*a7365e98SRichard Henderson          */
642*a7365e98SRichard Henderson         if (get_user_u32(magic2, fxstate_addr + xstate_size)) {
643*a7365e98SRichard Henderson             return false;
644*a7365e98SRichard Henderson         }
645*a7365e98SRichard Henderson         if (magic2 != TARGET_FP_XSTATE_MAGIC2) {
646*a7365e98SRichard Henderson             break;
647*a7365e98SRichard Henderson         }
648*a7365e98SRichard Henderson         cpu_x86_xrstor(env, fxstate_addr, -1);
6499e9b7d4cSRichard Henderson         return true;
650*a7365e98SRichard Henderson 
651*a7365e98SRichard Henderson     default:
652*a7365e98SRichard Henderson         break;
6535d245678SPaolo Bonzini     }
6545d245678SPaolo Bonzini 
655*a7365e98SRichard Henderson     cpu_x86_fxrstor(env, fxstate_addr);
6569e9b7d4cSRichard Henderson     return true;
6575d245678SPaolo Bonzini }
6585d245678SPaolo Bonzini 
659*a7365e98SRichard Henderson #ifndef TARGET_X86_64
660*a7365e98SRichard Henderson static bool frstor_sigcontext(CPUX86State *env, FPStateKind fpkind,
661*a7365e98SRichard Henderson                               struct target_fregs_state *fpstate,
662*a7365e98SRichard Henderson                               abi_ptr fpstate_addr,
663*a7365e98SRichard Henderson                               X86LegacyXSaveArea *fxstate,
664*a7365e98SRichard Henderson                               abi_ptr fxstate_addr)
665*a7365e98SRichard Henderson {
666*a7365e98SRichard Henderson     switch (fpkind) {
667*a7365e98SRichard Henderson     case FPSTATE_XSAVE:
668*a7365e98SRichard Henderson         if (!xrstor_sigcontext(env, fpkind, fxstate, fxstate_addr)) {
669*a7365e98SRichard Henderson             return false;
670*a7365e98SRichard Henderson         }
671*a7365e98SRichard Henderson         break;
672*a7365e98SRichard Henderson     case FPSTATE_FXSAVE:
673*a7365e98SRichard Henderson         cpu_x86_fxrstor(env, fxstate_addr);
674*a7365e98SRichard Henderson         break;
675*a7365e98SRichard Henderson     case FPSTATE_FSAVE:
676*a7365e98SRichard Henderson         break;
677*a7365e98SRichard Henderson     default:
678*a7365e98SRichard Henderson         g_assert_not_reached();
679*a7365e98SRichard Henderson     }
680*a7365e98SRichard Henderson 
681*a7365e98SRichard Henderson     /*
682*a7365e98SRichard Henderson      * Copy the legacy state because the FP portion of the FX frame has
683*a7365e98SRichard Henderson      * to be ignored for histerical raisins.  The kernel folds the two
684*a7365e98SRichard Henderson      * states together and then performs a single load; here we perform
685*a7365e98SRichard Henderson      * the merge within ENV by loading XSTATE/FXSTATE first, then
686*a7365e98SRichard Henderson      * overriding with the FSTATE afterward.
687*a7365e98SRichard Henderson      */
688*a7365e98SRichard Henderson     cpu_x86_frstor(env, fpstate_addr, 1);
689*a7365e98SRichard Henderson     return true;
690*a7365e98SRichard Henderson }
691*a7365e98SRichard Henderson #endif
692*a7365e98SRichard Henderson 
693c536f9b7SRichard Henderson static bool restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc)
694a075f313SLaurent Vivier {
695*a7365e98SRichard Henderson     abi_ptr fpstate_addr;
696*a7365e98SRichard Henderson     unsigned tmpflags, math_size;
697*a7365e98SRichard Henderson     FPStateKind fpkind;
698*a7365e98SRichard Henderson     void *fpstate;
699c536f9b7SRichard Henderson     bool ok;
700a075f313SLaurent Vivier 
701a075f313SLaurent Vivier #ifndef TARGET_X86_64
702a075f313SLaurent Vivier     cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
703a075f313SLaurent Vivier     cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
704a075f313SLaurent Vivier     cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
705a075f313SLaurent Vivier     cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
706a075f313SLaurent Vivier 
707a075f313SLaurent Vivier     env->regs[R_EDI] = tswapl(sc->edi);
708a075f313SLaurent Vivier     env->regs[R_ESI] = tswapl(sc->esi);
709a075f313SLaurent Vivier     env->regs[R_EBP] = tswapl(sc->ebp);
710a075f313SLaurent Vivier     env->regs[R_ESP] = tswapl(sc->esp);
711a075f313SLaurent Vivier     env->regs[R_EBX] = tswapl(sc->ebx);
712a075f313SLaurent Vivier     env->regs[R_EDX] = tswapl(sc->edx);
713a075f313SLaurent Vivier     env->regs[R_ECX] = tswapl(sc->ecx);
714a075f313SLaurent Vivier     env->regs[R_EAX] = tswapl(sc->eax);
715a075f313SLaurent Vivier 
716a075f313SLaurent Vivier     env->eip = tswapl(sc->eip);
717a075f313SLaurent Vivier #else
718a075f313SLaurent Vivier     env->regs[8] = tswapl(sc->r8);
719a075f313SLaurent Vivier     env->regs[9] = tswapl(sc->r9);
720a075f313SLaurent Vivier     env->regs[10] = tswapl(sc->r10);
721a075f313SLaurent Vivier     env->regs[11] = tswapl(sc->r11);
722a075f313SLaurent Vivier     env->regs[12] = tswapl(sc->r12);
723a075f313SLaurent Vivier     env->regs[13] = tswapl(sc->r13);
724a075f313SLaurent Vivier     env->regs[14] = tswapl(sc->r14);
725a075f313SLaurent Vivier     env->regs[15] = tswapl(sc->r15);
726a075f313SLaurent Vivier 
727a075f313SLaurent Vivier     env->regs[R_EDI] = tswapl(sc->rdi);
728a075f313SLaurent Vivier     env->regs[R_ESI] = tswapl(sc->rsi);
729a075f313SLaurent Vivier     env->regs[R_EBP] = tswapl(sc->rbp);
730a075f313SLaurent Vivier     env->regs[R_EBX] = tswapl(sc->rbx);
731a075f313SLaurent Vivier     env->regs[R_EDX] = tswapl(sc->rdx);
732a075f313SLaurent Vivier     env->regs[R_EAX] = tswapl(sc->rax);
733a075f313SLaurent Vivier     env->regs[R_ECX] = tswapl(sc->rcx);
734a075f313SLaurent Vivier     env->regs[R_ESP] = tswapl(sc->rsp);
735a075f313SLaurent Vivier 
736a075f313SLaurent Vivier     env->eip = tswapl(sc->rip);
737a075f313SLaurent Vivier #endif
738a075f313SLaurent Vivier 
739a075f313SLaurent Vivier     cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
740a075f313SLaurent Vivier     cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3);
741a075f313SLaurent Vivier 
742a075f313SLaurent Vivier     tmpflags = tswapl(sc->eflags);
743a075f313SLaurent Vivier     env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
744a075f313SLaurent Vivier 
745a075f313SLaurent Vivier     fpstate_addr = tswapl(sc->fpstate);
746c536f9b7SRichard Henderson     if (fpstate_addr == 0) {
747c536f9b7SRichard Henderson         return true;
748c536f9b7SRichard Henderson     }
749*a7365e98SRichard Henderson 
750*a7365e98SRichard Henderson     fpkind = get_fpstate_kind(env);
751*a7365e98SRichard Henderson     math_size = get_fpstate_size(env, fpkind);
752*a7365e98SRichard Henderson #ifndef TARGET_X86_64
753*a7365e98SRichard Henderson     if (fpkind != FPSTATE_FSAVE) {
754*a7365e98SRichard Henderson         math_size += sizeof(struct target_fregs_state);
755*a7365e98SRichard Henderson     }
756*a7365e98SRichard Henderson #endif
757*a7365e98SRichard Henderson     fpstate = lock_user(VERIFY_READ, fpstate_addr, math_size, 1);
758*a7365e98SRichard Henderson     if (!fpstate) {
759c536f9b7SRichard Henderson         return false;
760c7169b02SRichard Henderson     }
761a075f313SLaurent Vivier 
762*a7365e98SRichard Henderson #ifdef TARGET_X86_64
763*a7365e98SRichard Henderson     ok = xrstor_sigcontext(env, fpkind, fpstate, fpstate_addr);
764*a7365e98SRichard Henderson #else
765*a7365e98SRichard Henderson     ok = frstor_sigcontext(env, fpkind, fpstate, fpstate_addr,
766*a7365e98SRichard Henderson                            fpstate + sizeof(struct target_fregs_state),
767*a7365e98SRichard Henderson                            fpstate_addr + sizeof(struct target_fregs_state));
768*a7365e98SRichard Henderson #endif
769*a7365e98SRichard Henderson 
770*a7365e98SRichard Henderson     unlock_user(fpstate, fpstate_addr, 0);
771c536f9b7SRichard Henderson     return ok;
772a075f313SLaurent Vivier }
773a075f313SLaurent Vivier 
774a075f313SLaurent Vivier /* Note: there is no sigreturn on x86_64, there is only rt_sigreturn */
775a075f313SLaurent Vivier #ifndef TARGET_X86_64
776a075f313SLaurent Vivier long do_sigreturn(CPUX86State *env)
777a075f313SLaurent Vivier {
778a075f313SLaurent Vivier     struct sigframe *frame;
779a075f313SLaurent Vivier     abi_ulong frame_addr = env->regs[R_ESP] - 8;
780a075f313SLaurent Vivier     target_sigset_t target_set;
781a075f313SLaurent Vivier     sigset_t set;
782a075f313SLaurent Vivier 
783a075f313SLaurent Vivier     trace_user_do_sigreturn(env, frame_addr);
784*a7365e98SRichard Henderson     if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
785*a7365e98SRichard Henderson         force_sig(TARGET_SIGSEGV);
786*a7365e98SRichard Henderson         return -QEMU_ESIGRETURN;
787a075f313SLaurent Vivier     }
788a075f313SLaurent Vivier 
789*a7365e98SRichard Henderson     /* Set blocked signals. */
790*a7365e98SRichard Henderson     __get_user(target_set.sig[0], &frame->sc.oldmask);
791*a7365e98SRichard Henderson     for (int i = 1; i < TARGET_NSIG_WORDS; i++) {
792*a7365e98SRichard Henderson         __get_user(target_set.sig[i], &frame->extramask[i - 1]);
793*a7365e98SRichard Henderson     }
794a075f313SLaurent Vivier     target_to_host_sigset_internal(&set, &target_set);
795a075f313SLaurent Vivier     set_sigmask(&set);
796a075f313SLaurent Vivier 
797*a7365e98SRichard Henderson     /* Restore registers */
798c536f9b7SRichard Henderson     if (!restore_sigcontext(env, &frame->sc)) {
799a075f313SLaurent Vivier         force_sig(TARGET_SIGSEGV);
800*a7365e98SRichard Henderson     }
801*a7365e98SRichard Henderson 
802*a7365e98SRichard Henderson     unlock_user_struct(frame, frame_addr, 0);
80357a0c938SRichard Henderson     return -QEMU_ESIGRETURN;
804a075f313SLaurent Vivier }
805a075f313SLaurent Vivier #endif
806a075f313SLaurent Vivier 
807a075f313SLaurent Vivier long do_rt_sigreturn(CPUX86State *env)
808a075f313SLaurent Vivier {
809a075f313SLaurent Vivier     abi_ulong frame_addr;
810a075f313SLaurent Vivier     struct rt_sigframe *frame;
811a075f313SLaurent Vivier     sigset_t set;
812a075f313SLaurent Vivier 
813a075f313SLaurent Vivier     frame_addr = env->regs[R_ESP] - sizeof(abi_ulong);
814a075f313SLaurent Vivier     trace_user_do_rt_sigreturn(env, frame_addr);
815a075f313SLaurent Vivier     if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
816a075f313SLaurent Vivier         goto badframe;
817a075f313SLaurent Vivier     target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
818a075f313SLaurent Vivier     set_sigmask(&set);
819a075f313SLaurent Vivier 
820c536f9b7SRichard Henderson     if (!restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
821a075f313SLaurent Vivier         goto badframe;
822a075f313SLaurent Vivier     }
823a075f313SLaurent Vivier 
824ddc3e74dSRichard Henderson     target_restore_altstack(&frame->uc.tuc_stack, env);
825a075f313SLaurent Vivier 
826a075f313SLaurent Vivier     unlock_user_struct(frame, frame_addr, 0);
82757a0c938SRichard Henderson     return -QEMU_ESIGRETURN;
828a075f313SLaurent Vivier 
829a075f313SLaurent Vivier badframe:
830a075f313SLaurent Vivier     unlock_user_struct(frame, frame_addr, 0);
831a075f313SLaurent Vivier     force_sig(TARGET_SIGSEGV);
83257a0c938SRichard Henderson     return -QEMU_ESIGRETURN;
833a075f313SLaurent Vivier }
8348ee8a104SRichard Henderson 
8358ee8a104SRichard Henderson #ifndef TARGET_X86_64
8368ee8a104SRichard Henderson void setup_sigtramp(abi_ulong sigtramp_page)
8378ee8a104SRichard Henderson {
8388ee8a104SRichard Henderson     uint16_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 2 * 8, 0);
8398ee8a104SRichard Henderson     assert(tramp != NULL);
8408ee8a104SRichard Henderson 
8418ee8a104SRichard Henderson     default_sigreturn = sigtramp_page;
8428ee8a104SRichard Henderson     install_sigtramp(tramp);
8438ee8a104SRichard Henderson 
8448ee8a104SRichard Henderson     default_rt_sigreturn = sigtramp_page + 8;
8458ee8a104SRichard Henderson     install_rt_sigtramp(tramp + 8);
8468ee8a104SRichard Henderson 
8478ee8a104SRichard Henderson     unlock_user(tramp, sigtramp_page, 2 * 8);
8488ee8a104SRichard Henderson }
8498ee8a104SRichard Henderson #endif
850