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