Subject: Re: [PATCH v3 02/18] KVM: arm64: Don't override FFR save/restore argument

From: Mark Rutland <[email-masked]>
Date: Wed, 3 Jun 2026 10:25:23 +0100

On Tue, Jun 02, 2026 at 04:11:34PM +0100, Mark Rutland wrote:
>  SYM_FUNC_START(__sve_restore_state)
> -	mov	x2, #1
>  	sve_load 0, x1, x2, 3
>  	ret
>  SYM_FUNC_END(__sve_restore_state)
>  
>  SYM_FUNC_START(__sve_save_state)
> -	mov	x2, #1
>  	sve_save 0, x1, x2, 3
>  	ret
>  SYM_FUNC_END(__sve_save_state)

Sashiko pointed out that this change opens a type mismatch bug. Details
below; I'll send a v4 which fixes this since it's also a latent issue
elsewhere.

The function prototypes take the FFR parameter as a 32-bit int:

  void __sve_restore_state(void *sve_pffr, u32 *fpsr, int restore_ffr)
  void __sve_save_state(void *sve_pffr, u32 *fpsr, int save_ffr)

Per the AAPCS64 parameter passing rules, the callee is responsible for
widening values, and where a register contains a 32-bit argument, the
upper 32 bits of the register are permitted to contain arbitrary values.

The CBZ instructions in the sve_save and sve_load macros will consume
all 64 bits of x2, so depending on how the compiler generated the
'restore_ffr' or 'save_ffr' argument (and if the upper 32 bits happen to
be non-zero), it's possible that we'll attempt to save/restore FFR when
we shouldn't. In practice it's most likely the compiler will zero the
entire register when passing false, but the compiler isn't required to
do so.

The same issue exists in the sve_{save,load}_state() and
sme_{save,load}_state() functions before this series, and hence we
should fix that as a preparatory step for the sake of stable kernels.

We happened to avoid that issue in sve_flush_live() by virtue of passing
bool (which the caller has to pass as 0 or 1 specifically) and using tbz
on bit 0.

Mark.