arm64: alternatives: add shared NOP callback
authorMark Rutland <mark.rutland@arm.com>
Mon, 12 Sep 2022 16:22:10 +0000 (17:22 +0100)
committerCatalin Marinas <catalin.marinas@arm.com>
Fri, 16 Sep 2022 16:15:03 +0000 (17:15 +0100)
For each instance of an alternative, the compiler outputs a distinct
copy of the alternative instructions into a subsection. As the compiler
doesn't have special knowledge of alternatives, it cannot coalesce these
to save space.

In a defconfig kernel built with GCC 12.1.0, there are approximately
10,000 instances of alternative_has_feature_likely(), where the
replacement instruction is always a NOP. As NOPs are
position-independent, we don't need a unique copy per alternative
sequence.

This patch adds a callback to patch an alternative sequence with NOPs,
and make use of this in alternative_has_feature_likely(). So that this
can be used for other sites in future, this is written to patch multiple
instructions up to the original sequence length.

For NVHE, an alias is added to image-vars.h.

For modules, the callback is exported. Note that as modules are loaded
within 2GiB of the kernel, an alt_instr entry in a module can always
refer directly to the callback, and no special handling is necessary.

When building with GCC 12.1.0, the vmlinux is ~158KiB smaller, though
the resulting Image size is unchanged due to alignment constraints and
padding:

| % ls -al vmlinux-*
| -rwxr-xr-x 1 mark mark 134644592 Sep  1 14:52 vmlinux-after
| -rwxr-xr-x 1 mark mark 134486232 Sep  1 14:50 vmlinux-before
| % ls -al Image-*
| -rw-r--r-- 1 mark mark 37108224 Sep  1 14:52 Image-after
| -rw-r--r-- 1 mark mark 37108224 Sep  1 14:50 Image-before

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Ard Biesheuvel <ardb@kernel.org>
Cc: James Morse <james.morse@arm.com>
Cc: Joey Gouly <joey.gouly@arm.com>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Will Deacon <will@kernel.org>
Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20220912162210.3626215-9-mark.rutland@arm.com
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
arch/arm64/include/asm/alternative-macros.h
arch/arm64/kernel/alternative.c
arch/arm64/kernel/image-vars.h

index eaba9ec127897076787e519ba2d6152f8c94ac94..4a2a98d6d2227f689b1a6ce8d952a728a45c2a43 100644 (file)
@@ -224,7 +224,7 @@ alternative_has_feature_likely(unsigned long feature)
        BUILD_BUG_ON(feature >= ARM64_NCAPS);
 
        asm_volatile_goto(
-       ALTERNATIVE("b  %l[l_no]", "nop", %[feature])
+       ALTERNATIVE_CB("b       %l[l_no]", %[feature], alt_cb_patch_nops)
        :
        : [feature] "i" (feature)
        :
index 9a071a5fcb674204fb4611f9163ab00625647b8d..5a904d4e98eabe866cfee80d03a535ef0ad83784 100644 (file)
@@ -263,3 +263,11 @@ void apply_alternatives_module(void *start, size_t length)
        __apply_alternatives(&region, true, &all_capabilities[0]);
 }
 #endif
+
+noinstr void alt_cb_patch_nops(struct alt_instr *alt, __le32 *origptr,
+                              __le32 *updptr, int nr_inst)
+{
+       for (int i = 0; i < nr_inst; i++)
+               updptr[i] = cpu_to_le32(aarch64_insn_gen_nop());
+}
+EXPORT_SYMBOL(alt_cb_patch_nops);
index 118973a6ab05364a278ad00d8d401a8fb8b5b119..4aaa5f3d1f65f6bf42d28d6a46ac9489f8216957 100644 (file)
@@ -73,6 +73,7 @@ KVM_NVHE_ALIAS(spectre_bhb_patch_loop_iter);
 KVM_NVHE_ALIAS(spectre_bhb_patch_loop_mitigation_enable);
 KVM_NVHE_ALIAS(spectre_bhb_patch_wa3);
 KVM_NVHE_ALIAS(spectre_bhb_patch_clearbhb);
+KVM_NVHE_ALIAS(alt_cb_patch_nops);
 
 /* Global kernel state accessed by nVHE hyp code. */
 KVM_NVHE_ALIAS(kvm_vgic_global_state);