^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * <benh@kernel.crashing.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2012 ARM Limited
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2015 Regents of the University of California
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/elf.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/binfmts.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <asm/page.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #ifdef CONFIG_GENERIC_TIME_VSYSCALL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <vdso/datapage.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <asm/vdso.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) extern char vdso_start[], vdso_end[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) static unsigned int vdso_pages;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) static struct page **vdso_pagelist;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * The vDSO data page.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) static union {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct vdso_data data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) u8 page[PAGE_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) } vdso_data_store __page_aligned_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) struct vdso_data *vdso_data = &vdso_data_store.data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) static int __init vdso_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) vdso_pages = (vdso_end - vdso_start) >> PAGE_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) vdso_pagelist =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) kcalloc(vdso_pages + 1, sizeof(struct page *), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) if (unlikely(vdso_pagelist == NULL)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) pr_err("vdso: pagelist allocation failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) for (i = 0; i < vdso_pages; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) struct page *pg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) pg = virt_to_page(vdso_start + (i << PAGE_SHIFT));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) vdso_pagelist[i] = pg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) vdso_pagelist[i] = virt_to_page(vdso_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) arch_initcall(vdso_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) int arch_setup_additional_pages(struct linux_binprm *bprm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) int uses_interp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) struct mm_struct *mm = current->mm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) unsigned long vdso_base, vdso_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) vdso_len = (vdso_pages + 1) << PAGE_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) if (mmap_write_lock_killable(mm))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) return -EINTR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) vdso_base = get_unmapped_area(NULL, 0, vdso_len, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (IS_ERR_VALUE(vdso_base)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) ret = vdso_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) goto end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * Put vDSO base into mm struct. We need to do this before calling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * install_special_mapping or the perf counter mmap tracking code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * will fail to recognise it as a vDSO (since arch_vma_name fails).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) mm->context.vdso = (void *)vdso_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) ret =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) install_special_mapping(mm, vdso_base, vdso_pages << PAGE_SHIFT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) (VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) vdso_pagelist);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) if (unlikely(ret)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) mm->context.vdso = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) goto end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) vdso_base += (vdso_pages << PAGE_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) ret = install_special_mapping(mm, vdso_base, PAGE_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) (VM_READ | VM_MAYREAD), &vdso_pagelist[vdso_pages]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) if (unlikely(ret))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) mm->context.vdso = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) end:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) mmap_write_unlock(mm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) const char *arch_vma_name(struct vm_area_struct *vma)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (vma->vm_mm && (vma->vm_start == (long)vma->vm_mm->context.vdso))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) return "[vdso]";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (vma->vm_mm && (vma->vm_start ==
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) (long)vma->vm_mm->context.vdso + PAGE_SIZE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) return "[vdso_data]";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }