>> 1 // SPDX-License-Identifier: GPL-2.0-or-later 1 /* 2 /* 2 * Copyright (C) 2001 Andrea Arcangeli <andre !! 3 * Copyright (C) 2015 Imagination Technologies 3 * Copyright 2003 Andi Kleen, SuSE Labs. !! 4 * Author: Alex Smith <alex.smith@imgtec.com> 4 * << 5 * Thanks to hpa@transmeta.com for some usefu << 6 * Special thanks to Ingo Molnar for his earl << 7 * a different vsyscall implementation for Li << 8 */ 5 */ 9 6 10 #include <linux/time.h> !! 7 #include <linux/binfmts.h> >> 8 #include <linux/elf.h> >> 9 #include <linux/err.h> >> 10 #include <linux/init.h> >> 11 #include <linux/ioport.h> >> 12 #include <linux/kernel.h> >> 13 #include <linux/mm.h> >> 14 #include <linux/random.h> >> 15 #include <linux/sched.h> >> 16 #include <linux/slab.h> 11 #include <linux/timekeeper_internal.h> 17 #include <linux/timekeeper_internal.h> 12 18 13 #include <asm/vvar.h> !! 19 #include <asm/abi.h> >> 20 #include <asm/mips-cps.h> >> 21 #include <asm/page.h> >> 22 #include <asm/vdso.h> >> 23 #include <vdso/helpers.h> >> 24 #include <vdso/vsyscall.h> >> 25 >> 26 /* Kernel-provided data used by the VDSO. */ >> 27 static union vdso_data_store mips_vdso_data __page_aligned_data; >> 28 struct vdso_data *vdso_data = mips_vdso_data.data; 14 29 15 void update_vsyscall_tz(void) !! 30 /* >> 31 * Mapping for the VDSO data/GIC pages. The real pages are mapped manually, as >> 32 * what we map and where within the area they are mapped is determined at >> 33 * runtime. >> 34 */ >> 35 static struct page *no_pages[] = { NULL }; >> 36 static struct vm_special_mapping vdso_vvar_mapping = { >> 37 .name = "[vvar]", >> 38 .pages = no_pages, >> 39 }; >> 40 >> 41 static void __init init_vdso_image(struct mips_vdso_image *image) 16 { 42 { 17 if (unlikely(vvar_data == NULL)) !! 43 unsigned long num_pages, i; 18 return; !! 44 unsigned long data_pfn; >> 45 >> 46 BUG_ON(!PAGE_ALIGNED(image->data)); >> 47 BUG_ON(!PAGE_ALIGNED(image->size)); >> 48 >> 49 num_pages = image->size / PAGE_SIZE; >> 50 >> 51 data_pfn = __phys_to_pfn(__pa_symbol(image->data)); >> 52 for (i = 0; i < num_pages; i++) >> 53 image->mapping.pages[i] = pfn_to_page(data_pfn + i); >> 54 } >> 55 >> 56 static int __init init_vdso(void) >> 57 { >> 58 init_vdso_image(&vdso_image); >> 59 >> 60 #ifdef CONFIG_MIPS32_O32 >> 61 init_vdso_image(&vdso_image_o32); >> 62 #endif >> 63 >> 64 #ifdef CONFIG_MIPS32_N32 >> 65 init_vdso_image(&vdso_image_n32); >> 66 #endif 19 67 20 vvar_data->tz_minuteswest = sys_tz.tz_ !! 68 return 0; 21 vvar_data->tz_dsttime = sys_tz.tz_dstt << 22 } 69 } >> 70 subsys_initcall(init_vdso); 23 71 24 void update_vsyscall(struct timekeeper *tk) !! 72 static unsigned long vdso_base(void) 25 { 73 { 26 struct vvar_data *vdata = vvar_data; !! 74 unsigned long base = STACK_TOP; 27 75 28 if (unlikely(vdata == NULL)) !! 76 if (IS_ENABLED(CONFIG_MIPS_FP_SUPPORT)) { 29 return; !! 77 /* Skip the delay slot emulation page */ >> 78 base += PAGE_SIZE; >> 79 } 30 80 31 vvar_write_begin(vdata); !! 81 if (current->flags & PF_RANDOMIZE) { 32 vdata->vclock_mode = tk->tkr_mono.cloc !! 82 base += get_random_u32_below(VDSO_RANDOMIZE_SIZE); 33 vdata->clock.cycle_last = tk->tkr_mono !! 83 base = PAGE_ALIGN(base); 34 vdata->clock.mask = tk->tkr_mono.mask; !! 84 } 35 vdata->clock.mult = tk->tkr_mono.mult; << 36 vdata->clock.shift = tk->tkr_mono.shif << 37 85 38 vdata->wall_time_sec = tk->xtime_sec; !! 86 return base; 39 vdata->wall_time_snsec = tk->tkr_mono. !! 87 } 40 88 41 vdata->monotonic_time_sec = tk->xtime_ !! 89 int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) 42 tk->wall_t !! 90 { 43 vdata->monotonic_time_snsec = tk->tkr_ !! 91 struct mips_vdso_image *image = current->thread.abi->vdso; 44 (tk->wal !! 92 struct mm_struct *mm = current->mm; 45 tk->tkr !! 93 unsigned long gic_size, vvar_size, size, base, data_addr, vdso_addr, gic_pfn, gic_base; >> 94 struct vm_area_struct *vma; >> 95 int ret; >> 96 >> 97 if (mmap_write_lock_killable(mm)) >> 98 return -EINTR; >> 99 >> 100 if (IS_ENABLED(CONFIG_MIPS_FP_SUPPORT)) { >> 101 /* Map delay slot emulation page */ >> 102 base = mmap_region(NULL, STACK_TOP, PAGE_SIZE, >> 103 VM_READ | VM_EXEC | >> 104 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC, >> 105 0, NULL); >> 106 if (IS_ERR_VALUE(base)) { >> 107 ret = base; >> 108 goto out; >> 109 } >> 110 } 46 111 47 while (vdata->monotonic_time_snsec >= !! 112 /* 48 (((u64)NSEC_PER_SEC) << tk->tkr !! 113 * Determine total area size. This includes the VDSO data itself, the 49 vdata->monotonic_time_snsec -= !! 114 * data page, and the GIC user page if present. Always create a mapping 50 ((u64)NSEC_PER !! 115 * for the GIC user area if the GIC is present regardless of whether it 51 vdata->monotonic_time_sec++; !! 116 * is the current clocksource, in case it comes into use later on. We >> 117 * only map a page even though the total area is 64K, as we only need >> 118 * the counter registers at the start. >> 119 */ >> 120 gic_size = mips_gic_present() ? PAGE_SIZE : 0; >> 121 vvar_size = gic_size + PAGE_SIZE; >> 122 size = vvar_size + image->size; >> 123 >> 124 /* >> 125 * Find a region that's large enough for us to perform the >> 126 * colour-matching alignment below. >> 127 */ >> 128 if (cpu_has_dc_aliases) >> 129 size += shm_align_mask + 1; >> 130 >> 131 base = get_unmapped_area(NULL, vdso_base(), size, 0, 0); >> 132 if (IS_ERR_VALUE(base)) { >> 133 ret = base; >> 134 goto out; 52 } 135 } 53 136 54 vdata->wall_time_coarse_sec = tk->xtim !! 137 /* 55 vdata->wall_time_coarse_nsec = !! 138 * If we suffer from dcache aliasing, ensure that the VDSO data page 56 (long)(tk->tkr_mono.xt !! 139 * mapping is coloured the same as the kernel's mapping of that memory. >> 140 * This ensures that when the kernel updates the VDSO data userland >> 141 * will observe it without requiring cache invalidations. >> 142 */ >> 143 if (cpu_has_dc_aliases) { >> 144 base = __ALIGN_MASK(base, shm_align_mask); >> 145 base += ((unsigned long)vdso_data - gic_size) & shm_align_mask; >> 146 } 57 147 58 vdata->monotonic_time_coarse_sec = !! 148 data_addr = base + gic_size; 59 vdata->wall_time_coarse_sec + !! 149 vdso_addr = data_addr + PAGE_SIZE; 60 vdata->monotonic_time_coarse_nsec = << 61 vdata->wall_time_coarse_nsec + << 62 150 63 while (vdata->monotonic_time_coarse_ns !! 151 vma = _install_special_mapping(mm, base, vvar_size, 64 vdata->monotonic_time_coarse_n !! 152 VM_READ | VM_MAYREAD, 65 vdata->monotonic_time_coarse_s !! 153 &vdso_vvar_mapping); >> 154 if (IS_ERR(vma)) { >> 155 ret = PTR_ERR(vma); >> 156 goto out; 66 } 157 } 67 158 68 vvar_write_end(vdata); !! 159 /* Map GIC user page. */ >> 160 if (gic_size) { >> 161 gic_base = (unsigned long)mips_gic_base + MIPS_GIC_USER_OFS; >> 162 gic_pfn = PFN_DOWN(__pa(gic_base)); >> 163 >> 164 ret = io_remap_pfn_range(vma, base, gic_pfn, gic_size, >> 165 pgprot_noncached(vma->vm_page_prot)); >> 166 if (ret) >> 167 goto out; >> 168 } >> 169 >> 170 /* Map data page. */ >> 171 ret = remap_pfn_range(vma, data_addr, >> 172 virt_to_phys(vdso_data) >> PAGE_SHIFT, >> 173 PAGE_SIZE, vma->vm_page_prot); >> 174 if (ret) >> 175 goto out; >> 176 >> 177 /* Map VDSO image. */ >> 178 vma = _install_special_mapping(mm, vdso_addr, image->size, >> 179 VM_READ | VM_EXEC | >> 180 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC, >> 181 &image->mapping); >> 182 if (IS_ERR(vma)) { >> 183 ret = PTR_ERR(vma); >> 184 goto out; >> 185 } >> 186 >> 187 mm->context.vdso = (void *)vdso_addr; >> 188 ret = 0; >> 189 >> 190 out: >> 191 mmap_write_unlock(mm); >> 192 return ret; 69 } 193 } 70 194
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.