Re: kern/60539 (XSAVE changes break ucontext userspace API)
Taylor R Campbell <[email protected]>
| Newsgroups | gmane.os.netbsd.bugs |
|---|---|
| Message-ID | <[email protected]> |
> Date: Wed, 5 Aug 2026 15:36:03 +0000 > From: Taylor R Campbell <[email protected]> > > 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.