aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/Makefile8
-rw-r--r--arch/arm/include/asm/Kbuild1
-rw-r--r--arch/arm/include/asm/auxvec.h1
-rw-r--r--arch/arm/include/asm/elf.h11
-rw-r--r--arch/arm/include/asm/mmu.h3
-rw-r--r--arch/arm/include/asm/vdso.h32
-rw-r--r--arch/arm/include/asm/vdso_datapage.h60
-rw-r--r--arch/arm/include/uapi/asm/Kbuild1
-rw-r--r--arch/arm/include/uapi/asm/auxvec.h7
-rw-r--r--arch/arm/kernel/Makefile1
-rw-r--r--arch/arm/kernel/asm-offsets.c5
-rw-r--r--arch/arm/kernel/process.c16
-rw-r--r--arch/arm/kernel/setup.c5
-rw-r--r--arch/arm/kernel/vdso.c337
-rw-r--r--arch/arm/mach-vexpress/Kconfig1
-rw-r--r--arch/arm/mm/Kconfig16
-rw-r--r--arch/arm/mm/cache-l2x0.c33
-rw-r--r--arch/arm/mm/dma-mapping.c29
-rw-r--r--arch/arm/mm/fault.c1
-rw-r--r--arch/arm/mm/pageattr.c5
-rw-r--r--arch/arm/mm/proc-arm940.S26
-rw-r--r--arch/arm/mm/proc-arm946.S22
-rw-r--r--arch/arm/mm/proc-macros.S24
-rw-r--r--arch/arm/vdso/.gitignore1
-rw-r--r--arch/arm/vdso/Makefile74
-rw-r--r--arch/arm/vdso/datapage.S15
-rw-r--r--arch/arm/vdso/vdso.S35
-rw-r--r--arch/arm/vdso/vdso.lds.S87
-rw-r--r--arch/arm/vdso/vdsomunge.c201
-rw-r--r--arch/arm/vdso/vgettimeofday.c282
30 files changed, 1271 insertions, 69 deletions
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 7d980706bfb4..e9d1fd6067c6 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -263,6 +263,7 @@ core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_OBJ)
263core-$(CONFIG_VFP) += arch/arm/vfp/ 263core-$(CONFIG_VFP) += arch/arm/vfp/
264core-$(CONFIG_XEN) += arch/arm/xen/ 264core-$(CONFIG_XEN) += arch/arm/xen/
265core-$(CONFIG_KVM_ARM_HOST) += arch/arm/kvm/ 265core-$(CONFIG_KVM_ARM_HOST) += arch/arm/kvm/
266core-$(CONFIG_VDSO) += arch/arm/vdso/
266 267
267# If we have a machine-specific directory, then include it in the build. 268# If we have a machine-specific directory, then include it in the build.
268core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/ 269core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
@@ -320,6 +321,12 @@ dtbs: prepare scripts
320dtbs_install: 321dtbs_install:
321 $(Q)$(MAKE) $(dtbinst)=$(boot)/dts 322 $(Q)$(MAKE) $(dtbinst)=$(boot)/dts
322 323
324PHONY += vdso_install
325vdso_install:
326ifeq ($(CONFIG_VDSO),y)
327 $(Q)$(MAKE) $(build)=arch/arm/vdso $@
328endif
329
323# We use MRPROPER_FILES and CLEAN_FILES now 330# We use MRPROPER_FILES and CLEAN_FILES now
324archclean: 331archclean:
325 $(Q)$(MAKE) $(clean)=$(boot) 332 $(Q)$(MAKE) $(clean)=$(boot)
@@ -344,4 +351,5 @@ define archhelp
344 echo ' Install using (your) ~/bin/$(INSTALLKERNEL) or' 351 echo ' Install using (your) ~/bin/$(INSTALLKERNEL) or'
345 echo ' (distribution) /sbin/$(INSTALLKERNEL) or' 352 echo ' (distribution) /sbin/$(INSTALLKERNEL) or'
346 echo ' install to $$(INSTALL_PATH) and run lilo' 353 echo ' install to $$(INSTALL_PATH) and run lilo'
354 echo ' vdso_install - Install unstripped vdso.so to $$(INSTALL_MOD_PATH)/vdso'
347endef 355endef
diff --git a/arch/arm/include/asm/Kbuild b/arch/arm/include/asm/Kbuild
index fe74c0d1e485..eb0f43f3e3f1 100644
--- a/arch/arm/include/asm/Kbuild
+++ b/arch/arm/include/asm/Kbuild
@@ -1,6 +1,5 @@
1 1
2 2
3generic-y += auxvec.h
4generic-y += bitsperlong.h 3generic-y += bitsperlong.h
5generic-y += cputime.h 4generic-y += cputime.h
6generic-y += current.h 5generic-y += current.h
diff --git a/arch/arm/include/asm/auxvec.h b/arch/arm/include/asm/auxvec.h
new file mode 100644
index 000000000000..fbd388c46299
--- /dev/null
+++ b/arch/arm/include/asm/auxvec.h
@@ -0,0 +1 @@
#include <uapi/asm/auxvec.h>
diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h
index afb9cafd3786..e2f4781630f6 100644
--- a/arch/arm/include/asm/elf.h
+++ b/arch/arm/include/asm/elf.h
@@ -1,7 +1,9 @@
1#ifndef __ASMARM_ELF_H 1#ifndef __ASMARM_ELF_H
2#define __ASMARM_ELF_H 2#define __ASMARM_ELF_H
3 3
4#include <asm/auxvec.h>
4#include <asm/hwcap.h> 5#include <asm/hwcap.h>
6#include <asm/vdso_datapage.h>
5 7
6/* 8/*
7 * ELF register definitions.. 9 * ELF register definitions..
@@ -115,7 +117,7 @@ int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs);
115 the loader. We need to make sure that it is out of the way of the program 117 the loader. We need to make sure that it is out of the way of the program
116 that it will "exec", and that there is sufficient room for the brk. */ 118 that it will "exec", and that there is sufficient room for the brk. */
117 119
118#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) 120#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2)
119 121
120/* When the program starts, a1 contains a pointer to a function to be 122/* When the program starts, a1 contains a pointer to a function to be
121 registered with atexit, as per the SVR4 ABI. A value of 0 means we 123 registered with atexit, as per the SVR4 ABI. A value of 0 means we
@@ -130,6 +132,13 @@ extern unsigned long arch_randomize_brk(struct mm_struct *mm);
130#define arch_randomize_brk arch_randomize_brk 132#define arch_randomize_brk arch_randomize_brk
131 133
132#ifdef CONFIG_MMU 134#ifdef CONFIG_MMU
135#ifdef CONFIG_VDSO
136#define ARCH_DLINFO \
137do { \
138 NEW_AUX_ENT(AT_SYSINFO_EHDR, \
139 (elf_addr_t)current->mm->context.vdso); \
140} while (0)
141#endif
133#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1 142#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
134struct linux_binprm; 143struct linux_binprm;
135int arch_setup_additional_pages(struct linux_binprm *, int); 144int 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 {
11#endif 11#endif
12 unsigned int vmalloc_seq; 12 unsigned int vmalloc_seq;
13 unsigned long sigpage; 13 unsigned long sigpage;
14#ifdef CONFIG_VDSO
15 unsigned long vdso;
16#endif
14} mm_context_t; 17} mm_context_t;
15 18
16#ifdef CONFIG_CPU_HAS_ASID 19#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..d0295f1dd1a3
--- /dev/null
+++ b/arch/arm/include/asm/vdso.h
@@ -0,0 +1,32 @@
1#ifndef __ASM_VDSO_H
2#define __ASM_VDSO_H
3
4#ifdef __KERNEL__
5
6#ifndef __ASSEMBLY__
7
8struct mm_struct;
9
10#ifdef CONFIG_VDSO
11
12void arm_install_vdso(struct mm_struct *mm, unsigned long addr);
13
14extern char vdso_start, vdso_end;
15
16extern unsigned int vdso_total_pages;
17
18#else /* CONFIG_VDSO */
19
20static inline void arm_install_vdso(struct mm_struct *mm, unsigned long addr)
21{
22}
23
24#define vdso_total_pages 0
25
26#endif /* CONFIG_VDSO */
27
28#endif /* __ASSEMBLY__ */
29
30#endif /* __KERNEL__ */
31
32#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..9be259442fca
--- /dev/null
+++ b/arch/arm/include/asm/vdso_datapage.h
@@ -0,0 +1,60 @@
1/*
2 * Adapted from arm64 version.
3 *
4 * Copyright (C) 2012 ARM Limited
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18#ifndef __ASM_VDSO_DATAPAGE_H
19#define __ASM_VDSO_DATAPAGE_H
20
21#ifdef __KERNEL__
22
23#ifndef __ASSEMBLY__
24
25#include <asm/page.h>
26
27/* Try to be cache-friendly on systems that don't implement the
28 * generic timer: fit the unconditionally updated fields in the first
29 * 32 bytes.
30 */
31struct vdso_data {
32 u32 seq_count; /* sequence count - odd during updates */
33 u16 tk_is_cntvct; /* fall back to syscall if false */
34 u16 cs_shift; /* clocksource shift */
35 u32 xtime_coarse_sec; /* coarse time */
36 u32 xtime_coarse_nsec;
37
38 u32 wtm_clock_sec; /* wall to monotonic offset */
39 u32 wtm_clock_nsec;
40 u32 xtime_clock_sec; /* CLOCK_REALTIME - seconds */
41 u32 cs_mult; /* clocksource multiplier */
42
43 u64 cs_cycle_last; /* last cycle value */
44 u64 cs_mask; /* clocksource mask */
45
46 u64 xtime_clock_snsec; /* CLOCK_REALTIME sub-ns base */
47 u32 tz_minuteswest; /* timezone info for gettimeofday(2) */
48 u32 tz_dsttime;
49};
50
51union vdso_data_store {
52 struct vdso_data data;
53 u8 page[PAGE_SIZE];
54};
55
56#endif /* !__ASSEMBLY__ */
57
58#endif /* __KERNEL__ */
59
60#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 @@
1# UAPI Header export list 1# UAPI Header export list
2include include/uapi/asm-generic/Kbuild.asm 2include include/uapi/asm-generic/Kbuild.asm
3 3
4header-y += auxvec.h
4header-y += byteorder.h 5header-y += byteorder.h
5header-y += fcntl.h 6header-y += fcntl.h
6header-y += hwcap.h 7header-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..cb02a767a500
--- /dev/null
+++ b/arch/arm/include/uapi/asm/auxvec.h
@@ -0,0 +1,7 @@
1#ifndef __ASM_AUXVEC_H
2#define __ASM_AUXVEC_H
3
4/* VDSO location */
5#define AT_SYSINFO_EHDR 33
6
7#endif
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index b6544abe2f5e..ba5f83226011 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -75,6 +75,7 @@ obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o perf_event_cpu.o
75CFLAGS_pj4-cp0.o := -marm 75CFLAGS_pj4-cp0.o := -marm
76AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt 76AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt
77obj-$(CONFIG_ARM_CPU_TOPOLOGY) += topology.o 77obj-$(CONFIG_ARM_CPU_TOPOLOGY) += topology.o
78obj-$(CONFIG_VDSO) += vdso.o
78 79
79ifneq ($(CONFIG_ARCH_EBSA110),y) 80ifneq ($(CONFIG_ARCH_EBSA110),y)
80 obj-y += io.o 81 obj-y += io.o
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
index 2d2d6087b9b1..9147008f0d51 100644
--- a/arch/arm/kernel/asm-offsets.c
+++ b/arch/arm/kernel/asm-offsets.c
@@ -25,6 +25,7 @@
25#include <asm/memory.h> 25#include <asm/memory.h>
26#include <asm/procinfo.h> 26#include <asm/procinfo.h>
27#include <asm/suspend.h> 27#include <asm/suspend.h>
28#include <asm/vdso_datapage.h>
28#include <asm/hardware/cache-l2x0.h> 29#include <asm/hardware/cache-l2x0.h>
29#include <linux/kbuild.h> 30#include <linux/kbuild.h>
30 31
@@ -210,5 +211,9 @@ int main(void)
210#endif 211#endif
211 DEFINE(KVM_VTTBR, offsetof(struct kvm, arch.vttbr)); 212 DEFINE(KVM_VTTBR, offsetof(struct kvm, arch.vttbr));
212#endif 213#endif
214 BLANK();
215#ifdef CONFIG_VDSO
216 DEFINE(VDSO_DATA_SIZE, sizeof(union vdso_data_store));
217#endif
213 return 0; 218 return 0;
214} 219}
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index f810a6cc3790..f192a2a41719 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -334,7 +334,7 @@ const char *arch_vma_name(struct vm_area_struct *vma)
334} 334}
335 335
336/* If possible, provide a placement hint at a random offset from the 336/* If possible, provide a placement hint at a random offset from the
337 * stack for the signal page. 337 * stack for the sigpage and vdso pages.
338 */ 338 */
339static unsigned long sigpage_addr(const struct mm_struct *mm, 339static unsigned long sigpage_addr(const struct mm_struct *mm,
340 unsigned int npages) 340 unsigned int npages)
@@ -378,6 +378,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
378{ 378{
379 struct mm_struct *mm = current->mm; 379 struct mm_struct *mm = current->mm;
380 struct vm_area_struct *vma; 380 struct vm_area_struct *vma;
381 unsigned long npages;
381 unsigned long addr; 382 unsigned long addr;
382 unsigned long hint; 383 unsigned long hint;
383 int ret = 0; 384 int ret = 0;
@@ -387,9 +388,12 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
387 if (!signal_page) 388 if (!signal_page)
388 return -ENOMEM; 389 return -ENOMEM;
389 390
391 npages = 1; /* for sigpage */
392 npages += vdso_total_pages;
393
390 down_write(&mm->mmap_sem); 394 down_write(&mm->mmap_sem);
391 hint = sigpage_addr(mm, 1); 395 hint = sigpage_addr(mm, npages);
392 addr = get_unmapped_area(NULL, hint, PAGE_SIZE, 0, 0); 396 addr = get_unmapped_area(NULL, hint, npages << PAGE_SHIFT, 0, 0);
393 if (IS_ERR_VALUE(addr)) { 397 if (IS_ERR_VALUE(addr)) {
394 ret = addr; 398 ret = addr;
395 goto up_fail; 399 goto up_fail;
@@ -406,6 +410,12 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
406 410
407 mm->context.sigpage = addr; 411 mm->context.sigpage = addr;
408 412
413 /* Unlike the sigpage, failure to install the vdso is unlikely
414 * to be fatal to the process, so no error check needed
415 * here.
416 */
417 arm_install_vdso(mm, addr + PAGE_SIZE);
418
409 up_fail: 419 up_fail:
410 up_write(&mm->mmap_sem); 420 up_write(&mm->mmap_sem);
411 return ret; 421 return ret;
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 910bb1796946..6c777e908a24 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -246,12 +246,9 @@ static int __get_cpu_architecture(void)
246 if (cpu_arch) 246 if (cpu_arch)
247 cpu_arch += CPU_ARCH_ARMv3; 247 cpu_arch += CPU_ARCH_ARMv3;
248 } else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) { 248 } else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) {
249 unsigned int mmfr0;
250
251 /* Revised CPUID format. Read the Memory Model Feature 249 /* Revised CPUID format. Read the Memory Model Feature
252 * Register 0 and check for VMSAv7 or PMSAv7 */ 250 * Register 0 and check for VMSAv7 or PMSAv7 */
253 asm("mrc p15, 0, %0, c0, c1, 4" 251 unsigned int mmfr0 = read_cpuid_ext(CPUID_EXT_MMFR0);
254 : "=r" (mmfr0));
255 if ((mmfr0 & 0x0000000f) >= 0x00000003 || 252 if ((mmfr0 & 0x0000000f) >= 0x00000003 ||
256 (mmfr0 & 0x000000f0) >= 0x00000030) 253 (mmfr0 & 0x000000f0) >= 0x00000030)
257 cpu_arch = CPU_ARCH_ARMv7; 254 cpu_arch = CPU_ARCH_ARMv7;
diff --git a/arch/arm/kernel/vdso.c b/arch/arm/kernel/vdso.c
new file mode 100644
index 000000000000..0d31d3ccab81
--- /dev/null
+++ b/arch/arm/kernel/vdso.c
@@ -0,0 +1,337 @@
1/*
2 * Adapted from arm64 version.
3 *
4 * Copyright (C) 2012 ARM Limited
5 * Copyright (C) 2015 Mentor Graphics Corporation.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <linux/elf.h>
21#include <linux/err.h>
22#include <linux/kernel.h>
23#include <linux/mm.h>
24#include <linux/of.h>
25#include <linux/printk.h>
26#include <linux/slab.h>
27#include <linux/timekeeper_internal.h>
28#include <linux/vmalloc.h>
29#include <asm/arch_timer.h>
30#include <asm/barrier.h>
31#include <asm/cacheflush.h>
32#include <asm/page.h>
33#include <asm/vdso.h>
34#include <asm/vdso_datapage.h>
35#include <clocksource/arm_arch_timer.h>
36
37#define MAX_SYMNAME 64
38
39static struct page **vdso_text_pagelist;
40
41/* Total number of pages needed for the data and text portions of the VDSO. */
42unsigned int vdso_total_pages __read_mostly;
43
44/*
45 * The VDSO data page.
46 */
47static union vdso_data_store vdso_data_store __page_aligned_data;
48static struct vdso_data *vdso_data = &vdso_data_store.data;
49
50static struct page *vdso_data_page;
51static struct vm_special_mapping vdso_data_mapping = {
52 .name = "[vvar]",
53 .pages = &vdso_data_page,
54};
55
56static struct vm_special_mapping vdso_text_mapping = {
57 .name = "[vdso]",
58};
59
60struct elfinfo {
61 Elf32_Ehdr *hdr; /* ptr to ELF */
62 Elf32_Sym *dynsym; /* ptr to .dynsym section */
63 unsigned long dynsymsize; /* size of .dynsym section */
64 char *dynstr; /* ptr to .dynstr section */
65};
66
67/* Cached result of boot-time check for whether the arch timer exists,
68 * and if so, whether the virtual counter is useable.
69 */
70static bool cntvct_ok __read_mostly;
71
72static bool __init cntvct_functional(void)
73{
74 struct device_node *np;
75 bool ret = false;
76
77 if (!IS_ENABLED(CONFIG_ARM_ARCH_TIMER))
78 goto out;
79
80 /* The arm_arch_timer core should export
81 * arch_timer_use_virtual or similar so we don't have to do
82 * this.
83 */
84 np = of_find_compatible_node(NULL, NULL, "arm,armv7-timer");
85 if (!np)
86 goto out_put;
87
88 if (of_property_read_bool(np, "arm,cpu-registers-not-fw-configured"))
89 goto out_put;
90
91 ret = true;
92
93out_put:
94 of_node_put(np);
95out:
96 return ret;
97}
98
99static void * __init find_section(Elf32_Ehdr *ehdr, const char *name,
100 unsigned long *size)
101{
102 Elf32_Shdr *sechdrs;
103 unsigned int i;
104 char *secnames;
105
106 /* Grab section headers and strings so we can tell who is who */
107 sechdrs = (void *)ehdr + ehdr->e_shoff;
108 secnames = (void *)ehdr + sechdrs[ehdr->e_shstrndx].sh_offset;
109
110 /* Find the section they want */
111 for (i = 1; i < ehdr->e_shnum; i++) {
112 if (strcmp(secnames + sechdrs[i].sh_name, name) == 0) {
113 if (size)
114 *size = sechdrs[i].sh_size;
115 return (void *)ehdr + sechdrs[i].sh_offset;
116 }
117 }
118
119 if (size)
120 *size = 0;
121 return NULL;
122}
123
124static Elf32_Sym * __init find_symbol(struct elfinfo *lib, const char *symname)
125{
126 unsigned int i;
127
128 for (i = 0; i < (lib->dynsymsize / sizeof(Elf32_Sym)); i++) {
129 char name[MAX_SYMNAME], *c;
130
131 if (lib->dynsym[i].st_name == 0)
132 continue;
133 strlcpy(name, lib->dynstr + lib->dynsym[i].st_name,
134 MAX_SYMNAME);
135 c = strchr(name, '@');
136 if (c)
137 *c = 0;
138 if (strcmp(symname, name) == 0)
139 return &lib->dynsym[i];
140 }
141 return NULL;
142}
143
144static void __init vdso_nullpatch_one(struct elfinfo *lib, const char *symname)
145{
146 Elf32_Sym *sym;
147
148 sym = find_symbol(lib, symname);
149 if (!sym)
150 return;
151
152 sym->st_name = 0;
153}
154
155static void __init patch_vdso(void *ehdr)
156{
157 struct elfinfo einfo;
158
159 einfo = (struct elfinfo) {
160 .hdr = ehdr,
161 };
162
163 einfo.dynsym = find_section(einfo.hdr, ".dynsym", &einfo.dynsymsize);
164 einfo.dynstr = find_section(einfo.hdr, ".dynstr", NULL);
165
166 /* If the virtual counter is absent or non-functional we don't
167 * want programs to incur the slight additional overhead of
168 * dispatching through the VDSO only to fall back to syscalls.
169 */
170 if (!cntvct_ok) {
171 vdso_nullpatch_one(&einfo, "__vdso_gettimeofday");
172 vdso_nullpatch_one(&einfo, "__vdso_clock_gettime");
173 }
174}
175
176static int __init vdso_init(void)
177{
178 unsigned int text_pages;
179 int i;
180
181 if (memcmp(&vdso_start, "\177ELF", 4)) {
182 pr_err("VDSO is not a valid ELF object!\n");
183 return -ENOEXEC;
184 }
185
186 text_pages = (&vdso_end - &vdso_start) >> PAGE_SHIFT;
187 pr_debug("vdso: %i text pages at base %p\n", text_pages, &vdso_start);
188
189 /* Allocate the VDSO text pagelist */
190 vdso_text_pagelist = kcalloc(text_pages, sizeof(struct page *),
191 GFP_KERNEL);
192 if (vdso_text_pagelist == NULL)
193 return -ENOMEM;
194
195 /* Grab the VDSO data page. */
196 vdso_data_page = virt_to_page(vdso_data);
197
198 /* Grab the VDSO text pages. */
199 for (i = 0; i < text_pages; i++) {
200 struct page *page;
201
202 page = virt_to_page(&vdso_start + i * PAGE_SIZE);
203 vdso_text_pagelist[i] = page;
204 }
205
206 vdso_text_mapping.pages = vdso_text_pagelist;
207
208 vdso_total_pages = 1; /* for the data/vvar page */
209 vdso_total_pages += text_pages;
210
211 cntvct_ok = cntvct_functional();
212
213 patch_vdso(&vdso_start);
214
215 return 0;
216}
217arch_initcall(vdso_init);
218
219static int install_vvar(struct mm_struct *mm, unsigned long addr)
220{
221 struct vm_area_struct *vma;
222
223 vma = _install_special_mapping(mm, addr, PAGE_SIZE,
224 VM_READ | VM_MAYREAD,
225 &vdso_data_mapping);
226
227 return IS_ERR(vma) ? PTR_ERR(vma) : 0;
228}
229
230/* assumes mmap_sem is write-locked */
231void arm_install_vdso(struct mm_struct *mm, unsigned long addr)
232{
233 struct vm_area_struct *vma;
234 unsigned long len;
235
236 mm->context.vdso = 0;
237
238 if (vdso_text_pagelist == NULL)
239 return;
240
241 if (install_vvar(mm, addr))
242 return;
243
244 /* Account for vvar page. */
245 addr += PAGE_SIZE;
246 len = (vdso_total_pages - 1) << PAGE_SHIFT;
247
248 vma = _install_special_mapping(mm, addr, len,
249 VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
250 &vdso_text_mapping);
251
252 if (!IS_ERR(vma))
253 mm->context.vdso = addr;
254}
255
256static void vdso_write_begin(struct vdso_data *vdata)
257{
258 ++vdso_data->seq_count;
259 smp_wmb(); /* Pairs with smp_rmb in vdso_read_retry */
260}
261
262static void vdso_write_end(struct vdso_data *vdata)
263{
264 smp_wmb(); /* Pairs with smp_rmb in vdso_read_begin */
265 ++vdso_data->seq_count;
266}
267
268static bool tk_is_cntvct(const struct timekeeper *tk)
269{
270 if (!IS_ENABLED(CONFIG_ARM_ARCH_TIMER))
271 return false;
272
273 if (strcmp(tk->tkr.clock->name, "arch_sys_counter") != 0)
274 return false;
275
276 return true;
277}
278
279/**
280 * update_vsyscall - update the vdso data page
281 *
282 * Increment the sequence counter, making it odd, indicating to
283 * userspace that an update is in progress. Update the fields used
284 * for coarse clocks and, if the architected system timer is in use,
285 * the fields used for high precision clocks. Increment the sequence
286 * counter again, making it even, indicating to userspace that the
287 * update is finished.
288 *
289 * Userspace is expected to sample seq_count before reading any other
290 * fields from the data page. If seq_count is odd, userspace is
291 * expected to wait until it becomes even. After copying data from
292 * the page, userspace must sample seq_count again; if it has changed
293 * from its previous value, userspace must retry the whole sequence.
294 *
295 * Calls to update_vsyscall are serialized by the timekeeping core.
296 */
297void update_vsyscall(struct timekeeper *tk)
298{
299 struct timespec xtime_coarse;
300 struct timespec64 *wtm = &tk->wall_to_monotonic;
301
302 if (!cntvct_ok) {
303 /* The entry points have been zeroed, so there is no
304 * point in updating the data page.
305 */
306 return;
307 }
308
309 vdso_write_begin(vdso_data);
310
311 xtime_coarse = __current_kernel_time();
312 vdso_data->tk_is_cntvct = tk_is_cntvct(tk);
313 vdso_data->xtime_coarse_sec = xtime_coarse.tv_sec;
314 vdso_data->xtime_coarse_nsec = xtime_coarse.tv_nsec;
315 vdso_data->wtm_clock_sec = wtm->tv_sec;
316 vdso_data->wtm_clock_nsec = wtm->tv_nsec;
317
318 if (vdso_data->tk_is_cntvct) {
319 vdso_data->cs_cycle_last = tk->tkr.cycle_last;
320 vdso_data->xtime_clock_sec = tk->xtime_sec;
321 vdso_data->xtime_clock_snsec = tk->tkr.xtime_nsec;
322 vdso_data->cs_mult = tk->tkr.mult;
323 vdso_data->cs_shift = tk->tkr.shift;
324 vdso_data->cs_mask = tk->tkr.mask;
325 }
326
327 vdso_write_end(vdso_data);
328
329 flush_dcache_page(virt_to_page(vdso_data));
330}
331
332void update_vsyscall_tz(void)
333{
334 vdso_data->tz_minuteswest = sys_tz.tz_minuteswest;
335 vdso_data->tz_dsttime = sys_tz.tz_dsttime;
336 flush_dcache_page(virt_to_page(vdso_data));
337}
diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig
index 3c2509b4b694..4be537977040 100644
--- a/arch/arm/mach-vexpress/Kconfig
+++ b/arch/arm/mach-vexpress/Kconfig
@@ -42,6 +42,7 @@ if ARCH_VEXPRESS
42config ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA 42config ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA
43 bool "Enable A5 and A9 only errata work-arounds" 43 bool "Enable A5 and A9 only errata work-arounds"
44 default y 44 default y
45 select ARM_ERRATA_643719 if SMP
45 select ARM_ERRATA_720789 46 select ARM_ERRATA_720789
46 select PL310_ERRATA_753970 if CACHE_L2X0 47 select PL310_ERRATA_753970 if CACHE_L2X0
47 help 48 help
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 9b4f29e595a4..b7644310236b 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -738,7 +738,7 @@ config CPU_ICACHE_DISABLE
738 738
739config CPU_DCACHE_DISABLE 739config CPU_DCACHE_DISABLE
740 bool "Disable D-Cache (C-bit)" 740 bool "Disable D-Cache (C-bit)"
741 depends on CPU_CP15 741 depends on CPU_CP15 && !SMP
742 help 742 help
743 Say Y here to disable the processor data cache. Unless 743 Say Y here to disable the processor data cache. Unless
744 you have a reason not to or are unsure, say N. 744 you have a reason not to or are unsure, say N.
@@ -825,6 +825,20 @@ config KUSER_HELPERS
825 Say N here only if you are absolutely certain that you do not 825 Say N here only if you are absolutely certain that you do not
826 need these helpers; otherwise, the safe option is to say Y. 826 need these helpers; otherwise, the safe option is to say Y.
827 827
828config VDSO
829 bool "Enable VDSO for acceleration of some system calls"
830 depends on AEABI && MMU
831 default y if ARM_ARCH_TIMER
832 select GENERIC_TIME_VSYSCALL
833 help
834 Place in the process address space an ELF shared object
835 providing fast implementations of gettimeofday and
836 clock_gettime. Systems that implement the ARM architected
837 timer will receive maximum benefit.
838
839 You must have glibc 2.22 or later for programs to seamlessly
840 take advantage of this.
841
828config DMA_CACHE_RWFO 842config DMA_CACHE_RWFO
829 bool "Enable read/write for ownership DMA cache maintenance" 843 bool "Enable read/write for ownership DMA cache maintenance"
830 depends on CPU_V6K && SMP 844 depends on CPU_V6K && SMP
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 8b933dc43e24..e309c8f35af5 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -1131,23 +1131,22 @@ static void __init l2c310_of_parse(const struct device_node *np,
1131 } 1131 }
1132 1132
1133 ret = l2x0_cache_size_of_parse(np, aux_val, aux_mask, &assoc, SZ_512K); 1133 ret = l2x0_cache_size_of_parse(np, aux_val, aux_mask, &assoc, SZ_512K);
1134 if (ret) 1134 if (!ret) {
1135 return; 1135 switch (assoc) {
1136 1136 case 16:
1137 switch (assoc) { 1137 *aux_val &= ~L2X0_AUX_CTRL_ASSOC_MASK;
1138 case 16: 1138 *aux_val |= L310_AUX_CTRL_ASSOCIATIVITY_16;
1139 *aux_val &= ~L2X0_AUX_CTRL_ASSOC_MASK; 1139 *aux_mask &= ~L2X0_AUX_CTRL_ASSOC_MASK;
1140 *aux_val |= L310_AUX_CTRL_ASSOCIATIVITY_16; 1140 break;
1141 *aux_mask &= ~L2X0_AUX_CTRL_ASSOC_MASK; 1141 case 8:
1142 break; 1142 *aux_val &= ~L2X0_AUX_CTRL_ASSOC_MASK;
1143 case 8: 1143 *aux_mask &= ~L2X0_AUX_CTRL_ASSOC_MASK;
1144 *aux_val &= ~L2X0_AUX_CTRL_ASSOC_MASK; 1144 break;
1145 *aux_mask &= ~L2X0_AUX_CTRL_ASSOC_MASK; 1145 default:
1146 break; 1146 pr_err("L2C-310 OF cache associativity %d invalid, only 8 or 16 permitted\n",
1147 default: 1147 assoc);
1148 pr_err("L2C-310 OF cache associativity %d invalid, only 8 or 16 permitted\n", 1148 break;
1149 assoc); 1149 }
1150 break;
1151 } 1150 }
1152 1151
1153 prefetch = l2x0_saved_regs.prefetch_ctrl; 1152 prefetch = l2x0_saved_regs.prefetch_ctrl;
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index b8fe72080108..3866f81c70bc 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -171,7 +171,7 @@ static int __dma_supported(struct device *dev, u64 mask, bool warn)
171 */ 171 */
172 if (sizeof(mask) != sizeof(dma_addr_t) && 172 if (sizeof(mask) != sizeof(dma_addr_t) &&
173 mask > (dma_addr_t)~0 && 173 mask > (dma_addr_t)~0 &&
174 dma_to_pfn(dev, ~0) < max_pfn) { 174 dma_to_pfn(dev, ~0) < max_pfn - 1) {
175 if (warn) { 175 if (warn) {
176 dev_warn(dev, "Coherent DMA mask %#llx is larger than dma_addr_t allows\n", 176 dev_warn(dev, "Coherent DMA mask %#llx is larger than dma_addr_t allows\n",
177 mask); 177 mask);
@@ -1150,13 +1150,28 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size,
1150 gfp |= __GFP_NOWARN | __GFP_HIGHMEM; 1150 gfp |= __GFP_NOWARN | __GFP_HIGHMEM;
1151 1151
1152 while (count) { 1152 while (count) {
1153 int j, order = __fls(count); 1153 int j, order;
1154
1155 for (order = __fls(count); order > 0; --order) {
1156 /*
1157 * We do not want OOM killer to be invoked as long
1158 * as we can fall back to single pages, so we force
1159 * __GFP_NORETRY for orders higher than zero.
1160 */
1161 pages[i] = alloc_pages(gfp | __GFP_NORETRY, order);
1162 if (pages[i])
1163 break;
1164 }
1154 1165
1155 pages[i] = alloc_pages(gfp, order); 1166 if (!pages[i]) {
1156 while (!pages[i] && order) 1167 /*
1157 pages[i] = alloc_pages(gfp, --order); 1168 * Fall back to single page allocation.
1158 if (!pages[i]) 1169 * Might invoke OOM killer as last resort.
1159 goto error; 1170 */
1171 pages[i] = alloc_pages(gfp, 0);
1172 if (!pages[i])
1173 goto error;
1174 }
1160 1175
1161 if (order) { 1176 if (order) {
1162 split_page(pages[i], order); 1177 split_page(pages[i], order);
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index a982dc3190df..6333d9c17875 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -552,6 +552,7 @@ do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
552 552
553 pr_alert("Unhandled fault: %s (0x%03x) at 0x%08lx\n", 553 pr_alert("Unhandled fault: %s (0x%03x) at 0x%08lx\n",
554 inf->name, fsr, addr); 554 inf->name, fsr, addr);
555 show_pte(current->mm, addr);
555 556
556 info.si_signo = inf->sig; 557 info.si_signo = inf->sig;
557 info.si_errno = 0; 558 info.si_errno = 0;
diff --git a/arch/arm/mm/pageattr.c b/arch/arm/mm/pageattr.c
index 004e35cdcfff..cf30daff8932 100644
--- a/arch/arm/mm/pageattr.c
+++ b/arch/arm/mm/pageattr.c
@@ -49,7 +49,10 @@ static int change_memory_common(unsigned long addr, int numpages,
49 WARN_ON_ONCE(1); 49 WARN_ON_ONCE(1);
50 } 50 }
51 51
52 if (!is_module_address(start) || !is_module_address(end - 1)) 52 if (start < MODULES_VADDR || start >= MODULES_END)
53 return -EINVAL;
54
55 if (end < MODULES_VADDR || start >= MODULES_END)
53 return -EINVAL; 56 return -EINVAL;
54 57
55 data.set_mask = set_mask; 58 data.set_mask = set_mask;
diff --git a/arch/arm/mm/proc-arm940.S b/arch/arm/mm/proc-arm940.S
index 0a0b7a9167b6..ee5b66f847c4 100644
--- a/arch/arm/mm/proc-arm940.S
+++ b/arch/arm/mm/proc-arm940.S
@@ -297,26 +297,16 @@ __arm940_setup:
297 mcr p15, 0, r0, c6, c0, 1 297 mcr p15, 0, r0, c6, c0, 1
298 298
299 ldr r0, =(CONFIG_DRAM_BASE & 0xFFFFF000) @ base[31:12] of RAM 299 ldr r0, =(CONFIG_DRAM_BASE & 0xFFFFF000) @ base[31:12] of RAM
300 ldr r1, =(CONFIG_DRAM_SIZE >> 12) @ size of RAM (must be >= 4KB) 300 ldr r7, =CONFIG_DRAM_SIZE >> 12 @ size of RAM (must be >= 4KB)
301 mov r2, #10 @ 11 is the minimum (4KB) 301 pr_val r3, r0, r7, #1
3021: add r2, r2, #1 @ area size *= 2 302 mcr p15, 0, r3, c6, c1, 0 @ set area 1, RAM
303 mov r1, r1, lsr #1 303 mcr p15, 0, r3, c6, c1, 1
304 bne 1b @ count not zero r-shift
305 orr r0, r0, r2, lsl #1 @ the area register value
306 orr r0, r0, #1 @ set enable bit
307 mcr p15, 0, r0, c6, c1, 0 @ set area 1, RAM
308 mcr p15, 0, r0, c6, c1, 1
309 304
310 ldr r0, =(CONFIG_FLASH_MEM_BASE & 0xFFFFF000) @ base[31:12] of FLASH 305 ldr r0, =(CONFIG_FLASH_MEM_BASE & 0xFFFFF000) @ base[31:12] of FLASH
311 ldr r1, =(CONFIG_FLASH_SIZE >> 12) @ size of FLASH (must be >= 4KB) 306 ldr r7, =CONFIG_FLASH_SIZE @ size of FLASH (must be >= 4KB)
312 mov r2, #10 @ 11 is the minimum (4KB) 307 pr_val r3, r0, r6, #1
3131: add r2, r2, #1 @ area size *= 2 308 mcr p15, 0, r3, c6, c2, 0 @ set area 2, ROM/FLASH
314 mov r1, r1, lsr #1 309 mcr p15, 0, r3, c6, c2, 1
315 bne 1b @ count not zero r-shift
316 orr r0, r0, r2, lsl #1 @ the area register value
317 orr r0, r0, #1 @ set enable bit
318 mcr p15, 0, r0, c6, c2, 0 @ set area 2, ROM/FLASH
319 mcr p15, 0, r0, c6, c2, 1
320 310
321 mov r0, #0x06 311 mov r0, #0x06
322 mcr p15, 0, r0, c2, c0, 0 @ Region 1&2 cacheable 312 mcr p15, 0, r0, c2, c0, 0 @ Region 1&2 cacheable
diff --git a/arch/arm/mm/proc-arm946.S b/arch/arm/mm/proc-arm946.S
index c85b40d2117e..7361837edc31 100644
--- a/arch/arm/mm/proc-arm946.S
+++ b/arch/arm/mm/proc-arm946.S
@@ -343,24 +343,14 @@ __arm946_setup:
343 mcr p15, 0, r0, c6, c0, 0 @ set region 0, default 343 mcr p15, 0, r0, c6, c0, 0 @ set region 0, default
344 344
345 ldr r0, =(CONFIG_DRAM_BASE & 0xFFFFF000) @ base[31:12] of RAM 345 ldr r0, =(CONFIG_DRAM_BASE & 0xFFFFF000) @ base[31:12] of RAM
346 ldr r1, =(CONFIG_DRAM_SIZE >> 12) @ size of RAM (must be >= 4KB) 346 ldr r7, =CONFIG_DRAM_SIZE @ size of RAM (must be >= 4KB)
347 mov r2, #10 @ 11 is the minimum (4KB) 347 pr_val r3, r0, r7, #1
3481: add r2, r2, #1 @ area size *= 2 348 mcr p15, 0, r3, c6, c1, 0
349 mov r1, r1, lsr #1
350 bne 1b @ count not zero r-shift
351 orr r0, r0, r2, lsl #1 @ the region register value
352 orr r0, r0, #1 @ set enable bit
353 mcr p15, 0, r0, c6, c1, 0 @ set region 1, RAM
354 349
355 ldr r0, =(CONFIG_FLASH_MEM_BASE & 0xFFFFF000) @ base[31:12] of FLASH 350 ldr r0, =(CONFIG_FLASH_MEM_BASE & 0xFFFFF000) @ base[31:12] of FLASH
356 ldr r1, =(CONFIG_FLASH_SIZE >> 12) @ size of FLASH (must be >= 4KB) 351 ldr r7, =CONFIG_FLASH_SIZE @ size of FLASH (must be >= 4KB)
357 mov r2, #10 @ 11 is the minimum (4KB) 352 pr_val r3, r0, r7, #1
3581: add r2, r2, #1 @ area size *= 2 353 mcr p15, 0, r3, c6, c2, 0
359 mov r1, r1, lsr #1
360 bne 1b @ count not zero r-shift
361 orr r0, r0, r2, lsl #1 @ the region register value
362 orr r0, r0, #1 @ set enable bit
363 mcr p15, 0, r0, c6, c2, 0 @ set region 2, ROM/FLASH
364 354
365 mov r0, #0x06 355 mov r0, #0x06
366 mcr p15, 0, r0, c2, c0, 0 @ region 1,2 d-cacheable 356 mcr p15, 0, r0, c2, c0, 0 @ region 1,2 d-cacheable
diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S
index 0f13b5f9281e..c671f345266a 100644
--- a/arch/arm/mm/proc-macros.S
+++ b/arch/arm/mm/proc-macros.S
@@ -335,3 +335,27 @@ ENTRY(\name\()_tlb_fns)
335.macro initfn, func, base 335.macro initfn, func, base
336 .long \func - \base 336 .long \func - \base
337.endm 337.endm
338
339 /*
340 * Macro to calculate the log2 size for the protection region
341 * registers. This calculates rd = log2(size) - 1. tmp must
342 * not be the same register as rd.
343 */
344.macro pr_sz, rd, size, tmp
345 mov \tmp, \size, lsr #12
346 mov \rd, #11
3471: movs \tmp, \tmp, lsr #1
348 addne \rd, \rd, #1
349 bne 1b
350.endm
351
352 /*
353 * Macro to generate a protection region register value
354 * given a pre-masked address, size, and enable bit.
355 * Corrupts size.
356 */
357.macro pr_val, dest, addr, size, enable
358 pr_sz \dest, \size, \size @ calculate log2(size) - 1
359 orr \dest, \addr, \dest, lsl #1 @ mask in the region size
360 orr \dest, \dest, \enable
361.endm
diff --git a/arch/arm/vdso/.gitignore b/arch/arm/vdso/.gitignore
new file mode 100644
index 000000000000..f8b69d84238e
--- /dev/null
+++ b/arch/arm/vdso/.gitignore
@@ -0,0 +1 @@
vdso.lds
diff --git a/arch/arm/vdso/Makefile b/arch/arm/vdso/Makefile
new file mode 100644
index 000000000000..bab0a8be7924
--- /dev/null
+++ b/arch/arm/vdso/Makefile
@@ -0,0 +1,74 @@
1hostprogs-y := vdsomunge
2
3obj-vdso := vgettimeofday.o datapage.o
4
5# Build rules
6targets := $(obj-vdso) vdso.so vdso.so.dbg vdso.so.raw vdso.lds
7obj-vdso := $(addprefix $(obj)/, $(obj-vdso))
8
9ccflags-y := -shared -fPIC -fno-common -fno-builtin -fno-stack-protector
10ccflags-y += -nostdlib -Wl,-soname=linux-vdso.so.1 -DDISABLE_BRANCH_PROFILING
11ccflags-y += -Wl,--no-undefined $(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
12
13obj-y += vdso.o
14extra-y += vdso.lds
15CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
16
17CFLAGS_REMOVE_vdso.o = -pg
18
19# Force -O2 to avoid libgcc dependencies
20CFLAGS_REMOVE_vgettimeofday.o = -pg -Os
21CFLAGS_vgettimeofday.o = -O2
22
23# Disable gcov profiling for VDSO code
24GCOV_PROFILE := n
25
26# Force dependency
27$(obj)/vdso.o : $(obj)/vdso.so
28
29# Link rule for the .so file
30$(obj)/vdso.so.raw: $(src)/vdso.lds $(obj-vdso) FORCE
31 $(call if_changed,vdsold)
32
33$(obj)/vdso.so.dbg: $(obj)/vdso.so.raw $(obj)/vdsomunge FORCE
34 $(call if_changed,vdsomunge)
35
36# Strip rule for the .so file
37$(obj)/%.so: OBJCOPYFLAGS := -S
38$(obj)/%.so: $(obj)/%.so.dbg FORCE
39 $(call if_changed,objcopy)
40
41# Actual build commands
42quiet_cmd_vdsold = VDSO $@
43 cmd_vdsold = $(CC) $(c_flags) -Wl,-T $(filter %.lds,$^) $(filter %.o,$^) \
44 $(call cc-ldoption, -Wl$(comma)--build-id) \
45 -Wl,-Bsymbolic -Wl,-z,max-page-size=4096 \
46 -Wl,-z,common-page-size=4096 -o $@
47
48quiet_cmd_vdsomunge = MUNGE $@
49 cmd_vdsomunge = $(objtree)/$(obj)/vdsomunge $< $@
50
51#
52# Install the unstripped copy of vdso.so.dbg. If our toolchain
53# supports build-id, install .build-id links as well.
54#
55# Cribbed from arch/x86/vdso/Makefile.
56#
57quiet_cmd_vdso_install = INSTALL $<
58define cmd_vdso_install
59 cp $< "$(MODLIB)/vdso/vdso.so"; \
60 if readelf -n $< | grep -q 'Build ID'; then \
61 buildid=`readelf -n $< |grep 'Build ID' |sed -e 's/^.*Build ID: \(.*\)$$/\1/'`; \
62 first=`echo $$buildid | cut -b-2`; \
63 last=`echo $$buildid | cut -b3-`; \
64 mkdir -p "$(MODLIB)/vdso/.build-id/$$first"; \
65 ln -sf "../../vdso.so" "$(MODLIB)/vdso/.build-id/$$first/$$last.debug"; \
66 fi
67endef
68
69$(MODLIB)/vdso: FORCE
70 @mkdir -p $(MODLIB)/vdso
71
72PHONY += vdso_install
73vdso_install: $(obj)/vdso.so.dbg $(MODLIB)/vdso FORCE
74 $(call cmd,vdso_install)
diff --git a/arch/arm/vdso/datapage.S b/arch/arm/vdso/datapage.S
new file mode 100644
index 000000000000..a2e60367931b
--- /dev/null
+++ b/arch/arm/vdso/datapage.S
@@ -0,0 +1,15 @@
1#include <linux/linkage.h>
2#include <asm/asm-offsets.h>
3
4 .align 2
5.L_vdso_data_ptr:
6 .long _start - . - VDSO_DATA_SIZE
7
8ENTRY(__get_datapage)
9 .fnstart
10 adr r0, .L_vdso_data_ptr
11 ldr r1, [r0]
12 add r0, r0, r1
13 bx lr
14 .fnend
15ENDPROC(__get_datapage)
diff --git a/arch/arm/vdso/vdso.S b/arch/arm/vdso/vdso.S
new file mode 100644
index 000000000000..b2b97e3e7bab
--- /dev/null
+++ b/arch/arm/vdso/vdso.S
@@ -0,0 +1,35 @@
1/*
2 * Adapted from arm64 version.
3 *
4 * Copyright (C) 2012 ARM Limited
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Author: Will Deacon <will.deacon@arm.com>
19 */
20
21#include <linux/init.h>
22#include <linux/linkage.h>
23#include <linux/const.h>
24#include <asm/page.h>
25
26 __PAGE_ALIGNED_DATA
27
28 .globl vdso_start, vdso_end
29 .balign PAGE_SIZE
30vdso_start:
31 .incbin "arch/arm/vdso/vdso.so"
32 .balign PAGE_SIZE
33vdso_end:
34
35 .previous
diff --git a/arch/arm/vdso/vdso.lds.S b/arch/arm/vdso/vdso.lds.S
new file mode 100644
index 000000000000..89ca89f12d23
--- /dev/null
+++ b/arch/arm/vdso/vdso.lds.S
@@ -0,0 +1,87 @@
1/*
2 * Adapted from arm64 version.
3 *
4 * GNU linker script for the VDSO library.
5 *
6 * Copyright (C) 2012 ARM Limited
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 * Author: Will Deacon <will.deacon@arm.com>
21 * Heavily based on the vDSO linker scripts for other archs.
22 */
23
24#include <linux/const.h>
25#include <asm/page.h>
26#include <asm/vdso.h>
27
28OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
29OUTPUT_ARCH(arm)
30
31SECTIONS
32{
33 PROVIDE(_start = .);
34
35 . = SIZEOF_HEADERS;
36
37 .hash : { *(.hash) } :text
38 .gnu.hash : { *(.gnu.hash) }
39 .dynsym : { *(.dynsym) }
40 .dynstr : { *(.dynstr) }
41 .gnu.version : { *(.gnu.version) }
42 .gnu.version_d : { *(.gnu.version_d) }
43 .gnu.version_r : { *(.gnu.version_r) }
44
45 .note : { *(.note.*) } :text :note
46
47
48 .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
49 .eh_frame : { KEEP (*(.eh_frame)) } :text
50
51 .dynamic : { *(.dynamic) } :text :dynamic
52
53 .rodata : { *(.rodata*) } :text
54
55 .text : { *(.text*) } :text =0xe7f001f2
56
57 .got : { *(.got) }
58 .rel.plt : { *(.rel.plt) }
59
60 /DISCARD/ : {
61 *(.note.GNU-stack)
62 *(.data .data.* .gnu.linkonce.d.* .sdata*)
63 *(.bss .sbss .dynbss .dynsbss)
64 }
65}
66
67/*
68 * We must supply the ELF program headers explicitly to get just one
69 * PT_LOAD segment, and set the flags explicitly to make segments read-only.
70 */
71PHDRS
72{
73 text PT_LOAD FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */
74 dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
75 note PT_NOTE FLAGS(4); /* PF_R */
76 eh_frame_hdr PT_GNU_EH_FRAME;
77}
78
79VERSION
80{
81 LINUX_2.6 {
82 global:
83 __vdso_clock_gettime;
84 __vdso_gettimeofday;
85 local: *;
86 };
87}
diff --git a/arch/arm/vdso/vdsomunge.c b/arch/arm/vdso/vdsomunge.c
new file mode 100644
index 000000000000..9005b07296c8
--- /dev/null
+++ b/arch/arm/vdso/vdsomunge.c
@@ -0,0 +1,201 @@
1/*
2 * Copyright 2015 Mentor Graphics Corporation.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; version 2 of the
7 * License.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 *
18 * vdsomunge - Host program which produces a shared object
19 * architecturally specified to be usable by both soft- and hard-float
20 * programs.
21 *
22 * The Procedure Call Standard for the ARM Architecture (ARM IHI
23 * 0042E) says:
24 *
25 * 6.4.1 VFP and Base Standard Compatibility
26 *
27 * Code compiled for the VFP calling standard is compatible with
28 * the base standard (and vice-versa) if no floating-point or
29 * containerized vector arguments or results are used.
30 *
31 * And ELF for the ARM Architecture (ARM IHI 0044E) (Table 4-2) says:
32 *
33 * If both EF_ARM_ABI_FLOAT_XXXX bits are clear, conformance to the
34 * base procedure-call standard is implied.
35 *
36 * The VDSO is built with -msoft-float, as with the rest of the ARM
37 * kernel, and uses no floating point arguments or results. The build
38 * process will produce a shared object that may or may not have the
39 * EF_ARM_ABI_FLOAT_SOFT flag set (it seems to depend on the binutils
40 * version; binutils starting with 2.24 appears to set it). The
41 * EF_ARM_ABI_FLOAT_HARD flag should definitely not be set, and this
42 * program will error out if it is.
43 *
44 * If the soft-float flag is set, this program clears it. That's all
45 * it does.
46 */
47
48#define _GNU_SOURCE
49
50#include <byteswap.h>
51#include <elf.h>
52#include <errno.h>
53#include <error.h>
54#include <fcntl.h>
55#include <stdbool.h>
56#include <stdio.h>
57#include <stdlib.h>
58#include <string.h>
59#include <sys/mman.h>
60#include <sys/stat.h>
61#include <sys/types.h>
62#include <unistd.h>
63
64#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
65#define HOST_ORDER ELFDATA2LSB
66#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
67#define HOST_ORDER ELFDATA2MSB
68#endif
69
70/* Some of the ELF constants we'd like to use were added to <elf.h>
71 * relatively recently.
72 */
73#ifndef EF_ARM_EABI_VER5
74#define EF_ARM_EABI_VER5 0x05000000
75#endif
76
77#ifndef EF_ARM_ABI_FLOAT_SOFT
78#define EF_ARM_ABI_FLOAT_SOFT 0x200
79#endif
80
81#ifndef EF_ARM_ABI_FLOAT_HARD
82#define EF_ARM_ABI_FLOAT_HARD 0x400
83#endif
84
85static const char *outfile;
86
87static void cleanup(void)
88{
89 if (error_message_count > 0 && outfile != NULL)
90 unlink(outfile);
91}
92
93static Elf32_Word read_elf_word(Elf32_Word word, bool swap)
94{
95 return swap ? bswap_32(word) : word;
96}
97
98static Elf32_Half read_elf_half(Elf32_Half half, bool swap)
99{
100 return swap ? bswap_16(half) : half;
101}
102
103static void write_elf_word(Elf32_Word val, Elf32_Word *dst, bool swap)
104{
105 *dst = swap ? bswap_32(val) : val;
106}
107
108int main(int argc, char **argv)
109{
110 const Elf32_Ehdr *inhdr;
111 bool clear_soft_float;
112 const char *infile;
113 Elf32_Word e_flags;
114 const void *inbuf;
115 struct stat stat;
116 void *outbuf;
117 bool swap;
118 int outfd;
119 int infd;
120
121 atexit(cleanup);
122
123 if (argc != 3)
124 error(EXIT_FAILURE, 0, "Usage: %s [infile] [outfile]", argv[0]);
125
126 infile = argv[1];
127 outfile = argv[2];
128
129 infd = open(infile, O_RDONLY);
130 if (infd < 0)
131 error(EXIT_FAILURE, errno, "Cannot open %s", infile);
132
133 if (fstat(infd, &stat) != 0)
134 error(EXIT_FAILURE, errno, "Failed stat for %s", infile);
135
136 inbuf = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, infd, 0);
137 if (inbuf == MAP_FAILED)
138 error(EXIT_FAILURE, errno, "Failed to map %s", infile);
139
140 close(infd);
141
142 inhdr = inbuf;
143
144 if (memcmp(&inhdr->e_ident, ELFMAG, SELFMAG) != 0)
145 error(EXIT_FAILURE, 0, "Not an ELF file");
146
147 if (inhdr->e_ident[EI_CLASS] != ELFCLASS32)
148 error(EXIT_FAILURE, 0, "Unsupported ELF class");
149
150 swap = inhdr->e_ident[EI_DATA] != HOST_ORDER;
151
152 if (read_elf_half(inhdr->e_type, swap) != ET_DYN)
153 error(EXIT_FAILURE, 0, "Not a shared object");
154
155 if (read_elf_half(inhdr->e_machine, swap) != EM_ARM) {
156 error(EXIT_FAILURE, 0, "Unsupported architecture %#x",
157 inhdr->e_machine);
158 }
159
160 e_flags = read_elf_word(inhdr->e_flags, swap);
161
162 if (EF_ARM_EABI_VERSION(e_flags) != EF_ARM_EABI_VER5) {
163 error(EXIT_FAILURE, 0, "Unsupported EABI version %#x",
164 EF_ARM_EABI_VERSION(e_flags));
165 }
166
167 if (e_flags & EF_ARM_ABI_FLOAT_HARD)
168 error(EXIT_FAILURE, 0,
169 "Unexpected hard-float flag set in e_flags");
170
171 clear_soft_float = !!(e_flags & EF_ARM_ABI_FLOAT_SOFT);
172
173 outfd = open(outfile, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
174 if (outfd < 0)
175 error(EXIT_FAILURE, errno, "Cannot open %s", outfile);
176
177 if (ftruncate(outfd, stat.st_size) != 0)
178 error(EXIT_FAILURE, errno, "Cannot truncate %s", outfile);
179
180 outbuf = mmap(NULL, stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED,
181 outfd, 0);
182 if (outbuf == MAP_FAILED)
183 error(EXIT_FAILURE, errno, "Failed to map %s", outfile);
184
185 close(outfd);
186
187 memcpy(outbuf, inbuf, stat.st_size);
188
189 if (clear_soft_float) {
190 Elf32_Ehdr *outhdr;
191
192 outhdr = outbuf;
193 e_flags &= ~EF_ARM_ABI_FLOAT_SOFT;
194 write_elf_word(e_flags, &outhdr->e_flags, swap);
195 }
196
197 if (msync(outbuf, stat.st_size, MS_SYNC) != 0)
198 error(EXIT_FAILURE, errno, "Failed to sync %s", outfile);
199
200 return EXIT_SUCCESS;
201}
diff --git a/arch/arm/vdso/vgettimeofday.c b/arch/arm/vdso/vgettimeofday.c
new file mode 100644
index 000000000000..79214d5ff097
--- /dev/null
+++ b/arch/arm/vdso/vgettimeofday.c
@@ -0,0 +1,282 @@
1/*
2 * Copyright 2015 Mentor Graphics Corporation.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; version 2 of the
7 * License.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include <linux/compiler.h>
19#include <linux/hrtimer.h>
20#include <linux/time.h>
21#include <asm/arch_timer.h>
22#include <asm/barrier.h>
23#include <asm/bug.h>
24#include <asm/page.h>
25#include <asm/unistd.h>
26#include <asm/vdso_datapage.h>
27
28#ifndef CONFIG_AEABI
29#error This code depends on AEABI system call conventions
30#endif
31
32extern struct vdso_data *__get_datapage(void);
33
34static notrace u32 __vdso_read_begin(const struct vdso_data *vdata)
35{
36 u32 seq;
37repeat:
38 seq = ACCESS_ONCE(vdata->seq_count);
39 if (seq & 1) {
40 cpu_relax();
41 goto repeat;
42 }
43 return seq;
44}
45
46static notrace u32 vdso_read_begin(const struct vdso_data *vdata)
47{
48 u32 seq;
49
50 seq = __vdso_read_begin(vdata);
51
52 smp_rmb(); /* Pairs with smp_wmb in vdso_write_end */
53 return seq;
54}
55
56static notrace int vdso_read_retry(const struct vdso_data *vdata, u32 start)
57{
58 smp_rmb(); /* Pairs with smp_wmb in vdso_write_begin */
59 return vdata->seq_count != start;
60}
61
62static notrace long clock_gettime_fallback(clockid_t _clkid,
63 struct timespec *_ts)
64{
65 register struct timespec *ts asm("r1") = _ts;
66 register clockid_t clkid asm("r0") = _clkid;
67 register long ret asm ("r0");
68 register long nr asm("r7") = __NR_clock_gettime;
69
70 asm volatile(
71 " swi #0\n"
72 : "=r" (ret)
73 : "r" (clkid), "r" (ts), "r" (nr)
74 : "memory");
75
76 return ret;
77}
78
79static notrace int do_realtime_coarse(struct timespec *ts,
80 struct vdso_data *vdata)
81{
82 u32 seq;
83
84 do {
85 seq = vdso_read_begin(vdata);
86
87 ts->tv_sec = vdata->xtime_coarse_sec;
88 ts->tv_nsec = vdata->xtime_coarse_nsec;
89
90 } while (vdso_read_retry(vdata, seq));
91
92 return 0;
93}
94
95static notrace int do_monotonic_coarse(struct timespec *ts,
96 struct vdso_data *vdata)
97{
98 struct timespec tomono;
99 u32 seq;
100
101 do {
102 seq = vdso_read_begin(vdata);
103
104 ts->tv_sec = vdata->xtime_coarse_sec;
105 ts->tv_nsec = vdata->xtime_coarse_nsec;
106
107 tomono.tv_sec = vdata->wtm_clock_sec;
108 tomono.tv_nsec = vdata->wtm_clock_nsec;
109
110 } while (vdso_read_retry(vdata, seq));
111
112 ts->tv_sec += tomono.tv_sec;
113 timespec_add_ns(ts, tomono.tv_nsec);
114
115 return 0;
116}
117
118#ifdef CONFIG_ARM_ARCH_TIMER
119
120static notrace u64 get_ns(struct vdso_data *vdata)
121{
122 u64 cycle_delta;
123 u64 cycle_now;
124 u64 nsec;
125
126 cycle_now = arch_counter_get_cntvct();
127
128 cycle_delta = (cycle_now - vdata->cs_cycle_last) & vdata->cs_mask;
129
130 nsec = (cycle_delta * vdata->cs_mult) + vdata->xtime_clock_snsec;
131 nsec >>= vdata->cs_shift;
132
133 return nsec;
134}
135
136static notrace int do_realtime(struct timespec *ts, struct vdso_data *vdata)
137{
138 u64 nsecs;
139 u32 seq;
140
141 do {
142 seq = vdso_read_begin(vdata);
143
144 if (!vdata->tk_is_cntvct)
145 return -1;
146
147 ts->tv_sec = vdata->xtime_clock_sec;
148 nsecs = get_ns(vdata);
149
150 } while (vdso_read_retry(vdata, seq));
151
152 ts->tv_nsec = 0;
153 timespec_add_ns(ts, nsecs);
154
155 return 0;
156}
157
158static notrace int do_monotonic(struct timespec *ts, struct vdso_data *vdata)
159{
160 struct timespec tomono;
161 u64 nsecs;
162 u32 seq;
163
164 do {
165 seq = vdso_read_begin(vdata);
166
167 if (!vdata->tk_is_cntvct)
168 return -1;
169
170 ts->tv_sec = vdata->xtime_clock_sec;
171 nsecs = get_ns(vdata);
172
173 tomono.tv_sec = vdata->wtm_clock_sec;
174 tomono.tv_nsec = vdata->wtm_clock_nsec;
175
176 } while (vdso_read_retry(vdata, seq));
177
178 ts->tv_sec += tomono.tv_sec;
179 ts->tv_nsec = 0;
180 timespec_add_ns(ts, nsecs + tomono.tv_nsec);
181
182 return 0;
183}
184
185#else /* CONFIG_ARM_ARCH_TIMER */
186
187static notrace int do_realtime(struct timespec *ts, struct vdso_data *vdata)
188{
189 return -1;
190}
191
192static notrace int do_monotonic(struct timespec *ts, struct vdso_data *vdata)
193{
194 return -1;
195}
196
197#endif /* CONFIG_ARM_ARCH_TIMER */
198
199notrace int __vdso_clock_gettime(clockid_t clkid, struct timespec *ts)
200{
201 struct vdso_data *vdata;
202 int ret = -1;
203
204 vdata = __get_datapage();
205
206 switch (clkid) {
207 case CLOCK_REALTIME_COARSE:
208 ret = do_realtime_coarse(ts, vdata);
209 break;
210 case CLOCK_MONOTONIC_COARSE:
211 ret = do_monotonic_coarse(ts, vdata);
212 break;
213 case CLOCK_REALTIME:
214 ret = do_realtime(ts, vdata);
215 break;
216 case CLOCK_MONOTONIC:
217 ret = do_monotonic(ts, vdata);
218 break;
219 default:
220 break;
221 }
222
223 if (ret)
224 ret = clock_gettime_fallback(clkid, ts);
225
226 return ret;
227}
228
229static notrace long gettimeofday_fallback(struct timeval *_tv,
230 struct timezone *_tz)
231{
232 register struct timezone *tz asm("r1") = _tz;
233 register struct timeval *tv asm("r0") = _tv;
234 register long ret asm ("r0");
235 register long nr asm("r7") = __NR_gettimeofday;
236
237 asm volatile(
238 " swi #0\n"
239 : "=r" (ret)
240 : "r" (tv), "r" (tz), "r" (nr)
241 : "memory");
242
243 return ret;
244}
245
246notrace int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
247{
248 struct timespec ts;
249 struct vdso_data *vdata;
250 int ret;
251
252 vdata = __get_datapage();
253
254 ret = do_realtime(&ts, vdata);
255 if (ret)
256 return gettimeofday_fallback(tv, tz);
257
258 if (tv) {
259 tv->tv_sec = ts.tv_sec;
260 tv->tv_usec = ts.tv_nsec / 1000;
261 }
262 if (tz) {
263 tz->tz_minuteswest = vdata->tz_minuteswest;
264 tz->tz_dsttime = vdata->tz_dsttime;
265 }
266
267 return ret;
268}
269
270/* Avoid unresolved references emitted by GCC */
271
272void __aeabi_unwind_cpp_pr0(void)
273{
274}
275
276void __aeabi_unwind_cpp_pr1(void)
277{
278}
279
280void __aeabi_unwind_cpp_pr2(void)
281{
282}