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 /*
150a7365e98SRichard Henderson * The actual fpstate is placed after retcode[] below, to make room
151a7365e98SRichard Henderson * for the variable-sized xsave data. The older unused fpstate has
152a7365e98SRichard Henderson * to be kept to avoid changing the offset of extramask[], which
1535154d35bSPaolo Bonzini * is part of the ABI.
1545154d35bSPaolo Bonzini */
155a7365e98SRichard Henderson struct target_fpstate_32 fpstate_unused;
156a075f313SLaurent Vivier abi_ulong extramask[TARGET_NSIG_WORDS-1];
157a075f313SLaurent Vivier char retcode[8];
158a7365e98SRichard 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];
169a7365e98SRichard 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;
188a7365e98SRichard Henderson /* fp state follows here */
189a075f313SLaurent Vivier };
190a075f313SLaurent Vivier #endif
191a075f313SLaurent Vivier
192a7365e98SRichard Henderson typedef enum {
193a7365e98SRichard Henderson #ifndef TARGET_X86_64
194a7365e98SRichard Henderson FPSTATE_FSAVE,
195a7365e98SRichard Henderson #endif
196a7365e98SRichard Henderson FPSTATE_FXSAVE,
197a7365e98SRichard Henderson FPSTATE_XSAVE
198a7365e98SRichard Henderson } FPStateKind;
199a7365e98SRichard Henderson
get_fpstate_kind(CPUX86State * env)200a7365e98SRichard Henderson static FPStateKind get_fpstate_kind(CPUX86State *env)
201a7365e98SRichard Henderson {
202a7365e98SRichard Henderson if (env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE) {
203a7365e98SRichard Henderson return FPSTATE_XSAVE;
204a7365e98SRichard Henderson }
205a7365e98SRichard Henderson #ifdef TARGET_X86_64
206a7365e98SRichard Henderson return FPSTATE_FXSAVE;
207a7365e98SRichard Henderson #else
208a7365e98SRichard Henderson if (env->features[FEAT_1_EDX] & CPUID_FXSR) {
209a7365e98SRichard Henderson return FPSTATE_FXSAVE;
210a7365e98SRichard Henderson }
211a7365e98SRichard Henderson return FPSTATE_FSAVE;
212a7365e98SRichard Henderson #endif
213a7365e98SRichard Henderson }
214a7365e98SRichard Henderson
get_fpstate_size(CPUX86State * env,FPStateKind fpkind)215a7365e98SRichard Henderson static unsigned get_fpstate_size(CPUX86State *env, FPStateKind fpkind)
216a7365e98SRichard Henderson {
217a7365e98SRichard Henderson /*
218a7365e98SRichard Henderson * Kernel:
219a7365e98SRichard Henderson * fpu__alloc_mathframe
220a7365e98SRichard Henderson * xstate_sigframe_size(current->thread.fpu.fpstate);
221a7365e98SRichard Henderson * size = fpstate->user_size
222a7365e98SRichard Henderson * use_xsave() ? size + FP_XSTATE_MAGIC2_SIZE : size
223a7365e98SRichard Henderson * where fpstate->user_size is computed at init in
224a7365e98SRichard Henderson * fpu__init_system_xstate_size_legacy and
225a7365e98SRichard Henderson * fpu__init_system_xstate.
226a7365e98SRichard Henderson *
227a7365e98SRichard Henderson * Here we have no place to pre-compute, so inline it all.
228a7365e98SRichard Henderson */
229a7365e98SRichard Henderson switch (fpkind) {
230a7365e98SRichard Henderson case FPSTATE_XSAVE:
231a7365e98SRichard Henderson return (xsave_area_size(env->xcr0, false)
232a7365e98SRichard Henderson + TARGET_FP_XSTATE_MAGIC2_SIZE);
233a7365e98SRichard Henderson case FPSTATE_FXSAVE:
234a7365e98SRichard Henderson return sizeof(X86LegacyXSaveArea);
235a7365e98SRichard Henderson #ifndef TARGET_X86_64
236a7365e98SRichard Henderson case FPSTATE_FSAVE:
237a7365e98SRichard Henderson return sizeof(struct target_fregs_state);
238a7365e98SRichard Henderson #endif
239a7365e98SRichard Henderson }
240a7365e98SRichard Henderson g_assert_not_reached();
241a7365e98SRichard Henderson }
242a7365e98SRichard Henderson
get_sigframe(struct target_sigaction * ka,CPUX86State * env,unsigned frame_size,FPStateKind fpkind,abi_ptr * fpstate,abi_ptr * fxstate,abi_ptr * fpend)243a7365e98SRichard Henderson static abi_ptr get_sigframe(struct target_sigaction *ka, CPUX86State *env,
244a7365e98SRichard Henderson unsigned frame_size, FPStateKind fpkind,
245a7365e98SRichard Henderson abi_ptr *fpstate, abi_ptr *fxstate, abi_ptr *fpend)
246a7365e98SRichard Henderson {
247a7365e98SRichard Henderson abi_ptr sp;
248a7365e98SRichard Henderson unsigned math_size;
249a7365e98SRichard Henderson
250a7365e98SRichard Henderson /* Default to using normal stack */
251a7365e98SRichard Henderson sp = get_sp_from_cpustate(env);
252a7365e98SRichard Henderson #ifdef TARGET_X86_64
253a7365e98SRichard Henderson sp -= 128; /* this is the redzone */
254a7365e98SRichard Henderson #endif
255a7365e98SRichard Henderson
256a7365e98SRichard Henderson /* This is the X/Open sanctioned signal stack switching. */
257a7365e98SRichard Henderson if (ka->sa_flags & TARGET_SA_ONSTACK) {
258a7365e98SRichard Henderson sp = target_sigsp(sp, ka);
259a7365e98SRichard Henderson } else {
260a7365e98SRichard Henderson #ifndef TARGET_X86_64
261a7365e98SRichard Henderson /* This is the legacy signal stack switching. */
262a7365e98SRichard Henderson if ((env->segs[R_SS].selector & 0xffff) != __USER_DS
263a7365e98SRichard Henderson && !(ka->sa_flags & TARGET_SA_RESTORER)
264a7365e98SRichard Henderson && ka->sa_restorer) {
265a7365e98SRichard Henderson sp = ka->sa_restorer;
266a7365e98SRichard Henderson }
267a7365e98SRichard Henderson #endif
268a7365e98SRichard Henderson }
269a7365e98SRichard Henderson
270a7365e98SRichard Henderson math_size = get_fpstate_size(env, fpkind);
271a7365e98SRichard Henderson sp = ROUND_DOWN(sp - math_size, 64);
272a7365e98SRichard Henderson *fpend = sp + math_size;
273a7365e98SRichard Henderson *fxstate = sp;
274a7365e98SRichard Henderson #ifndef TARGET_X86_64
275a7365e98SRichard Henderson if (fpkind != FPSTATE_FSAVE) {
276a7365e98SRichard Henderson sp -= sizeof(struct target_fregs_state);
277a7365e98SRichard Henderson }
278a7365e98SRichard Henderson #endif
279a7365e98SRichard Henderson *fpstate = sp;
280a7365e98SRichard Henderson
281a7365e98SRichard Henderson sp -= frame_size;
282a7365e98SRichard Henderson /*
283a7365e98SRichard Henderson * Align the stack pointer according to the ABI, i.e. so that on
284a7365e98SRichard Henderson * function entry ((sp + sizeof(return_addr)) & 15) == 0.
285a7365e98SRichard Henderson */
286a7365e98SRichard Henderson sp += sizeof(target_ulong);
287a7365e98SRichard Henderson sp = ROUND_DOWN(sp, 16);
288a7365e98SRichard Henderson sp -= sizeof(target_ulong);
289a7365e98SRichard Henderson
290a7365e98SRichard Henderson return sp;
291a7365e98SRichard Henderson }
292a7365e98SRichard Henderson
293a075f313SLaurent Vivier /*
294a075f313SLaurent Vivier * Set up a signal frame.
295a075f313SLaurent Vivier */
296a075f313SLaurent Vivier
fxsave_sigcontext(CPUX86State * env,X86LegacyXSaveArea * fxstate)2979c2fb9e1SRichard Henderson static void fxsave_sigcontext(CPUX86State *env, X86LegacyXSaveArea *fxstate)
2982796f290SPaolo Bonzini {
299a7365e98SRichard Henderson struct target_fpx_sw_bytes *sw = (void *)&fxstate->sw_reserved;
3003b6e9491SRichard Henderson
3019c2fb9e1SRichard Henderson cpu_x86_fxsave(env, fxstate, sizeof(*fxstate));
3023b6e9491SRichard Henderson __put_user(0, &sw->magic1);
303a7365e98SRichard Henderson }
3045d245678SPaolo Bonzini
xsave_sigcontext(CPUX86State * env,X86LegacyXSaveArea * fxstate,abi_ptr fpstate_addr,abi_ptr xstate_addr,abi_ptr fpend_addr)305a7365e98SRichard Henderson static void xsave_sigcontext(CPUX86State *env,
306a7365e98SRichard Henderson X86LegacyXSaveArea *fxstate,
307a7365e98SRichard Henderson abi_ptr fpstate_addr,
308a7365e98SRichard Henderson abi_ptr xstate_addr,
309a7365e98SRichard Henderson abi_ptr fpend_addr)
310a7365e98SRichard Henderson {
311a7365e98SRichard Henderson struct target_fpx_sw_bytes *sw = (void *)&fxstate->sw_reserved;
3125d245678SPaolo Bonzini /*
313a7365e98SRichard Henderson * extended_size is the offset from fpstate_addr to right after
314a7365e98SRichard Henderson * the end of the extended save states. On 32-bit that includes
315a7365e98SRichard Henderson * the legacy FSAVE area.
3165d245678SPaolo Bonzini */
317a7365e98SRichard Henderson uint32_t extended_size = fpend_addr - fpstate_addr;
318a7365e98SRichard Henderson /* Recover xstate_size by removing magic2. */
319a7365e98SRichard Henderson uint32_t xstate_size = (fpend_addr - xstate_addr
320a7365e98SRichard Henderson - TARGET_FP_XSTATE_MAGIC2_SIZE);
321a7365e98SRichard Henderson /* magic2 goes just after xstate. */
322a7365e98SRichard Henderson uint32_t *magic2 = (void *)fxstate + xstate_size;
3235d245678SPaolo Bonzini
324a7365e98SRichard Henderson /* xstate_addr must be 64 byte aligned for xsave */
325a7365e98SRichard Henderson assert(!(xstate_addr & 0x3f));
3265d245678SPaolo Bonzini
3275d245678SPaolo Bonzini /* Zero the header, XSAVE *adds* features to an existing save state. */
328a7365e98SRichard Henderson memset(fxstate + 1, 0, sizeof(X86XSaveHeader));
329701890bdSRichard Henderson cpu_x86_xsave(env, fxstate, fpend_addr - xstate_addr, env->xcr0);
330a7365e98SRichard Henderson
3313b6e9491SRichard Henderson __put_user(TARGET_FP_XSTATE_MAGIC1, &sw->magic1);
3323b6e9491SRichard Henderson __put_user(extended_size, &sw->extended_size);
3333b6e9491SRichard Henderson __put_user(env->xcr0, &sw->xfeatures);
3343b6e9491SRichard Henderson __put_user(xstate_size, &sw->xstate_size);
335a7365e98SRichard Henderson __put_user(TARGET_FP_XSTATE_MAGIC2, magic2);
3362796f290SPaolo Bonzini }
3372796f290SPaolo Bonzini
setup_sigcontext(CPUX86State * env,struct target_sigcontext * sc,abi_ulong mask,FPStateKind fpkind,struct target_fregs_state * fpstate,abi_ptr fpstate_addr,X86LegacyXSaveArea * fxstate,abi_ptr fxstate_addr,abi_ptr fpend_addr)338a7365e98SRichard Henderson static void setup_sigcontext(CPUX86State *env,
339a7365e98SRichard Henderson struct target_sigcontext *sc,
340a7365e98SRichard Henderson abi_ulong mask, FPStateKind fpkind,
341a7365e98SRichard Henderson struct target_fregs_state *fpstate,
342a7365e98SRichard Henderson abi_ptr fpstate_addr,
343a7365e98SRichard Henderson X86LegacyXSaveArea *fxstate,
344a7365e98SRichard Henderson abi_ptr fxstate_addr,
345a7365e98SRichard Henderson abi_ptr fpend_addr)
346a075f313SLaurent Vivier {
3476aa9e42fSRichard Henderson CPUState *cs = env_cpu(env);
348a7365e98SRichard Henderson
349a075f313SLaurent Vivier #ifndef TARGET_X86_64
350a075f313SLaurent Vivier uint16_t magic;
351a075f313SLaurent Vivier
352a075f313SLaurent Vivier /* already locked in setup_frame() */
353a7365e98SRichard Henderson __put_user(env->segs[R_GS].selector, (uint32_t *)&sc->gs);
354a7365e98SRichard Henderson __put_user(env->segs[R_FS].selector, (uint32_t *)&sc->fs);
355a7365e98SRichard Henderson __put_user(env->segs[R_ES].selector, (uint32_t *)&sc->es);
356a7365e98SRichard Henderson __put_user(env->segs[R_DS].selector, (uint32_t *)&sc->ds);
357a075f313SLaurent Vivier __put_user(env->regs[R_EDI], &sc->edi);
358a075f313SLaurent Vivier __put_user(env->regs[R_ESI], &sc->esi);
359a075f313SLaurent Vivier __put_user(env->regs[R_EBP], &sc->ebp);
360a075f313SLaurent Vivier __put_user(env->regs[R_ESP], &sc->esp);
361a075f313SLaurent Vivier __put_user(env->regs[R_EBX], &sc->ebx);
362a075f313SLaurent Vivier __put_user(env->regs[R_EDX], &sc->edx);
363a075f313SLaurent Vivier __put_user(env->regs[R_ECX], &sc->ecx);
364a075f313SLaurent Vivier __put_user(env->regs[R_EAX], &sc->eax);
365a075f313SLaurent Vivier __put_user(cs->exception_index, &sc->trapno);
366a075f313SLaurent Vivier __put_user(env->error_code, &sc->err);
367a075f313SLaurent Vivier __put_user(env->eip, &sc->eip);
368a7365e98SRichard Henderson __put_user(env->segs[R_CS].selector, (uint32_t *)&sc->cs);
369a075f313SLaurent Vivier __put_user(env->eflags, &sc->eflags);
370a075f313SLaurent Vivier __put_user(env->regs[R_ESP], &sc->esp_at_signal);
371a7365e98SRichard Henderson __put_user(env->segs[R_SS].selector, (uint32_t *)&sc->ss);
372a075f313SLaurent Vivier
37376d8d0f8SRichard Henderson cpu_x86_fsave(env, fpstate, sizeof(*fpstate));
374a7365e98SRichard Henderson fpstate->status = fpstate->swd;
375a7365e98SRichard Henderson magic = (fpkind == FPSTATE_FSAVE ? 0 : 0xffff);
376a7365e98SRichard Henderson __put_user(magic, &fpstate->magic);
377a075f313SLaurent Vivier #else
378a075f313SLaurent Vivier __put_user(env->regs[R_EDI], &sc->rdi);
379a075f313SLaurent Vivier __put_user(env->regs[R_ESI], &sc->rsi);
380a075f313SLaurent Vivier __put_user(env->regs[R_EBP], &sc->rbp);
381a075f313SLaurent Vivier __put_user(env->regs[R_ESP], &sc->rsp);
382a075f313SLaurent Vivier __put_user(env->regs[R_EBX], &sc->rbx);
383a075f313SLaurent Vivier __put_user(env->regs[R_EDX], &sc->rdx);
384a075f313SLaurent Vivier __put_user(env->regs[R_ECX], &sc->rcx);
385a075f313SLaurent Vivier __put_user(env->regs[R_EAX], &sc->rax);
386a075f313SLaurent Vivier
387a075f313SLaurent Vivier __put_user(env->regs[8], &sc->r8);
388a075f313SLaurent Vivier __put_user(env->regs[9], &sc->r9);
389a075f313SLaurent Vivier __put_user(env->regs[10], &sc->r10);
390a075f313SLaurent Vivier __put_user(env->regs[11], &sc->r11);
391a075f313SLaurent Vivier __put_user(env->regs[12], &sc->r12);
392a075f313SLaurent Vivier __put_user(env->regs[13], &sc->r13);
393a075f313SLaurent Vivier __put_user(env->regs[14], &sc->r14);
394a075f313SLaurent Vivier __put_user(env->regs[15], &sc->r15);
395a075f313SLaurent Vivier
396a075f313SLaurent Vivier __put_user(cs->exception_index, &sc->trapno);
397a075f313SLaurent Vivier __put_user(env->error_code, &sc->err);
398a075f313SLaurent Vivier __put_user(env->eip, &sc->rip);
399a075f313SLaurent Vivier
400a075f313SLaurent Vivier __put_user(env->eflags, &sc->eflags);
401a075f313SLaurent Vivier __put_user(env->segs[R_CS].selector, &sc->cs);
402a075f313SLaurent Vivier __put_user((uint16_t)0, &sc->gs);
403a075f313SLaurent Vivier __put_user((uint16_t)0, &sc->fs);
404a075f313SLaurent Vivier __put_user(env->segs[R_SS].selector, &sc->ss);
4052796f290SPaolo Bonzini #endif
4062796f290SPaolo Bonzini
407a7365e98SRichard Henderson switch (fpkind) {
408a7365e98SRichard Henderson case FPSTATE_XSAVE:
409a7365e98SRichard Henderson xsave_sigcontext(env, fxstate, fpstate_addr, fxstate_addr, fpend_addr);
410a7365e98SRichard Henderson break;
411a7365e98SRichard Henderson case FPSTATE_FXSAVE:
4129c2fb9e1SRichard Henderson fxsave_sigcontext(env, fxstate);
413a7365e98SRichard Henderson break;
414a7365e98SRichard Henderson default:
415a7365e98SRichard Henderson break;
416a7365e98SRichard Henderson }
4172796f290SPaolo Bonzini
418a7365e98SRichard Henderson __put_user(fpstate_addr, &sc->fpstate);
4192796f290SPaolo Bonzini /* non-iBCS2 extensions.. */
420a075f313SLaurent Vivier __put_user(mask, &sc->oldmask);
421a075f313SLaurent Vivier __put_user(env->cr[2], &sc->cr2);
422a075f313SLaurent Vivier }
423a075f313SLaurent Vivier
424a075f313SLaurent Vivier #ifndef TARGET_X86_64
install_sigtramp(void * tramp)4258ee8a104SRichard Henderson static void install_sigtramp(void *tramp)
4268ee8a104SRichard Henderson {
4278ee8a104SRichard Henderson /* This is popl %eax ; movl $syscall,%eax ; int $0x80 */
4288ee8a104SRichard Henderson __put_user(0xb858, (uint16_t *)(tramp + 0));
4298ee8a104SRichard Henderson __put_user(TARGET_NR_sigreturn, (int32_t *)(tramp + 2));
4308ee8a104SRichard Henderson __put_user(0x80cd, (uint16_t *)(tramp + 6));
4318ee8a104SRichard Henderson }
4328ee8a104SRichard Henderson
install_rt_sigtramp(void * tramp)4338ee8a104SRichard Henderson static void install_rt_sigtramp(void *tramp)
4348ee8a104SRichard Henderson {
4358ee8a104SRichard Henderson /* This is movl $syscall,%eax ; int $0x80 */
4368ee8a104SRichard Henderson __put_user(0xb8, (uint8_t *)(tramp + 0));
4378ee8a104SRichard Henderson __put_user(TARGET_NR_rt_sigreturn, (int32_t *)(tramp + 1));
4388ee8a104SRichard Henderson __put_user(0x80cd, (uint16_t *)(tramp + 5));
4398ee8a104SRichard Henderson }
4408ee8a104SRichard Henderson
441a075f313SLaurent Vivier /* compare linux/arch/i386/kernel/signal.c:setup_frame() */
setup_frame(int sig,struct target_sigaction * ka,target_sigset_t * set,CPUX86State * env)442a075f313SLaurent Vivier void setup_frame(int sig, struct target_sigaction *ka,
443a075f313SLaurent Vivier target_sigset_t *set, CPUX86State *env)
444a075f313SLaurent Vivier {
445a7365e98SRichard Henderson abi_ptr frame_addr, fpstate_addr, fxstate_addr, fpend_addr;
446a075f313SLaurent Vivier struct sigframe *frame;
447a7365e98SRichard Henderson struct target_fregs_state *fpstate;
448a7365e98SRichard Henderson X86LegacyXSaveArea *fxstate;
449a7365e98SRichard Henderson unsigned total_size;
450a7365e98SRichard Henderson FPStateKind fpkind;
451a075f313SLaurent Vivier
452a7365e98SRichard Henderson fpkind = get_fpstate_kind(env);
453a7365e98SRichard Henderson frame_addr = get_sigframe(ka, env, sizeof(struct sigframe), fpkind,
454a7365e98SRichard Henderson &fpstate_addr, &fxstate_addr, &fpend_addr);
455a075f313SLaurent Vivier trace_user_setup_frame(env, frame_addr);
456a075f313SLaurent Vivier
457a7365e98SRichard Henderson total_size = fpend_addr - frame_addr;
458a7365e98SRichard Henderson frame = lock_user(VERIFY_WRITE, frame_addr, total_size, 0);
459a7365e98SRichard Henderson if (!frame) {
460a7365e98SRichard Henderson force_sigsegv(sig);
461a7365e98SRichard Henderson return;
462a7365e98SRichard Henderson }
463a075f313SLaurent Vivier
464a7365e98SRichard Henderson fxstate = (void *)frame + (fxstate_addr - frame_addr);
465a7365e98SRichard Henderson #ifdef TARGET_X86_64
466a7365e98SRichard Henderson fpstate = NULL;
467a7365e98SRichard Henderson #else
468a7365e98SRichard Henderson fpstate = (void *)frame + (fpstate_addr - frame_addr);
469a7365e98SRichard Henderson #endif
470a075f313SLaurent Vivier
471a7365e98SRichard Henderson setup_sigcontext(env, &frame->sc, set->sig[0], fpkind,
472a7365e98SRichard Henderson fpstate, fpstate_addr, fxstate, fxstate_addr, fpend_addr);
473a7365e98SRichard Henderson
474a7365e98SRichard Henderson for (int i = 1; i < TARGET_NSIG_WORDS; i++) {
475a075f313SLaurent Vivier __put_user(set->sig[i], &frame->extramask[i - 1]);
476a075f313SLaurent Vivier }
477a075f313SLaurent Vivier
478a075f313SLaurent Vivier /* Set up to return from userspace. If provided, use a stub
479a075f313SLaurent Vivier already in userspace. */
480a075f313SLaurent Vivier if (ka->sa_flags & TARGET_SA_RESTORER) {
481a075f313SLaurent Vivier __put_user(ka->sa_restorer, &frame->pretcode);
482a075f313SLaurent Vivier } else {
4838ee8a104SRichard Henderson /* This is no longer used, but is retained for ABI compatibility. */
4848ee8a104SRichard Henderson install_sigtramp(frame->retcode);
4858ee8a104SRichard Henderson __put_user(default_sigreturn, &frame->pretcode);
486a075f313SLaurent Vivier }
487a7365e98SRichard Henderson unlock_user(frame, frame_addr, total_size);
488a075f313SLaurent Vivier
489a075f313SLaurent Vivier /* Set up registers for signal handler */
490a075f313SLaurent Vivier env->regs[R_ESP] = frame_addr;
491a075f313SLaurent Vivier env->eip = ka->_sa_handler;
492a075f313SLaurent Vivier
493bae0455cSRichard Henderson /* Store argument for both -mregparm=3 and standard. */
494bae0455cSRichard Henderson env->regs[R_EAX] = sig;
495bae0455cSRichard Henderson __put_user(sig, &frame->sig);
496bae0455cSRichard Henderson /* The kernel clears EDX and ECX even though there is only one arg. */
497bae0455cSRichard Henderson env->regs[R_EDX] = 0;
498bae0455cSRichard Henderson env->regs[R_ECX] = 0;
499bae0455cSRichard Henderson
500a075f313SLaurent Vivier cpu_x86_load_seg(env, R_DS, __USER_DS);
501a075f313SLaurent Vivier cpu_x86_load_seg(env, R_ES, __USER_DS);
502a075f313SLaurent Vivier cpu_x86_load_seg(env, R_SS, __USER_DS);
503a075f313SLaurent Vivier cpu_x86_load_seg(env, R_CS, __USER_CS);
504a075f313SLaurent Vivier env->eflags &= ~TF_MASK;
505a075f313SLaurent Vivier }
506a075f313SLaurent Vivier #endif
507a075f313SLaurent Vivier
508a075f313SLaurent Vivier /* compare linux/arch/x86/kernel/signal.c:setup_rt_frame() */
setup_rt_frame(int sig,struct target_sigaction * ka,target_siginfo_t * info,target_sigset_t * set,CPUX86State * env)509a075f313SLaurent Vivier void setup_rt_frame(int sig, struct target_sigaction *ka,
510a075f313SLaurent Vivier target_siginfo_t *info,
511a075f313SLaurent Vivier target_sigset_t *set, CPUX86State *env)
512a075f313SLaurent Vivier {
513a7365e98SRichard Henderson abi_ptr frame_addr, fpstate_addr, fxstate_addr, fpend_addr;
514a075f313SLaurent Vivier struct rt_sigframe *frame;
515a7365e98SRichard Henderson X86LegacyXSaveArea *fxstate;
516a7365e98SRichard Henderson struct target_fregs_state *fpstate;
517a7365e98SRichard Henderson unsigned total_size;
518a7365e98SRichard Henderson FPStateKind fpkind;
519a075f313SLaurent Vivier
520a7365e98SRichard Henderson fpkind = get_fpstate_kind(env);
521a7365e98SRichard Henderson frame_addr = get_sigframe(ka, env, sizeof(struct rt_sigframe), fpkind,
522a7365e98SRichard Henderson &fpstate_addr, &fxstate_addr, &fpend_addr);
523a075f313SLaurent Vivier trace_user_setup_rt_frame(env, frame_addr);
524a075f313SLaurent Vivier
525a7365e98SRichard Henderson total_size = fpend_addr - frame_addr;
526a7365e98SRichard Henderson frame = lock_user(VERIFY_WRITE, frame_addr, total_size, 0);
527a7365e98SRichard Henderson if (!frame) {
528a075f313SLaurent Vivier goto give_sigsegv;
529a7365e98SRichard Henderson }
530a075f313SLaurent Vivier
531a075f313SLaurent Vivier if (ka->sa_flags & TARGET_SA_SIGINFO) {
5324d6d8a05SGustavo Romero frame->info = *info;
533a075f313SLaurent Vivier }
534a075f313SLaurent Vivier
535a075f313SLaurent Vivier /* Create the ucontext. */
536a7365e98SRichard Henderson __put_user(fpkind == FPSTATE_XSAVE, &frame->uc.tuc_flags);
537a075f313SLaurent Vivier __put_user(0, &frame->uc.tuc_link);
538465e237bSLaurent Vivier target_save_altstack(&frame->uc.tuc_stack, env);
539a075f313SLaurent Vivier
540a7365e98SRichard Henderson fxstate = (void *)frame + (fxstate_addr - frame_addr);
541a7365e98SRichard Henderson #ifdef TARGET_X86_64
542a7365e98SRichard Henderson fpstate = NULL;
543a7365e98SRichard Henderson #else
544a7365e98SRichard Henderson fpstate = (void *)frame + (fpstate_addr - frame_addr);
545a7365e98SRichard Henderson #endif
546a7365e98SRichard Henderson
547a7365e98SRichard Henderson setup_sigcontext(env, &frame->uc.tuc_mcontext, set->sig[0], fpkind,
548a7365e98SRichard Henderson fpstate, fpstate_addr, fxstate, fxstate_addr, fpend_addr);
549a7365e98SRichard Henderson
550a7365e98SRichard Henderson for (int i = 0; i < TARGET_NSIG_WORDS; i++) {
551a075f313SLaurent Vivier __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
552a075f313SLaurent Vivier }
553a075f313SLaurent Vivier
554a7365e98SRichard Henderson /*
555a7365e98SRichard Henderson * Set up to return from userspace. If provided, use a stub
556a7365e98SRichard Henderson * already in userspace.
557a7365e98SRichard Henderson */
558a075f313SLaurent Vivier if (ka->sa_flags & TARGET_SA_RESTORER) {
559a075f313SLaurent Vivier __put_user(ka->sa_restorer, &frame->pretcode);
560a075f313SLaurent Vivier } else {
561db205541SRichard Henderson #ifdef TARGET_X86_64
562db205541SRichard Henderson /* For x86_64, SA_RESTORER is required ABI. */
563db205541SRichard Henderson goto give_sigsegv;
564db205541SRichard Henderson #else
5658ee8a104SRichard Henderson /* This is no longer used, but is retained for ABI compatibility. */
5668ee8a104SRichard Henderson install_rt_sigtramp(frame->retcode);
5678ee8a104SRichard Henderson __put_user(default_rt_sigreturn, &frame->pretcode);
568a075f313SLaurent Vivier #endif
569db205541SRichard Henderson }
570a075f313SLaurent Vivier
571a075f313SLaurent Vivier /* Set up registers for signal handler */
572a075f313SLaurent Vivier env->regs[R_ESP] = frame_addr;
573a075f313SLaurent Vivier env->eip = ka->_sa_handler;
574a075f313SLaurent Vivier
575a075f313SLaurent Vivier #ifndef TARGET_X86_64
576bae0455cSRichard Henderson /* Store arguments for both -mregparm=3 and standard. */
577a075f313SLaurent Vivier env->regs[R_EAX] = sig;
578bae0455cSRichard Henderson __put_user(sig, &frame->sig);
5790c40c18eSIlya Leoshkevich env->regs[R_EDX] = frame_addr + offsetof(struct rt_sigframe, info);
580bae0455cSRichard Henderson __put_user(env->regs[R_EDX], &frame->pinfo);
5810c40c18eSIlya Leoshkevich env->regs[R_ECX] = frame_addr + offsetof(struct rt_sigframe, uc);
582bae0455cSRichard Henderson __put_user(env->regs[R_ECX], &frame->puc);
583a075f313SLaurent Vivier #else
584a075f313SLaurent Vivier env->regs[R_EAX] = 0;
585a075f313SLaurent Vivier env->regs[R_EDI] = sig;
5860c40c18eSIlya Leoshkevich env->regs[R_ESI] = frame_addr + offsetof(struct rt_sigframe, info);
5870c40c18eSIlya Leoshkevich env->regs[R_EDX] = frame_addr + offsetof(struct rt_sigframe, uc);
588a075f313SLaurent Vivier #endif
589a7365e98SRichard Henderson unlock_user(frame, frame_addr, total_size);
590a075f313SLaurent Vivier
591a075f313SLaurent Vivier cpu_x86_load_seg(env, R_DS, __USER_DS);
592a075f313SLaurent Vivier cpu_x86_load_seg(env, R_ES, __USER_DS);
593a075f313SLaurent Vivier cpu_x86_load_seg(env, R_CS, __USER_CS);
594a075f313SLaurent Vivier cpu_x86_load_seg(env, R_SS, __USER_DS);
595a075f313SLaurent Vivier env->eflags &= ~TF_MASK;
596a075f313SLaurent Vivier return;
597a075f313SLaurent Vivier
598a075f313SLaurent Vivier give_sigsegv:
599a075f313SLaurent Vivier force_sigsegv(sig);
600a075f313SLaurent Vivier }
601a075f313SLaurent Vivier
602a7365e98SRichard Henderson /*
603a7365e98SRichard Henderson * Restore a signal frame.
604a7365e98SRichard Henderson */
605a7365e98SRichard Henderson
xrstor_sigcontext(CPUX86State * env,FPStateKind fpkind,X86LegacyXSaveArea * fxstate,abi_ptr fxstate_addr)606a7365e98SRichard Henderson static bool xrstor_sigcontext(CPUX86State *env, FPStateKind fpkind,
607a7365e98SRichard Henderson X86LegacyXSaveArea *fxstate,
608a7365e98SRichard Henderson abi_ptr fxstate_addr)
6095d245678SPaolo Bonzini {
610a7365e98SRichard Henderson struct target_fpx_sw_bytes *sw = (void *)&fxstate->sw_reserved;
611a7365e98SRichard Henderson uint32_t magic1, magic2;
612a7365e98SRichard Henderson uint32_t extended_size, xstate_size, min_size, max_size;
6137973eb94SRichard Henderson uint64_t xfeatures;
614701890bdSRichard Henderson void *xstate;
615701890bdSRichard Henderson bool ok;
6163b6e9491SRichard Henderson
617a7365e98SRichard Henderson switch (fpkind) {
618a7365e98SRichard Henderson case FPSTATE_XSAVE:
619a7365e98SRichard Henderson magic1 = tswap32(sw->magic1);
620a7365e98SRichard Henderson extended_size = tswap32(sw->extended_size);
621a7365e98SRichard Henderson xstate_size = tswap32(sw->xstate_size);
622a7365e98SRichard Henderson min_size = sizeof(X86LegacyXSaveArea) + sizeof(X86XSaveHeader);
623a7365e98SRichard Henderson max_size = xsave_area_size(env->xcr0, false);
6245d245678SPaolo Bonzini
625a7365e98SRichard Henderson /* Check for the first magic field and other error scenarios. */
626a7365e98SRichard Henderson if (magic1 != TARGET_FP_XSTATE_MAGIC1 ||
627a7365e98SRichard Henderson xstate_size < min_size ||
628a7365e98SRichard Henderson xstate_size > max_size ||
629a7365e98SRichard Henderson xstate_size > extended_size) {
630a7365e98SRichard Henderson break;
631a7365e98SRichard Henderson }
6327973eb94SRichard Henderson
6337973eb94SRichard Henderson /*
6347973eb94SRichard Henderson * Restore the features indicated in the frame, masked by
6357973eb94SRichard Henderson * those currently enabled. Re-check the frame size.
6367973eb94SRichard Henderson * ??? It is not clear where the kernel does this, but it
6377973eb94SRichard Henderson * is not in check_xstate_in_sigframe, and so (probably)
6387973eb94SRichard Henderson * does not fall back to fxrstor.
6397973eb94SRichard Henderson */
6407973eb94SRichard Henderson xfeatures = tswap64(sw->xfeatures) & env->xcr0;
6417973eb94SRichard Henderson min_size = xsave_area_size(xfeatures, false);
6427973eb94SRichard Henderson if (xstate_size < min_size) {
6437973eb94SRichard Henderson return false;
6447973eb94SRichard Henderson }
6457973eb94SRichard Henderson
646701890bdSRichard Henderson /* Re-lock the entire xstate area, with the extensions and magic. */
647701890bdSRichard Henderson xstate = lock_user(VERIFY_READ, fxstate_addr,
648701890bdSRichard Henderson xstate_size + TARGET_FP_XSTATE_MAGIC2_SIZE, 1);
649701890bdSRichard Henderson if (!xstate) {
6509e9b7d4cSRichard Henderson return false;
6515d245678SPaolo Bonzini }
6527973eb94SRichard Henderson
653a7365e98SRichard Henderson /*
654a7365e98SRichard Henderson * Check for the presence of second magic word at the end of memory
655a7365e98SRichard Henderson * layout. This detects the case where the user just copied the legacy
656a7365e98SRichard Henderson * fpstate layout with out copying the extended state information
657a7365e98SRichard Henderson * in the memory layout.
658a7365e98SRichard Henderson */
659701890bdSRichard Henderson magic2 = tswap32(*(uint32_t *)(xstate + xstate_size));
660a7365e98SRichard Henderson if (magic2 != TARGET_FP_XSTATE_MAGIC2) {
661701890bdSRichard Henderson unlock_user(xstate, fxstate_addr, 0);
662a7365e98SRichard Henderson break;
663a7365e98SRichard Henderson }
6647973eb94SRichard Henderson
665701890bdSRichard Henderson ok = cpu_x86_xrstor(env, xstate, xstate_size, xfeatures);
666701890bdSRichard Henderson unlock_user(xstate, fxstate_addr, 0);
667701890bdSRichard Henderson return ok;
668a7365e98SRichard Henderson
669a7365e98SRichard Henderson default:
670a7365e98SRichard Henderson break;
6715d245678SPaolo Bonzini }
6725d245678SPaolo Bonzini
6739c2fb9e1SRichard Henderson cpu_x86_fxrstor(env, fxstate, sizeof(*fxstate));
6749e9b7d4cSRichard Henderson return true;
6755d245678SPaolo Bonzini }
6765d245678SPaolo Bonzini
677a7365e98SRichard Henderson #ifndef TARGET_X86_64
frstor_sigcontext(CPUX86State * env,FPStateKind fpkind,struct target_fregs_state * fpstate,abi_ptr fpstate_addr,X86LegacyXSaveArea * fxstate,abi_ptr fxstate_addr)678a7365e98SRichard Henderson static bool frstor_sigcontext(CPUX86State *env, FPStateKind fpkind,
679a7365e98SRichard Henderson struct target_fregs_state *fpstate,
680a7365e98SRichard Henderson abi_ptr fpstate_addr,
681a7365e98SRichard Henderson X86LegacyXSaveArea *fxstate,
682a7365e98SRichard Henderson abi_ptr fxstate_addr)
683a7365e98SRichard Henderson {
684a7365e98SRichard Henderson switch (fpkind) {
685a7365e98SRichard Henderson case FPSTATE_XSAVE:
686a7365e98SRichard Henderson if (!xrstor_sigcontext(env, fpkind, fxstate, fxstate_addr)) {
687a7365e98SRichard Henderson return false;
688a7365e98SRichard Henderson }
689a7365e98SRichard Henderson break;
690a7365e98SRichard Henderson case FPSTATE_FXSAVE:
6919c2fb9e1SRichard Henderson cpu_x86_fxrstor(env, fxstate, sizeof(*fxstate));
692a7365e98SRichard Henderson break;
693a7365e98SRichard Henderson case FPSTATE_FSAVE:
694a7365e98SRichard Henderson break;
695a7365e98SRichard Henderson default:
696a7365e98SRichard Henderson g_assert_not_reached();
697a7365e98SRichard Henderson }
698a7365e98SRichard Henderson
699a7365e98SRichard Henderson /*
700a7365e98SRichard Henderson * Copy the legacy state because the FP portion of the FX frame has
701a7365e98SRichard Henderson * to be ignored for histerical raisins. The kernel folds the two
702a7365e98SRichard Henderson * states together and then performs a single load; here we perform
703a7365e98SRichard Henderson * the merge within ENV by loading XSTATE/FXSTATE first, then
704a7365e98SRichard Henderson * overriding with the FSTATE afterward.
705a7365e98SRichard Henderson */
70676d8d0f8SRichard Henderson cpu_x86_frstor(env, fpstate, sizeof(*fpstate));
707a7365e98SRichard Henderson return true;
708a7365e98SRichard Henderson }
709a7365e98SRichard Henderson #endif
710a7365e98SRichard Henderson
restore_sigcontext(CPUX86State * env,struct target_sigcontext * sc)711c536f9b7SRichard Henderson static bool restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc)
712a075f313SLaurent Vivier {
713a7365e98SRichard Henderson abi_ptr fpstate_addr;
714a7365e98SRichard Henderson unsigned tmpflags, math_size;
715a7365e98SRichard Henderson FPStateKind fpkind;
716a7365e98SRichard Henderson void *fpstate;
717c536f9b7SRichard Henderson bool ok;
718a075f313SLaurent Vivier
719a075f313SLaurent Vivier #ifndef TARGET_X86_64
720a075f313SLaurent Vivier cpu_x86_load_seg(env, R_GS, tswap16(sc->gs));
721a075f313SLaurent Vivier cpu_x86_load_seg(env, R_FS, tswap16(sc->fs));
722a075f313SLaurent Vivier cpu_x86_load_seg(env, R_ES, tswap16(sc->es));
723a075f313SLaurent Vivier cpu_x86_load_seg(env, R_DS, tswap16(sc->ds));
724a075f313SLaurent Vivier
725a075f313SLaurent Vivier env->regs[R_EDI] = tswapl(sc->edi);
726a075f313SLaurent Vivier env->regs[R_ESI] = tswapl(sc->esi);
727a075f313SLaurent Vivier env->regs[R_EBP] = tswapl(sc->ebp);
728a075f313SLaurent Vivier env->regs[R_ESP] = tswapl(sc->esp);
729a075f313SLaurent Vivier env->regs[R_EBX] = tswapl(sc->ebx);
730a075f313SLaurent Vivier env->regs[R_EDX] = tswapl(sc->edx);
731a075f313SLaurent Vivier env->regs[R_ECX] = tswapl(sc->ecx);
732a075f313SLaurent Vivier env->regs[R_EAX] = tswapl(sc->eax);
733a075f313SLaurent Vivier
734a075f313SLaurent Vivier env->eip = tswapl(sc->eip);
735a075f313SLaurent Vivier #else
736a075f313SLaurent Vivier env->regs[8] = tswapl(sc->r8);
737a075f313SLaurent Vivier env->regs[9] = tswapl(sc->r9);
738a075f313SLaurent Vivier env->regs[10] = tswapl(sc->r10);
739a075f313SLaurent Vivier env->regs[11] = tswapl(sc->r11);
740a075f313SLaurent Vivier env->regs[12] = tswapl(sc->r12);
741a075f313SLaurent Vivier env->regs[13] = tswapl(sc->r13);
742a075f313SLaurent Vivier env->regs[14] = tswapl(sc->r14);
743a075f313SLaurent Vivier env->regs[15] = tswapl(sc->r15);
744a075f313SLaurent Vivier
745a075f313SLaurent Vivier env->regs[R_EDI] = tswapl(sc->rdi);
746a075f313SLaurent Vivier env->regs[R_ESI] = tswapl(sc->rsi);
747a075f313SLaurent Vivier env->regs[R_EBP] = tswapl(sc->rbp);
748a075f313SLaurent Vivier env->regs[R_EBX] = tswapl(sc->rbx);
749a075f313SLaurent Vivier env->regs[R_EDX] = tswapl(sc->rdx);
750a075f313SLaurent Vivier env->regs[R_EAX] = tswapl(sc->rax);
751a075f313SLaurent Vivier env->regs[R_ECX] = tswapl(sc->rcx);
752a075f313SLaurent Vivier env->regs[R_ESP] = tswapl(sc->rsp);
753a075f313SLaurent Vivier
754a075f313SLaurent Vivier env->eip = tswapl(sc->rip);
755a075f313SLaurent Vivier #endif
756a075f313SLaurent Vivier
757*eed4e3d4SPhilippe Mathieu-Daudé cpu_x86_load_seg(env, R_CS, lduw_le_p(&sc->cs) | 3);
758*eed4e3d4SPhilippe Mathieu-Daudé cpu_x86_load_seg(env, R_SS, lduw_le_p(&sc->ss) | 3);
759a075f313SLaurent Vivier
760a075f313SLaurent Vivier tmpflags = tswapl(sc->eflags);
761a075f313SLaurent Vivier env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
762a075f313SLaurent Vivier
763a075f313SLaurent Vivier fpstate_addr = tswapl(sc->fpstate);
764c536f9b7SRichard Henderson if (fpstate_addr == 0) {
765c536f9b7SRichard Henderson return true;
766c536f9b7SRichard Henderson }
767a7365e98SRichard Henderson
768a7365e98SRichard Henderson fpkind = get_fpstate_kind(env);
769a7365e98SRichard Henderson math_size = get_fpstate_size(env, fpkind);
770a7365e98SRichard Henderson #ifndef TARGET_X86_64
771a7365e98SRichard Henderson if (fpkind != FPSTATE_FSAVE) {
772a7365e98SRichard Henderson math_size += sizeof(struct target_fregs_state);
773a7365e98SRichard Henderson }
774a7365e98SRichard Henderson #endif
775a7365e98SRichard Henderson fpstate = lock_user(VERIFY_READ, fpstate_addr, math_size, 1);
776a7365e98SRichard Henderson if (!fpstate) {
777c536f9b7SRichard Henderson return false;
778c7169b02SRichard Henderson }
779a075f313SLaurent Vivier
780a7365e98SRichard Henderson #ifdef TARGET_X86_64
781a7365e98SRichard Henderson ok = xrstor_sigcontext(env, fpkind, fpstate, fpstate_addr);
782a7365e98SRichard Henderson #else
783a7365e98SRichard Henderson ok = frstor_sigcontext(env, fpkind, fpstate, fpstate_addr,
784a7365e98SRichard Henderson fpstate + sizeof(struct target_fregs_state),
785a7365e98SRichard Henderson fpstate_addr + sizeof(struct target_fregs_state));
786a7365e98SRichard Henderson #endif
787a7365e98SRichard Henderson
788a7365e98SRichard Henderson unlock_user(fpstate, fpstate_addr, 0);
789c536f9b7SRichard Henderson return ok;
790a075f313SLaurent Vivier }
791a075f313SLaurent Vivier
792a075f313SLaurent Vivier /* Note: there is no sigreturn on x86_64, there is only rt_sigreturn */
793a075f313SLaurent Vivier #ifndef TARGET_X86_64
do_sigreturn(CPUX86State * env)794a075f313SLaurent Vivier long do_sigreturn(CPUX86State *env)
795a075f313SLaurent Vivier {
796a075f313SLaurent Vivier struct sigframe *frame;
797a075f313SLaurent Vivier abi_ulong frame_addr = env->regs[R_ESP] - 8;
798a075f313SLaurent Vivier target_sigset_t target_set;
799a075f313SLaurent Vivier sigset_t set;
800a075f313SLaurent Vivier
801a075f313SLaurent Vivier trace_user_do_sigreturn(env, frame_addr);
802a7365e98SRichard Henderson if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
803a7365e98SRichard Henderson force_sig(TARGET_SIGSEGV);
804a7365e98SRichard Henderson return -QEMU_ESIGRETURN;
805a075f313SLaurent Vivier }
806a075f313SLaurent Vivier
807a7365e98SRichard Henderson /* Set blocked signals. */
808a7365e98SRichard Henderson __get_user(target_set.sig[0], &frame->sc.oldmask);
809a7365e98SRichard Henderson for (int i = 1; i < TARGET_NSIG_WORDS; i++) {
810a7365e98SRichard Henderson __get_user(target_set.sig[i], &frame->extramask[i - 1]);
811a7365e98SRichard Henderson }
812a075f313SLaurent Vivier target_to_host_sigset_internal(&set, &target_set);
813a075f313SLaurent Vivier set_sigmask(&set);
814a075f313SLaurent Vivier
815a7365e98SRichard Henderson /* Restore registers */
816c536f9b7SRichard Henderson if (!restore_sigcontext(env, &frame->sc)) {
817a075f313SLaurent Vivier force_sig(TARGET_SIGSEGV);
818a7365e98SRichard Henderson }
819a7365e98SRichard Henderson
820a7365e98SRichard Henderson unlock_user_struct(frame, frame_addr, 0);
82157a0c938SRichard Henderson return -QEMU_ESIGRETURN;
822a075f313SLaurent Vivier }
823a075f313SLaurent Vivier #endif
824a075f313SLaurent Vivier
do_rt_sigreturn(CPUX86State * env)825a075f313SLaurent Vivier long do_rt_sigreturn(CPUX86State *env)
826a075f313SLaurent Vivier {
827a075f313SLaurent Vivier abi_ulong frame_addr;
828a075f313SLaurent Vivier struct rt_sigframe *frame;
829a075f313SLaurent Vivier sigset_t set;
830a075f313SLaurent Vivier
831a075f313SLaurent Vivier frame_addr = env->regs[R_ESP] - sizeof(abi_ulong);
832a075f313SLaurent Vivier trace_user_do_rt_sigreturn(env, frame_addr);
833a075f313SLaurent Vivier if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
834a075f313SLaurent Vivier goto badframe;
835a075f313SLaurent Vivier target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
836a075f313SLaurent Vivier set_sigmask(&set);
837a075f313SLaurent Vivier
838c536f9b7SRichard Henderson if (!restore_sigcontext(env, &frame->uc.tuc_mcontext)) {
839a075f313SLaurent Vivier goto badframe;
840a075f313SLaurent Vivier }
841a075f313SLaurent Vivier
842ddc3e74dSRichard Henderson target_restore_altstack(&frame->uc.tuc_stack, env);
843a075f313SLaurent Vivier
844a075f313SLaurent Vivier unlock_user_struct(frame, frame_addr, 0);
84557a0c938SRichard Henderson return -QEMU_ESIGRETURN;
846a075f313SLaurent Vivier
847a075f313SLaurent Vivier badframe:
848a075f313SLaurent Vivier unlock_user_struct(frame, frame_addr, 0);
849a075f313SLaurent Vivier force_sig(TARGET_SIGSEGV);
85057a0c938SRichard Henderson return -QEMU_ESIGRETURN;
851a075f313SLaurent Vivier }
8528ee8a104SRichard Henderson
8538ee8a104SRichard Henderson #ifndef TARGET_X86_64
setup_sigtramp(abi_ulong sigtramp_page)8548ee8a104SRichard Henderson void setup_sigtramp(abi_ulong sigtramp_page)
8558ee8a104SRichard Henderson {
8568ee8a104SRichard Henderson uint16_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 2 * 8, 0);
8578ee8a104SRichard Henderson assert(tramp != NULL);
8588ee8a104SRichard Henderson
8598ee8a104SRichard Henderson default_sigreturn = sigtramp_page;
8608ee8a104SRichard Henderson install_sigtramp(tramp);
8618ee8a104SRichard Henderson
8628ee8a104SRichard Henderson default_rt_sigreturn = sigtramp_page + 8;
8638ee8a104SRichard Henderson install_rt_sigtramp(tramp + 8);
8648ee8a104SRichard Henderson
8658ee8a104SRichard Henderson unlock_user(tramp, sigtramp_page, 2 * 8);
8668ee8a104SRichard Henderson }
8678ee8a104SRichard Henderson #endif
868