Skip to contentSkip to conversation

arm64: Add a compat vDSO

RFC PATCH Superseded Kevin Brodsky 3 participants 19 messages Oct 27, 2016 – Dec 1, 2016

Subsystems (2)

v2 of 3 Superseded Latest is v3 →

lore
Share & tools
lore
#0 lore raw

v2 cover arm64: Add a compat vDSO

Hi,

This series adds support for a compat (AArch32) vDSO, providing two userspace functionalities to compat processes:

* "Virtual" time syscalls (gettimeofday and clock_gettime). The implementation is an adaptation of the arm vDSO (vgettimeofday.c), sharing the data page with the 64-bit vDSO.

* sigreturn trampolines, following the example of the 64-bit vDSO (sigreturn.S), but slightly more complicated because we provide A32 and T32 variants for both sigreturn and rt_sigreturn.

The first point brings the performance improvement expected of a vDSO, by implementing time syscalls directly in userspace. The second point allows us to get rid of the compat vector page, at the expense of the kuser helpers (this is one reason for not enabling the compat vDSO by default).

Unfortunately, this time we cannot escape using a 32-bit toolchain. To build the compat VDSO, CONFIG_COMPAT_VDSO must be set *and* CROSS_COMPILE_ARM32 must be defined to the prefix of a 32-bit compiler. Failure to do so will not prevent building the kernel, but a warning will be printed and the compat vDSO will not be built.

Thanks,
Kevin

Changelog v1..v2:
* Rebased on 4.9-rc2. I preserved the spirit of 5a9e3e156ec1 ("arm64:
apply __ro_after_init to some objects") by making the new vdso{,32}_mappings static variables __ro_after_init, and removing pages from struct vdso_mappings.
* Added CONFIG_CROSS_COMPILE_ARM32, on the same principle as CONFIG_CROSS_COMPILE. That may help avoid forgetting to set the variable when building the kernel with CONFIG_COMPAT_VDSO.

Kevin Brodsky (8):
arm64: Refactor vDSO setup
arm64: compat: Add time-related syscall numbers
arm64: compat: Expose offset to registers in sigframes
arm64: compat: Add a 32-bit vDSO
arm64: compat: 32-bit vDSO setup
arm64: elf: Set AT_SYSINFO_EHDR in compat processes
arm64: compat: Use vDSO sigreturn trampolines if available
arm64: Wire up and expose the new compat vDSO

 arch/arm64/Kconfig                       |  26 +++
 arch/arm64/Makefile                      |  28 ++-
 arch/arm64/include/asm/elf.h             |  15 +-
 arch/arm64/include/asm/signal32.h        |  46 +++++
 arch/arm64/include/asm/unistd.h          |   2 +
 arch/arm64/include/asm/vdso.h            |   3 +
 arch/arm64/kernel/Makefile               |   8 +-
 arch/arm64/kernel/asm-offsets.c          |  13 ++
 arch/arm64/kernel/signal32.c             |  61 ++-----
 arch/arm64/kernel/vdso.c                 | 199 ++++++++++++---------
 arch/arm64/kernel/vdso32/Makefile        | 121 +++++++++++++
 arch/arm64/kernel/vdso32/sigreturn.S     |  86 +++++++++
 arch/arm64/kernel/vdso32/vdso.S          |  32 ++++
 arch/arm64/kernel/vdso32/vdso.lds.S      |  98 +++++++++++
 arch/arm64/kernel/vdso32/vgettimeofday.c | 294 +++++++++++++++++++++++++++++++
 15 files changed, 897 insertions(+), 135 deletions(-)
 create mode 100644 arch/arm64/kernel/vdso32/Makefile
 create mode 100644 arch/arm64/kernel/vdso32/sigreturn.S
 create mode 100644 arch/arm64/kernel/vdso32/vdso.S
 create mode 100644 arch/arm64/kernel/vdso32/vdso.lds.S
 create mode 100644 arch/arm64/kernel/vdso32/vgettimeofday.c
Signature · 1 line
2.10.0
#1 lore raw

RFC PATCH v2 1/8 arm64: Refactor vDSO setup

Move the logic for setting up mappings and pages for the vDSO into static functions with a clear interface. This will allow to reuse the setup code for the future compat vDSO.

---
 arch/arm64/kernel/vdso.c | 177 ++++++++++++++++++++++++++---------------------
 1 file changed, 98 insertions(+), 79 deletions(-)
arch/arm64/kernel/vdso.c +98 -79
index a2c2478e7d78..c239b1c15eb3 100644
@@ -37,8 +37,10 @@
 #include <asm/vdso.h>
 #include <asm/vdso_datapage.h>
 
-extern char vdso_start, vdso_end;
-static unsigned long vdso_pages __ro_after_init;
+struct vdso_mappings {
+	unsigned long num_pages;
+	struct vm_special_mapping data_mapping, code_mapping;
+};
 
 /*
  * The vDSO data page.
@@ -49,6 +51,92 @@ static union {
 } vdso_data_store __page_aligned_data;
 struct vdso_data *vdso_data = &vdso_data_store.data;
 
+static int __init setup_vdso_mappings(const char *name,
+				      const char *code_start,
+				      const char *code_end,
+				      struct vdso_mappings *mappings)
+{
+	unsigned long i, num_pages;
+	struct page **pages;
+
+	if (memcmp(code_start, "\177ELF", 4)) {
+		pr_err("%s is not a valid ELF object!\n", name);
+		return -EINVAL;
+	}
+
+	num_pages = (code_end - code_start) >> PAGE_SHIFT;
+	pr_info("%s: %ld pages (%ld code @ %p, %ld data @ %p)\n",
+		name, num_pages + 1, num_pages, code_start, 1L, vdso_data);
+
+	/* Allocate the vDSO code pages, plus a page for the data. */
+	pages = kcalloc(num_pages + 1, sizeof(struct page *), GFP_KERNEL);
+	if (pages == NULL)
+		return -ENOMEM;
+
+	/* Grab the vDSO data page. */
+	pages[0] = pfn_to_page(PHYS_PFN(__pa(vdso_data)));
+
+	/* Grab the vDSO code pages. */
+	for (i = 0; i < num_pages; i++)
+		pages[i + 1] = pfn_to_page(PHYS_PFN(__pa(code_start)) + i);
+
+	/* Populate the special mapping structures */
+	mappings->data_mapping = (struct vm_special_mapping) {
+		.name	= "[vvar]",
+		.pages	= &pages[0],
+	};
+
+	mappings->code_mapping = (struct vm_special_mapping) {
+		.name	= "[vdso]",
+		.pages	= &pages[1],
+	};
+
+	mappings->num_pages = num_pages;
+	return 0;
+}
+
+static int setup_vdso_pages(const struct vdso_mappings *mappings)
+{
+	struct mm_struct *mm = current->mm;
+	unsigned long vdso_base, vdso_text_len, vdso_mapping_len;
+	void *ret;
+
+	vdso_text_len = mappings->num_pages << PAGE_SHIFT;
+	/* Be sure to map the data page */
+	vdso_mapping_len = vdso_text_len + PAGE_SIZE;
+
+	if (down_write_killable(&mm->mmap_sem))
+		return -EINTR;
+	vdso_base = get_unmapped_area(NULL, 0, vdso_mapping_len, 0, 0);
+	if (IS_ERR_VALUE(vdso_base)) {
+		ret = ERR_PTR(vdso_base);
+		goto up_fail;
+	}
+	ret = _install_special_mapping(mm, vdso_base, PAGE_SIZE,
+				       VM_READ|VM_MAYREAD,
+				       &mappings->data_mapping);
+	if (IS_ERR(ret))
+		goto up_fail;
+
+	vdso_base += PAGE_SIZE;
+	mm->context.vdso = (void *)vdso_base;
+	ret = _install_special_mapping(mm, vdso_base, vdso_text_len,
+				       VM_READ|VM_EXEC|
+				       VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
+				       &mappings->code_mapping);
+	if (IS_ERR(ret))
+		goto up_fail;
+
+
+	up_write(&mm->mmap_sem);
+	return 0;
+
+up_fail:
+	mm->context.vdso = NULL;
+	up_write(&mm->mmap_sem);
+	return PTR_ERR(ret);
+}
+
 #ifdef CONFIG_COMPAT
 /*
  * Create and map the vectors page for AArch32 tasks.
@@ -71,11 +159,11 @@ static int __init alloc_vectors_page(void)
 
 	/* kuser helpers */
 	memcpy((void *)vpage + 0x1000 - kuser_sz, __kuser_helper_start,
-		kuser_sz);
+	       kuser_sz);
 
 	/* sigreturn code */
 	memcpy((void *)vpage + AARCH32_KERN_SIGRET_CODE_OFFSET,
-               __aarch32_sigret_code_start, sigret_sz);
+	       __aarch32_sigret_code_start, sigret_sz);
 
 	flush_icache_range(vpage, vpage + PAGE_SIZE);
 	vectors_page[0] = virt_to_page(vpage);
@@ -110,90 +198,21 @@ int aarch32_setup_vectors_page(struct linux_binprm *bprm, int uses_interp)
 }
 #endif /* CONFIG_COMPAT */
 
-static struct vm_special_mapping vdso_spec[2] __ro_after_init = {
-	{
-		.name	= "[vvar]",
-	},
-	{
-		.name	= "[vdso]",
-	},
-};
+extern char vdso_start, vdso_end;
+
+static struct vdso_mappings vdso_mappings __ro_after_init;
 
 static int __init vdso_init(void)
 {
-	int i;
-	struct page **vdso_pagelist;
-
-	if (memcmp(&vdso_start, "\177ELF", 4)) {
-		pr_err("vDSO is not a valid ELF object!\n");
-		return -EINVAL;
-	}
-
-	vdso_pages = (&vdso_end - &vdso_start) >> PAGE_SHIFT;
-	pr_info("vdso: %ld pages (%ld code @ %p, %ld data @ %p)\n",
-		vdso_pages + 1, vdso_pages, &vdso_start, 1L, vdso_data);
-
-	/* Allocate the vDSO pagelist, plus a page for the data. */
-	vdso_pagelist = kcalloc(vdso_pages + 1, sizeof(struct page *),
-				GFP_KERNEL);
-	if (vdso_pagelist == NULL)
-		return -ENOMEM;
-
-	/* Grab the vDSO data page. */
-	vdso_pagelist[0] = pfn_to_page(PHYS_PFN(__pa(vdso_data)));
-
-	/* Grab the vDSO code pages. */
-	for (i = 0; i < vdso_pages; i++)
-		vdso_pagelist[i + 1] = pfn_to_page(PHYS_PFN(__pa(&vdso_start)) + i);
-
-	vdso_spec[0].pages = &vdso_pagelist[0];
-	vdso_spec[1].pages = &vdso_pagelist[1];
-
-	return 0;
+	return setup_vdso_mappings("vdso", &vdso_start, &vdso_end,
+				   &vdso_mappings);
 }
 arch_initcall(vdso_init);
 
 int arch_setup_additional_pages(struct linux_binprm *bprm,
 				int uses_interp)
 {
-	struct mm_struct *mm = current->mm;
-	unsigned long vdso_base, vdso_text_len, vdso_mapping_len;
-	void *ret;
-
-	vdso_text_len = vdso_pages << PAGE_SHIFT;
-	/* Be sure to map the data page */
-	vdso_mapping_len = vdso_text_len + PAGE_SIZE;
-
-	if (down_write_killable(&mm->mmap_sem))
-		return -EINTR;
-	vdso_base = get_unmapped_area(NULL, 0, vdso_mapping_len, 0, 0);
-	if (IS_ERR_VALUE(vdso_base)) {
-		ret = ERR_PTR(vdso_base);
-		goto up_fail;
-	}
-	ret = _install_special_mapping(mm, vdso_base, PAGE_SIZE,
-				       VM_READ|VM_MAYREAD,
-				       &vdso_spec[0]);
-	if (IS_ERR(ret))
-		goto up_fail;
-
-	vdso_base += PAGE_SIZE;
-	mm->context.vdso = (void *)vdso_base;
-	ret = _install_special_mapping(mm, vdso_base, vdso_text_len,
-				       VM_READ|VM_EXEC|
-				       VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
-				       &vdso_spec[1]);
-	if (IS_ERR(ret))
-		goto up_fail;
-
-
-	up_write(&mm->mmap_sem);
-	return 0;
-
-up_fail:
-	mm->context.vdso = NULL;
-	up_write(&mm->mmap_sem);
-	return PTR_ERR(ret);
+	return setup_vdso_pages(&vdso_mappings);
 }
 
 /*
Signature · 1 line
2.10.0
#2 lore raw

RFC PATCH v2 2/8 arm64: compat: Add time-related syscall numbers

In reply to Kevin Brodsky

They will be used by the future compat vDSO.

The compat syscall numbers correspond to the arm syscall numbers, see arch/arm/include/uapi/asm/unistd.h.

---
 arch/arm64/include/asm/unistd.h | 2 ++
 1 file changed, 2 insertions(+)
arch/arm64/include/asm/unistd.h +2 -0
index e78ac26324bd..8d1c5f5e58f3 100644
@@ -34,8 +34,10 @@
 #define __NR_compat_exit		1
 #define __NR_compat_read		3
 #define __NR_compat_write		4
+#define __NR_compat_gettimeofday	78
 #define __NR_compat_sigreturn		119
 #define __NR_compat_rt_sigreturn	173
+#define __NR_compat_clock_gettime	263
 
 /*
  * The following SVCs are ARM private.
Signature · 1 line
2.10.0
#3 lore raw

RFC PATCH v2 3/8 arm64: compat: Expose offset to registers in sigframes

In reply to Kevin Brodsky

This will be needed to provide debug information (CFI/unwind tables) in compat sigreturn trampolines, part of the future compat vDSO.

Also fix minor style issues reported by checkpatch.

---
 arch/arm64/include/asm/signal32.h | 46 +++++++++++++++++++++++++++++++++++++++
 arch/arm64/kernel/asm-offsets.c   | 13 +++++++++++
 arch/arm64/kernel/signal32.c      | 46 ---------------------------------------
 3 files changed, 59 insertions(+), 46 deletions(-)
arch/arm64/include/asm/signal32.h +46 -0
index eeaa97559bab..9b1bcd3abd83 100644
@@ -20,6 +20,52 @@
 #ifdef CONFIG_COMPAT
 #include <linux/compat.h>
 
+struct compat_sigcontext {
+	/* We always set these two fields to 0 */
+	compat_ulong_t			trap_no;
+	compat_ulong_t			error_code;
+
+	compat_ulong_t			oldmask;
+	compat_ulong_t			arm_r0;
+	compat_ulong_t			arm_r1;
+	compat_ulong_t			arm_r2;
+	compat_ulong_t			arm_r3;
+	compat_ulong_t			arm_r4;
+	compat_ulong_t			arm_r5;
+	compat_ulong_t			arm_r6;
+	compat_ulong_t			arm_r7;
+	compat_ulong_t			arm_r8;
+	compat_ulong_t			arm_r9;
+	compat_ulong_t			arm_r10;
+	compat_ulong_t			arm_fp;
+	compat_ulong_t			arm_ip;
+	compat_ulong_t			arm_sp;
+	compat_ulong_t			arm_lr;
+	compat_ulong_t			arm_pc;
+	compat_ulong_t			arm_cpsr;
+	compat_ulong_t			fault_address;
+};
+
+struct compat_ucontext {
+	compat_ulong_t			uc_flags;
+	compat_uptr_t			uc_link;
+	compat_stack_t			uc_stack;
+	struct compat_sigcontext	uc_mcontext;
+	compat_sigset_t			uc_sigmask;
+	int		__unused[32 - (sizeof(compat_sigset_t) / sizeof(int))];
+	compat_ulong_t			uc_regspace[128] __aligned(8);
+};
+
+struct compat_sigframe {
+	struct compat_ucontext	uc;
+	compat_ulong_t		retcode[2];
+};
+
+struct compat_rt_sigframe {
+	struct compat_siginfo info;
+	struct compat_sigframe sig;
+};
+
 #define AARCH32_KERN_SIGRET_CODE_OFFSET	0x500
 
 extern const compat_ulong_t aarch32_sigret_code[6];
arch/arm64/kernel/asm-offsets.c +13 -0
index 4a2f0f0fef32..965371186a5a 100644
@@ -26,6 +26,7 @@
 #include <asm/cpufeature.h>
 #include <asm/thread_info.h>
 #include <asm/memory.h>
+#include <asm/signal32.h>
 #include <asm/smp_plat.h>
 #include <asm/suspend.h>
 #include <asm/vdso_datapage.h>
@@ -75,6 +76,18 @@ int main(void)
   DEFINE(S_ORIG_ADDR_LIMIT,	offsetof(struct pt_regs, orig_addr_limit));
   DEFINE(S_FRAME_SIZE,		sizeof(struct pt_regs));
   BLANK();
+#ifdef CONFIG_COMPAT
+  DEFINE(COMPAT_SIGFRAME_REGS_OFFSET,
+				offsetof(struct compat_sigframe, uc) +
+				offsetof(struct compat_ucontext, uc_mcontext) +
+				offsetof(struct compat_sigcontext, arm_r0));
+  DEFINE(COMPAT_RT_SIGFRAME_REGS_OFFSET,
+				offsetof(struct compat_rt_sigframe, sig) +
+				offsetof(struct compat_sigframe, uc) +
+				offsetof(struct compat_ucontext, uc_mcontext) +
+				offsetof(struct compat_sigcontext, arm_r0));
+  BLANK();
+#endif
   DEFINE(MM_CONTEXT_ID,		offsetof(struct mm_struct, context.id.counter));
   BLANK();
   DEFINE(VMA_VM_MM,		offsetof(struct vm_area_struct, vm_mm));
arch/arm64/kernel/signal32.c +0 -46

58 lines not on this page · raw message

Signature · 1 line
2.10.0
#4 lore raw

RFC PATCH v2 4/8 arm64: compat: Add a 32-bit vDSO

In reply to Kevin Brodsky

Provide the files necessary for building a compat (AArch32) vDSO in kernel/vdso32.

This is mostly an adaptation of the arm vDSO. The most significant change in vgettimeofday.c is the use of the arm64 vdso_data struct, allowing the vDSO data page to be shared between the 32 and 64-bit vDSOs.

In addition to the time functions, sigreturn trampolines are also provided, aiming at replacing those in the vector page. To improve debugging, CFI and unwinding directives are used, based on glibc's implementation. Symbol offsets are made available to the kernel using the same method as the 64-bit vDSO.

There is unfortunately an important caveat to all this: we cannot get away with hand-coding 32-bit instructions like in kernel/kuser32.S, this time we really need a 32-bit compiler. The compat vDSO Makefile relies on CROSS_COMPILE_ARM32 to provide a 32-bit compiler, appropriate logic will be added to the arm64 Makefile later on to ensure that an attempt to build the compat vDSO is made only if this variable has been set properly.

---
 arch/arm64/kernel/vdso32/Makefile        | 121 +++++++++++++
 arch/arm64/kernel/vdso32/sigreturn.S     |  86 +++++++++
 arch/arm64/kernel/vdso32/vdso.S          |  32 ++++
 arch/arm64/kernel/vdso32/vdso.lds.S      |  98 +++++++++++
 arch/arm64/kernel/vdso32/vgettimeofday.c | 294 +++++++++++++++++++++++++++++++
 5 files changed, 631 insertions(+)
 create mode 100644 arch/arm64/kernel/vdso32/Makefile
 create mode 100644 arch/arm64/kernel/vdso32/sigreturn.S
 create mode 100644 arch/arm64/kernel/vdso32/vdso.S
 create mode 100644 arch/arm64/kernel/vdso32/vdso.lds.S
 create mode 100644 arch/arm64/kernel/vdso32/vgettimeofday.c
arch/arm64/kernel/vdso32/Makefile new file +121 -0
new file mode 100644
index 000000000000..38facc870f6e
@@ -0,0 +1,121 @@
+#
+# Building a vDSO image for AArch32.
+#
+# Author: Kevin Brodsky <[email protected]>
+# A mix between the arm64 and arm vDSO Makefiles.
+
+CC_ARM32 := $(CROSS_COMPILE_ARM32)gcc
+
+# Same as cc-ldoption, but using CC_ARM32 instead of CC
+cc32-ldoption = $(call try-run,\
+        $(CC_ARM32) $(1) -nostdlib -x c /dev/null -o "$$TMP",$(1),$(2))
+
+# Borrow vdsomunge.c from the arm vDSO
+munge := arch/arm/vdso/vdsomunge
+hostprogs-y := $(srctree)/$(munge)
+
+c-obj-vdso := vgettimeofday.o
+asm-obj-vdso := sigreturn.o
+
+# Build rules
+targets := $(c-obj-vdso) $(asm-obj-vdso) vdso.so vdso.so.dbg vdso.so.raw
+c-obj-vdso := $(addprefix $(obj)/, $(c-obj-vdso))
+asm-obj-vdso := $(addprefix $(obj)/, $(asm-obj-vdso))
+obj-vdso := $(c-obj-vdso) $(asm-obj-vdso)
+
+ccflags-y := -fPIC -fno-common -fno-builtin -fno-stack-protector
+ccflags-y += -DDISABLE_BRANCH_PROFILING
+
+# Force -O2 to avoid libgcc dependencies
+VDSO_CFLAGS := -march=armv8-a -O2
+# Import some useful flags from arch/arm/Makefile
+VDSO_CFLAGS += -mabi=aapcs-linux -mfloat-abi=soft -funwind-tables
+# The 32-bit compiler does not provide 128-bit integers, which are used in
+# some headers that are indirectly included from the vDSO code.
+# This hack makes the compiler happy and should trigger a warning/error if
+# variables of such type are referenced.
+VDSO_CFLAGS += -D__uint128_t='void*'
+# Silence some warnings coming from headers that operate on long's
+VDSO_CFLAGS += -Wno-shift-count-overflow -Wno-int-to-pointer-cast
+
+# We need to use the global flags to compile the vDSO files. However some flags
+# inherited from either the top-level or the arm64 Makefile are not appropriate
+# for the 32-bit compiler, this function takes care of changing them as
+# appropriate.
+sanitize_flags = \
+        $(subst $(shell $(CC) -print-file-name=include), \
+                $(shell $(CC_ARM32) -print-file-name=include), \
+        $(filter-out -pg -mgeneral-regs-only -mpc-relative-literal-loads \
+                     -fno-asynchronous-unwind-tables, \
+        $(1)))
+
+VDSO_LDFLAGS := -Wl,-Bsymbolic -Wl,--no-undefined -Wl,-soname=linux-vdso.so.1
+VDSO_LDFLAGS += -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096
+VDSO_LDFLAGS += -nostdlib -shared -mfloat-abi=soft
+VDSO_LDFLAGS += $(call cc32-ldoption, -Wl$(comma)--hash-style=sysv)
+VDSO_LDFLAGS += $(call cc32-ldoption, -Wl$(comma)--build-id)
+VDSO_LDFLAGS += $(call cc32-ldoption, -fuse-ld=bfd)
+
+obj-y += vdso.o
+extra-y += vdso.lds
+CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
+
+CFLAGS_REMOVE_vdso.o = -pg
+
+# Disable gcov profiling for VDSO code
+GCOV_PROFILE := n
+
+# Force dependency (incbin is bad)
+$(obj)/vdso.o: $(obj)/vdso.so
+
+# Link rule for the .so file, .lds has to be first
+$(obj)/vdso.so.raw: $(src)/vdso.lds $(obj-vdso) FORCE
+	$(call if_changed,vdsold)
+
+$(obj)/vdso.so.dbg: $(obj)/vdso.so.raw $(objtree)/$(munge) FORCE
+	$(call if_changed,vdsomunge)
+
+# Strip rule for the .so file
+$(obj)/%.so: OBJCOPYFLAGS := -S
+$(obj)/%.so: $(obj)/%.so.dbg FORCE
+	$(call if_changed,objcopy)
+
+# Generate vDSO offsets using helper script (borrowed from the 64-bit vDSO)
+gen-vdsosym := $(srctree)/$(src)/../vdso/gen_vdso_offsets.sh
+quiet_cmd_vdsosym = VDSOSYM $@
+# The AArch64 nm should be able to read an AArch32 binary
+define cmd_vdsosym
+	$(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@
+endef
+
+include/generated/vdso32-offsets.h: $(obj)/vdso.so.dbg FORCE
+	$(call if_changed,vdsosym)
+
+# Compilation rules for the vDSO sources
+$(c-obj-vdso): %.o: %.c FORCE
+	$(call if_changed_dep,vdsocc)
+$(asm-obj-vdso): %.o: %.S FORCE
+	$(call if_changed_dep,vdsoas)
+
+# Actual build commands
+quiet_cmd_vdsold = VDSOL   $@
+      cmd_vdsold = $(CC_ARM32) $(call sanitize_flags,$(c_flags)) \
+                   $(VDSO_LDFLAGS) -Wl,-T $(filter %.lds,$^) $(filter %.o,$^) -o $@
+quiet_cmd_vdsocc = VDSOC   $@
+      cmd_vdsocc = $(CC_ARM32) $(call sanitize_flags,$(c_flags)) \
+                   $(VDSO_CFLAGS) -c -o $@ $<
+quiet_cmd_vdsoas = VDSOA   $@
+      cmd_vdsoas = $(CC_ARM32) $(call sanitize_flags, $(a_flags)) -c -o $@ $<
+
+quiet_cmd_vdsomunge = MUNGE   $@
+      cmd_vdsomunge = $(objtree)/$(munge) $< $@
+
+# Install commands for the unstripped file
+quiet_cmd_vdso_install = INSTALL $@
+      cmd_vdso_install = cp $(obj)/[email protected] $(MODLIB)/vdso/vdso32.so
+
+vdso.so: $(obj)/vdso.so.dbg
+	@mkdir -p $(MODLIB)/vdso
+	$(call cmd,vdso_install)
+
+vdso_install: vdso.so
arch/arm64/kernel/vdso32/sigreturn.S new file +86 -0

86 lines not on this page · raw message

arch/arm64/kernel/vdso32/vdso.S new file +32 -0
new file mode 100644
index 000000000000..fe19ff70eb76
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Will Deacon <[email protected]>
+ */
+
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <linux/const.h>
+#include <asm/page.h>
+
+	.globl vdso32_start, vdso32_end
+	.section .rodata
+	.balign PAGE_SIZE
+vdso32_start:
+	.incbin "arch/arm64/kernel/vdso32/vdso.so"
+	.balign PAGE_SIZE
+vdso32_end:
+
+	.previous
arch/arm64/kernel/vdso32/vdso.lds.S new file +98 -0

98 lines not on this page · raw message

arch/arm64/kernel/vdso32/vgettimeofday.c new file +294 -0

294 lines not on this page · raw message

Signature · 1 line
2.10.0
#5 lore raw

RFC PATCH v2 4/8 arm64: compat: Add a 32-bit vDSO

Dear Kevin,

Quoted 62 lines · On Thu, 27 Oct 2016 17:30:54 +0100 Kevin Brodsky wrote:

Provide the files necessary for building a compat (AArch32) vDSO in kernel/vdso32.

This is mostly an adaptation of the arm vDSO. The most significant change in vgettimeofday.c is the use of the arm64 vdso_data struct, allowing the vDSO data page to be shared between the 32 and 64-bit vDSOs.

In addition to the time functions, sigreturn trampolines are also provided, aiming at replacing those in the vector page. To improve debugging, CFI and unwinding directives are used, based on glibc's implementation. Symbol offsets are made available to the kernel using the same method as the 64-bit vDSO.

There is unfortunately an important caveat to all this: we cannot get away with hand-coding 32-bit instructions like in kernel/kuser32.S, this time we really need a 32-bit compiler. The compat vDSO Makefile relies on CROSS_COMPILE_ARM32 to provide a 32-bit compiler, appropriate logic will be added to the arm64 Makefile later on to ensure that an attempt to build the compat vDSO is made only if this variable has been set properly.

---
 arch/arm64/kernel/vdso32/Makefile        | 121 +++++++++++++
 arch/arm64/kernel/vdso32/sigreturn.S     |  86 +++++++++
 arch/arm64/kernel/vdso32/vdso.S          |  32 ++++
 arch/arm64/kernel/vdso32/vdso.lds.S      |  98 +++++++++++
 arch/arm64/kernel/vdso32/vgettimeofday.c | 294 +++++++++++++++++++++++++++++++
 5 files changed, 631 insertions(+)
 create mode 100644 arch/arm64/kernel/vdso32/Makefile
 create mode 100644 arch/arm64/kernel/vdso32/sigreturn.S
 create mode 100644 arch/arm64/kernel/vdso32/vdso.S
 create mode 100644 arch/arm64/kernel/vdso32/vdso.lds.S
 create mode 100644 arch/arm64/kernel/vdso32/vgettimeofday.c
arch/arm64/kernel/vdso32/Makefile new file +20 -0
new file mode 100644
index 000000000000..38facc870f6e
@@ -0,0 +1,121 @@
+#
+# Building a vDSO image for AArch32.
+#
+# Author: Kevin Brodsky <[email protected]>
+# A mix between the arm64 and arm vDSO Makefiles.
+
+CC_ARM32 := $(CROSS_COMPILE_ARM32)gcc
+
+# Same as cc-ldoption, but using CC_ARM32 instead of CC
+cc32-ldoption = $(call try-run,\
+        $(CC_ARM32) $(1) -nostdlib -x c /dev/null -o "$$TMP",$(1),$(2))
+
+# Borrow vdsomunge.c from the arm vDSO
+munge := arch/arm/vdso/vdsomunge
+hostprogs-y := $(srctree)/$(munge)
+
+c-obj-vdso := vgettimeofday.o
+asm-obj-vdso := sigreturn.o
+
+# Build rules

arch/arm64/kernel/vdso32/Makefile line 30

Quoted 10 lines
arch/arm64/kernel/vdso32/Makefile new file +10 -0
+targets := $(c-obj-vdso) $(asm-obj-vdso) vdso.so vdso.so.dbg vdso.so.raw
+c-obj-vdso := $(addprefix $(obj)/, $(c-obj-vdso))
+asm-obj-vdso := $(addprefix $(obj)/, $(asm-obj-vdso))
+obj-vdso := $(c-obj-vdso) $(asm-obj-vdso)
+
+ccflags-y := -fPIC -fno-common -fno-builtin -fno-stack-protector
+ccflags-y += -DDISABLE_BRANCH_PROFILING
+
+# Force -O2 to avoid libgcc dependencies
+VDSO_CFLAGS := -march=armv8-a -O2

For completeness, bringing 32bit compiler need to check whether the 32bit toolchain support some options. IIRC, armv8-a support isn't enabled until gcc 4.8, so old toolchains such gcc-4.7 will complain:
error: unrecognized argument in option ?-march=armv8-a?

Thanks,
Jisheng

#6 lore raw

RFC PATCH v2 4/8 arm64: compat: Add a 32-bit vDSO

Quoted 81 lines · Jisheng Zhang

Dear Kevin,

Quoted 62 lines · On Thu, 27 Oct 2016 17:30:54 +0100 Kevin Brodsky wrote:

Provide the files necessary for building a compat (AArch32) vDSO in kernel/vdso32.

This is mostly an adaptation of the arm vDSO. The most significant change in vgettimeofday.c is the use of the arm64 vdso_data struct, allowing the vDSO data page to be shared between the 32 and 64-bit vDSOs.

In addition to the time functions, sigreturn trampolines are also provided, aiming at replacing those in the vector page. To improve debugging, CFI and unwinding directives are used, based on glibc's implementation. Symbol offsets are made available to the kernel using the same method as the 64-bit vDSO.

There is unfortunately an important caveat to all this: we cannot get away with hand-coding 32-bit instructions like in kernel/kuser32.S, this time we really need a 32-bit compiler. The compat vDSO Makefile relies on CROSS_COMPILE_ARM32 to provide a 32-bit compiler, appropriate logic will be added to the arm64 Makefile later on to ensure that an attempt to build the compat vDSO is made only if this variable has been set properly.

---
  arch/arm64/kernel/vdso32/Makefile        | 121 +++++++++++++
  arch/arm64/kernel/vdso32/sigreturn.S     |  86 +++++++++
  arch/arm64/kernel/vdso32/vdso.S          |  32 ++++
  arch/arm64/kernel/vdso32/vdso.lds.S      |  98 +++++++++++
  arch/arm64/kernel/vdso32/vgettimeofday.c | 294 +++++++++++++++++++++++++++++++
  5 files changed, 631 insertions(+)

create mode 100644 arch/arm64/kernel/vdso32/Makefile create mode 100644 arch/arm64/kernel/vdso32/sigreturn.S create mode 100644 arch/arm64/kernel/vdso32/vdso.S create mode 100644 arch/arm64/kernel/vdso32/vdso.lds.S create mode 100644 arch/arm64/kernel/vdso32/vgettimeofday.c

arch/arm64/kernel/vdso32/Makefile new file +20 -0
new file mode 100644
index 000000000000..38facc870f6e
@@ -0,0 +1,121 @@
+#
+# Building a vDSO image for AArch32.
+#
+# Author: Kevin Brodsky <[email protected]>
+# A mix between the arm64 and arm vDSO Makefiles.
+
+CC_ARM32 := $(CROSS_COMPILE_ARM32)gcc
+
+# Same as cc-ldoption, but using CC_ARM32 instead of CC
+cc32-ldoption = $(call try-run,\
+        $(CC_ARM32) $(1) -nostdlib -x c /dev/null -o "$$TMP",$(1),$(2))
+
+# Borrow vdsomunge.c from the arm vDSO
+munge := arch/arm/vdso/vdsomunge
+hostprogs-y := $(srctree)/$(munge)
+
+c-obj-vdso := vgettimeofday.o
+asm-obj-vdso := sigreturn.o
+
+# Build rules

arch/arm64/kernel/vdso32/Makefile line 30

Quoted 10 lines
arch/arm64/kernel/vdso32/Makefile new file +10 -0
+targets := $(c-obj-vdso) $(asm-obj-vdso) vdso.so vdso.so.dbg vdso.so.raw
+c-obj-vdso := $(addprefix $(obj)/, $(c-obj-vdso))
+asm-obj-vdso := $(addprefix $(obj)/, $(asm-obj-vdso))
+obj-vdso := $(c-obj-vdso) $(asm-obj-vdso)
+
+ccflags-y := -fPIC -fno-common -fno-builtin -fno-stack-protector
+ccflags-y += -DDISABLE_BRANCH_PROFILING
+
+# Force -O2 to avoid libgcc dependencies
+VDSO_CFLAGS := -march=armv8-a -O2

For completeness, bringing 32bit compiler need to check whether the 32bit toolchain support some options. IIRC, armv8-a support isn't enabled until gcc 4.8, so old toolchains such gcc-4.7 will complain:
error: unrecognized argument in option ?-march=armv8-a?

Quoted 2 lines

Thanks,
Jisheng

That's a fair point. I guess -march=armv8-a is not strictly necessary and the produced vDSO should be fine if arch/arm/vdso also compiles fine. However we would still need to pass -march=armv7-a. I'm not sure what to do between:
* Checking that the compiler supports -march=armv8-a when inspecting CROSS_COMPILE_ARM32, and if it doesn't vdso32 will not be built.
* Checking whether -march=armv8-a is available here, and if it is not fall back to -march=armv7-a.

Thanks!
Kevin

maintainer
#7 lore raw

RFC PATCH v2 4/8 arm64: compat: Add a 32-bit vDSO

Quoted 79 lines · Kevin Brodsky
Quoted 69 lines · Jisheng Zhang
Quoted 68 lines · On Thu, 27 Oct 2016 17:30:54 +0100 Kevin Brodsky wrote:

Provide the files necessary for building a compat (AArch32) vDSO in kernel/vdso32.

This is mostly an adaptation of the arm vDSO. The most significant change in vgettimeofday.c is the use of the arm64 vdso_data struct, allowing the vDSO data page to be shared between the 32 and 64-bit vDSOs.

In addition to the time functions, sigreturn trampolines are also provided, aiming at replacing those in the vector page. To improve debugging, CFI and unwinding directives are used, based on glibc's implementation. Symbol offsets are made available to the kernel using the same method as the 64-bit vDSO.

There is unfortunately an important caveat to all this: we cannot get away with hand-coding 32-bit instructions like in kernel/kuser32.S, this time we really need a 32-bit compiler. The compat vDSO Makefile relies on CROSS_COMPILE_ARM32 to provide a 32-bit compiler, appropriate logic will be added to the arm64 Makefile later on to ensure that an attempt to build the compat vDSO is made only if this variable has been set properly.

---
  arch/arm64/kernel/vdso32/Makefile        | 121 +++++++++++++
  arch/arm64/kernel/vdso32/sigreturn.S     |  86 +++++++++
  arch/arm64/kernel/vdso32/vdso.S          |  32 ++++
  arch/arm64/kernel/vdso32/vdso.lds.S      |  98 +++++++++++
  arch/arm64/kernel/vdso32/vgettimeofday.c | 294 +++++++++++++++++++++++++++++++
  5 files changed, 631 insertions(+)

create mode 100644 arch/arm64/kernel/vdso32/Makefile create mode 100644 arch/arm64/kernel/vdso32/sigreturn.S create mode 100644 arch/arm64/kernel/vdso32/vdso.S create mode 100644 arch/arm64/kernel/vdso32/vdso.lds.S create mode 100644 arch/arm64/kernel/vdso32/vgettimeofday.c

arch/arm64/kernel/vdso32/Makefile new file +26 -0
new file mode 100644
index 000000000000..38facc870f6e
@@ -0,0 +1,121 @@
+#
+# Building a vDSO image for AArch32.
+#
+# Author: Kevin Brodsky <[email protected]>
+# A mix between the arm64 and arm vDSO Makefiles.
+
+CC_ARM32 := $(CROSS_COMPILE_ARM32)gcc
+
+# Same as cc-ldoption, but using CC_ARM32 instead of CC
+cc32-ldoption = $(call try-run,\
+        $(CC_ARM32) $(1) -nostdlib -x c /dev/null -o "$$TMP",$(1),$(2))
+
+# Borrow vdsomunge.c from the arm vDSO
+munge := arch/arm/vdso/vdsomunge
+hostprogs-y := $(srctree)/$(munge)
+
+c-obj-vdso := vgettimeofday.o
+asm-obj-vdso := sigreturn.o
+
+# Build rules
+targets := $(c-obj-vdso) $(asm-obj-vdso) vdso.so vdso.so.dbg vdso.so.raw
+c-obj-vdso := $(addprefix $(obj)/, $(c-obj-vdso))
+asm-obj-vdso := $(addprefix $(obj)/, $(asm-obj-vdso))
+obj-vdso := $(c-obj-vdso) $(asm-obj-vdso)
+
+ccflags-y := -fPIC -fno-common -fno-builtin -fno-stack-protector
Quoted 8 lines

arch/arm64/kernel/vdso32/Makefile line 30

Quoted 4 lines
arch/arm64/kernel/vdso32/Makefile new file +4 -0
+ccflags-y += -DDISABLE_BRANCH_PROFILING
+
+# Force -O2 to avoid libgcc dependencies
+VDSO_CFLAGS := -march=armv8-a -O2

For completeness, bringing 32bit compiler need to check whether the 32bit toolchain support some options. IIRC, armv8-a support isn't enabled until gcc 4.8, so old toolchains such gcc-4.7 will complain:
error: unrecognized argument in option ?-march=armv8-a?

Quoted 8 lines

That's a fair point. I guess -march=armv8-a is not strictly necessary and the produced vDSO should be fine if arch/arm/vdso also compiles fine. However we would still need to pass -march=armv7-a. I'm not sure what to do between:
* Checking that the compiler supports -march=armv8-a when inspecting CROSS_COMPILE_ARM32, and if it doesn't vdso32 will not be built.
* Checking whether -march=armv8-a is available here, and if it is not fall back to -march=armv7-a.

Does v8 vs v7 make any difference in the generated code? If not, we could just stick to armv7-a permanently.

Signature · 1 line
Catalin
#8 lore raw

RFC PATCH v2 4/8 arm64: compat: Add a 32-bit vDSO

Quoted 87 lines · Catalin Marinas
Quoted 78 lines · Kevin Brodsky
Quoted 69 lines · Jisheng Zhang
Quoted 68 lines · On Thu, 27 Oct 2016 17:30:54 +0100 Kevin Brodsky wrote:

Provide the files necessary for building a compat (AArch32) vDSO in kernel/vdso32.

This is mostly an adaptation of the arm vDSO. The most significant change in vgettimeofday.c is the use of the arm64 vdso_data struct, allowing the vDSO data page to be shared between the 32 and 64-bit vDSOs.

In addition to the time functions, sigreturn trampolines are also provided, aiming at replacing those in the vector page. To improve debugging, CFI and unwinding directives are used, based on glibc's implementation. Symbol offsets are made available to the kernel using the same method as the 64-bit vDSO.

There is unfortunately an important caveat to all this: we cannot get away with hand-coding 32-bit instructions like in kernel/kuser32.S, this time we really need a 32-bit compiler. The compat vDSO Makefile relies on CROSS_COMPILE_ARM32 to provide a 32-bit compiler, appropriate logic will be added to the arm64 Makefile later on to ensure that an attempt to build the compat vDSO is made only if this variable has been set properly.

---
   arch/arm64/kernel/vdso32/Makefile        | 121 +++++++++++++
   arch/arm64/kernel/vdso32/sigreturn.S     |  86 +++++++++
   arch/arm64/kernel/vdso32/vdso.S          |  32 ++++
   arch/arm64/kernel/vdso32/vdso.lds.S      |  98 +++++++++++
   arch/arm64/kernel/vdso32/vgettimeofday.c | 294 +++++++++++++++++++++++++++++++
   5 files changed, 631 insertions(+)

create mode 100644 arch/arm64/kernel/vdso32/Makefile create mode 100644 arch/arm64/kernel/vdso32/sigreturn.S create mode 100644 arch/arm64/kernel/vdso32/vdso.S create mode 100644 arch/arm64/kernel/vdso32/vdso.lds.S create mode 100644 arch/arm64/kernel/vdso32/vgettimeofday.c

arch/arm64/kernel/vdso32/Makefile new file +26 -0
new file mode 100644
index 000000000000..38facc870f6e
@@ -0,0 +1,121 @@
+#
+# Building a vDSO image for AArch32.
+#
+# Author: Kevin Brodsky <[email protected]>
+# A mix between the arm64 and arm vDSO Makefiles.
+
+CC_ARM32 := $(CROSS_COMPILE_ARM32)gcc
+
+# Same as cc-ldoption, but using CC_ARM32 instead of CC
+cc32-ldoption = $(call try-run,\
+        $(CC_ARM32) $(1) -nostdlib -x c /dev/null -o "$$TMP",$(1),$(2))
+
+# Borrow vdsomunge.c from the arm vDSO
+munge := arch/arm/vdso/vdsomunge
+hostprogs-y := $(srctree)/$(munge)
+
+c-obj-vdso := vgettimeofday.o
+asm-obj-vdso := sigreturn.o
+
+# Build rules
+targets := $(c-obj-vdso) $(asm-obj-vdso) vdso.so vdso.so.dbg vdso.so.raw
+c-obj-vdso := $(addprefix $(obj)/, $(c-obj-vdso))
+asm-obj-vdso := $(addprefix $(obj)/, $(asm-obj-vdso))
+obj-vdso := $(c-obj-vdso) $(asm-obj-vdso)
+
+ccflags-y := -fPIC -fno-common -fno-builtin -fno-stack-protector
Quoted 8 lines

arch/arm64/kernel/vdso32/Makefile line 30

Quoted 4 lines
arch/arm64/kernel/vdso32/Makefile new file +4 -0
+ccflags-y += -DDISABLE_BRANCH_PROFILING
+
+# Force -O2 to avoid libgcc dependencies
+VDSO_CFLAGS := -march=armv8-a -O2

For completeness, bringing 32bit compiler need to check whether the 32bit toolchain support some options. IIRC, armv8-a support isn't enabled until gcc 4.8, so old toolchains such gcc-4.7 will complain:
error: unrecognized argument in option ?-march=armv8-a?

Quoted 8 lines

That's a fair point. I guess -march=armv8-a is not strictly necessary and the produced vDSO should be fine if arch/arm/vdso also compiles fine. However we would still need to pass -march=armv7-a. I'm not sure what to do between:
* Checking that the compiler supports -march=armv8-a when inspecting CROSS_COMPILE_ARM32, and if it doesn't vdso32 will not be built.
* Checking whether -march=armv8-a is available here, and if it is not fall back to -march=armv7-a.

Quoted 2 lines

Does v8 vs v7 make any difference in the generated code? If not, we could just stick to armv7-a permanently.

I've just tried compiling with -march=armv7-a, and in fact it doesn't compile at all. It turns out vgettimeofday.c uses smp_rmb(), which expands to dmb ishld on arm64, and ishld doesn't exist in ARMv7. We could possibly work around that, but I think requiring GCC 4.8 is reasonable.

Thanks,
Kevin

maintainer
#9 lore raw

RFC PATCH v2 4/8 arm64: compat: Add a 32-bit vDSO

Quoted 21 lines · Kevin Brodsky
Quoted 20 lines · Catalin Marinas
Quoted 18 lines · Kevin Brodsky
Quoted 8 lines · Jisheng Zhang

arch/arm64/kernel/vdso32/Makefile line 30

Quoted 2 lines · On Thu, 27 Oct 2016 17:30:54 +0100 Kevin Brodsky wrote:
arch/arm64/kernel/vdso32/Makefile new file +2 -0
+# Force -O2 to avoid libgcc dependencies
+VDSO_CFLAGS := -march=armv8-a -O2

For completeness, bringing 32bit compiler need to check whether the 32bit toolchain support some options. IIRC, armv8-a support isn't enabled until gcc 4.8, so old toolchains such gcc-4.7 will complain:
error: unrecognized argument in option ?-march=armv8-a?

That's a fair point. I guess -march=armv8-a is not strictly necessary and the produced vDSO should be fine if arch/arm/vdso also compiles fine. However we would still need to pass -march=armv7-a. I'm not sure what to do between:
* Checking that the compiler supports -march=armv8-a when inspecting CROSS_COMPILE_ARM32, and if it doesn't vdso32 will not be built.
* Checking whether -march=armv8-a is available here, and if it is not fall back to -march=armv7-a.

Quoted 7 lines
Quoted 2 lines

Does v8 vs v7 make any difference in the generated code? If not, we could just stick to armv7-a permanently.

I've just tried compiling with -march=armv7-a, and in fact it doesn't compile at all. It turns out vgettimeofday.c uses smp_rmb(), which expands to dmb ishld on arm64, and ishld doesn't exist in ARMv7. We could possibly work around that, but I think requiring GCC 4.8 is reasonable.

Since vgettimeofday.c is meant to be compiled for AArch32, it wouldn't look too bad to define its own barriers rather than relying on the AArch64 ones. So you could define v7_smp_rmb/v7_smp_wmb and use them in this file. Alternatively, replace smp_rmb() with smp_mb() in this file but with a big comment about ARMv7 compilation requirement and "ishld" not being available.

Signature · 1 line
Catalin
#10 lore raw

RFC PATCH v2 4/8 arm64: compat: Add a 32-bit vDSO

Quoted 25 lines · Catalin Marinas
Quoted 18 lines · Kevin Brodsky
Quoted 17 lines · Catalin Marinas
Quoted 16 lines · Kevin Brodsky
Quoted 7 lines · Jisheng Zhang

arch/arm64/kernel/vdso32/Makefile line 30

Quoted 2 lines · On Thu, 27 Oct 2016 17:30:54 +0100 Kevin Brodsky wrote:
arch/arm64/kernel/vdso32/Makefile new file +2 -0
+# Force -O2 to avoid libgcc dependencies
+VDSO_CFLAGS := -march=armv8-a -O2

For completeness, bringing 32bit compiler need to check whether the 32bit toolchain support some options. IIRC, armv8-a support isn't enabled until gcc 4.8, so old toolchains such gcc-4.7 will complain:
error: unrecognized argument in option ?-march=armv8-a?

That's a fair point. I guess -march=armv8-a is not strictly necessary and the produced vDSO should be fine if arch/arm/vdso also compiles fine. However we would still need to pass -march=armv7-a. I'm not sure what to do between:
* Checking that the compiler supports -march=armv8-a when inspecting CROSS_COMPILE_ARM32, and if it doesn't vdso32 will not be built.
* Checking whether -march=armv8-a is available here, and if it is not fall back to -march=armv7-a.

Quoted 6 lines
Quoted 2 lines

Does v8 vs v7 make any difference in the generated code? If not, we could just stick to armv7-a permanently.

I've just tried compiling with -march=armv7-a, and in fact it doesn't compile at all. It turns out vgettimeofday.c uses smp_rmb(), which expands to dmb ishld on arm64, and ishld doesn't exist in ARMv7. We could possibly work around that, but I think requiring GCC 4.8 is reasonable.

Quoted 6 lines

Since vgettimeofday.c is meant to be compiled for AArch32, it wouldn't look too bad to define its own barriers rather than relying on the AArch64 ones. So you could define v7_smp_rmb/v7_smp_wmb and use them in this file. Alternatively, replace smp_rmb() with smp_mb() in this file but with a big comment about ARMv7 compilation requirement and "ishld" not being available.

Fair enough. I'll add AArch32 barrier macros and compile with -march=armv7-a if the compiler doesn't support armv8-a. It's true that using arm64 barrier macros in 32-bit code is a bit dodgy anyway.

Cheers,
Kevin

#11 lore raw

RFC PATCH v2 5/8 arm64: compat: 32-bit vDSO setup

In reply to Kevin Brodsky

If the compat vDSO is enabled, install it in compat processes. In this case, the compat vDSO replaces the vector page.

aarch32_setup_vectors_page has also been renamed to the more generic aarch32_setup_additional_pages to reflect both use cases.

---
 arch/arm64/include/asm/elf.h |  6 +++---
 arch/arm64/kernel/vdso.c     | 22 +++++++++++++++++++++-
 2 files changed, 24 insertions(+), 4 deletions(-)
arch/arm64/include/asm/elf.h +3 -3
index a55384f4a5d7..7da9452596ad 100644
@@ -185,10 +185,10 @@ typedef compat_elf_greg_t		compat_elf_gregset_t[COMPAT_ELF_NGREG];
 #define compat_start_thread		compat_start_thread
 #define COMPAT_SET_PERSONALITY(ex)	set_thread_flag(TIF_32BIT);
 #define COMPAT_ARCH_DLINFO
-extern int aarch32_setup_vectors_page(struct linux_binprm *bprm,
-				      int uses_interp);
+extern int aarch32_setup_additional_pages(struct linux_binprm *bprm,
+					  int uses_interp);
 #define compat_arch_setup_additional_pages \
-					aarch32_setup_vectors_page
+					aarch32_setup_additional_pages
 
 #endif /* CONFIG_COMPAT */
 
arch/arm64/kernel/vdso.c +21 -1
index c239b1c15eb3..76fb5e9ca521 100644
@@ -138,6 +138,25 @@ static int setup_vdso_pages(const struct vdso_mappings *mappings)
 }
 
 #ifdef CONFIG_COMPAT
+#ifdef CONFIG_VDSO32
+extern char vdso32_start, vdso32_end;
+
+static struct vdso_mappings vdso32_mappings __ro_after_init;
+
+static int __init vdso32_init(void)
+{
+	return setup_vdso_mappings("vdso32", &vdso32_start, &vdso32_end,
+				   &vdso32_mappings);
+}
+arch_initcall(vdso32_init);
+
+int aarch32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
+{
+	return setup_vdso_pages(&vdso32_mappings);
+}
+
+#else /* CONFIG_VDSO32 */
+
 /*
  * Create and map the vectors page for AArch32 tasks.
  */
@@ -172,7 +191,7 @@ static int __init alloc_vectors_page(void)
 }
 arch_initcall(alloc_vectors_page);
 
-int aarch32_setup_vectors_page(struct linux_binprm *bprm, int uses_interp)
+int aarch32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 {
 	struct mm_struct *mm = current->mm;
 	unsigned long addr = AARCH32_VECTORS_BASE;
@@ -196,6 +215,7 @@ int aarch32_setup_vectors_page(struct linux_binprm *bprm, int uses_interp)
 
 	return PTR_ERR_OR_ZERO(ret);
 }
+#endif /* CONFIG_VDSO32 */
 #endif /* CONFIG_COMPAT */
 
 extern char vdso_start, vdso_end;
Signature · 1 line
2.10.0
#12 lore raw

RFC PATCH v2 6/8 arm64: elf: Set AT_SYSINFO_EHDR in compat processes

In reply to Kevin Brodsky

If the compat vDSO is enabled, we need to set AT_SYSINFO_EHDR in the auxiliary vector of compat processes to the address of the vDSO code page, so that the dynamic linker can find it (just like the regular vDSO).

Note that we cast context.vdso to unsigned long, instead of elf_addr_t, because elf_addr_t is 32-bit in compat_binfmt_elf.c, and casting to u32 would trigger a pointer narrowing warning.

---
 arch/arm64/include/asm/elf.h | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)
arch/arm64/include/asm/elf.h +7 -2
index 7da9452596ad..765c633950b7 100644
@@ -141,11 +141,12 @@ typedef struct user_fpsimd_state elf_fpregset_t;
 #define SET_PERSONALITY(ex)		clear_thread_flag(TIF_32BIT);
 
 /* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT entries changes */
-#define ARCH_DLINFO							\
+#define _SET_AUX_ENT_VDSO						\
 do {									\
 	NEW_AUX_ENT(AT_SYSINFO_EHDR,					\
-		    (elf_addr_t)current->mm->context.vdso);		\
+		    (unsigned long)current->mm->context.vdso);		\
 } while (0)
+#define ARCH_DLINFO _SET_AUX_ENT_VDSO
 
 #define ARCH_HAS_SETUP_ADDITIONAL_PAGES
 struct linux_binprm;
@@ -184,7 +185,11 @@ typedef compat_elf_greg_t		compat_elf_gregset_t[COMPAT_ELF_NGREG];
 
 #define compat_start_thread		compat_start_thread
 #define COMPAT_SET_PERSONALITY(ex)	set_thread_flag(TIF_32BIT);
+#ifdef CONFIG_VDSO32
+#define COMPAT_ARCH_DLINFO		_SET_AUX_ENT_VDSO
+#else
 #define COMPAT_ARCH_DLINFO
+#endif
 extern int aarch32_setup_additional_pages(struct linux_binprm *bprm,
 					  int uses_interp);
 #define compat_arch_setup_additional_pages \
Signature · 1 line
2.10.0
#13 lore raw

RFC PATCH v2 7/8 arm64: compat: Use vDSO sigreturn trampolines if available

In reply to Kevin Brodsky

If the compat vDSO is enabled, it replaces the vector page. Therefore, we use the sigreturn trampolines it provides instead of those in the vector page.

---
 arch/arm64/include/asm/vdso.h |  3 +++
 arch/arm64/kernel/signal32.c  | 15 +++++++++++++++
 2 files changed, 18 insertions(+)
arch/arm64/include/asm/vdso.h +3 -0
index 839ce0031bd5..f2a952338f1e 100644
@@ -28,6 +28,9 @@
 #ifndef __ASSEMBLY__
 
 #include <generated/vdso-offsets.h>
+#ifdef CONFIG_VDSO32
+#include <generated/vdso32-offsets.h>
+#endif
 
 #define VDSO_SYMBOL(base, name)						   \
 ({									   \
arch/arm64/kernel/signal32.c +15 -0
index 9de7d128e0e0..b72a4180a531 100644
@@ -28,6 +28,7 @@
 #include <asm/signal32.h>
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
+#include <asm/vdso.h>
 
 struct compat_vfp_sigframe {
 	compat_ulong_t	magic;
@@ -438,6 +439,19 @@ static void compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka,
 		retcode = ptr_to_compat(ka->sa.sa_restorer);
 	} else {
 		/* Set up sigreturn pointer */
+#ifdef CONFIG_VDSO32
+		void *vdso_page = current->mm->context.vdso;
+		void *trampoline =
+			(ka->sa.sa_flags & SA_SIGINFO
+			 ? (thumb
+			    ? VDSO_SYMBOL(vdso_page, compat_rt_sigreturn_thumb)
+			    : VDSO_SYMBOL(vdso_page, compat_rt_sigreturn_arm))
+			 : (thumb
+			    ? VDSO_SYMBOL(vdso_page, compat_sigreturn_thumb)
+			    : VDSO_SYMBOL(vdso_page, compat_sigreturn_arm)));
+
+		retcode = ptr_to_compat(trampoline) + thumb;
+#else
 		unsigned int idx = thumb << 1;
 
 		if (ka->sa.sa_flags & SA_SIGINFO)
@@ -446,6 +460,7 @@ static void compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka,
 		retcode = AARCH32_VECTORS_BASE +
 			  AARCH32_KERN_SIGRET_CODE_OFFSET +
 			  (idx << 2) + thumb;
+#endif
 	}
 
 	regs->regs[0]	= usig;
Signature · 1 line
2.10.0
#14 lore raw

RFC PATCH v2 8/8 arm64: Wire up and expose the new compat vDSO

In reply to Kevin Brodsky

Expose the new compat vDSO via the COMPAT_VDSO config option.

The option is not enabled in defconfig for two reasons:

* The vDSO page replaces the vector page. The vDSO provides its own sigreturn trampolines, replacing those in the vector page, but the kuser helpers are gone. As a result enabling the compat vDSO will break userspace programs relying on the kuser helpers.

* We really need a 32-bit compiler this time, and we rely on the user to provide it themselves by setting CROSS_COMPILE_ARM32. Therefore enabling the option by default would make little sense, since the user must explicitly set an environment variable anyway.

CONFIG_COMPAT_VDSO is not directly used in the code, because we want to ignore it (build as if it were not set) if the user didn't set CROSS_COMPILE_ARM32 properly. If the variable has been set to a valid prefix, CONFIG_VDSO32 will be set; this is the option that the code and Makefiles test.

For more flexibility, like CROSS_COMPILE, CROSS_COMPILE_ARM32 can also be set via CONFIG_CROSS_COMPILE_ARM32 (the environment variable overrides the config option).

---
 arch/arm64/Kconfig         | 26 ++++++++++++++++++++++++++
 arch/arm64/Makefile        | 28 ++++++++++++++++++++++++++--
 arch/arm64/kernel/Makefile |  8 ++++++--
 3 files changed, 58 insertions(+), 4 deletions(-)
arch/arm64/Kconfig +26 -0
index 969ef880d234..883e50def0eb 100644
@@ -1017,6 +1017,32 @@ config SYSVIPC_COMPAT
 	def_bool y
 	depends on COMPAT && SYSVIPC
 
+config COMPAT_VDSO
+	bool "32-bit vDSO"
+	depends on COMPAT
+	default n
+	help
+	  Warning: this completely removes the compat vector page, including
+	  kuser helpers, which may break 32-bit processes.
+
+	  Warning: a 32-bit toolchain is necessary to build the vDSO. You
+	  must explicitly define which toolchain should be used by setting
+	  CROSS_COMPILE_ARM32 to the prefix of the 32-bit toolchain (same format
+	  as CROSS_COMPILE). If a 32-bit compiler cannot be found, a warning
+	  will be printed and the kernel will be built as if COMPAT_VDSO had not
+	  been set.
+
+	  Provide a vDSO to 32-bit processes. It includes the symbols provided
+	  by the vDSO from the 32-bit kernel, so that a 32-bit libc can use
+	  the compat vDSO without modification. It also provides sigreturn
+	  trampolines, and replaces the vector page.
+
+config CROSS_COMPILE_ARM32
+	string "32-bit toolchain prefix"
+	help
+	  Same as setting CROSS_COMPILE_ARM32 in the environment, but saved for
+	  future builds. The environment variable overrides this config option.
+
 endmenu
 
 menu "Power management options"
arch/arm64/Makefile +26 -2
index 3635b8662724..370d8de0c100 100644
@@ -37,10 +37,32 @@ $(warning LSE atomics not supported by binutils)
   endif
 endif
 
-KBUILD_CFLAGS	+= -mgeneral-regs-only $(lseinstr)
+ifeq ($(CONFIG_COMPAT_VDSO), y)
+  CROSS_COMPILE_ARM32 ?= $(CONFIG_CROSS_COMPILE_ARM32:"%"=%)
+
+  # Check that the user has provided a valid prefix for the 32-bit toolchain.
+  # To prevent selecting the system gcc by default, the prefix is not allowed to
+  # be empty, unlike CROSS_COMPILE. In the unlikely event that the system gcc
+  # is actually the 32-bit ARM compiler to be used, the variable can be set to
+  # the dirname (e.g. CROSS_COMPILE_ARM32=/usr/bin/).
+  # Note: this Makefile is read both before and after regenerating the
+  # config (if needed). Any warning appearing before the config has been
+  # regenerated should be ignored.
+  ifeq ($(CROSS_COMPILE_ARM32),)
+    $(warning CROSS_COMPILE_ARM32 not defined or empty, the compat vDSO will not be built)
+  else ifeq ($(shell which $(CROSS_COMPILE_ARM32)gcc 2> /dev/null),)
+    $(warning $(CROSS_COMPILE_ARM32)gcc not found, the compat vDSO will not be built)
+  else
+    export CROSS_COMPILE_ARM32
+    export CONFIG_VDSO32 := y
+    vdso32 := -DCONFIG_VDSO32=1
+  endif
+endif
+
+KBUILD_CFLAGS	+= -mgeneral-regs-only $(lseinstr) $(vdso32)
 KBUILD_CFLAGS	+= -fno-asynchronous-unwind-tables
 KBUILD_CFLAGS	+= $(call cc-option, -mpc-relative-literal-loads)
-KBUILD_AFLAGS	+= $(lseinstr)
+KBUILD_AFLAGS	+= $(lseinstr) $(vdso32)
 
 ifeq ($(CONFIG_CPU_BIG_ENDIAN), y)
 KBUILD_CPPFLAGS	+= -mbig-endian
@@ -139,6 +161,8 @@ archclean:
 prepare: vdso_prepare
 vdso_prepare: prepare0
 	$(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso include/generated/vdso-offsets.h
+	$(if $(CONFIG_VDSO32),$(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso32 \
+					  include/generated/vdso32-offsets.h)
 
 define archhelp
   echo  '* Image.gz      - Compressed kernel image (arch/$(ARCH)/boot/Image.gz)'
arch/arm64/kernel/Makefile +6 -2
index 7d66bbaafc0c..1487f8cd06dd 100644
@@ -27,8 +27,11 @@ OBJCOPYFLAGS := --prefix-symbols=__efistub_
 $(obj)/%.stub.o: $(obj)/%.o FORCE
 	$(call if_changed,objcopy)
 
-arm64-obj-$(CONFIG_COMPAT)		+= sys32.o kuser32.o signal32.o 	\
-					   sys_compat.o entry32.o
+arm64-obj-$(CONFIG_COMPAT)		+= sys32.o signal32.o sys_compat.o	\
+					   entry32.o
+ifneq ($(CONFIG_VDSO32),y)
+arm64-obj-y				+= kuser32.o
+endif
 arm64-obj-$(CONFIG_FUNCTION_TRACER)	+= ftrace.o entry-ftrace.o
 arm64-obj-$(CONFIG_MODULES)		+= arm64ksyms.o module.o
 arm64-obj-$(CONFIG_ARM64_MODULE_PLTS)	+= module-plts.o
@@ -52,6 +55,7 @@ arm64-obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o	\
 					   cpu-reset.o
 
 obj-y					+= $(arm64-obj-y) vdso/ probes/
+obj-$(CONFIG_VDSO32)			+= vdso32/
 obj-m					+= $(arm64-obj-m)
 head-y					:= head.o
 extra-y					+= $(head-y) vmlinux.lds
Signature · 1 line
2.10.0
maintainer
#15 lore raw

RFC PATCH v2 8/8 arm64: Wire up and expose the new compat vDSO

Quoted 4 lines · Kevin Brodsky

* The vDSO page replaces the vector page. The vDSO provides its own sigreturn trampolines, replacing those in the vector page, but the kuser helpers are gone. As a result enabling the compat vDSO will break userspace programs relying on the kuser helpers.

I think vDSO and vectors page should not exclude each other. If you want to disable the vectors page, let's make it an independent config option like the KUSER_HELPERS in arch/arm64/mm/Kconfig. But I would very much like to be able to have both the vDSO and the vectors page at the same time.

Signature · 1 line
Catalin
#16 lore raw

RFC PATCH v2 8/8 arm64: Wire up and expose the new compat vDSO

Quoted 10 lines · Catalin Marinas
Quoted 4 lines · Kevin Brodsky

* The vDSO page replaces the vector page. The vDSO provides its own sigreturn trampolines, replacing those in the vector page, but the kuser helpers are gone. As a result enabling the compat vDSO will break userspace programs relying on the kuser helpers.

I think vDSO and vectors page should not exclude each other. If you want to disable the vectors page, let's make it an independent config option like the KUSER_HELPERS in arch/arm64/mm/Kconfig. But I would very much like to be able to have both the vDSO and the vectors page at the same time.

Indeed, I've had exactly the same feedback from Google yesterday (apparently many Android apps with native libs still target ARMv6....). I'll add the option to keep the kuser helpers.

There's a small problem though: how to ensure that the kuser helpers + sigreturn trampolines are always included if the compat vDSO is not built? I can enforce CONFIG_KUSER_HELPERS if !CONFIG_VDSO32 (directly in the code/Makefiles), but the dependency cannot be expressed in Kconfig.

Thanks,
Kevin

maintainer
#17 lore raw

RFC PATCH v2 8/8 arm64: Wire up and expose the new compat vDSO

Quoted 12 lines · Kevin Brodsky
Quoted 10 lines · Catalin Marinas
Quoted 4 lines · Kevin Brodsky

* The vDSO page replaces the vector page. The vDSO provides its own sigreturn trampolines, replacing those in the vector page, but the kuser helpers are gone. As a result enabling the compat vDSO will break userspace programs relying on the kuser helpers.

I think vDSO and vectors page should not exclude each other. If you want to disable the vectors page, let's make it an independent config option like the KUSER_HELPERS in arch/arm64/mm/Kconfig. But I would very much like to be able to have both the vDSO and the vectors page at the same time.

Quoted 8 lines

Indeed, I've had exactly the same feedback from Google yesterday (apparently many Android apps with native libs still target ARMv6....). I'll add the option to keep the kuser helpers.

There's a small problem though: how to ensure that the kuser helpers + sigreturn trampolines are always included if the compat vDSO is not built? I can enforce CONFIG_KUSER_HELPERS if !CONFIG_VDSO32 (directly in the code/Makefiles), but the dependency cannot be expressed in Kconfig.

Or you could insert a separate "sigpage" as arm32 does. This could leave independently of vDSO or vectors page.

Signature · 1 line
Catalin
#18 lore raw

RFC PATCH v2 8/8 arm64: Wire up and expose the new compat vDSO

Quoted 16 lines · Catalin Marinas
Quoted 15 lines · Kevin Brodsky
Quoted 10 lines · Catalin Marinas
Quoted 4 lines · Kevin Brodsky

* The vDSO page replaces the vector page. The vDSO provides its own sigreturn trampolines, replacing those in the vector page, but the kuser helpers are gone. As a result enabling the compat vDSO will break userspace programs relying on the kuser helpers.

I think vDSO and vectors page should not exclude each other. If you want to disable the vectors page, let's make it an independent config option like the KUSER_HELPERS in arch/arm64/mm/Kconfig. But I would very much like to be able to have both the vDSO and the vectors page at the same time.

Indeed, I've had exactly the same feedback from Google yesterday (apparently many Android apps with native libs still target ARMv6....). I'll add the option to keep the kuser helpers.

Quoted 6 lines
Quoted 4 lines

There's a small problem though: how to ensure that the kuser helpers + sigreturn trampolines are always included if the compat vDSO is not built? I can enforce CONFIG_KUSER_HELPERS if !CONFIG_VDSO32 (directly in the code/Makefiles), but the dependency cannot be expressed in Kconfig.

Or you could insert a separate "sigpage" as arm32 does. This could leave independently of vDSO or vectors page.

Yeah I thought about this too. It's a bit more work but probably cleaner and more flexible, that would also allow to disable the kuser helpers independently of the compat vDSO.

Thanks,
Kevin