Commit 4e3bca8f authored by Joey Gouly's avatar Joey Gouly Committed by Catalin Marinas
Browse files

arm64: alternative: patch alternatives in the vDSO



Make it possible to use alternatives in the vDSO, so that better
implementations can be used if possible.

Signed-off-by: default avatarJoey Gouly <joey.gouly@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Vincenzo Frascino <vincenzo.frascino@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Acked-by: default avatarMark Rutland <mark.rutland@arm.com>
Link: https://lore.kernel.org/r/20220830104833.34636-3-joey.gouly@arm.com


Signed-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
parent b3adc384
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -26,6 +26,9 @@
	(void *)(vdso_offset_##name - VDSO_LBASE + (unsigned long)(base)); \
})

extern char vdso_start[], vdso_end[];
extern char vdso32_start[], vdso32_end[];

#endif /* !__ASSEMBLY__ */

#endif /* __ASM_VDSO_H */
+28 −0
Original line number Diff line number Diff line
@@ -10,11 +10,14 @@

#include <linux/init.h>
#include <linux/cpu.h>
#include <linux/elf.h>
#include <asm/cacheflush.h>
#include <asm/alternative.h>
#include <asm/cpufeature.h>
#include <asm/insn.h>
#include <asm/module.h>
#include <asm/sections.h>
#include <asm/vdso.h>
#include <linux/stop_machine.h>

#define __ALT_PTR(a, f)		((void *)&(a)->f + (a)->f)
@@ -192,6 +195,30 @@ static void __nocfi __apply_alternatives(struct alt_region *region, bool is_modu
	}
}

void apply_alternatives_vdso(void)
{
	struct alt_region region;
	const struct elf64_hdr *hdr;
	const struct elf64_shdr *shdr;
	const struct elf64_shdr *alt;
	DECLARE_BITMAP(all_capabilities, ARM64_NPATCHABLE);

	bitmap_fill(all_capabilities, ARM64_NPATCHABLE);

	hdr = (struct elf64_hdr *)vdso_start;
	shdr = (void *)hdr + hdr->e_shoff;
	alt = find_section(hdr, shdr, ".altinstructions");
	if (!alt)
		return;

	region = (struct alt_region){
		.begin	= (void *)hdr + alt->sh_offset,
		.end	= (void *)hdr + alt->sh_offset + alt->sh_size,
	};

	__apply_alternatives(&region, false, &all_capabilities[0]);
}

/*
 * We might be patching the stop_machine state machine, so implement a
 * really simple polling protocol here.
@@ -225,6 +252,7 @@ static int __apply_alternatives_multi_stop(void *unused)

void __init apply_alternatives_all(void)
{
	apply_alternatives_vdso();
	/* better not try code patching on a live SMP system */
	stop_machine(__apply_alternatives_multi_stop, NULL, cpu_online_mask);
}
+0 −3
Original line number Diff line number Diff line
@@ -29,9 +29,6 @@
#include <asm/signal32.h>
#include <asm/vdso.h>

extern char vdso_start[], vdso_end[];
extern char vdso32_start[], vdso32_end[];

enum vdso_abi {
	VDSO_ABI_AA64,
	VDSO_ABI_AA32,
+7 −0
Original line number Diff line number Diff line
@@ -48,6 +48,13 @@ SECTIONS
	PROVIDE (_etext = .);
	PROVIDE (etext = .);

	. = ALIGN(4);
	.altinstructions : {
		__alt_instructions = .;
		*(.altinstructions)
		__alt_instructions_end = .;
	}

	.dynamic	: { *(.dynamic) }		:text	:dynamic

	.rela.dyn	: ALIGN(8) { *(.rela .rela*) }