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