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 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 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 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 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 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)); 329*701890bdSRichard 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 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 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 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() */ 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() */ 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 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; 614*701890bdSRichard Henderson void *xstate; 615*701890bdSRichard 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 646*701890bdSRichard Henderson /* Re-lock the entire xstate area, with the extensions and magic. */ 647*701890bdSRichard Henderson xstate = lock_user(VERIFY_READ, fxstate_addr, 648*701890bdSRichard Henderson xstate_size + TARGET_FP_XSTATE_MAGIC2_SIZE, 1); 649*701890bdSRichard 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 */ 659*701890bdSRichard Henderson magic2 = tswap32(*(uint32_t *)(xstate + xstate_size)); 660a7365e98SRichard Henderson if (magic2 != TARGET_FP_XSTATE_MAGIC2) { 661*701890bdSRichard Henderson unlock_user(xstate, fxstate_addr, 0); 662a7365e98SRichard Henderson break; 663a7365e98SRichard Henderson } 6647973eb94SRichard Henderson 665*701890bdSRichard Henderson ok = cpu_x86_xrstor(env, xstate, xstate_size, xfeatures); 666*701890bdSRichard Henderson unlock_user(xstate, fxstate_addr, 0); 667*701890bdSRichard 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 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 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 757a075f313SLaurent Vivier cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3); 758a075f313SLaurent Vivier cpu_x86_load_seg(env, R_SS, lduw_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 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 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 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