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;
  75
  76        /* Skip the delay slot emulation page */
  77        base = STACK_TOP + PAGE_SIZE;
  78
  79        if (current->flags & PF_RANDOMIZE) {
  80                base += get_random_int() & (VDSO_RANDOMIZE_SIZE - 1);
  81                base = PAGE_ALIGN(base);
  82        }
  83
  84        return base;
  85}
  86
  87int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
  88{
  89        struct mips_vdso_image *image = current->thread.abi->vdso;
  90        struct mm_struct *mm = current->mm;
  91        unsigned long gic_size, vvar_size, size, base, data_addr, vdso_addr, gic_pfn;
  92        struct vm_area_struct *vma;
  93        int ret;
  94
  95        if (down_write_killable(&mm->mmap_sem))
  96                return -EINTR;
  97
  98        /* Map delay slot emulation page */
  99        base = mmap_region(NULL, STACK_TOP, PAGE_SIZE,
 100                           VM_READ | VM_EXEC |
 101                           VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
 102                           0, NULL);
 103        if (IS_ERR_VALUE(base)) {
 104                ret = base;
 105                goto out;
 106        }
 107
 108        /*
 109         * Determine total area size. This includes the VDSO data itself, the
 110         * data page, and the GIC user page if present. Always create a mapping
 111         * for the GIC user area if the GIC is present regardless of whether it
 112         * is the current clocksource, in case it comes into use later on. We
 113         * only map a page even though the total area is 64K, as we only need
 114         * the counter registers at the start.
 115         */
 116        gic_size = mips_gic_present() ? PAGE_SIZE : 0;
 117        vvar_size = gic_size + PAGE_SIZE;
 118        size = vvar_size + image->size;
 119
 120        /*
 121         * Find a region that's large enough for us to perform the
 122         * colour-matching alignment below.
 123         */
 124        if (cpu_has_dc_aliases)
 125                size += shm_align_mask + 1;
 126
 127        base = get_unmapped_area(NULL, vdso_base(), size, 0, 0);
 128        if (IS_ERR_VALUE(base)) {
 129                ret = base;
 130                goto out;
 131        }
 132
 133        /*
 134         * If we suffer from dcache aliasing, ensure that the VDSO data page
 135         * mapping is coloured the same as the kernel's mapping of that memory.
 136         * This ensures that when the kernel updates the VDSO data userland
 137         * will observe it without requiring cache invalidations.
 138         */
 139        if (cpu_has_dc_aliases) {
 140                base = __ALIGN_MASK(base, shm_align_mask);
 141                base += ((unsigned long)vdso_data - gic_size) & shm_align_mask;
 142        }
 143
 144        data_addr = base + gic_size;
 145        vdso_addr = data_addr + PAGE_SIZE;
 146
 147        vma = _install_special_mapping(mm, base, vvar_size,
 148                                       VM_READ | VM_MAYREAD,
 149                                       &vdso_vvar_mapping);
 150        if (IS_ERR(vma)) {
 151                ret = PTR_ERR(vma);
 152                goto out;
 153        }
 154
 155        /* Map GIC user page. */
 156        if (gic_size) {
 157                gic_pfn = virt_to_phys(mips_gic_base + MIPS_GIC_USER_OFS) >> PAGE_SHIFT;
 158
 159                ret = io_remap_pfn_range(vma, base, gic_pfn, gic_size,
 160                                         pgprot_noncached(PAGE_READONLY));
 161                if (ret)
 162                        goto out;
 163        }
 164
 165        /* Map data page. */
 166        ret = remap_pfn_range(vma, data_addr,
 167                              virt_to_phys(vdso_data) >> PAGE_SHIFT,
 168                              PAGE_SIZE, PAGE_READONLY);
 169        if (ret)
 170                goto out;
 171
 172        /* Map VDSO image. */
 173        vma = _install_special_mapping(mm, vdso_addr, image->size,
 174                                       VM_READ | VM_EXEC |
 175                                       VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
 176                                       &image->mapping);
 177        if (IS_ERR(vma)) {
 178                ret = PTR_ERR(vma);
 179                goto out;
 180        }
 181
 182        mm->context.vdso = (void *)vdso_addr;
 183        ret = 0;
 184
 185out:
 186        up_write(&mm->mmap_sem);
 187        return ret;
 188}
 189