Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only
2 : : /*
3 : : * Adapted from arm64 version.
4 : : *
5 : : * Copyright (C) 2012 ARM Limited
6 : : * Copyright (C) 2015 Mentor Graphics Corporation.
7 : : */
8 : :
9 : : #include <linux/cache.h>
10 : : #include <linux/elf.h>
11 : : #include <linux/err.h>
12 : : #include <linux/kernel.h>
13 : : #include <linux/mm.h>
14 : : #include <linux/of.h>
15 : : #include <linux/printk.h>
16 : : #include <linux/slab.h>
17 : : #include <linux/timekeeper_internal.h>
18 : : #include <linux/vmalloc.h>
19 : : #include <asm/arch_timer.h>
20 : : #include <asm/barrier.h>
21 : : #include <asm/cacheflush.h>
22 : : #include <asm/page.h>
23 : : #include <asm/vdso.h>
24 : : #include <asm/vdso_datapage.h>
25 : : #include <clocksource/arm_arch_timer.h>
26 : :
27 : : #define MAX_SYMNAME 64
28 : :
29 : : static struct page **vdso_text_pagelist;
30 : :
31 : : extern char vdso_start[], vdso_end[];
32 : :
33 : : /* Total number of pages needed for the data and text portions of the VDSO. */
34 : : unsigned int vdso_total_pages __ro_after_init;
35 : :
36 : : /*
37 : : * The VDSO data page.
38 : : */
39 : : static union vdso_data_store vdso_data_store __page_aligned_data;
40 : : static struct vdso_data *vdso_data = &vdso_data_store.data;
41 : :
42 : : static struct page *vdso_data_page __ro_after_init;
43 : : static const struct vm_special_mapping vdso_data_mapping = {
44 : : .name = "[vvar]",
45 : : .pages = &vdso_data_page,
46 : : };
47 : :
48 : 0 : static int vdso_mremap(const struct vm_special_mapping *sm,
49 : : struct vm_area_struct *new_vma)
50 : : {
51 : 0 : unsigned long new_size = new_vma->vm_end - new_vma->vm_start;
52 : : unsigned long vdso_size;
53 : :
54 : : /* without VVAR page */
55 : 0 : vdso_size = (vdso_total_pages - 1) << PAGE_SHIFT;
56 : :
57 [ # # ]: 0 : if (vdso_size != new_size)
58 : : return -EINVAL;
59 : :
60 : 0 : current->mm->context.vdso = new_vma->vm_start;
61 : :
62 : 0 : return 0;
63 : : }
64 : :
65 : : static struct vm_special_mapping vdso_text_mapping __ro_after_init = {
66 : : .name = "[vdso]",
67 : : .mremap = vdso_mremap,
68 : : };
69 : :
70 : : struct elfinfo {
71 : : Elf32_Ehdr *hdr; /* ptr to ELF */
72 : : Elf32_Sym *dynsym; /* ptr to .dynsym section */
73 : : unsigned long dynsymsize; /* size of .dynsym section */
74 : : char *dynstr; /* ptr to .dynstr section */
75 : : };
76 : :
77 : : /* Cached result of boot-time check for whether the arch timer exists,
78 : : * and if so, whether the virtual counter is useable.
79 : : */
80 : : static bool cntvct_ok __ro_after_init;
81 : :
82 : 207 : static bool __init cntvct_functional(void)
83 : : {
84 : : struct device_node *np;
85 : : bool ret = false;
86 : :
87 : : if (!IS_ENABLED(CONFIG_ARM_ARCH_TIMER))
88 : : goto out;
89 : :
90 : : /* The arm_arch_timer core should export
91 : : * arch_timer_use_virtual or similar so we don't have to do
92 : : * this.
93 : : */
94 : 207 : np = of_find_compatible_node(NULL, NULL, "arm,armv7-timer");
95 [ - + ]: 207 : if (!np)
96 : 0 : np = of_find_compatible_node(NULL, NULL, "arm,armv8-timer");
97 [ + - ]: 207 : if (!np)
98 : : goto out_put;
99 : :
100 [ + - ]: 207 : if (of_property_read_bool(np, "arm,cpu-registers-not-fw-configured"))
101 : : goto out_put;
102 : :
103 : : ret = true;
104 : :
105 : : out_put:
106 : 207 : of_node_put(np);
107 : : out:
108 : 207 : return ret;
109 : : }
110 : :
111 : 414 : static void * __init find_section(Elf32_Ehdr *ehdr, const char *name,
112 : : unsigned long *size)
113 : : {
114 : : Elf32_Shdr *sechdrs;
115 : : unsigned int i;
116 : : char *secnames;
117 : :
118 : : /* Grab section headers and strings so we can tell who is who */
119 : 414 : sechdrs = (void *)ehdr + ehdr->e_shoff;
120 : 414 : secnames = (void *)ehdr + sechdrs[ehdr->e_shstrndx].sh_offset;
121 : :
122 : : /* Find the section they want */
123 [ + - ]: 1035 : for (i = 1; i < ehdr->e_shnum; i++) {
124 [ + + ]: 1035 : if (strcmp(secnames + sechdrs[i].sh_name, name) == 0) {
125 [ + + ]: 414 : if (size)
126 : 207 : *size = sechdrs[i].sh_size;
127 : 414 : return (void *)ehdr + sechdrs[i].sh_offset;
128 : : }
129 : : }
130 : :
131 [ # # ]: 0 : if (size)
132 : 0 : *size = 0;
133 : : return NULL;
134 : : }
135 : :
136 : 0 : static Elf32_Sym * __init find_symbol(struct elfinfo *lib, const char *symname)
137 : : {
138 : : unsigned int i;
139 : :
140 [ # # ]: 0 : for (i = 0; i < (lib->dynsymsize / sizeof(Elf32_Sym)); i++) {
141 : : char name[MAX_SYMNAME], *c;
142 : :
143 [ # # ]: 0 : if (lib->dynsym[i].st_name == 0)
144 : 0 : continue;
145 : 0 : strlcpy(name, lib->dynstr + lib->dynsym[i].st_name,
146 : : MAX_SYMNAME);
147 : 0 : c = strchr(name, '@');
148 [ # # ]: 0 : if (c)
149 : 0 : *c = 0;
150 [ # # ]: 0 : if (strcmp(symname, name) == 0)
151 : 0 : return &lib->dynsym[i];
152 : : }
153 : : return NULL;
154 : : }
155 : :
156 : 0 : static void __init vdso_nullpatch_one(struct elfinfo *lib, const char *symname)
157 : : {
158 : : Elf32_Sym *sym;
159 : :
160 : 0 : sym = find_symbol(lib, symname);
161 [ # # ]: 0 : if (!sym)
162 : 0 : return;
163 : :
164 : 0 : sym->st_name = 0;
165 : : }
166 : :
167 : 207 : static void __init patch_vdso(void *ehdr)
168 : : {
169 : : struct elfinfo einfo;
170 : :
171 : 207 : einfo = (struct elfinfo) {
172 : : .hdr = ehdr,
173 : : };
174 : :
175 : 207 : einfo.dynsym = find_section(einfo.hdr, ".dynsym", &einfo.dynsymsize);
176 : 207 : einfo.dynstr = find_section(einfo.hdr, ".dynstr", NULL);
177 : :
178 : : /* If the virtual counter is absent or non-functional we don't
179 : : * want programs to incur the slight additional overhead of
180 : : * dispatching through the VDSO only to fall back to syscalls.
181 : : */
182 [ - + ]: 207 : if (!cntvct_ok) {
183 : 0 : vdso_nullpatch_one(&einfo, "__vdso_gettimeofday");
184 : 0 : vdso_nullpatch_one(&einfo, "__vdso_clock_gettime");
185 : : }
186 : 207 : }
187 : :
188 : 207 : static int __init vdso_init(void)
189 : : {
190 : : unsigned int text_pages;
191 : : int i;
192 : :
193 [ - + ]: 207 : if (memcmp(vdso_start, "\177ELF", 4)) {
194 : 0 : pr_err("VDSO is not a valid ELF object!\n");
195 : 0 : return -ENOEXEC;
196 : : }
197 : :
198 : 207 : text_pages = (vdso_end - vdso_start) >> PAGE_SHIFT;
199 : :
200 : : /* Allocate the VDSO text pagelist */
201 : 207 : vdso_text_pagelist = kcalloc(text_pages, sizeof(struct page *),
202 : : GFP_KERNEL);
203 [ + - ]: 207 : if (vdso_text_pagelist == NULL)
204 : : return -ENOMEM;
205 : :
206 : : /* Grab the VDSO data page. */
207 : 207 : vdso_data_page = virt_to_page(vdso_data);
208 : :
209 : : /* Grab the VDSO text pages. */
210 [ + + ]: 414 : for (i = 0; i < text_pages; i++) {
211 : : struct page *page;
212 : :
213 : 207 : page = virt_to_page(vdso_start + i * PAGE_SIZE);
214 : 207 : vdso_text_pagelist[i] = page;
215 : : }
216 : :
217 : 207 : vdso_text_mapping.pages = vdso_text_pagelist;
218 : :
219 : 207 : vdso_total_pages = 1; /* for the data/vvar page */
220 : 207 : vdso_total_pages += text_pages;
221 : :
222 : 207 : cntvct_ok = cntvct_functional();
223 : :
224 : 207 : patch_vdso(vdso_start);
225 : :
226 : 207 : return 0;
227 : : }
228 : : arch_initcall(vdso_init);
229 : :
230 : : static int install_vvar(struct mm_struct *mm, unsigned long addr)
231 : : {
232 : : struct vm_area_struct *vma;
233 : :
234 : 808979 : vma = _install_special_mapping(mm, addr, PAGE_SIZE,
235 : : VM_READ | VM_MAYREAD,
236 : : &vdso_data_mapping);
237 : :
238 : : return PTR_ERR_OR_ZERO(vma);
239 : : }
240 : :
241 : : /* assumes mmap_sem is write-locked */
242 : 808985 : void arm_install_vdso(struct mm_struct *mm, unsigned long addr)
243 : : {
244 : : struct vm_area_struct *vma;
245 : : unsigned long len;
246 : :
247 : 808985 : mm->context.vdso = 0;
248 : :
249 [ + + ]: 808985 : if (vdso_text_pagelist == NULL)
250 : : return;
251 : :
252 [ + + ]: 808985 : if (install_vvar(mm, addr))
253 : : return;
254 : :
255 : : /* Account for vvar page. */
256 : 808984 : addr += PAGE_SIZE;
257 : 808984 : len = (vdso_total_pages - 1) << PAGE_SHIFT;
258 : :
259 : 808984 : vma = _install_special_mapping(mm, addr, len,
260 : : VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
261 : : &vdso_text_mapping);
262 : :
263 [ + - ]: 808985 : if (!IS_ERR(vma))
264 : 808985 : mm->context.vdso = addr;
265 : : }
266 : :
267 : : static void vdso_write_begin(struct vdso_data *vdata)
268 : : {
269 : 2606612 : ++vdso_data->seq_count;
270 : 2606612 : smp_wmb(); /* Pairs with smp_rmb in vdso_read_retry */
271 : : }
272 : :
273 : : static void vdso_write_end(struct vdso_data *vdata)
274 : : {
275 : 2606612 : smp_wmb(); /* Pairs with smp_rmb in vdso_read_begin */
276 : 2606612 : ++vdso_data->seq_count;
277 : : }
278 : :
279 : : static bool tk_is_cntvct(const struct timekeeper *tk)
280 : : {
281 : : if (!IS_ENABLED(CONFIG_ARM_ARCH_TIMER))
282 : : return false;
283 : :
284 [ + + ]: 2606612 : if (tk->tkr_mono.clock->archdata.clock_mode != VDSO_CLOCKMODE_ARCHTIMER)
285 : : return false;
286 : :
287 : : return true;
288 : : }
289 : :
290 : : /**
291 : : * update_vsyscall - update the vdso data page
292 : : *
293 : : * Increment the sequence counter, making it odd, indicating to
294 : : * userspace that an update is in progress. Update the fields used
295 : : * for coarse clocks and, if the architected system timer is in use,
296 : : * the fields used for high precision clocks. Increment the sequence
297 : : * counter again, making it even, indicating to userspace that the
298 : : * update is finished.
299 : : *
300 : : * Userspace is expected to sample seq_count before reading any other
301 : : * fields from the data page. If seq_count is odd, userspace is
302 : : * expected to wait until it becomes even. After copying data from
303 : : * the page, userspace must sample seq_count again; if it has changed
304 : : * from its previous value, userspace must retry the whole sequence.
305 : : *
306 : : * Calls to update_vsyscall are serialized by the timekeeping core.
307 : : */
308 : 2608889 : void update_vsyscall(struct timekeeper *tk)
309 : : {
310 : : struct timespec64 *wtm = &tk->wall_to_monotonic;
311 : :
312 [ + + ]: 2608889 : if (!cntvct_ok) {
313 : : /* The entry points have been zeroed, so there is no
314 : : * point in updating the data page.
315 : : */
316 : 2608889 : return;
317 : : }
318 : :
319 : : vdso_write_begin(vdso_data);
320 : :
321 : 5213224 : vdso_data->tk_is_cntvct = tk_is_cntvct(tk);
322 : 2606612 : vdso_data->xtime_coarse_sec = tk->xtime_sec;
323 : 5213224 : vdso_data->xtime_coarse_nsec = (u32)(tk->tkr_mono.xtime_nsec >>
324 : 2606612 : tk->tkr_mono.shift);
325 : 2606612 : vdso_data->wtm_clock_sec = wtm->tv_sec;
326 : 2606612 : vdso_data->wtm_clock_nsec = wtm->tv_nsec;
327 : :
328 [ + + ]: 2606612 : if (vdso_data->tk_is_cntvct) {
329 : 2602886 : vdso_data->cs_cycle_last = tk->tkr_mono.cycle_last;
330 : 2602886 : vdso_data->xtime_clock_sec = tk->xtime_sec;
331 : 2602886 : vdso_data->xtime_clock_snsec = tk->tkr_mono.xtime_nsec;
332 : 2602886 : vdso_data->cs_mult = tk->tkr_mono.mult;
333 : 2602886 : vdso_data->cs_shift = tk->tkr_mono.shift;
334 : 2602886 : vdso_data->cs_mask = tk->tkr_mono.mask;
335 : : }
336 : :
337 : : vdso_write_end(vdso_data);
338 : :
339 : 2606612 : flush_dcache_page(virt_to_page(vdso_data));
340 : : }
341 : :
342 : 207 : void update_vsyscall_tz(void)
343 : : {
344 : 207 : vdso_data->tz_minuteswest = sys_tz.tz_minuteswest;
345 : 207 : vdso_data->tz_dsttime = sys_tz.tz_dsttime;
346 : 207 : flush_dcache_page(virt_to_page(vdso_data));
347 : 207 : }
|