powerpc/vdso: Retrieve sigtramp offsets at buildtime
authorChristophe Leroy <christophe.leroy@csgroup.eu>
Sun, 27 Sep 2020 09:16:33 +0000 (09:16 +0000)
committerMichael Ellerman <mpe@ellerman.id.au>
Thu, 3 Dec 2020 14:01:17 +0000 (01:01 +1100)
This is copied from arm64.

Instead of using runtime generated signal trampoline offsets,
get offsets at buildtime.

If the said trampoline doesn't exist, build will fail. So no
need to check whether the trampoline exists or not in the VDSO.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/f8bfd6812c3e3678b1cdb4d55a52f9eb022b40d3.1601197618.git.christophe.leroy@csgroup.eu
12 files changed:
arch/powerpc/Makefile
arch/powerpc/include/asm/vdso.h
arch/powerpc/kernel/signal_32.c
arch/powerpc/kernel/signal_64.c
arch/powerpc/kernel/vdso32/Makefile
arch/powerpc/kernel/vdso32/gen_vdso_offsets.sh [new file with mode: 0755]
arch/powerpc/kernel/vdso32/vdso32.lds.S
arch/powerpc/kernel/vdso64/Makefile
arch/powerpc/kernel/vdso64/gen_vdso_offsets.sh [new file with mode: 0755]
arch/powerpc/kernel/vdso64/vdso64.lds.S
arch/powerpc/perf/callchain_32.c
arch/powerpc/perf/callchain_64.c

index 86c925bfbb76a778f69e1a9cd8efe540fb08b27b..fde3dbe57bda9be720ae556e8ddc29cc4d12760d 100644 (file)
@@ -409,6 +409,21 @@ install:
 archclean:
        $(Q)$(MAKE) $(clean)=$(boot)
 
+ifeq ($(KBUILD_EXTMOD),)
+# We need to generate vdso-offsets.h before compiling certain files in kernel/.
+# In order to do that, we should use the archprepare target, but we can't since
+# asm-offsets.h is included in some files used to generate vdso-offsets.h, and
+# asm-offsets.h is built in prepare0, for which archprepare is a dependency.
+# Therefore we need to generate the header after prepare0 has been made, hence
+# this hack.
+prepare: vdso_prepare
+vdso_prepare: prepare0
+       $(if $(CONFIG_VDSO32),$(Q)$(MAKE) \
+               $(build)=arch/powerpc/kernel/vdso32 include/generated/vdso32-offsets.h)
+       $(if $(CONFIG_PPC64),$(Q)$(MAKE) \
+               $(build)=arch/powerpc/kernel/vdso64 include/generated/vdso64-offsets.h)
+endif
+
 archprepare: checkbin
 
 archheaders:
index 2ff884853f975c1bee43471d11d2fb6e5c748c9a..f5257b7f17d0097a63ec6f1145b224dbef6cc759 100644 (file)
 
 #ifndef __ASSEMBLY__
 
+#ifdef CONFIG_PPC64
+#include <generated/vdso64-offsets.h>
+#endif
+
+#ifdef CONFIG_VDSO32
+#include <generated/vdso32-offsets.h>
+#endif
+
+#define VDSO64_SYMBOL(base, name) ((unsigned long)(base) + (vdso64_offset_##name))
+
+#define VDSO32_SYMBOL(base, name) ((unsigned long)(base) + (vdso32_offset_##name))
+
 /* Offsets relative to thread->vdso_base */
 extern unsigned long vdso64_rt_sigtramp;
 extern unsigned long vdso32_sigtramp;
index e45aafef4c5bb8e4120724a8f86b5d0095323370..934cbdf6dd10e4f966e7c690375ac4ece1cf2a24 100644 (file)
@@ -801,8 +801,8 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset,
        }
 
        /* Save user registers on the stack */
-       if (vdso32_rt_sigtramp && tsk->mm->context.vdso) {
-               tramp = (unsigned long)tsk->mm->context.vdso + vdso32_rt_sigtramp;
+       if (tsk->mm->context.vdso) {
+               tramp = VDSO32_SYMBOL(tsk->mm->context.vdso, sigtramp_rt32);
        } else {
                tramp = (unsigned long)mctx->mc_pad;
                /* Set up the sigreturn trampoline: li r0,sigret; sc */
@@ -901,8 +901,8 @@ int handle_signal32(struct ksignal *ksig, sigset_t *oldset,
        else
                unsafe_save_user_regs(regs, mctx, tm_mctx, 1, failed);
 
-       if (vdso32_sigtramp && tsk->mm->context.vdso) {
-               tramp = (unsigned long)tsk->mm->context.vdso + vdso32_sigtramp;
+       if (tsk->mm->context.vdso) {
+               tramp = VDSO32_SYMBOL(tsk->mm->context.vdso, sigtramp32);
        } else {
                tramp = (unsigned long)mctx->mc_pad;
                /* Set up the sigreturn trampoline: li r0,sigret; sc */
index 68e850bd5ef7731b33a68a9ba9dd2c229cb0ff84..f9e4a1ac440fb094718ee6402f38762a6e9c45de 100644 (file)
@@ -854,8 +854,8 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t *set,
        tsk->thread.fp_state.fpscr = 0;
 
        /* Set up to return from userspace. */
-       if (vdso64_rt_sigtramp && tsk->mm->context.vdso) {
-               regs->nip = (unsigned long)tsk->mm->context.vdso + vdso64_rt_sigtramp;
+       if (tsk->mm->context.vdso) {
+               regs->nip = VDSO64_SYMBOL(tsk->mm->context.vdso, sigtramp_rt64);
        } else {
                err |= setup_trampoline(__NR_rt_sigreturn, &frame->tramp[0]);
                if (err)
index a119d9f84b084c8207223174a5fae2821001ed1c..59aa2944ecaee483cbb0d545550f462c38fa0b24 100644 (file)
@@ -59,6 +59,14 @@ $(obj-vdso32): %.o: %.S FORCE
 $(obj)/vgettimeofday.o: %.o: %.c FORCE
        $(call if_changed_dep,vdso32cc)
 
+# Generate VDSO offsets using helper script
+gen-vdsosym := $(srctree)/$(src)/gen_vdso_offsets.sh
+quiet_cmd_vdsosym = VDSOSYM $@
+      cmd_vdsosym = $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@
+
+include/generated/vdso32-offsets.h: $(obj)/vdso32.so.dbg FORCE
+       $(call if_changed,vdsosym)
+
 # actual build commands
 quiet_cmd_vdso32ld_and_check = VDSO32L $@
       cmd_vdso32ld_and_check = $(VDSOCC) $(c_flags) $(CC32FLAGS) -o $@ -Wl,-T$(filter %.lds,$^) $(filter %.o,$^) ; $(cmd_vdso_check)
diff --git a/arch/powerpc/kernel/vdso32/gen_vdso_offsets.sh b/arch/powerpc/kernel/vdso32/gen_vdso_offsets.sh
new file mode 100755 (executable)
index 0000000..c7b54a5
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+
+#
+# Match symbols in the DSO that look like VDSO_*; produce a header file
+# of constant offsets into the shared object.
+#
+# Doing this inside the Makefile will break the $(filter-out) function,
+# causing Kbuild to rebuild the vdso-offsets header file every time.
+#
+# Author: Will Deacon <will.deacon@arm.com
+#
+
+LC_ALL=C
+sed -n -e 's/^00*/0/' -e \
+'s/^\([0-9a-fA-F]*\) . VDSO_\([a-zA-Z0-9_]*\)$/\#define vdso32_offset_\2\t0x\1/p'
index 88a2976e99428c920ea48c91c90733e098b8196a..078d75c0cd249d188b6dd21bd3d974a546966c7f 100644 (file)
@@ -164,3 +164,9 @@ VERSION
        local: *;
        };
 }
+
+/*
+ * Make the sigreturn code visible to the kernel.
+ */
+VDSO_sigtramp32                = __kernel_sigtramp32;
+VDSO_sigtramp_rt32     = __kernel_sigtramp_rt32;
index 29004ad1b0fbd72a7c889cf7ea048f5cda8cca62..d365810a689a06900fb2ef0b9eada87e01c786d0 100644 (file)
@@ -42,6 +42,14 @@ $(obj)/vdso64_wrapper.o : $(obj)/vdso64.so.dbg
 $(obj)/vdso64.so.dbg: $(src)/vdso64.lds $(obj-vdso64) $(obj)/vgettimeofday.o FORCE
        $(call if_changed,vdso64ld_and_check)
 
+# Generate VDSO offsets using helper script
+gen-vdsosym := $(srctree)/$(src)/gen_vdso_offsets.sh
+quiet_cmd_vdsosym = VDSOSYM $@
+      cmd_vdsosym = $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@
+
+include/generated/vdso64-offsets.h: $(obj)/vdso64.so.dbg FORCE
+       $(call if_changed,vdsosym)
+
 # actual build commands
 quiet_cmd_vdso64ld_and_check = VDSO64L $@
       cmd_vdso64ld_and_check = $(CC) $(c_flags) -o $@ -Wl,-T$(filter %.lds,$^) $(filter %.o,$^); $(cmd_vdso_check)
diff --git a/arch/powerpc/kernel/vdso64/gen_vdso_offsets.sh b/arch/powerpc/kernel/vdso64/gen_vdso_offsets.sh
new file mode 100755 (executable)
index 0000000..4bf15ff
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+
+#
+# Match symbols in the DSO that look like VDSO_*; produce a header file
+# of constant offsets into the shared object.
+#
+# Doing this inside the Makefile will break the $(filter-out) function,
+# causing Kbuild to rebuild the vdso-offsets header file every time.
+#
+# Author: Will Deacon <will.deacon@arm.com
+#
+
+LC_ALL=C
+sed -n -e 's/^00*/0/' -e \
+'s/^\([0-9a-fA-F]*\) . VDSO_\([a-zA-Z0-9_]*\)$/\#define vdso64_offset_\2\t0x\1/p'
index e43731386469de88c2c8b026d662775b445271ba..1f06e4f730a8e4635dc6f15d8034a93d2d811ec0 100644 (file)
@@ -159,3 +159,8 @@ VERSION
        local: *;
        };
 }
+
+/*
+ * Make the sigreturn code visible to the kernel.
+ */
+VDSO_sigtramp_rt64     = __kernel_sigtramp_rt64;
index b32e94047fb9856080231dbaeb0356beed982048..b83c47b7947f077a0b13812492c7b433436335b1 100644 (file)
@@ -59,8 +59,8 @@ static int is_sigreturn_32_address(unsigned int nip, unsigned int fp)
 {
        if (nip == fp + offsetof(struct signal_frame_32, mctx.mc_pad))
                return 1;
-       if (vdso32_sigtramp && current->mm->context.vdso &&
-           nip == (unsigned long)current->mm->context.vdso + vdso32_sigtramp)
+       if (current->mm->context.vdso &&
+           nip == VDSO32_SYMBOL(current->mm->context.vdso, sigtramp32))
                return 1;
        return 0;
 }
@@ -70,8 +70,8 @@ static int is_rt_sigreturn_32_address(unsigned int nip, unsigned int fp)
        if (nip == fp + offsetof(struct rt_signal_frame_32,
                                 uc.uc_mcontext.mc_pad))
                return 1;
-       if (vdso32_rt_sigtramp && current->mm->context.vdso &&
-           nip == (unsigned long)current->mm->context.vdso + vdso32_rt_sigtramp)
+       if (current->mm->context.vdso &&
+           nip == VDSO32_SYMBOL(current->mm->context.vdso, sigtramp_rt32))
                return 1;
        return 0;
 }
index 6b9c06058c33dbc18d775dc5fdcfc18bb6c19a77..8d0df4226328d869c941839ab8f9173f33a05e0b 100644 (file)
@@ -68,8 +68,8 @@ static int is_sigreturn_64_address(unsigned long nip, unsigned long fp)
 {
        if (nip == fp + offsetof(struct signal_frame_64, tramp))
                return 1;
-       if (vdso64_rt_sigtramp && current->mm->context.vdso &&
-           nip == (unsigned long)current->mm->context.vdso + vdso64_rt_sigtramp)
+       if (current->mm->context.vdso &&
+           nip == VDSO64_SYMBOL(current->mm->context.vdso, sigtramp_rt64))
                return 1;
        return 0;
 }