1 // SPDX-License-Identifier: GPL-2.0-or-later 1 2 /* 3 * Copyright (C) 2015 Imagination Technologies 4 * Author: Alex Smith <alex.smith@imgtec.com> 5 */ 6 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> 17 #include <linux/timekeeper_internal.h> 18 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 __ 28 struct vdso_data *vdso_data = mips_vdso_data.d 29 30 /* 31 * Mapping for the VDSO data/GIC pages. The re 32 * what we map and where within the area they 33 * runtime. 34 */ 35 static struct page *no_pages[] = { NULL }; 36 static struct vm_special_mapping vdso_vvar_map 37 .name = "[vvar]", 38 .pages = no_pages, 39 }; 40 41 static void __init init_vdso_image(struct mips 42 { 43 unsigned long num_pages, i; 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(i 52 for (i = 0; i < num_pages; i++) 53 image->mapping.pages[i] = pfn_ 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 67 68 return 0; 69 } 70 subsys_initcall(init_vdso); 71 72 static unsigned long vdso_base(void) 73 { 74 unsigned long base = STACK_TOP; 75 76 if (IS_ENABLED(CONFIG_MIPS_FP_SUPPORT) 77 /* Skip the delay slot emulati 78 base += PAGE_SIZE; 79 } 80 81 if (current->flags & PF_RANDOMIZE) { 82 base += get_random_u32_below(V 83 base = PAGE_ALIGN(base); 84 } 85 86 return base; 87 } 88 89 int arch_setup_additional_pages(struct linux_b 90 { 91 struct mips_vdso_image *image = curren 92 struct mm_struct *mm = current->mm; 93 unsigned long gic_size, vvar_size, siz 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 pa 102 base = mmap_region(NULL, STACK 103 VM_READ | VM_E 104 VM_MAYREAD | V 105 0, NULL); 106 if (IS_ERR_VALUE(base)) { 107 ret = base; 108 goto out; 109 } 110 } 111 112 /* 113 * Determine total area size. This inc 114 * data page, and the GIC user page if 115 * for the GIC user area if the GIC is 116 * is the current clocksource, in case 117 * only map a page even though the tot 118 * the counter registers at the start. 119 */ 120 gic_size = mips_gic_present() ? PAGE_S 121 vvar_size = gic_size + PAGE_SIZE; 122 size = vvar_size + image->size; 123 124 /* 125 * Find a region that's large enough f 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_ba 132 if (IS_ERR_VALUE(base)) { 133 ret = base; 134 goto out; 135 } 136 137 /* 138 * If we suffer from dcache aliasing, 139 * mapping is coloured the same as the 140 * This ensures that when the kernel u 141 * will observe it without requiring c 142 */ 143 if (cpu_has_dc_aliases) { 144 base = __ALIGN_MASK(base, shm_ 145 base += ((unsigned long)vdso_d 146 } 147 148 data_addr = base + gic_size; 149 vdso_addr = data_addr + PAGE_SIZE; 150 151 vma = _install_special_mapping(mm, bas 152 VM_READ 153 &vdso_v 154 if (IS_ERR(vma)) { 155 ret = PTR_ERR(vma); 156 goto out; 157 } 158 159 /* Map GIC user page. */ 160 if (gic_size) { 161 gic_base = (unsigned long)mips 162 gic_pfn = PFN_DOWN(__pa(gic_ba 163 164 ret = io_remap_pfn_range(vma, 165 pgpro 166 if (ret) 167 goto out; 168 } 169 170 /* Map data page. */ 171 ret = remap_pfn_range(vma, data_addr, 172 virt_to_phys(vds 173 PAGE_SIZE, vma-> 174 if (ret) 175 goto out; 176 177 /* Map VDSO image. */ 178 vma = _install_special_mapping(mm, vds 179 VM_READ 180 VM_MAYR 181 &image- 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; 193 } 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.