diff mbox series

[v2,2/3] arm64: alternative: patch alternatives in the vDSO

Message ID 20220830104833.34636-3-joey.gouly@arm.com (mailing list archive)
State New, archived
Headers show
Series Use CNTVCTSS_EL0 in gettimeofday() | expand

Commit Message

Joey Gouly Aug. 30, 2022, 10:48 a.m. UTC
Make it possible to use alternatives in the vDSO, so that better
implementations can be used if possible.

Signed-off-by: Joey Gouly <joey.gouly@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Vincenzo Frascino <vincenzo.frascino@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
---
 arch/arm64/include/asm/vdso.h     |  3 +++
 arch/arm64/kernel/alternative.c   | 28 ++++++++++++++++++++++++++++
 arch/arm64/kernel/vdso.c          |  3 ---
 arch/arm64/kernel/vdso/vdso.lds.S |  7 +++++++
 4 files changed, 38 insertions(+), 3 deletions(-)

Comments

Mark Rutland Aug. 30, 2022, 1:17 p.m. UTC | #1
On Tue, Aug 30, 2022 at 11:48:32AM +0100, Joey Gouly wrote:
> Make it possible to use alternatives in the vDSO, so that better
> implementations can be used if possible.
> 
> Signed-off-by: Joey Gouly <joey.gouly@arm.com>
> Cc: Catalin Marinas <catalin.marinas@arm.com>
> Cc: Will Deacon <will@kernel.org>
> Cc: Vincenzo Frascino <vincenzo.frascino@arm.com>
> Cc: Mark Rutland <mark.rutland@arm.com>

Acked-by: Mark Rutland <mark.rutland@arm.com>

Mark.

> ---
>  arch/arm64/include/asm/vdso.h     |  3 +++
>  arch/arm64/kernel/alternative.c   | 28 ++++++++++++++++++++++++++++
>  arch/arm64/kernel/vdso.c          |  3 ---
>  arch/arm64/kernel/vdso/vdso.lds.S |  7 +++++++
>  4 files changed, 38 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/vdso.h b/arch/arm64/include/asm/vdso.h
> index f99dcb94b438..b4ae32109932 100644
> --- a/arch/arm64/include/asm/vdso.h
> +++ b/arch/arm64/include/asm/vdso.h
> @@ -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 */
> diff --git a/arch/arm64/kernel/alternative.c b/arch/arm64/kernel/alternative.c
> index 9bcaa5eacf16..a97775963f35 100644
> --- a/arch/arm64/kernel/alternative.c
> +++ b/arch/arm64/kernel/alternative.c
> @@ -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);
>  }
> diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
> index a61fc4f989b3..ac93a2ee9c07 100644
> --- a/arch/arm64/kernel/vdso.c
> +++ b/arch/arm64/kernel/vdso.c
> @@ -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,
> diff --git a/arch/arm64/kernel/vdso/vdso.lds.S b/arch/arm64/kernel/vdso/vdso.lds.S
> index e69fb4aaaf3e..6028f1fe2d1c 100644
> --- a/arch/arm64/kernel/vdso/vdso.lds.S
> +++ b/arch/arm64/kernel/vdso/vdso.lds.S
> @@ -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*) }
> -- 
> 2.17.1
>
diff mbox series

Patch

diff --git a/arch/arm64/include/asm/vdso.h b/arch/arm64/include/asm/vdso.h
index f99dcb94b438..b4ae32109932 100644
--- a/arch/arm64/include/asm/vdso.h
+++ b/arch/arm64/include/asm/vdso.h
@@ -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 */
diff --git a/arch/arm64/kernel/alternative.c b/arch/arm64/kernel/alternative.c
index 9bcaa5eacf16..a97775963f35 100644
--- a/arch/arm64/kernel/alternative.c
+++ b/arch/arm64/kernel/alternative.c
@@ -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);
 }
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index a61fc4f989b3..ac93a2ee9c07 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -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,
diff --git a/arch/arm64/kernel/vdso/vdso.lds.S b/arch/arm64/kernel/vdso/vdso.lds.S
index e69fb4aaaf3e..6028f1fe2d1c 100644
--- a/arch/arm64/kernel/vdso/vdso.lds.S
+++ b/arch/arm64/kernel/vdso/vdso.lds.S
@@ -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*) }