[PATCH 13/20] arm64/fpsimd: Make clone() compatible with ZA lazy saving
Yury Khrustalev
yury.khrustalev at arm.com
Wed May 7 08:57:18 PDT 2025
On Tue, May 06, 2025 at 04:25:16PM +0100, Mark Rutland wrote:
> Linux is intended to be compatible with userspace written to Arm's
> AAPCS64 procedure call standard [1,2]. For the Scalable Matrix Extension
> (SME), AAPCS64 was extended with a "ZA lazy saving scheme", where SME's
> ZA tile is lazily callee-saved and caller-restored. In this scheme,
> TPIDR2_EL0 indicates whether the ZA tile is live or has been saved by
> pointing to a "TPIDR2 block" in memory, which has a "za_save_buffer"
> pointer. This scheme has been implemented in GCC and LLVM, with
> necessary runtime support implemented in glibc and bionic.
>
> AAPCS64 does not specify how the ZA lazy saving scheme is expected to
> interact with thread creation mechanisms such as fork() and
> pthread_create(), which would be implemented in terms of the Linux clone
> syscall. The behaviour implemented by Linux and glibc/bionic doesn't
> always compose safely, as explained below.
>
> Currently the clone syscall is implemented such that PSTATE.ZA and the
> ZA tile are always inherited by the new task, and TPIDR2_EL0 is
> inherited unless the 'flags' argument includes CLONE_SETTLS,
> in which case TPIDR2_EL0 is set to 0/NULL. This doesn't make much sense:
>
> (a) TPIDR2_EL0 is part of the calling convention, and changes as control
> is passed between functions. It is *NOT* used for thread local
> storage, despite superficial similarity to TPIDR_EL0, which is is
> used as the TLS register.
>
> (b) TPIDR2_EL0 and PSTATE.ZA are tightly coupled in the procedure call
> standard, and some combinations of states are illegal. In general,
> manipulating the two independently is not guaranteed to be safe.
>
> In practice, code which is compliant with the procedure call standard
> may issue a clone syscall while in the "ZA dormant" state, where
> PSTATE.ZA==1 and TPIDR2_EL0 is non-null and indicates that ZA needs to
> be saved. This can cause a variety of problems, including:
>
> * If the implementation of pthread_create() passes CLONE_SETTLS, the
> new thread will start with PSTATE.ZA==1 and TPIDR2==NULL. Per the
> procedure call standard this is not a legitimate state for most
> functions. This can cause data corruption (e.g. as code may rely on
> PSTATE.ZA being 0 to guarantee that an SMSTART ZA instruction will
> zero the ZA tile contents), and may result in other undefined
> behaviour.
>
> * If the implementation of pthread_create() does not pass CLONE_SETTLS, the
> new thread will start with PSTATE.ZA==1 and TPIDR2 pointing to a
> TPIDR2 block on the parent thread's stack. This can result in a
> variety of problems, e.g.
>
> - The child may write back to the parent's za_save_buffer, corrupting
> its contents.
>
> - The child may read from the TPIDR2 block after the parent has reused
> this memory for something else, and consequently the child may abort
> or clobber arbitrary memory.
>
> Ideally we'd require that userspace ensures that a task is in the "ZA
> off" state (with PSTATE.ZA==0 and TPIDR2_EL0==NULL) prior to issuing a
> clone syscall, and have the kernel force this state for new threads.
> Unfortunately, contemporary C libraries do not do this, and simply
> forcing this state within the implementation of clone would break
> fork().
>
> Instead, we can bodge around this by considering the CLONE_VM flag, and
> mainpulate PSTATE.ZA and TPIDR2_EL0 as a pair. CLONE_VM indicates that
> the new task will run in the same address space as its parent, and in
> that case it doesn't make sense to inherit a stale pointer to the
> parent's TPIDR2 block:
>
> * For fork(), CLONE_VM will not be set, and it is safe to inherit both
> PSTATE.ZA and TPIDR2_EL0 as the new task will have its own copy of the
> address space, and cannot clobber its parent's stack.
>
> * For pthread_create() and vfork(), CLONE_VM will be set, and discarding
> PSTATE.ZA and TPIDR2_EL0 for the new task doesn't break any existing
> assumptions in userspace.
Acked-by: Yury Khrustalev <yury.khrustalev at arm.com>
Kind regards,
Yury
More information about the linux-arm-kernel
mailing list