NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: kern/60539 (XSAVE changes break ucontext userspace API)



The following reply was made to PR kern/60539; it has been noted by GNATS.

From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
To: nia%sent.at@localhost, gnats-bugs%netbsd.org@localhost, lib-bug-people%netbsd.org@localhost,
	netbsd-bugs%netbsd.org@localhost, gnats-admin%netbsd.org@localhost
Cc: 
Subject: Re: kern/60539 (XSAVE changes break ucontext userspace API)
Date: Thu, 6 Aug 2026 02:47:23 +0000

 > Date: Wed, 5 Aug 2026 15:36:03 +0000
 > From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
 > 
 > I considered making the XSAVE and ucontext_t areas overlap, like this:
 > 
 >        / +-----------------------+
 >       |  | Hi16_ZMM              |
 >       |  | --------------------- |
 >       |  | ZMM_Hi256             |
 > XSAVE <  | --------------------- |
 >       |  | YMM_Hi128             |
 >       |  *-----------------------* \
 >       |  | FXSAVE in ucontext_t  |  |
 >        \ *-----------------------*  > ucontext_t
 >          | rest of ucontext_t    |  |
 >          +-----------------------+ /
 >          | siginfo_t             |
 >          +-----------------------+
 >          | return address        |
 >          +-----------------------+ <--- rsp on signal handler entry
 > 
 > However, [stuff about setcontext(2) copyin size issues]
 > [...]
 > So, perhaps we should combine the approaches:
 > 
 > 1. use the __xsaveptr/__xsavelen so that the MD cpu_setmcontext knows
 >    where to find the XSAVE area,
 > AND
 > 2. make the XSAVE area overlap the ucontext_t so the FXSAVE sections
 >    of the two coincide, with some careful attention to stack pointer
 >    arithmetic and alignment in sendsig_siginfo.
 
 Unfortunately, I recall now another reason why I didn't do it this
 way.  Although it looks like this might work on amd64 (and perhaps we
 should do it on amd64), it won't work at all on i386 because on i386,
 ucontext_t (and more specifically mcontext_t) doesn't end with the
 FXSAVE area -- the thread-local storage base pointer comes after it:
 
     115 typedef struct {
     116 	__gregset_t	__gregs;
     117 	__fpregset_t	__fpregs;
 ==> 118 	__greg_t	_mc_tlsbase;
     119 } mcontext_t;
 
 https://nxr.netbsd.org/xref/src/sys/arch/i386/include/mcontext.h?r=1.20#115
 
 i386 does have 33*4=132 bytes of unused padding at the end of
 __fpregset_t, but that's not enough for even the high 128-bit halves
 of the YMM registers (256 bytes), which is the minimal additional
 state for AVX to work:
 
      80 typedef struct {
      81 	union {
 ...
     110 	} __fp_reg_set;
     111 	int 	__fp_pad[33];			/* Historic padding */
     112 } __fpregset_t;
     113 __CTASSERT(sizeof (__fpregset_t) == 512 + 33 * 4);
 
 So, short of versioning setcontext (and sigaction and everything else
 that touches this) to provide an alternate mcontext_t that doesn't
 match the SysV ABI, I don't think there's a way to provide a single
 contiguous XSAVE area that overlaps the FXSAVE area, and thus we
 either need to:
 
 (a) _not_ have a contiguous XSAVE area, and instead assemble an XSAVE
     area from the existing mcontext_t FXSAVE area and a pointer to the
     rest (which might be fine except we already shipped 11.0 to
     provide a contiguous XSAVE area),
 or
 (b) have two FXSAVE areas (one in ucontext_t, one elsewhere) and make
     a decision about which one is treated as canonical (which is where
     we are now, and the one in the XSAVE area is treated as canonical
     in 11.0, so it might be a bit late to change that).
 
 
 Now, this all only affects existing applications that:
 
 1. already wanted to write to the x87/SSE registers in a signal
    handler to affect the CPU state on return from signal,
 AND
 2. still want to use the same unmodified logic when the signal handler
    might interrupt code that uses _additional_ CPU state.
 
 I think such applications are likely to be inherently problematic.  If
 you're doing value substitution in an FPU trap handler, and some
 AVX512 instruction operating on a 512-bit ZMM vector register traps,
 does it make sense for your trap handler to try to replace _just the
 low 128 bits_ of the ZMM register (i.e., the 128-bit XMM register it
 aliases) and restart the instruction stream?  I think this is not very
 likely.
 
 But I'm open to other thoughts on the matter.
 



Home | Main Index | Thread Index | Old Index