All of lore.kernel.org
 help / color / mirror / Atom feed
From: Usama Arif <usama.arif@linux.dev>
To: Borislav Petkov <bp@alien8.de>
Cc: Usama Arif <usama.arif@linux.dev>,
	david.laight.linux@gmail.com, dave.hansen@linux.intel.com,
	dsterba@suse.com, hpa@zytor.com, linux-kernel@vger.kernel.org,
	mingo@redhat.com, terrelln@fb.com, tglx@kernel.org,
	x86@kernel.org, torvalds@linux-foundation.org, kas@kernel.org,
	hannes@cmpxchg.org, riel@surriel.com, shakeel.butt@linux.dev,
	kernel-team@meta.com
Subject: Re: [PATCH v3 2/2] x86/lib: Use REP MOVSB for large memcpy() on ERMS CPUs without FSRM
Date: Fri, 13 Nov 2026 06:11:36 -0800	[thread overview]
Message-ID: <20261113141137.1113517-1-usama.arif@linux.dev> (raw)
In-Reply-To: <20261111234608.GAavT-QFRo6EtvoL0y@fat_crate.local>

On Wed, 11 Nov 2026 15:46:08 -0800 Borislav Petkov <bp@alien8.de> wrote:

> On Wed, Nov 11, 2026 at 05:20:53AM -0800, Usama Arif wrote:
> > diff --git a/arch/x86/lib/memcpy_64.S b/arch/x86/lib/memcpy_64.S
> > index 7bb146c811029..5320862e0274e 100644
> > --- a/arch/x86/lib/memcpy_64.S
> > +++ b/arch/x86/lib/memcpy_64.S
> > @@ -27,15 +27,13 @@
> >   *
> >   * The 'rep movsb' itself is small enough to replace the call, but the
> >   * two register moves blow up the code. And one of them is "needed"
> > - * only for the return value that is the same as the source input,
> > + * only for the return value that is the same as the destination input,
> >   * which the compiler could/should do much better anyway.
> >   */
> >  SYM_TYPED_FUNC_START(__memcpy)
> > -	ALTERNATIVE "jmp memcpy_orig", "", X86_FEATURE_FSRM
> > -
> >  	movq %rdi, %rax
> >  	movq %rdx, %rcx
> > -	rep movsb
> > +	ALTERNATIVE "jmp memcpy_orig", "rep movsb", X86_FEATURE_FSRM
> >  	RET
> >  SYM_FUNC_END(__memcpy)
> >  EXPORT_SYMBOL(__memcpy)
> > @@ -45,12 +43,16 @@ SYM_PIC_ALIAS(memcpy)
> >  EXPORT_SYMBOL(memcpy)
> >  
> >  SYM_FUNC_START_LOCAL(memcpy_orig)
> > -	movq %rdi, %rax
> > -	movq %rdx, %rcx
> > -
> >  	cmpq $0x20, %rcx
> >  	jb .Lhandle_tail
> >  
> > +	/*
> > +	 * RCX holds the count for REP MOVSB and scalar copying; RDX is scratch.
> > +	 * Shift RDX to check length >= 2048 without destroying the REP count.
> > +	 * The 10-byte alternative fits a NOP without ERMS.
> > +	 */
> > +	ALTERNATIVE "", __stringify(shrq $11, %rdx; jnz .Lerms), X86_FEATURE_ERMS
> 
> Sorry, this is adding more JMPs in "conditional" alternatives code and thus
> turns this into a bigger and unmaintainable mess than it already is.
>

How about something like what I have added at the end, would that be more
acceptable in terms of maintainability?
 
> The 2K limit looks like something conjured out of a thin air as it seems it
> work for your particular case. I'm sure we will have to whack it in the future
> because someone else will complain of the opposite.
> 

As mentioned in the commit message as well as [1], 2K came from experiments.

Changing the cmp immediate from 2048 to 32 bytes made aligned warmed
32/64/128/256-byte copies 101.2%/69.5%/53.5%/16.5% slower.

This is usecase driven, as Linus said in [2]: "let's see if somebody finds a
case where the kernel memory copies also care".

If someone finds a case where less than 2K is used and it doesnt cause a
regression for CPUs, they can try lowering it.

> This needs to be done with alternative_call*, even at the price of some
> duplicated code but without turning what already is a mess, into a bigger one.
> 

I tried alternative_call_2() from a C entry with separate helpers. It
adds a helper CALL/RET to every path, including FSRM. The attached
version uses tail jumps, so each helper returns directly to the original
caller and FSRM keeps REP inline. I am hoping this is acceptable?

> Or a static key or even with stop_machine_nmi() (currently in review) which
> patches the kernel even later, when it is convenient to do so.
> 
> Whatever it takes to keep this code readable and sane.
> 
> But not this.
> 
> Sorry.
> 

No worries! Hopefully the version below is more maintainable and acceptable
for everyone?

Thanks for the review!
Usama

[1] https://lore.kernel.org/all/20261017192727.2760919-1-usama.arif@linux.dev/
[2] https://git.kernel.org/linus/47ee3f1dd93bcbe031539b1ecdaafb44b661c772

diff --git a/arch/x86/lib/memcpy_64.S b/arch/x86/lib/memcpy_64.S
index 7bb146c811029..8a398edf6e160 100644
--- a/arch/x86/lib/memcpy_64.S
+++ b/arch/x86/lib/memcpy_64.S
@@ -27,15 +27,15 @@
  *
  * The 'rep movsb' itself is small enough to replace the call, but the
  * two register moves blow up the code. And one of them is "needed"
- * only for the return value that is the same as the source input,
+ * only for the return value that is the same as the destination input,
  * which the compiler could/should do much better anyway.
  */
 SYM_TYPED_FUNC_START(__memcpy)
-       ALTERNATIVE "jmp memcpy_orig", "", X86_FEATURE_FSRM
-
        movq %rdi, %rax
        movq %rdx, %rcx
-       rep movsb
+       /* FSRM takes precedence. Keep RET outside replacements for ITS. */
+       ALTERNATIVE_2 "jmp memcpy_orig", "jmp memcpy_erms", \
+                     X86_FEATURE_ERMS, "rep movsb", X86_FEATURE_FSRM
        RET
 SYM_FUNC_END(__memcpy)
 EXPORT_SYMBOL(__memcpy)
@@ -44,10 +44,15 @@ SYM_FUNC_ALIAS_MEMFUNC(memcpy, __memcpy)
 SYM_PIC_ALIAS(memcpy)
 EXPORT_SYMBOL(memcpy)

-SYM_FUNC_START_LOCAL(memcpy_orig)
-       movq %rdi, %rax
-       movq %rdx, %rcx
+/* The entry prepares RAX as the return value and RCX as the count. */
+SYM_FUNC_START_LOCAL(memcpy_erms)
+       cmpq $2048, %rcx
+       jb memcpy_orig
+       rep movsb
+       RET
+SYM_FUNC_END(memcpy_erms)

+SYM_FUNC_START_LOCAL(memcpy_orig)
        cmpq $0x20, %rcx
        jb .Lhandle_tail
 

  parent reply	other threads:[~2026-11-13 14:11 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-11 13:20 [PATCH v3 0/2] x86/lib: Use REP MOVSB for large memcpy() on ERMS CPUs without FSRM Usama Arif
2026-11-11 13:20 ` [PATCH v3 1/2] x86/lib: Keep the scalar memcpy() count in RCX Usama Arif
2026-11-11 13:20 ` [PATCH v3 2/2] x86/lib: Use REP MOVSB for large memcpy() on ERMS CPUs without FSRM Usama Arif
2026-11-11 13:56   ` Peter Zijlstra
2026-11-11 23:46   ` Borislav Petkov
2026-11-12  9:37     ` David Laight
2026-11-13 14:31       ` Usama Arif
2026-11-13 14:11     ` Usama Arif [this message]
2026-11-13 16:03       ` David Laight
2026-11-11 18:19 ` [PATCH v3 0/2] " Kiryl Shutsemau

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261113141137.1113517-1-usama.arif@linux.dev \
    --to=usama.arif@linux.dev \
    --cc=bp@alien8.de \
    --cc=dave.hansen@linux.intel.com \
    --cc=david.laight.linux@gmail.com \
    --cc=dsterba@suse.com \
    --cc=hannes@cmpxchg.org \
    --cc=hpa@zytor.com \
    --cc=kas@kernel.org \
    --cc=kernel-team@meta.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=riel@surriel.com \
    --cc=shakeel.butt@linux.dev \
    --cc=terrelln@fb.com \
    --cc=tglx@kernel.org \
    --cc=torvalds@linux-foundation.org \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.