| .. | .. |
|---|
| 32 | 32 | |
|---|
| 33 | 33 | extern char vdso_start[], vdso_end[]; |
|---|
| 34 | 34 | |
|---|
| 35 | | -/* Total number of pages needed for the data and text portions of the VDSO. */ |
|---|
| 35 | +/* |
|---|
| 36 | + * Total number of pages needed for the data, private and text |
|---|
| 37 | + * portions of the VDSO. |
|---|
| 38 | + */ |
|---|
| 36 | 39 | unsigned int vdso_total_pages __ro_after_init; |
|---|
| 37 | 40 | |
|---|
| 38 | 41 | /* |
|---|
| .. | .. |
|---|
| 53 | 56 | unsigned long new_size = new_vma->vm_end - new_vma->vm_start; |
|---|
| 54 | 57 | unsigned long vdso_size; |
|---|
| 55 | 58 | |
|---|
| 56 | | - /* without VVAR page */ |
|---|
| 57 | | - vdso_size = (vdso_total_pages - 1) << PAGE_SHIFT; |
|---|
| 59 | + /* without VVAR and VPRIV pages */ |
|---|
| 60 | + vdso_size = (vdso_total_pages - 2) << PAGE_SHIFT; |
|---|
| 58 | 61 | |
|---|
| 59 | 62 | if (vdso_size != new_size) |
|---|
| 60 | 63 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 180 | 183 | /* If the virtual counter is absent or non-functional we don't |
|---|
| 181 | 184 | * want programs to incur the slight additional overhead of |
|---|
| 182 | 185 | * dispatching through the VDSO only to fall back to syscalls. |
|---|
| 186 | + * However, if clocksources supporting generic MMIO access can |
|---|
| 187 | + * be reached via the vDSO, keep this fast path enabled. |
|---|
| 183 | 188 | */ |
|---|
| 184 | | - if (!cntvct_ok) { |
|---|
| 189 | + if (!cntvct_ok && !IS_ENABLED(CONFIG_GENERIC_CLOCKSOURCE_VDSO)) { |
|---|
| 185 | 190 | vdso_nullpatch_one(&einfo, "__vdso_gettimeofday"); |
|---|
| 186 | 191 | vdso_nullpatch_one(&einfo, "__vdso_clock_gettime"); |
|---|
| 187 | 192 | vdso_nullpatch_one(&einfo, "__vdso_clock_gettime64"); |
|---|
| .. | .. |
|---|
| 219 | 224 | |
|---|
| 220 | 225 | vdso_text_mapping.pages = vdso_text_pagelist; |
|---|
| 221 | 226 | |
|---|
| 222 | | - vdso_total_pages = 1; /* for the data/vvar page */ |
|---|
| 227 | + vdso_total_pages = 2; /* for the data/vvar and vpriv pages */ |
|---|
| 223 | 228 | vdso_total_pages += text_pages; |
|---|
| 224 | 229 | |
|---|
| 225 | 230 | cntvct_ok = cntvct_functional(); |
|---|
| 226 | 231 | |
|---|
| 227 | 232 | patch_vdso(vdso_start); |
|---|
| 233 | +#ifdef CONFIG_GENERIC_CLOCKSOURCE_VDSO |
|---|
| 234 | + vdso_data->cs_type_seq = CLOCKSOURCE_VDSO_NONE << 16 | 1; |
|---|
| 235 | +#endif |
|---|
| 228 | 236 | |
|---|
| 229 | 237 | return 0; |
|---|
| 230 | 238 | } |
|---|
| 231 | 239 | arch_initcall(vdso_init); |
|---|
| 240 | + |
|---|
| 241 | +static int install_vpriv(struct mm_struct *mm, unsigned long addr) |
|---|
| 242 | +{ |
|---|
| 243 | + return mmap_region(NULL, addr, PAGE_SIZE, |
|---|
| 244 | + VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE, |
|---|
| 245 | + 0, NULL) != addr ? -EINVAL : 0; |
|---|
| 246 | +} |
|---|
| 232 | 247 | |
|---|
| 233 | 248 | static int install_vvar(struct mm_struct *mm, unsigned long addr) |
|---|
| 234 | 249 | { |
|---|
| .. | .. |
|---|
| 237 | 252 | vma = _install_special_mapping(mm, addr, PAGE_SIZE, |
|---|
| 238 | 253 | VM_READ | VM_MAYREAD, |
|---|
| 239 | 254 | &vdso_data_mapping); |
|---|
| 255 | + if (IS_ERR(vma)) |
|---|
| 256 | + return PTR_ERR(vma); |
|---|
| 240 | 257 | |
|---|
| 241 | | - return PTR_ERR_OR_ZERO(vma); |
|---|
| 258 | + if (cache_is_vivt()) |
|---|
| 259 | + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); |
|---|
| 260 | + |
|---|
| 261 | + return vma->vm_start != addr ? -EINVAL : 0; |
|---|
| 242 | 262 | } |
|---|
| 243 | 263 | |
|---|
| 244 | 264 | /* assumes mmap_lock is write-locked */ |
|---|
| .. | .. |
|---|
| 252 | 272 | if (vdso_text_pagelist == NULL) |
|---|
| 253 | 273 | return; |
|---|
| 254 | 274 | |
|---|
| 255 | | - if (install_vvar(mm, addr)) |
|---|
| 275 | + if (install_vpriv(mm, addr)) { |
|---|
| 276 | + pr_err("cannot map VPRIV at expected address!\n"); |
|---|
| 256 | 277 | return; |
|---|
| 278 | + } |
|---|
| 257 | 279 | |
|---|
| 258 | | - /* Account for vvar page. */ |
|---|
| 280 | + /* Account for the private storage. */ |
|---|
| 259 | 281 | addr += PAGE_SIZE; |
|---|
| 260 | | - len = (vdso_total_pages - 1) << PAGE_SHIFT; |
|---|
| 282 | + if (install_vvar(mm, addr)) { |
|---|
| 283 | + WARN(1, "cannot map VVAR at expected address!\n"); |
|---|
| 284 | + return; |
|---|
| 285 | + } |
|---|
| 286 | + |
|---|
| 287 | + /* Account for vvar and vpriv pages. */ |
|---|
| 288 | + addr += PAGE_SIZE; |
|---|
| 289 | + len = (vdso_total_pages - 2) << PAGE_SHIFT; |
|---|
| 261 | 290 | |
|---|
| 262 | 291 | vma = _install_special_mapping(mm, addr, len, |
|---|
| 263 | 292 | VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC, |
|---|
| 264 | 293 | &vdso_text_mapping); |
|---|
| 265 | 294 | |
|---|
| 266 | | - if (!IS_ERR(vma)) |
|---|
| 295 | + if (IS_ERR(vma) || vma->vm_start != addr) |
|---|
| 296 | + WARN(1, "cannot map VDSO at expected address!\n"); |
|---|
| 297 | + else |
|---|
| 267 | 298 | mm->context.vdso = addr; |
|---|
| 268 | 299 | } |
|---|
| 269 | 300 | |
|---|