linux/arch/mips/kernel/vdso.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   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. */
  27static union mips_vdso_data mips_vdso_data __page_aligned_data;
  28struct vdso_data *vdso_data = mips_vdso_data.data;
  29
  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 */
  35static struct page *no_pages[] = { NULL };
  36static struct vm_special_mapping vdso_vvar_mapping = {
  37        .name = "[vvar]",
  38        .pages = no_pages,
  39};
  40
  41static void __init init_vdso_image(struct mips_vdso_image *image)
  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(image->data));
  52        for (i = 0; i < num_pages; i++)
  53                image->mapping.pages[i] = pfn_to_page(data_pfn + i);
  54}
  55
  56static 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}
  70subsys_initcall(init_vdso);
  71
  72static 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 emulation page */
  78                base += PAGE_SIZE;
  79        }
  80
  81        if (current->flags & PF_RANDOMIZE) {
  82                base += get_random_int() & (VDSO_RANDOMIZE_SIZE - 1);
  83                base = PAGE_ALIGN(base);
  84        }
  85
  86        return base;
  87}
  88
  89int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
  90{
  91        struct mips_vdso_image *image = current->thread.abi->vdso;
  92        struct mm_struct *mm = current->mm;
  93        unsigned long gic_size, vvar_size, size, base, data_addr, vdso_addr, gic_pfn;
  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        }
 111
 112        /*
 113         * Determine total area size. This includes the VDSO data itself, the
 114         * data page, and the GIC user page if present. Always create a mapping
 115         * for the GIC user area if the GIC is present regardless of whether it
 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;
 135        }
 136
 137        /*
 138         * If we suffer from dcache aliasing, ensure that the VDSO data page
 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        }
 147
 148        data_addr = base + gic_size;
 149        vdso_addr = data_addr + PAGE_SIZE;
 150
 151        vma = _install_special_mapping(mm, base, vvar_size,
 152                                       VM_READ | VM_MAYREAD,
 153                                       &vdso_vvar_mapping);
 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_pfn = virt_to_phys(mips_gic_base + MIPS_GIC_USER_OFS) >> PAGE_SHIFT;
 162
 163                ret = io_remap_pfn_range(vma, base, gic_pfn, gic_size,
 164                                         pgprot_noncached(PAGE_READONLY));
 165                if (ret)
 166                        goto out;
 167        }
 168
 169        /* Map data page. */
 170        ret = remap_pfn_range(vma, data_addr,
 171                              virt_to_phys(vdso_data) >> PAGE_SHIFT,
 172                              PAGE_SIZE, PAGE_READONLY);
 173        if (ret)
 174                goto out;
 175
 176        /* Map VDSO image. */
 177        vma = _install_special_mapping(mm, vdso_addr, image->size,
 178                                       VM_READ | VM_EXEC |
 179                                       VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
 180                                       &image->mapping);
 181        if (IS_ERR(vma)) {
 182                ret = PTR_ERR(vma);
 183                goto out;
 184        }
 185
 186        mm->context.vdso = (void *)vdso_addr;
 187        ret = 0;
 188
 189out:
 190        mmap_write_unlock(mm);
 191        return ret;
 192}
 193