root/arch/arm/kernel/vdso.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. vdso_mremap
  2. cntvct_functional
  3. find_section
  4. find_symbol
  5. vdso_nullpatch_one
  6. patch_vdso
  7. vdso_init
  8. install_vvar
  9. arm_install_vdso
  10. vdso_write_begin
  11. vdso_write_end
  12. tk_is_cntvct
  13. update_vsyscall
  14. update_vsyscall_tz

   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 static int vdso_mremap(const struct vm_special_mapping *sm,
  49                 struct vm_area_struct *new_vma)
  50 {
  51         unsigned long new_size = new_vma->vm_end - new_vma->vm_start;
  52         unsigned long vdso_size;
  53 
  54         /* without VVAR page */
  55         vdso_size = (vdso_total_pages - 1) << PAGE_SHIFT;
  56 
  57         if (vdso_size != new_size)
  58                 return -EINVAL;
  59 
  60         current->mm->context.vdso = new_vma->vm_start;
  61 
  62         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 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         np = of_find_compatible_node(NULL, NULL, "arm,armv7-timer");
  95         if (!np)
  96                 np = of_find_compatible_node(NULL, NULL, "arm,armv8-timer");
  97         if (!np)
  98                 goto out_put;
  99 
 100         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         of_node_put(np);
 107 out:
 108         return ret;
 109 }
 110 
 111 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         sechdrs = (void *)ehdr + ehdr->e_shoff;
 120         secnames = (void *)ehdr + sechdrs[ehdr->e_shstrndx].sh_offset;
 121 
 122         /* Find the section they want */
 123         for (i = 1; i < ehdr->e_shnum; i++) {
 124                 if (strcmp(secnames + sechdrs[i].sh_name, name) == 0) {
 125                         if (size)
 126                                 *size = sechdrs[i].sh_size;
 127                         return (void *)ehdr + sechdrs[i].sh_offset;
 128                 }
 129         }
 130 
 131         if (size)
 132                 *size = 0;
 133         return NULL;
 134 }
 135 
 136 static Elf32_Sym * __init find_symbol(struct elfinfo *lib, const char *symname)
 137 {
 138         unsigned int i;
 139 
 140         for (i = 0; i < (lib->dynsymsize / sizeof(Elf32_Sym)); i++) {
 141                 char name[MAX_SYMNAME], *c;
 142 
 143                 if (lib->dynsym[i].st_name == 0)
 144                         continue;
 145                 strlcpy(name, lib->dynstr + lib->dynsym[i].st_name,
 146                         MAX_SYMNAME);
 147                 c = strchr(name, '@');
 148                 if (c)
 149                         *c = 0;
 150                 if (strcmp(symname, name) == 0)
 151                         return &lib->dynsym[i];
 152         }
 153         return NULL;
 154 }
 155 
 156 static void __init vdso_nullpatch_one(struct elfinfo *lib, const char *symname)
 157 {
 158         Elf32_Sym *sym;
 159 
 160         sym = find_symbol(lib, symname);
 161         if (!sym)
 162                 return;
 163 
 164         sym->st_name = 0;
 165 }
 166 
 167 static void __init patch_vdso(void *ehdr)
 168 {
 169         struct elfinfo einfo;
 170 
 171         einfo = (struct elfinfo) {
 172                 .hdr = ehdr,
 173         };
 174 
 175         einfo.dynsym = find_section(einfo.hdr, ".dynsym", &einfo.dynsymsize);
 176         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         if (!cntvct_ok) {
 183                 vdso_nullpatch_one(&einfo, "__vdso_gettimeofday");
 184                 vdso_nullpatch_one(&einfo, "__vdso_clock_gettime");
 185         }
 186 }
 187 
 188 static int __init vdso_init(void)
 189 {
 190         unsigned int text_pages;
 191         int i;
 192 
 193         if (memcmp(vdso_start, "\177ELF", 4)) {
 194                 pr_err("VDSO is not a valid ELF object!\n");
 195                 return -ENOEXEC;
 196         }
 197 
 198         text_pages = (vdso_end - vdso_start) >> PAGE_SHIFT;
 199 
 200         /* Allocate the VDSO text pagelist */
 201         vdso_text_pagelist = kcalloc(text_pages, sizeof(struct page *),
 202                                      GFP_KERNEL);
 203         if (vdso_text_pagelist == NULL)
 204                 return -ENOMEM;
 205 
 206         /* Grab the VDSO data page. */
 207         vdso_data_page = virt_to_page(vdso_data);
 208 
 209         /* Grab the VDSO text pages. */
 210         for (i = 0; i < text_pages; i++) {
 211                 struct page *page;
 212 
 213                 page = virt_to_page(vdso_start + i * PAGE_SIZE);
 214                 vdso_text_pagelist[i] = page;
 215         }
 216 
 217         vdso_text_mapping.pages = vdso_text_pagelist;
 218 
 219         vdso_total_pages = 1; /* for the data/vvar page */
 220         vdso_total_pages += text_pages;
 221 
 222         cntvct_ok = cntvct_functional();
 223 
 224         patch_vdso(vdso_start);
 225 
 226         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         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 void arm_install_vdso(struct mm_struct *mm, unsigned long addr)
 243 {
 244         struct vm_area_struct *vma;
 245         unsigned long len;
 246 
 247         mm->context.vdso = 0;
 248 
 249         if (vdso_text_pagelist == NULL)
 250                 return;
 251 
 252         if (install_vvar(mm, addr))
 253                 return;
 254 
 255         /* Account for vvar page. */
 256         addr += PAGE_SIZE;
 257         len = (vdso_total_pages - 1) << PAGE_SHIFT;
 258 
 259         vma = _install_special_mapping(mm, addr, len,
 260                 VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
 261                 &vdso_text_mapping);
 262 
 263         if (!IS_ERR(vma))
 264                 mm->context.vdso = addr;
 265 }
 266 
 267 static void vdso_write_begin(struct vdso_data *vdata)
 268 {
 269         ++vdso_data->seq_count;
 270         smp_wmb(); /* Pairs with smp_rmb in vdso_read_retry */
 271 }
 272 
 273 static void vdso_write_end(struct vdso_data *vdata)
 274 {
 275         smp_wmb(); /* Pairs with smp_rmb in vdso_read_begin */
 276         ++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         if (!tk->tkr_mono.clock->archdata.vdso_direct)
 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 void update_vsyscall(struct timekeeper *tk)
 309 {
 310         struct timespec64 *wtm = &tk->wall_to_monotonic;
 311 
 312         if (!cntvct_ok) {
 313                 /* The entry points have been zeroed, so there is no
 314                  * point in updating the data page.
 315                  */
 316                 return;
 317         }
 318 
 319         vdso_write_begin(vdso_data);
 320 
 321         vdso_data->tk_is_cntvct                 = tk_is_cntvct(tk);
 322         vdso_data->xtime_coarse_sec             = tk->xtime_sec;
 323         vdso_data->xtime_coarse_nsec            = (u32)(tk->tkr_mono.xtime_nsec >>
 324                                                         tk->tkr_mono.shift);
 325         vdso_data->wtm_clock_sec                = wtm->tv_sec;
 326         vdso_data->wtm_clock_nsec               = wtm->tv_nsec;
 327 
 328         if (vdso_data->tk_is_cntvct) {
 329                 vdso_data->cs_cycle_last        = tk->tkr_mono.cycle_last;
 330                 vdso_data->xtime_clock_sec      = tk->xtime_sec;
 331                 vdso_data->xtime_clock_snsec    = tk->tkr_mono.xtime_nsec;
 332                 vdso_data->cs_mult              = tk->tkr_mono.mult;
 333                 vdso_data->cs_shift             = tk->tkr_mono.shift;
 334                 vdso_data->cs_mask              = tk->tkr_mono.mask;
 335         }
 336 
 337         vdso_write_end(vdso_data);
 338 
 339         flush_dcache_page(virt_to_page(vdso_data));
 340 }
 341 
 342 void update_vsyscall_tz(void)
 343 {
 344         vdso_data->tz_minuteswest       = sys_tz.tz_minuteswest;
 345         vdso_data->tz_dsttime           = sys_tz.tz_dsttime;
 346         flush_dcache_page(virt_to_page(vdso_data));
 347 }

/* [<][>][^][v][top][bottom][index][help] */