Print this page
15254 %ymm registers not restored after signal handler
15367 x86 getfpregs() summons corrupting %xmm ghosts
15333 want x86 /proc xregs support (libc_db, libproc, mdb, etc.)
15336 want libc functions for extended ucontext_t
15334 want ps_lwphandle-specific reg routines
15328 FPU_CW_INIT mistreats reserved bit
15335 i86pc fpu_subr.c isn't really platform-specific
15332 setcontext(2) isn't actually noreturn
15331 need <sys/stdalign.h>
Change-Id: I7060aa86042dfb989f77fc3323c065ea2eafa9ad
Conflicts:
    usr/src/uts/common/fs/proc/prcontrol.c
    usr/src/uts/intel/os/archdep.c
    usr/src/uts/intel/sys/ucontext.h
    usr/src/uts/intel/syscall/getcontext.c

*** 29,38 **** --- 29,42 ---- /* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */ /* All Rights Reserved */ + /* + * Copyright 2023 Oxide Computer Company + */ + #include <sys/types.h> #include <sys/param.h> #include <sys/sysmacros.h> #include <sys/signal.h> #include <sys/systm.h>
*** 110,122 **** * * old %rsp: * <128 bytes of untouched stack space> * <a siginfo_t [optional]> * <a ucontext_t> ! * <siginfo_t *> ! * <signal number> ! * new %rsp: <return address (deliberately invalid)> * * The signal number and siginfo_t pointer are only pushed onto the stack in * order to allow stack backtraces. The actual signal handling code expects the * arguments in registers. */ --- 114,127 ---- * * old %rsp: * <128 bytes of untouched stack space> * <a siginfo_t [optional]> * <a ucontext_t> ! * <a ucontext_t's xsave state> ! * <siginfo_t *> ---+ ! * <signal number> | sigframe ! * new %rsp: <return address (deliberately invalid)> ---+ * * The signal number and siginfo_t pointer are only pushed onto the stack in * order to allow stack backtraces. The actual signal handling code expects the * arguments in registers. */
*** 128,139 **** }; int sendsig(int sig, k_siginfo_t *sip, void (*hdlr)()) { ! volatile int minstacksz; ! int newstack; label_t ljb; volatile caddr_t sp; caddr_t fp; volatile struct regs *rp; volatile greg_t upc; --- 133,146 ---- }; int sendsig(int sig, k_siginfo_t *sip, void (*hdlr)()) { ! volatile size_t minstacksz; ! boolean_t newstack; ! size_t xsave_size; ! int ret; label_t ljb; volatile caddr_t sp; caddr_t fp; volatile struct regs *rp; volatile greg_t upc;
*** 169,186 **** * above means that sp (and thus sigframe) will be 8-byte aligned, * but not 16-byte aligned. ucontext_t, however, contains %xmm regs * which must be 16-byte aligned. Because of this, for correct * alignment, sigframe must be a multiple of 8-bytes in length, but * not 16-bytes. This will place ucontext_t at a nice 16-byte boundary. */ ! /* LINTED: logical expression always true: op "||" */ ! ASSERT((sizeof (struct sigframe) % 16) == 8); minstacksz = sizeof (struct sigframe) + SA(sizeof (*uc)); if (sip != NULL) minstacksz += SA(sizeof (siginfo_t)); ASSERT((minstacksz & (STACK_ENTRY_ALIGN - 1ul)) == 0); /* * Figure out whether we will be handling this signal on * an alternate stack specified by the user. Then allocate --- 176,205 ---- * above means that sp (and thus sigframe) will be 8-byte aligned, * but not 16-byte aligned. ucontext_t, however, contains %xmm regs * which must be 16-byte aligned. Because of this, for correct * alignment, sigframe must be a multiple of 8-bytes in length, but * not 16-bytes. This will place ucontext_t at a nice 16-byte boundary. + * + * When we move onto the xsave state, right now, we don't guarantee any + * alignment of the resulting data, but we will ensure that the + * resulting sp does have proper alignment. This will ensure that the + * guarantee on the ucontex_t is not violated. */ ! CTASSERT((sizeof (struct sigframe) % 16) == 8); minstacksz = sizeof (struct sigframe) + SA(sizeof (*uc)); if (sip != NULL) minstacksz += SA(sizeof (siginfo_t)); + + if (fpu_xsave_enabled()) { + xsave_size = SA(fpu_signal_size(lwp)); + minstacksz += xsave_size; + } else { + xsave_size = 0; + } + ASSERT((minstacksz & (STACK_ENTRY_ALIGN - 1ul)) == 0); /* * Figure out whether we will be handling this signal on * an alternate stack specified by the user. Then allocate
*** 293,312 **** sizeof (curthread->t_rprof->rp_state)); } } else sip_addr = NULL; /* ! * save the current context on the user stack directly after the ! * sigframe. Since sigframe is 8-byte-but-not-16-byte aligned, ! * and since sizeof (struct sigframe) is 24, this guarantees ! * 16-byte alignment for ucontext_t and its %xmm registers. */ - uc = (ucontext_t *)(sp + sizeof (struct sigframe)); tuc = kmem_alloc(sizeof (*tuc), KM_SLEEP); ! no_fault(); ! savecontext(tuc, &lwp->lwp_sigoldmask); if (on_fault(&ljb)) goto badstack; copyout_noerr(tuc, uc, sizeof (*tuc)); kmem_free(tuc, sizeof (*tuc)); tuc = NULL; --- 312,341 ---- sizeof (curthread->t_rprof->rp_state)); } } else sip_addr = NULL; + no_fault(); + /* ! * Save the current context on the user stack directly after the ! * sigframe. Since sigframe is 8-byte-but-not-16-byte aligned, and since ! * sizeof (struct sigframe) is 24, this guarantees 16-byte alignment for ! * ucontext_t and its %xmm registers. The xsave state part of the ! * ucontext_t may be inbetween these two. However, we have ensured that ! * the size of the stack space is 16-byte aligned as the actual size may ! * vary. */ tuc = kmem_alloc(sizeof (*tuc), KM_SLEEP); ! if (xsave_size != 0) { ! tuc->uc_xsave = (unsigned long)(sp + sizeof (struct sigframe)); ! } ! uc = (ucontext_t *)(sp + sizeof (struct sigframe) + xsave_size); ! ret = savecontext(tuc, &lwp->lwp_sigoldmask, SAVECTXT_F_EXTD | ! SAVECTXT_F_ONFAULT); ! if (ret != 0) ! goto postfault; if (on_fault(&ljb)) goto badstack; copyout_noerr(tuc, uc, sizeof (*tuc)); kmem_free(tuc, sizeof (*tuc)); tuc = NULL;
*** 376,385 **** --- 405,415 ---- */ return (1); badstack: no_fault(); + postfault: if (watched) watch_enable_addr((caddr_t)sp, minstacksz, S_WRITE); if (tuc) kmem_free(tuc, sizeof (*tuc)); #ifdef DEBUG
*** 397,406 **** --- 427,437 ---- * An i386 SVR4/ABI signal frame looks like this on the stack: * * old %esp: * <a siginfo32_t [optional]> * <a ucontext32_t> + * <a ucontext32_t's xsave state> * <pointer to that ucontext32_t> * <pointer to that siginfo32_t> * <signo> * new %esp: <return address (deliberately invalid)> */
*** 412,423 **** }; int sendsig32(int sig, k_siginfo_t *sip, void (*hdlr)()) { ! volatile int minstacksz; ! int newstack; label_t ljb; volatile caddr_t sp; caddr_t fp; volatile struct regs *rp; volatile greg_t upc; --- 443,456 ---- }; int sendsig32(int sig, k_siginfo_t *sip, void (*hdlr)()) { ! volatile size_t minstacksz; ! boolean_t newstack; ! size_t xsave_size; ! int ret; label_t ljb; volatile caddr_t sp; caddr_t fp; volatile struct regs *rp; volatile greg_t upc;
*** 432,441 **** --- 465,481 ---- upc = rp->r_pc; minstacksz = SA32(sizeof (struct sigframe32)) + SA32(sizeof (*uc)); if (sip != NULL) minstacksz += SA32(sizeof (siginfo32_t)); + + if (fpu_xsave_enabled()) { + xsave_size = SA32(fpu_signal_size(lwp)); + minstacksz += xsave_size; + } else { + xsave_size = 0; + } ASSERT((minstacksz & (STACK_ALIGN32 - 1)) == 0); /* * Figure out whether we will be handling this signal on * an alternate stack specified by the user. Then allocate
*** 538,554 **** sip_addr->si_mstate, sizeof (curthread->t_rprof->rp_state)); } } else sip_addr = NULL; /* save the current context on the user stack */ fp -= SA32(sizeof (*tuc)); uc = (ucontext32_t *)fp; ! tuc = kmem_alloc(sizeof (*tuc), KM_SLEEP); ! no_fault(); ! savecontext32(tuc, &lwp->lwp_sigoldmask); if (on_fault(&ljb)) goto badstack; copyout_noerr(tuc, uc, sizeof (*tuc)); kmem_free(tuc, sizeof (*tuc)); tuc = NULL; --- 578,601 ---- sip_addr->si_mstate, sizeof (curthread->t_rprof->rp_state)); } } else sip_addr = NULL; + no_fault(); /* save the current context on the user stack */ + tuc = kmem_alloc(sizeof (*tuc), KM_SLEEP); fp -= SA32(sizeof (*tuc)); uc = (ucontext32_t *)fp; ! if (xsave_size != 0) { ! fp -= xsave_size; ! tuc->uc_xsave = (int32_t)(uintptr_t)fp; ! } ! ret = savecontext32(tuc, &lwp->lwp_sigoldmask, SAVECTXT_F_EXTD | ! SAVECTXT_F_ONFAULT); ! if (ret != 0) ! goto postfault; if (on_fault(&ljb)) goto badstack; copyout_noerr(tuc, uc, sizeof (*tuc)); kmem_free(tuc, sizeof (*tuc)); tuc = NULL;
*** 618,627 **** --- 665,675 ---- */ return (1); badstack: no_fault(); + postfault: if (watched) watch_enable_addr((caddr_t)sp, minstacksz, S_WRITE); if (tuc) kmem_free(tuc, sizeof (*tuc)); #ifdef DEBUG