diff options
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) | |||
263 | core-$(CONFIG_VFP) += arch/arm/vfp/ | 263 | core-$(CONFIG_VFP) += arch/arm/vfp/ |
264 | core-$(CONFIG_XEN) += arch/arm/xen/ | 264 | core-$(CONFIG_XEN) += arch/arm/xen/ |
265 | core-$(CONFIG_KVM_ARM_HOST) += arch/arm/kvm/ | 265 | core-$(CONFIG_KVM_ARM_HOST) += arch/arm/kvm/ |
266 | core-$(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. |
268 | core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/ | 269 | core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/ |
@@ -320,6 +321,12 @@ dtbs: prepare scripts | |||
320 | dtbs_install: | 321 | dtbs_install: |
321 | $(Q)$(MAKE) $(dtbinst)=$(boot)/dts | 322 | $(Q)$(MAKE) $(dtbinst)=$(boot)/dts |
322 | 323 | ||
324 | PHONY += vdso_install | ||
325 | vdso_install: | ||
326 | ifeq ($(CONFIG_VDSO),y) | ||
327 | $(Q)$(MAKE) $(build)=arch/arm/vdso $@ | ||
328 | endif | ||
329 | |||
323 | # We use MRPROPER_FILES and CLEAN_FILES now | 330 | # We use MRPROPER_FILES and CLEAN_FILES now |
324 | archclean: | 331 | archclean: |
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' | ||
347 | endef | 355 | endef |
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 | ||
3 | generic-y += auxvec.h | ||
4 | generic-y += bitsperlong.h | 3 | generic-y += bitsperlong.h |
5 | generic-y += cputime.h | 4 | generic-y += cputime.h |
6 | generic-y += current.h | 5 | generic-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 \ | ||
137 | do { \ | ||
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 |
134 | struct linux_binprm; | 143 | struct linux_binprm; |
135 | int arch_setup_additional_pages(struct linux_binprm *, int); | 144 | 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 { | |||
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 | |||
8 | struct mm_struct; | ||
9 | |||
10 | #ifdef CONFIG_VDSO | ||
11 | |||
12 | void arm_install_vdso(struct mm_struct *mm, unsigned long addr); | ||
13 | |||
14 | extern char vdso_start, vdso_end; | ||
15 | |||
16 | extern unsigned int vdso_total_pages; | ||
17 | |||
18 | #else /* CONFIG_VDSO */ | ||
19 | |||
20 | static 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 | */ | ||
31 | struct 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 | |||
51 | union 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 |
2 | include include/uapi/asm-generic/Kbuild.asm | 2 | include include/uapi/asm-generic/Kbuild.asm |
3 | 3 | ||
4 | header-y += auxvec.h | ||
4 | header-y += byteorder.h | 5 | header-y += byteorder.h |
5 | header-y += fcntl.h | 6 | header-y += fcntl.h |
6 | header-y += hwcap.h | 7 | 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..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 | |||
75 | CFLAGS_pj4-cp0.o := -marm | 75 | CFLAGS_pj4-cp0.o := -marm |
76 | AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt | 76 | AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt |
77 | obj-$(CONFIG_ARM_CPU_TOPOLOGY) += topology.o | 77 | obj-$(CONFIG_ARM_CPU_TOPOLOGY) += topology.o |
78 | obj-$(CONFIG_VDSO) += vdso.o | ||
78 | 79 | ||
79 | ifneq ($(CONFIG_ARCH_EBSA110),y) | 80 | ifneq ($(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 | */ |
339 | static unsigned long sigpage_addr(const struct mm_struct *mm, | 339 | static 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 | |||
39 | static struct page **vdso_text_pagelist; | ||
40 | |||
41 | /* Total number of pages needed for the data and text portions of the VDSO. */ | ||
42 | unsigned int vdso_total_pages __read_mostly; | ||
43 | |||
44 | /* | ||
45 | * The VDSO data page. | ||
46 | */ | ||
47 | static union vdso_data_store vdso_data_store __page_aligned_data; | ||
48 | static struct vdso_data *vdso_data = &vdso_data_store.data; | ||
49 | |||
50 | static struct page *vdso_data_page; | ||
51 | static struct vm_special_mapping vdso_data_mapping = { | ||
52 | .name = "[vvar]", | ||
53 | .pages = &vdso_data_page, | ||
54 | }; | ||
55 | |||
56 | static struct vm_special_mapping vdso_text_mapping = { | ||
57 | .name = "[vdso]", | ||
58 | }; | ||
59 | |||
60 | struct 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 | */ | ||
70 | static bool cntvct_ok __read_mostly; | ||
71 | |||
72 | static 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 | |||
93 | out_put: | ||
94 | of_node_put(np); | ||
95 | out: | ||
96 | return ret; | ||
97 | } | ||
98 | |||
99 | static 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 | |||
124 | static 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 | |||
144 | static 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 | |||
155 | static 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 | |||
176 | static 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 | } | ||
217 | arch_initcall(vdso_init); | ||
218 | |||
219 | static 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 */ | ||
231 | void 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 | |||
256 | static 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 | |||
262 | static 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 | |||
268 | static 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 | */ | ||
297 | void 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 | |||
332 | void 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 | |||
42 | config ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA | 42 | config 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 | ||
739 | config CPU_DCACHE_DISABLE | 739 | config 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 | ||
828 | config 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 | |||
828 | config DMA_CACHE_RWFO | 842 | config 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 |
302 | 1: 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 |
313 | 1: 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 |
348 | 1: 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 |
358 | 1: 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 | ||
347 | 1: 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 @@ | |||
1 | hostprogs-y := vdsomunge | ||
2 | |||
3 | obj-vdso := vgettimeofday.o datapage.o | ||
4 | |||
5 | # Build rules | ||
6 | targets := $(obj-vdso) vdso.so vdso.so.dbg vdso.so.raw vdso.lds | ||
7 | obj-vdso := $(addprefix $(obj)/, $(obj-vdso)) | ||
8 | |||
9 | ccflags-y := -shared -fPIC -fno-common -fno-builtin -fno-stack-protector | ||
10 | ccflags-y += -nostdlib -Wl,-soname=linux-vdso.so.1 -DDISABLE_BRANCH_PROFILING | ||
11 | ccflags-y += -Wl,--no-undefined $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) | ||
12 | |||
13 | obj-y += vdso.o | ||
14 | extra-y += vdso.lds | ||
15 | CPPFLAGS_vdso.lds += -P -C -U$(ARCH) | ||
16 | |||
17 | CFLAGS_REMOVE_vdso.o = -pg | ||
18 | |||
19 | # Force -O2 to avoid libgcc dependencies | ||
20 | CFLAGS_REMOVE_vgettimeofday.o = -pg -Os | ||
21 | CFLAGS_vgettimeofday.o = -O2 | ||
22 | |||
23 | # Disable gcov profiling for VDSO code | ||
24 | GCOV_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 | ||
42 | quiet_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 | |||
48 | quiet_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 | # | ||
57 | quiet_cmd_vdso_install = INSTALL $< | ||
58 | define 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 | ||
67 | endef | ||
68 | |||
69 | $(MODLIB)/vdso: FORCE | ||
70 | @mkdir -p $(MODLIB)/vdso | ||
71 | |||
72 | PHONY += vdso_install | ||
73 | vdso_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 | |||
8 | ENTRY(__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 | ||
15 | ENDPROC(__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 | ||
30 | vdso_start: | ||
31 | .incbin "arch/arm/vdso/vdso.so" | ||
32 | .balign PAGE_SIZE | ||
33 | vdso_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 | |||
28 | OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") | ||
29 | OUTPUT_ARCH(arm) | ||
30 | |||
31 | SECTIONS | ||
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 | */ | ||
71 | PHDRS | ||
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 | |||
79 | VERSION | ||
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 | |||
85 | static const char *outfile; | ||
86 | |||
87 | static void cleanup(void) | ||
88 | { | ||
89 | if (error_message_count > 0 && outfile != NULL) | ||
90 | unlink(outfile); | ||
91 | } | ||
92 | |||
93 | static Elf32_Word read_elf_word(Elf32_Word word, bool swap) | ||
94 | { | ||
95 | return swap ? bswap_32(word) : word; | ||
96 | } | ||
97 | |||
98 | static Elf32_Half read_elf_half(Elf32_Half half, bool swap) | ||
99 | { | ||
100 | return swap ? bswap_16(half) : half; | ||
101 | } | ||
102 | |||
103 | static void write_elf_word(Elf32_Word val, Elf32_Word *dst, bool swap) | ||
104 | { | ||
105 | *dst = swap ? bswap_32(val) : val; | ||
106 | } | ||
107 | |||
108 | int 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 | |||
32 | extern struct vdso_data *__get_datapage(void); | ||
33 | |||
34 | static notrace u32 __vdso_read_begin(const struct vdso_data *vdata) | ||
35 | { | ||
36 | u32 seq; | ||
37 | repeat: | ||
38 | seq = ACCESS_ONCE(vdata->seq_count); | ||
39 | if (seq & 1) { | ||
40 | cpu_relax(); | ||
41 | goto repeat; | ||
42 | } | ||
43 | return seq; | ||
44 | } | ||
45 | |||
46 | static 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 | |||
56 | static 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 | |||
62 | static 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 | |||
79 | static 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 | |||
95 | static 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 | |||
120 | static 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 | |||
136 | static 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 | |||
158 | static 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 | |||
187 | static notrace int do_realtime(struct timespec *ts, struct vdso_data *vdata) | ||
188 | { | ||
189 | return -1; | ||
190 | } | ||
191 | |||
192 | static notrace int do_monotonic(struct timespec *ts, struct vdso_data *vdata) | ||
193 | { | ||
194 | return -1; | ||
195 | } | ||
196 | |||
197 | #endif /* CONFIG_ARM_ARCH_TIMER */ | ||
198 | |||
199 | notrace 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 | |||
229 | static 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 | |||
246 | notrace 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 | |||
272 | void __aeabi_unwind_cpp_pr0(void) | ||
273 | { | ||
274 | } | ||
275 | |||
276 | void __aeabi_unwind_cpp_pr1(void) | ||
277 | { | ||
278 | } | ||
279 | |||
280 | void __aeabi_unwind_cpp_pr2(void) | ||
281 | { | ||
282 | } | ||