2 * VDSO implementation for AArch64 and vector page setup for AArch32.
4 * Copyright (C) 2012 ARM Limited
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.
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.
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/>.
18 * Author: Will Deacon <will.deacon@arm.com>
21 #include <linux/kernel.h>
22 #include <linux/clocksource.h>
23 #include <linux/elf.h>
24 #include <linux/err.h>
25 #include <linux/errno.h>
26 #include <linux/gfp.h>
28 #include <linux/sched.h>
29 #include <linux/signal.h>
30 #include <linux/slab.h>
31 #include <linux/timekeeper_internal.h>
32 #include <linux/vmalloc.h>
34 #include <asm/cacheflush.h>
35 #include <asm/signal32.h>
37 #include <asm/vdso_datapage.h>
39 extern char vdso_start
, vdso_end
;
40 static unsigned long vdso_pages
;
41 static struct page
**vdso_pagelist
;
47 struct vdso_data data
;
49 } vdso_data_store __page_aligned_data
;
50 struct vdso_data
*vdso_data
= &vdso_data_store
.data
;
54 * Create and map the vectors page for AArch32 tasks.
56 static struct page
*vectors_page
[1];
58 static int alloc_vectors_page(void)
60 extern char __kuser_helper_start
[], __kuser_helper_end
[];
61 int kuser_sz
= __kuser_helper_end
- __kuser_helper_start
;
64 vpage
= get_zeroed_page(GFP_ATOMIC
);
70 memcpy((void *)vpage
+ 0x1000 - kuser_sz
, __kuser_helper_start
,
74 memcpy((void *)vpage
+ AARCH32_KERN_SIGRET_CODE_OFFSET
,
75 aarch32_sigret_code
, sizeof(aarch32_sigret_code
));
77 flush_icache_range(vpage
, vpage
+ PAGE_SIZE
);
78 vectors_page
[0] = virt_to_page(vpage
);
82 arch_initcall(alloc_vectors_page
);
84 int aarch32_setup_vectors_page(struct linux_binprm
*bprm
, int uses_interp
)
86 struct mm_struct
*mm
= current
->mm
;
87 unsigned long addr
= AARCH32_VECTORS_BASE
;
90 down_write(&mm
->mmap_sem
);
91 current
->mm
->context
.vdso
= (void *)addr
;
93 /* Map vectors page at the high address. */
94 ret
= install_special_mapping(mm
, addr
, PAGE_SIZE
,
95 VM_READ
|VM_EXEC
|VM_MAYREAD
|VM_MAYEXEC
,
98 up_write(&mm
->mmap_sem
);
102 #endif /* CONFIG_COMPAT */
104 static int __init
vdso_init(void)
110 vdso_pages
= (&vdso_end
- &vdso_start
) >> PAGE_SHIFT
;
111 pr_info("vdso: %ld pages (%ld code, %ld data) at base %p\n",
112 vdso_pages
+ 1, vdso_pages
, 1L, &vdso_start
);
114 /* Allocate the vDSO pagelist, plus a page for the data. */
115 vdso_pagelist
= kzalloc(sizeof(struct page
*) * (vdso_pages
+ 1),
117 if (vdso_pagelist
== NULL
) {
118 pr_err("Failed to allocate vDSO pagelist!\n");
122 /* Grab the vDSO code pages. */
123 for (i
= 0; i
< vdso_pages
; i
++) {
124 pg
= virt_to_page(&vdso_start
+ i
*PAGE_SIZE
);
125 ClearPageReserved(pg
);
127 vdso_pagelist
[i
] = pg
;
130 /* Sanity check the shared object header. */
131 vbase
= vmap(vdso_pagelist
, 1, 0, PAGE_KERNEL
);
133 pr_err("Failed to map vDSO pagelist!\n");
135 } else if (memcmp(vbase
, "\177ELF", 4)) {
136 pr_err("vDSO is not a valid ELF object!\n");
141 /* Grab the vDSO data page. */
142 pg
= virt_to_page(vdso_data
);
144 vdso_pagelist
[i
] = pg
;
150 arch_initcall(vdso_init
);
152 int arch_setup_additional_pages(struct linux_binprm
*bprm
,
155 struct mm_struct
*mm
= current
->mm
;
156 unsigned long vdso_base
, vdso_mapping_len
;
159 /* Be sure to map the data page */
160 vdso_mapping_len
= (vdso_pages
+ 1) << PAGE_SHIFT
;
162 down_write(&mm
->mmap_sem
);
163 vdso_base
= get_unmapped_area(NULL
, 0, vdso_mapping_len
, 0, 0);
164 if (IS_ERR_VALUE(vdso_base
)) {
168 mm
->context
.vdso
= (void *)vdso_base
;
170 ret
= install_special_mapping(mm
, vdso_base
, vdso_mapping_len
,
172 VM_MAYREAD
|VM_MAYWRITE
|VM_MAYEXEC
,
175 mm
->context
.vdso
= NULL
;
180 up_write(&mm
->mmap_sem
);
185 const char *arch_vma_name(struct vm_area_struct
*vma
)
188 * We can re-use the vdso pointer in mm_context_t for identifying
189 * the vectors page for compat applications. The vDSO will always
190 * sit above TASK_UNMAPPED_BASE and so we don't need to worry about
191 * it conflicting with the vectors base.
193 if (vma
->vm_mm
&& vma
->vm_start
== (long)vma
->vm_mm
->context
.vdso
) {
195 if (vma
->vm_start
== AARCH32_VECTORS_BASE
)
205 * We define AT_SYSINFO_EHDR, so we need these function stubs to keep
208 int in_gate_area_no_mm(unsigned long addr
)
213 int in_gate_area(struct mm_struct
*mm
, unsigned long addr
)
218 struct vm_area_struct
*get_gate_vma(struct mm_struct
*mm
)
224 * Update the vDSO data page to keep in sync with kernel timekeeping.
226 void update_vsyscall(struct timekeeper
*tk
)
228 struct timespec xtime_coarse
;
229 u32 use_syscall
= strcmp(tk
->clock
->name
, "arch_sys_counter");
231 ++vdso_data
->tb_seq_count
;
234 xtime_coarse
= __current_kernel_time();
235 vdso_data
->use_syscall
= use_syscall
;
236 vdso_data
->xtime_coarse_sec
= xtime_coarse
.tv_sec
;
237 vdso_data
->xtime_coarse_nsec
= xtime_coarse
.tv_nsec
;
238 vdso_data
->wtm_clock_sec
= tk
->wall_to_monotonic
.tv_sec
;
239 vdso_data
->wtm_clock_nsec
= tk
->wall_to_monotonic
.tv_nsec
;
242 vdso_data
->cs_cycle_last
= tk
->clock
->cycle_last
;
243 vdso_data
->xtime_clock_sec
= tk
->xtime_sec
;
244 vdso_data
->xtime_clock_nsec
= tk
->xtime_nsec
;
245 vdso_data
->cs_mult
= tk
->mult
;
246 vdso_data
->cs_shift
= tk
->shift
;
250 ++vdso_data
->tb_seq_count
;
253 void update_vsyscall_tz(void)
255 vdso_data
->tz_minuteswest
= sys_tz
.tz_minuteswest
;
256 vdso_data
->tz_dsttime
= sys_tz
.tz_dsttime
;