This source file includes following definitions.
- vdso_mremap
 
- cntvct_functional
 
- find_section
 
- find_symbol
 
- vdso_nullpatch_one
 
- patch_vdso
 
- vdso_init
 
- install_vvar
 
- arm_install_vdso
 
- vdso_write_begin
 
- vdso_write_end
 
- tk_is_cntvct
 
- update_vsyscall
 
- update_vsyscall_tz
 
   1 
   2 
   3 
   4 
   5 
   6 
   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 
  34 unsigned int vdso_total_pages __ro_after_init;
  35 
  36 
  37 
  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         
  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;           
  72         Elf32_Sym       *dynsym;        
  73         unsigned long   dynsymsize;     
  74         char            *dynstr;        
  75 };
  76 
  77 
  78 
  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         
  91 
  92 
  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         
 119         sechdrs = (void *)ehdr + ehdr->e_shoff;
 120         secnames = (void *)ehdr + sechdrs[ehdr->e_shstrndx].sh_offset;
 121 
 122         
 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         
 179 
 180 
 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         
 201         vdso_text_pagelist = kcalloc(text_pages, sizeof(struct page *),
 202                                      GFP_KERNEL);
 203         if (vdso_text_pagelist == NULL)
 204                 return -ENOMEM;
 205 
 206         
 207         vdso_data_page = virt_to_page(vdso_data);
 208 
 209         
 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; 
 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 
 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         
 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(); 
 271 }
 272 
 273 static void vdso_write_end(struct vdso_data *vdata)
 274 {
 275         smp_wmb(); 
 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 
 292 
 293 
 294 
 295 
 296 
 297 
 298 
 299 
 300 
 301 
 302 
 303 
 304 
 305 
 306 
 307 
 308 void update_vsyscall(struct timekeeper *tk)
 309 {
 310         struct timespec64 *wtm = &tk->wall_to_monotonic;
 311 
 312         if (!cntvct_ok) {
 313                 
 314 
 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 }