* [RFC] arm: vdso: Convert sigpage to vdso implementation
@ 2014-01-28 16:25 Steve Capper
2014-01-28 17:10 ` Russell King - ARM Linux
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: Steve Capper @ 2014-01-28 16:25 UTC (permalink / raw)
To: linux-arm-kernel
ARM has a special sigpage that is used for signal return trampolines.
Its implementation is very similar to a VDSO conceptually in that it
occupies a special mapping in user address space.
One could actually host the trampoline code in a VDSO instead with the
added advantage that one could also host specialised routines there.
One such routine could be gettimeofday where on ARM we have architected
(and some vendor supplied) timers that can be queried entirely in
userspace, obviating the need for an expensive syscall.
This patch converts the sigpage implementation to a VDSO. It is mostly
a direct port from Will Deacon's arm64 implementation with the ARM
signal trampoline plumbed in.
Signed-off-by: Steve Capper <steve.capper@linaro.org>
---
As can be inferred from this RFC, I am interested ultimately in
implementing a syscall-less gettimeofday for ARM. Whilst researching
possible vectors page or VDSO implementations, I came across the
sigpage mechanism which is very similar to a VDSO.
The very simple function, __kernel_vdso_doubler, resolved in a test
program automatically on my Arndale board (running Fedora 20) without
any additional prodding.
IPC stress tests from LTP were executed to test the signal trampoline.
I would appreciate any comments on this approach of converting the
sigpage to a VDSO. If this looks sane to people, I will work on the
gettimeofday logic in a later patch.
Cheers,
--
Steve
---
arch/arm/include/asm/elf.h | 11 +++-
arch/arm/include/asm/mmu.h | 2 +-
arch/arm/include/asm/vdso.h | 44 +++++++++++++
arch/arm/kernel/Makefile | 9 +++
arch/arm/kernel/process.c | 48 +++++---------
arch/arm/kernel/signal.c | 38 ++---------
arch/arm/kernel/vdso.c | 105 +++++++++++++++++++++++++++++++
arch/arm/kernel/vdso/.gitignore | 2 +
arch/arm/kernel/vdso/Makefile | 72 +++++++++++++++++++++
arch/arm/kernel/vdso/gen_vdso_offsets.sh | 15 +++++
arch/arm/kernel/vdso/simple.S | 31 +++++++++
arch/arm/kernel/vdso/vdso.S | 35 +++++++++++
arch/arm/kernel/vdso/vdso.lds.S | 99 +++++++++++++++++++++++++++++
13 files changed, 442 insertions(+), 69 deletions(-)
create mode 100644 arch/arm/include/asm/vdso.h
create mode 100644 arch/arm/kernel/vdso.c
create mode 100644 arch/arm/kernel/vdso/.gitignore
create mode 100644 arch/arm/kernel/vdso/Makefile
create mode 100755 arch/arm/kernel/vdso/gen_vdso_offsets.sh
create mode 100644 arch/arm/kernel/vdso/simple.S
create mode 100644 arch/arm/kernel/vdso/vdso.S
create mode 100644 arch/arm/kernel/vdso/vdso.lds.S
diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h
index f4b46d3..ee45b67 100644
--- a/arch/arm/include/asm/elf.h
+++ b/arch/arm/include/asm/elf.h
@@ -132,6 +132,15 @@ extern unsigned long arch_randomize_brk(struct mm_struct *mm);
#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
struct linux_binprm;
int arch_setup_additional_pages(struct linux_binprm *, int);
-#endif
+
+#define AT_SYSINFO_EHDR 33
+#define __HAVE_ARCH_GATE_AREA 1
+
+#define ARCH_DLINFO \
+do { \
+ NEW_AUX_ENT(AT_SYSINFO_EHDR, \
+ (elf_addr_t)current->mm->context.vdso); \
+} while (0)
+#endif /* CONFIG_MMU */
#endif
diff --git a/arch/arm/include/asm/mmu.h b/arch/arm/include/asm/mmu.h
index 64fd151..11bcbf3 100644
--- a/arch/arm/include/asm/mmu.h
+++ b/arch/arm/include/asm/mmu.h
@@ -10,7 +10,7 @@ typedef struct {
int switch_pending;
#endif
unsigned int vmalloc_seq;
- unsigned long sigpage;
+ unsigned long vdso;
} mm_context_t;
#ifdef CONFIG_CPU_HAS_ASID
diff --git a/arch/arm/include/asm/vdso.h b/arch/arm/include/asm/vdso.h
new file mode 100644
index 0000000..024b9726
--- /dev/null
+++ b/arch/arm/include/asm/vdso.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2014 Linaro Ltd.
+ *
+ * Based on Will Deacon's implementation in arch/arm64
+ * 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/>.
+ */
+#ifndef __ASM_VDSO_H
+#define __ASM_VDSO_H
+
+#ifdef __KERNEL__
+
+/*
+ * Default link address for the vDSO.
+ * Since we randomise the VDSO mapping, there's little point in trying
+ * to prelink this.
+ */
+#define VDSO_LBASE 0x0
+
+#ifndef __ASSEMBLY__
+
+#include <generated/vdso-offsets.h>
+
+#define VDSO_SYMBOL(base, name) \
+({ \
+ (void *)(vdso_offset_##name - VDSO_LBASE + (unsigned long)(base)); \
+})
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_VDSO_H */
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index a30fc9b..87983ef 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -99,3 +99,12 @@ obj-$(CONFIG_SMP) += psci_smp.o
endif
extra-y := $(head-y) vmlinux.lds
+
+ifdef CONFIG_MMU
+obj-y += vdso.o
+obj-y += vdso/
+
+# vDSO - this must be built first to generate the symbol offsets
+$(call objectify,$(obj-y)): $(obj)/vdso/vdso-offsets.h
+$(obj)/vdso/vdso-offsets.h: $(obj)/vdso
+endif
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 92f7b15..1aa1cc2 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -467,46 +467,28 @@ int in_gate_area_no_mm(unsigned long addr)
}
#define is_gate_vma(vma) ((vma) == &gate_vma)
#else
-#define is_gate_vma(vma) 0
-#endif
+#define is_gate_vma(vma) (0)
-const char *arch_vma_name(struct vm_area_struct *vma)
+struct vm_area_struct * get_gate_vma(struct mm_struct *mm)
{
- return is_gate_vma(vma) ? "[vectors]" :
- (vma->vm_mm && vma->vm_start == vma->vm_mm->context.sigpage) ?
- "[sigpage]" : NULL;
+ return NULL;
}
-static struct page *signal_page;
-extern struct page *get_signal_page(void);
-
-int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
+int in_gate_area_no_mm(unsigned long addr)
{
- struct mm_struct *mm = current->mm;
- unsigned long addr;
- int ret;
-
- if (!signal_page)
- signal_page = get_signal_page();
- if (!signal_page)
- return -ENOMEM;
-
- down_write(&mm->mmap_sem);
- addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0);
- if (IS_ERR_VALUE(addr)) {
- ret = addr;
- goto up_fail;
- }
+ return 0;
+}
+#endif
- ret = install_special_mapping(mm, addr, PAGE_SIZE,
- VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
- &signal_page);
+const char *arch_vma_name(struct vm_area_struct *vma)
+{
+ if (is_gate_vma(vma))
+ return "[vectors]";
- if (ret == 0)
- mm->context.sigpage = addr;
+ if (vma->vm_mm && vma->vm_start == vma->vm_mm->context.vdso)
+ return "[vdso]";
- up_fail:
- up_write(&mm->mmap_sem);
- return ret;
+ return NULL;
}
+
#endif
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 04d6388..b510077 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -20,11 +20,10 @@
#include <asm/ucontext.h>
#include <asm/unistd.h>
#include <asm/vfp.h>
+#include <asm/vdso.h>
extern const unsigned long sigreturn_codes[7];
-static unsigned long signal_return_offset;
-
#ifdef CONFIG_CRUNCH
static int preserve_crunch_context(struct crunch_sigframe __user *frame)
{
@@ -395,8 +394,9 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig,
* except when the MPU has protected the vectors
* page from PL0
*/
- retcode = mm->context.sigpage + signal_return_offset +
- (idx << 2) + thumb;
+ retcode = (unsigned long) VDSO_SYMBOL(mm->context.vdso,
+ sigtramp);
+ retcode += (idx << 2) + thumb;
} else
#endif
{
@@ -600,33 +600,3 @@ do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall)
} while (thread_flags & _TIF_WORK_MASK);
return 0;
}
-
-struct page *get_signal_page(void)
-{
- unsigned long ptr;
- unsigned offset;
- struct page *page;
- void *addr;
-
- page = alloc_pages(GFP_KERNEL, 0);
-
- if (!page)
- return NULL;
-
- addr = page_address(page);
-
- /* Give the signal return code some randomness */
- offset = 0x200 + (get_random_int() & 0x7fc);
- signal_return_offset = offset;
-
- /*
- * Copy signal return handlers into the vector page, and
- * set sigreturn to be a pointer to these.
- */
- memcpy(addr + offset, sigreturn_codes, sizeof(sigreturn_codes));
-
- ptr = (unsigned long)addr + offset;
- flush_icache_range(ptr, ptr + sizeof(sigreturn_codes));
-
- return page;
-}
diff --git a/arch/arm/kernel/vdso.c b/arch/arm/kernel/vdso.c
new file mode 100644
index 0000000..fd69184
--- /dev/null
+++ b/arch/arm/kernel/vdso.c
@@ -0,0 +1,105 @@
+/*
+ * VDSO implementation for ARM
+ *
+ * Copyright (C) 2014 Linaro Ltd.
+ *
+ * Code based on Will Deacon's arm64 VDSO implementation.
+ * 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/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/binfmts.h>
+#include <asm/vdso.h>
+
+extern char vdso_start, vdso_end;
+static unsigned long vdso_pages;
+static struct page **vdso_pagelist;
+
+static int __init vdso_init(void)
+{
+ struct page *pg;
+ char *vbase;
+ int i, ret = 0;
+
+ vdso_pages = (&vdso_end - &vdso_start) >> PAGE_SHIFT;
+ pr_info("vdso: %ld pages (%ld code, %ld data) at base %p\n",
+ vdso_pages, vdso_pages, 0L, &vdso_start);
+
+ vdso_pagelist = kzalloc(sizeof(struct page *) * vdso_pages,
+ GFP_KERNEL);
+ if (vdso_pagelist == NULL) {
+ pr_err("Failed to allocate vDSO pagelist!\n");
+ return -ENOMEM;
+ }
+
+ /* Grab the vDSO code pages. */
+ for (i = 0; i < vdso_pages; i++) {
+ pg = virt_to_page(&vdso_start + i*PAGE_SIZE);
+ ClearPageReserved(pg);
+ get_page(pg);
+ vdso_pagelist[i] = pg;
+ }
+
+ /* Sanity check the shared object header. */
+ vbase = vmap(vdso_pagelist, 1, 0, PAGE_KERNEL);
+ if (vbase == NULL) {
+ pr_err("Failed to map vDSO pagelist!\n");
+ return -ENOMEM;
+ } else if (memcmp(vbase, "\177ELF", 4)) {
+ pr_err("vDSO is not a valid ELF object!\n");
+ ret = -EINVAL;
+ goto unmap;
+ }
+
+unmap:
+ vunmap(vbase);
+ return ret;
+}
+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_mapping_len;
+ int ret;
+
+ vdso_mapping_len = vdso_pages << PAGE_SHIFT;
+
+ down_write(&mm->mmap_sem);
+ vdso_base = get_unmapped_area(NULL, 0, vdso_mapping_len, 0, 0);
+ if (IS_ERR_VALUE(vdso_base)) {
+ ret = vdso_base;
+ goto up_fail;
+ }
+ mm->context.vdso = vdso_base;
+
+ ret = install_special_mapping(mm, vdso_base, vdso_mapping_len,
+ VM_READ | VM_EXEC |
+ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
+ vdso_pagelist);
+
+ if (ret) {
+ mm->context.vdso = 0;
+ goto up_fail;
+ }
+
+ up_fail:
+ up_write(&mm->mmap_sem);
+ return ret;
+}
diff --git a/arch/arm/kernel/vdso/.gitignore b/arch/arm/kernel/vdso/.gitignore
new file mode 100644
index 0000000..b8cc94e
--- /dev/null
+++ b/arch/arm/kernel/vdso/.gitignore
@@ -0,0 +1,2 @@
+vdso.lds
+vdso-offsets.h
diff --git a/arch/arm/kernel/vdso/Makefile b/arch/arm/kernel/vdso/Makefile
new file mode 100644
index 0000000..13d3531
--- /dev/null
+++ b/arch/arm/kernel/vdso/Makefile
@@ -0,0 +1,72 @@
+#
+# Building a vDSO image for ARM.
+#
+# Based heavily on arm64 implementation by:
+# Author: Will Deacon <will.deacon@arm.com>
+# Heavily based on the vDSO Makefiles for other archs.
+#
+
+obj-vdso := simple.o
+obj-sig := sigreturn_codes.o
+
+# Build rules
+targets := $(obj-vdso) $(obj-sig) vdso.so vdso.so.dbg
+obj-vdso := $(addprefix $(obj)/, $(obj-vdso))
+obj-sig := $(addprefix $(obj)/, $(obj-sig))
+
+ccflags-y := -shared -fno-common -fno-builtin
+ccflags-y += -nostdlib -Wl,-soname=linux-vdso.so.1 \
+ $(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
+
+obj-y += vdso.o
+extra-y += vdso.lds vdso-offsets.h
+CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
+
+# 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.dbg: $(src)/vdso.lds $(obj-vdso) $(obj-sig)
+ $(call if_changed,vdsold)
+
+# 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
+gen-vdsosym := $(srctree)/$(src)/gen_vdso_offsets.sh
+quiet_cmd_vdsosym = VDSOSYM $@
+define cmd_vdsosym
+ $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@ && \
+ cp $@ include/generated/
+endef
+
+$(obj)/vdso-offsets.h: $(obj)/vdso.so.dbg FORCE
+ $(call if_changed,vdsosym)
+
+# We can't move sigreturn_codes.S into our vdso as it contains code
+# which can also be used if we have no mmu. So we re-compile the
+# source from the parent directory, to prevent code duplication.
+$(obj)/sigreturn_codes.o: $(obj)/../sigreturn_codes.S
+ $(call if_changed_dep,vdsoas)
+
+# Assembly rules for the .S files
+$(obj-vdso): %.o: %.S
+ $(call if_changed_dep,vdsoas)
+
+# Actual build commands
+quiet_cmd_vdsold = VDSOL $@
+ cmd_vdsold = $(CC) $(c_flags) -Wl,-T $^ -o $@
+quiet_cmd_vdsoas = VDSOA $@
+ cmd_vdsoas = $(CC) $(a_flags) -c -o $@ $<
+
+# Install commands for the unstripped file
+quiet_cmd_vdso_install = INSTALL $@
+ cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@
+
+vdso.so: $(obj)/vdso.so.dbg
+ @mkdir -p $(MODLIB)/vdso
+ $(call cmd,vdso_install)
+
+vdso_install: vdso.so
diff --git a/arch/arm/kernel/vdso/gen_vdso_offsets.sh b/arch/arm/kernel/vdso/gen_vdso_offsets.sh
new file mode 100755
index 0000000..5b329ae
--- /dev/null
+++ b/arch/arm/kernel/vdso/gen_vdso_offsets.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+#
+# 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 vdso_offset_\2\t0x\1/p'
diff --git a/arch/arm/kernel/vdso/simple.S b/arch/arm/kernel/vdso/simple.S
new file mode 100644
index 0000000..6f21324
--- /dev/null
+++ b/arch/arm/kernel/vdso/simple.S
@@ -0,0 +1,31 @@
+/*
+ * Simple test function for VDSO implementation for ARM
+ *
+ * Copyright (C) 2014 Linaro Ltd.
+ *
+ * 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/>.
+ */
+
+
+#include <linux/linkage.h>
+#include <asm/unistd.h>
+
+/*
+ * An extremely simple test function:
+ * unsigned int __kernel_vdso_doubler(unsigned int arg);
+ */
+ .text
+ENTRY(__kernel_vdso_doubler)
+ lsl r0, r0, #1
+ mov pc, lr
+ENDPROC(__kernel_vdso_doubler)
diff --git a/arch/arm/kernel/vdso/vdso.S b/arch/arm/kernel/vdso/vdso.S
new file mode 100644
index 0000000..a459d42
--- /dev/null
+++ b/arch/arm/kernel/vdso/vdso.S
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2014 Linaro Ltd.
+ *
+ * Based on arm64 implementation by Will Deacon.
+ * 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/>.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <linux/const.h>
+#include <asm/page.h>
+
+ __PAGE_ALIGNED_DATA
+
+ .globl vdso_start, vdso_end
+ .balign PAGE_SIZE
+vdso_start:
+ .incbin "arch/arm/kernel/vdso/vdso.so"
+ .balign PAGE_SIZE
+vdso_end:
+
+ .previous
diff --git a/arch/arm/kernel/vdso/vdso.lds.S b/arch/arm/kernel/vdso/vdso.lds.S
new file mode 100644
index 0000000..1bacbe8
--- /dev/null
+++ b/arch/arm/kernel/vdso/vdso.lds.S
@@ -0,0 +1,99 @@
+/*
+ * GNU linker script for the VDSO library.
+ *
+ * Copyright (C) 2014 Linaro ltd.
+ * Based heavily on work by:
+ * Will Deacon <will.deacon@arm.com>
+ * Copyright (C) 2012 ARM Limited
+ * Heavily based on the vDSO linker scripts for other archs.
+ *
+ * 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/>.
+ *
+ */
+
+#include <linux/const.h>
+#include <asm/page.h>
+#include <asm/vdso.h>
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+
+SECTIONS
+{
+ . = VDSO_LBASE + SIZEOF_HEADERS;
+
+ .hash : { *(.hash) } :text
+ .gnu.hash : { *(.gnu.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+
+ .note : { *(.note.*) } :text :note
+
+ . = ALIGN(16);
+
+ .text : { *(.text*) } :text
+ PROVIDE (__etext = .);
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+
+ .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
+ .eh_frame : { KEEP (*(.eh_frame)) } :text
+
+ .dynamic : { *(.dynamic) } :text :dynamic
+
+ .rodata : { *(.rodata*) } :text
+
+ _end = .;
+ PROVIDE(end = .);
+
+ . = ALIGN(PAGE_SIZE);
+ PROVIDE(_vdso_data = .);
+
+ /DISCARD/ : {
+ *(.note.GNU-stack)
+ *(.data .data.* .gnu.linkonce.d.* .sdata*)
+ *(.bss .sbss .dynbss .dynsbss)
+ }
+}
+
+/*
+ * We must supply the ELF program headers explicitly to get just one
+ * PT_LOAD segment, and set the flags explicitly to make segments read-only.
+ */
+PHDRS
+{
+ text PT_LOAD FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */
+ dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
+ note PT_NOTE FLAGS(4); /* PF_R */
+ eh_frame_hdr PT_GNU_EH_FRAME;
+}
+
+/*
+ * This controls what symbols we export from the DSO.
+ */
+VERSION
+{
+ LINUX_2.6.39 {
+ global:
+ __kernel_vdso_doubler;
+ local: *;
+ };
+}
+
+/*
+ * Make the sigreturn code visible to the kernel.
+ */
+VDSO_sigtramp = sigreturn_codes;
--
1.8.1.4
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [RFC] arm: vdso: Convert sigpage to vdso implementation
2014-01-28 16:25 [RFC] arm: vdso: Convert sigpage to vdso implementation Steve Capper
@ 2014-01-28 17:10 ` Russell King - ARM Linux
2014-01-29 14:22 ` Steve Capper
2014-01-28 21:05 ` Nathan Lynch
2014-01-28 21:06 ` [RFC/PATCH] ARM: vDSO gettimeofday using generic timer architecture Nathan Lynch
2 siblings, 1 reply; 9+ messages in thread
From: Russell King - ARM Linux @ 2014-01-28 17:10 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Jan 28, 2014 at 04:25:08PM +0000, Steve Capper wrote:
> ARM has a special sigpage that is used for signal return trampolines.
> Its implementation is very similar to a VDSO conceptually in that it
> occupies a special mapping in user address space.
>
> One could actually host the trampoline code in a VDSO instead with the
> added advantage that one could also host specialised routines there.
> One such routine could be gettimeofday where on ARM we have architected
> (and some vendor supplied) timers that can be queried entirely in
> userspace, obviating the need for an expensive syscall.
>
> This patch converts the sigpage implementation to a VDSO. It is mostly
> a direct port from Will Deacon's arm64 implementation with the ARM
> signal trampoline plumbed in.
>
> Signed-off-by: Steve Capper <steve.capper@linaro.org>
> ---
> As can be inferred from this RFC, I am interested ultimately in
> implementing a syscall-less gettimeofday for ARM. Whilst researching
> possible vectors page or VDSO implementations, I came across the
> sigpage mechanism which is very similar to a VDSO.
>
> The very simple function, __kernel_vdso_doubler, resolved in a test
> program automatically on my Arndale board (running Fedora 20) without
> any additional prodding.
>
> IPC stress tests from LTP were executed to test the signal trampoline.
>
> I would appreciate any comments on this approach of converting the
> sigpage to a VDSO. If this looks sane to people, I will work on the
> gettimeofday logic in a later patch.
I'm not happy with this removing much of the work I pushed into the
kernel to work around the security issues which were identified with
the fixed-address placement of stuff in the vectors page. Particularly
the random placement of the signal return stubs within the new signal
page is gone with the VDSO approach, which means if someone can discover
the VDSO page, they can issue any system call they please by knowing
the appropriate offset into the page to call.
While the VDSO page will be placed randomly, I'd also like to have the
signal handlers placed randomly within that page as well - there's no
need for them to be at a fixed offset. The only thing which needs to
know where they are after all is the kernel.
I'm not sure about putting gettimeofday() into this - gettimeofday()
would need to have various kernel variables exported into userspace
for the VDSO page to then compute the current time of day from the
timer value(s), and that's certainly not going to be at a fixed
address.
I believe x86 eventually ended up going down the path of trapping and
emulating calls to the VDSO page because VDSO became too much of a
problem (though I think it does provide the option for having it back
but not by default.)
--
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up. Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".
^ permalink raw reply [flat|nested] 9+ messages in thread
* [RFC] arm: vdso: Convert sigpage to vdso implementation
2014-01-28 16:25 [RFC] arm: vdso: Convert sigpage to vdso implementation Steve Capper
2014-01-28 17:10 ` Russell King - ARM Linux
@ 2014-01-28 21:05 ` Nathan Lynch
2014-01-29 14:39 ` Steve Capper
2014-01-28 21:06 ` [RFC/PATCH] ARM: vDSO gettimeofday using generic timer architecture Nathan Lynch
2 siblings, 1 reply; 9+ messages in thread
From: Nathan Lynch @ 2014-01-28 21:05 UTC (permalink / raw)
To: linux-arm-kernel
Hi Steve,
On 01/28/2014 10:25 AM, Steve Capper wrote:
> ARM has a special sigpage that is used for signal return trampolines.
> Its implementation is very similar to a VDSO conceptually in that it
> occupies a special mapping in user address space.
>
> One could actually host the trampoline code in a VDSO instead with the
> added advantage that one could also host specialised routines there.
> One such routine could be gettimeofday where on ARM we have architected
> (and some vendor supplied) timers that can be queried entirely in
> userspace, obviating the need for an expensive syscall.
>
> This patch converts the sigpage implementation to a VDSO. It is mostly
> a direct port from Will Deacon's arm64 implementation with the ARM
> signal trampoline plumbed in.
>
> Signed-off-by: Steve Capper <steve.capper@linaro.org>
> ---
> As can be inferred from this RFC, I am interested ultimately in
> implementing a syscall-less gettimeofday for ARM. Whilst researching
> possible vectors page or VDSO implementations, I came across the
> sigpage mechanism which is very similar to a VDSO.
>
> The very simple function, __kernel_vdso_doubler, resolved in a test
> program automatically on my Arndale board (running Fedora 20) without
> any additional prodding.
>
> IPC stress tests from LTP were executed to test the signal trampoline.
>
> I would appreciate any comments on this approach of converting the
> sigpage to a VDSO. If this looks sane to people, I will work on the
> gettimeofday logic in a later patch.
As it happens, I've been working on a vDSO implementation of
gettimeofday/clock_gettime which does not mess with the signal page.
I'll reply with the patch separately in a moment.
^ permalink raw reply [flat|nested] 9+ messages in thread
* [RFC/PATCH] ARM: vDSO gettimeofday using generic timer architecture
2014-01-28 16:25 [RFC] arm: vdso: Convert sigpage to vdso implementation Steve Capper
2014-01-28 17:10 ` Russell King - ARM Linux
2014-01-28 21:05 ` Nathan Lynch
@ 2014-01-28 21:06 ` Nathan Lynch
2014-01-28 21:22 ` Russell King - ARM Linux
2 siblings, 1 reply; 9+ messages in thread
From: Nathan Lynch @ 2014-01-28 21:06 UTC (permalink / raw)
To: linux-arm-kernel
Provide fast userspace implementations of gettimeofday and
clock_gettime on systems that implement the generic timers extension
defined in ARMv7. This follows the example of arm64 in conception but
significantly differs in some aspects of the implementation (C vs
assembly, mainly).
Clocks supported:
- CLOCK_REALTIME
- CLOCK_MONOTONIC
- CLOCK_REALTIME_COARSE
- CLOCK_MONOTONIC_COARSE
This also provides clock_getres (as arm64 does).
Tested on OMAP5 UEVM (Cortex A15) using a LD_PRELOAD shim to redirect
system calls to the vDSO. I plan to undertake adding proper support
to glibc if the overall approach is acceptable.
Note that while the high-precision realtime and monotonic clock
support depends on the generic timers extension, support for
clock_getres and (I think) the coarse clocks is pretty much
independent of the timer implementation in use and could be provided
unconditionally.
I also hope to add getcpu to the vDSO, using something like
TPIDRURO/TPIDRURW (although I believe these registers are claimed for
other uses already -- suggestions welcome).
This is RFC-quality code at the moment -- I haven't tested this on a
system lacking generic timers, nor have I done much build testing.
I'm sure there is plenty of room for improvement.
Based on linux-next 20140124.
---
arch/arm/Kconfig | 1 +
arch/arm/include/asm/arch_timer.h | 7 +-
arch/arm/include/asm/auxvec.h | 7 +
arch/arm/include/asm/elf.h | 6 +
arch/arm/include/asm/mmu.h | 1 +
arch/arm/include/asm/vdso.h | 26 +++
arch/arm/include/asm/vdso_datapage.h | 45 ++++++
arch/arm/kernel/Makefile | 3 +-
arch/arm/kernel/process.c | 16 +-
arch/arm/kernel/vdso.c | 157 ++++++++++++++++++
arch/arm/kernel/vdso/.gitignore | 2 +
arch/arm/kernel/vdso/Makefile | 46 ++++++
arch/arm/kernel/vdso/vdso.S | 35 ++++
arch/arm/kernel/vdso/vdso.lds.S | 93 +++++++++++
arch/arm/kernel/vdso/vgettimeofday.c | 303 +++++++++++++++++++++++++++++++++++
15 files changed, 742 insertions(+), 6 deletions(-)
create mode 100644 arch/arm/include/asm/auxvec.h
create mode 100644 arch/arm/include/asm/vdso.h
create mode 100644 arch/arm/include/asm/vdso_datapage.h
create mode 100644 arch/arm/kernel/vdso.c
create mode 100644 arch/arm/kernel/vdso/.gitignore
create mode 100644 arch/arm/kernel/vdso/Makefile
create mode 100644 arch/arm/kernel/vdso/vdso.S
create mode 100644 arch/arm/kernel/vdso/vdso.lds.S
create mode 100644 arch/arm/kernel/vdso/vgettimeofday.c
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index dc6ef9a2c649..c9f69d059c76 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -23,6 +23,7 @@ config ARM
select GENERIC_SMP_IDLE_THREAD
select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER
+ select GENERIC_TIME_VSYSCALL
select HARDIRQS_SW_RESEND
select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL
select HAVE_ARCH_KGDB
diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h
index 30cc2fb09416..80f24827af94 100644
--- a/arch/arm/include/asm/arch_timer.h
+++ b/arch/arm/include/asm/arch_timer.h
@@ -102,13 +102,16 @@ static inline void arch_counter_set_user_access(void)
{
u32 cntkctl = arch_timer_get_cntkctl();
- /* Disable user access to both physical/virtual counters/timers */
+ /* Disable user access to the timers and the physical counter */
/* Also disable virtual event stream */
cntkctl &= ~(ARCH_TIMER_USR_PT_ACCESS_EN
| ARCH_TIMER_USR_VT_ACCESS_EN
| ARCH_TIMER_VIRT_EVT_EN
- | ARCH_TIMER_USR_VCT_ACCESS_EN
| ARCH_TIMER_USR_PCT_ACCESS_EN);
+
+ /* Enable user access to the virtual counter */
+ cntkctl |= ARCH_TIMER_USR_VCT_ACCESS_EN;
+
arch_timer_set_cntkctl(cntkctl);
}
diff --git a/arch/arm/include/asm/auxvec.h b/arch/arm/include/asm/auxvec.h
new file mode 100644
index 000000000000..f56936b97ec2
--- /dev/null
+++ b/arch/arm/include/asm/auxvec.h
@@ -0,0 +1,7 @@
+#ifndef __ASM_AUXVEC_H
+#define __ASM_AUXVEC_H
+
+/* vDSO location */
+#define AT_SYSINFO_EHDR 33
+
+#endif
diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h
index f4b46d39b9cf..b8d099264000 100644
--- a/arch/arm/include/asm/elf.h
+++ b/arch/arm/include/asm/elf.h
@@ -1,6 +1,7 @@
#ifndef __ASMARM_ELF_H
#define __ASMARM_ELF_H
+#include <asm/auxvec.h>
#include <asm/hwcap.h>
/*
@@ -129,6 +130,11 @@ extern unsigned long arch_randomize_brk(struct mm_struct *mm);
#define arch_randomize_brk arch_randomize_brk
#ifdef CONFIG_MMU
+#define ARCH_DLINFO \
+do { \
+ NEW_AUX_ENT(AT_SYSINFO_EHDR, \
+ (elf_addr_t)current->mm->context.vdso); \
+} while (0)
#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
struct linux_binprm;
int arch_setup_additional_pages(struct linux_binprm *, int);
diff --git a/arch/arm/include/asm/mmu.h b/arch/arm/include/asm/mmu.h
index 64fd15159b7d..1ee0f42a3b26 100644
--- a/arch/arm/include/asm/mmu.h
+++ b/arch/arm/include/asm/mmu.h
@@ -11,6 +11,7 @@ typedef struct {
#endif
unsigned int vmalloc_seq;
unsigned long sigpage;
+ unsigned long vdso;
} mm_context_t;
#ifdef CONFIG_CPU_HAS_ASID
diff --git a/arch/arm/include/asm/vdso.h b/arch/arm/include/asm/vdso.h
new file mode 100644
index 000000000000..ab080bbc4acf
--- /dev/null
+++ b/arch/arm/include/asm/vdso.h
@@ -0,0 +1,26 @@
+#ifndef __ASM_VDSO_H
+#define __ASM_VDSO_H
+
+#ifdef __KERNEL__
+
+#ifndef __ASSEMBLY__
+
+#include <linux/mm_types.h>
+#include <asm/mmu.h>
+
+static inline bool vma_is_vdso(struct vm_area_struct *vma)
+{
+ if (vma->vm_mm && vma->vm_start == vma->vm_mm->context.vdso)
+ return true;
+ return false;
+}
+
+void arm_install_vdso(void);
+
+#endif /* __ASSEMBLY__ */
+
+#define VDSO_LBASE 0x0
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_VDSO_H */
diff --git a/arch/arm/include/asm/vdso_datapage.h b/arch/arm/include/asm/vdso_datapage.h
new file mode 100644
index 000000000000..e55358c1d565
--- /dev/null
+++ b/arch/arm/include/asm/vdso_datapage.h
@@ -0,0 +1,45 @@
+/*
+ * Adapted from arm64 version.
+ *
+ * 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/>.
+ */
+#ifndef __ASM_VDSO_DATAPAGE_H
+#define __ASM_VDSO_DATAPAGE_H
+
+#ifdef __KERNEL__
+
+#ifndef __ASSEMBLY__
+
+struct vdso_data {
+ __u64 cs_cycle_last; /* Timebase at clocksource init */
+ __u32 xtime_clock_sec; /* Kernel time */
+ __u32 xtime_clock_nsec;
+ __u32 xtime_coarse_sec; /* Coarse time */
+ __u32 xtime_coarse_nsec;
+ __u32 wtm_clock_sec; /* Wall to monotonic time */
+ __u32 wtm_clock_nsec;
+ __u32 tb_seq_count; /* Timebase sequence counter */
+ __u32 cs_mult; /* Clocksource multiplier */
+ __u32 cs_shift; /* Clocksource shift */
+ __u32 tz_minuteswest; /* Whacky timezone stuff */
+ __u32 tz_dsttime;
+ __u32 use_syscall;
+};
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_VDSO_DATAPAGE_H */
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index a30fc9be9e9e..9e785550b307 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -18,7 +18,8 @@ CFLAGS_REMOVE_return_address.o = -pg
obj-y := elf.o entry-common.o irq.o opcodes.o \
process.o ptrace.o return_address.o \
setup.o signal.o sigreturn_codes.o \
- stacktrace.o sys_arm.o time.o traps.o
+ stacktrace.o sys_arm.o time.o traps.o \
+ vdso.o vdso/
obj-$(CONFIG_ATAGS) += atags_parse.o
obj-$(CONFIG_ATAGS_PROC) += atags_proc.o
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 92f7b15dd221..9907227adf92 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -41,6 +41,7 @@
#include <asm/stacktrace.h>
#include <asm/mach/time.h>
#include <asm/tls.h>
+#include <asm/vdso.h>
#ifdef CONFIG_CC_STACKPROTECTOR
#include <linux/stackprotector.h>
@@ -472,9 +473,16 @@ int in_gate_area_no_mm(unsigned long addr)
const char *arch_vma_name(struct vm_area_struct *vma)
{
- return is_gate_vma(vma) ? "[vectors]" :
- (vma->vm_mm && vma->vm_start == vma->vm_mm->context.sigpage) ?
- "[sigpage]" : NULL;
+ if (is_gate_vma(vma))
+ return "[vectors]";
+
+ if (vma->vm_mm && vma->vm_start == vma->vm_mm->context.sigpage)
+ return "[sigpage]";
+
+ if (vma_is_vdso(vma))
+ return "[vdso]";
+
+ return NULL;
}
static struct page *signal_page;
@@ -505,6 +513,8 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
if (ret == 0)
mm->context.sigpage = addr;
+ arm_install_vdso();
+
up_fail:
up_write(&mm->mmap_sem);
return ret;
diff --git a/arch/arm/kernel/vdso.c b/arch/arm/kernel/vdso.c
new file mode 100644
index 000000000000..82ffb77df861
--- /dev/null
+++ b/arch/arm/kernel/vdso.c
@@ -0,0 +1,157 @@
+/*
+ * Adapted from arm64 version.
+ *
+ * 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/>.
+ */
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/timekeeper_internal.h>
+#include <linux/vmalloc.h>
+
+#include <asm/page.h>
+#include <asm/vdso.h>
+#include <asm/vdso_datapage.h>
+
+extern char vdso_start, vdso_end;
+
+static unsigned long vdso_pages;
+static struct page **vdso_pagelist;
+
+static union {
+ struct vdso_data data;
+ u8 page[PAGE_SIZE];
+} vdso_data_store __page_aligned_data;
+struct vdso_data *vdso_data = &vdso_data_store.data;
+
+/*
+ * The vDSO data page.
+ */
+
+static int __init vdso_init(void)
+{
+ struct page *pg;
+ char *vbase;
+ int i, ret = 0;
+
+ vdso_pages = (&vdso_end - &vdso_start) >> PAGE_SHIFT;
+ pr_info("vdso: %ld pages (%ld code, %ld data) at base %p\n",
+ vdso_pages + 1, vdso_pages, 1L, &vdso_start);
+
+ /* Allocate the vDSO pagelist, plus a page for the data. */
+ vdso_pagelist = kzalloc(sizeof(struct page *) * (vdso_pages + 1),
+ GFP_KERNEL);
+ if (vdso_pagelist == NULL) {
+ pr_err("Failed to allocate vDSO pagelist!\n");
+ return -ENOMEM;
+ }
+
+ /* Grab the vDSO code pages. */
+ for (i = 0; i < vdso_pages; i++) {
+ pg = virt_to_page(&vdso_start + i*PAGE_SIZE);
+ ClearPageReserved(pg);
+ get_page(pg);
+ vdso_pagelist[i] = pg;
+ }
+
+ /* Sanity check the shared object header. */
+ vbase = vmap(vdso_pagelist, 1, 0, PAGE_KERNEL);
+ if (vbase == NULL) {
+ pr_err("Failed to map vDSO pagelist!\n");
+ return -ENOMEM;
+ } else if (memcmp(vbase, "\177ELF", 4)) {
+ pr_err("vDSO is not a valid ELF object!\n");
+ ret = -EINVAL;
+ goto unmap;
+ }
+
+ /* Grab the vDSO data page. */
+ pg = virt_to_page(vdso_data);
+ get_page(pg);
+ vdso_pagelist[i] = pg;
+
+unmap:
+ vunmap(vbase);
+ return ret;
+}
+arch_initcall(vdso_init);
+
+/* assumes mmap_sem is write-locked */
+void arm_install_vdso(void)
+{
+ struct mm_struct *mm = current->mm;
+ unsigned long vdso_base, vdso_mapping_len;
+ int ret;
+
+ /* Be sure to map the data page */
+ vdso_mapping_len = (vdso_pages + 1) << PAGE_SHIFT;
+
+ vdso_base = get_unmapped_area(NULL, 0, vdso_mapping_len, 0, 0);
+ if (IS_ERR_VALUE(vdso_base)) {
+ pr_notice_once("%s: get_unapped_area failed (%ld)\n",
+ __func__, (long)vdso_base);
+ ret = vdso_base;
+ return;
+ }
+ mm->context.vdso = vdso_base;
+
+ ret = install_special_mapping(mm, vdso_base, vdso_mapping_len,
+ VM_READ|VM_EXEC|
+ VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
+ vdso_pagelist);
+ if (ret) {
+ pr_notice_once("%s: install_special_mapping failed (%d)\n",
+ __func__, ret);
+ mm->context.vdso = 0;
+ return;
+ }
+}
+
+void update_vsyscall(struct timekeeper *tk)
+{
+ struct timespec xtime_coarse;
+ struct timespec wall_time = tk_xtime(tk);
+ struct timespec *wtm = &tk->wall_to_monotonic;
+ u32 use_syscall = strcmp(tk->clock->name, "arch_sys_counter");
+
+ ++vdso_data->tb_seq_count;
+ smp_wmb();
+
+ xtime_coarse = __current_kernel_time();
+ vdso_data->use_syscall = use_syscall;
+ vdso_data->xtime_coarse_sec = xtime_coarse.tv_sec;
+ vdso_data->xtime_coarse_nsec = xtime_coarse.tv_nsec;
+
+ if (!use_syscall) {
+ vdso_data->cs_cycle_last = tk->clock->cycle_last;
+ vdso_data->xtime_clock_sec = wall_time.tv_sec;
+ vdso_data->xtime_clock_nsec = wall_time.tv_nsec;
+ vdso_data->cs_mult = tk->mult;
+ vdso_data->cs_shift = tk->shift;
+ vdso_data->wtm_clock_sec = wtm->tv_sec;
+ vdso_data->wtm_clock_nsec = wtm->tv_nsec;
+ }
+
+ smp_wmb();
+ ++vdso_data->tb_seq_count;
+}
+
+void update_vsyscall_tz(void)
+{
+ vdso_data->tz_minuteswest = sys_tz.tz_minuteswest;
+ vdso_data->tz_dsttime = sys_tz.tz_dsttime;
+}
diff --git a/arch/arm/kernel/vdso/.gitignore b/arch/arm/kernel/vdso/.gitignore
new file mode 100644
index 000000000000..a4093e0671be
--- /dev/null
+++ b/arch/arm/kernel/vdso/.gitignore
@@ -0,0 +1,2 @@
+vdso.lds
+
diff --git a/arch/arm/kernel/vdso/Makefile b/arch/arm/kernel/vdso/Makefile
new file mode 100644
index 000000000000..cc2b42db840e
--- /dev/null
+++ b/arch/arm/kernel/vdso/Makefile
@@ -0,0 +1,46 @@
+obj-vdso := vgettimeofday.o
+
+# Build rules
+targets := $(obj-vdso) vdso.so vdso.so.dbg vdso.lds
+obj-vdso := $(addprefix $(obj)/, $(obj-vdso))
+
+ccflags-y := -shared -fPIC -fno-common -fno-builtin
+ccflags-y += -nostdlib -Wl,-soname=linux-vdso.so.1 \
+ $(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
+
+obj-y += vdso.o
+extra-y += vdso.lds
+CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
+
+CFLAGS_REMOVE_vdso.o = -pg
+CFLAGS_REMOVE_vgettimeofday.o = -pg
+
+# Disable gcov profiling for VDSO code
+GCOV_PROFILE := n
+
+# Force dependency
+$(obj)/vdso.o : $(obj)/vdso.so
+
+# Link rule for the .so file, .lds has to be first
+SYSCFLAGS_vdso.so.dbg = $(c_flags)
+$(obj)/vdso.so.dbg: $(src)/vdso.lds $(obj-vdso)
+ $(call if_changed,vdsold)
+
+# Strip rule for the .so file
+$(obj)/%.so: OBJCOPYFLAGS := -S
+$(obj)/%.so: $(obj)/%.so.dbg FORCE
+ $(call if_changed,objcopy)
+
+# Actual build commands
+quiet_cmd_vdsold = VDSOL $@
+ cmd_vdsold = $(CC) $(c_flags) -Wl,-T $^ -o $@
+
+# Install commands for the unstripped file
+quiet_cmd_vdso_install = INSTALL $@
+ cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@
+
+vdso.so: $(obj)/vdso.so.dbg
+ @mkdir -p $(MODLIB)/vdso
+ $(call cmd,vdso_install)
+
+vdso_install: vdso.so
diff --git a/arch/arm/kernel/vdso/vdso.S b/arch/arm/kernel/vdso/vdso.S
new file mode 100644
index 000000000000..aed16ff84c5f
--- /dev/null
+++ b/arch/arm/kernel/vdso/vdso.S
@@ -0,0 +1,35 @@
+/*
+ * Adapted from arm64 version.
+ *
+ * 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 <will.deacon@arm.com>
+ */
+
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <linux/const.h>
+#include <asm/page.h>
+
+ __PAGE_ALIGNED_DATA
+
+ .globl vdso_start, vdso_end
+ .balign PAGE_SIZE
+vdso_start:
+ .incbin "arch/arm/kernel/vdso/vdso.so"
+ .balign PAGE_SIZE
+vdso_end:
+
+ .previous
diff --git a/arch/arm/kernel/vdso/vdso.lds.S b/arch/arm/kernel/vdso/vdso.lds.S
new file mode 100644
index 000000000000..e16f8f6f08e1
--- /dev/null
+++ b/arch/arm/kernel/vdso/vdso.lds.S
@@ -0,0 +1,93 @@
+/*
+ * Adapted from arm64 version.
+ *
+ * GNU linker script for the VDSO library.
+ *
+ * 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 <will.deacon@arm.com>
+ * Heavily based on the vDSO linker scripts for other archs.
+ */
+
+#include <linux/const.h>
+#include <asm/page.h>
+#include <asm/vdso.h>
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+
+SECTIONS
+{
+ . = VDSO_LBASE + SIZEOF_HEADERS;
+
+ .hash : { *(.hash) } :text
+ .gnu.hash : { *(.gnu.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+
+ .note : { *(.note.*) } :text :note
+
+ . = ALIGN(16);
+
+ .text : { *(.text*) } :text =0xd503201f
+ PROVIDE (__etext = .);
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+
+ .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
+ .eh_frame : { KEEP (*(.eh_frame)) } :text
+
+ .dynamic : { *(.dynamic) } :text :dynamic
+
+ .rodata : { *(.rodata*) } :text
+
+ _end = .;
+ PROVIDE(end = .);
+
+ . = ALIGN(PAGE_SIZE);
+ PROVIDE(_vdso_data = .);
+
+ /DISCARD/ : {
+ *(.note.GNU-stack)
+ *(.data .data.* .gnu.linkonce.d.* .sdata*)
+ *(.bss .sbss .dynbss .dynsbss)
+ }
+}
+
+/*
+ * We must supply the ELF program headers explicitly to get just one
+ * PT_LOAD segment, and set the flags explicitly to make segments read-only.
+ */
+PHDRS
+{
+ text PT_LOAD FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */
+ dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
+ note PT_NOTE FLAGS(4); /* PF_R */
+ eh_frame_hdr PT_GNU_EH_FRAME;
+}
+
+VERSION
+{
+ LINUX_3.15 {
+ global:
+ __kernel_clock_getres;
+ __kernel_clock_gettime;
+ __kernel_gettimeofday;
+ local: *;
+ };
+}
diff --git a/arch/arm/kernel/vdso/vgettimeofday.c b/arch/arm/kernel/vdso/vgettimeofday.c
new file mode 100644
index 000000000000..1519283dc2e5
--- /dev/null
+++ b/arch/arm/kernel/vdso/vgettimeofday.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2014 Mentor Graphics Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ */
+
+#include <linux/compiler.h>
+#include <linux/hrtimer.h>
+#include <linux/time.h>
+#include <asm/arch_timer.h>
+#include <asm/barrier.h>
+#include <asm/unistd.h>
+#include <asm/vdso_datapage.h>
+
+extern struct vdso_data _vdso_data;
+
+static struct vdso_data *get_datapage(void)
+{
+ struct vdso_data *ret;
+
+ /* Hack to perform pc-relative load of data page */
+ asm("b 1f\n"
+ ".align 2\n"
+ "2:\n"
+ ".long _vdso_data - .\n"
+ "1:\n"
+ "adr r2, 2b\n"
+ "ldr r3, [r2]\n"
+ "add %0, r2, r3\n" :
+ "=r" (ret) : : "r2", "r3");
+
+ return ret;
+}
+
+static u32 seqcnt_acquire(struct vdso_data *vdata)
+{
+ u32 seq;
+
+ do {
+ seq = ACCESS_ONCE(vdata->tb_seq_count);
+ } while (seq & 1);
+
+ dmb(ish);
+
+ return seq;
+}
+
+static u32 seqcnt_read(struct vdso_data *vdata)
+{
+ dmb(ish);
+
+ return ACCESS_ONCE(vdata->tb_seq_count);
+}
+
+static long clock_gettime_fallback(clockid_t _clkid, struct timespec *_ts)
+{
+ register struct timespec *ts asm("r1") = _ts;
+ register clockid_t clkid asm("r0") = _clkid;
+ register long ret asm ("r0");
+ register long nr asm("r7") = __NR_clock_gettime;
+
+ asm("swi #0" : "=r" (ret) : "r" (clkid), "r" (ts), "r" (nr) : "memory");
+
+ return ret;
+}
+
+static int do_realtime_coarse(struct timespec *ts, struct vdso_data *vdata)
+{
+ struct timespec copy;
+ u32 seq;
+
+ do {
+ seq = seqcnt_acquire(vdata);
+
+ if (vdata->use_syscall)
+ return -1;
+
+ copy.tv_sec = vdata->xtime_coarse_sec;
+ copy.tv_nsec = vdata->xtime_coarse_nsec;
+ } while (seq != seqcnt_read(vdata));
+
+ *ts = copy;
+
+ return 0;
+}
+
+static int do_monotonic_coarse(struct timespec *ts, struct vdso_data *vdata)
+{
+ struct timespec copy;
+ struct timespec wtm;
+ u32 seq;
+
+ do {
+ seq = seqcnt_acquire(vdata);
+
+ if (vdata->use_syscall)
+ return -1;
+
+ copy.tv_sec = vdata->xtime_coarse_sec;
+ copy.tv_nsec = vdata->xtime_coarse_nsec;
+ wtm.tv_sec = vdata->wtm_clock_sec;
+ wtm.tv_nsec = vdata->wtm_clock_nsec;
+ } while (seq != seqcnt_read(vdata));
+
+ copy.tv_sec += wtm.tv_sec;
+ copy.tv_nsec += wtm.tv_nsec;
+ if (copy.tv_nsec >= NSEC_PER_SEC) {
+ copy.tv_nsec -= NSEC_PER_SEC;
+ copy.tv_sec += 1;
+ }
+
+ *ts = copy;
+
+ return 0;
+}
+
+static int do_realtime(struct timespec *ts, struct vdso_data *vdata)
+{
+ unsigned long sec;
+ u32 seq;
+ u64 ns;
+
+ do {
+ u64 cycles;
+
+ seq = seqcnt_acquire(vdata);
+
+ if (vdata->use_syscall)
+ return -1;
+
+ cycles = arch_counter_get_cntvct() - vdata->cs_cycle_last;
+
+ /* The generic timer architecture guarantees only 56 bits */
+ cycles &= ~(0xff00ULL << 48);
+ ns = (cycles * vdata->cs_mult) >> vdata->cs_shift;
+
+ sec = vdata->xtime_clock_sec;
+ ns += vdata->xtime_clock_nsec;
+
+ while (ns >= NSEC_PER_SEC) {
+ ns -= NSEC_PER_SEC;
+ sec += 1;
+ }
+ } while (seq != seqcnt_read(vdata));
+
+ ts->tv_sec = sec;
+ ts->tv_nsec = ns;
+
+ return 0;
+}
+
+static int do_monotonic(struct timespec *ts, struct vdso_data *vdata)
+{
+ unsigned long sec;
+ u32 seq;
+ u64 ns;
+
+ do {
+ u64 cycles;
+
+ seq = seqcnt_acquire(vdata);
+
+ if (vdata->use_syscall)
+ return -1;
+
+ cycles = arch_counter_get_cntvct() - vdata->cs_cycle_last;
+
+ /* The generic timer architecture guarantees only 56 bits */
+ cycles &= ~(0xff00ULL << 48);
+ ns = (cycles * vdata->cs_mult) >> vdata->cs_shift;
+
+ sec = vdata->xtime_clock_sec;
+ ns += vdata->xtime_clock_nsec;
+
+ sec += vdata->wtm_clock_sec;
+ ns += vdata->wtm_clock_nsec;
+
+ while (ns >= NSEC_PER_SEC) {
+ ns -= NSEC_PER_SEC;
+ sec += 1;
+ }
+ } while (seq != seqcnt_read(vdata));
+
+ ts->tv_sec = sec;
+ ts->tv_nsec = ns;
+
+ return 0;
+}
+
+int __kernel_clock_gettime(clockid_t clkid, struct timespec *ts)
+{
+ struct vdso_data *vdata;
+ int ret = -1;
+
+ vdata = get_datapage();
+
+ switch (clkid) {
+ case CLOCK_REALTIME_COARSE:
+ ret = do_realtime_coarse(ts, vdata);
+ break;
+ case CLOCK_MONOTONIC_COARSE:
+ ret = do_monotonic_coarse(ts, vdata);
+ break;
+ case CLOCK_REALTIME:
+ ret = do_realtime(ts, vdata);
+ break;
+ case CLOCK_MONOTONIC:
+ ret = do_monotonic(ts, vdata);
+ break;
+ default:
+ break;
+ }
+
+ if (ret)
+ ret = clock_gettime_fallback(clkid, ts);
+
+ return ret;
+}
+
+static long clock_getres_fallback(clockid_t _clkid, struct timespec *_ts)
+{
+ register struct timespec *ts asm("r1") = _ts;
+ register clockid_t clkid asm("r0") = _clkid;
+ register long ret asm ("r0");
+ register long nr asm("r7") = __NR_clock_getres;
+
+ asm volatile(
+ "swi #0" :
+ "=r" (ret) :
+ "r" (clkid), "r" (ts), "r" (nr) :
+ "memory");
+
+ return ret;
+}
+
+int __kernel_clock_getres(clockid_t clkid, struct timespec *ts)
+{
+ int ret;
+
+ switch (clkid) {
+ case CLOCK_REALTIME:
+ case CLOCK_MONOTONIC:
+ if (ts) {
+ ts->tv_sec = 0;
+ ts->tv_nsec = MONOTONIC_RES_NSEC;
+ }
+ ret = 0;
+ break;
+ case CLOCK_REALTIME_COARSE:
+ case CLOCK_MONOTONIC_COARSE:
+ if (ts) {
+ ts->tv_sec = 0;
+ ts->tv_nsec = LOW_RES_NSEC;
+ }
+ ret = 0;
+ break;
+ default:
+ ret = clock_getres_fallback(clkid, ts);
+ break;
+ }
+
+ return ret;
+}
+
+static long gettimeofday_fallback(struct timeval *_tv, struct timezone *_tz)
+{
+ register struct timezone *tz asm("r1") = _tz;
+ register struct timeval *tv asm("r0") = _tv;
+ register long ret asm ("r0");
+ register long nr asm("r7") = __NR_gettimeofday;
+
+ asm("swi #0" : "=r" (ret) : "r" (tv), "r" (tz), "r" (nr) : "memory");
+
+ return ret;
+}
+
+int __kernel_gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+ struct timespec ts;
+ struct vdso_data *vdata;
+ int ret;
+
+ vdata = get_datapage();
+
+ ret = do_realtime(&ts, vdata);
+ if (ret)
+ return gettimeofday_fallback(tv, tz);
+
+ if (tv) {
+ tv->tv_sec = ts.tv_sec;
+ tv->tv_usec = ts.tv_nsec / 1000;
+ }
+ if (tz) {
+ tz->tz_minuteswest = vdata->tz_minuteswest;
+ tz->tz_dsttime = vdata->tz_dsttime;
+ }
+
+ return ret;
+}
--
1.8.3.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [RFC/PATCH] ARM: vDSO gettimeofday using generic timer architecture
2014-01-28 21:06 ` [RFC/PATCH] ARM: vDSO gettimeofday using generic timer architecture Nathan Lynch
@ 2014-01-28 21:22 ` Russell King - ARM Linux
2014-01-28 21:48 ` Nathan Lynch
0 siblings, 1 reply; 9+ messages in thread
From: Russell King - ARM Linux @ 2014-01-28 21:22 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Jan 28, 2014 at 03:06:53PM -0600, Nathan Lynch wrote:
> +static union {
> + struct vdso_data data;
> + u8 page[PAGE_SIZE];
> +} vdso_data_store __page_aligned_data;
> +struct vdso_data *vdso_data = &vdso_data_store.data;
So this is in the kernel data segment.
> +void update_vsyscall(struct timekeeper *tk)
> +{
> + struct timespec xtime_coarse;
> + struct timespec wall_time = tk_xtime(tk);
> + struct timespec *wtm = &tk->wall_to_monotonic;
> + u32 use_syscall = strcmp(tk->clock->name, "arch_sys_counter");
> +
> + ++vdso_data->tb_seq_count;
> + smp_wmb();
> +
> + xtime_coarse = __current_kernel_time();
> + vdso_data->use_syscall = use_syscall;
> + vdso_data->xtime_coarse_sec = xtime_coarse.tv_sec;
> + vdso_data->xtime_coarse_nsec = xtime_coarse.tv_nsec;
> +
> + if (!use_syscall) {
> + vdso_data->cs_cycle_last = tk->clock->cycle_last;
> + vdso_data->xtime_clock_sec = wall_time.tv_sec;
> + vdso_data->xtime_clock_nsec = wall_time.tv_nsec;
> + vdso_data->cs_mult = tk->mult;
> + vdso_data->cs_shift = tk->shift;
> + vdso_data->wtm_clock_sec = wtm->tv_sec;
> + vdso_data->wtm_clock_nsec = wtm->tv_nsec;
> + }
> +
> + smp_wmb();
> + ++vdso_data->tb_seq_count;
> +}
> +
> +void update_vsyscall_tz(void)
> +{
> + vdso_data->tz_minuteswest = sys_tz.tz_minuteswest;
> + vdso_data->tz_dsttime = sys_tz.tz_dsttime;
> +}
which gets written to directly, and read from userspace. This won't work
with aliasing caches, of which we have VIVT caches on all ARMv4 and ARMv5
CPUs, and VIPT caches on some ARMv6.
Either this needs to be limited to just VIPT nonaliasing caches, or it
needs cache handling.
The above also looks rather unsafe from the SMP perspective - how does
vdso_data->tb_seq_count protect this data between CPUs?
--
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up. Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".
^ permalink raw reply [flat|nested] 9+ messages in thread
* [RFC/PATCH] ARM: vDSO gettimeofday using generic timer architecture
2014-01-28 21:22 ` Russell King - ARM Linux
@ 2014-01-28 21:48 ` Nathan Lynch
0 siblings, 0 replies; 9+ messages in thread
From: Nathan Lynch @ 2014-01-28 21:48 UTC (permalink / raw)
To: linux-arm-kernel
On 01/28/2014 03:22 PM, Russell King - ARM Linux wrote:
> On Tue, Jan 28, 2014 at 03:06:53PM -0600, Nathan Lynch wrote:
>> +static union {
>> + struct vdso_data data;
>> + u8 page[PAGE_SIZE];
>> +} vdso_data_store __page_aligned_data;
>> +struct vdso_data *vdso_data = &vdso_data_store.data;
>
> So this is in the kernel data segment.
>
>> +void update_vsyscall(struct timekeeper *tk)
>> +{
>> + struct timespec xtime_coarse;
>> + struct timespec wall_time = tk_xtime(tk);
>> + struct timespec *wtm = &tk->wall_to_monotonic;
>> + u32 use_syscall = strcmp(tk->clock->name, "arch_sys_counter");
>> +
>> + ++vdso_data->tb_seq_count;
>> + smp_wmb();
>> +
>> + xtime_coarse = __current_kernel_time();
>> + vdso_data->use_syscall = use_syscall;
>> + vdso_data->xtime_coarse_sec = xtime_coarse.tv_sec;
>> + vdso_data->xtime_coarse_nsec = xtime_coarse.tv_nsec;
>> +
>> + if (!use_syscall) {
>> + vdso_data->cs_cycle_last = tk->clock->cycle_last;
>> + vdso_data->xtime_clock_sec = wall_time.tv_sec;
>> + vdso_data->xtime_clock_nsec = wall_time.tv_nsec;
>> + vdso_data->cs_mult = tk->mult;
>> + vdso_data->cs_shift = tk->shift;
>> + vdso_data->wtm_clock_sec = wtm->tv_sec;
>> + vdso_data->wtm_clock_nsec = wtm->tv_nsec;
>> + }
>> +
>> + smp_wmb();
>> + ++vdso_data->tb_seq_count;
>> +}
>> +
>> +void update_vsyscall_tz(void)
>> +{
>> + vdso_data->tz_minuteswest = sys_tz.tz_minuteswest;
>> + vdso_data->tz_dsttime = sys_tz.tz_dsttime;
>> +}
>
> which gets written to directly, and read from userspace. This won't work
> with aliasing caches, of which we have VIVT caches on all ARMv4 and ARMv5
> CPUs, and VIPT caches on some ARMv6.
>
> Either this needs to be limited to just VIPT nonaliasing caches, or it
> needs cache handling.
Thanks, I will address this.
>
> The above also looks rather unsafe from the SMP perspective - how does
> vdso_data->tb_seq_count protect this data between CPUs?
It doesn't -- it merely provides a mechanism for signaling the
consistency of the data userspace reads from the page. It's basically a
seqlock.
Looks like timekeeper_lock in kernel/time/timekeeping.c prevents
concurrent calls to update_vsyscall. I could document that dependency...
^ permalink raw reply [flat|nested] 9+ messages in thread
* [RFC] arm: vdso: Convert sigpage to vdso implementation
2014-01-28 17:10 ` Russell King - ARM Linux
@ 2014-01-29 14:22 ` Steve Capper
2014-01-30 18:51 ` Will Deacon
0 siblings, 1 reply; 9+ messages in thread
From: Steve Capper @ 2014-01-29 14:22 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Jan 26, 2014 at 05:10:15PM +0000, Russell King - ARM Linux wrote:
> On Tue, Jan 28, 2014 at 04:25:08PM +0000, Steve Capper wrote:
> > ARM has a special sigpage that is used for signal return trampolines.
> > Its implementation is very similar to a VDSO conceptually in that it
> > occupies a special mapping in user address space.
> >
> > One could actually host the trampoline code in a VDSO instead with the
> > added advantage that one could also host specialised routines there.
> > One such routine could be gettimeofday where on ARM we have architected
> > (and some vendor supplied) timers that can be queried entirely in
> > userspace, obviating the need for an expensive syscall.
> >
> > This patch converts the sigpage implementation to a VDSO. It is mostly
> > a direct port from Will Deacon's arm64 implementation with the ARM
> > signal trampoline plumbed in.
> >
> > Signed-off-by: Steve Capper <steve.capper@linaro.org>
> > ---
> > As can be inferred from this RFC, I am interested ultimately in
> > implementing a syscall-less gettimeofday for ARM. Whilst researching
> > possible vectors page or VDSO implementations, I came across the
> > sigpage mechanism which is very similar to a VDSO.
> >
> > The very simple function, __kernel_vdso_doubler, resolved in a test
> > program automatically on my Arndale board (running Fedora 20) without
> > any additional prodding.
> >
> > IPC stress tests from LTP were executed to test the signal trampoline.
> >
> > I would appreciate any comments on this approach of converting the
> > sigpage to a VDSO. If this looks sane to people, I will work on the
> > gettimeofday logic in a later patch.
>
> I'm not happy with this removing much of the work I pushed into the
> kernel to work around the security issues which were identified with
> the fixed-address placement of stuff in the vectors page. Particularly
> the random placement of the signal return stubs within the new signal
> page is gone with the VDSO approach, which means if someone can discover
> the VDSO page, they can issue any system call they please by knowing
> the appropriate offset into the page to call.
Hi Russell,
I didn't mean to undo you work.
Essentially I saw the sigpage was so close to being a vdso, it just
needed a little nudge to contain other code too.
>
> While the VDSO page will be placed randomly, I'd also like to have the
> signal handlers placed randomly within that page as well - there's no
> need for them to be at a fixed offset. The only thing which needs to
> know where they are after all is the kernel.
I was considering a larger segment containing the trampoline at random
offset, but came to the conclusion that the VA randomisation of the
vdso page location was in itself sufficient?
>
> I'm not sure about putting gettimeofday() into this - gettimeofday()
> would need to have various kernel variables exported into userspace
> for the VDSO page to then compute the current time of day from the
> timer value(s), and that's certainly not going to be at a fixed
> address.
I believe a vdso data page could house the variables, the offsets
within the page could be fixed at compile time.
>
> I believe x86 eventually ended up going down the path of trapping and
> emulating calls to the VDSO page because VDSO became too much of a
> problem (though I think it does provide the option for having it back
> but not by default.)
Cheers,
--
Steve
^ permalink raw reply [flat|nested] 9+ messages in thread
* [RFC] arm: vdso: Convert sigpage to vdso implementation
2014-01-28 21:05 ` Nathan Lynch
@ 2014-01-29 14:39 ` Steve Capper
0 siblings, 0 replies; 9+ messages in thread
From: Steve Capper @ 2014-01-29 14:39 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Jan 28, 2014 at 03:05:59PM -0600, Nathan Lynch wrote:
> Hi Steve,
>
> On 01/28/2014 10:25 AM, Steve Capper wrote:
> > ARM has a special sigpage that is used for signal return trampolines.
> > Its implementation is very similar to a VDSO conceptually in that it
> > occupies a special mapping in user address space.
> >
> > One could actually host the trampoline code in a VDSO instead with the
> > added advantage that one could also host specialised routines there.
> > One such routine could be gettimeofday where on ARM we have architected
> > (and some vendor supplied) timers that can be queried entirely in
> > userspace, obviating the need for an expensive syscall.
> >
> > This patch converts the sigpage implementation to a VDSO. It is mostly
> > a direct port from Will Deacon's arm64 implementation with the ARM
> > signal trampoline plumbed in.
> >
> > Signed-off-by: Steve Capper <steve.capper@linaro.org>
> > ---
> > As can be inferred from this RFC, I am interested ultimately in
> > implementing a syscall-less gettimeofday for ARM. Whilst researching
> > possible vectors page or VDSO implementations, I came across the
> > sigpage mechanism which is very similar to a VDSO.
> >
> > The very simple function, __kernel_vdso_doubler, resolved in a test
> > program automatically on my Arndale board (running Fedora 20) without
> > any additional prodding.
> >
> > IPC stress tests from LTP were executed to test the signal trampoline.
> >
> > I would appreciate any comments on this approach of converting the
> > sigpage to a VDSO. If this looks sane to people, I will work on the
> > gettimeofday logic in a later patch.
>
> As it happens, I've been working on a vDSO implementation of
> gettimeofday/clock_gettime which does not mess with the signal page.
> I'll reply with the patch separately in a moment.
Cheers Nathan,
--
Steve
>
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* [RFC] arm: vdso: Convert sigpage to vdso implementation
2014-01-29 14:22 ` Steve Capper
@ 2014-01-30 18:51 ` Will Deacon
0 siblings, 0 replies; 9+ messages in thread
From: Will Deacon @ 2014-01-30 18:51 UTC (permalink / raw)
To: linux-arm-kernel
On Wed, Jan 29, 2014 at 02:22:36PM +0000, Steve Capper wrote:
> On Tue, Jan 26, 2014 at 05:10:15PM +0000, Russell King - ARM Linux wrote:
> > I'm not happy with this removing much of the work I pushed into the
> > kernel to work around the security issues which were identified with
> > the fixed-address placement of stuff in the vectors page. Particularly
> > the random placement of the signal return stubs within the new signal
> > page is gone with the VDSO approach, which means if someone can discover
> > the VDSO page, they can issue any system call they please by knowing
> > the appropriate offset into the page to call.
[...]
> > While the VDSO page will be placed randomly, I'd also like to have the
> > signal handlers placed randomly within that page as well - there's no
> > need for them to be at a fixed offset. The only thing which needs to
> > know where they are after all is the kernel.
>
> I was considering a larger segment containing the trampoline at random
> offset, but came to the conclusion that the VA randomisation of the
> vdso page location was in itself sufficient?
Whilst randomising within a page could potentially be beneficial, I question
just how much use it is doing it only for the signal page. For example, for
a system running a given version of libc, if you know where libc is mapped,
then you can easily find syscall sequences in there. Similarly for
gettimeofday() in the vDSO, there is a syscall fallback path too.
Dynamically randomising the layout of shared libraries is likely to confuse
the dynamic linker and completely break debugging with GDB. It's also not
something that I'm aware of being done by any other architectures in the
kernel.
I think there's a trade-off between the measurable performance advantage of
exporting functions such as gtod in the vDSO and the unclear security gains
of randomising the sigreturn code within a page when the page address is
already randomised.
> > I believe x86 eventually ended up going down the path of trapping and
> > emulating calls to the VDSO page because VDSO became too much of a
> > problem (though I think it does provide the option for having it back
> > but not by default.)
Hmm, do you have any pointers to more information about that? I know that
the vsyscall page went the way of the dodo because it was placed at a fixed
address, but I thought that the vDSO was still alive and kicking.
Will
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2014-01-30 18:51 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-01-28 16:25 [RFC] arm: vdso: Convert sigpage to vdso implementation Steve Capper
2014-01-28 17:10 ` Russell King - ARM Linux
2014-01-29 14:22 ` Steve Capper
2014-01-30 18:51 ` Will Deacon
2014-01-28 21:05 ` Nathan Lynch
2014-01-29 14:39 ` Steve Capper
2014-01-28 21:06 ` [RFC/PATCH] ARM: vDSO gettimeofday using generic timer architecture Nathan Lynch
2014-01-28 21:22 ` Russell King - ARM Linux
2014-01-28 21:48 ` Nathan Lynch
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).