All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 0/6] ARM: vdso gettimeofday using generic timer architecture
@ 2014-04-23  0:48 Nathan Lynch
  2014-04-23  0:48 ` [PATCH v6 1/6] ARM: place sigpage at a random offset above stack Nathan Lynch
                   ` (7 more replies)
  0 siblings, 8 replies; 21+ messages in thread
From: Nathan Lynch @ 2014-04-23  0:48 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).

Note that while the high-precision realtime and monotonic clock
support depends on the generic timers extension, support for
clock_getres and coarse clocks is independent of the timer
implementation and is provided unconditionally.

Run-time tested on OMAP5 and i.MX6, verifying that results obtained
with the vdso are consistent with those obtained from the kernel.  On
OMAP5 I observe a 3- to 4-fold speedup for gettimeofday /
CLOCK_REALTIME, with even better (if less interesting) speedups for
the coarse clock ids and clock_getres.

As a preliminary step, the placement of the sigpage is changed to be
at a randomized offset above the stack.  The vdso is placed
immediately above the sigpage.

Changes since v5:
- Update to 3.15-rc1.
- Place vdso at a randomized offset above the stack along with the
  sigpage.
- Properly export asm/auxvec.h.
- Split patch into series for ease of review.

Changes since v4:
- Map data page at the beginning of the VMA to prevent orphan
  sections at the end of output invalidating the calculated offset.
- Move checkundef into cmd_vdsold to avoid spurious rebuilds.
- Change vdso_init message to pr_debug.
- Add -fno-stack-protector to cflags.

Changes since v3:
- Update to 3.14-rc6.
- Record vdso base in mm context before installing mapping (for the
  sake of perf_mmap_event).
- Use a more seqcount-like API for critical sections.  Using seqcount
  API directly, however, would leak kernel pointers to userspace when
  lockdep is enabled.
- Trap instead of looping forever in division-by-zero stubs.

Changes since v2:
- Update to 3.14-rc4.
- Make vDSO configurable, depending on AEABI and MMU.
- Defer shifting of nanosecond component of timespec: fixes observed
  1ns inconsistencies for CLOCK_REALTIME, CLOCK_MONOTONIC (see
  45a7905fc48f for arm64 equivalent).
- Force reload of seq_count when spinning: without a memory clobber
  after the load of vdata->seq_count, GCC can generate code like this:
    2f8:   e59c9020        ldr     r9, [ip, #32]
    2fc:   e3190001        tst     r9, #1
    300:   1a000033        bne     3d4 <do_realtime+0x104>
    304:   f57ff05b        dmb     ish
    308:   e59c3034        ldr     r3, [ip, #52]   ; 0x34
    ...
    3d4:   eafffffe        b       3d4 <do_realtime+0x104>
- Build vdso.so with -lgcc: calls to __lshrdi3, __divsi3 sometimes
  emitted (especially with -Os).  Override certain libgcc functions to
  prevent undefined symbols.
- Do not clear PG_reserved on vdso pages.
- Remove unnecessary get_page calls.
- Simplify ELF signature check during init.
- Use volatile for asm syscall fallbacks.
- Check whether vdso_pagelist is initialized in arm_install_vdso.
- Record clocksource mask in data page.
- Reduce code duplication in do_realtime, do_monotonic.
- Reduce calculations performed in critical sections.
- Simplify coarse clock handling.
- Move datapage load to its own assembly routine.
- Tune vdso_data layout and tweak field names.
- Check vdso shared object for undefined symbols during build.

Changes since v1:
- update to 3.14-rc1
- ensure cache coherency for data page
- Document the kernel-to-userspace protocol for vdso data page updates,
  and note that the timekeeping core prevents concurrent updates.
- update wall-to-monotonic fields unconditionally
- move vdso_start, vdso_end declarations to vdso.h
- correctly build and run when CONFIG_ARM_ARCH_TIMER=n
- rearrange linker script to avoid overlapping sections when CONFIG_DEBUGINFO=n
- remove use_syscall checks from coarse clock paths
- crib BUG_INSTR (0xe7f001f2) from asm/bug.h for text fill


Nathan Lynch (6):
  ARM: place sigpage at a random offset above stack
  ARM: allow user access to arch timer virtual counter
  ARM: miscellaneous vdso infrastructure, preparation
  ARM: add vdso user-space code
  ARM: vdso initialization, mapping, and synchronization
  ARM: add CONFIG_VDSO Kconfig and Makefile bits

 arch/arm/include/asm/Kbuild          |   1 -
 arch/arm/include/asm/arch_timer.h    |   7 +-
 arch/arm/include/asm/elf.h           |  11 ++
 arch/arm/include/asm/mmu.h           |   3 +
 arch/arm/include/asm/vdso.h          |  47 +++++
 arch/arm/include/asm/vdso_datapage.h |  60 +++++++
 arch/arm/include/uapi/asm/Kbuild     |   1 +
 arch/arm/include/uapi/asm/auxvec.h   |   7 +
 arch/arm/kernel/Makefile             |   1 +
 arch/arm/kernel/asm-offsets.c        |   5 +
 arch/arm/kernel/process.c            |  56 +++++-
 arch/arm/kernel/vdso.c               | 168 +++++++++++++++++
 arch/arm/kernel/vdso/.gitignore      |   1 +
 arch/arm/kernel/vdso/Makefile        |  50 ++++++
 arch/arm/kernel/vdso/checkundef.sh   |   9 +
 arch/arm/kernel/vdso/datapage.S      |  15 ++
 arch/arm/kernel/vdso/vdso.S          |  35 ++++
 arch/arm/kernel/vdso/vdso.lds.S      |  88 +++++++++
 arch/arm/kernel/vdso/vgettimeofday.c | 338 +++++++++++++++++++++++++++++++++++
 arch/arm/mm/Kconfig                  |  15 ++
 20 files changed, 911 insertions(+), 7 deletions(-)
 create mode 100644 arch/arm/include/asm/vdso.h
 create mode 100644 arch/arm/include/asm/vdso_datapage.h
 create mode 100644 arch/arm/include/uapi/asm/auxvec.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/checkundef.sh
 create mode 100644 arch/arm/kernel/vdso/datapage.S
 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

-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v6 1/6] ARM: place sigpage at a random offset above stack
  2014-04-23  0:48 [PATCH v6 0/6] ARM: vdso gettimeofday using generic timer architecture Nathan Lynch
@ 2014-04-23  0:48 ` Nathan Lynch
  2014-04-23  0:48 ` [PATCH v6 2/6] ARM: allow user access to arch timer virtual counter Nathan Lynch
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 21+ messages in thread
From: Nathan Lynch @ 2014-04-23  0:48 UTC (permalink / raw)
  To: linux-arm-kernel

The sigpage is currently placed alongside shared libraries etc in the
address space.  Similar to what x86_64 does, place the sigpage at a
randomized offset above the stack so that learning the base address of
the sigpage doesn't help expose where shared libraries are loaded in
the address space (and vice versa).

This code will be used for placing the vdso as well, hence the
vdso_addr function name and npages argument.

Signed-off-by: Nathan Lynch <nathan_lynch@mentor.com>
---
 arch/arm/kernel/process.c | 33 ++++++++++++++++++++++++++++++++-
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 81ef686a91ca..219a0d1d10fc 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -477,6 +477,35 @@ const char *arch_vma_name(struct vm_area_struct *vma)
 		 "[sigpage]" : NULL;
 }
 
+static unsigned long vdso_addr(const struct mm_struct *mm, unsigned int npages)
+{
+	unsigned long offset;
+	unsigned long first;
+	unsigned long last;
+	unsigned long addr;
+	unsigned int slots;
+
+	first = PAGE_ALIGN(mm->start_stack);
+
+	last = TASK_SIZE - (npages << PAGE_SHIFT);
+
+	/* No room after stack? */
+	if (first > last)
+		return 0;
+
+	/* Just enough room? */
+	if (first == last)
+		return first;
+
+	slots = ((last - first) >> PAGE_SHIFT) + 1;
+
+	offset = get_random_int() % slots;
+
+	addr = first + (offset << PAGE_SHIFT);
+
+	return addr;
+}
+
 static struct page *signal_page;
 extern struct page *get_signal_page(void);
 
@@ -484,6 +513,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 {
 	struct mm_struct *mm = current->mm;
 	unsigned long addr;
+	unsigned long hint;
 	int ret;
 
 	if (!signal_page)
@@ -492,7 +522,8 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 		return -ENOMEM;
 
 	down_write(&mm->mmap_sem);
-	addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0);
+	hint = vdso_addr(mm, 1);
+	addr = get_unmapped_area(NULL, hint, PAGE_SIZE, 0, 0);
 	if (IS_ERR_VALUE(addr)) {
 		ret = addr;
 		goto up_fail;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v6 2/6] ARM: allow user access to arch timer virtual counter
  2014-04-23  0:48 [PATCH v6 0/6] ARM: vdso gettimeofday using generic timer architecture Nathan Lynch
  2014-04-23  0:48 ` [PATCH v6 1/6] ARM: place sigpage at a random offset above stack Nathan Lynch
@ 2014-04-23  0:48 ` Nathan Lynch
  2014-04-23 17:32   ` Will Deacon
  2014-04-23  0:48 ` [PATCH v6 3/6] ARM: miscellaneous vdso infrastructure, preparation Nathan Lynch
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 21+ messages in thread
From: Nathan Lynch @ 2014-04-23  0:48 UTC (permalink / raw)
  To: linux-arm-kernel

As ARM64 does.  This is a necessary prerequisite for implementing
gettimeofday and clock_gettime in a vdso.

Signed-off-by: Nathan Lynch <nathan_lynch@mentor.com>
---
 arch/arm/include/asm/arch_timer.h | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h
index 0704e0cf5571..047c800b57f0 100644
--- a/arch/arm/include/asm/arch_timer.h
+++ b/arch/arm/include/asm/arch_timer.h
@@ -103,13 +103,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);
 }
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v6 3/6] ARM: miscellaneous vdso infrastructure, preparation
  2014-04-23  0:48 [PATCH v6 0/6] ARM: vdso gettimeofday using generic timer architecture Nathan Lynch
  2014-04-23  0:48 ` [PATCH v6 1/6] ARM: place sigpage at a random offset above stack Nathan Lynch
  2014-04-23  0:48 ` [PATCH v6 2/6] ARM: allow user access to arch timer virtual counter Nathan Lynch
@ 2014-04-23  0:48 ` Nathan Lynch
  2014-04-23  0:48 ` [PATCH v6 4/6] ARM: add vdso user-space code Nathan Lynch
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 21+ messages in thread
From: Nathan Lynch @ 2014-04-23  0:48 UTC (permalink / raw)
  To: linux-arm-kernel

Define the layout of the data structure shared between kernel and
userspace.

Track the vdso address in the mm_context; needed for reporting [vdso]
via /proc/pid/maps and communicating AT_SYSINFO_EHDR to the ELF
loader.

Add declarations for vma_is_vdso, arm_install_vdso, and !CONFIG_VDSO
implementations of same.  The CONFIG_VDSO=y implementations of these
come later.

Make arch_vma_name recognize a vdso VMA, using vma_is_vdso to return
"[vdso]" when appropriate.

Define AT_SYSINFO_EHDR, and, if CONFIG_VDSO=y, report the vdso shared
object address via the ELF auxiliary vector.

Note - this adds the AT_SYSINFO_EHDR in a new user-visible header
asm/auxvec.h; this is consistent with other architectures.

Signed-off-by: Nathan Lynch <nathan_lynch@mentor.com>
---
 arch/arm/include/asm/Kbuild          |  1 -
 arch/arm/include/asm/elf.h           | 11 +++++++
 arch/arm/include/asm/mmu.h           |  3 ++
 arch/arm/include/asm/vdso.h          | 47 ++++++++++++++++++++++++++++
 arch/arm/include/asm/vdso_datapage.h | 60 ++++++++++++++++++++++++++++++++++++
 arch/arm/include/uapi/asm/Kbuild     |  1 +
 arch/arm/include/uapi/asm/auxvec.h   |  7 +++++
 arch/arm/kernel/process.c            | 14 +++++++--
 8 files changed, 140 insertions(+), 4 deletions(-)
 create mode 100644 arch/arm/include/asm/vdso.h
 create mode 100644 arch/arm/include/asm/vdso_datapage.h
 create mode 100644 arch/arm/include/uapi/asm/auxvec.h

diff --git a/arch/arm/include/asm/Kbuild b/arch/arm/include/asm/Kbuild
index 23e728ecf8ab..a0b3a7486488 100644
--- a/arch/arm/include/asm/Kbuild
+++ b/arch/arm/include/asm/Kbuild
@@ -1,6 +1,5 @@
 
 
-generic-y += auxvec.h
 generic-y += bitsperlong.h
 generic-y += cputime.h
 generic-y += current.h
diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h
index f4b46d39b9cf..45d2ddff662a 100644
--- a/arch/arm/include/asm/elf.h
+++ b/arch/arm/include/asm/elf.h
@@ -1,7 +1,9 @@
 #ifndef __ASMARM_ELF_H
 #define __ASMARM_ELF_H
 
+#include <asm/auxvec.h>
 #include <asm/hwcap.h>
+#include <asm/vdso_datapage.h>
 
 /*
  * ELF register definitions..
@@ -129,6 +131,15 @@ extern unsigned long arch_randomize_brk(struct mm_struct *mm);
 #define arch_randomize_brk arch_randomize_brk
 
 #ifdef CONFIG_MMU
+#ifdef CONFIG_VDSO
+#define ARCH_DLINFO								\
+do {										\
+	/* Account for the data page at the beginning of the [vdso] VMA. */	\
+	NEW_AUX_ENT(AT_SYSINFO_EHDR,						\
+		    (elf_addr_t)current->mm->context.vdso +			\
+		    sizeof(union vdso_data_store));				\
+} while (0)
+#endif
 #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..a5b47421059d 100644
--- a/arch/arm/include/asm/mmu.h
+++ b/arch/arm/include/asm/mmu.h
@@ -11,6 +11,9 @@ typedef struct {
 #endif
 	unsigned int	vmalloc_seq;
 	unsigned long	sigpage;
+#ifdef CONFIG_VDSO
+	unsigned long	vdso;
+#endif
 } 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..0e2a6154eceb
--- /dev/null
+++ b/arch/arm/include/asm/vdso.h
@@ -0,0 +1,47 @@
+#ifndef __ASM_VDSO_H
+#define __ASM_VDSO_H
+
+#ifdef __KERNEL__
+
+#ifndef __ASSEMBLY__
+
+#include <linux/mm_types.h>
+#include <asm/mmu.h>
+
+#ifdef CONFIG_VDSO
+
+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(struct mm_struct *mm, unsigned long addr);
+
+extern char vdso_start, vdso_end;
+
+extern unsigned long vdso_mapping_len;
+
+#else /* CONFIG_VDSO */
+
+static inline bool vma_is_vdso(struct vm_area_struct *vma)
+{
+	return false;
+}
+
+static inline void arm_install_vdso(struct mm_struct *mm, unsigned long addr)
+{
+}
+
+#define vdso_mapping_len 0
+
+#endif /* CONFIG_VDSO */
+
+#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..f08bdb73d3f4
--- /dev/null
+++ b/arch/arm/include/asm/vdso_datapage.h
@@ -0,0 +1,60 @@
+/*
+ * 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__
+
+#include <asm/page.h>
+
+/* Try to be cache-friendly on systems that don't implement the
+ * generic timer: fit the unconditionally updated fields in the first
+ * 32 bytes.
+ */
+struct vdso_data {
+	u32 seq_count;		/* sequence count - odd during updates */
+	u16 use_syscall;	/* whether to fall back to syscalls */
+	u16 cs_shift;		/* clocksource shift */
+	u32 xtime_coarse_sec;	/* coarse time */
+	u32 xtime_coarse_nsec;
+
+	u32 wtm_clock_sec;	/* wall to monotonic offset */
+	u32 wtm_clock_nsec;
+	u32 xtime_clock_sec;	/* CLOCK_REALTIME - seconds */
+	u32 cs_mult;		/* clocksource multiplier */
+
+	u64 cs_cycle_last;	/* last cycle value */
+	u64 cs_mask;		/* clocksource mask */
+
+	u64 xtime_clock_snsec;	/* CLOCK_REALTIME sub-ns base */
+	u32 tz_minuteswest;	/* timezone info for gettimeofday(2) */
+	u32 tz_dsttime;
+};
+
+union vdso_data_store {
+	struct vdso_data data;
+	u8 page[PAGE_SIZE];
+};
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_VDSO_DATAPAGE_H */
diff --git a/arch/arm/include/uapi/asm/Kbuild b/arch/arm/include/uapi/asm/Kbuild
index 70a1c9da30ca..a1c05f93d920 100644
--- a/arch/arm/include/uapi/asm/Kbuild
+++ b/arch/arm/include/uapi/asm/Kbuild
@@ -1,6 +1,7 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
+header-y += auxvec.h
 header-y += byteorder.h
 header-y += fcntl.h
 header-y += hwcap.h
diff --git a/arch/arm/include/uapi/asm/auxvec.h b/arch/arm/include/uapi/asm/auxvec.h
new file mode 100644
index 000000000000..f56936b97ec2
--- /dev/null
+++ b/arch/arm/include/uapi/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/kernel/process.c b/arch/arm/kernel/process.c
index 219a0d1d10fc..40445fb71ac9 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -41,6 +41,7 @@
 #include <asm/system_misc.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 unsigned long vdso_addr(const struct mm_struct *mm, unsigned int npages)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v6 4/6] ARM: add vdso user-space code
  2014-04-23  0:48 [PATCH v6 0/6] ARM: vdso gettimeofday using generic timer architecture Nathan Lynch
                   ` (2 preceding siblings ...)
  2014-04-23  0:48 ` [PATCH v6 3/6] ARM: miscellaneous vdso infrastructure, preparation Nathan Lynch
@ 2014-04-23  0:48 ` Nathan Lynch
  2014-04-23  0:48 ` [PATCH v6 5/6] ARM: vdso initialization, mapping, and synchronization Nathan Lynch
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 21+ messages in thread
From: Nathan Lynch @ 2014-04-23  0:48 UTC (permalink / raw)
  To: linux-arm-kernel

Place vdso-related user-space code in arch/arm/kernel/vdso/.

It is almost completely written in C with some assembly helpers to
load the data page address, sample the counter, and fall back to
system calls when necessary.

If CONFIG_ARM_ARCH_TIMER is not enabled, the vdso cannot service
high-resolution clocks and falls back to syscalls.  Low-resolution
clocks e.g. CLOCK_REALTIME_COARSE can be serviced regardless.

Signed-off-by: Nathan Lynch <nathan_lynch@mentor.com>
---
 arch/arm/kernel/asm-offsets.c        |   5 +
 arch/arm/kernel/vdso/.gitignore      |   1 +
 arch/arm/kernel/vdso/Makefile        |  50 ++++++
 arch/arm/kernel/vdso/checkundef.sh   |   9 +
 arch/arm/kernel/vdso/datapage.S      |  15 ++
 arch/arm/kernel/vdso/vdso.S          |  35 ++++
 arch/arm/kernel/vdso/vdso.lds.S      |  88 +++++++++
 arch/arm/kernel/vdso/vgettimeofday.c | 338 +++++++++++++++++++++++++++++++++++
 8 files changed, 541 insertions(+)
 create mode 100644 arch/arm/kernel/vdso/.gitignore
 create mode 100644 arch/arm/kernel/vdso/Makefile
 create mode 100755 arch/arm/kernel/vdso/checkundef.sh
 create mode 100644 arch/arm/kernel/vdso/datapage.S
 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/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
index 85598b5d1efd..a582bb42dc87 100644
--- a/arch/arm/kernel/asm-offsets.c
+++ b/arch/arm/kernel/asm-offsets.c
@@ -24,6 +24,7 @@
 #include <asm/memory.h>
 #include <asm/procinfo.h>
 #include <asm/suspend.h>
+#include <asm/vdso_datapage.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <linux/kbuild.h>
 
@@ -200,5 +201,9 @@ int main(void)
 #endif
   DEFINE(KVM_VTTBR,		offsetof(struct kvm, arch.vttbr));
 #endif
+  BLANK();
+#ifdef CONFIG_VDSO
+  DEFINE(VDSO_DATA_SIZE,	sizeof(union vdso_data_store));
+#endif
   return 0; 
 }
diff --git a/arch/arm/kernel/vdso/.gitignore b/arch/arm/kernel/vdso/.gitignore
new file mode 100644
index 000000000000..f8b69d84238e
--- /dev/null
+++ b/arch/arm/kernel/vdso/.gitignore
@@ -0,0 +1 @@
+vdso.lds
diff --git a/arch/arm/kernel/vdso/Makefile b/arch/arm/kernel/vdso/Makefile
new file mode 100644
index 000000000000..d4ba13f6f66b
--- /dev/null
+++ b/arch/arm/kernel/vdso/Makefile
@@ -0,0 +1,50 @@
+obj-vdso := vgettimeofday.o datapage.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 -fno-stack-protector
+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)
+
+checkundef = sh $(srctree)/$(src)/checkundef.sh
+
+# Actual build commands
+quiet_cmd_vdsold = VDSOL   $@
+      cmd_vdsold = $(CC) $(c_flags) -Wl,-T $^ -o $@ -lgcc && \
+		   $(checkundef) '$(NM)' $@
+
+
+# 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/checkundef.sh b/arch/arm/kernel/vdso/checkundef.sh
new file mode 100755
index 000000000000..185c30da202b
--- /dev/null
+++ b/arch/arm/kernel/vdso/checkundef.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+nm="$1"
+file="$2"
+"$nm" -u "$file" | ( ret=0; while read discard symbol
+do
+    echo "$file: undefined symbol $symbol"
+    ret=1
+done ; exit $ret )
+exit $?
diff --git a/arch/arm/kernel/vdso/datapage.S b/arch/arm/kernel/vdso/datapage.S
new file mode 100644
index 000000000000..fbf36d75da06
--- /dev/null
+++ b/arch/arm/kernel/vdso/datapage.S
@@ -0,0 +1,15 @@
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+
+	.align 2
+.L_vdso_data_ptr:
+	.long	_start - . - VDSO_DATA_SIZE
+
+ENTRY(__get_datapage)
+	.cfi_startproc
+	adr	r0, .L_vdso_data_ptr
+	ldr	r1, [r0]
+	add	r0, r0, r1
+	bx	lr
+	.cfi_endproc
+ENDPROC(__get_datapage)
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..ce645a8dc8fb
--- /dev/null
+++ b/arch/arm/kernel/vdso/vdso.lds.S
@@ -0,0 +1,88 @@
+/*
+ * 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
+{
+	PROVIDE(_start = .);
+
+	. = 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
+
+
+	.eh_frame_hdr	: { *(.eh_frame_hdr) }		:text	:eh_frame_hdr
+	.eh_frame	: { KEEP (*(.eh_frame)) }	:text
+
+	.dynamic	: { *(.dynamic) }		:text	:dynamic
+
+	.rodata		: { *(.rodata*) }		:text
+
+	.text		: { *(.text*) }			:text	=0xe7f001f2
+
+	.got		: { *(.got) }
+	.rel.plt	: { *(.rel.plt) }
+
+	/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.16 {
+	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..8532b45cad62
--- /dev/null
+++ b/arch/arm/kernel/vdso/vgettimeofday.c
@@ -0,0 +1,338 @@
+/*
+ * 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/bug.h>
+#include <asm/page.h>
+#include <asm/unistd.h>
+#include <asm/vdso_datapage.h>
+
+#ifndef CONFIG_AEABI
+#error This code depends on AEABI system call conventions
+#endif
+
+extern struct vdso_data *__get_datapage(void);
+
+static u32 __vdso_read_begin(const struct vdso_data *vdata)
+{
+	u32 seq;
+repeat:
+	seq = ACCESS_ONCE(vdata->seq_count);
+	if (seq & 1) {
+		cpu_relax();
+		goto repeat;
+	}
+	return seq;
+}
+
+static u32 vdso_read_begin(const struct vdso_data *vdata)
+{
+	u32 seq = __vdso_read_begin(vdata);
+	smp_rmb();
+	return seq;
+}
+
+static int vdso_read_retry(const struct vdso_data *vdata, u32 start)
+{
+	smp_rmb();
+	return vdata->seq_count != start;
+}
+
+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 volatile(
+	"	swi #0\n"
+	: "=r" (ret)
+	: "r" (clkid), "r" (ts), "r" (nr)
+	: "memory");
+
+	return ret;
+}
+
+static int do_realtime_coarse(struct timespec *ts, struct vdso_data *vdata)
+{
+	u32 seq;
+
+	do {
+		seq = vdso_read_begin(vdata);
+
+		ts->tv_sec = vdata->xtime_coarse_sec;
+		ts->tv_nsec = vdata->xtime_coarse_nsec;
+
+	} while (vdso_read_retry(vdata, seq));
+
+	return 0;
+}
+
+static int do_monotonic_coarse(struct timespec *ts, struct vdso_data *vdata)
+{
+	struct timespec tomono;
+	u32 seq;
+
+	do {
+		seq = vdso_read_begin(vdata);
+
+		ts->tv_sec = vdata->xtime_coarse_sec;
+		ts->tv_nsec = vdata->xtime_coarse_nsec;
+
+		tomono.tv_sec = vdata->wtm_clock_sec;
+		tomono.tv_nsec = vdata->wtm_clock_nsec;
+
+	} while (vdso_read_retry(vdata, seq));
+
+	ts->tv_sec += tomono.tv_sec;
+	timespec_add_ns(ts, tomono.tv_nsec);
+
+	return 0;
+}
+
+#ifdef CONFIG_ARM_ARCH_TIMER
+
+static u64 get_ns(struct vdso_data *vdata)
+{
+	u64 cycle_delta;
+	u64 cycle_now;
+	u64 nsec;
+
+	cycle_now = arch_counter_get_cntvct();
+
+	cycle_delta = (cycle_now - vdata->cs_cycle_last) & vdata->cs_mask;
+
+	nsec = (cycle_delta * vdata->cs_mult) + vdata->xtime_clock_snsec;
+	nsec >>= vdata->cs_shift;
+
+	return nsec;
+}
+
+static int do_realtime(struct timespec *ts, struct vdso_data *vdata)
+{
+	u64 nsecs;
+	u32 seq;
+
+	do {
+		seq = vdso_read_begin(vdata);
+
+		if (vdata->use_syscall)
+			return -1;
+
+		ts->tv_sec = vdata->xtime_clock_sec;
+		nsecs = get_ns(vdata);
+
+	} while (vdso_read_retry(vdata, seq));
+
+	ts->tv_nsec = 0;
+	timespec_add_ns(ts, nsecs);
+
+	return 0;
+}
+
+static int do_monotonic(struct timespec *ts, struct vdso_data *vdata)
+{
+	struct timespec tomono;
+	u64 nsecs;
+	u32 seq;
+
+	do {
+		seq = vdso_read_begin(vdata);
+
+		if (vdata->use_syscall)
+			return -1;
+
+		ts->tv_sec = vdata->xtime_clock_sec;
+		nsecs = get_ns(vdata);
+
+		tomono.tv_sec = vdata->wtm_clock_sec;
+		tomono.tv_nsec = vdata->wtm_clock_nsec;
+
+	} while (vdso_read_retry(vdata, seq));
+
+	ts->tv_sec += tomono.tv_sec;
+	ts->tv_nsec = 0;
+	timespec_add_ns(ts, nsecs + tomono.tv_nsec);
+
+	return 0;
+}
+
+#else /* CONFIG_ARM_ARCH_TIMER */
+
+static int do_realtime(struct timespec *ts, struct vdso_data *vdata)
+{
+	return -1;
+}
+
+static int do_monotonic(struct timespec *ts, struct vdso_data *vdata)
+{
+	return -1;
+}
+
+#endif /* CONFIG_ARM_ARCH_TIMER */
+
+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\n"
+	: "=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 volatile(
+	"	swi #0\n"
+	: "=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;
+}
+
+static inline void vdso_bug(void)
+{
+	/* Cribbed from asm/bug.h - force illegal instruction */
+	asm volatile(BUG_INSTR(BUG_INSTR_VALUE) "\n");
+	unreachable();
+}
+
+/* Avoid undefined symbols that can be referenced by routines brought
+ * in from libgcc.  libgcc's __div0, __aeabi_idiv0 and __aeabi_ldiv0
+ * can call raise(3); here they are defined to trap with an undefined
+ * instruction: divide by zero should not be possible in this code.
+ */
+void __div0(void)
+{
+	vdso_bug();
+}
+
+void __aeabi_idiv0(void)
+{
+	vdso_bug();
+}
+
+void __aeabi_ldiv0(void)
+{
+	vdso_bug();
+}
+
+void __aeabi_unwind_cpp_pr0(void)
+{
+}
+
+void __aeabi_unwind_cpp_pr1(void)
+{
+}
+
+void __aeabi_unwind_cpp_pr2(void)
+{
+}
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v6 5/6] ARM: vdso initialization, mapping, and synchronization
  2014-04-23  0:48 [PATCH v6 0/6] ARM: vdso gettimeofday using generic timer architecture Nathan Lynch
                   ` (3 preceding siblings ...)
  2014-04-23  0:48 ` [PATCH v6 4/6] ARM: add vdso user-space code Nathan Lynch
@ 2014-04-23  0:48 ` Nathan Lynch
  2014-04-23  0:48 ` [PATCH v6 6/6] ARM: add CONFIG_VDSO Kconfig and Makefile bits Nathan Lynch
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 21+ messages in thread
From: Nathan Lynch @ 2014-04-23  0:48 UTC (permalink / raw)
  To: linux-arm-kernel

Initialize the vdso page list at boot, install the vdso mapping at
exec time, and update the data page during timer ticks.  This code is
not built if CONFIG_VDSO is not enabled.

Account for the vdso length when randomizing the offset from the
stack.  The vdso is placed immediately following the sigpage with a
separate install_special_mapping call in arm_install_vdso.

Signed-off-by: Nathan Lynch <nathan_lynch@mentor.com>
---
 arch/arm/kernel/process.c |  13 +++-
 arch/arm/kernel/vdso.c    | 168 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 179 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm/kernel/vdso.c

diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 40445fb71ac9..39b0d68aa068 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -520,6 +520,7 @@ extern struct page *get_signal_page(void);
 int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 {
 	struct mm_struct *mm = current->mm;
+	unsigned long npages;
 	unsigned long addr;
 	unsigned long hint;
 	int ret;
@@ -529,9 +530,11 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 	if (!signal_page)
 		return -ENOMEM;
 
+	npages = (vdso_mapping_len >> PAGE_SHIFT) + 1;
+
 	down_write(&mm->mmap_sem);
-	hint = vdso_addr(mm, 1);
-	addr = get_unmapped_area(NULL, hint, PAGE_SIZE, 0, 0);
+	hint = vdso_addr(mm, npages);
+	addr = get_unmapped_area(NULL, hint, npages, 0, 0);
 	if (IS_ERR_VALUE(addr)) {
 		ret = addr;
 		goto up_fail;
@@ -544,6 +547,12 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 	if (ret == 0)
 		mm->context.sigpage = addr;
 
+	/* Unlike the sigpage, failure to install the vdso is unlikely
+	 * to be fatal to the process, so no error check needed
+	 * here.
+	 */
+	arm_install_vdso(mm, addr + PAGE_SIZE);
+
  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..0cfd25f09adf
--- /dev/null
+++ b/arch/arm/kernel/vdso.c
@@ -0,0 +1,168 @@
+/*
+ * 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/barrier.h>
+#include <asm/cacheflush.h>
+#include <asm/page.h>
+#include <asm/vdso.h>
+#include <asm/vdso_datapage.h>
+
+static struct page **vdso_pagelist;
+
+unsigned long vdso_mapping_len __read_mostly;
+
+/*
+ * The vDSO data page.
+ */
+static union vdso_data_store vdso_data_store __page_aligned_data;
+static struct vdso_data *vdso_data = &vdso_data_store.data;
+
+static int __init vdso_init(void)
+{
+	unsigned long vdso_pages;
+	int i;
+
+	if (memcmp(&vdso_start, "\177ELF", 4)) {
+		pr_err("vDSO is not a valid ELF object!\n");
+		return -ENOEXEC;
+	}
+
+	vdso_pages = (&vdso_end - &vdso_start) >> PAGE_SHIFT;
+	pr_debug("vdso: %ld code pages at base %p\n", vdso_pages, &vdso_start);
+
+	/* 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] = virt_to_page(vdso_data);
+
+	/* Grab the vDSO code pages. */
+	for (i = 0; i < vdso_pages; i++)
+		vdso_pagelist[i + 1] = virt_to_page(&vdso_start + i * PAGE_SIZE);
+
+	/* Precompute the mapping size */
+	vdso_mapping_len = (vdso_pages + 1) << PAGE_SHIFT;
+
+	return 0;
+}
+arch_initcall(vdso_init);
+
+/* assumes mmap_sem is write-locked */
+void arm_install_vdso(struct mm_struct *mm, unsigned long addr)
+{
+	int ret;
+
+	mm->context.vdso = ~0UL;
+
+	if (vdso_pagelist == NULL)
+		return;
+
+	/*
+	 * Put vDSO base into mm struct before calling
+	 * install_special_mapping so the perf counter mmap tracking
+	 * code will recognise it as a vDSO.
+	 */
+	mm->context.vdso = addr;
+
+	ret = install_special_mapping(mm, addr, 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 = ~0UL;
+		return;
+	}
+}
+
+static void vdso_write_begin(struct vdso_data *vdata)
+{
+	++vdso_data->seq_count;
+	smp_wmb();
+}
+
+static void vdso_write_end(struct vdso_data *vdata)
+{
+	smp_wmb();
+	++vdso_data->seq_count;
+}
+
+/**
+ * update_vsyscall - update the vdso data page
+ *
+ * Increment the sequence counter, making it odd, indicating to
+ * userspace that an update is in progress.  Update the fields used
+ * for coarse clocks and, if the architected system timer is in use,
+ * the fields used for high precision clocks.  Increment the sequence
+ * counter again, making it even, indicating to userspace that the
+ * update is finished.
+ *
+ * Userspace is expected to sample seq_count before reading any other
+ * fields from the data page.  If seq_count is odd, userspace is
+ * expected to wait until it becomes even.  After copying data from
+ * the page, userspace must sample seq_count again; if it has changed
+ * from its previous value, userspace must retry the whole sequence.
+ *
+ * Calls to update_vsyscall are serialized by the timekeeping core.
+ */
+void update_vsyscall(struct timekeeper *tk)
+{
+	struct timespec xtime_coarse;
+	struct timespec *wtm = &tk->wall_to_monotonic;
+	bool use_syscall = strcmp(tk->clock->name, "arch_sys_counter");
+
+	vdso_write_begin(vdso_data);
+
+	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;
+	vdso_data->wtm_clock_sec		= wtm->tv_sec;
+	vdso_data->wtm_clock_nsec		= wtm->tv_nsec;
+
+	if (!use_syscall) {
+		vdso_data->cs_cycle_last	= tk->cycle_last;
+		vdso_data->xtime_clock_sec	= tk->xtime_sec;
+		vdso_data->xtime_clock_snsec	= tk->xtime_nsec;
+		vdso_data->cs_mult		= tk->mult;
+		vdso_data->cs_shift		= tk->shift;
+		vdso_data->cs_mask		= tk->clock->mask;
+	}
+
+	vdso_write_end(vdso_data);
+
+	flush_dcache_page(virt_to_page(vdso_data));
+}
+
+void update_vsyscall_tz(void)
+{
+	vdso_data->tz_minuteswest	= sys_tz.tz_minuteswest;
+	vdso_data->tz_dsttime		= sys_tz.tz_dsttime;
+	flush_dcache_page(virt_to_page(vdso_data));
+}
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v6 6/6] ARM: add CONFIG_VDSO Kconfig and Makefile bits
  2014-04-23  0:48 [PATCH v6 0/6] ARM: vdso gettimeofday using generic timer architecture Nathan Lynch
                   ` (4 preceding siblings ...)
  2014-04-23  0:48 ` [PATCH v6 5/6] ARM: vdso initialization, mapping, and synchronization Nathan Lynch
@ 2014-04-23  0:48 ` Nathan Lynch
  2014-04-23 19:45 ` [PATCH v6 0/6] ARM: vdso gettimeofday using generic timer architecture Stephen Boyd
  2014-04-23 21:50 ` Russell King - ARM Linux
  7 siblings, 0 replies; 21+ messages in thread
From: Nathan Lynch @ 2014-04-23  0:48 UTC (permalink / raw)
  To: linux-arm-kernel

Allow users to enable the vdso in Kconfig; include the vdso in the
build if CONFIG_VDSO is enabled.

Signed-off-by: Nathan Lynch <nathan_lynch@mentor.com>
---
 arch/arm/kernel/Makefile |  1 +
 arch/arm/mm/Kconfig      | 15 +++++++++++++++
 2 files changed, 16 insertions(+)

diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index a766bcbaf8ad..c70b5a4855d9 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -84,6 +84,7 @@ obj-$(CONFIG_PERF_EVENTS)	+= perf_regs.o
 obj-$(CONFIG_HW_PERF_EVENTS)	+= perf_event.o perf_event_cpu.o
 AFLAGS_iwmmxt.o			:= -Wa,-mcpu=iwmmxt
 obj-$(CONFIG_ARM_CPU_TOPOLOGY)  += topology.o
+obj-$(CONFIG_VDSO)		+= vdso.o vdso/
 
 ifneq ($(CONFIG_ARCH_EBSA110),y)
   obj-y		+= io.o
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index f5ad9ee70426..0e89f59ff4c3 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -824,6 +824,21 @@ config KUSER_HELPERS
 	  Say N here only if you are absolutely certain that you do not
 	  need these helpers; otherwise, the safe option is to say Y.
 
+config VDSO
+	bool "Enable vDSO for acceleration of some system calls"
+	depends on AEABI && MMU
+	default y if ARM_ARCH_TIMER
+	select GENERIC_TIME_VSYSCALL
+	help
+	  Place in the process address space an ELF shared object
+	  providing fast implementations of several system calls,
+	  including gettimeofday and clock_gettime.  Systems that
+	  implement the ARM architected timer will receive maximum
+	  benefit.
+
+	  You must have glibc 2.20 or later for programs to seamlessly
+	  take advantage of this.
+
 config DMA_CACHE_RWFO
 	bool "Enable read/write for ownership DMA cache maintenance"
 	depends on CPU_V6K && SMP
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v6 2/6] ARM: allow user access to arch timer virtual counter
  2014-04-23  0:48 ` [PATCH v6 2/6] ARM: allow user access to arch timer virtual counter Nathan Lynch
@ 2014-04-23 17:32   ` Will Deacon
  2014-04-23 17:41     ` Nathan Lynch
  0 siblings, 1 reply; 21+ messages in thread
From: Will Deacon @ 2014-04-23 17:32 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Apr 23, 2014 at 01:48:53AM +0100, Nathan Lynch wrote:
> As ARM64 does.  This is a necessary prerequisite for implementing
> gettimeofday and clock_gettime in a vdso.

Doesn't this change make arch_counter_set_user_access identical for arm and
arm64? In which case, we could move it into the driver itself.

Will

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v6 2/6] ARM: allow user access to arch timer virtual counter
  2014-04-23 17:32   ` Will Deacon
@ 2014-04-23 17:41     ` Nathan Lynch
  2014-04-24 10:18       ` Will Deacon
  0 siblings, 1 reply; 21+ messages in thread
From: Nathan Lynch @ 2014-04-23 17:41 UTC (permalink / raw)
  To: linux-arm-kernel

On 04/23/2014 12:32 PM, Will Deacon wrote:
> On Wed, Apr 23, 2014 at 01:48:53AM +0100, Nathan Lynch wrote:
>> As ARM64 does.  This is a necessary prerequisite for implementing
>> gettimeofday and clock_gettime in a vdso.
> 
> Doesn't this change make arch_counter_set_user_access identical for arm and
> arm64? In which case, we could move it into the driver itself.

True; I had considered this but wasn't sure how it could be staged.

Would a single patch updating arch/arm64, arch/arm, and
drivers/clocksource/arm_arch_timer.c be okay?

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v6 0/6] ARM: vdso gettimeofday using generic timer architecture
  2014-04-23  0:48 [PATCH v6 0/6] ARM: vdso gettimeofday using generic timer architecture Nathan Lynch
                   ` (5 preceding siblings ...)
  2014-04-23  0:48 ` [PATCH v6 6/6] ARM: add CONFIG_VDSO Kconfig and Makefile bits Nathan Lynch
@ 2014-04-23 19:45 ` Stephen Boyd
  2014-04-24  2:28   ` Nathan Lynch
  2014-04-23 21:50 ` Russell King - ARM Linux
  7 siblings, 1 reply; 21+ messages in thread
From: Stephen Boyd @ 2014-04-23 19:45 UTC (permalink / raw)
  To: linux-arm-kernel

On 04/22/14 17:48, Nathan Lynch wrote:
> 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).
>
> Note that while the high-precision realtime and monotonic clock
> support depends on the generic timers extension, support for
> clock_getres and coarse clocks is independent of the timer
> implementation and is provided unconditionally.

I think we'll need to rename the clocksource in arch_timer.c if we only
have an mmio architected timer to something like arch_mem_counter. Or we
would need to map the register space for the view into userspace? I'm
guessing that is hard, but if that was done then I assume it would lay
the foundation for any mmio clocksource being used for the vdso.

----8<-----
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index b009012429b5..3f3d8ed465f4 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -449,10 +449,12 @@ static void __init arch_counter_register(unsigned type)
        u64 start_count;
 
        /* Register the CP15 based counter if we have one */
-       if (type & ARCH_CP15_TIMER)
+       if (type & ARCH_CP15_TIMER) {
                arch_timer_read_counter = arch_counter_get_cntvct_cp15;
-       else
+       } else {
                arch_timer_read_counter = arch_counter_get_cntvct_mem;
+               clocksource_counter.name = "arch_mem_counter";
+       }
 
        start_count = arch_timer_read_counter();
        clocksource_register_hz(&clocksource_counter, arch_timer_rate);

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v6 0/6] ARM: vdso gettimeofday using generic timer architecture
  2014-04-23  0:48 [PATCH v6 0/6] ARM: vdso gettimeofday using generic timer architecture Nathan Lynch
                   ` (6 preceding siblings ...)
  2014-04-23 19:45 ` [PATCH v6 0/6] ARM: vdso gettimeofday using generic timer architecture Stephen Boyd
@ 2014-04-23 21:50 ` Russell King - ARM Linux
  2014-04-24  7:37   ` Ard Biesheuvel
  2014-04-24 14:59   ` Nathan Lynch
  7 siblings, 2 replies; 21+ messages in thread
From: Russell King - ARM Linux @ 2014-04-23 21:50 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Apr 22, 2014 at 07:48:51PM -0500, Nathan Lynch wrote:
> - Build vdso.so with -lgcc: calls to __lshrdi3, __divsi3 sometimes
>   emitted (especially with -Os).  Override certain libgcc functions to
>   prevent undefined symbols.

This rather worries me.

For a start, the toolchain I use for cross-building kernels (which I
build myself from gnu.org source) never has a libgcc with it - that's
because in order to build libgcc, I need a libc, and I don't want to
have a full cross environment on my machine just to build the soddin
compiler.

So, I want to be able to build kernels without having a libgcc sitting
around.

Second point here is that we have multiple different versions of
userspace crap with multiple different ABIs.  Think about armel vs
armhf for starters.  There's at least *three* different ELF formats -
OABI, EABI armel, EABI armhf.  Okay, we can forget about OABI, but
what about the other two?  What about single zImage where you may
want a single kernel image which can run on either flavour?

It is not possible to build a single .so which is compatible with
both - an armhf dynamic linker rejects armel outright, and vice versa.

This, to me, sounds like one big fail... and as far as I'm aware, the
kernel has no idea itself which flavour of userspace is running, so it
has no idea which flavour of VDSO to offer (if it even had both.)

-- 
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v6 0/6] ARM: vdso gettimeofday using generic timer architecture
  2014-04-23 19:45 ` [PATCH v6 0/6] ARM: vdso gettimeofday using generic timer architecture Stephen Boyd
@ 2014-04-24  2:28   ` Nathan Lynch
  2014-04-24 17:00     ` Stephen Boyd
  0 siblings, 1 reply; 21+ messages in thread
From: Nathan Lynch @ 2014-04-24  2:28 UTC (permalink / raw)
  To: linux-arm-kernel

On 04/23/2014 02:45 PM, Stephen Boyd wrote:
> On 04/22/14 17:48, Nathan Lynch wrote:
>> 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).
>>
>> Note that while the high-precision realtime and monotonic clock
>> support depends on the generic timers extension, support for
>> clock_getres and coarse clocks is independent of the timer
>> implementation and is provided unconditionally.
> 
> I think we'll need to rename the clocksource in arch_timer.c if we only
> have an mmio architected timer to something like arch_mem_counter.

I guess ARMv7 would allow you to have mmio without cp15 (AFAIK ARMv8
does not).  I don't see any dts in arch/arm that contains an
arm,armv7-timer-mem node without an arm,armv7-timer node, though.

If this is a practical concern, I think using
CONFIG_ARCH_CLOCKSOURCE_DATA is perhaps a better way to communicate
whether cp15 access is available.  That's how the x86 vdso, for example,
decides between using HPET vs TSC etc.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v6 0/6] ARM: vdso gettimeofday using generic timer architecture
  2014-04-23 21:50 ` Russell King - ARM Linux
@ 2014-04-24  7:37   ` Ard Biesheuvel
  2014-04-24 15:15     ` Nathan Lynch
  2014-04-24 14:59   ` Nathan Lynch
  1 sibling, 1 reply; 21+ messages in thread
From: Ard Biesheuvel @ 2014-04-24  7:37 UTC (permalink / raw)
  To: linux-arm-kernel

On 23 April 2014 23:50, Russell King - ARM Linux <linux@arm.linux.org.uk> wrote:
> On Tue, Apr 22, 2014 at 07:48:51PM -0500, Nathan Lynch wrote:
>> - Build vdso.so with -lgcc: calls to __lshrdi3, __divsi3 sometimes
>>   emitted (especially with -Os).  Override certain libgcc functions to
>>   prevent undefined symbols.

After reading Russell's concerns below, I had a quick play with these
patches, and I noticed that the libgcc dependencies are actually only
present when compiling -Os. However, with normal optimization enabled
(which most people are using anyway), you don't need libgcc at all. So
why not override -O2 optimization for vdso.so, and be done with it?

WIth -Os:

Archive member included because of file (symbol)

/usr/lib/gcc-cross/arm-linux-gnueabihf/4.8/sf/libgcc.a(_divsi3.o)
                              arch/arm/kernel/vdso/vgettimeofday.o
(__aeabi_idiv)
/usr/lib/gcc-cross/arm-linux-gnueabihf/4.8/sf/libgcc.a(_lshrdi3.o)
                              arch/arm/kernel/vdso/vgettimeofday.o
(__aeabi_llsr)

Without CONFIG_OPTIMIZE_FOR_SIZE, no archive members are included at all.

-- 
Ard.



>
> This rather worries me.
>
> For a start, the toolchain I use for cross-building kernels (which I
> build myself from gnu.org source) never has a libgcc with it - that's
> because in order to build libgcc, I need a libc, and I don't want to
> have a full cross environment on my machine just to build the soddin
> compiler.
>
> So, I want to be able to build kernels without having a libgcc sitting
> around.
>
> Second point here is that we have multiple different versions of
> userspace crap with multiple different ABIs.  Think about armel vs
> armhf for starters.  There's at least *three* different ELF formats -
> OABI, EABI armel, EABI armhf.  Okay, we can forget about OABI, but
> what about the other two?  What about single zImage where you may
> want a single kernel image which can run on either flavour?
>
> It is not possible to build a single .so which is compatible with
> both - an armhf dynamic linker rejects armel outright, and vice versa.
>
> This, to me, sounds like one big fail... and as far as I'm aware, the
> kernel has no idea itself which flavour of userspace is running, so it
> has no idea which flavour of VDSO to offer (if it even had both.)
>
> --
> FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
> improving, and getting towards what was expected from it.
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v6 2/6] ARM: allow user access to arch timer virtual counter
  2014-04-23 17:41     ` Nathan Lynch
@ 2014-04-24 10:18       ` Will Deacon
  0 siblings, 0 replies; 21+ messages in thread
From: Will Deacon @ 2014-04-24 10:18 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Apr 23, 2014 at 06:41:03PM +0100, Nathan Lynch wrote:
> On 04/23/2014 12:32 PM, Will Deacon wrote:
> > On Wed, Apr 23, 2014 at 01:48:53AM +0100, Nathan Lynch wrote:
> >> As ARM64 does.  This is a necessary prerequisite for implementing
> >> gettimeofday and clock_gettime in a vdso.
> > 
> > Doesn't this change make arch_counter_set_user_access identical for arm and
> > arm64? In which case, we could move it into the driver itself.
> 
> True; I had considered this but wasn't sure how it could be staged.
> 
> Would a single patch updating arch/arm64, arch/arm, and
> drivers/clocksource/arm_arch_timer.c be okay?

I'd probably modify arm_arch_timer.c to have it's own implementation, then
have follow-up patches removing the arch-private definitions. You could
probably deal with arch_timer_evtstrm_enable at the same time.

Will

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v6 0/6] ARM: vdso gettimeofday using generic timer architecture
  2014-04-23 21:50 ` Russell King - ARM Linux
  2014-04-24  7:37   ` Ard Biesheuvel
@ 2014-04-24 14:59   ` Nathan Lynch
  2014-04-24 16:22     ` Russell King - ARM Linux
  1 sibling, 1 reply; 21+ messages in thread
From: Nathan Lynch @ 2014-04-24 14:59 UTC (permalink / raw)
  To: linux-arm-kernel

On 04/23/2014 04:50 PM, Russell King - ARM Linux wrote:
> On Tue, Apr 22, 2014 at 07:48:51PM -0500, Nathan Lynch wrote:
>> - Build vdso.so with -lgcc: calls to __lshrdi3, __divsi3 sometimes
>>   emitted (especially with -Os).  Override certain libgcc functions to
>>   prevent undefined symbols.
> 
> This rather worries me.
> 
> For a start, the toolchain I use for cross-building kernels (which I
> build myself from gnu.org source) never has a libgcc with it - that's
> because in order to build libgcc, I need a libc, and I don't want to
> have a full cross environment on my machine just to build the soddin
> compiler.
> 
> So, I want to be able to build kernels without having a libgcc sitting
> around.

I should be able to accommodate that (see Ard's suggestion for a
possible approach).


> Second point here is that we have multiple different versions of
> userspace crap with multiple different ABIs.  Think about armel vs
> armhf for starters.  There's at least *three* different ELF formats -
> OABI, EABI armel, EABI armhf.  Okay, we can forget about OABI, but
> what about the other two?  What about single zImage where you may
> want a single kernel image which can run on either flavour?

I confess I had not contemplated that use case.


> It is not possible to build a single .so which is compatible with
> both - an armhf dynamic linker rejects armel outright, and vice versa.
> 
> This, to me, sounds like one big fail... and as far as I'm aware, the
> kernel has no idea itself which flavour of userspace is running, so it
> has no idea which flavour of VDSO to offer (if it even had both.)

Maybe I'm confused about something, but I'm able to use the vdso fine
with an armhf userspace:

# readelf -A vdso.txt # dumped from /proc/pid/mem
Attribute Section: aeabi
File Attributes
  Tag_CPU_name: "6K"
  Tag_CPU_arch: v6K
  Tag_ARM_ISA_use: Yes
  Tag_THUMB_ISA_use: Thumb-1
  Tag_FP_arch: VFPv2
  Tag_ABI_PCS_wchar_t: 4
  Tag_ABI_FP_denormal: Needed
  Tag_ABI_FP_exceptions: Needed
  Tag_ABI_FP_number_model: IEEE 754
  Tag_ABI_align_needed: 8-byte
  Tag_ABI_enum_size: int
  Tag_ABI_optimization_goals: Aggressive Speed
  Tag_CPU_unaligned_access: v6
# readelf -A /usr/bin/vdsotest
Attribute Section: aeabi
File Attributes
  Tag_CPU_name: "7-A"
  Tag_CPU_arch: v7
  Tag_CPU_arch_profile: Application
  Tag_ARM_ISA_use: Yes
  Tag_THUMB_ISA_use: Thumb-2
  Tag_FP_arch: VFPv3-D16
  Tag_ABI_PCS_wchar_t: 4
  Tag_ABI_FP_rounding: Needed
  Tag_ABI_FP_denormal: Needed
  Tag_ABI_FP_exceptions: Needed
  Tag_ABI_FP_number_model: IEEE 754
  Tag_ABI_align_needed: 8-byte
  Tag_ABI_align_preserved: 8-byte, except leaf SP
  Tag_ABI_enum_size: int
  Tag_ABI_HardFP_use: SP and DP
  Tag_ABI_VFP_args: VFP registers
  Tag_CPU_unaligned_access: v6
  Tag_MPextension_use: Allowed
  Tag_Virtualization_use: TrustZone
# LD_TRACE_LOADED_OBJECTS=1 /usr/bin/vdsotest
        linux-vdso.so.1 (0xbec96000)
        librt.so.1 => /lib/arm-linux-gnueabihf/librt.so.1 (0xb6fca000)
        libdl.so.2 => /lib/arm-linux-gnueabihf/libdl.so.2 (0xb6fbf000)
        libc.so.6 => /lib/arm-linux-gnueabihf/libc.so.6 (0xb6ed8000)
        libpthread.so.0 => /lib/arm-linux-gnueabihf/libpthread.so.0
(0xb6ebd000)
        /lib/ld-linux-armhf.so.3 (0xb6fd8000)
# vdsotest -v clock-gettime-realtime bench
clock-gettime-realtime: syscalls = 324192, vdso calls = 3282333
clock-gettime-realtime system calls per second: 648309
clock-gettime-realtime vdso calls per second:   6563926 (10.12x speedup)

(That's with a kernel with lots of debugging enabled, don't get excited
about the speedup reported.)

The test program (vdsotest) is using dlsym to get at the vdso and the
glibc is straight from a Linaro toolchain, no vdso patches.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v6 0/6] ARM: vdso gettimeofday using generic timer architecture
  2014-04-24  7:37   ` Ard Biesheuvel
@ 2014-04-24 15:15     ` Nathan Lynch
  2014-04-24 15:25       ` Ard Biesheuvel
  0 siblings, 1 reply; 21+ messages in thread
From: Nathan Lynch @ 2014-04-24 15:15 UTC (permalink / raw)
  To: linux-arm-kernel

On 04/24/2014 02:37 AM, Ard Biesheuvel wrote:
> On 23 April 2014 23:50, Russell King - ARM Linux <linux@arm.linux.org.uk> wrote:
>> On Tue, Apr 22, 2014 at 07:48:51PM -0500, Nathan Lynch wrote:
>>> - Build vdso.so with -lgcc: calls to __lshrdi3, __divsi3 sometimes
>>>   emitted (especially with -Os).  Override certain libgcc functions to
>>>   prevent undefined symbols.
> 
> After reading Russell's concerns below, I had a quick play with these
> patches, and I noticed that the libgcc dependencies are actually only
> present when compiling -Os. However, with normal optimization enabled
> (which most people are using anyway), you don't need libgcc at all. So
> why not override -O2 optimization for vdso.so, and be done with it?
> 
> WIth -Os:
> 
> Archive member included because of file (symbol)
> 
> /usr/lib/gcc-cross/arm-linux-gnueabihf/4.8/sf/libgcc.a(_divsi3.o)
>                               arch/arm/kernel/vdso/vgettimeofday.o
> (__aeabi_idiv)
> /usr/lib/gcc-cross/arm-linux-gnueabihf/4.8/sf/libgcc.a(_lshrdi3.o)
>                               arch/arm/kernel/vdso/vgettimeofday.o
> (__aeabi_llsr)
> 
> Without CONFIG_OPTIMIZE_FOR_SIZE, no archive members are included at all.

Thanks.  I had thought about forcing -O2 in the past but just wasn't
confident that it would prevent calls to __divsi3 etc in all situations.
 I mean, that's not really a documented or guaranteed behavior of -O2,
is it?

I've now built vdso.so with your suggested change with GCC 4.[4-8]
without getting any unresolved symbols, so here's hoping this is a
viable option.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v6 0/6] ARM: vdso gettimeofday using generic timer architecture
  2014-04-24 15:15     ` Nathan Lynch
@ 2014-04-24 15:25       ` Ard Biesheuvel
  0 siblings, 0 replies; 21+ messages in thread
From: Ard Biesheuvel @ 2014-04-24 15:25 UTC (permalink / raw)
  To: linux-arm-kernel

On 24 April 2014 17:15, Nathan Lynch <Nathan_Lynch@mentor.com> wrote:
> On 04/24/2014 02:37 AM, Ard Biesheuvel wrote:
>> On 23 April 2014 23:50, Russell King - ARM Linux <linux@arm.linux.org.uk> wrote:
>>> On Tue, Apr 22, 2014 at 07:48:51PM -0500, Nathan Lynch wrote:
>>>> - Build vdso.so with -lgcc: calls to __lshrdi3, __divsi3 sometimes
>>>>   emitted (especially with -Os).  Override certain libgcc functions to
>>>>   prevent undefined symbols.
>>
>> After reading Russell's concerns below, I had a quick play with these
>> patches, and I noticed that the libgcc dependencies are actually only
>> present when compiling -Os. However, with normal optimization enabled
>> (which most people are using anyway), you don't need libgcc at all. So
>> why not override -O2 optimization for vdso.so, and be done with it?
>>
>> WIth -Os:
>>
>> Archive member included because of file (symbol)
>>
>> /usr/lib/gcc-cross/arm-linux-gnueabihf/4.8/sf/libgcc.a(_divsi3.o)
>>                               arch/arm/kernel/vdso/vgettimeofday.o
>> (__aeabi_idiv)
>> /usr/lib/gcc-cross/arm-linux-gnueabihf/4.8/sf/libgcc.a(_lshrdi3.o)
>>                               arch/arm/kernel/vdso/vgettimeofday.o
>> (__aeabi_llsr)
>>
>> Without CONFIG_OPTIMIZE_FOR_SIZE, no archive members are included at all.
>
> Thanks.  I had thought about forcing -O2 in the past but just wasn't
> confident that it would prevent calls to __divsi3 etc in all situations.
>  I mean, that's not really a documented or guaranteed behavior of -O2,
> is it?
>

No it is not, unfortunately. But I agree with Russell that pulling in
bits of libgcc.a into your vdso is a bad idea.
It would be interesting to find out why exactly these dependencies are
there, so you can work around them.
And if that is not an option, it would be preferable IMO to duplicate
__aeabi_idiv under vdso/ somewhere if you really depend on it.

> I've now built vdso.so with your suggested change with GCC 4.[4-8]
> without getting any unresolved symbols, so here's hoping this is a
> viable option.
>

-- 
Ard.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v6 0/6] ARM: vdso gettimeofday using generic timer architecture
  2014-04-24 14:59   ` Nathan Lynch
@ 2014-04-24 16:22     ` Russell King - ARM Linux
  2014-04-24 18:41       ` Nathan Lynch
  0 siblings, 1 reply; 21+ messages in thread
From: Russell King - ARM Linux @ 2014-04-24 16:22 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Apr 24, 2014 at 09:59:59AM -0500, Nathan Lynch wrote:
> Maybe I'm confused about something, but I'm able to use the vdso fine
> with an armhf userspace:

On my Dove CuBox, I have both armel and armhf binaries.  All armel stuff
lives in /armel (the machine used to run ubuntu 12.04 armel but now runs
ubuntu 12.04 armhf.)

root at cubox:~# LD_TRACE_LOADED_OBJECTS=1 /armel/lib/arm-linux-gnueabi/ld-linux.so.3 --library-path /lib/arm-linux-gnueabihf/ /armel/bin/cat
root at cubox:~# strace env LD_TRACE_LOADED_OBJECTS=1 /armel/lib/arm-linux-gnueabi/ld-linux.so.3 --library-path /lib/arm-linux-gnueabihf/ /armel/bin/cat
...
open("/lib/arm-linux-gnueabihf/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0(\0\1\0\0\0\355p\1\0004\0\0\0"..., 512) = 512
lseek(3, 888764, SEEK_SET)              = 888764
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1360) = 1360
lseek(3, 888324, SEEK_SET)              = 888324
read(3, "A4\0\0\0aeabi\0\1*\0\0\0\0057-A\0\6\n\7A\10\1\t\2\n\4\22"..., 53) = 53
exit_group(1)                           = ?

So there we have an armel dynamic linker with an armel binary encountering
an armhf library and silently failing.  Now let's try it the other way
around:

root at cubox:~# strace env LD_TRACE_LOADED_OBJECTS=1 /lib/arm-linux-gnueabihf/ld-linux-armhf.so.3 --library-path /armel/lib/arm-linux-gnueabi/ /bin/cat
...
open("/armel/lib/arm-linux-gnueabi/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0(\0\1\0\0\0\355p\1\0004\0\0\0"..., 512) = 512
lseek(3, 880572, SEEK_SET)              = 880572
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1360) = 1360
lseek(3, 880132, SEEK_SET)              = 880132
read(3, "A2\0\0\0aeabi\0\1(\0\0\0\0057-A\0\6\n\7A\10\1\t\2\n\4\22"..., 51) = 51
exit_group(1)                           = ?

The linker again silently throws its toys out the pram.

To prove that it's a working environment:

root at cubox:~# strace env LD_TRACE_LOADED_OBJECTS=1 /armel/lib/arm-linux-gnueabi/ld-linux.so.3 --library-path /armel/lib/arm-linux-gnueabi/ /armel/bin/cat
open("/armel/lib/arm-linux-gnueabi/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0(\0\1\0\0\0\355p\1\0004\0\0\0"..., 512) = 512
lseek(3, 880572, SEEK_SET)              = 880572
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1360) = 1360
lseek(3, 880132, SEEK_SET)              = 880132
read(3, "A2\0\0\0aeabi\0\1(\0\0\0\0057-A\0\6\n\7A\10\1\t\2\n\4\22"..., 51) = 51
fstat64(3, {st_mode=S_IFREG|0755, st_size=881932, ...}) = 0
...
set_tls(0xb6e544c0, 0xb6e54b98, 0xb6f59048, 0xb6e544c0, 0xb6f374f0) = 0
writev(1, [{"\t", 1}, {"libc.so.6", 9}, {" => ", 4}, {"/armel/lib/arm-linux-gnueabi/lib"..., 38}, {" (0x", 4}, {"b6e55000", 8}, {")\n", 2}], 7  libc.so.6 => /armel/lib/arm-linux-gnueabi/libc.so.6 (0xb6e55000)
) = 66
writev(1, [{"\t", 1}, {"/lib/ld-linux.so.3", 18}, {" => ", 4}, {"/armel/lib/arm-linux-gnueabi/ld-"..., 42}, {" (0x", 4}, {"b6f3a000", 8}, {")\n", 2}], 7
/lib/ld-linux.so.3 => /armel/lib/arm-linux-gnueabi/ld-linux.so.3 (0xb6f3a000)
) = 79
exit_group(0)                           = ?

and of course the armhf environment works because that's the one the
machine currently boots.

The obvious question therefore is, if the dynamic linker throws its toys
out if it encounters a wrong-float-ABI library during a standard library
search, why would it _not_ throw its toys out on dlsym.  The difference
in behaviour would to me seem to be a bug - both should behave the same,
though of course not throwing its toys out, but instead producing an error
_or_ accepting the difference.  Given that it's an ABI difference,
rejecting the library is the only sane approach.

-- 
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v6 0/6] ARM: vdso gettimeofday using generic timer architecture
  2014-04-24  2:28   ` Nathan Lynch
@ 2014-04-24 17:00     ` Stephen Boyd
  0 siblings, 0 replies; 21+ messages in thread
From: Stephen Boyd @ 2014-04-24 17:00 UTC (permalink / raw)
  To: linux-arm-kernel

On 04/23/14 19:28, Nathan Lynch wrote:
> On 04/23/2014 02:45 PM, Stephen Boyd wrote:
>> On 04/22/14 17:48, Nathan Lynch wrote:
>>> 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).
>>>
>>> Note that while the high-precision realtime and monotonic clock
>>> support depends on the generic timers extension, support for
>>> clock_getres and coarse clocks is independent of the timer
>>> implementation and is provided unconditionally.
>> I think we'll need to rename the clocksource in arch_timer.c if we only
>> have an mmio architected timer to something like arch_mem_counter.
> I guess ARMv7 would allow you to have mmio without cp15 (AFAIK ARMv8
> does not).  I don't see any dts in arch/arm that contains an
> arm,armv7-timer-mem node without an arm,armv7-timer node, though.

I only know of an ARMv7 device that is like this but the support for it
isn't in linus' tree.

> If this is a practical concern, I think using
> CONFIG_ARCH_CLOCKSOURCE_DATA is perhaps a better way to communicate
> whether cp15 access is available.  That's how the x86 vdso, for example,
> decides between using HPET vs TSC etc.
>

I don't quite follow why it's any better than changing the string
because we only really care about using cp15. If we cared about using
cp15 vs mmio it might make sense.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v6 0/6] ARM: vdso gettimeofday using generic timer architecture
  2014-04-24 16:22     ` Russell King - ARM Linux
@ 2014-04-24 18:41       ` Nathan Lynch
  2014-04-24 18:45         ` Russell King - ARM Linux
  0 siblings, 1 reply; 21+ messages in thread
From: Nathan Lynch @ 2014-04-24 18:41 UTC (permalink / raw)
  To: linux-arm-kernel

On 04/24/2014 11:22 AM, Russell King - ARM Linux wrote:
> 
> The obvious question therefore is, if the dynamic linker throws its toys
> out if it encounters a wrong-float-ABI library during a standard library
> search, why would it _not_ throw its toys out on dlsym.  The difference
> in behaviour would to me seem to be a bug - both should behave the same,
> though of course not throwing its toys out, but instead producing an error
> _or_ accepting the difference.  Given that it's an ABI difference,
> rejecting the library is the only sane approach.

The VDSO would appear to not be subject to the same validation that a
file-based DSO is.  I'll dig deeper into this to understand exactly
what's going on, but I have a guess as to why the VDSO happens to work
with armhf userspace: the calling convention is different only for
floating point arguments, and there are none in the VDSO routines.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v6 0/6] ARM: vdso gettimeofday using generic timer architecture
  2014-04-24 18:41       ` Nathan Lynch
@ 2014-04-24 18:45         ` Russell King - ARM Linux
  0 siblings, 0 replies; 21+ messages in thread
From: Russell King - ARM Linux @ 2014-04-24 18:45 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Apr 24, 2014 at 01:41:45PM -0500, Nathan Lynch wrote:
> On 04/24/2014 11:22 AM, Russell King - ARM Linux wrote:
> > 
> > The obvious question therefore is, if the dynamic linker throws its toys
> > out if it encounters a wrong-float-ABI library during a standard library
> > search, why would it _not_ throw its toys out on dlsym.  The difference
> > in behaviour would to me seem to be a bug - both should behave the same,
> > though of course not throwing its toys out, but instead producing an error
> > _or_ accepting the difference.  Given that it's an ABI difference,
> > rejecting the library is the only sane approach.
> 
> The VDSO would appear to not be subject to the same validation that a
> file-based DSO is.  I'll dig deeper into this to understand exactly
> what's going on, but I have a guess as to why the VDSO happens to work
> with armhf userspace: the calling convention is different only for
> floating point arguments, and there are none in the VDSO routines.

I don't believe the dynamic linker has the necessary information to
know whether any functions take FP arguments.  I have some armel
libraries which definitely make no use of FP, and the linker refuses
to use them with armhf.

It's something that the linker doesn't take account of either - we've
had issues in the kernel with differing float ABIs which cause hard
errors when two dissimilar objects are tried to be linked, even though
they make no use of FP.  They just seem to need to be marked differently
for stuff to complain/reject them.

-- 
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2014-04-24 18:45 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-04-23  0:48 [PATCH v6 0/6] ARM: vdso gettimeofday using generic timer architecture Nathan Lynch
2014-04-23  0:48 ` [PATCH v6 1/6] ARM: place sigpage at a random offset above stack Nathan Lynch
2014-04-23  0:48 ` [PATCH v6 2/6] ARM: allow user access to arch timer virtual counter Nathan Lynch
2014-04-23 17:32   ` Will Deacon
2014-04-23 17:41     ` Nathan Lynch
2014-04-24 10:18       ` Will Deacon
2014-04-23  0:48 ` [PATCH v6 3/6] ARM: miscellaneous vdso infrastructure, preparation Nathan Lynch
2014-04-23  0:48 ` [PATCH v6 4/6] ARM: add vdso user-space code Nathan Lynch
2014-04-23  0:48 ` [PATCH v6 5/6] ARM: vdso initialization, mapping, and synchronization Nathan Lynch
2014-04-23  0:48 ` [PATCH v6 6/6] ARM: add CONFIG_VDSO Kconfig and Makefile bits Nathan Lynch
2014-04-23 19:45 ` [PATCH v6 0/6] ARM: vdso gettimeofday using generic timer architecture Stephen Boyd
2014-04-24  2:28   ` Nathan Lynch
2014-04-24 17:00     ` Stephen Boyd
2014-04-23 21:50 ` Russell King - ARM Linux
2014-04-24  7:37   ` Ard Biesheuvel
2014-04-24 15:15     ` Nathan Lynch
2014-04-24 15:25       ` Ard Biesheuvel
2014-04-24 14:59   ` Nathan Lynch
2014-04-24 16:22     ` Russell King - ARM Linux
2014-04-24 18:41       ` Nathan Lynch
2014-04-24 18:45         ` Russell King - ARM Linux

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.