Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/6] arm64: alternatives: switch most used alternatives to callbacks
@ 2026-09-28 13:30 Ada Couprie Diaz
  2026-09-28 13:30 ` [PATCH 1/6] arm64: insn: remove deprecated memory barrier types Ada Couprie Diaz
                   ` (6 more replies)
  0 siblings, 7 replies; 15+ messages in thread
From: Ada Couprie Diaz @ 2026-09-28 13:30 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Mark Rutland, Marc Zyngier, Barry Song, Vladimir Murzin,
	Arnd Bergmann, Anshuman Khandual, Catalin Marinas,
	Shanker Donthineni, Vikram Sethi, Oliver Upton, James Morse,
	Andre Przywara, Tejun Heo, Lucas Wei, Will Deacon

Hello,

This series looks at some size reductions for the kernel by replacing
the most used instruction-based alternatives with callbacks, implementing
ideas of my previous RFC on the insn framework[0] and taking into account
Marc's comments.
The goal here is to create specialized callbacks rather than overhauling
the whole insn framework, which lead to using bitwise operations to modify
the original instructions in most cases.

Using the alternatives dump produced by Mark's patch[0] on v7.3-rc4 defconfig,
the most common instruction-based alternatives are :
	1. 10k entries, `ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE`,
	2. 10k entries, `ARM64_WORKAROUND_NVIDIA_OLYMPUS_1027`,
	3. 3k entries, `ARM64_HAS_VIRT_HOST_EXTN`,
representing a potential maximum 92kB space saved on alternative instructions.

Sadly this is not realized in practice, but I wanted to share the results
below and see what the mailing list thinks.

All in all, it feels like a fair bit of changes for 1% gains on the Image size
and an increase in size for vmlinux.
The gains on the I/O workarounds are more clear cut and could be taken
by themselves, but remain quite slim.

I would be curious if other configurations benefit more, and the impact
when tested on high core-count machines.

=== Structure

- Patches 1 and 2 are preparatory commits for patch 3 to make
  the insn functions used safe to be called when patching alternatives ;
- Patch 5 is an optional clean-up of hard-coded values, to be re-used
  in patch 6 ;
- Patches 3, 4 and 6 are the actual alternatives changes
  - Patch 3 : replaces the NVIDIA workaround to device I/O reads
  - Patch 4 : replaces the Cortex-A57 workaround to device I/O reads
  - Patch 6 : replaces the TPIDR_EL1 to TPIDR_EL2 switch for per-cpu

=== Results

All numbers are on v7.3-rc4 building defconfig with GCC 13.3.0.
Only the patches mentioned are applied on each line.

|   Patches    |  Size (B) |	|    Patch    | Size (B) |
| Base vmlinux | 172826400 |	|  Base Image | 52374016 |
|          1-3 |    -71672 |	|         1-3 |   -65536 |
|            4 |    -71704 |    |           4 |   -65536 |
|          1-4 |    -64712 |	|         1-4 |   -65536 |
|          5-6 |    +68008 |	|         5-6 |       -0 |
|  All patches |    + 3240 |    | All patches |   -65536 |

The impact on alternatives is two-fold :
1. As expected, all alternatives for the two I/O workarounds and
   97% of the `ARM64_HAS_VIRT_HOST_EXTN` alternatives are converted to
   callbacks, saving 85848 bytes (20 pages).
2. The raw number of alternatives *increases* by about 3% (250 new entries)

Almost all alternatives that are patched later, e.g. drivers loading,
are now using callbacks as well.

From my limited testing on a Morello board, boot time seems unaffected.

=== Analysis

I was a bit perplexed by the results, not expecting either the new entries
nor the increase in size due to the TPIDR patch.

Using `readelf`, it appears that most of the increase in size comes from
debug sections massively increasing with the TPIDR patch,
specifically `.debug_line` and `.debug_info`.
Most of the new alternative entries also come from the TPIDR patch,
which is probably due to the compiler making different optimization decisions.

Interestingly, as most of the size increase is in the debug sections,
`CONFIG_DEBUG_INFO_COMPRESSED_` options have a stronger impact. Despite the
increase in size with all patches, compressed debug info shrinks vmlinux
by 57856 bytes compared to v7.3-rc4 with the same debug info compression.

I experimented with adding `volatile` to the asm block in
`__kern_my_cpu_offset()` to see how that would impact both the size and
the amount of alternatives.
Without the patches, it does add 200 new alternatie entries but shrinks
`vmlinux` by 100 kB. The patches add 260 more alternatives and shrinks
`vmlinux` by another 2 kB.
So it looks like compiler optimization would be a large cause of the change.
I have not tested the effects on performance of this change, but given
the comment it would probably be detrimentary so I elected not to include it.

Previous to this series, I also looked into creating a callback to handle
reading and writing to system registers with exception level variants,
mostly used in KVM, but with no benefit. I will share the findings below
in case they can be useful to anyone.



I am curious about what people think, thank you in advance !
Kind regards,
Ada

Based on v7.3-rc4.

[0]: https://lore.kernel.org/r/20250923174903.76283-1-ada.coupriediaz@arm.com 
[1]: https://git.kernel.org/pub/scm/linux/kernel/git/mark/linux.git/commit/?id=ee8dd3d5de66e92a98896d6f316a71ec815cd51e

Ada Couprie Diaz (6):
  arm64: insn: remove deprecated memory barrier types
  arm64: insn: make `aarch64_insn_gen_d{m,s}b()` alternative-safe
  arm64: io: replace NVIDIA Olympus erratum alternative with callback
  arm64: io: replace ARM erratum 832075 alternative with callback
  arm64: insn: operate on MSR/MRS sysreg field via defines
  arm64: use alternatie callback to patch TPIDR_EL1 accesses

 arch/arm64/include/asm/alternative.h |  3 ++
 arch/arm64/include/asm/assembler.h   | 12 ++---
 arch/arm64/include/asm/insn.h        | 65 +++++++++++++++++++++++----
 arch/arm64/include/asm/io.h          | 51 ++++++++++++---------
 arch/arm64/include/asm/percpu.h      | 12 ++---
 arch/arm64/kernel/alternative.c      | 25 +++++++++++
 arch/arm64/kernel/image-vars.h       |  3 ++
 arch/arm64/kernel/io.c               | 49 +++++++++++++++++++++
 arch/arm64/lib/insn.c                | 66 ++--------------------------
 9 files changed, 182 insertions(+), 104 deletions(-)


base-commit: 93f51579e7df248780214094418f205253383cc5
-- 
2.43.0


=== Abandoned : system registers with _ELx variants

KVM uses alternative instructions to access the correct registers
for the desired exception level when in non-VHE mode.
This is used in a good number of places in KVM, so I wondered if
a callback could save some space.

Going through the system register encodings, the following pattern
emerges for registers with multiple variants depending on EL :
- CRn, CRm and op2 are identical
- op1 encodes the exception level of the register access :
  - EL0  : 0b011
  - EL1  : 0b000
  - EL2  : 0b100
  - EL3  : 0b110
  - EL02 : 0b101
  - EL12 : 0b101

So it looked like it would be possible to bit-mask the op1 field per-EL.

However, among the registers with ELx variants there were exceptions :
- TPDIR_EL1 and TPDIR_EL2, which are used for per-cpu functions,
  do not share the same op2 field
- BRBCR_EL1's op1 does not match above pattern
- MAIR2_EL{1,12} and MAIR2_EL{2,3} pairs have different CRm fields
- SP_EL{0,1}'s op1 do not match the above pattern

And, in general :
- Arm ARM DDI 0487 C5.1.1[2] mentions that op1 has different values for EL1
- Indeed, many registers outside of those with multiple ELx variants do not fit
  the above pattern
- There is no hard guarantee that the above logic will be maintained long term


Considering the above, I reimplemented `{read,write}_sysreg_elx` with a
compile time check switching between the current alternative and
the bitmasking callback for the instructions that do match the pattern.

This did convert about 200 alternative entries to callbacks, but because of
the increase in size of debug sections and symbol tables, this only made
`vmlinux` bigger by about 3 kB with no change for the Image.

Given the negative impact on size, limited applicability and benefits,
I did not move further with this.
However, it might be useful to simplify some of the awk script generating
sysreg defines.

[2]: https://support.arm.com/documentation/ddi0487/mc (version M.c)


^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2026-10-09 10:19 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-28 13:30 [PATCH 0/6] arm64: alternatives: switch most used alternatives to callbacks Ada Couprie Diaz
2026-09-28 13:30 ` [PATCH 1/6] arm64: insn: remove deprecated memory barrier types Ada Couprie Diaz
2026-10-07  6:21   ` Vladimir Murzin
2026-10-07 17:05     ` Ada Couprie Diaz
2026-10-09 10:19       ` Vladimir Murzin
2026-09-28 13:30 ` [PATCH 2/6] arm64: insn: make `aarch64_insn_gen_d{m,s}b()` alternative-safe Ada Couprie Diaz
2026-09-28 13:30 ` [PATCH 3/6] arm64: io: replace NVIDIA Olympus erratum alternative with callback Ada Couprie Diaz
2026-09-28 13:30 ` [PATCH 4/6] arm64: io: replace ARM erratum 832075 " Ada Couprie Diaz
2026-09-28 13:30 ` [PATCH 5/6] arm64: insn: operate on MSR/MRS sysreg field via defines Ada Couprie Diaz
2026-10-07  6:53   ` Vladimir Murzin
2026-10-07 16:31     ` Ada Couprie Diaz
2026-10-09  9:14       ` Vladimir Murzin
2026-09-28 13:30 ` [PATCH 6/6] arm64: use alternatie callback to patch TPIDR_EL1 accesses Ada Couprie Diaz
2026-10-06 16:28 ` [PATCH 0/6] arm64: alternatives: switch most used alternatives to callbacks Catalin Marinas
2026-10-06 17:30   ` Ada Couprie Diaz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox