1 // SPDX-License-Identifier: GPL-2.0 << 2 /* 1 /* 3 * Author: Huacai Chen <chenhuacai@loongson.cn !! 2 * Copyright (C) 2001 Andrea Arcangeli <andrea@suse.de> SuSE 4 * Copyright (C) 2020-2022 Loongson Technology !! 3 * Copyright 2003 Andi Kleen, SuSE Labs. >> 4 * >> 5 * Thanks to hpa@transmeta.com for some useful hint. >> 6 * Special thanks to Ingo Molnar for his early experience with >> 7 * a different vsyscall implementation for Linux/IA32 and for the name. 5 */ 8 */ 6 9 7 #include <linux/binfmts.h> !! 10 #include <linux/time.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> << 17 #include <linux/time_namespace.h> << 18 #include <linux/timekeeper_internal.h> 11 #include <linux/timekeeper_internal.h> 19 12 20 #include <asm/page.h> !! 13 #include <asm/vvar.h> 21 #include <asm/vdso.h> << 22 #include <vdso/helpers.h> << 23 #include <vdso/vsyscall.h> << 24 #include <vdso/datapage.h> << 25 #include <generated/vdso-offsets.h> << 26 << 27 extern char vdso_start[], vdso_end[]; << 28 << 29 /* Kernel-provided data used by the VDSO. */ << 30 static union vdso_data_store generic_vdso_data << 31 << 32 static union { << 33 u8 page[LOONGARCH_VDSO_DATA_SIZE]; << 34 struct loongarch_vdso_data vdata; << 35 } loongarch_vdso_data __page_aligned_data; << 36 << 37 struct vdso_data *vdso_data = generic_vdso_dat << 38 struct vdso_pcpu_data *vdso_pdata = loongarch_ << 39 struct vdso_rng_data *vdso_rng_data = &loongar << 40 << 41 static int vdso_mremap(const struct vm_special << 42 { << 43 current->mm->context.vdso = (void *)(n << 44 << 45 return 0; << 46 } << 47 14 48 static vm_fault_t vvar_fault(const struct vm_s !! 15 void update_vsyscall_tz(void) 49 struct vm_area_st << 50 { 16 { 51 unsigned long pfn; !! 17 if (unlikely(vvar_data == NULL)) 52 struct page *timens_page = find_timens !! 18 return; 53 << 54 switch (vmf->pgoff) { << 55 case VVAR_GENERIC_PAGE_OFFSET: << 56 if (!timens_page) << 57 pfn = sym_to_pfn(vdso_ << 58 else << 59 pfn = page_to_pfn(time << 60 break; << 61 #ifdef CONFIG_TIME_NS << 62 case VVAR_TIMENS_PAGE_OFFSET: << 63 /* << 64 * If a task belongs to a time << 65 * VVAR is mapped with the VVA << 66 * VVAR page is mapped with th << 67 * See also the comment near t << 68 */ << 69 if (!timens_page) << 70 return VM_FAULT_SIGBUS << 71 else << 72 pfn = sym_to_pfn(vdso_ << 73 break; << 74 #endif /* CONFIG_TIME_NS */ << 75 case VVAR_LOONGARCH_PAGES_START ... VV << 76 pfn = sym_to_pfn(&loongarch_vd << 77 break; << 78 default: << 79 return VM_FAULT_SIGBUS; << 80 } << 81 19 82 return vmf_insert_pfn(vma, vmf->addres !! 20 vvar_data->tz_minuteswest = sys_tz.tz_minuteswest; >> 21 vvar_data->tz_dsttime = sys_tz.tz_dsttime; 83 } 22 } 84 23 85 struct loongarch_vdso_info vdso_info = { !! 24 void update_vsyscall(struct timekeeper *tk) 86 .vdso = vdso_start, << 87 .code_mapping = { << 88 .name = "[vdso]", << 89 .mremap = vdso_mremap, << 90 }, << 91 .data_mapping = { << 92 .name = "[vvar]", << 93 .fault = vvar_fault, << 94 }, << 95 .offset_sigreturn = vdso_offset_sigret << 96 }; << 97 << 98 static int __init init_vdso(void) << 99 { 25 { 100 unsigned long i, cpu, pfn; !! 26 struct vvar_data *vdata = vvar_data; 101 27 102 BUG_ON(!PAGE_ALIGNED(vdso_info.vdso)); !! 28 if (unlikely(vdata == NULL)) >> 29 return; 103 30 104 for_each_possible_cpu(cpu) !! 31 vvar_write_begin(vdata); 105 vdso_pdata[cpu].node = cpu_to_ !! 32 vdata->vclock_mode = tk->tkr_mono.clock->archdata.vclock_mode; >> 33 vdata->clock.cycle_last = tk->tkr_mono.cycle_last; >> 34 vdata->clock.mask = tk->tkr_mono.mask; >> 35 vdata->clock.mult = tk->tkr_mono.mult; >> 36 vdata->clock.shift = tk->tkr_mono.shift; 106 37 107 vdso_info.size = PAGE_ALIGN(vdso_end - !! 38 vdata->wall_time_sec = tk->xtime_sec; 108 vdso_info.code_mapping.pages = !! 39 vdata->wall_time_snsec = tk->tkr_mono.xtime_nsec; 109 kcalloc(vdso_info.size / PAGE_ << 110 40 111 pfn = __phys_to_pfn(__pa_symbol(vdso_i !! 41 vdata->monotonic_time_sec = tk->xtime_sec + 112 for (i = 0; i < vdso_info.size / PAGE_ !! 42 tk->wall_to_monotonic.tv_sec; 113 vdso_info.code_mapping.pages[i !! 43 vdata->monotonic_time_snsec = tk->tkr_mono.xtime_nsec + >> 44 (tk->wall_to_monotonic.tv_nsec << >> 45 tk->tkr_mono.shift); 114 46 115 return 0; !! 47 while (vdata->monotonic_time_snsec >= 116 } !! 48 (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift)) { 117 subsys_initcall(init_vdso); !! 49 vdata->monotonic_time_snsec -= 118 !! 50 ((u64)NSEC_PER_SEC) << tk->tkr_mono.shift; 119 #ifdef CONFIG_TIME_NS !! 51 vdata->monotonic_time_sec++; 120 struct vdso_data *arch_get_vdso_data(void *vva << 121 { << 122 return (struct vdso_data *)(vvar_page) << 123 } << 124 << 125 /* << 126 * The vvar mapping contains data for a specif << 127 * task changes namespace we must unmap its vv << 128 * Subsequent faults will map in data for the << 129 * << 130 * For more details see timens_setup_vdso_data << 131 */ << 132 int vdso_join_timens(struct task_struct *task, << 133 { << 134 struct mm_struct *mm = task->mm; << 135 struct vm_area_struct *vma; << 136 << 137 VMA_ITERATOR(vmi, mm, 0); << 138 << 139 mmap_read_lock(mm); << 140 for_each_vma(vmi, vma) { << 141 if (vma_is_special_mapping(vma << 142 zap_vma_pages(vma); << 143 } 52 } 144 mmap_read_unlock(mm); << 145 53 146 return 0; !! 54 vdata->wall_time_coarse_sec = tk->xtime_sec; 147 } !! 55 vdata->wall_time_coarse_nsec = 148 #endif !! 56 (long)(tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift); 149 57 150 static unsigned long vdso_base(void) !! 58 vdata->monotonic_time_coarse_sec = 151 { !! 59 vdata->wall_time_coarse_sec + tk->wall_to_monotonic.tv_sec; 152 unsigned long base = STACK_TOP; !! 60 vdata->monotonic_time_coarse_nsec = >> 61 vdata->wall_time_coarse_nsec + tk->wall_to_monotonic.tv_nsec; 153 62 154 if (current->flags & PF_RANDOMIZE) { !! 63 while (vdata->monotonic_time_coarse_nsec >= NSEC_PER_SEC) { 155 base += get_random_u32_below(V !! 64 vdata->monotonic_time_coarse_nsec -= NSEC_PER_SEC; 156 base = PAGE_ALIGN(base); !! 65 vdata->monotonic_time_coarse_sec++; 157 } 66 } 158 67 159 return base; !! 68 vvar_write_end(vdata); 160 } << 161 << 162 int arch_setup_additional_pages(struct linux_b << 163 { << 164 int ret; << 165 unsigned long size, data_addr, vdso_ad << 166 struct mm_struct *mm = current->mm; << 167 struct vm_area_struct *vma; << 168 struct loongarch_vdso_info *info = cur << 169 << 170 if (mmap_write_lock_killable(mm)) << 171 return -EINTR; << 172 << 173 /* << 174 * Determine total area size. This inc << 175 * and the data pages. << 176 */ << 177 size = VVAR_SIZE + info->size; << 178 << 179 data_addr = get_unmapped_area(NULL, vd << 180 if (IS_ERR_VALUE(data_addr)) { << 181 ret = data_addr; << 182 goto out; << 183 } << 184 << 185 vma = _install_special_mapping(mm, dat << 186 VM_READ << 187 &info-> << 188 if (IS_ERR(vma)) { << 189 ret = PTR_ERR(vma); << 190 goto out; << 191 } << 192 << 193 vdso_addr = data_addr + VVAR_SIZE; << 194 vma = _install_special_mapping(mm, vds << 195 VM_READ << 196 &info-> << 197 if (IS_ERR(vma)) { << 198 ret = PTR_ERR(vma); << 199 goto out; << 200 } << 201 << 202 mm->context.vdso = (void *)vdso_addr; << 203 ret = 0; << 204 << 205 out: << 206 mmap_write_unlock(mm); << 207 return ret; << 208 } 69 } 209 70
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.